1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.geronimo.plugin.car;
21
22 import java.io.File;
23 import java.net.URI;
24
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Iterator;
28 import java.util.Set;
29 import java.util.HashSet;
30
31 import org.apache.geronimo.deployment.PluginBootstrap2;
32 import org.apache.geronimo.system.configuration.RepositoryConfigurationStore;
33 import org.apache.geronimo.system.repository.Maven2Repository;
34 import org.apache.geronimo.system.resolver.ExplicitDefaultArtifactResolver;
35 import org.apache.geronimo.kernel.Kernel;
36 import org.apache.geronimo.kernel.KernelRegistry;
37 import org.apache.geronimo.kernel.KernelFactory;
38 import org.apache.geronimo.kernel.Naming;
39 import org.apache.geronimo.kernel.repository.DefaultArtifactManager;
40 import org.apache.geronimo.kernel.log.GeronimoLogging;
41 import org.apache.geronimo.kernel.management.State;
42 import org.apache.geronimo.kernel.config.ConfigurationManager;
43 import org.apache.geronimo.kernel.config.ConfigurationUtil;
44 import org.apache.geronimo.kernel.config.ConfigurationData;
45 import org.apache.geronimo.kernel.config.KernelConfigurationManager;
46 import org.apache.geronimo.gbean.AbstractName;
47 import org.apache.geronimo.gbean.GBeanData;
48 import org.apache.geronimo.gbean.GBeanInfo;
49 import org.apache.geronimo.gbean.ReferencePatterns;
50 import org.apache.geronimo.gbean.AbstractNameQuery;
51
52 import org.apache.geronimo.genesis.ArtifactItem;
53
54 import org.apache.maven.archiver.MavenArchiveConfiguration;
55 import org.apache.maven.archiver.MavenArchiver;
56 import org.apache.maven.plugin.MojoExecutionException;
57 import org.apache.maven.artifact.Artifact;
58
59 import org.codehaus.plexus.util.FileUtils;
60 import org.codehaus.plexus.archiver.jar.JarArchiver;
61
62 /**
63 * Build a Geronimo Configuration using the local Maven infrastructure.
64 *
65 * <p>
66 * <b>NOTE:</b> Calling pom.xml must have defined a ${geronimoVersion} property.
67 * </p>
68 *
69 * @goal package
70 * @requiresDependencyResolution runtime
71 *
72 * @version $Rev: 451661 $ $Date: 2006-09-30 13:45:53 -0700 (Sat, 30 Sep 2006) $
73 */
74 public class PackageMojo
75 extends AbstractCarMojo
76 {
77 /**
78 * The maven archive configuration to use.
79 *
80 * See <a href="http://maven.apache.org/ref/current/maven-archiver/apidocs/org/apache/maven/archiver/MavenArchiveConfiguration.html">the Javadocs for MavenArchiveConfiguration</a>.
81 *
82 * @parameter
83 */
84 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
85
86 /**
87 * The Jar archiver.
88 *
89 * @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
90 * @required
91 * @readonly
92 */
93 private JarArchiver jarArchiver = null;
94
95 /**
96 * Directory containing the generated archive.
97 *
98 * @parameter expression="${project.build.directory}"
99 * @required
100 */
101 private File outputDirectory = null;
102
103 /**
104 * Directory containing the classes/resources.
105 *
106 * @parameter expression="${project.build.outputDirectory}"
107 * @required
108 */
109 private File classesDirectory = null;
110
111 /**
112 * Name of the generated archive.
113 *
114 * @parameter expression="${project.build.finalName}"
115 * @required
116 */
117 private String finalName = null;
118
119 /**
120 * ???
121 *
122 * @parameter expression="${settings.localRepository}"
123 * @required
124 * @readonly
125 */
126 private File repository = null;
127
128 /**
129 * ???
130 *
131 * @parameter expression="${project.build.directory}/repository"
132 * @required
133 */
134 private File targetRepository = null;
135
136 /**
137 * ???
138 *
139 * @parameter expression="org.apache.geronimo.configs/geronimo-gbean-deployer/${geronimoVersion}/car"
140 * @required
141 * @readonly
142 */
143 private String deafultDeploymentConfig = null;
144
145 /**
146 * ???
147 *
148 * @parameter
149 */
150 private List deploymentConfigs;
151
152 /**
153 * The name of the deployer which will be used to deploy the CAR.
154 *
155 * @parameter expression="org.apache.geronimo.configs/geronimo-gbean-deployer/${geronimoVersion}/car?j2eeType=Deployer,name=Deployer"
156 * @required
157 */
158 private String deployerName = null;
159
160 /**
161 * The plan file for the CAR.
162 *
163 * @parameter expression="${project.build.directory}/plan/plan.xml"
164 * @required
165 */
166 private File planFile = null;
167
168 /**
169 * The file to include as a module of the CAR.
170 *
171 * @parameter
172 */
173 private File moduleFile = null;
174
175 /**
176 * An {@link ArtifactItem} to include as a module of the CAR.
177 *
178 * @parameter
179 */
180 private ArtifactItem module = null;
181
182 /**
183 * The location where the properties mapping will be generated.
184 *
185 * <p>
186 * Probably don't wanto to change this.
187 *
188 * @parameter expression="${project.build.directory}/explicit-versions.properties"
189 */
190 private File explicitResolutionProperties = null;
191
192 /**
193 * An array of {@link ClasspathElement} objects which will be used to construct the
194 * Class-Path entry of the manifest.
195 *
196 * This is needed to allow per-element prefixes to be added, which the standard Maven archiver
197 * does not provide.
198 *
199 * @parameter
200 */
201 private ClasspathElement[] classpath = null;
202
203 /**
204 * The default prefix to be applied to all elements of the <tt>classpath</tt> which
205 * do not provide a prefix.
206 *
207 * @parameter
208 */
209 private String classpathPrefix = null;
210
211 /**
212 * True to enable the bootshell when packaging.
213 *
214 * @parameter
215 */
216 private boolean bootstrap = false;
217
218
219
220
221
222 protected void doExecute() throws Exception {
223
224 FileUtils.forceDelete(targetRepository);
225 FileUtils.forceMkdir(targetRepository);
226
227
228 if (deploymentConfigs == null) {
229 deploymentConfigs = new ArrayList();
230 deploymentConfigs.add(deafultDeploymentConfig);
231 }
232 log.debug("Deployment configs: " + deploymentConfigs);
233
234
235 if (module != null) {
236 Artifact artifact = getArtifact(module);
237 moduleFile = artifact.getFile();
238 log.debug("Using module file: " + moduleFile);
239 }
240
241 generateExplicitVersionProperties(explicitResolutionProperties);
242
243 if (bootstrap) {
244 executeBootShell();
245 }
246 else {
247 buildPackage();
248 }
249
250
251 File archive = createArchive();
252
253
254 project.getArtifact().setFile(archive);
255 }
256
257 private File getArtifactInRepositoryDir() {
258
259
260
261
262 File dir = new File(targetRepository, project.getGroupId().replace('.', '/'));
263 dir = new File(dir, project.getArtifactId());
264 dir = new File(dir, project.getVersion());
265 dir = new File(dir, project.getArtifactId() + "-" + project.getVersion() + ".car");
266
267 return dir;
268 }
269
270 public void executeBootShell() throws Exception {
271 log.debug("Starting bootstrap shell...");
272
273 PluginBootstrap2 boot = new PluginBootstrap2();
274
275 boot.setBuildDir(outputDirectory);
276 boot.setCarFile(getArtifactInRepositoryDir());
277 boot.setLocalRepo(repository);
278 boot.setPlan(planFile);
279
280
281 boot.setExpanded(true);
282
283 boot.bootstrap();
284 }
285
286 /**
287 * Generates the configuration archive.
288 */
289 private File createArchive() throws MojoExecutionException {
290 File archiveFile = getArchiveFile(outputDirectory, finalName, null);
291
292 MavenArchiver archiver = new MavenArchiver();
293 archiver.setArchiver(jarArchiver);
294 archiver.setOutputFile(archiveFile);
295
296 try {
297
298 archiver.getArchiver().addDirectory(getArtifactInRepositoryDir());
299
300
301 if (classesDirectory.isDirectory()) {
302 archiver.getArchiver().addDirectory(classesDirectory);
303 }
304
305 if (classpath != null) {
306 archive.addManifestEntry("Class-Path", getClassPath());
307 }
308
309 archiver.createArchive(project, archive);
310
311 return archiveFile;
312 }
313 catch (Exception e) {
314 throw new MojoExecutionException("Failed to create archive", e);
315 }
316 }
317
318 private String getClassPath() throws MojoExecutionException {
319 StringBuffer buff = new StringBuffer();
320
321 for (int i=0; i < classpath.length; i++) {
322 Artifact artifact = getArtifact(classpath[i]);
323
324
325
326
327
328 String prefix = classpath[i].getClasspathPrefix();
329 if (prefix == null) {
330 prefix = classpathPrefix;
331 }
332
333 if (prefix != null) {
334 buff.append(prefix);
335
336 if (!prefix.endsWith("/")) {
337 buff.append("/");
338 }
339 }
340
341 File file = artifact.getFile();
342 buff.append(file.getName());
343
344 if (i + 1< classpath.length) {
345 buff.append(" ");
346 }
347 }
348
349 log.debug("Using classpath: " + buff);
350
351 return buff.toString();
352 }
353
354
355
356
357
358 private static final String KERNEL_NAME = "geronimo.maven";
359
360 /**
361 * Reference to the kernel that will last the lifetime of this classloader.
362 * The KernelRegistry keeps soft references that may be garbage collected.
363 */
364 private static Kernel kernel;
365
366 private static AbstractName targetConfigStoreAName;
367
368 private static AbstractName targetRepositoryAName;
369
370 private boolean targetSet;
371
372 public void buildPackage() throws Exception {
373 log.info("Packaging module configuration: " + planFile);
374
375
376 Kernel kernel = createKernel();
377 if (!targetSet) {
378 kernel.stopGBean(targetRepositoryAName);
379 kernel.setAttribute(targetRepositoryAName, "root", targetRepository.toURI());
380 kernel.startGBean(targetRepositoryAName);
381
382 if (kernel.getGBeanState(targetConfigStoreAName) != State.RUNNING_INDEX) {
383 throw new IllegalStateException("After restarted repository then config store is not running");
384 }
385
386 targetSet = true;
387 }
388
389 log.debug("Starting configuration...");
390
391
392 ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
393 try {
394 for (Iterator iterator = deploymentConfigs.iterator(); iterator.hasNext();) {
395 String artifactName = (String) iterator.next();
396 org.apache.geronimo.kernel.repository.Artifact configName =
397 org.apache.geronimo.kernel.repository.Artifact.create(artifactName);
398 if (!configurationManager.isLoaded(configName)) {
399 configurationManager.loadConfiguration(configName);
400 configurationManager.startConfiguration(configName);
401 }
402 }
403 } finally {
404 ConfigurationUtil.releaseConfigurationManager(kernel, configurationManager);
405 }
406
407 log.debug("Deploying...");
408
409 AbstractName deployer = locateDeployer(kernel);
410 invokeDeployer(kernel, deployer, targetConfigStoreAName.toString());
411 }
412
413 /**
414 * Create a Geronimo Kernel to contain the deployment configurations.
415 */
416 private synchronized Kernel createKernel() throws Exception {
417
418 if (kernel != null) {
419 return kernel;
420 }
421
422 log.debug("Creating kernel...");
423
424
425 kernel = KernelRegistry.getKernel(KERNEL_NAME);
426 if (kernel != null) {
427 return kernel;
428 }
429
430 GeronimoLogging geronimoLogging = GeronimoLogging.getGeronimoLogging("WARN");
431 if (geronimoLogging == null) {
432 geronimoLogging = GeronimoLogging.DEBUG;
433 }
434 GeronimoLogging.initialize(geronimoLogging);
435
436
437 kernel = KernelFactory.newInstance().createKernel(KERNEL_NAME);
438 kernel.boot();
439
440 bootDeployerSystem();
441
442 return kernel;
443 }
444
445 /**
446 * Boot the in-Maven deployment system.
447 *
448 * <p>
449 * This contains Repository and ConfigurationStore GBeans that map to
450 * the local maven installation.
451 */
452 private void bootDeployerSystem() throws Exception {
453 log.debug("Booting deployer system...");
454
455 org.apache.geronimo.kernel.repository.Artifact baseId =
456 new org.apache.geronimo.kernel.repository.Artifact("geronimo", "packaging", "fixed", "car");
457 Naming naming = kernel.getNaming();
458 ConfigurationData bootstrap = new ConfigurationData(baseId, naming);
459 ClassLoader cl = getClass().getClassLoader();
460 Set repoNames = new HashSet();
461
462
463 GBeanData repoGBean = bootstrap.addGBean("SourceRepository", GBeanInfo.getGBeanInfo(Maven2Repository.class.getName(), cl));
464 URI repositoryURI = repository.toURI();
465 repoGBean.setAttribute("root", repositoryURI);
466 repoNames.add(repoGBean.getAbstractName());
467
468
469 GBeanData targetRepoGBean = bootstrap.addGBean("TargetRepository", GBeanInfo.getGBeanInfo(Maven2Repository.class.getName(), cl));
470 URI targetRepositoryURI = targetRepository.toURI();
471 targetRepoGBean.setAttribute("root", targetRepositoryURI);
472 repoNames.add(targetRepoGBean.getAbstractName());
473 targetRepositoryAName = targetRepoGBean.getAbstractName();
474
475 GBeanData artifactManagerGBean = bootstrap.addGBean("ArtifactManager", DefaultArtifactManager.GBEAN_INFO);
476 GBeanData artifactResolverGBean = bootstrap.addGBean("ArtifactResolver", ExplicitDefaultArtifactResolver.GBEAN_INFO);
477 artifactResolverGBean.setAttribute("versionMapLocation", explicitResolutionProperties.getAbsolutePath());
478 ReferencePatterns repoPatterns = new ReferencePatterns(repoNames);
479 artifactResolverGBean.setReferencePatterns("Repositories", repoPatterns);
480 artifactResolverGBean.setReferencePattern("ArtifactManager", artifactManagerGBean.getAbstractName());
481
482 Set storeNames = new HashSet();
483
484
485 GBeanInfo configStoreInfo = GBeanInfo.getGBeanInfo(MavenConfigStore.class.getName(), cl);
486 GBeanData storeGBean = bootstrap.addGBean("ConfigStore", configStoreInfo);
487 if (configStoreInfo.getReference("Repository") != null) {
488 storeGBean.setReferencePattern("Repository", repoGBean.getAbstractName());
489 }
490 storeNames.add(storeGBean.getAbstractName());
491
492
493 GBeanInfo targetConfigStoreInfo = GBeanInfo.getGBeanInfo(RepositoryConfigurationStore.class.getName(), cl);
494 GBeanData targetStoreGBean = bootstrap.addGBean("TargetConfigStore", targetConfigStoreInfo);
495 if (targetConfigStoreInfo.getReference("Repository") != null) {
496 targetStoreGBean.setReferencePattern("Repository", targetRepoGBean.getAbstractName());
497 }
498 storeNames.add(targetStoreGBean.getAbstractName());
499
500 targetConfigStoreAName = targetStoreGBean.getAbstractName();
501 targetSet = true;
502
503 GBeanData attrManagerGBean = bootstrap.addGBean("AttributeStore", MavenAttributeStore.GBEAN_INFO);
504 GBeanData configManagerGBean = bootstrap.addGBean("ConfigManager", KernelConfigurationManager.GBEAN_INFO);
505 configManagerGBean.setReferencePatterns("Stores", new ReferencePatterns(storeNames));
506 configManagerGBean.setReferencePattern("AttributeStore", attrManagerGBean.getAbstractName());
507 configManagerGBean.setReferencePattern("ArtifactManager", artifactManagerGBean.getAbstractName());
508 configManagerGBean.setReferencePattern("ArtifactResolver", artifactResolverGBean.getAbstractName());
509 configManagerGBean.setReferencePatterns("Repositories", repoPatterns);
510
511 ConfigurationUtil.loadBootstrapConfiguration(kernel, bootstrap, cl);
512 }
513
514 /**
515 * Locate a Deployer GBean matching the deployerName pattern.
516 *
517 * @param kernel the kernel to search.
518 * @return the ObjectName of the Deployer GBean
519 *
520 * @throws IllegalStateException if there is not exactly one GBean matching the deployerName pattern
521 */
522 private AbstractName locateDeployer(final Kernel kernel) {
523 AbstractName name = new AbstractName(URI.create(deployerName));
524
525 Iterator i = kernel.listGBeans(new AbstractNameQuery(name)).iterator();
526 if (!i.hasNext()) {
527 throw new IllegalStateException("No deployer found matching deployerName: " + name);
528 }
529
530 AbstractName deployer = (AbstractName)i.next();
531 if (i.hasNext()) {
532 throw new IllegalStateException("Multiple deployers found matching deployerName: " + name);
533 }
534
535 return deployer;
536 }
537
538 private static final String[] DEPLOY_SIGNATURE = {
539 boolean.class.getName(),
540 File.class.getName(),
541 File.class.getName(),
542 File.class.getName(),
543 Boolean.TYPE.getName(),
544 String.class.getName(),
545 String.class.getName(),
546 String.class.getName(),
547 String.class.getName(),
548 String.class.getName(),
549 String.class.getName(),
550 String.class.getName(),
551 String.class.getName(),
552 };
553
554 private List invokeDeployer(final Kernel kernel, final AbstractName deployer, final String targetConfigStore) throws Exception {
555 Object[] args = {
556 Boolean.FALSE,
557 planFile,
558 moduleFile,
559 null,
560 Boolean.TRUE,
561 null,
562 null,
563 null,
564 null,
565 null,
566 null,
567 null,
568 targetConfigStore
569 };
570
571 return (List) kernel.invoke(deployer, "deploy", args, DEPLOY_SIGNATURE);
572 }
573 }