Source Code Cross Referenced for AjaxRequestTarget.java in  » J2EE » wicket » wicket » ajax » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » wicket » wicket.ajax 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $Id: AjaxRequestTarget.java 4837 2006-03-08 14:46:58 -0800 (Wed, 08 Mar 2006)
003:         * ivaynberg $ $Revision: 508111 $ $Date: 2006-03-08 14:46:58 -0800 (Wed, 08 Mar
004:         * 2006) $
005:         * 
006:         * ==============================================================================
007:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
008:         * use this file except in compliance with the License. You may obtain a copy of
009:         * the License at
010:         * 
011:         * http://www.apache.org/licenses/LICENSE-2.0
012:         * 
013:         * Unless required by applicable law or agreed to in writing, software
014:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016:         * License for the specific language governing permissions and limitations under
017:         * the License.
018:         */
019:        package wicket.ajax;
020:
021:        import java.io.OutputStream;
022:        import java.util.ArrayList;
023:        import java.util.HashMap;
024:        import java.util.Iterator;
025:        import java.util.List;
026:        import java.util.Map;
027:        import java.util.Map.Entry;
028:
029:        import org.apache.commons.logging.Log;
030:        import org.apache.commons.logging.LogFactory;
031:
032:        import wicket.Application;
033:        import wicket.Component;
034:        import wicket.IRequestTarget;
035:        import wicket.MarkupContainer;
036:        import wicket.Page;
037:        import wicket.RequestCycle;
038:        import wicket.Response;
039:        import wicket.markup.html.internal.HtmlHeaderContainer;
040:        import wicket.markup.parser.filter.HtmlHeaderSectionHandler;
041:        import wicket.protocol.http.WebResponse;
042:        import wicket.util.string.AppendingStringBuffer;
043:        import wicket.util.string.Strings;
044:
045:        /**
046:         * A request target that produces ajax response envelopes used on the client
047:         * side to update component markup as well as evaluate arbitrary javascript.
048:         * <p>
049:         * A component whose markup needs to be updated should be added to this target
050:         * via AjaxRequestTarget#addComponent(Component) method. Its body will be
051:         * rendered and added to the envelope when the target is processed, and
052:         * refreshed on the client side when the ajax response is received.
053:         * <p>
054:         * It is important that the component whose markup needs to be updated contains
055:         * an id attribute in the generated markup that is equal to the value retrieved
056:         * from Component#getMarkupId(). This can be accomplished by either setting the
057:         * id attribute in the html template, or using an attribute modifier that will
058:         * add the attribute with value Component#getMarkupId() to the tag ( such as
059:         * MarkupIdSetter )
060:         * <p>
061:         * Any javascript that needs to be evaluater on the client side can be added
062:         * using AjaxRequestTarget#addJavascript(String). For example, this feature can
063:         * be useful when it is desirable to link component update with some javascript
064:         * effects.
065:         * 
066:         * @since 1.2
067:         * 
068:         * @author Igor Vaynberg (ivaynberg)
069:         * @author Eelco Hillenius
070:         */
071:        public class AjaxRequestTarget implements  IRequestTarget {
072:            /**
073:             * Response that uses an encoder to encode its contents
074:             * 
075:             * @author Igor Vaynberg (ivaynberg)
076:             */
077:            private final class EncodingResponse extends Response {
078:                private final AppendingStringBuffer buffer = new AppendingStringBuffer(
079:                        256);
080:
081:                private boolean escaped = false;
082:
083:                private final Response originalResponse;
084:
085:                /**
086:                 * Construct.
087:                 * 
088:                 * @param originalResponse
089:                 */
090:                public EncodingResponse(Response originalResponse) {
091:                    this .originalResponse = originalResponse;
092:                }
093:
094:                /**
095:                 * @see wicket.Response#encodeURL(CharSequence)
096:                 */
097:                public CharSequence encodeURL(CharSequence url) {
098:                    return originalResponse.encodeURL(url);
099:                }
100:
101:                /**
102:                 * @return contents of the response
103:                 */
104:                public CharSequence getContents() {
105:                    return buffer;
106:                }
107:
108:                /**
109:                 * NOTE: this method is not supported
110:                 * 
111:                 * @see wicket.Response#getOutputStream()
112:                 */
113:                public OutputStream getOutputStream() {
114:                    throw new UnsupportedOperationException(
115:                            "Cannot get output stream on StringResponse");
116:                }
117:
118:                /**
119:                 * @return true if any escaping has been performed, false otherwise
120:                 */
121:                public boolean isContentsEncoded() {
122:                    return escaped;
123:                }
124:
125:                /**
126:                 * Resets the response to a clean state so it can be reused to save on
127:                 * garbage.
128:                 */
129:                public void reset() {
130:                    buffer.clear();
131:                    escaped = false;
132:
133:                }
134:
135:                /**
136:                 * @see wicket.Response#write(CharSequence)
137:                 */
138:                public void write(CharSequence cs) {
139:                    String string = cs.toString();
140:                    if (needsEncoding(string)) {
141:                        string = encode(string);
142:                        escaped = true;
143:                        buffer.append(string);
144:                    } else {
145:                        buffer.append(cs);
146:                    }
147:                }
148:
149:            }
150:
151:            private static final Log LOG = LogFactory
152:                    .getLog(AjaxRequestTarget.class);
153:
154:            private final List/* <String> */appendJavascripts = new ArrayList();
155:
156:            /**
157:             * Create a response for component body and javascript that will escape
158:             * output to make it safe to use inside a CDATA block
159:             */
160:            private final EncodingResponse encodingBodyResponse;
161:
162:            /**
163:             * Response for header contributon that will escape output to make it safe
164:             * to use inside a CDATA block
165:             */
166:            private final EncodingResponse encodingHeaderResponse;
167:
168:            /** the component instances that will be rendered */
169:            private final Map/* <String,Component> */markupIdToComponent = new HashMap();
170:
171:            private final List/* <String> */prependJavascripts = new ArrayList();
172:
173:            /**
174:             * Constructor
175:             */
176:            public AjaxRequestTarget() {
177:                Response response = RequestCycle.get().getResponse();
178:                encodingBodyResponse = new EncodingResponse(response);
179:                encodingHeaderResponse = new EncodingResponse(response);
180:            }
181:
182:            /**
183:             * Adds a component to the list of components to be rendered
184:             * 
185:             * @param component
186:             *            component to be rendered
187:             */
188:            public final void addComponent(Component component) {
189:                addComponent(component, component.getMarkupId());
190:            }
191:
192:            /**
193:             * Adds a component to the list of components to be rendered
194:             * 
195:             * @param markupId
196:             *            id of client-side dom element that will be updated
197:             * 
198:             * @param component
199:             *            component to be rendered
200:             */
201:            public final void addComponent(Component component, String markupId) {
202:                if (Strings.isEmpty(markupId)) {
203:                    throw new IllegalArgumentException(
204:                            "markupId cannot be empty");
205:                }
206:                if (component == null) {
207:                    throw new IllegalArgumentException(
208:                            "component cannot be null");
209:                } else if (component instanceof  Page) {
210:                    throw new IllegalArgumentException(
211:                            "component cannot be a page");
212:                }
213:
214:                markupIdToComponent.put(markupId, component);
215:            }
216:
217:            /**
218:             * Adds javascript that will be evaluated on the client side after
219:             * components are replaced
220:             * 
221:             * @deprecated use appendJavascript(String javascript) instead
222:             * @param javascript
223:             */
224:            public final void addJavascript(String javascript) {
225:                appendJavascript(javascript);
226:            }
227:
228:            /**
229:             * Adds javascript that will be evaluated on the client side after
230:             * components are replaced
231:             * 
232:             * @param javascript
233:             */
234:            public final void appendJavascript(String javascript) {
235:                if (javascript == null) {
236:                    throw new IllegalArgumentException(
237:                            "javascript cannot be null");
238:                }
239:
240:                appendJavascripts.add(javascript);
241:            }
242:
243:            /**
244:             * @see wicket.IRequestTarget#detach(wicket.RequestCycle)
245:             */
246:            public void detach(final RequestCycle requestCycle) {
247:            }
248:
249:            /**
250:             * @see java.lang.Object#equals(java.lang.Object)
251:             */
252:            public boolean equals(final Object obj) {
253:                if (obj instanceof  AjaxRequestTarget) {
254:                    AjaxRequestTarget that = (AjaxRequestTarget) obj;
255:                    return markupIdToComponent.equals(that.markupIdToComponent)
256:                            && prependJavascripts
257:                                    .equals(that.prependJavascripts)
258:                            && appendJavascripts.equals(that.appendJavascripts);
259:                }
260:                return false;
261:            }
262:
263:            /**
264:             * @see wicket.IRequestTarget#getLock(RequestCycle)
265:             */
266:            public Object getLock(final RequestCycle requestCycle) {
267:                return requestCycle.getSession();
268:            }
269:
270:            /**
271:             * @see java.lang.Object#hashCode()
272:             */
273:            public int hashCode() {
274:                int result = "AjaxRequestTarget".hashCode();
275:                result += markupIdToComponent.hashCode() * 17;
276:                result += prependJavascripts.hashCode() * 17;
277:                result += appendJavascripts.hashCode() * 17;
278:                return result;
279:            }
280:
281:            /**
282:             * Adds javascript that will be evaluated on the client side before
283:             * components are replaced
284:             * 
285:             * @param javascript
286:             */
287:            public final void prependJavascript(String javascript) {
288:                if (javascript == null) {
289:                    throw new IllegalArgumentException(
290:                            "javascript cannot be null");
291:                }
292:
293:                prependJavascripts.add(javascript);
294:            }
295:
296:            /**
297:             * @see wicket.IRequestTarget#respond(wicket.RequestCycle)
298:             */
299:            public final void respond(final RequestCycle requestCycle) {
300:                try {
301:                    final Application app = Application.get();
302:
303:                    // Determine encoding
304:                    final String encoding = app.getRequestCycleSettings()
305:                            .getResponseRequestEncoding();
306:
307:                    // Set content type based on markup type for page
308:                    WebResponse response = (WebResponse) requestCycle
309:                            .getResponse();
310:                    response.setCharacterEncoding(encoding);
311:                    response.setContentType("text/xml; charset=" + encoding);
312:
313:                    // Make sure it is not cached by a client
314:                    response.setHeader("Expires",
315:                            "Mon, 26 Jul 1997 05:00:00 GMT");
316:                    response.setHeader("Cache-Control",
317:                            "no-cache, must-revalidate");
318:                    response.setHeader("Pragma", "no-cache");
319:
320:                    response.write("<?xml version=\"1.0\" encoding=\"");
321:                    response.write(encoding);
322:                    response.write("\"?>");
323:                    response.write("<ajax-response>");
324:
325:                    // normal behavior
326:                    Iterator it = prependJavascripts.iterator();
327:                    while (it.hasNext()) {
328:                        String js = (String) it.next();
329:                        respondInvocation(response, js);
330:                    }
331:
332:                    it = markupIdToComponent.entrySet().iterator();
333:                    while (it.hasNext()) {
334:                        final Map.Entry entry = (Entry) it.next();
335:                        final Component component = (Component) entry
336:                                .getValue();
337:                        final String markupId = (String) entry.getKey();
338:
339:                        respondComponent(response, markupId, component);
340:                    }
341:
342:                    it = appendJavascripts.iterator();
343:                    while (it.hasNext()) {
344:                        String js = (String) it.next();
345:                        respondInvocation(response, js);
346:                    }
347:
348:                    response.write("</ajax-response>");
349:                } catch (RuntimeException ex) {
350:                    // log the error but output nothing in the response, parse
351:                    // failure
352:                    // of response will cause any javascript failureHandler to be
353:                    // invoked
354:                    LOG.error("Error while responding to an AJAX request: "
355:                            + toString(), ex);
356:                } finally {
357:                    // clean up the page
358:                    if (markupIdToComponent.size() > 0) {
359:                        final Component c = (Component) markupIdToComponent
360:                                .values().iterator().next();
361:                        c.getPage().internalDetach();
362:                    }
363:                }
364:            }
365:
366:            /**
367:             * @see java.lang.Object#toString()
368:             */
369:            public String toString() {
370:                return "[AjaxRequestTarget@" + hashCode()
371:                        + " markupIdToComponent [" + markupIdToComponent
372:                        + "], prependJavascript [" + prependJavascripts
373:                        + "], appendJavascript [" + appendJavascripts + "]";
374:            }
375:
376:            /**
377:             * Encodes a string so it is safe to use inside CDATA blocks
378:             * 
379:             * @param str
380:             * @return encoded string
381:             */
382:            protected String encode(String str) {
383:                // TODO Post 1.2: Java5: we can use str.replace(charseq, charseq) for
384:                // more efficient replacement
385:                return str.replaceAll("]", "]^");
386:            }
387:
388:            /**
389:             * @return name of encoding used to possibly encode the contents of the
390:             *         CDATA blocks
391:             */
392:            protected String getEncodingName() {
393:                return "wicket1";
394:            }
395:
396:            /**
397:             * 
398:             * @param str
399:             * @return true if string needs to be encoded, false otherwise
400:             */
401:            protected boolean needsEncoding(String str) {
402:                /*
403:                 * TODO Post 1.2: Ajax: we can improve this by keeping a buffer of at
404:                 * least 3 characters and checking that buffer so that we can narrow
405:                 * down escaping occuring only for ']]>' sequence, or at least for ]] if ]
406:                 * is the last char in this buffer.
407:                 * 
408:                 * but this improvement will only work if we write first and encode
409:                 * later instead of working on fragments sent to write
410:                 */
411:
412:                return str.indexOf(']') >= 0;
413:            }
414:
415:            /**
416:             * 
417:             * @param response
418:             * @param markupId
419:             *            id of client-side dom element
420:             * @param component
421:             *            component to render
422:             */
423:            private void respondComponent(final Response response,
424:                    final String markupId, final Component component) {
425:                if (component.getRenderBodyOnly() == true) {
426:                    throw new IllegalStateException(
427:                            "Ajax render cannot be called on component that has setRenderBodyOnly enabled. Component: "
428:                                    + component.toString());
429:                }
430:
431:                component.setOutputMarkupId(true);
432:
433:                // substitute our encoding response for the real one so we can capture
434:                // component's markup in a manner safe for transport inside CDATA block
435:                final Response originalResponse = response;
436:                encodingBodyResponse.reset();
437:                RequestCycle.get().setResponse(encodingBodyResponse);
438:
439:                // Initialize temporary variables
440:                final Page page = component.getPage();
441:                if (page == null) {
442:                    throw new IllegalStateException(
443:                            "Ajax request attempted on a component that is not associated with a Page");
444:                }
445:
446:                final boolean versioned = page.isVersioned();
447:                page.setVersioned(false);
448:
449:                page.startComponentRender(component);
450:                component.renderComponent();
451:
452:                respondHeaderContribution(response, component);
453:
454:                page.endComponentRender(component);
455:
456:                page.setVersioned(versioned);
457:
458:                // Restore original response
459:                RequestCycle.get().setResponse(originalResponse);
460:
461:                response.write("<component id=\"");
462:                response.write(markupId);
463:                response.write("\" ");
464:                if (encodingBodyResponse.isContentsEncoded()) {
465:                    response.write(" encoding=\"");
466:                    response.write(getEncodingName());
467:                    response.write("\" ");
468:                }
469:                response.write("><![CDATA[");
470:                response.write(encodingBodyResponse.getContents());
471:                response.write("]]></component>");
472:
473:                encodingBodyResponse.reset();
474:            }
475:
476:            /**
477:             * 
478:             * @param response
479:             * @param component
480:             */
481:            private void respondHeaderContribution(final Response response,
482:                    final Component component) {
483:                final HtmlHeaderContainer header = new HtmlHeaderContainer(
484:                        HtmlHeaderSectionHandler.HEADER_ID);
485:                if (component.getPage().get(HtmlHeaderSectionHandler.HEADER_ID) != null) {
486:                    component.getPage().replace(header);
487:                } else {
488:                    component.getPage().add(header);
489:                }
490:
491:                Response oldResponse = RequestCycle.get().setResponse(
492:                        encodingHeaderResponse);
493:
494:                encodingHeaderResponse.reset();
495:
496:                component.renderHead(header);
497:                component.detachBehaviors();
498:                if (component instanceof  MarkupContainer) {
499:                    ((MarkupContainer) component)
500:                            .visitChildren(new Component.IVisitor() {
501:                                public Object component(Component component) {
502:                                    if (component.isVisible()) {
503:                                        component.renderHead(header);
504:                                        component.detachBehaviors();
505:                                        return CONTINUE_TRAVERSAL;
506:                                    } else {
507:                                        return CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
508:                                    }
509:                                }
510:                            });
511:                }
512:
513:                RequestCycle.get().setResponse(oldResponse);
514:
515:                if (encodingHeaderResponse.getContents().length() != 0) {
516:                    response.write("<header-contribution");
517:
518:                    if (encodingHeaderResponse.isContentsEncoded()) {
519:                        response.write(" encoding=\"");
520:                        response.write(getEncodingName());
521:                        response.write("\" ");
522:                    }
523:
524:                    // we need to write response as CDATA and parse it on client,
525:                    // because
526:                    // konqueror crashes when there is a <script> element
527:                    response
528:                            .write("><![CDATA[<head xmlns:wicket=\"http://wicket.sourceforge.net\">");
529:
530:                    response.write(encodingHeaderResponse.getContents());
531:
532:                    response.write("</head>]]>");
533:
534:                    response.write("</header-contribution>");
535:                }
536:            }
537:
538:            /**
539:             * 
540:             * @param response
541:             * @param js
542:             */
543:            private void respondInvocation(final Response response,
544:                    final String js) {
545:                boolean encoded = false;
546:                String javascript = js;
547:
548:                // encode the response if needed
549:                if (needsEncoding(js)) {
550:                    encoded = true;
551:                    javascript = encode(js);
552:                }
553:
554:                response.write("<evaluate");
555:                if (encoded) {
556:                    response.write(" encoding=\"");
557:                    response.write(getEncodingName());
558:                    response.write("\"");
559:                }
560:                response.write(">");
561:                response.write("<![CDATA[");
562:                response.write(javascript);
563:                response.write("]]>");
564:                response.write("</evaluate>");
565:
566:                encodingBodyResponse.reset();
567:            }
568:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.