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 package org.apache.servicemix.geronimo;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.net.URI;
022 import java.net.URL;
023 import java.util.Collection;
024 import java.util.Enumeration;
025 import java.util.HashMap;
026 import java.util.Map;
027 import java.util.Properties;
028 import java.util.Set;
029 import java.util.jar.JarFile;
030 import java.util.zip.ZipEntry;
031
032 import javax.management.MalformedObjectNameException;
033
034 import org.apache.commons.logging.Log;
035 import org.apache.commons.logging.LogFactory;
036 import org.apache.geronimo.common.DeploymentException;
037 import org.apache.geronimo.deployment.ConfigurationBuilder;
038 import org.apache.geronimo.deployment.DeploymentContext;
039 import org.apache.geronimo.deployment.ModuleIDBuilder;
040 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
041 import org.apache.geronimo.deployment.util.DeploymentUtil;
042 import org.apache.geronimo.gbean.AbstractName;
043 import org.apache.geronimo.gbean.AbstractNameQuery;
044 import org.apache.geronimo.gbean.GBeanData;
045 import org.apache.geronimo.gbean.GBeanInfo;
046 import org.apache.geronimo.gbean.GBeanInfoBuilder;
047 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
048 import org.apache.geronimo.kernel.Kernel;
049 import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException;
050 import org.apache.geronimo.kernel.config.ConfigurationModuleType;
051 import org.apache.geronimo.kernel.config.ConfigurationStore;
052 import org.apache.geronimo.kernel.config.ConfigurationUtil;
053 import org.apache.geronimo.kernel.repository.Artifact;
054 import org.apache.geronimo.kernel.repository.ArtifactResolver;
055 import org.apache.geronimo.kernel.repository.Environment;
056 import org.apache.geronimo.kernel.repository.ImportType;
057 import org.apache.geronimo.kernel.repository.Repository;
058 import org.apache.geronimo.kernel.repository.Version;
059 import org.apache.servicemix.jbi.deployment.Descriptor;
060 import org.apache.servicemix.jbi.deployment.DescriptorFactory;
061 import org.apache.servicemix.jbi.deployment.ServiceUnit;
062 import org.apache.servicemix.jbi.deployment.SharedLibraryList;
063
064 public class ServiceMixConfigBuilder implements ConfigurationBuilder {
065
066 private static final Log log = LogFactory.getLog(ServiceMixConfigBuilder.class);
067
068 private final Environment defaultEnvironment;
069
070 private final Collection repositories;
071
072 private final Kernel kernel;
073
074 public static final GBeanInfo GBEAN_INFO;
075
076 static {
077 GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(ServiceMixConfigBuilder.class, NameFactory.CONFIG_BUILDER);
078 infoFactory.addInterface(ConfigurationBuilder.class);
079 infoFactory.addAttribute("defaultEnvironment", Environment.class, true, true);
080 infoFactory.addAttribute("kernel", Kernel.class, false);
081 infoFactory.addReference("Repositories", Repository.class, "Repository");
082 infoFactory.setConstructor(new String[] { "defaultEnvironment", "Repositories", "kernel" });
083 GBEAN_INFO = infoFactory.getBeanInfo();
084 }
085
086 public static GBeanInfo getGBeanInfo() {
087 return GBEAN_INFO;
088 }
089
090 public ServiceMixConfigBuilder(Environment defaultEnvironment, Collection repositories, Kernel kernel) {
091 this.defaultEnvironment = defaultEnvironment;
092 this.repositories = repositories;
093 this.kernel = kernel;
094 }
095
096 /**
097 * Builds a deployment plan specific to this builder from a planFile and/or
098 * module if this builder can process it.
099 *
100 * @param planFile
101 * the deployment plan to examine; can be null
102 * @param module
103 * the URL of the module to examine; can be null
104 * @return the deployment plan, or null if this builder can not handle the
105 * module
106 * @throws org.apache.geronimo.common.DeploymentException
107 * if there was a problem with the configuration
108 */
109 public Object getDeploymentPlan(File planFile, JarFile module, ModuleIDBuilder idBuilder)
110 throws DeploymentException {
111 log.debug("Checking for ServiceMix deployment.");
112 System.err.println("Checking for ServiceMix deployment.");
113 if (module == null) {
114 return null;
115 }
116
117 // Check that the jbi descriptor is present
118 try {
119 URL url = DeploymentUtil.createJarURL(module, "META-INF/jbi.xml");
120 Descriptor descriptor = DescriptorFactory.buildDescriptor(url);
121 if (descriptor == null) {
122 return null;
123 }
124 DescriptorFactory.checkDescriptor(descriptor);
125 return descriptor;
126 } catch (Exception e) {
127 log.debug("Not a ServiceMix deployment: no jbi.xml found.", e);
128 // no jbi.xml, not for us
129 return null;
130 }
131 }
132
133 /**
134 * Checks what configuration URL will be used for the provided module.
135 *
136 * @param plan
137 * the deployment plan
138 * @param module
139 * the module to build
140 * @return the ID that will be used for the Configuration
141 * @throws IOException
142 * if there was a problem reading or writing the files
143 * @throws org.apache.geronimo.common.DeploymentException
144 * if there was a problem with the configuration
145 */
146 public Artifact getConfigurationID(Object plan, JarFile module, ModuleIDBuilder idBuilder) throws IOException,
147 DeploymentException {
148 Descriptor descriptor = (Descriptor) plan;
149 if (descriptor.getComponent() != null) {
150 return new Artifact("servicemix-components", descriptor.getComponent().getIdentification().getName(),
151 "0.0", "car");
152 } else if (descriptor.getServiceAssembly() != null) {
153 return new Artifact("servicemix-assemblies", descriptor.getServiceAssembly().getIdentification().getName(),
154 "0.0", "car");
155 } else if (descriptor.getSharedLibrary() != null) {
156 return new Artifact("servicemix-libraries", descriptor.getSharedLibrary().getIdentification().getName(),
157 descriptor.getSharedLibrary().getVersion(), "car");
158 } else {
159 throw new DeploymentException("Unable to construct configuration ID " + module.getName()
160 + ": unrecognized jbi package. Should be a component, assembly or library.");
161 }
162 }
163
164 /**
165 * Build a configuration from a local file
166 *
167 * @param inPlaceDeployment
168 * @param configId
169 * @param plan
170 * @param earFile
171 * @param configurationStores
172 * @param artifactResolver
173 * @param targetConfigurationStore
174 * @return the DeploymentContext information
175 * @throws IOException
176 * if there was a problem reading or writing the files
177 * @throws org.apache.geronimo.common.DeploymentException
178 * if there was a problem with the configuration
179 */
180 public DeploymentContext buildConfiguration(boolean inPlaceDeployment, Artifact configId, Object plan,
181 JarFile jarFile, Collection configurationStores, ArtifactResolver artifactResolver,
182 ConfigurationStore targetConfigurationStore) throws IOException, DeploymentException {
183 if (plan == null) {
184 log.warn("Expected a Descriptor but received null");
185 return null;
186 }
187 if (plan instanceof Descriptor == false) {
188 log.warn("Expected a Descriptor but received a " + plan.getClass().getName());
189 return null;
190 }
191 File configurationDir;
192 try {
193 configurationDir = targetConfigurationStore.createNewConfigurationDir(configId);
194 } catch (ConfigurationAlreadyExistsException e) {
195 throw new DeploymentException(e);
196 }
197
198 Environment environment = new Environment();
199 environment.setConfigId(configId);
200 EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
201
202 DeploymentContext context = null;
203 try {
204 Descriptor descriptor = (Descriptor) plan;
205 Map name = new HashMap();
206 name.put("Config", configId.toString());
207 context = new DeploymentContext(configurationDir,
208 inPlaceDeployment ? DeploymentUtil.toFile(jarFile) : null, environment,
209 new AbstractName(configId, name),
210 ConfigurationModuleType.SERVICE, kernel.getNaming(), ConfigurationUtil
211 .getConfigurationManager(kernel), repositories);
212 if (descriptor.getComponent() != null) {
213 buildComponent(descriptor, context, jarFile);
214 } else if (descriptor.getServiceAssembly() != null) {
215 buildServiceAssembly(descriptor, context, jarFile);
216 } else if (descriptor.getSharedLibrary() != null) {
217 buildSharedLibrary(descriptor, context, jarFile);
218 } else {
219 throw new IllegalStateException("Invalid jbi descriptor");
220 }
221 } catch (Exception e) {
222 if (context != null) {
223 context.close();
224 }
225 DeploymentUtil.recursiveDelete(configurationDir);
226 throw new DeploymentException("Unable to deploy", e);
227 }
228
229 return context;
230 }
231
232 protected void buildComponent(Descriptor descriptor, DeploymentContext context, JarFile module) throws Exception {
233 Environment environment = context.getConfiguration().getEnvironment();
234 // Unzip the component
235 File targetDir = new File(context.getBaseDir(), "install");
236 targetDir.mkdirs();
237 unzip(context, module, new URI("install/"));
238 // Create workspace dir
239 File workDir = new File(context.getBaseDir(), "workspace");
240 workDir.mkdirs();
241 // Create the bootstrap and perform installation
242 // TODO: Create the bootstrap and perform installation
243 // Add classpath entries
244 if ("self-first".equals(descriptor.getComponent().getComponentClassLoaderDelegation())) {
245 context.getConfiguration().getEnvironment().setInverseClassLoading(true);
246 }
247 SharedLibraryList[] slList = descriptor.getComponent().getSharedLibraries();
248 if (slList != null) {
249 for (int i = 0; i < slList.length; i++) {
250 Artifact sl = new Artifact("servicemix-libraries", slList[i].getName(), slList[i].getVersion(), "car");
251 environment.addDependency(sl, ImportType.CLASSES);
252 }
253 }
254 if (descriptor.getComponent().getComponentClassPath() != null) {
255 String[] pathElements = descriptor.getComponent().getComponentClassPath().getPathElements();
256 if (pathElements != null) {
257 for (int i = 0; i < pathElements.length; i++) {
258 context.getConfiguration().addToClassPath(new URI("install/").resolve(pathElements[i]).toString());
259 }
260 }
261 }
262 // Create the JBI deployment managed object
263 Properties props = new Properties();
264 props.put("jbiType", "JBIComponent");
265 props.put("name", descriptor.getComponent().getIdentification().getName());
266 AbstractName name = new AbstractName(environment.getConfigId(), props);
267 GBeanData gbeanData = new GBeanData(name, Component.GBEAN_INFO);
268 gbeanData.setAttribute("name", descriptor.getComponent().getIdentification().getName());
269 gbeanData.setAttribute("description", descriptor.getComponent().getIdentification().getDescription());
270 gbeanData.setAttribute("type", descriptor.getComponent().getType());
271 gbeanData.setAttribute("className", descriptor.getComponent().getComponentClassName());
272 gbeanData.setReferencePattern("container", getContainerObjectName());
273 context.addGBean(gbeanData);
274 }
275
276 protected void buildServiceAssembly(Descriptor descriptor, DeploymentContext context, JarFile module)
277 throws Exception {
278 Environment environment = context.getConfiguration().getEnvironment();
279 // Unzip the component
280 File targetDir = new File(context.getBaseDir(), "install");
281 targetDir.mkdirs();
282 unzip(context, module, new URI("install/"));
283 // Unzip SUs
284 ServiceUnit[] sus = descriptor.getServiceAssembly().getServiceUnits();
285 for (int i = 0; i < sus.length; i++) {
286 String name = sus[i].getIdentification().getName();
287 String zip = sus[i].getTarget().getArtifactsZip();
288 String comp = sus[i].getTarget().getComponentName();
289 unzip(context, new JarFile(new File(targetDir, zip)), new URI("sus/" + comp + "/" + name + "/"));
290 // Deploy the SU on the component
291 // TODO: deploy
292 // Add component config as a dependency
293 Artifact sl = new Artifact("servicemix-components", comp, (Version) null, "car");
294 environment.addDependency(sl, ImportType.ALL);
295 }
296 // Create the JBI deployment managed object
297 Properties props = new Properties();
298 props.put("jbiType", "JBIServiceAssembly");
299 props.put("name", descriptor.getServiceAssembly().getIdentification().getName());
300 AbstractName name = new AbstractName(environment.getConfigId(), props);
301 GBeanData gbeanData = new GBeanData(name, ServiceAssembly.GBEAN_INFO);
302 gbeanData.setAttribute("name", descriptor.getServiceAssembly().getIdentification().getName());
303 gbeanData.setReferencePattern("container", getContainerObjectName());
304 for (int i = 0; i < sus.length; i++) {
305 String comp = sus[i].getTarget().getComponentName();
306 gbeanData.addDependency(getComponentName(comp));
307 }
308 context.addGBean(gbeanData);
309 }
310
311 protected void buildSharedLibrary(Descriptor descriptor, DeploymentContext context, JarFile module)
312 throws Exception {
313 Environment environment = context.getConfiguration().getEnvironment();
314 // Unzip the SL
315 File targetDir = new File(context.getBaseDir(), "install");
316 targetDir.mkdirs();
317 unzip(context, module, new URI("install/"));
318 // Create workspace dir
319 File workDir = new File(context.getBaseDir(), "workspace");
320 workDir.mkdirs();
321 // Add classpath entries
322 if ("self-first".equals(descriptor.getSharedLibrary().getClassLoaderDelegation())) {
323 context.getConfiguration().getEnvironment().setInverseClassLoading(true);
324 }
325 if (descriptor.getSharedLibrary().getSharedLibraryClassPath() != null) {
326 String[] pathElements = descriptor.getSharedLibrary().getSharedLibraryClassPath().getPathElements();
327 if (pathElements != null) {
328 for (int i = 0; i < pathElements.length; i++) {
329 log.debug("Processing pathElements[" + i + "]: " + pathElements[i]);
330 // We can not add includes directly, so move the file and
331 // include it
332 File include = new File(targetDir, pathElements[i]);
333 File temp = new File(workDir, pathElements[i]);
334 if (!include.isFile()) {
335 throw new Exception("Classpath element '" + pathElements[i] + "' not found");
336 }
337 temp.getParentFile().mkdirs();
338 include.renameTo(temp);
339 context.addInclude(new URI("install/").resolve(pathElements[i]), temp);
340 temp.delete();
341 }
342 } else {
343 log.debug("SharedLibrary().getSharedLibraryClassPath().getPathElements() is null");
344 }
345 } else {
346 log.debug("SharedLibrary().getSharedLibraryClassPath() is null");
347 }
348 // Create the JBI deployment managed object
349 Properties props = new Properties();
350 props.put("jbiType", "JBISharedLibrary");
351 props.put("name", descriptor.getSharedLibrary().getIdentification().getName());
352 AbstractName name = new AbstractName(environment.getConfigId(), props);
353 GBeanData gbeanData = new GBeanData(name, SharedLibrary.GBEAN_INFO);
354 gbeanData.setAttribute("name", descriptor.getSharedLibrary().getIdentification().getName());
355 gbeanData.setAttribute("description", descriptor.getSharedLibrary().getIdentification().getDescription());
356 gbeanData.setReferencePattern("container", getContainerObjectName());
357 context.addGBean(gbeanData);
358 }
359
360 protected void unzip(DeploymentContext context, JarFile module, URI targetUri) throws IOException {
361 Enumeration entries = module.entries();
362 while (entries.hasMoreElements()) {
363 ZipEntry entry = (ZipEntry) entries.nextElement();
364 URI target = targetUri.resolve(entry.getName());
365 context.addFile(target, module, entry);
366 }
367 }
368
369 protected AbstractName getContainerObjectName() {
370 AbstractNameQuery query = new AbstractNameQuery(Container.class.getName());
371 Set names = kernel.listGBeans(query);
372 return (AbstractName) names.iterator().next();
373 }
374
375 protected AbstractNameQuery getComponentName(String name) throws MalformedObjectNameException {
376 URI uri = URI.create("servicemix-components/" + name + "//car?jbiType=JBIComponent");
377 return new AbstractNameQuery(uri);
378 }
379
380 }