001: package org.sakaibrary.osid.loader;
002:
003: /**
004: * OsidLoader loads a specific implementation of an Open Service Interface
005: * Definition (OSID) with its getManager method. The getManager method loads
006: * an instance of the OSID's org.osid.OsidManager, assigns the manager's OsidContext,
007: * assigns any configuration information, and returns the instance of the OSID
008: * implementation. This usage of the getManager method in the OsidLoader is
009: * how applications should bind a particular implementation to an OSID. The
010: * value of this approach is that an application can defer which specific OSID
011: * implementation is used until runtime. The specific implementation package
012: * name can then be part of the configuration information rather than being
013: * hard coded. Changing implementations is simplified with this approach.
014: *
015: * <p>
016: * As an example, in order to create a new Hierarchy, an application does not
017: * use the new operator. It uses the OsidLoader getManager method to get an
018: * instance of a class that implements HierarchyManager (a subclass of
019: * org.osid.OsidManager). The application uses the HierarchyManager instance to create
020: * the Hierarchy. It is the createHierarchy() method in some package (e.g.
021: * org.osid.hierarchy.impl.HierarchyManager) which uses the new operator on
022: * org.osid.hierarchy.impl.Hierarchy, casts it as
023: * org.osid.hierarchy.Hierarchy, and returns it to the application. This
024: * indirection offers the significant value of being able to change
025: * implementations in one spot with one modification, namely by using a
026: * implementation package name argument for the OsidLoader getManager method.
027: * </p>
028: *
029: * <p>
030: * Sample:
031: * <blockquote>
032: * org.osid.OsidContext myContext = new org.osid.OsidContext();<br/
033: * >String key = "myKey";<br/
034: * >myContext.assignContext(key, "I want to save this string as context");<br/
035: * >String whatWasMyContext = myContext.getContext(key);<br/
036: * >org.osid.hierarchy.HierarchyManager hierarchyManager =
037: * <blockquote>
038: * org.osid.OsidLoader.getManager("org.osid.hierarchy.HierarchyManager","org.osid.shared.impl",myContext,null);
039: * </blockquote>
040: * org.osid.hierarchy.Hierarchy myHierarchy =
041: * hierarchyManager.createHierarchy(...);<br/>
042: * </blockquote>
043: * </p>
044: *
045: * <p>
046: * A similar technique can be used for creating other objects. OSIDs that have
047: * org.osid.OsidManager implementations loaded by OsidLoader, will define an
048: * appropriate interface to create these objects.
049: * </p>
050: *
051: * <p>
052: * The arguments to OsidLoader.getManager method are the OSID org.osid.OsidManager
053: * interface name, the implementing package name, the OsidContext, and any
054: * additional configuration information.
055: * </p>
056: *
057: * <p>
058: * OSID Version: 2.0
059: * </p>
060: *
061: * <p>
062: * Licensed under the {@link org.osid.SidImplementationLicenseMIT MIT
063: * O.K.I. OSID Definition License}.
064: * </p>
065: */
066:
067: public class OsidLoader implements java.io.Serializable {
068:
069: private static final long serialVersionUID = 1L;
070:
071: private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
072: .getLog("org.sakaibrary.osid.loader.OsidLoader");
073:
074: /**
075: * Returns an instance of the org.osid.OsidManager of the OSID specified by the OSID
076: * package org.osid.OsidManager interface name and the implementation package name.
077: * The implementation class name is constructed from the SID package
078: * Manager interface name. A configuration file name is constructed in a
079: * similar manner and if the file exists it is loaded into the
080: * implementation's org.osid.OsidManager's configuration.
081: *
082: * <p>
083: * Example: To load an implementation of the org.osid.Filing OSID
084: * implemented in a package "xyz", one would use:
085: * </p>
086: *
087: * <p>
088: * org.osid.filing.FilingManager fm =
089: * (org.osid.filing.FilingManager)org.osid.OsidLoader.getManager(
090: * </p>
091: *
092: * <p>
093: * "org.osid.filing.FilingManager" ,
094: * </p>
095: *
096: * <p>
097: * "xyz" ,
098: * </p>
099: *
100: * <p>
101: * new org.osid.OsidContext());
102: * </p>
103: *
104: * @param osidPackageManagerName osidPackageManagerName is a fully
105: * qualified org.osid.OsidManager interface name
106: * @param implPackageName implPackageName is a fully qualified
107: * implementation package name
108: * @param context
109: * @param additionalConfiguration
110: *
111: * @return org.osid.OsidManager
112: *
113: * @throws org.osid.OsidException An exception with one of the following
114: * messages defined in org.osid.OsidException: {@link
115: * org.osid.OsidException#OPERATION_FAILED OPERATION_FAILED},
116: * {@link org.osid.OsidException#NULL_ARGUMENT NULL_ARGUMENT},
117: * {@link org.osid.OsidException#VERSION_ERROR VERSION_ERROR},
118: * ={@link org.osid.OsidException#INTERFACE_NOT_FOUND
119: * INTERFACE_NOT_FOUND}, ={@link
120: * org.osid.OsidException#MANAGER_NOT_FOUND MANAGER_NOT_FOUND},
121: * ={@link org.osid.OsidException#MANAGER_INSTANTIATION_ERROR
122: * MANAGER_INSTANTIATION_ERROR}, ={@link
123: * org.osid.OsidException#ERROR_ASSIGNING_CONTEXT
124: * ERROR_ASSIGNING_CONTEXT}, ={@link
125: * org.osid.OsidException#ERROR_ASSIGNING_CONFIGURATION
126: * ERROR_ASSIGNING_CONFIGURATION}
127: */
128: public static org.osid.OsidManager getManager(
129: String osidPackageManagerName, String implPackageName,
130: org.osid.OsidContext context,
131: java.util.Properties additionalConfiguration)
132: throws org.osid.OsidException {
133:
134: try {
135: if ((null != context) && (null != osidPackageManagerName)
136: && (null != implPackageName)) {
137: String osidInterfaceName = osidPackageManagerName;
138: String className = makeClassName(osidPackageManagerName);
139: String managerClassName = makeFullyQualifiedClassName(
140: implPackageName, className);
141:
142: LOG.debug("osid interface name: " + osidInterfaceName);
143: Class osidInterface = Class.forName(osidInterfaceName);
144:
145: if (null != osidInterface) {
146: LOG.debug("osid manager class name: "
147: + managerClassName);
148: Class managerClass = Class
149: .forName(managerClassName);
150:
151: if (null != managerClass) {
152: if (osidInterface
153: .isAssignableFrom(managerClass)) {
154: org.osid.OsidManager manager = (org.osid.OsidManager) managerClass
155: .newInstance();
156:
157: if (null != manager) {
158: try {
159: manager.osidVersion_2_0();
160: } catch (Throwable ex) {
161: throw new org.osid.OsidException(
162: org.osid.OsidException.VERSION_ERROR);
163: }
164:
165: try {
166: manager.assignOsidContext(context);
167: } catch (Exception ex) {
168: throw new org.osid.OsidException(
169: org.osid.OsidException.ERROR_ASSIGNING_CONTEXT);
170: }
171:
172: try {
173: java.util.Properties configuration = getConfiguration(manager);
174:
175: if (null == configuration) {
176: configuration = new java.util.Properties();
177: }
178:
179: if (null != additionalConfiguration) {
180: java.util.Enumeration enumer = additionalConfiguration
181: .propertyNames();
182:
183: while (enumer.hasMoreElements()) {
184: java.io.Serializable key = (java.io.Serializable) enumer
185: .nextElement();
186:
187: if (null != key) {
188: java.io.Serializable value = (java.io.Serializable) additionalConfiguration
189: .get(key);
190:
191: if (null != value) {
192: configuration.put(
193: key, value);
194: }
195: }
196: }
197: }
198:
199: manager
200: .assignConfiguration(configuration);
201: LOG
202: .debug("configuration has been assigned done.");
203:
204: return manager;
205: } catch (Exception ex) {
206: throw new org.osid.OsidException(
207: org.osid.OsidException.ERROR_ASSIGNING_CONFIGURATION);
208: }
209: }
210:
211: throw new org.osid.OsidException(
212: org.osid.OsidException.MANAGER_INSTANTIATION_ERROR);
213: }
214:
215: throw new org.osid.OsidException(
216: org.osid.OsidException.MANAGER_NOT_OSID_IMPLEMENTATION);
217: }
218:
219: throw new org.osid.OsidException(
220: org.osid.OsidException.MANAGER_NOT_FOUND);
221: }
222:
223: throw new org.osid.OsidException(
224: org.osid.OsidException.INTERFACE_NOT_FOUND);
225: }
226:
227: throw new org.osid.OsidException(
228: org.osid.OsidException.NULL_ARGUMENT);
229: } catch (org.osid.OsidException oex) {
230: LOG.error(oex.getMessage());
231: throw new org.osid.OsidException(oex.getMessage());
232: } catch (java.lang.Throwable ex) {
233: LOG.error(ex.getMessage());
234: throw new org.osid.OsidException(
235: org.osid.OsidException.OPERATION_FAILED);
236: }
237: }
238:
239: private static String makeClassName(String packageManagerName)
240: throws org.osid.OsidException {
241: String className = packageManagerName;
242:
243: if (null != className) {
244: className = (className.endsWith(".") ? className.substring(
245: 0, className.length() - 1) : className);
246:
247: int lastdot = className.lastIndexOf(".");
248:
249: if (-1 != lastdot) {
250: className = className.substring(lastdot + 1);
251: }
252: }
253:
254: return className;
255: }
256:
257: private static String makeFullyQualifiedClassName(
258: String packageName, String className)
259: throws org.osid.OsidException {
260: String cName = className;
261:
262: if (null != packageName) {
263: String pName = (packageName.endsWith(".") ? packageName
264: : new String(packageName + "."));
265: cName = pName + className;
266: }
267:
268: return cName;
269: }
270:
271: /******* Utility Methods For Sakai Implementations ********/
272:
273: /**
274: * Get an InputStream for a particular file name - first check the sakai.home area and then
275: * revert to the classpath.
276: *
277: * This is a utility method used several places.
278: */
279: public static java.io.InputStream getConfigStream(String fileName,
280: Class curClass) {
281: String dataFolder = "/data/";
282: String filePath = dataFolder + fileName;
283:
284: try {
285: java.io.File f = new java.io.File(filePath);
286: if (f.exists()) {
287: return new java.io.FileInputStream(f);
288: }
289: } catch (Throwable t) {
290: // Not found in the sakai.home area
291: }
292:
293: if (curClass == null)
294: return null;
295:
296: // If there is a class context, load from the class context...
297: java.io.InputStream istream = null;
298:
299: // Load from the class loader
300: istream = curClass.getClassLoader().getResourceAsStream(
301: fileName);
302: if (istream != null)
303: return istream;
304:
305: // Load from the class relative
306: istream = curClass.getResourceAsStream(fileName);
307: if (istream != null)
308: return istream;
309:
310: // Loading from the class at the data root
311: istream = curClass.getResourceAsStream("/data/" + fileName);
312: return istream;
313: }
314:
315: private static java.util.Properties getConfiguration(
316: org.osid.OsidManager manager) throws org.osid.OsidException {
317: java.util.Properties properties = null;
318:
319: if (null != manager) {
320: Class managerClass = manager.getClass();
321: String propertyName = "default: RepositoryManager.properties";
322:
323: try {
324: String managerClassName = managerClass.getName();
325: int index = managerClassName.lastIndexOf(".");
326:
327: if (-1 != index) {
328: managerClassName = managerClassName
329: .substring(index + 1);
330: }
331:
332: // RepositoryManager.properties is built
333: propertyName = managerClassName + ".properties";
334:
335: // read RepositoryManager.properties file
336: // java.io.InputStream is = new java.io.FileInputStream( "data/" +
337: // propertyName );
338: java.io.InputStream is = getConfigStream(propertyName,
339: managerClass);
340:
341: // RepositoryManager.properties is read and
342: // loaded into a java.util.Properties object
343: if (null != is) {
344: properties = new java.util.Properties();
345: properties.load(is);
346: }
347:
348: LOG.debug("Read osid manager properties from: "
349: + propertyName);
350: } catch (Throwable ex) {
351: LOG.error("Error reading " + propertyName
352: + " property file --" + ex.getMessage());
353: }
354: }
355:
356: return properties;
357: }
358:
359: /**
360: * <p>
361: * MIT O.K.I. SID Definition License.
362: * </p>
363: *
364: * <p>
365: * <b>Copyright and license statement:</b>
366: * </p>
367: *
368: * <p>
369: * Copyright © 2003 Massachusetts Institute of Technology <or
370: * copyright holder>
371: * </p>
372: *
373: * <p>
374: * This work is being provided by the copyright holder(s) subject to
375: * the terms of the O.K.I. SID Definition License. By obtaining,
376: * using and/or copying this Work, you agree that you have read,
377: * understand, and will comply with the O.K.I. SID Definition
378: * License.
379: * </p>
380: *
381: * <p>
382: * THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
383: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
384: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
385: * NONINFRINGEMENT. IN NO EVENT SHALL MASSACHUSETTS INSTITUTE OF
386: * TECHNOLOGY, THE AUTHORS, OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
387: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
388: * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
389: * WITH THE WORK OR THE USE OR OTHER DEALINGS IN THE WORK.
390: * </p>
391: *
392: * <p>
393: * <b>O.K.I. SID Definition License</b>
394: * </p>
395: *
396: * <p>
397: * This work (the “Work”), including any software,
398: * documents, or other items related to O.K.I. SID definitions, is
399: * being provided by the copyright holder(s) subject to the terms of
400: * the O.K.I. SID Definition License. By obtaining, using and/or
401: * copying this Work, you agree that you have read, understand, and
402: * will comply with the following terms and conditions of the
403: * O.K.I. SID Definition License:
404: * </p>
405: *
406: * <p>
407: * You may use, copy, and distribute unmodified versions of this Work
408: * for any purpose, without fee or royalty, provided that you include
409: * the following on ALL copies of the Work that you make or
410: * distribute:
411: * </p>
412: *
413: * <ul>
414: * <li>
415: * The full text of the O.K.I. SID Definition License in a location
416: * viewable to users of the redistributed Work.
417: * </li>
418: * </ul>
419: *
420: *
421: * <ul>
422: * <li>
423: * Any pre-existing intellectual property disclaimers, notices, or terms
424: * and conditions. If none exist, a short notice similar to the following
425: * should be used within the body of any redistributed Work:
426: * “Copyright © 2003 Massachusetts Institute of Technology. All
427: * Rights Reserved.”
428: * </li>
429: * </ul>
430: *
431: * <p>
432: * You may modify or create Derivatives of this Work only for your
433: * internal purposes. You shall not distribute or transfer any such
434: * Derivative of this Work to any location or any other third party.
435: * For purposes of this license, “Derivative” shall mean
436: * any derivative of the Work as defined in the United States
437: * Copyright Act of 1976, such as a translation or modification.
438: * </p>
439: *
440: * <p>
441: * THE WORK PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
442: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
443: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
444: * NONINFRINGEMENT. IN NO EVENT SHALL MASSACHUSETTS INSTITUTE OF
445: * TECHNOLOGY, THE AUTHORS, OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
446: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
447: * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
448: * WITH THE WORK OR THE USE OR OTHER DEALINGS IN THE WORK.
449: * </p>
450: *
451: * <p>
452: * The name and trademarks of copyright holder(s) and/or O.K.I. may
453: * NOT be used in advertising or publicity pertaining to the Work
454: * without specific, written prior permission. Title to copyright in
455: * the Work and any associated documentation will at all times remain
456: * with the copyright holders.
457: * </p>
458: *
459: * <p>
460: * The export of software employing encryption technology may require a
461: * specific license from the United States Government. It is the
462: * responsibility of any person or organization contemplating export
463: * to obtain such a license before exporting this Work.
464: * </p>
465: */
466: }
|