1 17 18 package org.apache.geronimo.deployment; 19 20 import java.io.File ; 21 import java.io.IOException ; 22 import java.net.URI ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.Collections ; 26 import java.util.Enumeration ; 27 import java.util.Hashtable ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Properties ; 31 import java.util.Set ; 32 import java.util.jar.Attributes ; 33 import java.util.jar.JarFile ; 34 import java.util.jar.Manifest ; 35 36 import javax.management.ObjectName ; 37 38 import org.apache.commons.logging.Log; 39 import org.apache.commons.logging.LogFactory; 40 import org.apache.geronimo.common.DeploymentException; 41 import org.apache.geronimo.deployment.util.DeploymentUtil; 42 import org.apache.geronimo.gbean.AbstractName; 43 import org.apache.geronimo.gbean.AbstractNameQuery; 44 import org.apache.geronimo.gbean.GBeanInfo; 45 import org.apache.geronimo.gbean.GBeanInfoBuilder; 46 import org.apache.geronimo.kernel.GBeanNotFoundException; 47 import org.apache.geronimo.kernel.Kernel; 48 import org.apache.geronimo.kernel.config.Configuration; 49 import org.apache.geronimo.kernel.config.ConfigurationData; 50 import org.apache.geronimo.kernel.config.ConfigurationManager; 51 import org.apache.geronimo.kernel.config.ConfigurationStore; 52 import org.apache.geronimo.kernel.config.ConfigurationUtil; 53 import org.apache.geronimo.kernel.config.InvalidConfigException; 54 import org.apache.geronimo.kernel.config.DeploymentWatcher; 55 import org.apache.geronimo.kernel.repository.Artifact; 56 import org.apache.geronimo.kernel.repository.ArtifactResolver; 57 import org.apache.geronimo.system.configuration.ExecutableConfigurationUtil; 58 import org.apache.geronimo.system.main.CommandLineManifest; 59 60 65 public class Deployer { 66 private static final Log log = LogFactory.getLog(Deployer.class); 67 private final int REAPER_INTERVAL = 60 * 1000; 68 private final Properties pendingDeletionIndex = new Properties (); 69 private DeployerReaper reaper; 70 private final Collection builders; 71 private final Collection stores; 72 private final Collection watchers; 73 private final ArtifactResolver artifactResolver; 74 private final Kernel kernel; 75 76 public Deployer(Collection builders, Collection stores, Collection watchers, Kernel kernel) { 77 this(builders, stores, watchers, getArtifactResolver(kernel), kernel); 78 } 79 80 private static ArtifactResolver getArtifactResolver(Kernel kernel) { 81 ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel); 82 return configurationManager.getArtifactResolver(); 83 } 84 85 public Deployer(Collection builders, Collection stores, Collection watchers, ArtifactResolver artifactResolver, Kernel kernel) { 86 this.builders = builders; 87 this.stores = stores; 88 this.watchers = watchers; 89 this.artifactResolver = artifactResolver; 90 this.kernel = kernel; 91 92 this.reaper = new DeployerReaper(REAPER_INTERVAL); 94 Thread t = new Thread (reaper, "Geronimo Config Store Reaper"); 95 t.setDaemon(true); 96 t.start(); 97 } 98 99 public List deploy(boolean inPlace, File moduleFile, File planFile) throws DeploymentException { 100 return deploy(inPlace, moduleFile, planFile, null); 101 } 102 103 public List deploy(boolean inPlace, File moduleFile, File planFile, String targetConfigStore) throws DeploymentException { 104 File originalModuleFile = moduleFile; 105 File tmpDir = null; 106 if (moduleFile != null && !moduleFile.isDirectory()) { 107 try { 112 tmpDir = File.createTempFile("geronimo-deployer", ".tmpdir"); 113 tmpDir.delete(); 114 tmpDir.mkdir(); 115 File tmpFile = new File (tmpDir, moduleFile.getName()); 116 DeploymentUtil.copyFile(moduleFile, tmpFile); 117 moduleFile = tmpFile; 118 } catch (IOException e) { 119 throw new DeploymentException(e); 120 } 121 } 122 123 try { 124 return deploy(inPlace, planFile, moduleFile, null, true, null, null, null, null, null, null, null, targetConfigStore); 125 } catch (DeploymentException e) { 126 log.debug("Deployment failed: plan=" + planFile + ", module=" + originalModuleFile, e); 127 throw e.cleanse(); 128 } finally { 129 if (tmpDir != null) { 130 if (!DeploymentUtil.recursiveDelete(tmpDir)) { 131 pendingDeletionIndex.setProperty(tmpDir.getName(), "delete"); 132 } 133 } 134 } 135 } 136 137 147 public String getRemoteDeployUploadURL() { 148 Set set = kernel.listGBeans(new AbstractNameQuery("org.apache.geronimo.deployment.remote.RemoteDeployToken")); 150 if (set.size() == 0) { 151 return null; 152 } 153 AbstractName token = (AbstractName) set.iterator().next(); 154 set = kernel.getDependencyManager().getParents(token); 156 ObjectName config = null; 157 for (Iterator it = set.iterator(); it.hasNext();) { 158 AbstractName name = (AbstractName) it.next(); 159 if (Configuration.isConfigurationObjectName(name.getObjectName())) { 160 config = name.getObjectName(); 161 break; 162 } 163 } 164 if (config == null) { 165 log.warn("Unable to find remote deployment configuration; is the remote deploy web application running?"); 166 return null; 167 } 168 Hashtable hash = new Hashtable (); 170 hash.put("J2EEApplication", token.getObjectName().getKeyProperty("J2EEApplication")); 171 hash.put("j2eeType", "WebModule"); 172 try { 173 hash.put("name", Configuration.getConfigurationID(config).toString()); 174 Set names = kernel.listGBeans(new AbstractNameQuery(null, hash)); 175 if (names.size() != 1) { 176 log.error("Unable to look up remote deploy upload URL"); 177 return null; 178 } 179 AbstractName module = (AbstractName) names.iterator().next(); 180 return kernel.getAttribute(module, "URLFor") + "/upload"; 181 } catch (Exception e) { 182 log.error("Unable to look up remote deploy upload URL", e); 183 return null; 184 } 185 } 186 187 public List deploy(boolean inPlace, 188 File planFile, 189 File moduleFile, 190 File targetFile, 191 boolean install, 192 String mainClass, 193 String mainGBean, String mainMethod, String manifestConfigurations, String classPath, 194 String endorsedDirs, 195 String extensionDirs, 196 String targetConfigurationStore) throws DeploymentException { 197 if (planFile == null && moduleFile == null) { 198 throw new DeploymentException("No plan or module specified"); 199 } 200 201 if (planFile != null) { 202 if (!planFile.exists()) { 203 throw new DeploymentException("Plan file does not exist: " + planFile.getAbsolutePath()); 204 } 205 if (!planFile.isFile()) { 206 throw new DeploymentException("Plan file is not a regular file: " + planFile.getAbsolutePath()); 207 } 208 } 209 210 JarFile module = null; 211 if (moduleFile != null) { 212 if (inPlace && !moduleFile.isDirectory()) { 213 throw new DeploymentException("In place deployment is not allowed for packed module"); 214 } 215 if (!moduleFile.exists()) { 216 throw new DeploymentException("Module file does not exist: " + moduleFile.getAbsolutePath()); 217 } 218 try { 219 module = DeploymentUtil.createJarFile(moduleFile); 220 } catch (IOException e) { 221 throw new DeploymentException("Cound not open module file: " + moduleFile.getAbsolutePath(), e); 222 } 223 } 224 225 ModuleIDBuilder idBuilder = new ModuleIDBuilder(); 227 try { 228 Object plan = null; 229 ConfigurationBuilder builder = null; 230 for (Iterator i = builders.iterator(); i.hasNext();) { 231 ConfigurationBuilder candidate = (ConfigurationBuilder) i.next(); 232 plan = candidate.getDeploymentPlan(planFile, module, idBuilder); 233 if (plan != null) { 234 builder = candidate; 235 break; 236 } 237 } 238 if (builder == null) { 239 throw new DeploymentException("Cannot deploy the requested application module because no deployer is able to handle it. " + 240 " This can happen if you have omitted the J2EE deployment descriptor, disabled a deployer module, or if, for example, you are trying to deploy an" + 241 " EJB module on a minimal Geronimo server that does not have EJB support installed. (" + 242 (planFile == null ? "" : "planFile=" + planFile.getAbsolutePath()) + 243 (moduleFile == null ? "" : (planFile == null ? "" : ", ") + "moduleFile=" + moduleFile.getAbsolutePath()) + ")"); 244 } 245 246 Artifact configID = builder.getConfigurationID(plan, module, idBuilder); 247 if (!configID.isResolved()) { 249 configID = idBuilder.resolve(configID, "car"); 250 } 251 try { 253 kernel.getGBeanState(Configuration.getConfigurationAbstractName(configID)); 254 throw new DeploymentException("Module " + configID + " already exists in the server. Try to undeploy it first or use the redeploy command."); 255 } catch (GBeanNotFoundException e) { 256 } 258 259 Manifest manifest; 261 if (mainClass != null) { 262 manifest = new Manifest (); 263 Attributes mainAttributes = manifest.getMainAttributes(); 264 mainAttributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); 265 if (mainClass != null) { 266 mainAttributes.putValue(Attributes.Name.MAIN_CLASS.toString(), mainClass); 267 } 268 if (mainGBean != null) { 269 mainAttributes.putValue(CommandLineManifest.MAIN_GBEAN.toString(), mainGBean); 270 } 271 if (mainMethod != null) { 272 mainAttributes.putValue(CommandLineManifest.MAIN_METHOD.toString(), mainMethod); 273 } 274 if (manifestConfigurations != null) { 275 mainAttributes.putValue(CommandLineManifest.CONFIGURATIONS.toString(), manifestConfigurations); 276 } 277 if (classPath != null) { 278 mainAttributes.putValue(Attributes.Name.CLASS_PATH.toString(), classPath); 279 } 280 if (endorsedDirs != null) { 281 mainAttributes.putValue(CommandLineManifest.ENDORSED_DIRS.toString(), endorsedDirs); 282 } 283 if (extensionDirs != null) { 284 mainAttributes.putValue(CommandLineManifest.EXTENSION_DIRS.toString(), extensionDirs); 285 } 286 } else { 287 manifest = null; 288 } 289 290 if (stores.isEmpty()) { 291 throw new DeploymentException("No ConfigurationStores!"); 292 } 293 ConfigurationStore store; 294 if (targetConfigurationStore != null) { 295 AbstractName targetStoreName = new AbstractName(new URI (targetConfigurationStore)); 296 store = (ConfigurationStore) kernel.getGBean(targetStoreName); 297 } else { 298 store = (ConfigurationStore) stores.iterator().next(); 299 } 300 301 DeploymentContext context = builder.buildConfiguration(inPlace, configID, plan, module, stores, artifactResolver, store); 303 List configurations = new ArrayList (); 304 boolean configsCleanupRequired = false; 305 configurations.add(context.getConfigurationData()); 306 configurations.addAll(context.getAdditionalDeployment()); 307 308 if (configurations.isEmpty()) { 309 throw new DeploymentException("Deployer did not create any configurations"); 310 } 311 312 Thread thread = Thread.currentThread(); 318 ClassLoader oldCl = thread.getContextClassLoader(); 319 thread.setContextClassLoader( context.getConfiguration().getConfigurationClassLoader()); 320 try { 321 if (targetFile != null) { 322 if (configurations.size() > 1) { 323 throw new DeploymentException("Deployer created more than one configuration"); 324 } 325 ConfigurationData configurationData = (ConfigurationData) configurations.get(0); 326 ExecutableConfigurationUtil.createExecutableConfiguration(configurationData, manifest, targetFile); 327 } 328 if (install) { 329 List deployedURIs = new ArrayList (); 330 for (Iterator iterator = configurations.iterator(); iterator.hasNext();) { 331 ConfigurationData configurationData = (ConfigurationData) iterator.next(); 332 store.install(configurationData); 333 deployedURIs.add(configurationData.getId().toString()); 334 } 335 notifyWatchers(deployedURIs); 336 return deployedURIs; 337 } else { 338 configsCleanupRequired = true; 339 return Collections.EMPTY_LIST; 340 } 341 } catch (DeploymentException e) { 342 configsCleanupRequired = true; 343 throw e; 344 } catch (IOException e) { 345 configsCleanupRequired = true; 346 throw e; 347 } catch (InvalidConfigException e) { 348 configsCleanupRequired = true; 349 throw new DeploymentException(e); 351 } catch (Throwable e) { 352 configsCleanupRequired = true; 354 throw e; 355 } finally { 356 thread.setContextClassLoader(oldCl); 357 if (context != null) { 358 context.close(); 359 } 360 if (configsCleanupRequired) { 361 cleanupConfigurations(configurations); 363 } 364 } 365 } catch (Throwable e) { 366 376 if (e instanceof Error ) { 377 log.error("Deployment failed due to ", e); 378 throw (Error ) e; 379 } else if (e instanceof DeploymentException) { 380 throw (DeploymentException) e; 381 } else if (e instanceof Exception ) { 382 log.error("Deployment failed due to ", e); 383 throw new DeploymentException(e); 384 } 385 throw new Error (e); 386 } finally { 387 DeploymentUtil.close(module); 388 } 389 } 390 391 private void notifyWatchers(List list) { 392 Artifact[] arts = new Artifact[list.size()]; 393 for (int i = 0; i < list.size(); i++) { 394 String s = (String ) list.get(i); 395 arts[i] = Artifact.create(s); 396 } 397 for (Iterator it = watchers.iterator(); it.hasNext();) { 398 DeploymentWatcher watcher = (DeploymentWatcher) it.next(); 399 for (int i = 0; i < arts.length; i++) { 400 Artifact art = arts[i]; 401 watcher.deployed(art); 402 } 403 } 404 } 405 406 private void cleanupConfigurations(List configurations) { 407 for (Iterator iterator = configurations.iterator(); iterator.hasNext();) { 408 ConfigurationData configurationData = (ConfigurationData) iterator.next(); 409 File configurationDir = configurationData.getConfigurationDir(); 410 if (!DeploymentUtil.recursiveDelete(configurationDir)) { 411 pendingDeletionIndex.setProperty(configurationDir.getName(), "delete"); 412 log.debug("Queued deployment directory to be reaped " + configurationDir); 413 } 414 } 415 } 416 417 422 class DeployerReaper implements Runnable { 423 private final int reaperInterval; 424 private volatile boolean done = false; 425 426 public DeployerReaper(int reaperInterval) { 427 this.reaperInterval = reaperInterval; 428 } 429 430 public void close() { 431 this.done = true; 432 } 433 434 public void run() { 435 log.debug("ConfigStoreReaper started"); 436 while (!done) { 437 try { 438 Thread.sleep(reaperInterval); 439 } catch (InterruptedException e) { 440 continue; 441 } 442 reap(); 443 } 444 } 445 446 450 public void reap() { 451 if (pendingDeletionIndex.size() == 0) 453 return; 454 Enumeration list = pendingDeletionIndex.propertyNames(); 456 while (list.hasMoreElements()) { 457 String dirName = (String ) list.nextElement(); 458 File deleteDir = new File (dirName); 459 460 if (!DeploymentUtil.recursiveDelete(deleteDir)) { 461 pendingDeletionIndex.remove(deleteDir); 462 log.debug("Reaped deployment directory " + deleteDir); 463 } 464 } 465 } 466 } 467 468 public static final GBeanInfo GBEAN_INFO; 469 470 private static final String DEPLOYER = "Deployer"; 471 472 static { 473 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(Deployer.class, DEPLOYER); 474 475 infoFactory.addAttribute("kernel", Kernel.class, false); 476 infoFactory.addAttribute("remoteDeployUploadURL", String .class, false); 477 infoFactory.addOperation("deploy", new Class []{boolean.class, File .class, File .class}); 478 infoFactory.addOperation("deploy", new Class []{boolean.class, File .class, File .class, String .class}); 479 infoFactory.addOperation("deploy", new Class []{boolean.class, File .class, File .class, File .class, boolean.class, String .class, String .class, String .class, String .class, String .class, String .class, String .class, String .class}); 480 481 infoFactory.addReference("Builders", ConfigurationBuilder.class, "ConfigBuilder"); 482 infoFactory.addReference("Store", ConfigurationStore.class, "ConfigurationStore"); 483 infoFactory.addReference("Watchers", DeploymentWatcher.class); 484 485 infoFactory.setConstructor(new String []{"Builders", "Store", "Watchers", "kernel"}); 486 487 GBEAN_INFO = infoFactory.getBeanInfo(); 488 } 489 490 public static GBeanInfo getGBeanInfo() { 491 return GBEAN_INFO; 492 } 493 } 494 | Popular Tags |