Source code: echopoint/template/SwitchedDataSource.java
1 package echopoint.template;
2 /*
3 * This file is part of the Echo Point Project. This project is a collection
4 * of Components that have extended the Echo Web Application Framework.
5 *
6 * EchoPoint is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * EchoPoint is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with Echo Point; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URL;
26
27 import javax.servlet.ServletContext;
28
29 import nextapp.echo.EchoInstance;
30 import nextapp.echoservlet.ServerContext;
31
32 import echopoint.util.URLKit;
33
34
35 /**
36 * <code>SwitchedDataSource</code> allows you to use a
37 * 3 step strategy for finding HTML template data.
38 * <p>
39 * Step 1:<p>
40 * This class will first look for the existence of a file and if it
41 * exists then it will use it as the template data source. The file
42 * name is defined as <code>fileDirectoryPrefix</code> + <code>fileOrResourceName</code>
43 * <p>
44 * Step 2:<p>
45 * Faling that, if you provide an EchoInstance, it will retrieve the
46 * javax.servlet.ServletContext from the instance and attempt to
47 * load it using <code>javax.servlet.ServletContext.getResource(java.lang.String)</code>
48 * and the <code>fileOrResourceName</code>. This step allows you to
49 * access resources in your web application that are not under a
50 * class path directory.
51 * <p>
52 * Step 3:<p>
53 * If ServletContext.getResource() fails or the EchoIntance is null, it will then
54 * attempt to load the template data as a class resource
55 * via Class.getResource(java.lang.String).
56 * <p>
57 * This class is useful when moving between development and production.
58 * For example, in development your templates may reside in your
59 * web project source directory (probably under source control).
60 * <p>
61 * Then when you move to production, they will reside as class resources
62 * under the web application servlet context root directory or
63 * WEB-INF/classes directory of your web application.
64 * <p>
65 * This class will allow for easier template changes during development
66 * and testing and then use class loading in production.
67 * <p>
68 * You would use this class something like this :
69 * <blockquote><pre>
70 * ds = new SwitchedDataSource(
71 * "/java/myproject/finance/src",
72 * "/com/bankwest/templates/login.html",
73 * getEchoInstance());
74 *
75 * template.setTemplate(ds);
76 * </pre></blockquote>
77 *
78 * In the above example the <code>SwitchedDataSource</code> will
79 * first look for the template data as a File in :
80 * <blockquote><pre>
81 * "/java/myproject/finance/src/com/bankwest/templates/login.html"
82 * </pre></blockquote>
83 * Then if this file cant be found it will load the template data as
84 * a ServletContext resource using the name :
85 * <blockquote><pre>
86 * "/com/bankwest/templates/login.html"
87 * </pre></blockquote>
88 * Finally if this files it will load the template data as
89 * a Class resource using the name :
90 * <blockquote><pre>
91 * "/com/bankwest/templates/login.html"
92 * </pre></blockquote>
93 *
94 * @see echopoint.util.URLKit#locate(String, String, EchoInstance, Class)
95 */
96 public class SwitchedDataSource implements DataSource {
97
98 private CachedFileDataSource cachedDS;
99
100 /**
101 * Constructs a <code>SwitchedDataSource</code> that
102 * locates the template data using the following strategy :
103 * <p>
104 * Step 1 : Looks for a file called 'fileDirectoryPrefix + fileOrResourceName'
105 * <p>
106 * Step 2 : failing that, it will a Class.getResource(fileOrResourceName)
107 *
108 * @param fileDirectoryPrefix - the directory prefix to use when looking
109 * initially for the File. May be null.
110 * @param fileOrResourceName - the file or class resource name to use.
111 *
112 * @throws IOException
113 * @throws UnsupportedEncodingException
114 *
115 * @see Class#getResource(java.lang.String)
116 * @see echopoint.util.URLKit#locate(String, String, EchoInstance, Class)
117 */
118 public SwitchedDataSource(String fileDirectoryPrefix, String fileOrResourceName) throws IOException {
119 this(fileDirectoryPrefix,fileOrResourceName,null,AbstractDataSource.DEFAULT_ENCODING, SwitchedDataSource.class);
120 }
121
122
123 /**
124 * Constructs a <code>SwitchedDataSource</code> that
125 * locates the template data using the following strategy :
126 * <p>
127 * Step 1 : Looks for a file called 'fileDirectoryPrefix + fileOrResourceName'
128 * <p>
129 * Step 2 : failing that, it uses the EchoInstance to locate the URL
130 * via ServletContext.getResource(fileOrResourceName), if the
131 * EchoInstance is not null.
132 * <p>
133 * Step 3 : failing that, it will a Class.getResource(fileOrResourceName)
134 *
135 * @param fileDirectoryPrefix - the directory prefix to use when looking
136 * initially for the File. May be null.
137 * @param fileOrResourceName - the file or class resource name to use.
138 * @param echoInstance - the EchoInstance to retreive the ServletContext from. This
139 * can be null, in which case ServletContext resource loading
140 * will not be used.
141 *
142 * @throws IOException
143 * @throws UnsupportedEncodingException
144 *
145 * @see Class#getResource(java.lang.String)
146 * @see echopoint.util.URLKit#locate(String, String, EchoInstance, Class)
147 */
148 public SwitchedDataSource(String fileDirectoryPrefix, String fileOrResourceName, EchoInstance echoInstance) throws IOException {
149 this(fileDirectoryPrefix,fileOrResourceName,echoInstance,AbstractDataSource.DEFAULT_ENCODING, SwitchedDataSource.class);
150 }
151
152 /**
153 * Constructs a <code>SwitchedDataSource</code> that
154 * locates the template data using the following strategy :
155 * <p>
156 * Step 1 : Looks for a file called 'fileDirectoryPrefix + fileOrResourceName'
157 * <p>
158 * Step 2 : failing that, it uses the EchoInstance to locate the URL
159 * via ServletContext.getResource(fileOrResourceName), if the
160 * EchoInstance is not null.
161 * <p>
162 * Step 3 : failing that, it will a Class.getResource(fileOrResourceName)
163 *
164 * @param fileDirectoryPrefix - the directory prefix to use when looking
165 * initially for the File. May be null.
166 * @param fileOrResourceName - the file or class resource name to use.
167 * @param encoding - the character encoding to use when reading the data
168 *
169 * @throws IOException
170 * @throws UnsupportedEncodingException
171 *
172 * @see Class#getResource(java.lang.String)
173 * @see echopoint.util.URLKit#locate(String, String, EchoInstance, Class)
174 */
175 public SwitchedDataSource(String fileDirectoryPrefix, String fileOrResourceName, String encoding) throws IOException, UnsupportedEncodingException {
176 this(fileDirectoryPrefix, fileOrResourceName, null, encoding, SwitchedDataSource.class);
177 }
178
179
180 /**
181 * Constructs a <code>SwitchedDataSource</code> that
182 * locates the template data using the following strategy :
183 * <p>
184 * Step 1 : Looks for a file called 'fileDirectoryPrefix + fileOrResourceName'
185 * <p>
186 * Step 2 : failing that, it uses the EchoInstance to locate the URL
187 * via ServletContext.getResource(fileOrResourceName), if the
188 * EchoInstance is not null.
189 * <p>
190 * Step 3 : failing that, it will a Class.getResource(fileOrResourceName)
191 *
192 * @param fileDirectoryPrefix - the directory prefix to use when looking
193 * initially for the File. May be null.
194 * @param fileOrResourceName - the file or class resource name to use.
195 * @param echoInstance - the EchoInstance to retreive the ServletContext from. This
196 * can be null, in which case ServletContext resource loading
197 * will not be used.
198 * @param encoding - the character encoding to use when reading the data
199 * @param resourceClass - the class to use when loading the resource data via
200 * Class.getResource(java.lang.String)
201 *
202 * @throws IOException
203 * @throws UnsupportedEncodingException
204 *
205 * @see Class#getResource(java.lang.String)
206 * @see echopoint.util.URLKit#locate(String, String, EchoInstance, Class)
207 */
208 public SwitchedDataSource(String fileDirectoryPrefix, String fileOrResourceName, EchoInstance echoInstance, String encoding, Class resourceClass) throws IOException, UnsupportedEncodingException {
209 if (fileOrResourceName == null && fileDirectoryPrefix == null)
210 throw new IllegalArgumentException(" The SwitchedDataSource fileDirectoryPrefix or the fileOrResourceName must be non null!");
211
212 if (resourceClass == null)
213 resourceClass = SwitchedDataSource.class;
214
215 cachedDS = null;
216 String fileName = fileOrResourceName;
217 if (fileDirectoryPrefix != null)
218 fileName = fileDirectoryPrefix + fileOrResourceName;
219
220 //
221 // So that the DataSource lastModified time is still valid
222 // for files we use the File invocation if the file exists, otherwise
223 // we move onto standard URLKit processing
224 File file = new File(fileName);
225 if (file.exists()) {
226 cachedDS = new CachedFileDataSource(file,CachedFileDataSource.CACHED_SIZE_LIMIT,encoding);
227 cachedDS.lastModified();
228 }
229 //
230 // Try the ServletContext and get the real file path. That way
231 // last modified processing will still work!
232 if (cachedDS == null && echoInstance != null) {
233 ServerContext echoServerC = (ServerContext) echoInstance.getAttribute(ServerContext.ATTRIBUTE_NAME);
234 if (echoServerC != null) {
235 ServletContext sc = echoServerC.getServletConfig().getServletContext();
236 String realFileName = sc.getRealPath(fileOrResourceName);
237 file = new File(realFileName);
238 if (file.exists()) {
239 cachedDS = new CachedFileDataSource(file,CachedFileDataSource.CACHED_SIZE_LIMIT,encoding);
240 cachedDS.lastModified();
241 }
242 }
243 }
244
245 //
246 // File isnt any good lets try the URLKit way!
247 if (cachedDS == null) {
248 URL url = URLKit.locate(fileDirectoryPrefix,fileOrResourceName,echoInstance,resourceClass);
249 if (url == null)
250 throw new IllegalArgumentException("The SwitchedDataSource class resource could not be loaded : '" + fileOrResourceName + "' nor could the file : '" + fileName + "'");
251 cachedDS = new CachedFileDataSource(url,encoding);
252 }
253 }
254
255 /**
256 * @see echopoint.template.DataSource#getCanonicalName()
257 */
258 public String getCanonicalName() {
259 return cachedDS.getCanonicalName();
260 }
261
262 /**
263 * @see echopoint.template.DataSource#getCharacterEncoding()
264 */
265 public String getCharacterEncoding() {
266 return cachedDS.getCharacterEncoding();
267 }
268
269 /**
270 * @see echopoint.template.DataSource#getInputReader()
271 */
272 public Reader getInputReader() throws IOException {
273 return cachedDS.getInputReader();
274 }
275
276 /**
277 * @see echopoint.template.DataSource#lastModified()
278 */
279 public long lastModified() {
280 return cachedDS.lastModified();
281 }
282
283 }