001 /**
002 * Copyright 2005 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.apache.geronimo.plugin.car;
018
019 import java.io.File;
020 import java.net.URI;
021 import java.util.Collection;
022 import java.util.HashSet;
023 import java.util.Iterator;
024 import java.util.List;
025 import java.util.Set;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029 import org.apache.geronimo.gbean.AbstractName;
030 import org.apache.geronimo.gbean.AbstractNameQuery;
031 import org.apache.geronimo.gbean.GBeanData;
032 import org.apache.geronimo.gbean.GBeanInfo;
033 import org.apache.geronimo.gbean.ReferencePatterns;
034 import org.apache.geronimo.kernel.Kernel;
035 import org.apache.geronimo.kernel.KernelFactory;
036 import org.apache.geronimo.kernel.KernelRegistry;
037 import org.apache.geronimo.kernel.Naming;
038 import org.apache.geronimo.kernel.config.ConfigurationData;
039 import org.apache.geronimo.kernel.config.ConfigurationManager;
040 import org.apache.geronimo.kernel.config.ConfigurationUtil;
041 import org.apache.geronimo.kernel.config.KernelConfigurationManager;
042 import org.apache.geronimo.kernel.log.GeronimoLogging;
043 import org.apache.geronimo.kernel.management.State;
044 import org.apache.geronimo.kernel.repository.Artifact;
045 import org.apache.geronimo.kernel.repository.DefaultArtifactManager;
046 import org.apache.geronimo.system.resolver.ExplicitDefaultArtifactResolver;
047
048 /**
049 * Builds a Geronimo Configuration using the local Maven infrastructure.
050 *
051 * @version $Rev:385659 $ $Date: 2006-08-12 12:22:18 +0200 (sam., 12 août 2006) $
052 */
053 public class PackageBuilder
054 {
055 private static final String KERNEL_NAME = "geronimo.maven";
056
057 private static final String[] ARG_TYPES = {
058 boolean.class.getName(),
059 File.class.getName(),
060 File.class.getName(),
061 File.class.getName(),
062 Boolean.TYPE.getName(),
063 String.class.getName(),
064 String.class.getName(),
065 String.class.getName(),
066 String.class.getName(),
067 String.class.getName(),
068 String.class.getName(),
069 String.class.getName(),
070 String.class.getName(),
071 };
072
073 private static final Log log = LogFactory.getLog(PackageBuilder.class);
074
075 /**
076 * Reference to the kernel that will last the lifetime of this classloader.
077 * The KernelRegistry keeps soft references that may be garbage collected.
078 */
079 private static Kernel kernel;
080
081 private static AbstractName targetConfigStoreAName;
082
083 private static AbstractName targetRepositoryAName;
084
085 private String repositoryClass;
086
087 private String configurationStoreClass;
088
089 private String targetRepositoryClass;
090
091 private String targetConfigurationStoreClass;
092
093 private File repository;
094
095 private File targetRepository;
096
097 private Collection deploymentConfigs;
098
099 private AbstractName deployerName;
100
101 private File planFile;
102
103 private File moduleFile;
104
105 private File packageFile;
106
107 private String explicitResolutionLocation;
108
109 private boolean targetSet;
110
111 public String getRepositoryClass() {
112 return repositoryClass;
113 }
114
115 public void setRepositoryClass(final String repositoryClass) {
116 this.repositoryClass = repositoryClass;
117 }
118
119 public String getConfigurationStoreClass() {
120 return configurationStoreClass;
121 }
122
123 public void setConfigurationStoreClass(final String configurationStoreClass) {
124 this.configurationStoreClass = configurationStoreClass;
125 }
126
127 public File getRepository() {
128 return repository;
129 }
130
131 public void setRepository(final File repository) {
132 this.repository = repository;
133 }
134
135 public String getTargetRepositoryClass() {
136 return targetRepositoryClass;
137 }
138
139 public void setTargetRepositoryClass(final String targetRepositoryClass) {
140 this.targetRepositoryClass = targetRepositoryClass;
141 }
142
143 public String getTargetConfigurationStoreClass() {
144 return targetConfigurationStoreClass;
145 }
146
147 public void setTargetConfigurationStoreClass(final String targetConfigurationStoreClass) {
148 this.targetConfigurationStoreClass = targetConfigurationStoreClass;
149 }
150
151 public File getTargetRepository() {
152 return targetRepository;
153 }
154
155 public void setTargetRepository(final File targetRepository) {
156 this.targetRepository = targetRepository;
157 }
158
159 public Collection getDeploymentConfig() {
160 return deploymentConfigs;
161 }
162
163 /**
164 * Set the id of the Configuration to use to perform the packaging.
165 *
166 * @param deploymentConfigString comma-separated list of the ids of the Configurations performing the deployment
167 */
168 public void setDeploymentConfig(final Collection deploymentConfigString) {
169 this.deploymentConfigs = deploymentConfigString;
170 }
171
172 public String getDeployerName() {
173 return deployerName.toString();
174 }
175
176 /**
177 * Set the name of the GBean that is the Deployer.
178 *
179 * @param deployerName the name of the Deployer GBean
180 */
181 public void setDeployerName(final String deployerName) {
182 this.deployerName = new AbstractName(URI.create(deployerName));
183 }
184
185 public File getPlanFile() {
186 return planFile;
187 }
188
189 /**
190 * Set the File that is the deployment plan.
191 *
192 * @param planFile the deployment plan
193 */
194 public void setPlanFile(final File planFile) {
195 this.planFile = planFile;
196 }
197
198 public File getModuleFile() {
199 return moduleFile;
200 }
201
202 /**
203 * Set the File that is the module being deployed.
204 *
205 * @param moduleFile the module to deploy
206 */
207 public void setModuleFile(final File moduleFile) {
208 this.moduleFile = moduleFile;
209 }
210
211 public File getPackageFile() {
212 return packageFile;
213 }
214
215 /**
216 * Set the File where the Configuration will be stored; normally the artifact being produced.
217 *
218 * @param packageFile the package file to produce
219 */
220 public void setPackageFile(final File packageFile) {
221 this.packageFile = packageFile;
222 }
223
224 public String getExplicitResolutionLocation() {
225 return explicitResolutionLocation;
226 }
227
228 public void setExplicitResolutionLocation(final String explicitResolutionLocation) {
229 this.explicitResolutionLocation = explicitResolutionLocation;
230 }
231
232 public void execute() throws Exception {
233 System.out.println("Packaging module configuration: " + planFile);
234
235 try {
236 Kernel kernel = createKernel();
237 if (!targetSet) {
238 setTargetConfigStore();
239 }
240
241 // start the Configuration we're going to use for this deployment
242 ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
243 try {
244 for (Iterator iterator = deploymentConfigs.iterator(); iterator.hasNext();) {
245 String artifactName = (String) iterator.next();
246 Artifact configName = Artifact.create(artifactName);
247 if (!configurationManager.isLoaded(configName)) {
248 configurationManager.loadConfiguration(configName);
249 configurationManager.startConfiguration(configName);
250 }
251 }
252 } finally {
253 ConfigurationUtil.releaseConfigurationManager(kernel, configurationManager);
254 }
255
256 AbstractName deployer = locateDeployer(kernel);
257 invokeDeployer(kernel, deployer, targetConfigStoreAName.toString());
258 }
259 catch (Exception e) {
260 log.error(e.getClass().getName() + ": " + e.getMessage(), e);
261 throw e;
262 }
263 }
264
265 private void setTargetConfigStore() throws Exception {
266 kernel.stopGBean(targetRepositoryAName);
267 kernel.setAttribute(targetRepositoryAName, "root", targetRepository.toURI());
268 kernel.startGBean(targetRepositoryAName);
269
270 if (kernel.getGBeanState(targetConfigStoreAName) != State.RUNNING_INDEX) {
271 throw new IllegalStateException("After restarted repository then config store is not running");
272 }
273
274 targetSet = true;
275 }
276
277 /**
278 * Create a Geronimo Kernel to contain the deployment configurations.
279 */
280 private synchronized Kernel createKernel() throws Exception {
281 // first return our cached version
282 if (kernel != null) {
283 return kernel;
284 }
285
286 // check the registry in case someone else created one
287 kernel = KernelRegistry.getKernel(KERNEL_NAME);
288 if (kernel != null) {
289 return kernel;
290 }
291
292 GeronimoLogging geronimoLogging = GeronimoLogging.getGeronimoLogging("WARN");
293 if (geronimoLogging == null) {
294 geronimoLogging = GeronimoLogging.DEBUG;
295 }
296 GeronimoLogging.initialize(geronimoLogging);
297
298 // boot one ourselves
299 kernel = KernelFactory.newInstance().createKernel(KERNEL_NAME);
300 kernel.boot();
301
302 bootDeployerSystem();
303
304 return kernel;
305 }
306
307 /**
308 * Boot the in-Maven deployment system.
309 *
310 * This contains Repository and ConfigurationStore GBeans that map to
311 * the local maven installation.
312 */
313 private void bootDeployerSystem() throws Exception {
314 Artifact baseId = new Artifact("geronimo", "packaging", "fixed", "car");
315 Naming naming = kernel.getNaming();
316 ConfigurationData bootstrap = new ConfigurationData(baseId, naming);
317 ClassLoader cl = PackageBuilder.class.getClassLoader();
318 Set repoNames = new HashSet();
319
320 // Source repo
321 GBeanData repoGBean = bootstrap.addGBean("SourceRepository", GBeanInfo.getGBeanInfo(repositoryClass, cl));
322 URI repositoryURI = repository.toURI();
323 repoGBean.setAttribute("root", repositoryURI);
324 repoNames.add(repoGBean.getAbstractName());
325
326 // Target repo
327 GBeanData targetRepoGBean = bootstrap.addGBean("TargetRepository", GBeanInfo.getGBeanInfo(targetRepositoryClass, cl));
328 URI targetRepositoryURI = targetRepository.toURI();
329 targetRepoGBean.setAttribute("root", targetRepositoryURI);
330 repoNames.add(targetRepoGBean.getAbstractName());
331 targetRepositoryAName = targetRepoGBean.getAbstractName();
332
333 GBeanData artifactManagerGBean = bootstrap.addGBean("ArtifactManager", DefaultArtifactManager.GBEAN_INFO);
334 GBeanData artifactResolverGBean = bootstrap.addGBean("ArtifactResolver", ExplicitDefaultArtifactResolver.GBEAN_INFO);
335 artifactResolverGBean.setAttribute("versionMapLocation", explicitResolutionLocation);
336 ReferencePatterns repoPatterns = new ReferencePatterns(repoNames);
337 artifactResolverGBean.setReferencePatterns("Repositories", repoPatterns);
338 artifactResolverGBean.setReferencePattern("ArtifactManager", artifactManagerGBean.getAbstractName());
339
340 Set storeNames = new HashSet();
341
342 // Source config store
343 GBeanInfo configStoreInfo = GBeanInfo.getGBeanInfo(configurationStoreClass, cl);
344 GBeanData storeGBean = bootstrap.addGBean("ConfigStore", configStoreInfo);
345 if (configStoreInfo.getReference("Repository") != null) {
346 storeGBean.setReferencePattern("Repository", repoGBean.getAbstractName());
347 }
348 storeNames.add(storeGBean.getAbstractName());
349
350 // Target config store
351 GBeanInfo targetConfigStoreInfo = GBeanInfo.getGBeanInfo(targetConfigurationStoreClass, cl);
352 GBeanData targetStoreGBean = bootstrap.addGBean("TargetConfigStore", targetConfigStoreInfo);
353 if (targetConfigStoreInfo.getReference("Repository") != null) {
354 targetStoreGBean.setReferencePattern("Repository", targetRepoGBean.getAbstractName());
355 }
356 storeNames.add(targetStoreGBean.getAbstractName());
357
358 targetConfigStoreAName = targetStoreGBean.getAbstractName();
359 targetSet = true;
360
361 GBeanData attrManagerGBean = bootstrap.addGBean("AttributeStore", MavenAttributeStore.GBEAN_INFO);
362 GBeanData configManagerGBean = bootstrap.addGBean("ConfigManager", KernelConfigurationManager.GBEAN_INFO);
363 configManagerGBean.setReferencePatterns("Stores", new ReferencePatterns(storeNames));
364 configManagerGBean.setReferencePattern("AttributeStore", attrManagerGBean.getAbstractName());
365 configManagerGBean.setReferencePattern("ArtifactManager", artifactManagerGBean.getAbstractName());
366 configManagerGBean.setReferencePattern("ArtifactResolver", artifactResolverGBean.getAbstractName());
367 configManagerGBean.setReferencePatterns("Repositories", repoPatterns);
368
369 ConfigurationUtil.loadBootstrapConfiguration(kernel, bootstrap, cl);
370 }
371
372 /**
373 * Locate a Deployer GBean matching the deployerName pattern.
374 *
375 * @param kernel the kernel to search.
376 * @return the ObjectName of the Deployer GBean
377 *
378 * @throws IllegalStateException if there is not exactly one GBean matching the deployerName pattern
379 */
380 private AbstractName locateDeployer(final Kernel kernel) {
381 Iterator i = kernel.listGBeans(new AbstractNameQuery(deployerName)).iterator();
382 if (!i.hasNext()) {
383 throw new IllegalStateException("No deployer found matching deployerName: " + deployerName);
384 }
385
386 AbstractName deployer = (AbstractName) i.next();
387 if (i.hasNext()) {
388 throw new IllegalStateException("Multiple deployers found matching deployerName: " + deployerName);
389 }
390
391 return deployer;
392 }
393
394 private List invokeDeployer(final Kernel kernel, final AbstractName deployer, final String targetConfigStore) throws Exception {
395 Object[] args = {
396 Boolean.FALSE, // Not in-place
397 planFile,
398 moduleFile,
399 null, // Target file
400 Boolean.TRUE, // Install
401 null, // main-class
402 null, // main-gbean
403 null, // main-method
404 null, // Manifest configurations
405 null, // class-path
406 null, // endorsed-dirs
407 null, // extension-dirs
408 targetConfigStore
409 };
410
411 return (List) kernel.invoke(deployer, "deploy", args, ARG_TYPES);
412 }
413 }