001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.util;
020:
021: import java.io.BufferedReader;
022: import java.io.IOException;
023: import java.io.InputStreamReader;
024: import java.net.URL;
025: import java.util.List;
026: import java.util.logging.Level;
027: import java.util.logging.Logger;
028:
029: import org.restlet.Application;
030: import org.restlet.Client;
031: import org.restlet.Component;
032: import org.restlet.Context;
033: import org.restlet.Directory;
034: import org.restlet.Server;
035: import org.restlet.data.CharacterSet;
036: import org.restlet.data.ClientInfo;
037: import org.restlet.data.Form;
038: import org.restlet.data.Language;
039: import org.restlet.data.Request;
040: import org.restlet.data.Response;
041: import org.restlet.resource.Representation;
042: import org.restlet.resource.Resource;
043: import org.restlet.resource.Variant;
044:
045: /**
046: * Facade to the engine implementating the Restlet API. Note that this is an SPI
047: * class that is not intended for public usage.
048: *
049: * @author Jerome Louvel (contact@noelios.com)
050: */
051: public abstract class Engine {
052: /** Obtain a suitable logger. */
053: private static Logger logger = Logger.getLogger(Engine.class
054: .getCanonicalName());
055:
056: /** Major version number. */
057: public static final String MAJOR_NUMBER = "1";
058:
059: /** Minor version number. */
060: public static final String MINOR_NUMBER = "0";
061:
062: /** Release number. */
063: public static final String RELEASE_NUMBER = ".8";
064:
065: /** Complete version. */
066: public static final String VERSION = MAJOR_NUMBER + '.'
067: + MINOR_NUMBER + '.' + RELEASE_NUMBER;
068:
069: /** The registered engine. */
070: private static Engine instance = null;
071:
072: /** Provider resource. */
073: private static final String providerResource = "META-INF/services/org.restlet.util.Engine";
074:
075: /** Classloader to use for dynamic class loading. */
076: private static ClassLoader classloader = Engine.class
077: .getClassLoader();
078:
079: /**
080: * Returns a class loader to use when creating instantiating implementation
081: * classes. By default, it reused the classloader of this Engine's class.
082: */
083: public static ClassLoader getClassLoader() {
084: return classloader;
085: }
086:
087: /**
088: * Returns the registered Restlet engine.
089: *
090: * @return The registered Restlet engine.
091: */
092: public static Engine getInstance() {
093: Engine result = instance;
094:
095: if (result == null) {
096: // Find the engine class name
097: String engineClassName = null;
098:
099: // Try the default classloader
100: ClassLoader cl = getClassLoader();
101: URL configURL = cl.getResource(providerResource);
102:
103: if (configURL == null) {
104: // Try the current thread's classloader
105: cl = Thread.currentThread().getContextClassLoader();
106: configURL = cl.getResource(providerResource);
107: }
108:
109: if (configURL == null) {
110: // Try the system classloader
111: cl = ClassLoader.getSystemClassLoader();
112: configURL = cl.getResource(providerResource);
113: }
114:
115: if (configURL != null) {
116: BufferedReader reader = null;
117: try {
118: reader = new BufferedReader(new InputStreamReader(
119: configURL.openStream(), "utf-8"));
120: String providerName = reader.readLine();
121:
122: if (providerName != null)
123: engineClassName = providerName.substring(0,
124: providerName.indexOf('#')).trim();
125: } catch (IOException e) {
126: logger
127: .log(
128: Level.SEVERE,
129: "Unable to register the Restlet API implementation. Please check that the JAR file is in your classpath.");
130: } finally {
131: if (reader != null) {
132: try {
133: reader.close();
134: } catch (IOException e) {
135: logger
136: .warning("IOException encountered while closing an open BufferedReader"
137: + e.getMessage());
138: }
139: }
140:
141: }
142:
143: // Instantiate the engine
144: try {
145: instance = (Engine) Class.forName(engineClassName)
146: .newInstance();
147: result = instance;
148: } catch (Exception e) {
149: logger
150: .log(
151: Level.SEVERE,
152: "Unable to register the Restlet API implementation",
153: e);
154: throw new RuntimeException(
155: "Unable to register the Restlet API implementation");
156: }
157: }
158:
159: if (configURL == null) {
160: logger
161: .log(
162: Level.SEVERE,
163: "Unable to find an implementation of the Restlet API. Please check your classpath.");
164:
165: }
166: }
167:
168: return result;
169: }
170:
171: /**
172: * Computes the hash code of a set of objects. Follows the algorithm
173: * specified in List.hasCode().
174: *
175: * @return The hash code of a set of objects.
176: */
177: public static int hashCode(Object... objects) {
178: int result = 1;
179:
180: if (objects != null) {
181: for (Object obj : objects) {
182: result = 31 * result
183: + (obj == null ? 0 : obj.hashCode());
184: }
185: }
186:
187: return result;
188: }
189:
190: /**
191: * Sets a new class loader to use when creating instantiating implementation
192: * classes.
193: *
194: * @param newClassloader
195: * The new class loader to use.
196: */
197: public static void setClassLoader(ClassLoader newClassloader) {
198: classloader = newClassloader;
199: }
200:
201: /**
202: * Sets the registered Restlet engine.
203: *
204: * @param engine
205: * The registered Restlet engine.
206: */
207: public static void setInstance(Engine engine) {
208: instance = engine;
209: }
210:
211: /**
212: * Creates a directory resource.
213: *
214: * @param handler
215: * The parent directory handler.
216: * @param request
217: * The request to handle.
218: * @param response
219: * The response to return.
220: * @return A new directory resource.
221: * @throws IOException
222: */
223: public abstract Resource createDirectoryResource(Directory handler,
224: Request request, Response response) throws IOException;
225:
226: /**
227: * Creates a new helper for a given component.
228: *
229: * @param application
230: * The application to help.
231: * @param parentContext
232: * The parent context, typically the component's context.
233: * @return The new helper.
234: */
235: public abstract Helper createHelper(Application application,
236: Context parentContext);
237:
238: /**
239: * Creates a new helper for a given client connector.
240: *
241: * @param client
242: * The client to help.
243: * @return The new helper.
244: */
245: public abstract Helper createHelper(Client client);
246:
247: /**
248: * Creates a new helper for a given component.
249: *
250: * @param component
251: * The component to help.
252: * @return The new helper.
253: */
254: public abstract Helper createHelper(Component component);
255:
256: /**
257: * Creates a new helper for a given server connector.
258: *
259: * @param server
260: * The server to help.
261: * @return The new helper.
262: */
263: public abstract Helper createHelper(Server server);
264:
265: /**
266: * Returns the best variant representation for a given resource according
267: * the the client preferences.<br/>A default language is provided in case
268: * the variants don't match the client preferences.
269: *
270: * @param client
271: * The client preferences.
272: * @param variants
273: * The list of variants to compare.
274: * @param defaultLanguage
275: * The default language.
276: * @return The preferred variant.
277: * @see <a
278: * href="http://httpd.apache.org/docs/2.2/en/content-negotiation.html#algorithm">Apache
279: * content negotiation algorithm</a>
280: */
281: public abstract Variant getPreferredVariant(ClientInfo client,
282: List<Variant> variants, Language defaultLanguage);
283:
284: /**
285: * Parses a representation into a form.
286: *
287: * @param logger
288: * The logger to use.
289: * @param form
290: * The target form.
291: * @param representation
292: * The representation to parse.
293: */
294: public abstract void parse(Logger logger, Form form,
295: Representation representation);
296:
297: /**
298: * Parses an URL encoded query string into a given form.
299: *
300: * @param logger
301: * The logger to use.
302: * @param form
303: * The target form.
304: * @param queryString
305: * Query string.
306: * @param characterSet
307: * The supported character encoding.
308: */
309: public abstract void parse(Logger logger, Form form,
310: String queryString, CharacterSet characterSet);
311:
312: }
|