View Javadoc

1   /*
2    * Copyright (c) 2001 Peter Antman Tim <peter.antman@tim.se>
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2 of the License, or (at your option) any later version
8    * 
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   * 
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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     // Should we allways throw a MallformedURLEx when resource is not found,
169     // or should we have an IO exception also?????
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 	// Try get it from registry
189 	URLFactory f = (URLFactory)registry.get(schema);
190 	if (f != null) {
191 	    url = f.getURL(uri);
192 	}else{
193 	    // Try a normal URL, or should we register it under url schema ?
194 	    try {
195 		url = new URL(uri.toExternalForm()); 
196 		
197 	    }catch(MalformedURLException ex) {
198 	    }
199 	}
200 	if ( url == null) {
201            // use default as a last resort, may handle the schema ;-)
202            f = (URLFactory)registry.get("default");
203            url = f.getURL(uri);
204            
205         } // end of if ()
206         
207 	//If url is still null, should is it good to thow Malformed?
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 } // URIFactory
243 
244 
245 
246 
247 
248 
249 
250