Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.servicemix.jbi.deployer.impl; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.jbi.JBIException; import javax.jbi.component.Bootstrap; import javax.jbi.management.DeploymentException; import javax.jbi.management.InstallerMBean; import javax.jbi.management.LifeCycleMBean; import javax.management.Attribute; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; import org.apache.servicemix.jbi.deployer.Component; import org.apache.servicemix.jbi.deployer.SharedLibrary; import org.apache.servicemix.jbi.deployer.artifacts.ComponentImpl; import org.apache.servicemix.jbi.deployer.descriptor.ComponentDesc; import org.apache.servicemix.jbi.deployer.descriptor.Descriptor; import org.apache.servicemix.jbi.deployer.descriptor.SharedLibraryList; import org.apache.servicemix.jbi.deployer.utils.FileUtil; import org.apache.servicemix.jbi.deployer.utils.ManagementSupport; import org.apache.xbean.classloader.MultiParentClassLoader; import org.apache.servicemix.nmr.management.Nameable; import org.osgi.framework.Bundle; import org.osgi.service.prefs.BackingStoreException; import org.springframework.osgi.util.BundleDelegatingClassLoader; public class ComponentInstaller extends AbstractInstaller implements InstallerMBean, Nameable { private InstallationContextImpl installationContext; private ObjectName objectName; private ObjectName extensionMBeanName; private boolean initialized; private Bootstrap bootstrap; private javax.jbi.component.Component innerComponent; public ComponentInstaller(Deployer deployer, Descriptor descriptor, File jbiArtifact, boolean autoStart) throws Exception { super(deployer, descriptor, jbiArtifact, autoStart); this.installRoot = new File(System.getProperty("servicemix.base"), "data/jbi/" + getName() + "/install"); this.installRoot.mkdirs(); this.installationContext = new InstallationContextImpl(descriptor.getComponent(), deployer.getEnvironment(), deployer.getManagementStrategy(), deployer.getMbeanServer()); this.installationContext.setInstallRoot(installRoot); } /** * Get the installation root directory path for this BC or SE. * * @return the full installation path of this component. */ public String getInstallRoot() { return installationContext.getInstallRoot(); } public void register() throws JMException { try { deployer.getManagementStrategy().manageObject(this); } catch (Exception ex) { throw new JMException(ex.getMessage()); } } public void unregister() throws JMException { try { deployer.getManagementStrategy().unmanageObject(this); } catch (Exception ex) { throw new JMException(ex.getMessage()); } } public String getName() { return descriptor.getComponent().getIdentification().getName(); } public javax.jbi.component.Component getInnerComponent() { return innerComponent; } public void setInnerComponent(javax.jbi.component.Component innerComponent) { this.innerComponent = innerComponent; } public void init() throws Exception { // Check requirements if (descriptor.getComponent().getSharedLibraries() != null) { for (SharedLibraryList sl : descriptor.getComponent().getSharedLibraries()) { if (deployer.getSharedLibrary(sl.getName()) == null) { throw new PendingException(bundle, "SharedLibrary not installed: " + sl.getName()); } } } // Extract bundle super.init(); // Init bootstrap if (isModified) { initBootstrap(); } } /** * Install a BC or SE. * * @return JMX ObjectName representing the ComponentLifeCycle for the installed component, or null if the * installation did not complete. * @throws javax.jbi.JBIException if the installation fails. */ public ObjectName install() throws JBIException { try { if (isModified) { if (isInstalled()) { throw new DeploymentException("Component is already installed"); } initBootstrap(); if (bootstrap != null) { bootstrap.onInstall(); } try { ObjectName name = initComponent(); cleanUpBootstrap(); installationContext.setInstall(false); postInstall(); return name; } catch (Exception e) { cleanUpBootstrap(); throw e; } } else { ObjectName name = initComponent(); postInstall(); return name; } } catch (Exception e) { LOGGER.error(e.getMessage()); throw new JBIException(e); } } /** * Determine whether or not the component is installed. * * @return true if this component is currently installed, false if not. */ public boolean isInstalled() { return !installationContext.isInstall(); } /** * Uninstall a BC or SE. This completely removes the component from the JBI system. * * @throws javax.jbi.JBIException if the uninstallation fails. */ public void uninstall() throws javax.jbi.JBIException { try { uninstall(false); } catch (JBIException e) { throw e; } catch (Exception e) { throw new JBIException(e); } } public void stop(boolean force) throws Exception { ComponentImpl comp = deployer.getComponent(getName()); if (comp == null && !force) { throw ManagementSupport.failure("uninstallComponent", "Component '" + getName() + "' is not installed."); } // Check component state is shutdown if (comp != null && !LifeCycleMBean.SHUTDOWN.equals(comp.getCurrentState())) { if (!force) { throw ManagementSupport.failure("uninstallComponent", "Component '" + getName() + "' is not shut down."); } if (LifeCycleMBean.STARTED.equals(comp.getCurrentState())) { comp.stop(false); } if (LifeCycleMBean.STOPPED.equals(comp.getCurrentState())) { comp.shutDown(false, force); } } } public void uninstall(boolean force) throws Exception { // Shutdown component stop(force); // Retrieve component ComponentImpl comp = deployer.getComponent(getName()); if (comp == null && !force) { throw ManagementSupport.failure("uninstallComponent", "Component '" + getName() + "' is not installed."); } // TODO: if there is any SA deployed onto this component, undeploy the SA and put it in a pending state // Bootstrap stuff if (hasBootstrap()) { try { initBootstrap(); bootstrap.init(this.installationContext); bootstrap.getExtensionMBeanName(); bootstrap.onUninstall(); cleanUpBootstrap(); installationContext.setInstall(true); } catch (Exception e) { cleanUpBootstrap(); throw e; } } // Unregister component deployer.unregisterComponent(comp); // Remove preferences try { deletePreferences(); } catch (BackingStoreException e) { LOGGER.warn("Error cleaning persistent state for component: " + getName(), e); } // Uninstall bundle uninstallBundle(); // Remove files FileUtil.deleteFile(installRoot); } /** * Get the installer configuration MBean name for this component. * * @return the MBean object name of the Installer Configuration MBean. * @throws javax.jbi.JBIException if the component is not in the LOADED state or any error occurs during processing. */ public ObjectName getInstallerConfigurationMBean() throws javax.jbi.JBIException { return this.extensionMBeanName; } /** * @return Returns the objectName. */ public ObjectName getObjectName() { if (objectName == null) { try { objectName = deployer.getManagementStrategy().getManagedObjectName(this, null, ObjectName.class); } catch (Exception e) { // ignore } } return objectName; } /** * @param objectName The objectName to set. */ public void setObjectName(ObjectName objectName) { this.objectName = objectName; } protected ClassLoader createClassLoader(Bundle bundle, String name, String[] classPathNames, boolean parentFirst, SharedLibrary[] sharedLibs) { // Create parents classloaders ClassLoader[] parents; if (sharedLibs != null) { parents = new ClassLoader[sharedLibs.length + 2]; for (int i = 0; i < sharedLibs.length; i++) { parents[i] = sharedLibs[i].getClassLoader(); } } else { parents = new ClassLoader[2]; } parents[parents.length - 2] = BundleDelegatingClassLoader.createBundleClassLoaderFor(bundle, getClass().getClassLoader()); parents[parents.length - 1] = BundleDelegatingClassLoader .createBundleClassLoaderFor(getBundleContext().getBundle(0)); // Create urls List<URL> urls = new ArrayList<URL>(); for (int i = 0; i < classPathNames.length; i++) { File f = new File(installRoot, classPathNames[i]); if (!f.exists()) { LOGGER.warn("Component classpath entry not found: '" + classPathNames[i] + "'"); } try { urls.add(f.getCanonicalFile().toURL()); } catch (IOException e) { throw new IllegalArgumentException( "Component classpath entry not found: '" + classPathNames[i] + "'"); } } // Create classloader return new MultiParentClassLoader(name, urls.toArray(new URL[urls.size()]), parents, !parentFirst, new String[0], new String[] { "java.", "javax." }); } private void initBootstrap() throws DeploymentException { if (!hasBootstrap()) { return; } try { if (!initialized) { // Unregister a previously registered extension mbean, // in case the bootstrap has not done it try { if (extensionMBeanName != null) { deployer.getManagementStrategy().unmanageObject(extensionMBeanName); } } catch (Exception e) { // ignore } if (bootstrap == null) { bootstrap = createBootstrap(); } // Init bootstrap ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(bootstrap.getClass().getClassLoader()); bootstrap.init(this.installationContext); extensionMBeanName = bootstrap.getExtensionMBeanName(); } finally { Thread.currentThread().setContextClassLoader(oldCl); } initialized = true; } } catch (JBIException e) { LOGGER.error("Could not initialize bootstrap", e); throw new DeploymentException(e); } } protected void cleanUpBootstrap() throws DeploymentException { if (bootstrap != null) { ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(bootstrap.getClass().getClassLoader()); bootstrap.cleanUp(); } catch (JBIException e) { LOGGER.error("Could not initialize bootstrap", e); throw new DeploymentException(e); } finally { initialized = false; Thread.currentThread().setContextClassLoader(oldCl); } } } private boolean hasBootstrap() { ComponentDesc descriptor = installationContext.getDescriptor(); return descriptor.getBootstrapClassName() != null; } private Bootstrap createBootstrap() throws DeploymentException { ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); ComponentDesc descriptor = installationContext.getDescriptor(); try { ClassLoader cl = createClassLoader(getBundle(), installationContext.getInstallRoot(), descriptor.getBootstrapClassPath().getPathElements(), descriptor.isBootstrapClassLoaderDelegationParentFirst(), null); Thread.currentThread().setContextClassLoader(cl); Class bootstrapClass = cl.loadClass(descriptor.getBootstrapClassName()); return (Bootstrap) bootstrapClass.newInstance(); } catch (ClassNotFoundException e) { LOGGER.error("Class not found: " + descriptor.getBootstrapClassName(), e); throw new DeploymentException(e); } catch (InstantiationException e) { LOGGER.error("Could not instantiate : " + descriptor.getBootstrapClassName(), e); throw new DeploymentException(e); } catch (IllegalAccessException e) { LOGGER.error("Illegal access on: " + descriptor.getBootstrapClassName(), e); throw new DeploymentException(e); } finally { Thread.currentThread().setContextClassLoader(oldCl); } } private ObjectName initComponent() throws Exception { ComponentDesc componentDesc = installationContext.getDescriptor(); List<SharedLibrary> libs = new ArrayList<SharedLibrary>(); if (componentDesc.getSharedLibraries() != null) { for (SharedLibraryList sll : componentDesc.getSharedLibraries()) { SharedLibrary lib = deployer.getSharedLibrary(sll.getName()); if (lib == null) { // TODO: throw exception here ? } else { libs.add(lib); } } } SharedLibrary[] aLibs = libs.toArray(new SharedLibrary[libs.size()]); if (innerComponent == null) { ClassLoader classLoader = createClassLoader(getBundle(), componentDesc.getIdentification().getName(), (String[]) installationContext.getClassPathElements() .toArray(new String[installationContext.getClassPathElements().size()]), componentDesc.isComponentClassLoaderDelegationParentFirst(), aLibs); ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(classLoader); Class clazz = classLoader.loadClass(componentDesc.getComponentClassName()); innerComponent = (javax.jbi.component.Component) clazz.newInstance(); } finally { Thread.currentThread().setContextClassLoader(oldCl); } } Component component = deployer.registerComponent(getBundle(), componentDesc, innerComponent, aLibs); return deployer.getManagementStrategy().getManagedObjectName(component, null, ObjectName.class); } public void configure(Properties props) throws Exception { if (props != null && props.size() > 0) { ObjectName on = getInstallerConfigurationMBean(); if (on == null) { LOGGER.warn( "Could not find installation configuration MBean. Installation properties will be ignored."); } else { MBeanServer mbs = deployer.getMbeanServer(); for (Object o : props.keySet()) { String key = (String) o; String val = props.getProperty(key); try { mbs.setAttribute(on, new Attribute(key, val)); } catch (JMException e) { throw new DeploymentException("Could not set installation property: (" + key + " = " + val, e); } } } } } public String getParent() { return null; } public String getMainType() { return "service-engine"; } public String getSubType() { return "Installer"; } public String getVersion() { return null; } public Class getPrimaryInterface() { return InstallerMBean.class; } }