View Javadoc

1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.portletbridge.portlet;
17  
18  import java.io.StringReader;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.security.MessageDigest;
22  import java.security.NoSuchAlgorithmException;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import javax.xml.transform.ErrorListener;
28  import javax.xml.transform.Source;
29  import javax.xml.transform.Templates;
30  import javax.xml.transform.TransformerConfigurationException;
31  import javax.xml.transform.TransformerException;
32  import javax.xml.transform.TransformerFactory;
33  import javax.xml.transform.TransformerFactoryConfigurationError;
34  import javax.xml.transform.stream.StreamSource;
35  
36  import org.portletbridge.ResourceException;
37  
38  /***
39   * @author JMcCrindle
40   */
41  public class DefaultTemplateFactory implements TemplateFactory {
42  
43      private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
44              .getLog(DefaultTemplateFactory.class);
45      
46      private Templates defaultTemplate;
47  
48      private String defaultTemplateSytemId;
49      
50      private Map templateCache = Collections.synchronizedMap(new HashMap());
51  
52      public DefaultTemplateFactory() {
53          defaultTemplateSytemId = getClass().getResource(
54                  "/org/portletbridge/xsl/default.xsl").toExternalForm();
55          Source templateSource = new StreamSource(defaultTemplateSytemId);
56          try {
57              defaultTemplate = TransformerFactory.newInstance().newTemplates(
58                      templateSource);
59              log.debug("created default template");
60          } catch (TransformerConfigurationException e) {
61              throw new IllegalStateException(e.getMessage());
62          } catch (TransformerFactoryConfigurationError e) {
63              throw new IllegalStateException(e.getMessage());
64          }
65      }
66  
67      /***
68       * Creates compiled templates for a particular stylesheet for performance.
69       * 
70       * @param systemId
71       *            the stylesheet to compile
72       * @return @throws
73       *         ResourceException if the stylesheet could not be found.
74       * @throws TransformerFactoryConfigurationError
75       *             if there was a problem finding a suitable transformer
76       *             factory.
77       */
78      public Templates getTemplatesFromUrl(String systemId)
79              throws ResourceException, TransformerFactoryConfigurationError {
80          if (systemId == null) {
81              throw new ResourceException("error.stylesheet");
82          }
83          Templates result = null;
84          TransformerFactory factory = TransformerFactory.newInstance();
85          try {
86              // this means that the templatecache is going to be a mix
87              // of md5 checksums and urls
88              Templates templates = (Templates) templateCache.get(systemId);
89              if(templates != null) {
90                  return templates;
91              } else {
92                  URL resourceUrl = null;
93                  if (systemId.startsWith("classpath:")) {
94                      String substring = systemId.substring(10);
95                      resourceUrl = this.getClass().getResource(substring);
96                  } else {
97                      resourceUrl = new URL(systemId);
98                  }
99                  if (resourceUrl == null) {
100                     throw new ResourceException("error.stylesheet.notfound",
101                             systemId);
102                 }
103                 result = factory.newTemplates(new StreamSource(resourceUrl
104                         .toExternalForm()));
105                 templateCache.put(systemId, result);
106             }
107         } catch (TransformerConfigurationException e) {
108             throw new ResourceException("error.transformer", e.getMessage(), e);
109         } catch (MalformedURLException e) {
110             throw new ResourceException("error.stylesheet.url", e.getMessage(),
111                     e);
112         }
113         return result;
114     }
115 
116     /***
117      * Creates compiled templates for a particular stylesheet for performance.
118      * 
119      * @param stylesheet
120      *            the stylesheet to compile
121      * @return @throws
122      *         ResourceException if the stylesheet could not be found.
123      * @throws TransformerFactoryConfigurationError
124      *             if there was a problem finding a suitable transformer
125      *             factory.
126      */
127     public Templates getTemplatesFromString(String stylesheet)
128             throws ResourceException, TransformerFactoryConfigurationError {
129 
130         if (stylesheet == null || stylesheet.trim().length() == 0) {
131             return defaultTemplate;
132         }
133         Templates result = null;
134         TransformerFactory factory = TransformerFactory.newInstance();
135         final Exception[] exceptionHolder = new Exception[1];
136         factory.setErrorListener(new ErrorListener() {
137             public void error(TransformerException exception)
138                     throws TransformerException {
139                 exceptionHolder[0] = exception;
140             }
141 
142             public void fatalError(TransformerException exception)
143                     throws TransformerException {
144                 exceptionHolder[0] = exception;
145             }
146 
147             public void warning(TransformerException exception)
148                     throws TransformerException {
149                 exceptionHolder[0] = exception;
150             }
151         });
152 
153         try {
154             // caching but lots of object creation...
155             MessageDigest messageDigest = MessageDigest.getInstance("MD5");
156             messageDigest.update(stylesheet.getBytes());
157             String key = new String(messageDigest.digest());
158             Templates templates = (Templates) templateCache.get(key);
159             if(templates != null) {
160                 result = templates;
161             } else {
162                 result = factory.newTemplates(new StreamSource(new StringReader(
163                         stylesheet), defaultTemplateSytemId));
164                 templateCache.put(key, result);
165             }
166         } catch (TransformerConfigurationException e) {
167             exceptionHolder[0] = e;
168         } catch (NoSuchAlgorithmException e) {
169             exceptionHolder[0] = e;
170         }
171         if (exceptionHolder[0] != null) {
172             throw new ResourceException("error.transformer", exceptionHolder[0].getMessage(), exceptionHolder[0]);
173         }
174         return result;
175     }
176 
177 }