Source Code Cross Referenced for PluginManager.java in  » Content-Management-System » dspace » org » dspace » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » dspace » org.dspace.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * PluginManager.java
003:         *
004:         * Version: $Revision: 1865 $
005:         *
006:         * Date: $Date: 2007-04-23 05:28:41 -0500 (Mon, 23 Apr 2007) $
007:         *
008:         * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
009:         * Institute of Technology.  All rights reserved.
010:         *
011:         * Redistribution and use in source and binary forms, with or without
012:         * modification, are permitted provided that the following conditions are
013:         * met:
014:         *
015:         * - Redistributions of source code must retain the above copyright
016:         * notice, this list of conditions and the following disclaimer.
017:         *
018:         * - Redistributions in binary form must reproduce the above copyright
019:         * notice, this list of conditions and the following disclaimer in the
020:         * documentation and/or other materials provided with the distribution.
021:         *
022:         * - Neither the name of the Hewlett-Packard Company nor the name of the
023:         * Massachusetts Institute of Technology nor the names of their
024:         * contributors may be used to endorse or promote products derived from
025:         * this software without specific prior written permission.
026:         *
027:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028:         * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
030:         * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031:         * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
032:         * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
033:         * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
034:         * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
036:         * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
037:         * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
038:         * DAMAGE.
039:         */
040:
041:        package org.dspace.core;
042:
043:        import java.util.Map;
044:        import java.util.HashMap;
045:        import java.util.HashSet;
046:        import java.util.Enumeration;
047:        import java.util.List;
048:        import java.util.ArrayList;
049:        import java.util.Collection;
050:        import java.util.Iterator;
051:        import java.util.regex.Pattern;
052:        import java.util.regex.Matcher;
053:        import java.lang.reflect.InvocationTargetException;
054:        import java.lang.reflect.Array;
055:        import java.io.BufferedReader;
056:        import java.io.FileReader;
057:        import java.io.File;
058:        import java.io.IOException;
059:
060:        import org.apache.log4j.Logger;
061:
062:        /**
063:         * The Plugin Manager is a very simple component container.  It creates and
064:         * organizes components (plugins), and helps select a plugin in the cases
065:         * where there are many possible choices.  It also gives some limited
066:         * control over the lifecycle of a plugin.  It manages three different types
067:         * (usage patterns) of plugins:
068:         * <p>
069:         * <ol><li> Singleton Plugin
070:         * <br>  There is only one implementation class for the plugin.  It is indicated
071:         *   in the configuration.  This type of plugin chooses an implementations of
072:         *   a service, for the entire system, at configuration time.  Your
073:         *   application just fetches the plugin for that interface and gets the
074:         *   configured-in choice.
075:         *
076:         * <p><li> Sequence Plugins
077:         *  <br> You need a sequence or series of plugins, to implement a mechanism like
078:         *   StackableAuthenticationMethods or a pipeline, where each plugin is
079:         *   called in order to contribute its implementation of a process to the
080:         *   whole.
081:         *  <p><li> Named Plugins
082:         *  <br> Use a named plugin when the application has to choose one plugin
083:         *   implementation out of many available ones.  Each implementation is bound
084:         *   to one or more names (symbolic identifiers) in the configuration.
085:         *  </ol><p>
086:         *  The name is just a <code>String</code> to be associated with the
087:         *  combination of implementation class and interface.  It may contain
088:         *  any characters except for comma (,) and equals (=).  It may contain
089:         *  embedded spaces.  Comma is a special character used to separate
090:         *  names in the configuration entry.
091:         *
092:         * @author Larry Stone
093:         * @version $Revision: 1865 $
094:         * @see SelfNamedPlugin
095:         */
096:        public class PluginManager {
097:            /** log4j category */
098:            private static Logger log = Logger.getLogger(PluginManager.class);
099:
100:            /**
101:             * Prefixes of names of properties to look for in DSpace Configuration
102:             */
103:            private static final String SINGLE_PREFIX = "plugin.single.";
104:            private static final String SEQUENCE_PREFIX = "plugin.sequence.";
105:            private static final String NAMED_PREFIX = "plugin.named.";
106:            private static final String SELFNAMED_PREFIX = "plugin.selfnamed.";
107:            private static final String REUSABLE_PREFIX = "plugin.reusable.";
108:
109:            // Separator character (from perl $;) to make "two dimensional"
110:            // hashtable key out of interface classname and plugin name;
111:            // this character separates the words.
112:            private static final String SEP = "\034";
113:
114:            // Map of plugin class to "reusable" metric (as Boolean, must be Object)
115:            // Key is Class, value is Boolean (true by default).
116:            private static HashMap cacheMeCache = new HashMap();
117:
118:            // Predicate -- whether or not to cache this class.  Ironically,
119:            // the cacheability information is itself cached.
120:            private static boolean cacheMe(Class implClass) {
121:                if (cacheMeCache.containsKey(implClass)) {
122:                    return ((Boolean) cacheMeCache.get(implClass))
123:                            .booleanValue();
124:                } else {
125:                    String key = REUSABLE_PREFIX + implClass.getName();
126:                    boolean reusable = ConfigurationManager.getBooleanProperty(
127:                            key, true);
128:                    cacheMeCache.put(implClass, new Boolean(reusable));
129:                    return reusable;
130:                }
131:            }
132:
133:            /**
134:             * Returns an instance of the singleton (single) plugin implementing
135:             * the given interface.  There must be exactly one single plugin
136:             * configured for this interface, otherwise the
137:             * <code>PluginConfigurationError</code> is thrown.
138:             * <p>
139:             * Note that this is the only "get plugin" method which throws an
140:             * exception.  It is typically used at initialization time to set up
141:             * a permanent part of the system so any failure is fatal.
142:             *
143:             * @param interfaceClass interface Class object
144:             * @return instance of plugin
145:             * @throws PluginConfigurationError
146:             */
147:            public static Object getSinglePlugin(Class interfaceClass)
148:                    throws PluginConfigurationError,
149:                    PluginInstantiationException {
150:                String iname = interfaceClass.getName();
151:
152:                // configuration format is  prefix.<interface> = <classname>
153:                String classname = ConfigurationManager
154:                        .getProperty(SINGLE_PREFIX + iname);
155:                if (classname != null)
156:                    return getAnonymousPlugin(classname.trim());
157:                else
158:                    throw new PluginConfigurationError(
159:                            "No Single Plugin configured for interface \""
160:                                    + iname + "\"");
161:            }
162:
163:            // cache of config data for Sequence Plugins; format its
164:            // <interface-name> -> [ <classname>.. ]  (value is Array)
165:            private static HashMap sequenceConfig = new HashMap();
166:
167:            /**
168:             * Returns instances of all plugins that implement the interface
169:             * intface, in an Array.  Returns an empty array if no there are no
170:             * matching plugins.
171:             * <p>
172:             * The order of the plugins in the array is the same as their class
173:             * names in the configuration's value field.
174:             *
175:             * @param intfc interface for which to find plugins.
176:             * @return an array of plugin instances; if none are
177:             *   available an empty array is returned.
178:             */
179:            public static Object[] getPluginSequence(Class intfc)
180:                    throws PluginInstantiationException {
181:                // cache the configuration for this interface after grovelling it once:
182:                // format is  prefix.<interface> = <classname>
183:                String iname = intfc.getName();
184:                String classname[] = null;
185:                if (!sequenceConfig.containsKey(iname)) {
186:                    String val = ConfigurationManager
187:                            .getProperty(SEQUENCE_PREFIX + iname);
188:                    if (val == null) {
189:                        log
190:                                .warn("No Configuration entry found for Sequence Plugin interface="
191:                                        + iname);
192:                        return new Object[0];
193:                    }
194:                    classname = val.trim().split("\\s*,\\s*");
195:                    sequenceConfig.put(iname, classname);
196:                } else
197:                    classname = (String[]) sequenceConfig.get(iname);
198:
199:                Object result[] = (Object[]) Array.newInstance(intfc,
200:                        classname.length);
201:                for (int i = 0; i < classname.length; ++i) {
202:                    log.debug("Adding Sequence plugin for interface= " + iname
203:                            + ", class=" + classname[i]);
204:                    result[i] = getAnonymousPlugin(classname[i]);
205:                }
206:                return result;
207:            }
208:
209:            // Map of cached (reusable) single plugin instances - class -> instance.
210:            private static HashMap anonymousInstanceCache = new HashMap();
211:
212:            // Get possibly-cached plugin instance for un-named plugin,
213:            // this is shared by Single and Sequence plugins.
214:            private static Object getAnonymousPlugin(String classname)
215:                    throws PluginInstantiationException {
216:                try {
217:                    Class pluginClass = Class.forName(classname);
218:                    if (cacheMe(pluginClass)) {
219:                        Object cached = anonymousInstanceCache.get(pluginClass);
220:                        if (cached == null) {
221:                            cached = pluginClass.newInstance();
222:                            anonymousInstanceCache.put(pluginClass, cached);
223:                        }
224:                        return cached;
225:                    } else
226:                        return pluginClass.newInstance();
227:                } catch (ClassNotFoundException e) {
228:                    throw new PluginInstantiationException(
229:                            "Cannot load plugin class: " + e.toString(), e);
230:                } catch (InstantiationException e) {
231:                    throw new PluginInstantiationException(e);
232:                } catch (IllegalAccessException e) {
233:                    throw new PluginInstantiationException(e);
234:                }
235:            }
236:
237:            // Map of named plugin classes, [intfc,name] -> class
238:            // Also contains intfc -> "marker" to mark when interface has been loaded.
239:            private static HashMap namedPluginClasses = new HashMap();
240:
241:            // Map of cached (reusable) named plugin instances, [class,name] -> instance
242:            private static HashMap namedInstanceCache = new HashMap();
243:
244:            // load and cache configuration data for the given interface.
245:            private static void configureNamedPlugin(String iname)
246:                    throws ClassNotFoundException {
247:                int found = 0;
248:
249:                /**
250:                 * First load the class map for this interface (if not done yet):
251:                 * key is [intfc,name], value is class.
252:                 * There is ALSO a "marker key" of "intfc" by itself to show we
253:                 * loaded this intfc's configuration.
254:                 */
255:                if (!namedPluginClasses.containsKey(iname)) {
256:                    // 1. Get classes named by the configuration. format is:
257:                    //    plugin.named.<INTF> = <CLASS> = <name>, <name> [,] \
258:                    //                        <CLASS> = <name>, <name> [ ... ]
259:                    String namedVal = ConfigurationManager
260:                            .getProperty(NAMED_PREFIX + iname);
261:                    if (namedVal != null) {
262:                        namedVal = namedVal.trim();
263:                        log.debug("Got Named configuration for interface="
264:                                + iname + ", config=" + namedVal);
265:
266:                        // match  "<classname> ="
267:                        Pattern classnameEqual = Pattern
268:                                .compile("([\\w\\p{Sc}\\.]+)\\s*\\=");
269:
270:                        int prevEnd = -1;
271:                        String prevClassName = null;
272:                        Matcher classMatcher = classnameEqual.matcher(namedVal);
273:                        while (classMatcher.find()) {
274:                            if (prevClassName != null)
275:                                found += installNamedConfigs(iname,
276:                                        prevClassName, namedVal.substring(
277:                                                prevEnd, classMatcher.start())
278:                                                .trim().split("\\s*,\\s*"));
279:                            prevClassName = classMatcher.group(1);
280:                            prevEnd = classMatcher.end();
281:                        }
282:                        if (prevClassName != null)
283:                            found += installNamedConfigs(iname, prevClassName,
284:                                    namedVal.substring(prevEnd).trim().split(
285:                                            "\\s*,\\s*"));
286:                    }
287:
288:                    // 2. Get Self-named config entries:
289:                    // format is plugin.selfnamed.<INTF> = <CLASS> , <CLASS> ..
290:                    String selfNamedVal = ConfigurationManager
291:                            .getProperty(SELFNAMED_PREFIX + iname);
292:                    if (selfNamedVal != null) {
293:                        String classnames[] = selfNamedVal.trim().split(
294:                                "\\s*,\\s*");
295:                        for (int i = 0; i < classnames.length; ++i) {
296:                            try {
297:                                Class pluginClass = Class
298:                                        .forName(classnames[i]);
299:                                String names[] = (String[]) pluginClass
300:                                        .getMethod("getPluginNames").invoke(
301:                                                null);
302:                                if (names == null || names.length == 0)
303:                                    log
304:                                            .error("Self-named plugin class \""
305:                                                    + classnames[i]
306:                                                    + "\" returned null or empty name list!");
307:                                else
308:                                    found += installNamedConfigs(iname,
309:                                            classnames[i], names);
310:                            } catch (NoSuchMethodException e) {
311:                                log
312:                                        .error("Implementation Class \""
313:                                                + classnames[i]
314:                                                + "\" is not a subclass of SelfNamedPlugin, it has no getPluginNames() method.");
315:                            } catch (Exception e) {
316:                                log
317:                                        .error("While configuring self-named plugin: "
318:                                                + e.toString());
319:                            }
320:                        }
321:                    }
322:                    namedPluginClasses.put(iname, "org.dspace.core.marker");
323:                    if (found == 0)
324:                        log.error("No named plugins found for interface="
325:                                + iname);
326:                }
327:            }
328:
329:            // add info for a named plugin to cache, under all its names.
330:            private static int installNamedConfigs(String iname,
331:                    String classname, String names[])
332:                    throws ClassNotFoundException {
333:                int found = 0;
334:                for (int i = 0; i < names.length; ++i) {
335:                    String key = iname + SEP + names[i];
336:                    if (namedPluginClasses.containsKey(key))
337:                        log
338:                                .error("Name collision in named plugin, implementation class=\""
339:                                        + classname
340:                                        + "\", name=\""
341:                                        + names[i]
342:                                        + "\"");
343:                    else
344:                        namedPluginClasses.put(key, classname);
345:                    log.debug("Got Named Plugin, intfc=" + iname + ", name="
346:                            + names[i] + ", class=" + classname);
347:                    ++found;
348:                }
349:                return found;
350:            }
351:
352:            /**
353:             * Returns an instance of a plugin that implements the interface
354:             * intface and is bound to a name matching name.  If there is no
355:             * matching plugin, it returns null.  The names are matched by
356:             * String.equals().
357:             *
358:             * @param intfc the interface class of the plugin
359:             * @param name under which the plugin implementation is configured.
360:             * @return instance of plugin implementation, or null if there is no match or an error.
361:             */
362:            public static Object getNamedPlugin(Class intfc, String name)
363:                    throws PluginInstantiationException {
364:                try {
365:                    String iname = intfc.getName();
366:                    configureNamedPlugin(iname);
367:                    String key = iname + SEP + name;
368:                    String cname = (String) namedPluginClasses.get(key);
369:                    if (cname == null)
370:                        log.warn("Cannot find named plugin for interface="
371:                                + iname + ", name=\"" + name + "\"");
372:                    else {
373:                        Class pluginClass = Class.forName(cname);
374:                        if (cacheMe(pluginClass)) {
375:                            String nkey = pluginClass.getName() + SEP + name;
376:                            Object cached = namedInstanceCache.get(nkey);
377:                            if (cached == null) {
378:                                log.debug("Creating cached instance of: "
379:                                        + cname + " for interface=" + iname
380:                                        + " pluginName=" + name);
381:                                cached = pluginClass.newInstance();
382:                                if (cached instanceof  SelfNamedPlugin)
383:                                    ((SelfNamedPlugin) cached)
384:                                            .setPluginInstanceName(name);
385:                                namedInstanceCache.put(nkey, cached);
386:                            }
387:                            return cached;
388:                        } else {
389:                            log.debug("Creating UNcached instance of: " + cname
390:                                    + " for interface=" + iname
391:                                    + " pluginName=" + name);
392:                            Object result = pluginClass.newInstance();
393:                            if (result instanceof  SelfNamedPlugin)
394:                                ((SelfNamedPlugin) result)
395:                                        .setPluginInstanceName(name);
396:                            return result;
397:                        }
398:                    }
399:                } catch (ClassNotFoundException e) {
400:                    throw new PluginInstantiationException(
401:                            "Cannot load plugin class: " + e.toString(), e);
402:                } catch (InstantiationException e) {
403:                    throw new PluginInstantiationException(e);
404:                } catch (IllegalAccessException e) {
405:                    throw new PluginInstantiationException(e);
406:                }
407:
408:                return null;
409:            }
410:
411:            /**
412:             * Returns all of the names under which a named plugin implementing
413:             * the interface intface can be requested (with getNamedPlugin()).
414:             * The array is empty if there are no matches.  Use this to populate
415:             * a menu of plugins for interactive selection, or to document what
416:             * the possible choices are.
417:             * <p>
418:             * NOTE: The names are NOT returned in any deterministic order.
419:             *
420:             * @param intfc plugin interface for which to return names.
421:             * @return an array of strings with every name; if none are
422:             *   available an empty array is returned.
423:             */
424:            public static String[] getAllPluginNames(Class intfc) {
425:                try {
426:                    String iname = intfc.getName();
427:                    configureNamedPlugin(iname);
428:                    String prefix = iname + SEP;
429:                    ArrayList result = new ArrayList();
430:
431:                    Iterator ki = namedPluginClasses.keySet().iterator();
432:                    while (ki.hasNext()) {
433:                        String key = (String) ki.next();
434:                        if (key.startsWith(prefix))
435:                            result.add(key.substring(prefix.length()));
436:                    }
437:                    if (result.size() == 0)
438:                        log
439:                                .error("Cannot find any names for named plugin, interface="
440:                                        + iname);
441:
442:                    return (String[]) result.toArray(new String[result.size()]);
443:                } catch (ClassNotFoundException e) {
444:                    return new String[0];
445:                }
446:            }
447:
448:            /**
449:             * Tells the Plugin Manager to let go of any references to a
450:             * reusable plugin, to prevent it from being given out again and to
451:             * allow the object to be garbage-collected.  Call this when a
452:             * plugin instance must be taken out of circulation.
453:             *
454:             * @param plugin the object to release, must have been created by
455:             *   <code>getNamedPlugin</code> etc.
456:             */
457:            public static void releasePlugin(Object plugin) {
458:                forgetInstance(plugin, namedInstanceCache);
459:                forgetInstance(plugin, anonymousInstanceCache);
460:            }
461:
462:            private static void forgetInstance(Object plugin, Map cacheMap) {
463:                Collection values = cacheMap.values();
464:                Iterator ci = values.iterator();
465:                while (ci.hasNext()) {
466:                    Object val = ci.next();
467:                    if (val == plugin)
468:                        values.remove(val);
469:                }
470:            }
471:
472:            /* -----------------------------------------------------------------
473:             *  Code to check configuration is all below this line
474:             * -----------------------------------------------------------------
475:             */
476:
477:            // true if classname is valid and loadable.
478:            private static boolean checkClassname(String iname, String msg) {
479:                try {
480:                    Class intf = Class.forName(iname);
481:                    return true;
482:                } catch (ClassNotFoundException ce) {
483:                    log.error("No class definition found for " + msg + ": \""
484:                            + iname + "\"");
485:                }
486:                return false;
487:            }
488:
489:            // true if classname is loadable AND is subclass of SelfNamedPlugin
490:            private static boolean checkSelfNamed(String iname) {
491:                try {
492:                    if (!checkSelfNamed(Class.forName(iname)))
493:                        log
494:                                .error("The class \""
495:                                        + iname
496:                                        + "\" is NOT a subclass of SelfNamedPlugin but it should be!");
497:                } catch (ClassNotFoundException ce) {
498:                    log
499:                            .error("No class definition found for self-named class interface: \""
500:                                    + iname + "\"");
501:                }
502:                return false;
503:            }
504:
505:            // recursively climb superclass stack until we find SelfNamedPlugin
506:            private static boolean checkSelfNamed(Class cls) {
507:                Class sup = cls.getSuperclass();
508:                if (sup == null)
509:                    return false;
510:                else if (sup.equals(SelfNamedPlugin.class))
511:                    return true;
512:                else
513:                    return checkSelfNamed(sup);
514:            }
515:
516:            // check named-plugin names by interface -- call the usual
517:            // configuration and let it find missing or duplicate names.
518:            private static void checkNames(String iname) {
519:                try {
520:                    configureNamedPlugin(iname);
521:                } catch (ClassNotFoundException ce) {
522:                    // bogus classname should be old news by now.
523:                }
524:            }
525:
526:            /**
527:             * Validate the entries in the DSpace Configuration relevant to
528:             * PluginManager.  Look for inconsistencies, illegal syntax, etc.
529:             * Announce violations with "log.error" so they appear in the log
530:             * or in the standard error stream if this is run interactively.
531:             * <ul>
532:             * <li>Look for duplicate keys (by parsing the config file)
533:             * <li>Interface in plugin.single, plugin.sequence, plugin.named, plugin.selfnamed is valid.
534:             * <li>Classname in plugin.reusable exists and matches a plugin config.
535:             * <li>Classnames in config values exist.
536:             * <li>Classnames in plugin.selfnamed loads and is subclass of <code>SelfNamedPlugin</code>
537:             * <li>Implementations of named plugin have no name collisions.
538:             * <li>Named plugin entries lacking names.
539:             * </ul>
540:             */
541:            public static void checkConfiguration() throws IOException {
542:                /*  XXX TODO:  (maybe) test that implementation class is really a
543:                 *  subclass or impl of the plugin "interface"
544:                 */
545:
546:                // tables of config keys for each type of config line:
547:                Map singleKey = new HashMap();
548:                Map sequenceKey = new HashMap();
549:                Map namedKey = new HashMap();
550:                Map selfnamedKey = new HashMap();
551:                Map reusableKey = new HashMap();
552:
553:                // 1. First pass -- grovel the actual config file to check for
554:                //    duplicate keys, since Properties class hides them from us.
555:                //    Also build lists of each type of key, check for misspellings.
556:                File config = ConfigurationManager.getConfigurationFile();
557:                BufferedReader cr = new BufferedReader(new FileReader(config));
558:                String line = null;
559:                boolean continued = false;
560:                HashMap keyMap = new HashMap();
561:                Pattern keyPattern = Pattern.compile("([^\\s\\=\\:]+)");
562:                while ((line = cr.readLine()) != null) {
563:                    line = line.trim();
564:                    if (line.startsWith("!") || line.startsWith("#"))
565:                        continued = false;
566:                    else {
567:                        if (!continued && line.startsWith("plugin.")) {
568:                            Matcher km = keyPattern.matcher(line);
569:                            if (km.find()) {
570:                                String key = line.substring(0, km.end(1));
571:                                if (keyMap.containsKey(key))
572:                                    log
573:                                            .error("Duplicate key \""
574:                                                    + key
575:                                                    + "\" in DSpace configuration file="
576:                                                    + config.toString());
577:                                else
578:                                    keyMap.put(key, key);
579:
580:                                if (key.startsWith(SINGLE_PREFIX))
581:                                    singleKey.put(key.substring(SINGLE_PREFIX
582:                                            .length()), key);
583:                                else if (key.startsWith(SEQUENCE_PREFIX))
584:                                    sequenceKey.put(
585:                                            key.substring(SEQUENCE_PREFIX
586:                                                    .length()), key);
587:                                else if (key.startsWith(NAMED_PREFIX))
588:                                    namedKey.put(key.substring(NAMED_PREFIX
589:                                            .length()), key);
590:                                else if (key.startsWith(SELFNAMED_PREFIX))
591:                                    selfnamedKey.put(key
592:                                            .substring(SELFNAMED_PREFIX
593:                                                    .length()), key);
594:                                else if (key.startsWith(REUSABLE_PREFIX))
595:                                    reusableKey.put(
596:                                            key.substring(REUSABLE_PREFIX
597:                                                    .length()), key);
598:                                else
599:                                    log
600:                                            .error("Key with unknown prefix \""
601:                                                    + key
602:                                                    + "\" in DSpace configuration file="
603:                                                    + config.toString());
604:                            }
605:                        }
606:                        continued = line.length() > 0
607:                                && line.charAt(line.length() - 1) == '\\';
608:                    }
609:                }
610:
611:                // 1.1 Sanity check, make sure keyMap == set of keys from Configuration
612:                Enumeration pne = ConfigurationManager.propertyNames();
613:                HashSet pn = new HashSet();
614:                while (pne.hasMoreElements()) {
615:                    String nk = (String) pne.nextElement();
616:                    if (nk.startsWith("plugin.")) {
617:                        pn.add(nk);
618:                        if (!keyMap.containsKey(nk))
619:                            log
620:                                    .error("Key is in ConfigurationManager.propertyNames() but NOT text crawl: \""
621:                                            + nk + "\"");
622:                    }
623:                }
624:                Iterator pi = keyMap.keySet().iterator();
625:                while (pi.hasNext()) {
626:                    String key = (String) pi.next();
627:                    if (!pn.contains(key))
628:                        log
629:                                .error("Key is in text crawl but NOT ConfigurationManager.propertyNames(): \""
630:                                        + key + "\"");
631:                }
632:
633:                // 2. Build up list of all interfaces and test that they are loadable.
634:                // don't bother testing that they are "interface" rather than "class"
635:                // since either one will work for the Plugin Manager.
636:                ArrayList allInterfaces = new ArrayList();
637:                allInterfaces.addAll(singleKey.keySet());
638:                allInterfaces.addAll(sequenceKey.keySet());
639:                allInterfaces.addAll(namedKey.keySet());
640:                allInterfaces.addAll(selfnamedKey.keySet());
641:                allInterfaces.addAll(reusableKey.keySet());
642:                Iterator ii = allInterfaces.iterator();
643:                while (ii.hasNext())
644:                    checkClassname((String) ii.next(), "key interface or class");
645:
646:                // Check implementation classes:
647:                //  - each class is loadable.
648:                //  - plugin.selfnamed values are each  subclass of SelfNamedPlugin
649:                //  - save classname in allImpls
650:                Map allImpls = new HashMap();
651:
652:                // single plugins - just check that it has a valid impl. class
653:                ii = singleKey.keySet().iterator();
654:                while (ii.hasNext()) {
655:                    String key = (String) ii.next();
656:                    String val = ConfigurationManager.getProperty(SINGLE_PREFIX
657:                            + key);
658:                    if (val == null)
659:                        log.error("Single plugin config not found for: "
660:                                + SINGLE_PREFIX + key);
661:                    else {
662:                        val = val.trim();
663:                        if (checkClassname(val, "implementation class"))
664:                            allImpls.put(val, val);
665:                    }
666:                }
667:
668:                // sequence plugins - all values must be classes
669:                ii = sequenceKey.keySet().iterator();
670:                while (ii.hasNext()) {
671:                    String key = (String) ii.next();
672:                    String val = ConfigurationManager
673:                            .getProperty(SEQUENCE_PREFIX + key);
674:                    if (val == null)
675:                        log.error("Sequence plugin config not found for: "
676:                                + SEQUENCE_PREFIX + key);
677:                    else {
678:                        val = val.trim();
679:                        String classname[] = val.split("\\s*,\\s*");
680:                        for (int i = 0; i < classname.length; ++i)
681:                            if (checkClassname(classname[i],
682:                                    "implementation class"))
683:                                allImpls.put(classname[i], classname[i]);
684:                    }
685:                }
686:
687:                // 3. self-named plugins - grab and check all values
688:                //   then make sure it is a subclass of SelfNamedPlugin
689:                ii = selfnamedKey.keySet().iterator();
690:                while (ii.hasNext()) {
691:                    String key = (String) ii.next();
692:                    String val = ConfigurationManager
693:                            .getProperty(SELFNAMED_PREFIX + key);
694:                    if (val == null)
695:                        log.error("Selfnamed plugin config not found for: "
696:                                + SELFNAMED_PREFIX + key);
697:                    else {
698:                        val = val.trim();
699:                        String classname[] = val.split("\\s*,\\s*");
700:                        for (int i = 0; i < classname.length; ++i)
701:                            if (checkClassname(classname[i],
702:                                    "selfnamed implementation class")) {
703:                                allImpls.put(classname[i], classname[i]);
704:                                checkSelfNamed(classname[i]);
705:                            }
706:                        checkNames(key);
707:                    }
708:                }
709:
710:                // 4. named plugins - extract the classnames and treat same as sequence.
711:                // use named plugin config mechanism to test for duplicates, unnamed.
712:                ii = namedKey.keySet().iterator();
713:                Pattern classnameEqual = Pattern
714:                        .compile("([\\w\\p{Sc}\\.]+)\\s*\\=");
715:                while (ii.hasNext()) {
716:                    String key = (String) ii.next();
717:                    String val = ConfigurationManager.getProperty(NAMED_PREFIX
718:                            + key);
719:                    if (val == null)
720:                        log.error("Named plugin config not found for: "
721:                                + NAMED_PREFIX + key);
722:                    else {
723:                        checkNames(key);
724:                        val = val.trim();
725:                        Matcher classMatcher = classnameEqual.matcher(val);
726:                        while (classMatcher.find()) {
727:                            String classname = classMatcher.group(1);
728:
729:                            if (checkClassname(classname,
730:                                    "implementation class"))
731:                                allImpls.put(classname, classname);
732:                        }
733:                    }
734:                }
735:
736:                // 5. all classes named in Reusable config lines must be other classes.
737:                Iterator ri = reusableKey.keySet().iterator();
738:                while (ri.hasNext()) {
739:                    String rk = (String) ri.next();
740:                    if (!(allImpls.containsKey(rk)))
741:                        log.error("In plugin.reusable configuration, class \""
742:                                + rk
743:                                + "\" is NOT a plugin implementation class.");
744:                }
745:            }
746:
747:            /**
748:             * Invoking this class from the command line just runs
749:             * <code>checkConfiguration</code> and shows the results.
750:             * There are no command-line options.
751:             */
752:            public static void main(String[] argv) throws Exception {
753:                checkConfiguration();
754:            }
755:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.