View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  
19  package org.apache.geronimo.deployment.service;
20  
21  import java.beans.PropertyEditorManager;
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.net.URI;
26  import java.net.URL;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.jar.JarFile;
30  
31  import javax.xml.namespace.QName;
32  
33  import org.apache.geronimo.common.DeploymentException;
34  import org.apache.geronimo.deployment.ConfigurationBuilder;
35  import org.apache.geronimo.deployment.DeploymentContext;
36  import org.apache.geronimo.deployment.ModuleIDBuilder;
37  import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
38  import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
39  import org.apache.geronimo.deployment.util.DeploymentUtil;
40  import org.apache.geronimo.deployment.xbeans.ArtifactType;
41  import org.apache.geronimo.deployment.xbeans.EnvironmentType;
42  import org.apache.geronimo.deployment.xbeans.ModuleDocument;
43  import org.apache.geronimo.deployment.xbeans.ModuleType;
44  import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
45  import org.apache.geronimo.gbean.AbstractName;
46  import org.apache.geronimo.gbean.GBeanInfo;
47  import org.apache.geronimo.gbean.GBeanInfoBuilder;
48  import org.apache.geronimo.kernel.Kernel;
49  import org.apache.geronimo.kernel.Naming;
50  import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException;
51  import org.apache.geronimo.kernel.config.ConfigurationManager;
52  import org.apache.geronimo.kernel.config.ConfigurationModuleType;
53  import org.apache.geronimo.kernel.config.ConfigurationStore;
54  import org.apache.geronimo.kernel.config.ConfigurationUtil;
55  import org.apache.geronimo.kernel.config.SimpleConfigurationManager;
56  import org.apache.geronimo.kernel.repository.Artifact;
57  import org.apache.geronimo.kernel.repository.ArtifactResolver;
58  import org.apache.geronimo.kernel.repository.Environment;
59  import org.apache.geronimo.kernel.repository.Repository;
60  import org.apache.xmlbeans.XmlCursor;
61  import org.apache.xmlbeans.XmlException;
62  import org.apache.xmlbeans.XmlObject;
63  
64  /**
65   * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
66   */
67  public class ServiceConfigBuilder implements ConfigurationBuilder {
68      private final Environment defaultEnvironment;
69      private final Collection repositories;
70  
71      private static final QName MODULE_QNAME = ModuleDocument.type.getDocumentElementName();
72      public static final String SERVICE_MODULE = "ServiceModule";
73      private final Naming naming;
74      private final ConfigurationManager configurationManager;
75      private final NamespaceDrivenBuilderCollection serviceBuilders;
76  
77      public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Naming naming) {
78          this(defaultEnvironment, repositories, Collections.EMPTY_LIST, naming, null);
79      }
80  
81      public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Kernel kernel) {
82          this(defaultEnvironment, repositories, serviceBuilders, kernel.getNaming(), ConfigurationUtil.getConfigurationManager(kernel));
83      }
84  
85      public ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Naming naming) {
86          this(defaultEnvironment, repositories, serviceBuilders, naming, null);
87      }
88  
89      private ServiceConfigBuilder(Environment defaultEnvironment, Collection repositories, Collection serviceBuilders, Naming naming, ConfigurationManager configurationManager) {
90          this.naming = naming;
91          this.configurationManager = configurationManager;
92  
93          EnvironmentBuilder environmentBuilder = new EnvironmentBuilder();
94          this.defaultEnvironment = defaultEnvironment;
95  
96          this.repositories = repositories;
97          this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders);
98      }
99  
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 }