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: */package org.apache.geronimo.deployment.service;
017:
018: import java.beans.PropertyEditorManager;
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.io.IOException;
022: import java.net.URI;
023: import java.net.URL;
024: import java.util.Collection;
025: import java.util.Collections;
026: import java.util.Map;
027: import java.util.HashMap;
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.gbean.GBeanLifecycle;
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: 610760 $ $Date: 2008-01-10 03:07:04 -0800 (Thu, 10 Jan 2008) $
066: */
067: public class ServiceConfigBuilder implements ConfigurationBuilder,
068: GBeanLifecycle {
069: private final Environment defaultEnvironment;
070: private final Collection repositories;
071:
072: private static final QName MODULE_QNAME = ModuleDocument.type
073: .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(
078: "http://geronimo.apache.org/xml/ns/deployment",
079: "http://geronimo.apache.org/xml/ns/deployment-1.2");
080: NAMESPACE_UPDATES.put(
081: "http://geronimo.apache.org/xml/ns/deployment-1.1",
082: "http://geronimo.apache.org/xml/ns/deployment-1.2");
083: NAMESPACE_UPDATES
084: .put(
085: "http://geronimo.apache.org/xml/ns/deployment/javabean",
086: "http://geronimo.apache.org/xml/ns/deployment/javabean-1.0");
087: }
088:
089: private final Naming naming;
090: private final ConfigurationManager configurationManager;
091: private final NamespaceDrivenBuilderCollection serviceBuilders;
092:
093: public ServiceConfigBuilder(Environment defaultEnvironment,
094: Collection repositories, Naming naming) {
095: this (defaultEnvironment, repositories, Collections.EMPTY_LIST,
096: naming, null);
097: }
098:
099: public ServiceConfigBuilder(Environment defaultEnvironment,
100: Collection repositories, Collection serviceBuilders,
101: Kernel kernel) {
102: this (defaultEnvironment, repositories, serviceBuilders, kernel
103: .getNaming(), ConfigurationUtil
104: .getConfigurationManager(kernel));
105: }
106:
107: public ServiceConfigBuilder(Environment defaultEnvironment,
108: Collection repositories, Collection serviceBuilders,
109: Naming naming) {
110: this (defaultEnvironment, repositories, serviceBuilders, naming,
111: null);
112: }
113:
114: public void doStart() throws Exception {
115: XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
116: }
117:
118: public void doStop() {
119: XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
120: }
121:
122: public void doFail() {
123: doStop();
124: }
125:
126: private ServiceConfigBuilder(Environment defaultEnvironment,
127: Collection repositories, Collection serviceBuilders,
128: Naming naming, ConfigurationManager configurationManager) {
129: this .naming = naming;
130: this .configurationManager = configurationManager;
131:
132: EnvironmentBuilder environmentBuilder = new EnvironmentBuilder();
133: this .defaultEnvironment = defaultEnvironment;
134:
135: this .repositories = repositories;
136: this .serviceBuilders = new NamespaceDrivenBuilderCollection(
137: serviceBuilders, GBeanBuilder.SERVICE_QNAME);
138: }
139:
140: public Object getDeploymentPlan(File planFile, JarFile jarFile,
141: ModuleIDBuilder idBuilder) throws DeploymentException {
142: if (planFile == null && jarFile == null) {
143: return null;
144: }
145:
146: try {
147: XmlObject xmlObject;
148: if (planFile != null) {
149: xmlObject = XmlBeansUtil.parse(planFile.toURL(),
150: getClass().getClassLoader());
151: } else {
152: URL path = DeploymentUtil.createJarURL(jarFile,
153: "META-INF/geronimo-service.xml");
154: try {
155: xmlObject = XmlBeansUtil.parse(path, getClass()
156: .getClassLoader());
157: } catch (FileNotFoundException e) {
158: // It has a JAR but no plan, and nothing at META-INF/geronimo-service.xml,
159: // therefore it's not a service deployment
160: return null;
161: }
162: }
163: if (xmlObject == null) {
164: return null;
165: }
166:
167: XmlCursor cursor = xmlObject.newCursor();
168: try {
169: cursor.toFirstChild();
170: if (!MODULE_QNAME.equals(cursor.getName())) {
171: return null;
172: }
173: } finally {
174: cursor.dispose();
175: }
176: ModuleDocument moduleDoc;
177: if (xmlObject instanceof ModuleDocument) {
178: moduleDoc = (ModuleDocument) xmlObject;
179: } else {
180: moduleDoc = (ModuleDocument) xmlObject
181: .changeType(ModuleDocument.type);
182: }
183: XmlBeansUtil.validateDD(moduleDoc);
184: // 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.
185: if (jarFile == null
186: && (moduleDoc.getModule().getEnvironment() == null
187: || moduleDoc.getModule().getEnvironment()
188: .getModuleId() == null || moduleDoc
189: .getModule().getEnvironment().getModuleId()
190: .getArtifactId() == null)) {
191: if (moduleDoc.getModule().getEnvironment() == null) {
192: moduleDoc.getModule().addNewEnvironment();
193: }
194: if (moduleDoc.getModule().getEnvironment()
195: .getModuleId() == null) {
196: moduleDoc.getModule().getEnvironment()
197: .addNewModuleId();
198: }
199: String name = planFile.getName();
200: int pos = name.lastIndexOf('.');
201: if (pos > -1) {
202: name = name.substring(0, pos);
203: }
204: moduleDoc.getModule().getEnvironment().getModuleId()
205: .setArtifactId(name);
206: }
207: return moduleDoc.getModule();
208: } catch (XmlException e) {
209: throw new DeploymentException(
210: "Could not parse xml in plan", e);
211: } catch (IOException e) {
212: throw new DeploymentException("no plan at " + planFile, e);
213: }
214: }
215:
216: public Artifact getConfigurationID(Object plan, JarFile module,
217: ModuleIDBuilder idBuilder) throws IOException,
218: DeploymentException {
219: ModuleType configType = (ModuleType) plan;
220: EnvironmentType environmentType = configType.getEnvironment();
221: Environment environment = EnvironmentBuilder.buildEnvironment(
222: environmentType, defaultEnvironment);
223: idBuilder.resolve(environment, module == null ? "" : new File(
224: module.getName()).getName(), "car");
225: if (!environment.getConfigId().isResolved()) {
226: throw new IllegalStateException(
227: "Service Module ID is not fully populated ("
228: + environment.getConfigId() + ")");
229: }
230: return environment.getConfigId();
231: }
232:
233: public DeploymentContext buildConfiguration(
234: boolean inPlaceDeployment, Artifact configId, Object plan,
235: JarFile jar, Collection configurationStores,
236: ArtifactResolver artifactResolver,
237: ConfigurationStore targetConfigurationStore)
238: throws IOException, DeploymentException {
239: ModuleType configType = (ModuleType) plan;
240:
241: return buildConfiguration(inPlaceDeployment, configId,
242: configType, jar, configurationStores, artifactResolver,
243: targetConfigurationStore);
244: }
245:
246: public DeploymentContext buildConfiguration(
247: boolean inPlaceDeployment, Artifact configId,
248: ModuleType moduleType, JarFile jar,
249: Collection configurationStores,
250: ArtifactResolver artifactResolver,
251: ConfigurationStore targetConfigurationStore)
252: throws DeploymentException, IOException {
253: ArtifactType type = moduleType.getEnvironment().isSetModuleId() ? moduleType
254: .getEnvironment().getModuleId()
255: : moduleType.getEnvironment().addNewModuleId();
256: type.setArtifactId(configId.getArtifactId());
257: type.setGroupId(configId.getGroupId());
258: type.setType(configId.getType());
259: type.setVersion(configId.getVersion().toString());
260: Environment environment = EnvironmentBuilder.buildEnvironment(
261: moduleType.getEnvironment(), defaultEnvironment);
262: if (!environment.getConfigId().isResolved()) {
263: throw new IllegalStateException(
264: "Module ID should be fully resolved by now (not "
265: + environment.getConfigId() + ")");
266: }
267: File outfile;
268: try {
269: outfile = targetConfigurationStore
270: .createNewConfigurationDir(configId);
271: } catch (ConfigurationAlreadyExistsException e) {
272: throw new DeploymentException(e);
273: }
274:
275: DeploymentContext context = null;
276: try {
277: ConfigurationManager configurationManager = this .configurationManager;
278: if (configurationManager == null) {
279: configurationManager = new SimpleConfigurationManager(
280: configurationStores, artifactResolver,
281: repositories);
282: }
283:
284: AbstractName moduleName = naming.createRootName(configId,
285: configId.toString(), SERVICE_MODULE);
286: context = new DeploymentContext(outfile, inPlaceDeployment
287: && null != jar ? DeploymentUtil.toFile(jar) : null,
288: environment, moduleName,
289: ConfigurationModuleType.SERVICE, naming,
290: configurationManager, repositories);
291: if (jar != null) {
292: File file = new File(jar.getName());
293: context.addIncludeAsPackedJar(URI
294: .create(file.getName()), jar);
295: }
296:
297: serviceBuilders.build(moduleType, context, context);
298: return context;
299: } catch (DeploymentException de) {
300: cleanupAfterFailedBuild(context, outfile);
301: throw de;
302: } catch (IOException ie) {
303: cleanupAfterFailedBuild(context, outfile);
304: throw ie;
305: } catch (RuntimeException re) {
306: cleanupAfterFailedBuild(context, outfile);
307: throw re;
308: } catch (Error e) {
309: cleanupAfterFailedBuild(context, outfile);
310: throw e;
311: }
312: }
313:
314: private void cleanupAfterFailedBuild(DeploymentContext context,
315: File directory) {
316: try {
317: if (context != null) {
318: context.close();
319: }
320: } catch (DeploymentException de) {
321: // ignore error on cleanup
322: } catch (IOException ioe) {
323: // ignore error on cleanu
324: }
325: if (directory != null) {
326: DeploymentUtil.recursiveDelete(directory);
327: }
328: }
329:
330: public static final GBeanInfo GBEAN_INFO;
331:
332: static {
333: PropertyEditorManager.registerEditor(Environment.class,
334: EnvironmentBuilder.class);
335:
336: GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(
337: ServiceConfigBuilder.class, CONFIG_BUILDER);
338:
339: infoBuilder.addInterface(ConfigurationBuilder.class);
340:
341: infoBuilder.addAttribute("defaultEnvironment",
342: Environment.class, true);
343: infoBuilder.addReference("Repository", Repository.class,
344: "Repository");
345: infoBuilder.addReference("ServiceBuilders",
346: NamespaceDrivenBuilder.class, "ModuleBuilder");
347: infoBuilder.addAttribute("kernel", Kernel.class, false, false);
348:
349: infoBuilder.setConstructor(new String[] { "defaultEnvironment",
350: "Repository", "ServiceBuilders", "kernel" });
351:
352: GBEAN_INFO = infoBuilder.getBeanInfo();
353: }
354:
355: public static GBeanInfo getGBeanInfo() {
356: return GBEAN_INFO;
357: }
358:
359: }
|