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.jar.JarFile; 029 030 import javax.xml.namespace.QName; 031 032 import org.apache.geronimo.common.DeploymentException; 033 import org.apache.geronimo.deployment.ConfigurationBuilder; 034 import org.apache.geronimo.deployment.DeploymentContext; 035 import org.apache.geronimo.deployment.ModuleIDBuilder; 036 import org.apache.geronimo.deployment.NamespaceDrivenBuilder; 037 import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection; 038 import org.apache.geronimo.deployment.util.DeploymentUtil; 039 import org.apache.geronimo.deployment.xbeans.ArtifactType; 040 import org.apache.geronimo.deployment.xbeans.EnvironmentType; 041 import org.apache.geronimo.deployment.xbeans.ModuleDocument; 042 import org.apache.geronimo.deployment.xbeans.ModuleType; 043 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil; 044 import org.apache.geronimo.gbean.AbstractName; 045 import org.apache.geronimo.gbean.GBeanInfo; 046 import org.apache.geronimo.gbean.GBeanInfoBuilder; 047 import org.apache.geronimo.kernel.Kernel; 048 import org.apache.geronimo.kernel.Naming; 049 import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException; 050 import org.apache.geronimo.kernel.config.ConfigurationManager; 051 import org.apache.geronimo.kernel.config.ConfigurationModuleType; 052 import org.apache.geronimo.kernel.config.ConfigurationStore; 053 import org.apache.geronimo.kernel.config.ConfigurationUtil; 054 import org.apache.geronimo.kernel.config.SimpleConfigurationManager; 055 import org.apache.geronimo.kernel.repository.Artifact; 056 import org.apache.geronimo.kernel.repository.ArtifactResolver; 057 import org.apache.geronimo.kernel.repository.Environment; 058 import org.apache.geronimo.kernel.repository.Repository; 059 import org.apache.xmlbeans.XmlCursor; 060 import org.apache.xmlbeans.XmlException; 061 import org.apache.xmlbeans.XmlObject; 062 063 /** 064 * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $ 065 */ 066 public class ServiceConfigBuilder implements ConfigurationBuilder { 067 private final Environment defaultEnvironment; 068 private final Collection repositories; 069 070 private static final QName MODULE_QNAME = ModuleDocument.type.getDocumentElementName(); 071 public static final String SERVICE_MODULE = "ServiceModule"; 072 private final Naming naming; 073 private final ConfigurationManager configurationManager; 074 private final NamespaceDrivenBuilderCollection serviceBuilders; 075 076 public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Naming naming) { 077 this(defaultEnvironment, repositories, Collections.EMPTY_LIST, naming, null); 078 } 079 080 public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Kernel kernel) { 081 this(defaultEnvironment, repositories, serviceBuilders, kernel.getNaming(), ConfigurationUtil.getConfigurationManager(kernel)); 082 } 083 084 public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Naming naming) { 085 this(defaultEnvironment, repositories, serviceBuilders, naming, null); 086 } 087 088 private ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Naming naming, ConfigurationManager configurationManager) { 089 this.naming = naming; 090 this.configurationManager = configurationManager; 091 092 EnvironmentBuilder environmentBuilder = new EnvironmentBuilder(); 093 this.defaultEnvironment = defaultEnvironment; 094 095 this.repositories = repositories; 096 this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders, GBeanBuilder.SERVICE_QNAME); 097 } 098 099 public Object getDeploymentPlan(File planFile, JarFile jarFile, ModuleIDBuilder idBuilder) throws DeploymentException { 100 if (planFile == null && jarFile == null) { 101 return null; 102 } 103 104 try { 105 XmlObject xmlObject; 106 if (planFile != null) { 107 xmlObject = XmlBeansUtil.parse(planFile.toURL(), getClass().getClassLoader()); 108 } else { 109 URL path = DeploymentUtil.createJarURL(jarFile, "META-INF/geronimo-service.xml"); 110 try { 111 xmlObject = XmlBeansUtil.parse(path, getClass().getClassLoader()); 112 } catch (FileNotFoundException e) { 113 // It has a JAR but no plan, and nothing at META-INF/geronimo-service.xml, 114 // therefore it's not a service deployment 115 return null; 116 } 117 } 118 if(xmlObject == null) { 119 return null; 120 } 121 122 XmlCursor cursor = xmlObject.newCursor(); 123 try { 124 cursor.toFirstChild(); 125 if (!MODULE_QNAME.equals(cursor.getName())) { 126 return null; 127 } 128 } finally { 129 cursor.dispose(); 130 } 131 ModuleDocument moduleDoc; 132 if (xmlObject instanceof ModuleDocument) { 133 moduleDoc = (ModuleDocument) xmlObject; 134 } else { 135 moduleDoc = (ModuleDocument) xmlObject.changeType(ModuleDocument.type); 136 } 137 XmlBeansUtil.validateDD(moduleDoc); 138 // 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. 139 if(jarFile == null && (moduleDoc.getModule().getEnvironment() == null || 140 moduleDoc.getModule().getEnvironment().getModuleId() == null || 141 moduleDoc.getModule().getEnvironment().getModuleId().getArtifactId() == null)) { 142 if(moduleDoc.getModule().getEnvironment() == null) { 143 moduleDoc.getModule().addNewEnvironment(); 144 } 145 if(moduleDoc.getModule().getEnvironment().getModuleId() == null) { 146 moduleDoc.getModule().getEnvironment().addNewModuleId(); 147 } 148 String name = planFile.getName(); 149 int pos = name.lastIndexOf('.'); 150 if(pos > -1) { 151 name = name.substring(0, pos); 152 } 153 moduleDoc.getModule().getEnvironment().getModuleId().setArtifactId(name); 154 } 155 return moduleDoc.getModule(); 156 } catch (XmlException e) { 157 throw new DeploymentException("Could not parse xml in plan", e); 158 } catch (IOException e) { 159 throw new DeploymentException("no plan at " + planFile, e); 160 } 161 } 162 163 public Artifact getConfigurationID(Object plan, JarFile module, ModuleIDBuilder idBuilder) throws IOException, DeploymentException { 164 ModuleType configType = (ModuleType) plan; 165 EnvironmentType environmentType = configType.getEnvironment(); 166 Environment environment = EnvironmentBuilder.buildEnvironment(environmentType, defaultEnvironment); 167 idBuilder.resolve(environment, module == null ? "" : new File(module.getName()).getName(), "car"); 168 if(!environment.getConfigId().isResolved()) { 169 throw new IllegalStateException("Service Module ID is not fully populated ("+environment.getConfigId()+")"); 170 } 171 return environment.getConfigId(); 172 } 173 174 public DeploymentContext buildConfiguration(boolean inPlaceDeployment, Artifact configId, Object plan, JarFile jar, Collection configurationStores, ArtifactResolver artifactResolver, ConfigurationStore targetConfigurationStore) throws IOException, DeploymentException { 175 ModuleType configType = (ModuleType) plan; 176 177 return buildConfiguration(inPlaceDeployment, configId, configType, jar, configurationStores, artifactResolver, targetConfigurationStore); 178 } 179 180 public DeploymentContext buildConfiguration(boolean inPlaceDeployment, Artifact configId, ModuleType moduleType, JarFile jar, Collection configurationStores, ArtifactResolver artifactResolver, ConfigurationStore targetConfigurationStore) throws DeploymentException, IOException { 181 ArtifactType type = moduleType.getEnvironment().isSetModuleId() ? moduleType.getEnvironment().getModuleId() : moduleType.getEnvironment().addNewModuleId(); 182 type.setArtifactId(configId.getArtifactId()); 183 type.setGroupId(configId.getGroupId()); 184 type.setType(configId.getType()); 185 type.setVersion(configId.getVersion().toString()); 186 Environment environment = EnvironmentBuilder.buildEnvironment(moduleType.getEnvironment(), defaultEnvironment); 187 if(!environment.getConfigId().isResolved()) { 188 throw new IllegalStateException("Module ID should be fully resolved by now (not "+environment.getConfigId()+")"); 189 } 190 File outfile; 191 try { 192 outfile = targetConfigurationStore.createNewConfigurationDir(configId); 193 } catch (ConfigurationAlreadyExistsException e) { 194 throw new DeploymentException(e); 195 } 196 197 DeploymentContext context = null; 198 try { 199 ConfigurationManager configurationManager = this.configurationManager; 200 if (configurationManager == null) { 201 configurationManager = new SimpleConfigurationManager(configurationStores, artifactResolver, repositories); 202 } 203 204 AbstractName moduleName = naming.createRootName(configId, configId.toString(), SERVICE_MODULE); 205 context = new DeploymentContext(outfile, 206 inPlaceDeployment && null != jar ? DeploymentUtil.toFile(jar) : null, 207 environment, 208 moduleName, 209 ConfigurationModuleType.SERVICE, 210 naming, 211 configurationManager, 212 repositories); 213 if(jar != null) { 214 File file = new File(jar.getName()); 215 context.addIncludeAsPackedJar(URI.create(file.getName()), jar); 216 } 217 218 serviceBuilders.build(moduleType, context, context); 219 return context; 220 } catch (DeploymentException de) { 221 cleanupAfterFailedBuild(context, outfile); 222 throw de; 223 } catch (IOException ie) { 224 cleanupAfterFailedBuild(context, outfile); 225 throw ie; 226 } catch (RuntimeException re) { 227 cleanupAfterFailedBuild(context, outfile); 228 throw re; 229 } catch (Error e) { 230 cleanupAfterFailedBuild(context, outfile); 231 throw e; 232 } 233 } 234 235 private void cleanupAfterFailedBuild(DeploymentContext context, File directory) { 236 try { 237 if (context !=null) { 238 context.close(); 239 } 240 } catch (DeploymentException de) { 241 // ignore error on cleanup 242 } catch (IOException ioe) { 243 // ignore error on cleanu 244 } 245 if (directory != null) { 246 DeploymentUtil.recursiveDelete(directory); 247 } 248 } 249 250 public static final GBeanInfo GBEAN_INFO; 251 252 static { 253 PropertyEditorManager.registerEditor(Environment.class, EnvironmentBuilder.class); 254 255 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(ServiceConfigBuilder.class, CONFIG_BUILDER); 256 257 infoBuilder.addInterface(ConfigurationBuilder.class); 258 259 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true); 260 infoBuilder.addReference("Repository", Repository.class, "Repository"); 261 infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, "ModuleBuilder"); 262 infoBuilder.addAttribute("kernel", Kernel.class, false, false); 263 264 infoBuilder.setConstructor(new String[]{"defaultEnvironment", "Repository", "ServiceBuilders", "kernel"}); 265 266 GBEAN_INFO = infoBuilder.getBeanInfo(); 267 } 268 269 public static GBeanInfo getGBeanInfo() { 270 return GBEAN_INFO; 271 } 272 273 }