1 16 17 package org.apache.catalina.cluster.deploy; 18 19 import java.io.File ; 20 import java.io.IOException ; 21 import java.net.URL ; 22 import java.util.HashMap ; 23 24 import javax.management.MBeanServer ; 25 import javax.management.ObjectName ; 26 27 import org.apache.catalina.Context; 28 import org.apache.catalina.Engine; 29 import org.apache.catalina.Host; 30 import org.apache.catalina.Lifecycle; 31 import org.apache.catalina.LifecycleException; 32 import org.apache.catalina.cluster.CatalinaCluster; 33 import org.apache.catalina.cluster.ClusterDeployer; 34 import org.apache.catalina.cluster.ClusterMessage; 35 import org.apache.catalina.cluster.Member; 36 import org.apache.commons.modeler.Registry; 37 38 57 public class FarmWarDeployer implements ClusterDeployer, FileChangeListener { 58 59 public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory 60 .getLog(FarmWarDeployer.class); 61 62 63 protected CatalinaCluster cluster = null; 64 65 protected boolean started = false; 67 protected HashMap fileFactories = new HashMap (); 68 69 protected String deployDir; 70 71 protected String tempDir; 72 73 protected String watchDir; 74 75 protected boolean watchEnabled = false; 76 77 protected WarWatcher watcher = null; 78 79 82 private int count = 0; 83 84 89 protected int processDeployFrequency = 2; 90 91 94 protected File configBase = null; 95 96 99 protected Host host = null; 100 101 104 protected File appBase = null; 105 106 109 protected MBeanServer mBeanServer = null; 110 111 114 protected ObjectName oname = null; 115 116 117 public FarmWarDeployer() { 118 } 119 120 121 public void start() throws Exception { 122 if (started) 123 return; 124 getCluster().addClusterListener(this); 125 if (watchEnabled) { 126 watcher = new WarWatcher(this, new File (getWatchDir())); 127 if (log.isInfoEnabled()) 128 log.info("Cluster deployment is watching " + getWatchDir() 129 + " for changes."); 130 } 132 host = (Host) getCluster().getContainer(); 134 Engine engine = (Engine) host.getParent(); 135 try { 136 oname = new ObjectName (engine.getName() + ":type=Deployer,host=" 137 + host.getName()); 138 } catch (Exception e) { 139 log.error("Can't construct MBean object name" + e); 140 } 141 configBase = new File (System.getProperty("catalina.base"), "conf"); 142 if (engine != null) { 143 configBase = new File (configBase, engine.getName()); 144 } 145 if (host != null) { 146 configBase = new File (configBase, host.getName()); 147 } 148 149 mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); 151 152 started = true; 153 count = 0; 154 if (log.isInfoEnabled()) 155 log.info("Cluster FarmWarDeployer started."); 156 } 157 158 163 public void stop() throws LifecycleException { 164 started = false; 165 getCluster().removeClusterListener(this); 166 count = 0; 167 if (watcher != null) { 168 watcher.clear(); 169 watcher = null; 170 171 } 172 if (log.isInfoEnabled()) 173 log.info("Cluster FarmWarDeployer stopped."); 174 } 175 176 public void cleanDeployDir() { 177 throw new java.lang.UnsupportedOperationException ( 178 "Method cleanDeployDir() not yet implemented."); 179 } 180 181 188 public void messageReceived(ClusterMessage msg) { 189 try { 190 if (msg instanceof FileMessage && msg != null) { 191 FileMessage fmsg = (FileMessage) msg; 192 if (log.isDebugEnabled()) 193 log.debug("receive cluster deployment [ path: " 194 + fmsg.getContextPath() + " war: " 195 + fmsg.getFileName() + " ]"); 196 FileMessageFactory factory = getFactory(fmsg); 197 if (factory.writeMessage(fmsg)) { 199 String name = factory.getFile().getName(); 201 if (!name.endsWith(".war")) 202 name = name + ".war"; 203 File deployable = new File (getDeployDir(), name); 204 try { 205 String path = fmsg.getContextPath(); 206 if (!isServiced(path)) { 207 addServiced(path); 208 try { 209 remove(path); 210 factory.getFile().renameTo(deployable); 211 check(path); 212 } finally { 213 removeServiced(path); 214 } 215 if (log.isDebugEnabled()) 216 log.debug("deployment from " + path 217 + " finished."); 218 } else 219 log.error("Application " + path 220 + " in used. touch war file " + name 221 + " again!"); 222 } catch (Exception ex) { 223 log.error(ex); 224 } finally { 225 removeFactory(fmsg); 226 } 227 } } else if (msg instanceof UndeployMessage && msg != null) { 229 try { 230 UndeployMessage umsg = (UndeployMessage) msg; 231 String path = umsg.getContextPath(); 232 if (log.isDebugEnabled()) 233 log.debug("receive cluster undeployment from " + path); 234 if (!isServiced(path)) { 235 addServiced(path); 236 try { 237 remove(path); 238 } finally { 239 removeServiced(path); 240 } 241 if (log.isDebugEnabled()) 242 log.debug("undeployment from " + path 243 + " finished."); 244 } else 245 log 246 .error("Application " 247 + path 248 + " in used. Sorry not remove from backup cluster nodes!"); 249 } catch (Exception ex) { 250 log.error(ex); 251 } 252 } } catch (java.io.IOException x) { 254 log.error("Unable to read farm deploy file message.", x); 255 } 256 } 257 258 266 public synchronized FileMessageFactory getFactory(FileMessage msg) 267 throws java.io.FileNotFoundException , java.io.IOException { 268 File tmpFile = new File (msg.getFileName()); 269 File writeToFile = new File (getTempDir(), tmpFile.getName()); 270 FileMessageFactory factory = (FileMessageFactory) fileFactories.get(msg 271 .getFileName()); 272 if (factory == null) { 273 factory = FileMessageFactory.getInstance(writeToFile, true); 274 fileFactories.put(msg.getFileName(), factory); 275 } 276 return factory; 277 } 278 279 284 public void removeFactory(FileMessage msg) { 285 fileFactories.remove(msg.getFileName()); 286 } 287 288 299 public boolean accept(ClusterMessage msg) { 300 return (msg instanceof FileMessage) || (msg instanceof UndeployMessage); 301 } 302 303 332 public void install(String contextPath, URL war) throws IOException { 333 Member[] members = getCluster().getMembers(); 334 Member localMember = getCluster().getLocalMember(); 335 FileMessageFactory factory = FileMessageFactory.getInstance(new File ( 336 war.getFile()), false); 337 FileMessage msg = new FileMessage(localMember, war.getFile(), 338 contextPath); 339 if(log.isDebugEnabled()) 340 log.debug("Send cluster war deployment [ path:" 341 + contextPath + " war: " + war + " ] started."); 342 msg = factory.readMessage(msg); 343 while (msg != null) { 344 for (int i = 0; i < members.length; i++) { 345 if (log.isDebugEnabled()) 346 log.debug("Send cluster war fragment [ path: " 347 + contextPath + " war: " + war + " to: " + members[i] + " ]"); 348 getCluster().send(msg, members[i]); 349 } msg = factory.readMessage(msg); 351 } if(log.isDebugEnabled()) 353 log.debug("Send cluster war deployment [ path: " 354 + contextPath + " war: " + war + " ] finished."); 355 } 356 357 379 public void remove(String contextPath, boolean undeploy) throws IOException { 380 if (log.isInfoEnabled()) 381 log.info("Cluster wide remove of web app " + contextPath); 382 Member[] members = getCluster().getMembers(); 384 Member localMember = getCluster().getLocalMember(); 385 UndeployMessage msg = new UndeployMessage(localMember, System 386 .currentTimeMillis(), "Undeploy:" + contextPath + ":" 387 + System.currentTimeMillis(), contextPath, undeploy); 388 if (log.isDebugEnabled()) 389 log.debug("Send cluster wide undeployment from " 390 + contextPath ); 391 cluster.send(msg); 392 if (undeploy) { 394 try { 395 if (!isServiced(contextPath)) { 396 addServiced(contextPath); 397 try { 398 remove(contextPath); 399 } finally { 400 removeServiced(contextPath); 401 } 402 } else 403 log.error("Local remove from " + contextPath 404 + "failed, other manager has app in service!"); 405 406 } catch (Exception ex) { 407 log.error("local remove from " + contextPath + " failed", ex); 408 } 409 } 410 411 } 412 413 418 public void fileModified(File newWar) { 419 try { 420 File deployWar = new File (getDeployDir(), newWar.getName()); 421 copy(newWar, deployWar); 422 String contextName = "/" 423 + deployWar.getName().substring(0, 424 deployWar.getName().lastIndexOf(".war")); 425 if (log.isInfoEnabled()) 426 log.info("Installing webapp[" + contextName + "] from " 427 + deployWar.getAbsolutePath()); 428 try { 429 remove(contextName, false); 430 } catch (Exception x) { 431 log.error("No removal", x); 432 } 433 install(contextName, deployWar.toURL()); 434 } catch (Exception x) { 435 log.error("Unable to install WAR file", x); 436 } 437 } 438 439 444 public void fileRemoved(File removeWar) { 445 try { 446 String contextName = "/" 447 + removeWar.getName().substring(0, 448 removeWar.getName().lastIndexOf(".war")); 449 if (log.isInfoEnabled()) 450 log.info("Removing webapp[" + contextName + "]"); 451 remove(contextName, true); 452 } catch (Exception x) { 453 log.error("Unable to remove WAR file", x); 454 } 455 } 456 457 460 protected String getConfigFile(String path) { 461 String basename = null; 462 if (path.equals("")) { 463 basename = "ROOT"; 464 } else { 465 basename = path.substring(1).replace('/', '#'); 466 } 467 return (basename); 468 } 469 470 473 protected String getDocBase(String path) { 474 String basename = null; 475 if (path.equals("")) { 476 basename = "ROOT"; 477 } else { 478 basename = path.substring(1); 479 } 480 return (basename); 481 } 482 483 487 protected File getAppBase() { 488 489 if (appBase != null) { 490 return appBase; 491 } 492 493 File file = new File (host.getAppBase()); 494 if (!file.isAbsolute()) 495 file = new File (System.getProperty("catalina.base"), host 496 .getAppBase()); 497 try { 498 appBase = file.getCanonicalFile(); 499 } catch (IOException e) { 500 appBase = file; 501 } 502 return (appBase); 503 504 } 505 506 509 protected void remove(String path) throws Exception { 510 Context context = (Context) host.findChild(path); 513 if (context != null) { 514 if(log.isDebugEnabled()) 515 log.debug("Undeploy local context " +path ); 516 ((Lifecycle) context).stop(); 517 File war = new File (getAppBase(), getDocBase(path) + ".war"); 518 File dir = new File (getAppBase(), getDocBase(path)); 519 File xml = new File (configBase, getConfigFile(path) + ".xml"); 520 if (war.exists()) { 521 war.delete(); 522 } else if (dir.exists()) { 523 undeployDir(dir); 524 } else { 525 xml.delete(); 526 } 527 check(path); 529 } 530 531 } 532 533 540 protected void undeployDir(File dir) { 541 542 String files[] = dir.list(); 543 if (files == null) { 544 files = new String [0]; 545 } 546 for (int i = 0; i < files.length; i++) { 547 File file = new File (dir, files[i]); 548 if (file.isDirectory()) { 549 undeployDir(file); 550 } else { 551 file.delete(); 552 } 553 } 554 dir.delete(); 555 556 } 557 558 563 public void backgroundProcess() { 564 if (started) { 565 count = (count + 1) % processDeployFrequency; 566 if (count == 0 && watchEnabled) { 567 watcher.check(); 568 } 569 } 570 571 } 572 573 574 575 578 protected void check(String name) throws Exception { 579 String [] params = { name }; 580 String [] signature = { "java.lang.String" }; 581 mBeanServer.invoke(oname, "check", params, signature); 582 } 583 584 587 protected boolean isServiced(String name) throws Exception { 588 String [] params = { name }; 589 String [] signature = { "java.lang.String" }; 590 Boolean result = (Boolean ) mBeanServer.invoke(oname, "isServiced", 591 params, signature); 592 return result.booleanValue(); 593 } 594 595 598 protected void addServiced(String name) throws Exception { 599 String [] params = { name }; 600 String [] signature = { "java.lang.String" }; 601 mBeanServer.invoke(oname, "addServiced", params, signature); 602 } 603 604 607 protected void removeServiced(String name) throws Exception { 608 String [] params = { name }; 609 String [] signature = { "java.lang.String" }; 610 mBeanServer.invoke(oname, "removeServiced", params, signature); 611 } 612 613 614 public CatalinaCluster getCluster() { 615 return cluster; 616 } 617 618 public void setCluster(CatalinaCluster cluster) { 619 this.cluster = cluster; 620 } 621 622 public boolean equals(Object listener) { 623 return super.equals(listener); 624 } 625 626 public int hashCode() { 627 return super.hashCode(); 628 } 629 630 public String getDeployDir() { 631 return deployDir; 632 } 633 634 public void setDeployDir(String deployDir) { 635 this.deployDir = deployDir; 636 } 637 638 public String getTempDir() { 639 return tempDir; 640 } 641 642 public void setTempDir(String tempDir) { 643 this.tempDir = tempDir; 644 } 645 646 public String getWatchDir() { 647 return watchDir; 648 } 649 650 public void setWatchDir(String watchDir) { 651 this.watchDir = watchDir; 652 } 653 654 public boolean isWatchEnabled() { 655 return watchEnabled; 656 } 657 658 public boolean getWatchEnabled() { 659 return watchEnabled; 660 } 661 662 public void setWatchEnabled(boolean watchEnabled) { 663 this.watchEnabled = watchEnabled; 664 } 665 666 669 public int getProcessDeployFrequency() { 670 671 return (this.processDeployFrequency); 672 673 } 674 675 681 public void setProcessDeployFrequency(int processExpiresFrequency) { 682 683 if (processExpiresFrequency <= 0) { 684 return; 685 } 686 this.processDeployFrequency = processExpiresFrequency; 687 } 688 689 693 protected boolean copy(File from, File to) { 694 try { 695 if (!to.exists()) 696 to.createNewFile(); 697 java.io.FileInputStream is = new java.io.FileInputStream (from); 698 java.io.FileOutputStream os = new java.io.FileOutputStream (to, 699 false); 700 byte[] buf = new byte[4096]; 701 while (true) { 702 int len = is.read(buf); 703 if (len < 0) 704 break; 705 os.write(buf, 0, len); 706 } 707 is.close(); 708 os.close(); 709 } catch (IOException e) { 710 log.error("Unable to copy file from:" + from + " to:" + to, e); 711 return false; 712 } 713 return true; 714 } 715 716 } | Popular Tags |