1 17 package org.apache.servicemix.jbi.framework; 18 19 import java.io.File ; 20 import java.io.IOException ; 21 import java.net.MalformedURLException ; 22 import java.net.URL ; 23 import java.util.ArrayList ; 24 import java.util.Date ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Set ; 31 import java.util.Timer ; 32 import java.util.TimerTask ; 33 34 import javax.jbi.JBIException; 35 import javax.jbi.management.DeploymentException; 36 import javax.management.JMException ; 37 import javax.management.MBeanAttributeInfo ; 38 import javax.resource.spi.work.Work ; 39 import javax.resource.spi.work.WorkException ; 40 41 import org.apache.commons.logging.Log; 42 import org.apache.commons.logging.LogFactory; 43 import org.apache.servicemix.jbi.container.EnvironmentContext; 44 import org.apache.servicemix.jbi.container.JBIContainer; 45 import org.apache.servicemix.jbi.deployment.Component; 46 import org.apache.servicemix.jbi.deployment.Descriptor; 47 import org.apache.servicemix.jbi.deployment.DescriptorFactory; 48 import org.apache.servicemix.jbi.deployment.ServiceAssembly; 49 import org.apache.servicemix.jbi.management.AttributeInfoHelper; 50 import org.apache.servicemix.jbi.management.BaseSystemService; 51 import org.apache.servicemix.jbi.util.FileUtil; 52 import org.apache.servicemix.jbi.util.XmlPersistenceSupport; 53 54 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap; 55 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean; 56 61 public class AutoDeploymentService extends BaseSystemService implements AutoDeploymentServiceMBean { 62 63 private static final Log log = LogFactory.getLog(AutoDeploymentService.class); 64 private EnvironmentContext environmentContext; 65 private DeploymentService deploymentService; 66 private InstallationService installationService; 67 private boolean monitorInstallationDirectory = true; 68 private boolean monitorDeploymentDirectory = true; 69 private int monitorInterval = 10; 70 private AtomicBoolean started = new AtomicBoolean(false); 71 private Timer statsTimer; 72 private TimerTask timerTask; 73 private Map pendingComponents = new ConcurrentHashMap(); 74 private Map pendingSAs = new ConcurrentHashMap(); 75 private Map installFileMap = null; 76 private Map deployFileMap = null; 77 78 81 public String getDescription(){ 82 return "automatically installs and deploys JBI Archives"; 83 } 84 85 88 public boolean isMonitorInstallationDirectory(){ 89 return monitorInstallationDirectory; 90 } 91 92 96 public void setMonitorInstallationDirectory(boolean monitorInstallationDirectory){ 97 this.monitorInstallationDirectory=monitorInstallationDirectory; 98 } 99 100 103 public boolean isMonitorDeploymentDirectory(){ 104 return monitorDeploymentDirectory; 105 } 106 107 111 public void setMonitorDeploymentDirectory(boolean monitorDeploymentDirectory){ 112 this.monitorDeploymentDirectory=monitorDeploymentDirectory; 113 } 114 115 118 public int getMonitorInterval(){ 119 return monitorInterval; 120 } 121 122 126 public void setMonitorInterval(int monitorInterval){ 127 this.monitorInterval=monitorInterval; 128 } 129 130 public void start() throws javax.jbi.JBIException{ 131 super.start(); 132 if(started.compareAndSet(false,true)){ 133 scheduleDirectoryTimer(); 134 } 135 } 136 137 143 public void stop() throws javax.jbi.JBIException{ 144 if(started.compareAndSet(true,false)){ 145 super.stop(); 146 if(timerTask!=null){ 147 timerTask.cancel(); 148 } 149 } 150 } 151 152 158 public void init(JBIContainer container) throws JBIException { 159 super.init(container); 160 this.environmentContext=container.getEnvironmentContext(); 161 this.installationService=container.getInstallationService(); 162 this.deploymentService=container.getDeploymentService(); 163 if(environmentContext.getTmpDir()!=null){ 165 FileUtil.deleteFile(environmentContext.getTmpDir()); 166 } 167 initializeFileMaps(); 168 } 169 170 protected Class getServiceMBean() { 171 return AutoDeploymentServiceMBean.class; 172 } 173 174 175 181 public ArchiveEntry updateExternalArchive(String location,boolean autoStart) throws DeploymentException { 182 ArchiveEntry entry = new ArchiveEntry(); 183 entry.location = location; 184 entry.lastModified = new Date (); 185 updateArchive(location,entry,autoStart); 186 return entry; 187 } 188 189 196 public void updateArchive(String location, ArchiveEntry entry, boolean autoStart) throws DeploymentException { 197 File tmpDir = null; 198 try { 199 tmpDir = AutoDeploymentService.unpackLocation(environmentContext.getTmpDir(), location); 200 } catch (Exception e) { 201 throw failure("deploy", "Unable to unpack archive: " + location, e); 202 } 203 if (tmpDir == null) { 205 throw failure("deploy", "Unable to find jbi descriptor: " + location); 206 } 207 Descriptor root = null; 208 try { 209 root = DescriptorFactory.buildDescriptor(tmpDir); 210 } catch (Exception e) { 211 throw failure("deploy", "Unable to build jbi descriptor: " + location, e); 212 } 213 if (root == null) { 214 throw failure("deploy", "Unable to find jbi descriptor: " + location); 215 } 216 if (root != null) { 217 try{ 218 container.getBroker().suspend(); 219 if (root.getComponent() != null) { 220 Component comp = root.getComponent(); 221 String componentName = comp.getIdentification().getName(); 222 entry.type = "component"; 223 entry.name = componentName; 224 try { 225 if (container.getRegistry().getComponent(componentName) != null) { 226 installationService.unloadInstaller(componentName, true); 227 } 228 entry.dependencies = getSharedLibraryNames(comp); 230 if (log.isDebugEnabled()) { 231 log.debug("Component dependencies: " + entry.dependencies); 232 } 233 String missings = null; 234 boolean canInstall = true; 235 for (Iterator it = entry.dependencies.iterator(); it.hasNext();) { 236 String libraryName = (String ) it.next(); 237 if (container.getRegistry().getSharedLibrary(libraryName) == null) { 238 canInstall = false; 239 if (missings != null) { 240 missings += ", " + libraryName; 241 } else { 242 missings = libraryName; 243 } 244 } 245 } 246 if (canInstall) { 247 installationService.install(tmpDir, null, root, autoStart); 248 checkPendingSAs(); 249 } else { 250 entry.pending = true; 251 log.warn("Shared libraries " + missings + " are not installed yet: the component" + componentName + 252 " installation is suspended and will be resumed once the listed shared libraries are installed"); 253 pendingComponents.put(tmpDir, entry); 254 } 255 } catch (Exception e) { 256 String errStr = "Failed to update Component: " + componentName; 257 log.error(errStr, e); 258 throw new DeploymentException(errStr, e); 259 } 260 } else if (root.getSharedLibrary() != null) { 261 String libraryName = root.getSharedLibrary().getIdentification().getName(); 262 entry.type = "library"; 263 entry.name = libraryName; 264 installationService.doInstallSharedLibrary(tmpDir, root.getSharedLibrary()); 265 checkPendingComponents(); 266 } else if (root.getServiceAssembly() != null) { 267 ServiceAssembly sa = root.getServiceAssembly(); 268 String name = sa.getIdentification().getName(); 269 entry.type = "assembly"; 270 entry.name = name; 271 try { 272 if (deploymentService.isSaDeployed(name)) { 273 deploymentService.shutDown(name); 274 deploymentService.undeploy(name); 275 } 276 entry.dependencies = getComponentNames(sa); 278 if (log.isDebugEnabled()) { 279 log.debug("SA dependencies: " + entry.dependencies); 280 } 281 String missings = null; 282 boolean canDeploy = true; 283 for (Iterator it = entry.dependencies.iterator(); it.hasNext();) { 284 String componentName = (String ) it.next(); 285 if (container.getComponent(componentName) == null) { 286 canDeploy = false; 287 if (missings != null) { 288 missings += ", " + componentName; 289 } else { 290 missings = componentName; 291 } 292 } 293 } 294 if (canDeploy) { 295 deploymentService.deployServiceAssembly(tmpDir, sa); 296 if (autoStart){ 297 deploymentService.start(name); 298 } 299 } else { 300 entry.pending = true; 302 log.warn("Components " + missings + " are not installed yet: the service assembly " + name + 303 " deployment is suspended and will be resumed once the listed components are installed"); 304 pendingSAs.put(tmpDir, entry); 305 } 306 } catch (Exception e) { 307 String errStr = "Failed to update Service Assembly: " + name; 308 log.error(errStr, e); 309 throw new DeploymentException(errStr, e); 310 } 311 } 312 } finally { 313 container.getBroker().resume(); 314 } 315 } 316 } 317 318 protected DeploymentException failure(String task, String info) { 319 return failure(task, info, null, null); 320 } 321 322 protected DeploymentException failure(String task, String info, Exception e) { 323 return failure(task, info, e, null); 324 } 325 326 protected DeploymentException failure(String task, String info, Exception e, List componentResults) { 327 ManagementSupport.Message msg = new ManagementSupport.Message(); 328 msg.setTask(task); 329 msg.setResult("FAILED"); 330 msg.setType("ERROR"); 331 msg.setException(e); 332 msg.setMessage(info); 333 return new DeploymentException(ManagementSupport.createFrameworkMessage(msg, componentResults)); 334 } 335 336 protected Set getComponentNames(ServiceAssembly sa) { 337 Set names = new HashSet (); 338 if (sa.getServiceUnits() != null && sa.getServiceUnits().length > 0) { 339 for (int i = 0; i < sa.getServiceUnits().length; i++) { 340 names.add(sa.getServiceUnits()[i].getTarget().getComponentName()); 341 } 342 } 343 return names; 344 } 345 346 protected Set getSharedLibraryNames(Component comp) { 347 Set names = new HashSet (); 348 if (comp.getSharedLibraries() != null && comp.getSharedLibraries().length > 0) { 349 for (int i = 0; i < comp.getSharedLibraries().length; i++) { 350 names.add(comp.getSharedLibraries()[i].getName()); 351 } 352 } 353 return names; 354 } 355 356 362 public void removeArchive(ArchiveEntry entry) throws DeploymentException { 363 log.info("Attempting to remove archive at: " + entry.location); 364 try{ 365 container.getBroker().suspend(); 366 if ("component".equals(entry.type)) { 367 log.info("Uninstalling component: " + entry.name); 368 installationService.loadInstaller(entry.name); 370 installationService.unloadInstaller(entry.name,true); 372 } 373 if ("library".equals(entry.type)) { 374 log.info("Removing shared library: " + entry.name); 375 installationService.uninstallSharedLibrary(entry.name); 376 } 377 if ("assembly".equals(entry.type)) { 378 log.info("Undeploying service assembly " + entry.name); 379 try{ 380 if(deploymentService.isSaDeployed(entry.name)){ 381 deploymentService.shutDown(entry.name); 382 deploymentService.undeploy(entry.name); 383 } 384 } catch(Exception e) { 385 String errStr = "Failed to update service assembly: "+ entry.name; 386 log.error(errStr,e); 387 throw new DeploymentException(errStr,e); 388 } 389 } 390 } finally { 391 container.getBroker().resume(); 392 } 393 } 394 395 400 private void checkPendingSAs() { 401 Set deployedSas = new HashSet (); 402 for (Iterator it = pendingSAs.entrySet().iterator(); it.hasNext();) { 403 Map.Entry me = (Map.Entry ) it.next(); 404 ArchiveEntry entry = (ArchiveEntry) me.getValue(); 405 boolean canDeploy = true; 406 for (Iterator it2 = entry.dependencies.iterator(); it2.hasNext();) { 407 String componentName = (String ) it2.next(); 408 if (container.getComponent(componentName) == null) { 409 canDeploy = false; 410 break; 411 } 412 } 413 if (canDeploy) { 414 File tmp = (File ) me.getKey(); 415 deployedSas.add(tmp); 416 try { 417 Descriptor root = DescriptorFactory.buildDescriptor(tmp); 418 deploymentService.deployServiceAssembly(tmp, root.getServiceAssembly()); 419 deploymentService.start(root.getServiceAssembly().getIdentification().getName()); 420 } catch (Exception e) { 421 String errStr = "Failed to update Service Assembly: " + tmp.getName(); 422 log.error(errStr, e); 423 } 424 } 425 } 426 if (!deployedSas.isEmpty()) { 427 for (Iterator it = deployedSas.iterator(); it.hasNext();) { 429 ArchiveEntry entry = (ArchiveEntry) pendingSAs.remove(it.next()); 430 entry.pending = false; 431 } 432 persistState(environmentContext.getDeploymentDir(), deployFileMap); 434 persistState(environmentContext.getInstallationDir(), installFileMap); 435 } 436 } 437 438 private void checkPendingComponents() { 439 Set installedComponents = new HashSet (); 440 for (Iterator it = pendingComponents.entrySet().iterator(); it.hasNext();) { 441 Map.Entry me = (Map.Entry ) it.next(); 442 ArchiveEntry entry = (ArchiveEntry) me.getValue(); 443 boolean canInstall = true; 444 for (Iterator it2 = entry.dependencies.iterator(); it2.hasNext();) { 445 String libraryName = (String ) it2.next(); 446 if (container.getRegistry().getSharedLibrary(libraryName) == null) { 447 canInstall = false; 448 break; 449 } 450 } 451 if (canInstall) { 452 File tmp = (File ) me.getKey(); 453 installedComponents.add(tmp); 454 try { 455 Descriptor root = DescriptorFactory.buildDescriptor(tmp); 456 installationService.install(tmp, null, root, true); 457 } catch (Exception e) { 458 String errStr = "Failed to update Component: " + tmp.getName(); 459 log.error(errStr, e); 460 } 461 } 462 } 463 if (!installedComponents.isEmpty()) { 464 for (Iterator it = installedComponents.iterator(); it.hasNext();) { 466 ArchiveEntry entry = (ArchiveEntry) pendingComponents.remove(it.next()); 467 entry.pending = false; 468 } 469 persistState(environmentContext.getDeploymentDir(), deployFileMap); 471 persistState(environmentContext.getInstallationDir(), installFileMap); 472 checkPendingSAs(); 474 } 475 } 476 477 483 public MBeanAttributeInfo [] getAttributeInfos() throws JMException { 484 AttributeInfoHelper helper=new AttributeInfoHelper(); 485 helper.addAttribute(getObjectToManage(),"monitorInstallationDirectory", 486 "Periodically monitor the Installation directory"); 487 helper.addAttribute(getObjectToManage(),"monitorInterval","Interval (secs) before monitoring"); 488 return AttributeInfoHelper.join(super.getAttributeInfos(),helper.getAttributeInfos()); 489 } 490 491 499 protected static File unpackLocation(File tmpRoot, String location) throws DeploymentException { 500 File tmpDir = null; 501 try { 502 File file = new File (location); 503 if (file.isDirectory()) { 504 if (log.isDebugEnabled()) { 505 log.debug("Deploying an exploded jar/zip, we will create a temporary jar for it."); 506 } 507 File newFile = new File (tmpRoot.getAbsolutePath() + "/exploded.jar"); 509 newFile.delete(); 510 FileUtil.zipDir(file.getAbsolutePath(), newFile.getAbsolutePath()); 511 file = newFile; 512 if (log.isDebugEnabled()) { 513 log.debug("Deployment will now work from " + file.getAbsolutePath()); 514 } 515 } 516 if (!file.exists()) { 517 try{ 519 URL url = new URL (location); 520 String fileName = url.getFile(); 521 if (fileName == null || (!fileName.endsWith(".zip") && !fileName.endsWith(".jar"))) { 522 throw new DeploymentException("Location: " + location + " is not an archive"); 523 } 524 file = FileUtil.unpackArchive(url,tmpRoot); 525 } catch (MalformedURLException e) { 526 throw new DeploymentException(e); 527 } 528 } 529 if (FileUtil.archiveContainsEntry(file, DescriptorFactory.DESCRIPTOR_FILE)) { 530 tmpDir = FileUtil.createUniqueDirectory(tmpRoot, file.getName()); 531 FileUtil.unpackArchive(file, tmpDir); 532 if (log.isDebugEnabled()) { 533 log.debug("Unpacked archive " + location + " to " + tmpDir); 534 } 535 } 536 } catch (IOException e) { 537 throw new DeploymentException(e); 538 } 539 return tmpDir; 540 } 541 542 private void scheduleDirectoryTimer(){ 543 if (!container.isEmbedded() && (isMonitorInstallationDirectory() || isMonitorDeploymentDirectory())) { 544 if(statsTimer==null){ 545 statsTimer=new Timer (true); 546 } 547 if(timerTask!=null){ 548 timerTask.cancel(); 549 } 550 timerTask=new TimerTask (){ 551 public void run(){ 552 if(isMonitorInstallationDirectory()){ 553 monitorDirectory(environmentContext.getInstallationDir(),installFileMap); 554 } 555 if(isMonitorDeploymentDirectory()){ 556 monitorDirectory(environmentContext.getDeploymentDir(),deployFileMap); 557 } 558 } 559 }; 560 long interval=monitorInterval*1000; 561 statsTimer.scheduleAtFixedRate(timerTask,0,interval); 562 } 563 } 564 565 566 private void monitorDirectory(final File root,final Map fileMap){ 567 if(root!=null) 568 log.debug("Monitoring directory "+root.getAbsolutePath()+" for new or modified archives"); 569 else 570 log.debug("No directory to monitor for new or modified archives for "+"" 571 +((fileMap==installFileMap)?"Installation":"Deployment")+"."); 572 List tmpList=new ArrayList (); 573 if(root!=null&&root.exists()&&root.isDirectory()){ 574 File [] files=root.listFiles(); 575 if(files!=null){ 576 for(int i=0;i<files.length;i++){ 577 final File file=files[i]; 578 tmpList.add(file.getName()); 579 if(file.getPath().endsWith(".jar")||file.getPath().endsWith(".zip")){ 580 ArchiveEntry lastEntry = (ArchiveEntry) fileMap.get(file.getName()); 581 if(lastEntry == null || file.lastModified() > lastEntry.lastModified.getTime()){ 582 try{ 583 final ArchiveEntry entry = new ArchiveEntry(); 584 entry.location = file.getName(); 585 entry.lastModified = new Date (file.lastModified()); 586 fileMap.put(file.getName(), entry); 587 container.getWorkManager().doWork(new Work (){ 588 public void run(){ 589 log.info("Directory: "+root.getName()+": Archive changed: processing " 590 +file.getName()+" ..."); 591 try{ 592 updateArchive(file.getAbsolutePath(), entry, true); 593 log.info("Directory: "+root.getName()+": Finished installation of archive: " 594 +file.getName()); 595 }catch(Exception e){ 596 log.warn("Directory: "+root.getName()+": Automatic install of "+file 597 +" failed",e); 598 } 599 } 600 601 public void release(){} 602 }); 603 }catch(WorkException e){ 604 log.warn("Automatic install of "+file+" failed",e); 605 }finally{ 606 persistState(root, fileMap); 607 } 608 } 609 } 610 } 611 } 612 Map map=new HashMap (fileMap); 614 for(Iterator i=map.keySet().iterator();i.hasNext();){ 615 String location=i.next().toString(); 616 if(!tmpList.contains(location)){ 617 ArchiveEntry entry = (ArchiveEntry) fileMap.remove(location); 618 try{ 619 log.info("Location "+location+" no longer exists - removing ..."); 620 removeArchive(entry); 621 } catch (DeploymentException e) { 622 log.error("Failed to removeArchive: "+location,e); 623 } 624 } 625 } 626 if (!map.equals(fileMap)){ 627 persistState(root, fileMap); 628 } 629 } 630 } 631 632 private void persistState(File root, Map map) { 633 try { 634 File file = new File (environmentContext.getJbiRootDir(), root.getName() + ".xml"); 635 XmlPersistenceSupport.write(file, map); 636 } catch (IOException e) { 637 log.error("Failed to persist file state to: " + root, e); 638 } 639 } 640 641 private Map readState(File root) { 642 Map result = new HashMap (); 643 try { 644 File file = new File (environmentContext.getJbiRootDir(), root.getName() + ".xml"); 645 if (file.exists()) { 646 result = (Map ) XmlPersistenceSupport.read(file); 647 } else { 648 log.debug("State file doesn't exist: " + file.getPath()); 649 } 650 } catch (Exception e) { 651 log.error("Failed to read file state from: " + root, e); 652 } 653 return result; 654 } 655 656 private void initializeFileMaps(){ 657 if (isMonitorInstallationDirectory() && !container.isEmbedded()) { 658 try { 659 installFileMap=readState(environmentContext.getInstallationDir()); 660 removePendingEntries(installFileMap); 661 } catch (Exception e) { 662 log.error("Failed to read installed state", e); 663 } 664 } 665 if (isMonitorDeploymentDirectory() && !container.isEmbedded()) { 666 try { 667 deployFileMap=readState(environmentContext.getDeploymentDir()); 668 removePendingEntries(deployFileMap); 669 } catch (Exception e) { 670 log.error("Failed to read deployed state", e); 671 } 672 } 673 } 674 675 private void removePendingEntries(Map map) { 676 Set pendings = new HashSet (); 677 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 678 Map.Entry e = (Map.Entry ) it.next(); 679 if (((ArchiveEntry) e.getValue()).pending) { 680 pendings.add(e.getKey()); 681 } 682 } 683 for (Iterator it = pendings.iterator(); it.hasNext();) { 684 map.remove(it.next()); 685 } 686 } 687 688 public static class ArchiveEntry { 689 public String location; 690 public Date lastModified; 691 public String type; 692 public String name; 693 public boolean pending; 694 public transient Set dependencies; 695 } 696 } 697 | Popular Tags |