View Javadoc

1   package org.apache.torque.generator.template;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  import java.io.Reader;
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.torque.generator.configuration.ConfigurationException;
32  import org.apache.torque.generator.configuration.ConfigurationProvider;
33  import org.apache.torque.generator.control.ControllerState;
34  import org.apache.torque.generator.control.TokenReplacer;
35  import org.apache.torque.generator.outlet.OutletImpl;
36  import org.apache.torque.generator.qname.QualifiedName;
37  
38  /**
39   * An implementation of the TemplateOutlet interface.
40   */
41  public abstract class TemplateOutletImpl
42          extends OutletImpl
43          implements TemplateOutlet
44  {
45      /** The log of the class. */
46      private static Log log = LogFactory.getLog(TemplateOutletImpl.class);
47  
48      /**
49       * The content of the templates.
50       * The key is the resolved template path, the value is the template content.
51       * There may be more than one template content per template because
52       * the template path can contain tokens.
53       */
54      private final Map<String, String> contentMap = new HashMap<String, String>();
55  
56      /**
57       * The path to the template. May contain unresolved tokens.
58       */
59      private String path = null;
60  
61      /**
62       * The encoding of the template.
63       */
64      private String encoding = null;
65  
66      /**
67       * The configuration provider for accessing the template content.
68       */
69      private final ConfigurationProvider configurationProvider;
70  
71      /**
72       * The Filter for filtering the template content.
73       */
74      private final TemplateFilter templateFilter;
75  
76      /** Buffer size for loading the template File. */
77      private static final int LOAD_BUFFER_SIZE = 8192;
78  
79      /**
80       * How many characters of a template content should be output
81       * in the toString method.
82       */
83      private static final int CONTENT_TO_STRING_MAX_OUTPUT_LENGTH = 40;
84  
85      /**
86       * Constructs a TemplateOutletImpl with the given name.
87       *
88       * @param name the name of this outlet, not null.
89       * @param configurationProvider the provider for reading the templates,
90       *        not null.
91       * @param path the path to the templates, not null.
92       *        May contain tokens of the form ${....}, these are parsed.
93       * @param encoding the encoding of the file, or null if the system's
94       *        default encoding should be used.
95       * @param templateFilter a possible filter for preprocessing the template,
96       *        not null.
97       *
98       * @throws NullPointerException if name or inputStream are null.
99       * @throws ConfigurationException if the template cannot be loaded.
100      */
101     protected TemplateOutletImpl(
102             QualifiedName name,
103             ConfigurationProvider configurationProvider,
104             String path,
105             String encoding,
106             TemplateFilter templateFilter)
107         throws ConfigurationException
108     {
109         super(name);
110         if (configurationProvider == null)
111         {
112             throw new NullPointerException(
113                     "configurationProvider must not be null");
114         }
115         if (path == null)
116         {
117             throw new NullPointerException("path must not be null");
118         }
119         this.configurationProvider = configurationProvider;
120         this.path = path;
121         this.encoding = encoding;
122         this.templateFilter = templateFilter;
123     }
124 
125     public String getContent(ControllerState controllerState)
126             throws ConfigurationException
127     {
128         TokenReplacer tokenReplacer = new TokenReplacer(controllerState);
129         String detokenizedPath = tokenReplacer.process(path);
130 
131         String result = contentMap.get(detokenizedPath);
132         if (result == null)
133         {
134             InputStream templateInputStream = null;
135             try
136             {
137                 templateInputStream
138                         = configurationProvider.getTemplateInputStream(
139                             detokenizedPath);
140                 result = load(templateInputStream, encoding, templateFilter);
141             }
142             catch (IOException e)
143             {
144                 throw new ConfigurationException(e);
145             }
146             finally
147             {
148                 if (templateInputStream != null)
149                 {
150                     try
151                     {
152                         templateInputStream.close();
153                     }
154                     catch (IOException e)
155                     {
156                         log.warn("Could not close template reader", e);
157                     }
158                 }
159             }
160             contentMap.put(detokenizedPath, result);
161         }
162 
163         return result;
164     }
165 
166     /**
167      * Loads the template, possibly filtering the content..
168      *
169      * @param inputStream the stream to read from.
170      * @param encoding the encoding of the template, or null for auto detection.
171      * @param filter a filter for modifying the template,
172      *        or null for no filtering.
173      *
174      * @return the content of the read and filtered template.
175      *
176      * @throws IOException if an error occurs while reading the template.
177      */
178     protected String load(
179             InputStream inputStream,
180             String encoding,
181             TemplateFilter filter)
182         throws IOException
183     {
184         InputStream filteredStream;
185         if (filter != null)
186         {
187             filteredStream = filter.filter(inputStream, encoding);
188         }
189         else
190         {
191             filteredStream = inputStream;
192         }
193         Reader reader;
194         if (encoding == null)
195         {
196             reader = new InputStreamReader(filteredStream);
197         }
198         else
199         {
200             reader = new InputStreamReader(filteredStream, encoding);
201         }
202 
203         StringBuffer contentBuffer = new StringBuffer();
204         while (true)
205         {
206             char[] charBuffer = new char[LOAD_BUFFER_SIZE];
207             int filledChars = reader.read(charBuffer);
208             if (filledChars == -1)
209             {
210                 break;
211             }
212             contentBuffer.append(charBuffer, 0, filledChars);
213         }
214 
215         return contentBuffer.toString();
216     }
217 
218     /**
219      * Returns a String representation of this outlet for debugging purposes.
220      *
221      * @return a String representation of this outlet, never null.
222      *
223      * @see Object#toString()
224      */
225     @Override
226     public String toString()
227     {
228         StringBuffer result = new StringBuffer(super.toString()).append(",");
229         result.append("encoding=").append(encoding).append(",");
230         result.append("content=");
231         if (!contentMap.isEmpty())
232         {
233             String firstContent = contentMap.values().iterator().next();
234             if (firstContent.length() > CONTENT_TO_STRING_MAX_OUTPUT_LENGTH)
235             {
236                 result.append(firstContent.substring(
237                         0,
238                         CONTENT_TO_STRING_MAX_OUTPUT_LENGTH));
239             }
240             else
241             {
242                 result.append(firstContent);
243             }
244         }
245         return result.toString();
246     }
247 }