/**
*
* Copyright 2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.geronimo.plugin.packaging;
import java.io.File;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.apache.geronimo.gbean.GBeanData;
import org.apache.geronimo.gbean.GReferenceInfo;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.kernel.KernelFactory;
import org.apache.geronimo.kernel.KernelRegistry;
import org.apache.geronimo.kernel.config.ConfigurationManager;
import org.apache.geronimo.kernel.config.ConfigurationManagerImpl;
import org.apache.geronimo.kernel.config.ConfigurationUtil;
import org.apache.log4j.BasicConfigurator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* JellyBean that builds a Geronimo Configuration using the local Mavem
* infrastructure.
*
* @version $Rev: 355876 $ $Date$
*/
public class PackageBuilder {
private static Log log = LogFactory.getLog(PackageBuilder.class);
private static final String KERNEL_NAME = "geronimo.maven";
/**
* The name of the GBean that will load dependencies from the Maven repository.
*/
private static final ObjectName REPOSITORY_NAME;
/**
* The name of the GBean that will load Configurations from the Maven repository.
*/
private static final ObjectName CONFIGSTORE_NAME;
/**
* The name of the GBean that will manage Configurations.
*/
private static final ObjectName CONFIGMANAGER_NAME;
/**
* The name of the GBean that will provide values for managed attributes.
*/
private static final ObjectName ATTRIBUTESTORE_NAME;
/**
* Reference to the kernel that will last the lifetime of this classloader.
* The KernelRegistry keeps soft references that may be garbage collected.
*/
private static Kernel kernel;
private static final String[] ARG_TYPES = {
File.class.getName(),
File.class.getName(),
File.class.getName(),
Boolean.TYPE.getName(),
String.class.getName(),
String.class.getName(),
String.class.getName(),
String.class.getName(),
};
static {
try {
REPOSITORY_NAME = new ObjectName(KERNEL_NAME + ":name=Repository");
CONFIGSTORE_NAME = new ObjectName(KERNEL_NAME + ":name=MavenConfigStore,j2eeType=ConfigurationStore");
CONFIGMANAGER_NAME = new ObjectName(KERNEL_NAME + ":name=ConfigurationManager,j2eeType=ConfigurationManager");
ATTRIBUTESTORE_NAME = new ObjectName(KERNEL_NAME + ":name=ManagedAttributeStore");
} catch (MalformedObjectNameException e) {
throw new ExceptionInInitializerError(e.getMessage());
}
}
private String repositoryClass;
private String configurationStoreClass;
private File repository;
private String deploymentConfigString;
private URI[] deploymentConfig;
private ObjectName deployerName;
private File planFile;
private File moduleFile;
private File packageFile;
private String mainClass;
private String classPath;
private String endorsedDirs;
private String extensionDirs;
public String getRepositoryClass() {
return repositoryClass;
}
public void setRepositoryClass(String repositoryClass) {
this.repositoryClass = repositoryClass;
}
public String getConfigurationStoreClass() {
return configurationStoreClass;
}
public void setConfigurationStoreClass(String configurationStoreClass) {
this.configurationStoreClass = configurationStoreClass;
}
public File getRepository() {
return repository;
}
/**
* Set the location of the Maven repository; typically ${maven.repo.local}
*
* @param repository the location of the Maven repository
*/
public void setRepository(File repository) {
this.repository = repository;
}
public String getDeploymentConfig() {
return deploymentConfigString;
}
/**
* Set the id of the Configuration to use to perform the packaging.
*
* @param deploymentConfigString comma-separated list of the ids of the Configurations performing the deployment
*/
public void setDeploymentConfig(String deploymentConfigString) {
this.deploymentConfigString = deploymentConfigString;
String[] configNames = deploymentConfigString.split(",");
deploymentConfig = new URI[configNames.length];
for (int i = 0; i < configNames.length; i++) {
String configName = configNames[i];
deploymentConfig[i] = URI.create(configName);
}
}
public String getDeployerName() {
return deployerName.toString();
}
/**
* Set the name of the GBean that is the Deployer.
*
* @param deployerName the name of the Deployer GBean
*/
public void setDeployerName(String deployerName) {
try {
this.deployerName = new ObjectName(deployerName);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException("deployerName is not a valid ObjectName: " + deployerName);
}
}
public File getPlanFile() {
return planFile;
}
/**
* Set the File that is the deployment plan.
*
* @param planFile the deployment plan
*/
public void setPlanFile(File planFile) {
this.planFile = planFile;
}
public File getModuleFile() {
return moduleFile;
}
/**
* Set the File that is the module being deployed.
*
* @param moduleFile the module to deploy
*/
public void setModuleFile(File moduleFile) {
this.moduleFile = moduleFile;
}
public File getPackageFile() {
return packageFile;
}
/**
* Set the File where the Configuration will be stored; normally the artifact being produced.
*
* @param packageFile the package file to produce
*/
public void setPackageFile(File packageFile) {
this.packageFile = packageFile;
}
public String getMainClass() {
return mainClass;
}
/**
* Set the name of the class containing the main method for a executable configuration.
*
* @param mainClass
*/
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
}
public String getClassPath() {
return classPath;
}
public void setClassPath(String classPath) {
this.classPath = classPath;
}
public String getEndorsedDirs() {
return endorsedDirs;
}
public void setEndorsedDirs(String endorsedDirs) {
this.endorsedDirs = endorsedDirs;
}
public String getExtensionDirs() {
return extensionDirs;
}
public void setExtensionDirs(String extensionDirs) {
this.extensionDirs = extensionDirs;
}
public void execute() throws Exception {
try {
Kernel kernel = createKernel(repository, repositoryClass, configurationStoreClass);
// start the Configuration we're going to use for this deployment
ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
try {
for (int i = 0; i < deploymentConfig.length; i++) {
URI configName = deploymentConfig[i];
if (!configurationManager.isLoaded(configName)) {
List configs = configurationManager.loadRecursive(configName);
for (Iterator iterator = configs.iterator(); iterator.hasNext(); ) {
URI ancestorConfigName = (URI) iterator.next();
try {
configurationManager.loadGBeans(ancestorConfigName);
} catch (Throwable e) {
throw new RuntimeException("Could not start configuration: " + configName, e);
}
}
configurationManager.start(configName);
}
}
} finally {
ConfigurationUtil.releaseConfigurationManager(kernel, configurationManager);
}
ObjectName deployer = locateDeployer(kernel);
invokeDeployer(kernel, deployer);
System.out.println("Generated package " + packageFile);
} catch (Exception e) {
log.error(e.getClass().getName()+": "+e.getMessage(), e);
throw e;
}
}
/**
* Create a Geronimo Kernel to contain the deployment configurations.
*/
private static synchronized Kernel createKernel(File repository, String repoClass, String configStoreClass) throws Exception {
// first return our cached version
if (kernel != null) {
return kernel;
}
// check the registry in case someone else created one
kernel = KernelRegistry.getKernel(KERNEL_NAME);
if (kernel != null) {
return kernel;
}
BasicConfigurator.configure();
// boot one ourselves
kernel = KernelFactory.newInstance().createKernel(KERNEL_NAME);
kernel.boot();
bootDeployerSystem(kernel, repository, repoClass, configStoreClass);
return kernel;
}
/**
* Boot the in-Maven deployment system.
* This contains Repository and ConfigurationStore GBeans that map to
* the local maven installation.
*/
private static void bootDeployerSystem(Kernel kernel, File repository, String repoClass, String configStoreClass) throws Exception {
ClassLoader cl = PackageBuilder.class.getClassLoader();
GBeanInfo repoInfo = GBeanInfo.getGBeanInfo(repoClass, cl);
GBeanData repoGBean = new GBeanData(REPOSITORY_NAME, repoInfo);
repoGBean.setAttribute("root", repository);
kernel.loadGBean(repoGBean, cl);
kernel.startGBean(REPOSITORY_NAME);
GBeanInfo configStoreInfo = GBeanInfo.getGBeanInfo(configStoreClass, cl);
GBeanData storeGBean = new GBeanData(CONFIGSTORE_NAME, configStoreInfo);
Set refs = configStoreInfo.getReferences();
for (Iterator iterator = refs.iterator(); iterator.hasNext();) {
GReferenceInfo refInfo = (GReferenceInfo) iterator.next();
if ("Repository".equals(refInfo.getName())) {
storeGBean.setReferencePattern("Repository", REPOSITORY_NAME);
break;
}
}
kernel.loadGBean(storeGBean, cl);
kernel.startGBean(CONFIGSTORE_NAME);
GBeanData configManagerGBean = new GBeanData(CONFIGMANAGER_NAME, ConfigurationManagerImpl.GBEAN_INFO);
configManagerGBean.setReferencePattern("Stores", CONFIGSTORE_NAME);
configManagerGBean.setReferencePattern("AttributeStore", ATTRIBUTESTORE_NAME);
kernel.loadGBean(configManagerGBean, cl);
kernel.startGBean(CONFIGMANAGER_NAME);
GBeanData attrManagerGBean = new GBeanData(ATTRIBUTESTORE_NAME, MavenAttributeStore.GBEAN_INFO);
kernel.loadGBean(attrManagerGBean, cl);
kernel.startGBean(ATTRIBUTESTORE_NAME);
}
/**
* Locate a Deployer GBean matching the deployerName pattern.
*
* @param kernel the kernel to search.
* @return the ObjectName of the Deployer GBean
* @throws IllegalStateException if there is not exactly one GBean matching the deployerName pattern
*/
private ObjectName locateDeployer(Kernel kernel) {
Iterator i = kernel.listGBeans(deployerName).iterator();
if (!i.hasNext()) {
throw new IllegalStateException("No deployer found matching deployerName: " + deployerName);
}
ObjectName deployer = (ObjectName) i.next();
if (i.hasNext()) {
throw new IllegalStateException("Multiple deployers found matching deployerName: " + deployerName);
}
return deployer;
}
private List invokeDeployer(Kernel kernel, ObjectName deployer) throws Exception {
Object[] args = {planFile, moduleFile, packageFile, Boolean.FALSE, mainClass, classPath, endorsedDirs, extensionDirs};
return (List) kernel.invoke(deployer, "deploy", args, ARG_TYPES);
}
}