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    }