1 20 21 package org.jivesoftware.whack.container; 22 23 import org.dom4j.Document; 24 import org.dom4j.Element; 25 import org.dom4j.io.SAXReader; 26 import org.xmpp.component.Component; 27 import org.xmpp.component.ComponentException; 28 import org.xmpp.component.ComponentManager; 29 30 import java.io.File ; 31 import java.io.FileFilter ; 32 import java.io.FileOutputStream ; 33 import java.io.InputStream ; 34 import java.util.*; 35 import java.util.concurrent.ScheduledExecutorService ; 36 import java.util.concurrent.ScheduledThreadPoolExecutor ; 37 import java.util.concurrent.TimeUnit ; 38 import java.util.jar.JarEntry ; 39 import java.util.jar.JarFile ; 40 import java.util.zip.ZipFile ; 41 42 51 public class ComponentFinder { 52 53 private File componentDirectory; 54 private Map<String ,Component> components; 55 private Map<Component,ComponentClassLoader> classloaders; 56 private Map<Component,File > componentDirs; 57 private Map<Component, String > componentDomains; 58 private boolean setupMode = true; 59 private ComponentManager manager; 60 private ScheduledExecutorService executor = null; 61 62 67 public ComponentFinder(ServerContainer server, File componentDir) { 68 this.componentDirectory = componentDir; 69 components = new HashMap<String ,Component>(); 70 componentDirs = new HashMap<Component,File >(); 71 classloaders = new HashMap<Component,ComponentClassLoader>(); 72 componentDomains = new HashMap<Component,String >(); 73 manager = server.getManager(); 74 setupMode = server.isSetupMode(); 75 } 76 77 80 public void start() { 81 executor = new ScheduledThreadPoolExecutor (1); 82 executor.scheduleWithFixedDelay(new ComponentMonitor(), 0, 10, TimeUnit.SECONDS); 83 } 84 85 88 public void shutdown() { 89 if (executor != null) { 91 executor.shutdown(); 92 } 93 for (String subdomain : componentDomains.values()) { 95 try { 96 manager.removeComponent(subdomain); 97 } catch (ComponentException e) { 98 manager.getLog().error("Error shutting down component", e); 99 } 100 } 101 components.clear(); 102 componentDirs.clear(); 103 classloaders.clear(); 104 componentDomains.clear(); 105 } 106 107 112 public Collection<Component> getComponents() { 113 return Collections.unmodifiableCollection(components.values()); 114 } 115 116 124 public Component getComponent(String name) { 125 return components.get(name); 126 } 127 128 134 public File getComponentDirectory(Component component) { 135 return componentDirs.get(component); 136 } 137 138 151 private void loadComponent(File componentDir) { 152 if (setupMode) { 154 return; 155 } 156 manager.getLog().debug("Loading component: " + componentDir.getName()); 157 Component component = null; 158 try { 159 File componentConfig = new File (componentDir, "component.xml"); 160 if (componentConfig.exists()) { 161 SAXReader saxReader = new SAXReader(); 162 Document componentXML = saxReader.read(componentConfig); 163 ComponentClassLoader classLoader = new ComponentClassLoader(componentDir); 164 String className = componentXML.selectSingleNode("/component/class").getText(); 165 String subdomain = componentXML.selectSingleNode("/component/subdomain").getText(); 166 Class aClass = classLoader.loadClass(className); 168 component = (Component)aClass.newInstance(); 169 170 manager.addComponent(subdomain, component); 171 172 components.put(componentDir.getName(), component); 173 componentDirs.put(component, componentDir); 174 classloaders.put(component, classLoader); 175 componentDomains.put(component, subdomain); 176 File webXML = new File (componentDir, "web" + File.separator + "web.xml"); 178 if (webXML.exists()) { 179 ComponentServlet.registerServlets(this, component, webXML); 180 } 181 Element adminElement = (Element)componentXML.selectSingleNode("/component/adminconsole"); 183 if (adminElement != null) { 184 Element imageEl = (Element)adminElement.selectSingleNode( 186 "/component/adminconsole/global/logo-image"); 187 if (imageEl != null) { 188 imageEl.setText("components/" + componentDir.getName() + "/" + imageEl.getText()); 189 } 190 imageEl = (Element)adminElement.selectSingleNode( 191 "/component/adminconsole/global/login-image"); 192 if (imageEl != null) { 193 imageEl.setText("components/" + componentDir.getName() + "/" + imageEl.getText()); 194 } 195 203 } 204 } 205 else { 206 manager.getLog().warn("Component " + componentDir + " could not be loaded: no component.xml file found"); 207 } 208 } 209 catch (Exception e) { 210 manager.getLog().error("Error loading component: " + componentDir.getName(), e); 211 } 212 } 213 214 226 public void unloadComponent(String componentName) { 227 manager.getLog().debug("Unloading component " + componentName); 228 Component component = components.get(componentName); 229 if (component == null) { 230 return; 231 } 232 File webXML = new File (componentDirectory + File.separator + componentName + 233 File.separator + "web" + File.separator + "web.xml"); 234 if (webXML.exists()) { 235 ComponentServlet.unregisterServlets(webXML); 237 } 238 239 ComponentClassLoader classLoader = classloaders.get(component); 240 try { 241 manager.removeComponent(componentDomains.get(component)); 242 } catch (ComponentException e) { 243 manager.getLog().error("Error shutting down component", e); 244 } 245 classLoader.destroy(); 246 components.remove(componentName); 247 componentDirs.remove(component); 248 classloaders.remove(component); 249 componentDomains.remove(component); 250 } 251 252 public Class loadClass(String className, Component component) throws ClassNotFoundException , 253 IllegalAccessException , InstantiationException 254 { 255 ComponentClassLoader loader = classloaders.get(component); 256 return loader.loadClass(className); 257 } 258 259 267 public String getName(Component component) { 268 String name = getElementValue(component, "/component/name"); 269 if (name != null) { 270 return name; 271 } 272 else { 273 return componentDirs.get(component).getName(); 274 } 275 } 276 277 284 public String getDescription(Component component) { 285 return getElementValue(component, "/component/description"); 286 } 287 288 295 public String getAuthor(Component component) { 296 return getElementValue(component, "/component/author"); 297 } 298 299 306 public String getVersion(Component component) { 307 return getElementValue(component, "/component/version"); 308 } 309 310 318 private String getElementValue(Component component, String xpath) { 319 File componentDir = componentDirs.get(component); 320 if (componentDir == null) { 321 return null; 322 } 323 try { 324 File componentConfig = new File (componentDir, "component.xml"); 325 if (componentConfig.exists()) { 326 SAXReader saxReader = new SAXReader(); 327 Document componentXML = saxReader.read(componentConfig); 328 Element element = (Element)componentXML.selectSingleNode(xpath); 329 if (element != null) { 330 return element.getTextTrim(); 331 } 332 } 333 } 334 catch (Exception e) { 335 manager.getLog().error(e); 336 } 337 return null; 338 } 339 340 345 private class ComponentMonitor implements Runnable { 346 347 public void run() { 348 try { 349 File [] jars = componentDirectory.listFiles(new FileFilter () { 350 public boolean accept(File pathname) { 351 String fileName = pathname.getName().toLowerCase(); 352 return (fileName.endsWith(".jar") || fileName.endsWith(".war")); 353 } 354 }); 355 356 for (int i=0; i<jars.length; i++) { 357 File jarFile = jars[i]; 358 String componentName = jarFile.getName().substring( 359 0, jarFile.getName().length()-4).toLowerCase(); 360 File dir = new File (componentDirectory, componentName); 362 if (!dir.exists()) { 364 unzipComponent(componentName, jarFile, dir); 365 } 366 else if (jarFile.lastModified() > dir.lastModified()) { 369 unloadComponent(componentName); 370 System.gc(); 372 while (!deleteDir(dir)) { 373 manager.getLog().error("Error unloading component " + componentName + ". " + 374 "Will attempt again momentarily."); 375 Thread.sleep(5000); 376 } 377 unzipComponent(componentName, jarFile, dir); 379 } 380 } 381 382 File [] dirs = componentDirectory.listFiles(new FileFilter () { 383 public boolean accept(File pathname) { 384 return pathname.isDirectory(); 385 } 386 }); 387 388 for (int i=0; i<dirs.length; i++) { 389 File dirFile = dirs[i]; 390 if (!components.containsKey(dirFile.getName())) { 392 loadComponent(dirFile); 393 } 394 } 395 396 if (components.size() > jars.length + 1) { 399 List<String > toDelete = new ArrayList<String >(); 402 for (String componentName : components.keySet()) { 403 File file = new File (componentDirectory, componentName + ".jar"); 404 if (!file.exists()) { 405 toDelete.add(componentName); 406 } 407 } 408 for (String componentName : toDelete) { 409 unloadComponent(componentName); 410 System.gc(); 411 while (!deleteDir(new File (componentDirectory, componentName))) { 412 manager.getLog().error("Error unloading component " + componentName + ". " + 413 "Will attempt again momentarily."); 414 Thread.sleep(5000); 415 } 416 } 417 } 418 } 419 catch (Exception e) { 420 manager.getLog().error(e); 421 } 422 } 423 424 432 private void unzipComponent(String componentName, File file, File dir) { 433 try { 434 ZipFile zipFile = new JarFile (file); 435 if (zipFile.getEntry("component.xml") == null) { 437 return; 438 } 439 dir.mkdir(); 440 manager.getLog().debug("Extracting component: " + componentName); 441 for (Enumeration e=zipFile.entries(); e.hasMoreElements(); ) { 442 JarEntry entry = (JarEntry )e.nextElement(); 443 File entryFile = new File (dir, entry.getName()); 444 if (entry.getName().toLowerCase().endsWith("manifest.mf")) { 446 continue; 447 } 448 if (!entry.isDirectory()) { 449 entryFile.getParentFile().mkdirs(); 450 FileOutputStream out = new FileOutputStream (entryFile); 451 InputStream zin = zipFile.getInputStream(entry); 452 byte [] b = new byte[512]; 453 int len = 0; 454 while ( (len=zin.read(b))!= -1 ) { 455 out.write(b,0,len); 456 } 457 out.flush(); 458 out.close(); 459 zin.close(); 460 } 461 } 462 zipFile.close(); 463 zipFile = null; 464 } 465 catch (Exception e) { 466 manager.getLog().error(e); 467 } 468 } 469 470 473 public boolean deleteDir(File dir) { 474 if (dir.isDirectory()) { 475 String [] children = dir.list(); 476 for (int i=0; i<children.length; i++) { 477 boolean success = deleteDir(new File (dir, children[i])); 478 if (!success) { 479 return false; 480 } 481 } 482 } 483 return dir.delete(); 484 } 485 } 486 } 487 | Popular Tags |