1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.backsource.utils.resource;
19
20 import java.net.URL;
21 import java.net.MalformedURLException;
22 import java.util.HashMap;
23
24 /***
25 * <p>A factory that produces URI:s that translates URI:s to URL with
26 * the help of URLFactories.
27 *</p>
28 *
29 * <p>The factory do not only produce URI:s but is also the callback
30 * or factory used by URI:s to translate URI:s to URL. A URI created
31 * without any prior knowledge of the URIFactory will get a factory
32 * through the help of the URIFactoryContext wich is a helper class
33 * that may be used to create different type of singletons.</p>
34 *
35 * <p>The translation of a URI to a URL is dependant on the setup of
36 * the URI factory. The standard setup is that URI:s that resolves to
37 * URL:s are delegated as normal URL. URI:s that are not URL are
38 * delegated to other URLFactories, which is goverened by the schema
39 * part of the url. All schemaless URI:s and URI:s whose schma does to
40 * have a registered URLFactory is delegated to be loaded by the
41 * default URLFactory (which is configured in the
42 * ClassContextURLFactory.)</p>
43 *
44 * <p>Here are some typical usecases:</p>
45 *
46 * <ul class="noindent">
47 * <li>1. Simple, not setup of the context done anywhere in the
48 * VM.</li>
49 * </ul>
50 *
51 * <pre>
52 * URI uri = new URI("http://my.site");
53 * URL url = uri.getURL();//Will get the url to the site
54 *
55 * URI uri = new URI("my.properties");
56 * URL url = uri.getURL();//Will search the classpath and return an URL it.
57 * </pre>
58 *
59 * <ul class="noindent">
60 * <li>2. Configure an URLFactory and use it directly</li>
61 * </ul>
62 *
63 * <pre>
64 * // Preregistered is the "class:"
65 * // Registere different handler
66 * URIFactory f = new URIFactory();
67 * // Make a default wich searched first the servlet context then the
68 * // context classloader
69 * f.register("default:", new ServletFirstURLFactory( servletContext));
70 * //Registere a specific one for the servlet schema
71 * f.register("servlet:", new ServletURLFactory(servletContext));
72 * // Register an URLFactory that searches for resources backwards, i.e starts
73 * // in the leaf classloader.
74 * f.register("class", new ClassContextUrlFactory( new ReverseClassLoader(contextClassLoader)));
75 *
76 * // keep the URLFactory around programatically and use it in these three ways:
77 *
78 * // Use URI constructor
79 * URI uri = new URI("servlet:/WEB-INF/my.properties", f);
80 * URL url = uri.getURL();
81 *
82 * //User getURL method in URI
83 * URI uri = new URI("class:META-INF/descr.xml");
84 * URL url = uri.getURL(f);
85 *
86 * // Use factory direct
87 * URL url = f.getURL(uri);
88 * </pre>
89 *
90 * <ul class="noindent">
91 * <li>3. Configure a factory and set the URIFactoryContext.</li>
92 * </ul>
93 *
94 * <p>The URIFactory context is a classic singleton. It is used by the
95 * URI when the URIFactory is not know to URI. It has one static get
96 * method that returns a URIFactory. If no set method has been used it
97 * returns a default unconfigured URIFactory, which is available in
98 * the global JVM.</p>
99 *
100 * <p>URIFactoryContext however has several set-methods that may be
101 * use to localize the context and make a particular URIFactory
102 * available only in a particular context in the JVM. This gives great
103 * flexibility at the cost of some performance, since the algoritm
104 * will have to search bottom up to guarantee that the most localized
105 * version will be used. There are four ways to localize a factory
106 * currently:</p>
107 *
108 * <ul class="noindent">
109 * <li>1. set() - will make the factory available in the complete JVM
110 * (a classic singleton).</li>
111 *
112 * <li>2. setIntheritClassLocal - will make the factory available in
113 * the context classloader where the factory was set and in any child
114 * classloader.</li>
115 *
116 * <li>3. setClassLocal - will make the factory available only in the
117 * context classloader it was set.</li>
118 *
119 * <li>4. setThreadLocal - will make the factory available in the
120 * thread it was set in, typically has to be done in every
121 * invocation.</li>
122 * </ul>
123 *
124 * <p>What good is this? Say for example that you have to war-files
125 * (webapplications). Both want's to use the servlet context resource
126 * loading. Each webaplication then have to configure a URIFactory
127 * with its particular servlet context. With a normal singleton this
128 * is not possible. But by using for example setClassLocal it will be
129 * possible to do this. In the init method of a central servlet this
130 * could be done:</p>
131 *
132 * <pre>
133 * ServletURLFactory sf = new ServletURLFactory( servletConfig.getServletContext() );
134 * URIFactory f = new URIFactory();
135 * f.register("default", sf);
136 *
137 * URIFactoryContext.setClassLocal(f);
138 * </pre>
139 *
140 * <p>If, and this is important, the servlet engine uses a particular
141 * context class loader, it will be possible to use URI in any class
142 * used by all the servlets and jsp pages in the particular
143 * webapplication and the URI will automatically use the registered
144 * URIFactory and get resources from the servlet context. Created: Fri
145 * Feb 1 09:52:20 2002</p>
146 *
147 * @author Peter Antman
148 * @version $Id: URIFactory.java,v 1.1.1.1 2004/05/19 12:07:31 pra Exp $
149 */
150
151 public class URIFactory {
152 HashMap registry = new HashMap();
153
154 /***
155 * Create a URIFactory with a ClassURLFactory as default handler.
156 */
157 public URIFactory() {
158 this( new ClassContextURLFactory());
159 }
160
161 /***
162 * Create an URIFactory with sepcifyed default URLFactory.
163 */
164 public URIFactory(URLFactory defaultFactory) {
165 registry.put("default", defaultFactory);
166 }
167
168
169
170
171 /***
172 * Get an URL from URI (without using URI.getURL()).
173 *
174 * If no schema is given or no URLFactory is found for the given schema the
175 * default URLFactory will be used, except uri:s that are valid URL:s in
176 them self where an URL is constructed if no URLFactory was registered for the schema/protocol.
177 *
178 * @param uri an URI object. Its URLFactoryContext will not be used!
179 * @exception MalformedURLException if no URL was possible to constuct.
180 */
181 public URL getURL(URI uri) throws MalformedURLException {
182 URL url = null;
183
184 String schema = uri.getScheme();
185 if(schema == null)
186 schema = "default";
187
188
189 URLFactory f = (URLFactory)registry.get(schema);
190 if (f != null) {
191 url = f.getURL(uri);
192 }else{
193
194 try {
195 url = new URL(uri.toExternalForm());
196
197 }catch(MalformedURLException ex) {
198 }
199 }
200 if ( url == null) {
201
202 f = (URLFactory)registry.get("default");
203 url = f.getURL(uri);
204
205 }
206
207
208 if (url == null)
209 throw new MalformedURLException("Could not get an URL for uri: " + uri.toExternalForm());
210 else
211 return url;
212
213
214 }
215
216 /***
217 * Same as with URI as parameter.
218 *
219 * @param uri a string wich may be parsed into an URI.
220 */
221 public URL getURL(String uri) throws MalformedURLException {
222 URI u = null;
223 try {
224 u = new URI(uri);
225 }catch(MalformedURIException ex) {
226 throw new MalformedURLException(ex.toString());
227 }
228 return getURL(u);
229 }
230
231 /***
232 * Register an URLFactory for a schema. The schema name default will set
233 * the default URLFactory.
234 *
235 * @param schema an URI schema.
236 * @param factory an URLFactory handling the schema.
237 */
238 public void register(String schema, URLFactory factory) {
239 registry.put(schema,factory);
240 }
241
242 }
243
244
245
246
247
248
249
250