001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.deployment.service; 019 020 import java.beans.PropertyEditorManager; 021 import java.io.File; 022 import java.io.FileNotFoundException; 023 import java.io.IOException; 024 import java.net.URI; 025 import java.net.URL; 026 import java.util.Collection; 027 import java.util.Collections; 028 import java.util.Map; 029 import java.util.HashMap; 030 import java.util.jar.JarFile; 031 032 import javax.xml.namespace.QName; 033 034 import org.apache.geronimo.common.DeploymentException; 035 import org.apache.geronimo.deployment.ConfigurationBuilder; 036 import org.apache.geronimo.deployment.DeploymentContext; 037 import org.apache.geronimo.deployment.ModuleIDBuilder; 038 import org.apache.geronimo.deployment.NamespaceDrivenBuilder; 039 import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection; 040 import org.apache.geronimo.deployment.util.DeploymentUtil; 041 import org.apache.geronimo.deployment.xbeans.ArtifactType; 042 import org.apache.geronimo.deployment.xbeans.EnvironmentType; 043 import org.apache.geronimo.deployment.xbeans.ModuleDocument; 044 import org.apache.geronimo.deployment.xbeans.ModuleType; 045 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil; 046 import org.apache.geronimo.gbean.AbstractName; 047 import org.apache.geronimo.gbean.GBeanInfo; 048 import org.apache.geronimo.gbean.GBeanInfoBuilder; 049 import org.apache.geronimo.gbean.GBeanLifecycle; 050 import org.apache.geronimo.kernel.Kernel; 051 import org.apache.geronimo.kernel.Naming; 052 import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException; 053 import org.apache.geronimo.kernel.config.ConfigurationManager; 054 import org.apache.geronimo.kernel.config.ConfigurationModuleType; 055 import org.apache.geronimo.kernel.config.ConfigurationStore; 056 import org.apache.geronimo.kernel.config.ConfigurationUtil; 057 import org.apache.geronimo.kernel.config.SimpleConfigurationManager; 058 import org.apache.geronimo.kernel.repository.Artifact; 059 import org.apache.geronimo.kernel.repository.ArtifactResolver; 060 import org.apache.geronimo.kernel.repository.Environment; 061 import org.apache.geronimo.kernel.repository.Repository; 062 import org.apache.xmlbeans.XmlCursor; 063 import org.apache.xmlbeans.XmlException; 064 import org.apache.xmlbeans.XmlObject; 065 066 /** 067 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 068 */ 069 public class ServiceConfigBuilder implements ConfigurationBuilder, GBeanLifecycle { 070 private final Environment defaultEnvironment; 071 private final Collection repositories; 072 073 private static final QName MODULE_QNAME = ModuleDocument.type.getDocumentElementName(); 074 public static final String SERVICE_MODULE = "ServiceModule"; 075 private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>(); 076 static { 077 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment", "http://geronimo.apache.org/xml/ns/deployment-1.2"); 078 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment-1.1", "http://geronimo.apache.org/xml/ns/deployment-1.2"); 079 NAMESPACE_UPDATES.put("http://geronimo.apache.org/xml/ns/deployment/javabean", "http://geronimo.apache.org/xml/ns/deployment/javabean-1.0"); 080 } 081 082 private final Naming naming; 083 private final ConfigurationManager configurationManager; 084 private final NamespaceDrivenBuilderCollection serviceBuilders; 085 086 public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Naming naming) { 087 this(defaultEnvironment, repositories, Collections.EMPTY_LIST, naming, null); 088 } 089 090 public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Kernel kernel) { 091 this(defaultEnvironment, repositories, serviceBuilders, kernel.getNaming(), ConfigurationUtil.getConfigurationManager(kernel)); 092 } 093 094 public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Naming naming) { 095 this(defaultEnvironment, repositories, serviceBuilders, naming, null); 096 } 097 098 public void doStart() throws Exception { 099 XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES); 100 } 101 102 public void doStop() { 103 XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES); 104 } 105 106 public void doFail() { 107 doStop(); 108 } 109 110 private ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Naming naming, ConfigurationManager configurationManager) { 111 this.naming = naming; 112 this.configurationManager = configurationManager; 113 114 EnvironmentBuilder environmentBuilder = new EnvironmentBuilder(); 115 this.defaultEnvironment = defaultEnvironment; 116 117 this.repositories = repositories; 118 this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders, GBeanBuilder.SERVICE_QNAME); 119 } 120 121 public Object getDeploymentPlan(File planFile, JarFile jarFile, ModuleIDBuilder idBuilder) throws DeploymentException { 122 if (planFile == null && jarFile == null) { 123 return null; 124 } 125 126 try { 127 XmlObject xmlObject; 128 if (planFile != null) { 129 xmlObject = XmlBeansUtil.parse(planFile.toURL(), getClass().getClassLoader()); 130 } else { 131 URL path = DeploymentUtil.createJarURL(jarFile, "META-INF/geronimo-service.xml"); 132 try { 133 xmlObject = XmlBeansUtil.parse(path, getClass().getClassLoader()); 134 } catch (FileNotFoundException e) { 135 // It has a JAR but no plan, and nothing at META-INF/geronimo-service.xml, 136 // therefore it's not a service deployment 137 return null; 138 } 139 } 140 if(xmlObject == null) { 141 return null; 142 } 143 144 XmlCursor cursor = xmlObject.newCursor(); 145 try { 146 cursor.toFirstChild(); 147 if (!MODULE_QNAME.equals(cursor.getName())) { 148 return null; 149 } 150 } finally { 151 cursor.dispose(); 152 } 153 ModuleDocument moduleDoc; 154 if (xmlObject instanceof ModuleDocument) { 155 moduleDoc = (ModuleDocument) xmlObject; 156 } else { 157 moduleDoc = (ModuleDocument) xmlObject.changeType(ModuleDocument.type); 158 } 159 XmlBeansUtil.validateDD(moduleDoc); 160 // If there's no artifact ID and we won't be able to figure one out later, use the plan file name. Bit of a hack. 161 if(jarFile == null && (moduleDoc.getModule().getEnvironment() == null || 162 moduleDoc.getModule().getEnvironment().getModuleId() == null || 163 moduleDoc.getModule().getEnvironment().getModuleId().getArtifactId() == null)) { 164 if(moduleDoc.getModule().getEnvironment() == null) { 165 moduleDoc.getModule().addNewEnvironment(); 166 } 167 if(moduleDoc.getModule().getEnvironment().getModuleId() == null) { 168 moduleDoc.getModule().getEnvironment().addNewModuleId(); 169 } 170 String name = planFile.getName(); 171 int pos = name.lastIndexOf('.'); 172 if(pos > -1) { 173 name = name.substring(0, pos); 174 } 175 moduleDoc.getModule().getEnvironment().getModuleId().setArtifactId(name); 176 } 177 return moduleDoc.getModule(); 178 } catch (XmlException e) { 179 throw new DeploymentException("Could not parse xml in plan", e); 180 } catch (IOException e) { 181 throw new DeploymentException("no plan at " + planFile, e); 182 } 183 } 184 185 public Artifact getConfigurationID(Object plan, JarFile module, ModuleIDBuilder idBuilder) throws IOException, DeploymentException { 186 ModuleType configType = (ModuleType) plan; 187 EnvironmentType environmentType = configType.getEnvironment(); 188 Environment environment = EnvironmentBuilder.buildEnvironment(environmentType, defaultEnvironment); 189 idBuilder.resolve(environment, module == null ? "" : new File(module.getName()).getName(), "car"); 190 if(!environment.getConfigId().isResolved()) { 191 throw new IllegalStateException("Service Module ID is not fully populated ("+environment.getConfigId()+")"); 192 } 193 return environment.getConfigId(); 194 } 195 196 public DeploymentContext buildConfiguration(boolean inPlaceDeployment, Artifact configId, Object plan, JarFile jar, Collection configurationStores, ArtifactResolver artifactResolver, ConfigurationStore targetConfigurationStore) throws IOException, DeploymentException { 197 ModuleType configType = (ModuleType) plan; 198 199 return buildConfiguration(inPlaceDeployment, configId, configType, jar, configurationStores, artifactResolver, targetConfigurationStore); 200 } 201 202 public DeploymentContext buildConfiguration(boolean inPlaceDeployment, Artifact configId, ModuleType moduleType, JarFile jar, Collection configurationStores, ArtifactResolver artifactResolver, ConfigurationStore targetConfigurationStore) throws DeploymentException, IOException { 203 ArtifactType type = moduleType.getEnvironment().isSetModuleId() ? moduleType.getEnvironment().getModuleId() : moduleType.getEnvironment().addNewModuleId(); 204 type.setArtifactId(configId.getArtifactId()); 205 type.setGroupId(configId.getGroupId()); 206 type.setType(configId.getType()); 207 type.setVersion(configId.getVersion().toString()); 208 Environment environment = EnvironmentBuilder.buildEnvironment(moduleType.getEnvironment(), defaultEnvironment); 209 if(!environment.getConfigId().isResolved()) { 210 throw new IllegalStateException("Module ID should be fully resolved by now (not "+environment.getConfigId()+")"); 211 } 212 File outfile; 213 try { 214 outfile = targetConfigurationStore.createNewConfigurationDir(configId); 215 } catch (ConfigurationAlreadyExistsException e) { 216 throw new DeploymentException(e); 217 } 218 219 DeploymentContext context = null; 220 try { 221 ConfigurationManager configurationManager = this.configurationManager; 222 if (configurationManager == null) { 223 configurationManager = new SimpleConfigurationManager(configurationStores, artifactResolver, repositories); 224 } 225 226 AbstractName moduleName = naming.createRootName(configId, configId.toString(), SERVICE_MODULE); 227 context = new DeploymentContext(outfile, 228 inPlaceDeployment && null != jar ? DeploymentUtil.toFile(jar) : null, 229 environment, 230 moduleName, 231 ConfigurationModuleType.SERVICE, 232 naming, 233 configurationManager, 234 repositories); 235 if(jar != null) { 236 File file = new File(jar.getName()); 237 context.addIncludeAsPackedJar(URI.create(file.getName()), jar); 238 } 239 240 serviceBuilders.build(moduleType, context, context); 241 return context; 242 } catch (DeploymentException de) { 243 cleanupAfterFailedBuild(context, outfile); 244 throw de; 245 } catch (IOException ie) { 246 cleanupAfterFailedBuild(context, outfile); 247 throw ie; 248 } catch (RuntimeException re) { 249 cleanupAfterFailedBuild(context, outfile); 250 throw re; 251 } catch (Error e) { 252 cleanupAfterFailedBuild(context, outfile); 253 throw e; 254 } 255 } 256 257 private void cleanupAfterFailedBuild(DeploymentContext context, File directory) { 258 try { 259 if (context !=null) { 260 context.close(); 261 } 262 } catch (DeploymentException de) { 263 // ignore error on cleanup 264 } catch (IOException ioe) { 265 // ignore error on cleanu 266 } 267 if (directory != null) { 268 DeploymentUtil.recursiveDelete(directory); 269 } 270 } 271 272 public static final GBeanInfo GBEAN_INFO; 273 274 static { 275 PropertyEditorManager.registerEditor(Environment.class, EnvironmentBuilder.class); 276 277 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(ServiceConfigBuilder.class, CONFIG_BUILDER); 278 279 infoBuilder.addInterface(ConfigurationBuilder.class); 280 281 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true); 282 infoBuilder.addReference("Repository", Repository.class, "Repository"); 283 infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, "ModuleBuilder"); 284 infoBuilder.addAttribute("kernel", Kernel.class, false, false); 285 286 infoBuilder.setConstructor(new String[]{"defaultEnvironment", "Repository", "ServiceBuilders", "kernel"}); 287 288 GBEAN_INFO = infoBuilder.getBeanInfo(); 289 } 290 291 public static GBeanInfo getGBeanInfo() { 292 return GBEAN_INFO; 293 } 294 295 }