Source Code Cross Referenced for XsltView.java in  » J2EE » spring-framework-2.0.6 » org » springframework » web » servlet » view » xslt » 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 » spring framework 2.0.6 » org.springframework.web.servlet.view.xslt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2002-2007 the original author or authors.
003:         *
004:         * Licensed under the Apache License, Version 2.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         *
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         *
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:
017:        package org.springframework.web.servlet.view.xslt;
018:
019:        import java.io.IOException;
020:        import java.io.InputStream;
021:        import java.io.Reader;
022:        import java.util.Enumeration;
023:        import java.util.Iterator;
024:        import java.util.Map;
025:        import java.util.Properties;
026:
027:        import javax.servlet.http.HttpServletRequest;
028:        import javax.servlet.http.HttpServletResponse;
029:        import javax.xml.transform.ErrorListener;
030:        import javax.xml.transform.OutputKeys;
031:        import javax.xml.transform.Result;
032:        import javax.xml.transform.Source;
033:        import javax.xml.transform.Templates;
034:        import javax.xml.transform.Transformer;
035:        import javax.xml.transform.TransformerConfigurationException;
036:        import javax.xml.transform.TransformerFactory;
037:        import javax.xml.transform.URIResolver;
038:        import javax.xml.transform.dom.DOMSource;
039:        import javax.xml.transform.stream.StreamResult;
040:        import javax.xml.transform.stream.StreamSource;
041:
042:        import org.w3c.dom.Document;
043:        import org.w3c.dom.Node;
044:
045:        import org.springframework.beans.BeansException;
046:        import org.springframework.context.ApplicationContextException;
047:        import org.springframework.core.io.Resource;
048:        import org.springframework.util.CollectionUtils;
049:        import org.springframework.util.ObjectUtils;
050:        import org.springframework.util.StringUtils;
051:        import org.springframework.util.xml.SimpleTransformErrorListener;
052:        import org.springframework.web.servlet.view.AbstractUrlBasedView;
053:        import org.springframework.web.util.WebUtils;
054:
055:        /**
056:         * XSLT-driven View that allows for response context to be rendered as the
057:         * result of an XSLT transformation.
058:         *
059:         * <p>The XSLT Source object is supplied as a parameter in the model and then
060:         * {@link #locateSource detected} during response rendering. Users can either specify
061:         * a specific entry in the model via the {@link #setSourceKey sourceKey} property or
062:         * have Spring locate the Source object. This class also provides basic conversion
063:         * of objects into Source implementations. See {@link #getSourceTypes() here}
064:         * for more details.
065:         *
066:         * <p>All model parameters are passed to the XSLT Transformer as parameters.
067:         * In addition the user can configure {@link #setOutputProperties output properties}
068:         * to be passed to the Transformer.
069:         *
070:         * @author Rob Harrop
071:         * @author Juergen Hoeller
072:         * @since 2.0
073:         */
074:        public class XsltView extends AbstractUrlBasedView {
075:
076:            private final TransformerFactory transformerFactory = TransformerFactory
077:                    .newInstance();
078:
079:            private String sourceKey;
080:
081:            private URIResolver uriResolver;
082:
083:            private ErrorListener errorListener = new SimpleTransformErrorListener(
084:                    logger);
085:
086:            private boolean indent = true;
087:
088:            private Properties outputProperties;
089:
090:            private boolean cacheTemplates = true;
091:
092:            private Templates cachedTemplates;
093:
094:            /**
095:             * Set the name of the model attribute that represents the XSLT Source.
096:             * If not specified, the model map will be searched for a matching value type.
097:             * <p>The following source types are supported out of the box:
098:             * {@link Source}, {@link Document}, {@link Node}, {@link Reader},
099:             * {@link InputStream} and {@link Resource}.
100:             * @see #getSourceTypes
101:             * @see #convertSource
102:             */
103:            public void setSourceKey(String sourceKey) {
104:                this .sourceKey = sourceKey;
105:            }
106:
107:            /**
108:             * Set the URIResolver used in the transform.
109:             * <p>The URIResolver handles calls to the XSLT <code>document()</code> function.
110:             */
111:            public void setUriResolver(URIResolver uriResolver) {
112:                this .uriResolver = uriResolver;
113:            }
114:
115:            /**
116:             * Set an implementation of the {@link javax.xml.transform.ErrorListener}
117:             * interface for custom handling of transformation errors and warnings.
118:             * <p>If not set, a default
119:             * {@link org.springframework.util.xml.SimpleTransformErrorListener} is
120:             * used that simply logs warnings using the logger instance of the view class,
121:             * and rethrows errors to discontinue the XML transformation.
122:             * @see org.springframework.util.xml.SimpleTransformErrorListener
123:             */
124:            public void setErrorListener(ErrorListener errorListener) {
125:                this .errorListener = (errorListener != null ? errorListener
126:                        : new SimpleTransformErrorListener(logger));
127:            }
128:
129:            /**
130:             * Set whether the XSLT transformer may add additional whitespace when
131:             * outputting the result tree.
132:             * <p>Default is <code>true</code> (on); set this to <code>false</code> (off)
133:             * to not specify an "indent" key, leaving the choice up to the stylesheet.
134:             * @see javax.xml.transform.OutputKeys#INDENT
135:             */
136:            public void setIndent(boolean indent) {
137:                this .indent = indent;
138:            }
139:
140:            /**
141:             * Set arbitrary transformer output properties to be applied to the stylesheet.
142:             * <p>Any values specified here will override defaults that this view sets
143:             * programmatically.
144:             * @see javax.xml.transform.Transformer#setOutputProperty
145:             */
146:            public void setOutputProperties(Properties outputProperties) {
147:                this .outputProperties = outputProperties;
148:            }
149:
150:            /**
151:             * Turn on/off the caching of the XSLT {@link Templates} instance.
152:             * <p>The default value is "true". Only set this to "false" in development,
153:             * where caching does not seriously impact performance.
154:             */
155:            public void setCacheTemplates(boolean cacheTemplates) {
156:                this .cacheTemplates = cacheTemplates;
157:            }
158:
159:            /**
160:             * Initialize this XsltView's TransformerFactory.
161:             */
162:            protected void initApplicationContext() throws BeansException {
163:                this .transformerFactory.setErrorListener(this .errorListener);
164:
165:                if (this .uriResolver != null) {
166:                    if (logger.isInfoEnabled()) {
167:                        logger.info("Using custom URIResolver '"
168:                                + this .uriResolver
169:                                + "' in XSLT view with URL '" + getUrl() + "'");
170:                    }
171:                    this .transformerFactory.setURIResolver(this .uriResolver);
172:                }
173:
174:                if (logger.isDebugEnabled()) {
175:                    logger.debug("URL in view is '" + getUrl() + "'");
176:                }
177:
178:                if (this .cacheTemplates) {
179:                    this .cachedTemplates = loadTemplates();
180:                }
181:            }
182:
183:            /**
184:             * Return the TransformerFactory that this XsltView uses.
185:             * @return the TransformerFactory (never <code>null</code>)
186:             */
187:            protected final TransformerFactory getTransformerFactory() {
188:                return this .transformerFactory;
189:            }
190:
191:            protected void renderMergedOutputModel(Map model,
192:                    HttpServletRequest request, HttpServletResponse response)
193:                    throws Exception {
194:
195:                Templates templates = this .cachedTemplates;
196:                if (templates == null) {
197:                    templates = loadTemplates();
198:                }
199:
200:                Transformer transformer = createTransformer(templates);
201:                configureTransformer(model, response, transformer);
202:                configureResponse(model, response, transformer);
203:                Source source = null;
204:                try {
205:                    source = locateSource(model);
206:                    if (source == null) {
207:                        throw new IllegalArgumentException(
208:                                "Unable to locate Source object in model: "
209:                                        + model);
210:                    }
211:                    transformer.transform(source, createResult(response));
212:                } finally {
213:                    closeSourceIfNecessary(source);
214:                }
215:            }
216:
217:            /**
218:             * Create the XSLT {@link Result} used to render the result of the transformation.
219:             * <p>The default implementation creates a {@link StreamResult} wrapping the supplied
220:             * HttpServletResponse's {@link HttpServletResponse#getOutputStream() OutputStream}.
221:             * @param response current HTTP response
222:             * @return the XSLT Result to use
223:             * @throws Exception if the Result cannot be built
224:             */
225:            protected Result createResult(HttpServletResponse response)
226:                    throws Exception {
227:                return new StreamResult(response.getOutputStream());
228:            }
229:
230:            /**
231:             * <p>Locate the {@link Source} object in the supplied model,
232:             * converting objects as required.
233:             * The default implementation first attempts to look under the configured
234:             * {@link #setSourceKey source key}, if any, before attempting to locate
235:             * an object of {@link #getSourceTypes() supported type}.
236:             * @param model the merged model Map
237:             * @return the XSLT Source object (or <code>null</code> if none found)
238:             * @throws Exception if an error occured during locating the source
239:             * @see #setSourceKey
240:             * @see #convertSource
241:             */
242:            protected Source locateSource(Map model) throws Exception {
243:                if (this .sourceKey != null) {
244:                    return convertSource(model.get(this .sourceKey));
245:                }
246:                Object source = CollectionUtils.findValueOfType(model.values(),
247:                        getSourceTypes());
248:                return (source != null ? convertSource(source) : null);
249:            }
250:
251:            /**
252:             * Return the array of {@link Class Classes} that are supported when converting to an
253:             * XSLT {@link Source}.
254:             * <p>Currently supports {@link Source}, {@link Document}, {@link Node},
255:             * {@link Reader}, {@link InputStream} and {@link Resource}.
256:             * @return the supported source types
257:             */
258:            protected Class[] getSourceTypes() {
259:                return new Class[] { Source.class, Document.class, Node.class,
260:                        Reader.class, InputStream.class, Resource.class };
261:            }
262:
263:            /**
264:             * Convert the supplied {@link Object} into an XSLT {@link Source} if the
265:             * {@link Object} type is {@link #getSourceTypes() supported}.
266:             * @param source the original source object
267:             * @return the adapted XSLT Source
268:             * @throws IllegalArgumentException if the given Object is not of a supported type
269:             */
270:            protected Source convertSource(Object source) throws Exception {
271:                if (source instanceof  Source) {
272:                    return (Source) source;
273:                } else if (source instanceof  Document) {
274:                    return new DOMSource(((Document) source)
275:                            .getDocumentElement());
276:                } else if (source instanceof  Node) {
277:                    return new DOMSource((Node) source);
278:                } else if (source instanceof  Reader) {
279:                    return new StreamSource((Reader) source);
280:                } else if (source instanceof  InputStream) {
281:                    return new StreamSource((InputStream) source);
282:                } else if (source instanceof  Resource) {
283:                    return new StreamSource(((Resource) source)
284:                            .getInputStream());
285:                } else {
286:                    throw new IllegalArgumentException("Value '" + source
287:                            + "' cannot be converted to XSLT Source");
288:                }
289:            }
290:
291:            /**
292:             * Configure the supplied {@link Transformer} instance.
293:             * <p>The default implementation copies parameters from the model into the
294:             * Transformer's {@link Transformer#setParameter parameter set}.
295:             * This implementation also copies the {@link #setOutputProperties output properties}
296:             * into the {@link Transformer} {@link Transformer#setOutputProperty output properties}.
297:             * Indentation properties are set as well.
298:             * @param model merged output Map (never <code>null</code>)
299:             * @param response current HTTP response
300:             * @param transformer the target transformer
301:             * @see #copyModelParameters(Map, Transformer)
302:             * @see #copyOutputProperties(Transformer)
303:             * @see #configureIndentation(Transformer)
304:             */
305:            protected void configureTransformer(Map model,
306:                    HttpServletResponse response, Transformer transformer) {
307:                copyModelParameters(model, transformer);
308:                copyOutputProperties(transformer);
309:                configureIndentation(transformer);
310:            }
311:
312:            /**
313:             * Configure the indentation settings for the supplied {@link Transformer}.
314:             * @param transformer the target transformer
315:             * @throws IllegalArgumentException if the supplied {@link Transformer} is <code>null</code>
316:             * @see TransformerUtils#enableIndenting(javax.xml.transform.Transformer) 
317:             * @see TransformerUtils#disableIndenting(javax.xml.transform.Transformer)
318:             */
319:            protected final void configureIndentation(Transformer transformer) {
320:                if (this .indent) {
321:                    TransformerUtils.enableIndenting(transformer);
322:                } else {
323:                    TransformerUtils.disableIndenting(transformer);
324:                }
325:            }
326:
327:            /**
328:             * Copy the configured output {@link Properties}, if any, into the
329:             * {@link Transformer#setOutputProperty output property set} of the supplied
330:             * {@link Transformer}.
331:             * @param transformer the target transformer
332:             */
333:            protected final void copyOutputProperties(Transformer transformer) {
334:                if (this .outputProperties != null) {
335:                    Enumeration en = this .outputProperties.propertyNames();
336:                    while (en.hasMoreElements()) {
337:                        String name = (String) en.nextElement();
338:                        transformer.setOutputProperty(name,
339:                                this .outputProperties.getProperty(name));
340:                    }
341:                }
342:            }
343:
344:            /**
345:             * Copy all entries from the supplied Map into the
346:             * {@link Transformer#setParameter(String, Object) parameter set}
347:             * of the supplied {@link Transformer}.
348:             * @param model merged output Map (never <code>null</code>)
349:             * @param transformer the target transformer
350:             */
351:            protected final void copyModelParameters(Map model,
352:                    Transformer transformer) {
353:                copyMapEntriesToTransformerParameters(model, transformer);
354:            }
355:
356:            /**
357:             * Configure the supplied {@link HttpServletResponse}.
358:             * <p>The default implementation of this method sets the
359:             * {@link HttpServletResponse#setContentType content type} and
360:             * {@link HttpServletResponse#setCharacterEncoding encoding}
361:             * from the "media-type" and "encoding" output properties
362:             * specified in the {@link Transformer}.
363:             * @param model merged output Map (never <code>null</code>)
364:             * @param response current HTTP response
365:             * @param transformer the target transformer
366:             */
367:            protected void configureResponse(Map model,
368:                    HttpServletResponse response, Transformer transformer) {
369:                String contentType = getContentType();
370:                String mediaType = transformer
371:                        .getOutputProperty(OutputKeys.MEDIA_TYPE);
372:                String encoding = transformer
373:                        .getOutputProperty(OutputKeys.ENCODING);
374:                if (StringUtils.hasText(mediaType)) {
375:                    contentType = mediaType;
376:                }
377:                if (StringUtils.hasText(encoding)) {
378:                    // Only apply encoding if content type is specified but does not contain charset clause already.
379:                    if (contentType != null
380:                            && contentType.toLowerCase().indexOf(
381:                                    WebUtils.CONTENT_TYPE_CHARSET_PREFIX) == -1) {
382:                        contentType = contentType
383:                                + WebUtils.CONTENT_TYPE_CHARSET_PREFIX
384:                                + encoding;
385:                    }
386:                }
387:                response.setContentType(contentType);
388:            }
389:
390:            /**
391:             * Load the {@link Templates} instance for the stylesheet at the configured location.
392:             */
393:            private Templates loadTemplates()
394:                    throws ApplicationContextException {
395:                Source stylesheetSource = getStylesheetSource();
396:                try {
397:                    Templates templates = this .transformerFactory
398:                            .newTemplates(stylesheetSource);
399:                    if (logger.isDebugEnabled()) {
400:                        logger.debug("Loading templates '" + templates + "'");
401:                    }
402:                    return templates;
403:                } catch (TransformerConfigurationException ex) {
404:                    throw new ApplicationContextException(
405:                            "Can't load stylesheet from '" + getUrl() + "'", ex);
406:                } finally {
407:                    closeSourceIfNecessary(stylesheetSource);
408:                }
409:            }
410:
411:            /**
412:             * Create the {@link Transformer} instance used to prefer the XSLT transformation.
413:             * <p>The default implementation simply calls {@link Templates#newTransformer()}, and
414:             * configures the {@link Transformer} with the custom {@link URIResolver} if specified.
415:             * @param templates the XSLT Templates instance to create a Transformer for
416:             */
417:            protected Transformer createTransformer(Templates templates)
418:                    throws TransformerConfigurationException {
419:                Transformer transformer = templates.newTransformer();
420:                if (this .uriResolver != null) {
421:                    transformer.setURIResolver(this .uriResolver);
422:                }
423:                return transformer;
424:            }
425:
426:            /**
427:             * Get the XSLT {@link Source} for the XSLT template under the {@link #setUrl configured URL}.
428:             */
429:            protected Source getStylesheetSource() {
430:                String url = getUrl();
431:                if (logger.isDebugEnabled()) {
432:                    logger.debug("Loading XSLT stylesheet from '" + url + "'");
433:                }
434:                try {
435:                    Resource stylesheetResource = getApplicationContext()
436:                            .getResource(url);
437:                    String systemId = url
438:                            .substring(0, url.lastIndexOf('/') + 1);
439:                    return new StreamSource(
440:                            stylesheetResource.getInputStream(), systemId);
441:                } catch (IOException ex) {
442:                    throw new ApplicationContextException(
443:                            "Can't load XSLT stylesheet from '" + url + "'", ex);
444:                }
445:            }
446:
447:            /**
448:             * Copy all {@link Map.Entry entries} from the supplied {@link Map} into the
449:             * {@link Transformer#setParameter(String, Object) parameter set} of the supplied
450:             * {@link Transformer}.
451:             */
452:            private void copyMapEntriesToTransformerParameters(Map map,
453:                    Transformer transformer) {
454:                for (Iterator iterator = map.entrySet().iterator(); iterator
455:                        .hasNext();) {
456:                    Map.Entry entry = (Map.Entry) iterator.next();
457:                    transformer.setParameter(ObjectUtils.nullSafeToString(entry
458:                            .getKey()), entry.getValue());
459:                }
460:            }
461:
462:            /**
463:             * Close the underlying resource managed by the supplied {@link Source} if applicable.
464:             * <p>Only works for {@link StreamSource StreamSources}.
465:             * @param source the XSLT Source to close (may be <code>null</code>)
466:             */
467:            private void closeSourceIfNecessary(Source source) {
468:                if (source instanceof  StreamSource) {
469:                    StreamSource streamSource = (StreamSource) source;
470:                    if (streamSource.getReader() != null) {
471:                        try {
472:                            streamSource.getReader().close();
473:                        } catch (IOException ex) {
474:                        }
475:                    }
476:                    if (streamSource.getInputStream() != null) {
477:                        try {
478:                            streamSource.getInputStream().close();
479:                        } catch (IOException ex) {
480:                        }
481:                    }
482:                }
483:            }
484:
485:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.