1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
package org.apache.tapestry.engine; |
16 | |
|
17 | |
import org.apache.commons.fileupload.RequestContext; |
18 | |
import org.apache.commons.logging.Log; |
19 | |
import org.apache.commons.logging.LogFactory; |
20 | |
import org.apache.hivemind.ApplicationRuntimeException; |
21 | |
import org.apache.hivemind.ErrorLog; |
22 | |
import org.apache.hivemind.impl.ErrorLogImpl; |
23 | |
import org.apache.hivemind.util.Defense; |
24 | |
import org.apache.hivemind.util.ToStringBuilder; |
25 | |
import org.apache.tapestry.*; |
26 | |
import org.apache.tapestry.record.PageRecorderImpl; |
27 | |
import org.apache.tapestry.record.PropertyPersistenceStrategySource; |
28 | |
import org.apache.tapestry.services.AbsoluteURLBuilder; |
29 | |
import org.apache.tapestry.services.Infrastructure; |
30 | |
import org.apache.tapestry.services.ResponseBuilder; |
31 | |
import org.apache.tapestry.services.ServiceConstants; |
32 | |
import org.apache.tapestry.util.IdAllocator; |
33 | |
import org.apache.tapestry.util.QueryParameterMap; |
34 | |
import org.apache.tapestry.util.io.CompressedDataEncoder; |
35 | |
|
36 | |
import java.util.HashMap; |
37 | |
import java.util.Iterator; |
38 | |
import java.util.Map; |
39 | |
import java.util.Stack; |
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
|
48 | |
public class RequestCycle implements IRequestCycle |
49 | |
{ |
50 | 0 | private static final Log LOG = LogFactory.getLog(RequestCycle.class); |
51 | |
|
52 | |
protected ResponseBuilder _responseBuilder; |
53 | |
|
54 | |
private IPage _page; |
55 | |
|
56 | |
private IEngine _engine; |
57 | |
|
58 | |
private String _serviceName; |
59 | |
|
60 | |
|
61 | |
|
62 | |
private PropertyPersistenceStrategySource _strategySource; |
63 | |
|
64 | |
|
65 | |
|
66 | |
private IPageSource _pageSource; |
67 | |
|
68 | |
|
69 | |
|
70 | |
private Infrastructure _infrastructure; |
71 | |
|
72 | |
|
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
private QueryParameterMap _parameters; |
80 | |
|
81 | |
|
82 | |
|
83 | |
private AbsoluteURLBuilder _absoluteURLBuilder; |
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
private Map _loadedPages; |
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
|
97 | |
private Map _pageRecorders; |
98 | |
|
99 | 0 | private boolean _rewinding = false; |
100 | |
|
101 | 0 | private Map _attributes = new HashMap(); |
102 | |
|
103 | |
private int _targetActionId; |
104 | |
|
105 | |
private IComponent _targetComponent; |
106 | |
|
107 | |
|
108 | |
|
109 | |
private Object[] _listenerParameters; |
110 | |
|
111 | |
|
112 | |
|
113 | |
private ErrorLog _log; |
114 | |
|
115 | |
|
116 | |
|
117 | 0 | private IdAllocator _idAllocator = new IdAllocator(); |
118 | |
|
119 | 0 | private Stack _renderStack = new Stack(); |
120 | |
|
121 | 0 | private boolean _focusDisabled = false; |
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | |
|
131 | |
|
132 | |
|
133 | |
|
134 | |
|
135 | |
|
136 | |
|
137 | |
public RequestCycle(IEngine engine, QueryParameterMap parameters, String serviceName, |
138 | |
RequestCycleEnvironment environment) |
139 | 0 | { |
140 | |
|
141 | |
|
142 | 0 | _engine = engine; |
143 | 0 | _parameters = parameters; |
144 | 0 | _serviceName = serviceName; |
145 | |
|
146 | |
|
147 | |
|
148 | 0 | _infrastructure = environment.getInfrastructure(); |
149 | 0 | _pageSource = _infrastructure.getPageSource(); |
150 | 0 | _strategySource = environment.getStrategySource(); |
151 | 0 | _absoluteURLBuilder = environment.getAbsoluteURLBuilder(); |
152 | 0 | _log = new ErrorLogImpl(environment.getErrorHandler(), LOG); |
153 | 0 | } |
154 | |
|
155 | |
|
156 | |
|
157 | |
|
158 | |
|
159 | |
|
160 | |
public RequestCycle() |
161 | 0 | { |
162 | 0 | } |
163 | |
|
164 | |
|
165 | |
|
166 | |
|
167 | |
|
168 | |
|
169 | |
public void cleanup() |
170 | |
{ |
171 | 0 | if (_loadedPages == null) |
172 | 0 | return; |
173 | |
|
174 | 0 | Iterator i = _loadedPages.values().iterator(); |
175 | |
|
176 | 0 | while (i.hasNext()) |
177 | |
{ |
178 | 0 | IPage page = (IPage) i.next(); |
179 | |
|
180 | 0 | _pageSource.releasePage(page); |
181 | 0 | } |
182 | |
|
183 | 0 | _loadedPages = null; |
184 | 0 | _pageRecorders = null; |
185 | 0 | _renderStack.clear(); |
186 | 0 | } |
187 | |
|
188 | |
public IEngineService getService() |
189 | |
{ |
190 | 0 | return _infrastructure.getServiceMap().getService(_serviceName); |
191 | |
} |
192 | |
|
193 | |
public String encodeURL(String URL) |
194 | |
{ |
195 | 0 | return _infrastructure.getResponse().encodeURL(URL); |
196 | |
} |
197 | |
|
198 | |
public IEngine getEngine() |
199 | |
{ |
200 | 0 | return _engine; |
201 | |
} |
202 | |
|
203 | |
public Object getAttribute(String name) |
204 | |
{ |
205 | 0 | return _attributes.get(name); |
206 | |
} |
207 | |
|
208 | |
public IPage getPage() |
209 | |
{ |
210 | 0 | return _page; |
211 | |
} |
212 | |
|
213 | |
|
214 | |
|
215 | |
|
216 | |
|
217 | |
public IPage getPage(String name) |
218 | |
{ |
219 | 0 | Defense.notNull(name, "name"); |
220 | |
|
221 | 0 | IPage result = null; |
222 | |
|
223 | 0 | if (_loadedPages != null) |
224 | 0 | result = (IPage) _loadedPages.get(name); |
225 | |
|
226 | 0 | if (result == null) |
227 | |
{ |
228 | 0 | result = loadPage(name); |
229 | |
|
230 | 0 | if (_loadedPages == null) |
231 | 0 | _loadedPages = new HashMap(); |
232 | |
|
233 | 0 | _loadedPages.put(name, result); |
234 | |
} |
235 | |
|
236 | 0 | return result; |
237 | |
} |
238 | |
|
239 | |
private IPage loadPage(String name) |
240 | |
{ |
241 | 0 | IPage result = _pageSource.getPage(this, name); |
242 | |
|
243 | |
|
244 | |
|
245 | |
|
246 | 0 | IPageRecorder recorder = getPageRecorder(name); |
247 | |
|
248 | |
|
249 | |
|
250 | |
|
251 | |
|
252 | 0 | recorder.rollback(result); |
253 | |
|
254 | |
|
255 | |
|
256 | |
|
257 | 0 | result.setChangeObserver(recorder); |
258 | |
|
259 | |
|
260 | |
|
261 | 0 | result.firePageAttached(); |
262 | |
|
263 | 0 | return result; |
264 | |
} |
265 | |
|
266 | |
|
267 | |
|
268 | |
|
269 | |
|
270 | |
|
271 | |
protected IPageRecorder getPageRecorder(String name) |
272 | |
{ |
273 | 0 | if (_pageRecorders == null) |
274 | 0 | _pageRecorders = new HashMap(); |
275 | |
|
276 | 0 | IPageRecorder result = (IPageRecorder) _pageRecorders.get(name); |
277 | |
|
278 | 0 | if (result == null) |
279 | |
{ |
280 | 0 | result = new PageRecorderImpl(name, _strategySource, _log); |
281 | 0 | _pageRecorders.put(name, result); |
282 | |
} |
283 | |
|
284 | 0 | return result; |
285 | |
} |
286 | |
|
287 | |
public void setResponseBuilder(ResponseBuilder builder) |
288 | |
{ |
289 | |
|
290 | |
|
291 | |
|
292 | |
|
293 | 0 | _responseBuilder = builder; |
294 | 0 | } |
295 | |
|
296 | |
public ResponseBuilder getResponseBuilder() |
297 | |
{ |
298 | 0 | return _responseBuilder; |
299 | |
} |
300 | |
|
301 | |
|
302 | |
|
303 | |
|
304 | |
public boolean renderStackEmpty() |
305 | |
{ |
306 | 0 | return _renderStack.isEmpty(); |
307 | |
} |
308 | |
|
309 | |
|
310 | |
|
311 | |
|
312 | |
public IRender renderStackPeek() |
313 | |
{ |
314 | 0 | if (_renderStack.size() < 1) |
315 | 0 | return null; |
316 | |
|
317 | 0 | return (IRender)_renderStack.peek(); |
318 | |
} |
319 | |
|
320 | |
|
321 | |
|
322 | |
|
323 | |
public IRender renderStackPop() |
324 | |
{ |
325 | 0 | if (_renderStack.size() == 0) |
326 | 0 | return null; |
327 | |
|
328 | 0 | return (IRender)_renderStack.pop(); |
329 | |
} |
330 | |
|
331 | |
|
332 | |
|
333 | |
|
334 | |
public IRender renderStackPush(IRender render) |
335 | |
{ |
336 | 0 | if (_renderStack.size() > 0 && _renderStack.peek() == render) |
337 | 0 | return render; |
338 | |
|
339 | 0 | return (IRender)_renderStack.push(render); |
340 | |
} |
341 | |
|
342 | |
|
343 | |
|
344 | |
|
345 | |
public int renderStackSearch(IRender render) |
346 | |
{ |
347 | 0 | return _renderStack.search(render); |
348 | |
} |
349 | |
|
350 | |
|
351 | |
|
352 | |
|
353 | |
public Iterator renderStackIterator() |
354 | |
{ |
355 | 0 | return _renderStack.iterator(); |
356 | |
} |
357 | |
|
358 | |
public boolean isRewinding() |
359 | |
{ |
360 | 0 | return _rewinding; |
361 | |
} |
362 | |
|
363 | |
public boolean isRewound(IComponent component) |
364 | |
{ |
365 | |
|
366 | |
|
367 | 0 | if (!_rewinding) |
368 | 0 | return false; |
369 | |
|
370 | |
|
371 | |
|
372 | 0 | if (component == _targetComponent) |
373 | 0 | return true; |
374 | |
|
375 | |
|
376 | |
|
377 | 0 | throw new StaleLinkException(component, Integer.toHexString(_targetActionId), _targetComponent.getExtendedId()); |
378 | |
} |
379 | |
|
380 | |
public void removeAttribute(String name) |
381 | |
{ |
382 | 0 | if (LOG.isDebugEnabled()) |
383 | 0 | LOG.debug("Removing attribute " + name); |
384 | |
|
385 | 0 | _attributes.remove(name); |
386 | 0 | } |
387 | |
|
388 | |
|
389 | |
|
390 | |
|
391 | |
|
392 | |
|
393 | |
public void renderPage(ResponseBuilder builder) |
394 | |
{ |
395 | 0 | _rewinding = false; |
396 | 0 | preallocateReservedIds(); |
397 | |
|
398 | |
try |
399 | |
{ |
400 | 0 | _page.renderPage(builder, this); |
401 | |
|
402 | |
} |
403 | 0 | catch (ApplicationRuntimeException ex) |
404 | |
{ |
405 | |
|
406 | |
|
407 | 0 | throw ex; |
408 | |
} |
409 | 0 | catch (Throwable ex) |
410 | |
{ |
411 | |
|
412 | |
|
413 | |
|
414 | 0 | throw new ApplicationRuntimeException(ex.getMessage(), _page, null, ex); |
415 | |
} |
416 | |
finally |
417 | |
{ |
418 | 0 | reset(); |
419 | 0 | } |
420 | |
|
421 | 0 | } |
422 | |
|
423 | |
|
424 | |
|
425 | |
|
426 | |
|
427 | |
|
428 | |
private void preallocateReservedIds() |
429 | |
{ |
430 | 0 | for (int i = 0; i < ServiceConstants.RESERVED_IDS.length; i++) |
431 | |
{ |
432 | 0 | _idAllocator.allocateId(ServiceConstants.RESERVED_IDS[i]); |
433 | |
} |
434 | 0 | } |
435 | |
|
436 | |
|
437 | |
|
438 | |
|
439 | |
|
440 | |
private void reset() |
441 | |
{ |
442 | 0 | _attributes.clear(); |
443 | 0 | _idAllocator.clear(); |
444 | 0 | } |
445 | |
|
446 | |
|
447 | |
|
448 | |
|
449 | |
|
450 | |
|
451 | |
|
452 | |
|
453 | |
|
454 | |
|
455 | |
|
456 | |
|
457 | |
|
458 | |
public void rewindForm(IForm form) |
459 | |
{ |
460 | 0 | IPage page = form.getPage(); |
461 | 0 | _rewinding = true; |
462 | |
|
463 | 0 | _targetComponent = form; |
464 | |
|
465 | |
try |
466 | |
{ |
467 | 0 | page.beginPageRender(); |
468 | |
|
469 | 0 | form.rewind(NullWriter.getSharedInstance(), this); |
470 | |
|
471 | |
|
472 | |
|
473 | |
|
474 | 0 | throw new StaleLinkException(Tapestry.format("RequestCycle.form-rewind-failure", form.getExtendedId()), form); |
475 | |
} |
476 | 0 | catch (RenderRewoundException ex) |
477 | |
{ |
478 | |
|
479 | |
} |
480 | 0 | catch (ApplicationRuntimeException ex) |
481 | |
{ |
482 | |
|
483 | 0 | throw ex; |
484 | |
} |
485 | 0 | catch (Throwable ex) |
486 | |
{ |
487 | |
|
488 | |
|
489 | |
|
490 | 0 | throw new ApplicationRuntimeException(ex.getMessage(), page, null, ex); |
491 | |
} |
492 | |
finally |
493 | |
{ |
494 | 0 | page.endPageRender(); |
495 | |
|
496 | 0 | reset(); |
497 | 0 | _rewinding = false; |
498 | 0 | } |
499 | 0 | } |
500 | |
|
501 | |
|
502 | |
|
503 | |
|
504 | |
public void disableFocus() |
505 | |
{ |
506 | 0 | _focusDisabled = true; |
507 | 0 | } |
508 | |
|
509 | |
|
510 | |
|
511 | |
|
512 | |
public boolean isFocusDisabled() |
513 | |
{ |
514 | 0 | return _focusDisabled; |
515 | |
} |
516 | |
|
517 | |
public void setAttribute(String name, Object value) |
518 | |
{ |
519 | 0 | if (LOG.isDebugEnabled()) |
520 | 0 | LOG.debug("Set attribute " + name + " to " + value); |
521 | |
|
522 | 0 | _attributes.put(name, value); |
523 | 0 | } |
524 | |
|
525 | |
|
526 | |
|
527 | |
|
528 | |
|
529 | |
|
530 | |
public void commitPageChanges() |
531 | |
{ |
532 | 0 | if (LOG.isDebugEnabled()) |
533 | 0 | LOG.debug("Committing page changes"); |
534 | |
|
535 | 0 | if (_pageRecorders == null || _pageRecorders.isEmpty()) |
536 | 0 | return; |
537 | |
|
538 | 0 | Iterator i = _pageRecorders.values().iterator(); |
539 | |
|
540 | 0 | while (i.hasNext()) |
541 | |
{ |
542 | 0 | IPageRecorder recorder = (IPageRecorder) i.next(); |
543 | |
|
544 | 0 | recorder.commit(); |
545 | 0 | } |
546 | 0 | } |
547 | |
|
548 | |
|
549 | |
|
550 | |
|
551 | |
|
552 | |
|
553 | |
|
554 | |
public void discardPage(String name) |
555 | |
{ |
556 | 0 | forgetPage(name); |
557 | 0 | } |
558 | |
|
559 | |
|
560 | |
public Object[] getListenerParameters() |
561 | |
{ |
562 | 0 | return _listenerParameters; |
563 | |
} |
564 | |
|
565 | |
|
566 | |
public void setListenerParameters(Object[] parameters) |
567 | |
{ |
568 | 0 | _listenerParameters = parameters; |
569 | 0 | } |
570 | |
|
571 | |
|
572 | |
|
573 | |
public void activate(String name) |
574 | |
{ |
575 | 0 | IPage page = getPage(name); |
576 | |
|
577 | 0 | activate(page); |
578 | 0 | } |
579 | |
|
580 | |
|
581 | |
|
582 | |
public void activate(IPage page) |
583 | |
{ |
584 | 0 | Defense.notNull(page, "page"); |
585 | |
|
586 | 0 | if (LOG.isDebugEnabled()) |
587 | 0 | LOG.debug("Activating page " + page); |
588 | |
|
589 | 0 | Tapestry.clearMethodInvocations(); |
590 | |
|
591 | 0 | page.validate(this); |
592 | |
|
593 | 0 | Tapestry.checkMethodInvocation(Tapestry.ABSTRACTPAGE_VALIDATE_METHOD_ID, "validate()", page); |
594 | |
|
595 | 0 | _page = page; |
596 | 0 | } |
597 | |
|
598 | |
|
599 | |
public String getParameter(String name) |
600 | |
{ |
601 | 0 | return _parameters.getParameterValue(name); |
602 | |
} |
603 | |
|
604 | |
|
605 | |
public String[] getParameters(String name) |
606 | |
{ |
607 | 0 | return _parameters.getParameterValues(name); |
608 | |
} |
609 | |
|
610 | |
|
611 | |
|
612 | |
|
613 | |
public String toString() |
614 | |
{ |
615 | 0 | ToStringBuilder b = new ToStringBuilder(this); |
616 | |
|
617 | 0 | b.append("rewinding", _rewinding); |
618 | 0 | b.append("serviceName", _serviceName); |
619 | 0 | b.append("serviceParameters", _listenerParameters); |
620 | |
|
621 | 0 | if (_loadedPages != null) |
622 | 0 | b.append("loadedPages", _loadedPages.keySet()); |
623 | |
|
624 | 0 | b.append("attributes", _attributes); |
625 | 0 | b.append("targetActionId", _targetActionId); |
626 | 0 | b.append("targetComponent", _targetComponent); |
627 | |
|
628 | 0 | return b.toString(); |
629 | |
} |
630 | |
|
631 | |
|
632 | |
|
633 | |
public String getAbsoluteURL(String partialURL) |
634 | |
{ |
635 | 0 | String contextPath = _infrastructure.getRequest().getContextPath(); |
636 | |
|
637 | 0 | return _absoluteURLBuilder.constructURL(contextPath + partialURL); |
638 | |
} |
639 | |
|
640 | |
|
641 | |
|
642 | |
public void forgetPage(String pageName) |
643 | |
{ |
644 | 0 | Defense.notNull(pageName, "pageName"); |
645 | |
|
646 | 0 | _strategySource.discardAllStoredChanged(pageName); |
647 | 0 | } |
648 | |
|
649 | |
|
650 | |
|
651 | |
public Infrastructure getInfrastructure() |
652 | |
{ |
653 | 0 | return _infrastructure; |
654 | |
} |
655 | |
|
656 | |
|
657 | |
|
658 | |
public String getUniqueId(String baseId) |
659 | |
{ |
660 | 0 | return _idAllocator.allocateId(baseId); |
661 | |
} |
662 | |
|
663 | |
|
664 | |
|
665 | |
public String peekUniqueId(String baseId) |
666 | |
{ |
667 | 0 | return _idAllocator.peekNextId(baseId); |
668 | |
} |
669 | |
|
670 | |
|
671 | |
public void sendRedirect(String URL) |
672 | |
{ |
673 | 0 | throw new RedirectException(URL); |
674 | |
} |
675 | |
|
676 | |
public String encodeIdState() |
677 | |
{ |
678 | 0 | return CompressedDataEncoder.encodeString(_idAllocator.toExternalString()); |
679 | |
} |
680 | |
|
681 | |
public void initializeIdState(String encodedSeed) |
682 | |
{ |
683 | 0 | _idAllocator = IdAllocator.fromExternalString( CompressedDataEncoder.decodeString(encodedSeed)); |
684 | 0 | } |
685 | |
} |