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 }