1 40 41 package org.dspace.core; 42 43 import java.util.Map ; 44 import java.util.HashMap ; 45 import java.util.HashSet ; 46 import java.util.Enumeration ; 47 import java.util.List ; 48 import java.util.ArrayList ; 49 import java.util.Collection ; 50 import java.util.Iterator ; 51 import java.util.regex.Pattern ; 52 import java.util.regex.Matcher ; 53 import java.lang.reflect.InvocationTargetException ; 54 import java.lang.reflect.Array ; 55 import java.io.BufferedReader ; 56 import java.io.FileReader ; 57 import java.io.File ; 58 import java.io.IOException ; 59 60 import org.apache.log4j.Logger; 61 62 96 public class PluginManager 97 { 98 99 private static Logger log = Logger.getLogger(PluginManager.class); 100 101 104 private static final String SINGLE_PREFIX = "plugin.single."; 105 private static final String SEQUENCE_PREFIX = "plugin.sequence."; 106 private static final String NAMED_PREFIX = "plugin.named."; 107 private static final String SELFNAMED_PREFIX = "plugin.selfnamed."; 108 private static final String REUSABLE_PREFIX = "plugin.reusable."; 109 110 private static final String SEP = "\034"; 114 115 private static HashMap cacheMeCache = new HashMap (); 118 119 private static boolean cacheMe(Class implClass) 122 { 123 if (cacheMeCache.containsKey(implClass)) 124 { 125 return ((Boolean )cacheMeCache.get(implClass)).booleanValue(); 126 } 127 else 128 { 129 String key = REUSABLE_PREFIX+implClass.getName(); 130 boolean reusable = ConfigurationManager.getBooleanProperty(key, true); 131 cacheMeCache.put(implClass, new Boolean (reusable)); 132 return reusable; 133 } 134 } 135 136 150 public static Object getSinglePlugin(Class interfaceClass) 151 throws PluginConfigurationError, PluginInstantiationException 152 { 153 String iname = interfaceClass.getName(); 154 155 String classname = ConfigurationManager.getProperty(SINGLE_PREFIX+iname); 157 if (classname != null) 158 return getAnonymousPlugin(classname.trim()); 159 else 160 throw new PluginConfigurationError("No Single Plugin configured for interface \""+iname+"\""); 161 } 162 163 164 private static HashMap sequenceConfig = new HashMap (); 167 168 180 public static Object [] getPluginSequence(Class intfc) 181 throws PluginInstantiationException 182 { 183 String iname = intfc.getName(); 186 String classname[] = null; 187 if (!sequenceConfig.containsKey(iname)) 188 { 189 String val = ConfigurationManager.getProperty(SEQUENCE_PREFIX+iname); 190 if (val == null) 191 { 192 log.warn("No Configuration entry found for Sequence Plugin interface="+iname); 193 return new Object [0]; 194 } 195 classname = val.trim().split("\\s*,\\s*"); 196 sequenceConfig.put(iname, classname); 197 } 198 else 199 classname = (String [])sequenceConfig.get(iname); 200 201 Object result[] = (Object [])Array.newInstance(intfc, classname.length); 202 for (int i = 0; i < classname.length; ++i) 203 { 204 log.debug("Adding Sequence plugin for interface= "+iname+", class="+classname[i]); 205 result[i] = getAnonymousPlugin(classname[i]); 206 } 207 return result; 208 } 209 210 private static HashMap anonymousInstanceCache = new HashMap (); 212 213 private static Object getAnonymousPlugin(String classname) 216 throws PluginInstantiationException 217 { 218 try 219 { 220 Class pluginClass = Class.forName(classname); 221 if (cacheMe(pluginClass)) 222 { 223 Object cached = anonymousInstanceCache.get(pluginClass); 224 if (cached == null) 225 { 226 cached = pluginClass.newInstance(); 227 anonymousInstanceCache.put(pluginClass, cached); 228 } 229 return cached; 230 } 231 else 232 return pluginClass.newInstance(); 233 } 234 catch (ClassNotFoundException e) 235 { 236 throw new PluginInstantiationException("Cannot load plugin class: " + 237 e.toString(), e); 238 } 239 catch (InstantiationException e) 240 { 241 throw new PluginInstantiationException(e); 242 } 243 catch (IllegalAccessException e) 244 { 245 throw new PluginInstantiationException(e); 246 } 247 } 248 249 private static HashMap namedPluginClasses = new HashMap (); 252 253 private static HashMap namedInstanceCache = new HashMap (); 255 256 private static void configureNamedPlugin(String iname) 258 throws ClassNotFoundException 259 { 260 int found = 0; 261 262 268 if (!namedPluginClasses.containsKey(iname)) 269 { 270 String namedVal = ConfigurationManager.getProperty(NAMED_PREFIX+iname); 274 if (namedVal != null) 275 { 276 namedVal = namedVal.trim(); 277 log.debug("Got Named configuration for interface="+iname+", config="+namedVal); 278 279 Pattern classnameEqual = Pattern.compile("([\\w\\p{Sc}\\.]+)\\s*\\="); 281 282 int prevEnd = -1; 283 String prevClassName = null; 284 Matcher classMatcher = classnameEqual.matcher(namedVal); 285 while (classMatcher.find()) 286 { 287 if (prevClassName != null) 288 found += installNamedConfigs(iname, prevClassName, 289 namedVal.substring(prevEnd, classMatcher.start()).trim().split("\\s*,\\s*")); 290 prevClassName = classMatcher.group(1); 291 prevEnd = classMatcher.end(); 292 } 293 if (prevClassName != null) 294 found += installNamedConfigs(iname, prevClassName, 295 namedVal.substring(prevEnd).trim().split("\\s*,\\s*")); 296 } 297 298 String selfNamedVal = ConfigurationManager.getProperty(SELFNAMED_PREFIX+iname); 301 if (selfNamedVal != null) 302 { 303 String classnames[] = selfNamedVal.trim().split("\\s*,\\s*"); 304 for (int i = 0; i < classnames.length; ++i) 305 { 306 try 307 { 308 Class pluginClass = Class.forName(classnames[i]); 309 String names[] = (String [])pluginClass.getMethod("getPluginNames", null). 310 invoke(null, null); 311 if (names == null || names.length == 0) 312 log.error("Self-named plugin class \""+classnames[i]+"\" returned null or empty name list!"); 313 else 314 found += installNamedConfigs(iname, classnames[i], names); 315 } 316 catch (NoSuchMethodException e) 317 { 318 log.error("Implementation Class \""+classnames[i]+"\" is not a subclass of SelfNamedPlugin, it has no getPluginNames() method."); 319 } 320 catch (Exception e) 321 { 322 log.error("While configuring self-named plugin: " + e.toString()); 323 } 324 } 325 } 326 namedPluginClasses.put(iname, "org.dspace.core.marker"); 327 if (found == 0) 328 log.error("No named plugins found for interface="+iname); 329 } 330 } 331 332 private static int installNamedConfigs(String iname, String classname, String names[]) 334 throws ClassNotFoundException 335 { 336 int found = 0; 337 for (int i = 0; i < names.length; ++i) 338 { 339 String key = iname+SEP+names[i]; 340 if (namedPluginClasses.containsKey(key)) 341 log.error("Name collision in named plugin, implementation class=\""+classname+ 342 "\", name=\""+names[i]+"\""); 343 else 344 namedPluginClasses.put(key, classname); 345 log.debug("Got Named Plugin, intfc="+iname+", name="+names[i]+", class="+classname); 346 ++found; 347 } 348 return found; 349 } 350 351 361 public static Object getNamedPlugin(Class intfc, String name) 362 throws PluginInstantiationException 363 { 364 try 365 { 366 String iname = intfc.getName(); 367 configureNamedPlugin(iname); 368 String key = iname + SEP + name; 369 String cname = (String )namedPluginClasses.get(key); 370 if (cname == null) 371 log.warn("Cannot find named plugin for interface="+iname+", name=\""+name+"\""); 372 else 373 { 374 Class pluginClass = Class.forName(cname); 375 if (cacheMe(pluginClass)) 376 { 377 String nkey = pluginClass.getName() + SEP + name; 378 Object cached = namedInstanceCache.get(nkey); 379 if (cached == null) 380 { 381 log.debug("Creating cached instance of: " + cname + 382 " for interface=" + iname + 383 " pluginName=" + name ); 384 cached = pluginClass.newInstance(); 385 if (cached instanceof SelfNamedPlugin) 386 ((SelfNamedPlugin)cached).setPluginInstanceName(name); 387 namedInstanceCache.put(nkey, cached); 388 } 389 return cached; 390 } 391 else 392 { 393 log.debug("Creating UNcached instance of: " + cname + 394 " for interface=" + iname + 395 " pluginName=" + name ); 396 Object result = pluginClass.newInstance(); 397 if (result instanceof SelfNamedPlugin) 398 ((SelfNamedPlugin)result).setPluginInstanceName(name); 399 return result; 400 } 401 } 402 } 403 catch (ClassNotFoundException e) 404 { 405 throw new PluginInstantiationException("Cannot load plugin class: " + 406 e.toString(), e); 407 } 408 catch (InstantiationException e) 409 { 410 throw new PluginInstantiationException(e); 411 } 412 catch (IllegalAccessException e) 413 { 414 throw new PluginInstantiationException(e); 415 } 416 417 return null; 418 } 419 420 421 434 public static String [] getAllPluginNames(Class intfc) 435 { 436 try 437 { 438 String iname = intfc.getName(); 439 configureNamedPlugin(iname); 440 String prefix = iname + SEP; 441 ArrayList result = new ArrayList (); 442 443 Iterator ki = namedPluginClasses.keySet().iterator(); 444 while (ki.hasNext()) 445 { 446 String key = (String )ki.next(); 447 if (key.startsWith(prefix)) 448 result.add(key.substring(prefix.length())); 449 } 450 if (result.size() == 0) 451 log.error("Cannot find any names for named plugin, interface="+iname); 452 453 return (String [])result.toArray(new String [result.size()]); 454 } 455 catch (ClassNotFoundException e) 456 { 457 return new String [0]; 458 } 459 } 460 461 470 public static void releasePlugin(Object plugin) 471 { 472 forgetInstance(plugin, namedInstanceCache); 473 forgetInstance(plugin, anonymousInstanceCache); 474 } 475 476 private static void forgetInstance(Object plugin, Map cacheMap) 477 { 478 Collection values = cacheMap.values(); 479 Iterator ci = values.iterator(); 480 while (ci.hasNext()) 481 { 482 Object val = ci.next(); 483 if (val == plugin) 484 values.remove(val); 485 } 486 } 487 488 492 493 private static boolean checkClassname(String iname, String msg) 495 { 496 try 497 { 498 Class intf = Class.forName(iname); 499 return true; 500 } 501 catch (ClassNotFoundException ce) 502 { 503 log.error("No class definition found for "+msg+": \""+iname+"\""); 504 } 505 return false; 506 } 507 508 private static boolean checkSelfNamed(String iname) 510 { 511 try 512 { 513 if (!checkSelfNamed(Class.forName(iname))) 514 log.error("The class \""+iname+"\" is NOT a subclass of SelfNamedPlugin but it should be!"); 515 } 516 catch (ClassNotFoundException ce) 517 { 518 log.error("No class definition found for self-named class interface: \""+iname+"\""); 519 } 520 return false; 521 } 522 523 private static boolean checkSelfNamed(Class cls) 525 { 526 Class sup = cls.getSuperclass(); 527 if (sup == null) 528 return false; 529 else if (sup.equals(SelfNamedPlugin.class)) 530 return true; 531 else 532 return checkSelfNamed(sup); 533 } 534 535 private static void checkNames(String iname) 538 { 539 try 540 { 541 configureNamedPlugin(iname); 542 } 543 catch (ClassNotFoundException ce) 544 { 545 } 547 } 548 549 564 public static void checkConfiguration() 565 throws IOException 566 { 567 570 571 Map singleKey = new HashMap (); 573 Map sequenceKey = new HashMap (); 574 Map namedKey = new HashMap (); 575 Map selfnamedKey = new HashMap (); 576 Map reusableKey = new HashMap (); 577 578 File config = ConfigurationManager.getConfigurationFile(); 582 BufferedReader cr = new BufferedReader (new FileReader (config)); 583 String line = null; 584 boolean continued = false; 585 HashMap keyMap = new HashMap (); 586 Pattern keyPattern = Pattern.compile("([^\\s\\=\\:]+)"); 587 while ((line = cr.readLine()) != null) 588 { 589 line = line.trim(); 590 if (line.startsWith("!") || line.startsWith("#")) 591 continued = false; 592 else 593 { 594 if (!continued && line.startsWith("plugin.")) 595 { 596 Matcher km = keyPattern.matcher(line); 597 if (km.find()) 598 { 599 String key = line.substring(0, km.end(1)); 600 if (keyMap.containsKey(key)) 601 log.error("Duplicate key \""+key+"\" in DSpace configuration file="+config.toString()); 602 else 603 keyMap.put(key, key); 604 605 if (key.startsWith(SINGLE_PREFIX)) 606 singleKey.put(key.substring(SINGLE_PREFIX.length()), key); 607 else if (key.startsWith(SEQUENCE_PREFIX)) 608 sequenceKey.put(key.substring(SEQUENCE_PREFIX.length()), key); 609 else if (key.startsWith(NAMED_PREFIX)) 610 namedKey.put(key.substring(NAMED_PREFIX.length()), key); 611 else if (key.startsWith(SELFNAMED_PREFIX)) 612 selfnamedKey.put(key.substring(SELFNAMED_PREFIX.length()), key); 613 else if (key.startsWith(REUSABLE_PREFIX)) 614 reusableKey.put(key.substring(REUSABLE_PREFIX.length()), key); 615 else 616 log.error("Key with unknown prefix \""+key+"\" in DSpace configuration file="+config.toString()); 617 } 618 } 619 continued = line.length() > 0 && line.charAt(line.length()-1) == '\\'; 620 } 621 } 622 623 Enumeration pne = ConfigurationManager.propertyNames(); 625 HashSet pn = new HashSet (); 626 while (pne.hasMoreElements()) 627 { 628 String nk = (String )pne.nextElement(); 629 if (nk.startsWith("plugin.")) 630 { 631 pn.add(nk); 632 if (!keyMap.containsKey(nk)) 633 log.error("Key is in ConfigurationManager.propertyNames() but NOT text crawl: \""+nk+"\""); 634 } 635 } 636 Iterator pi = keyMap.keySet().iterator(); 637 while (pi.hasNext()) 638 { 639 String key = (String )pi.next(); 640 if (!pn.contains(key)) 641 log.error("Key is in text crawl but NOT ConfigurationManager.propertyNames(): \""+key+"\""); 642 } 643 644 ArrayList allInterfaces = new ArrayList (); 648 allInterfaces.addAll(singleKey.keySet()); 649 allInterfaces.addAll(sequenceKey .keySet()); 650 allInterfaces.addAll(namedKey.keySet()); 651 allInterfaces.addAll(selfnamedKey.keySet()); 652 allInterfaces.addAll(reusableKey.keySet()); 653 Iterator ii = allInterfaces.iterator(); 654 while (ii.hasNext()) 655 checkClassname((String )ii.next(), "key interface or class"); 656 657 Map allImpls = new HashMap (); 662 663 ii = singleKey.keySet().iterator(); 665 while (ii.hasNext()) 666 { 667 String key = (String )ii.next(); 668 String val = ConfigurationManager.getProperty(SINGLE_PREFIX+key); 669 if (val == null) 670 log.error("Single plugin config not found for: "+SINGLE_PREFIX+key); 671 else 672 { 673 val = val.trim(); 674 if (checkClassname(val, "implementation class")) 675 allImpls.put(val, val); 676 } 677 } 678 679 ii = sequenceKey.keySet().iterator(); 681 while (ii.hasNext()) 682 { 683 String key = (String )ii.next(); 684 String val = ConfigurationManager.getProperty(SEQUENCE_PREFIX+key); 685 if (val == null) 686 log.error("Sequence plugin config not found for: "+SEQUENCE_PREFIX+key); 687 else 688 { 689 val = val.trim(); 690 String classname[] = val.split("\\s*,\\s*"); 691 for (int i = 0; i < classname.length; ++i) 692 if (checkClassname(classname[i], "implementation class")) 693 allImpls.put(classname[i], classname[i]); 694 } 695 } 696 697 ii = selfnamedKey.keySet().iterator(); 700 while (ii.hasNext()) 701 { 702 String key = (String )ii.next(); 703 String val = ConfigurationManager.getProperty(SELFNAMED_PREFIX+key); 704 if (val == null) 705 log.error("Selfnamed plugin config not found for: "+SELFNAMED_PREFIX+key); 706 else 707 { 708 val = val.trim(); 709 String classname[] = val.split("\\s*,\\s*"); 710 for (int i = 0; i < classname.length; ++i) 711 if (checkClassname(classname[i], "selfnamed implementation class")) 712 { 713 allImpls.put(classname[i], classname[i]); 714 checkSelfNamed(classname[i]); 715 } 716 checkNames(key); 717 } 718 } 719 720 ii = namedKey.keySet().iterator(); 723 Pattern classnameEqual = Pattern.compile("([\\w\\p{Sc}\\.]+)\\s*\\="); 724 while (ii.hasNext()) 725 { 726 String key = (String )ii.next(); 727 String val = ConfigurationManager.getProperty(NAMED_PREFIX+key); 728 if (val == null) 729 log.error("Named plugin config not found for: "+NAMED_PREFIX+key); 730 else 731 { 732 checkNames(key); 733 val = val.trim(); 734 Matcher classMatcher = classnameEqual.matcher(val); 735 while (classMatcher.find()) 736 { 737 String classname = classMatcher.group(1); 738 739 if (checkClassname(classname, "implementation class")) 740 allImpls.put(classname, classname); 741 } 742 } 743 } 744 745 Iterator ri = reusableKey.keySet().iterator(); 747 while (ri.hasNext()) 748 { 749 String rk = (String )ri.next(); 750 if (!(allImpls.containsKey(rk))) 751 log.error("In plugin.reusable configuration, class \""+rk+"\" is NOT a plugin implementation class."); 752 } 753 } 754 755 760 public static void main(String [] argv) throws Exception 761 { 762 checkConfiguration(); 763 } 764 } 765 | Popular Tags |