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