All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.geronimo.system.sharedlib.SharedLib Maven / Gradle / Ivy

The newest version!
/**
 *  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.geronimo.system.sharedlib;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.gbean.annotation.GBean;
import org.apache.geronimo.gbean.annotation.ParamAttribute;
import org.apache.geronimo.gbean.annotation.ParamReference;
import org.apache.geronimo.gbean.annotation.ParamSpecial;
import org.apache.geronimo.gbean.annotation.SpecialAttributeType;
import org.apache.geronimo.kernel.config.Manifest;
import org.apache.geronimo.kernel.repository.Artifact;
import org.apache.geronimo.kernel.util.IOUtils;
import org.apache.geronimo.system.serverinfo.ServerInfo;
import org.apache.xbean.osgi.bundle.util.BundleUtils;
import org.apache.xbean.osgi.bundle.util.DelegatingBundle;
import org.apache.xbean.osgi.bundle.util.HeaderBuilder;
import org.apache.xbean.osgi.bundle.util.HeaderParser;
import org.apache.xbean.osgi.bundle.util.HeaderParser.HeaderElement;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @version $Rev$ $Date$
 */
@GBean
public class SharedLib implements GBeanLifecycle {

    private static final Logger logger = LoggerFactory.getLogger(SharedLib.class);

    private File baseFolder;

    private String[] libDirs;

    private String[] classesDirs;

    private ServerInfo serverInfo;

    private BundleContext bundleContext;

    private AbstractName name;

    private Bundle sharedLibBundle;

    public SharedLib(@ParamAttribute(name = "baseDir") String baseDir,
            @ParamAttribute(name = "classesDirs") String[] classesDirs,
            @ParamAttribute(name = "libDirs") String[] libDirs,
            @ParamReference(name = "ServerInfo") ServerInfo serverInfo,
            @ParamSpecial(type = SpecialAttributeType.bundleContext) BundleContext bundleContext,
            @ParamSpecial(type = SpecialAttributeType.abstractName) AbstractName name) {
        if (baseDir == null) {
            throw new IllegalArgumentException("baseDir is required to configured for the sharedLib, and the values of classesDirs and libDirs should be relative to the baseDir");
        }
        baseFolder = serverInfo.resolveServer(baseDir);
        if (!baseFolder.exists()) {
            if (!baseFolder.mkdirs()) {
                throw new IllegalArgumentException("Failed to create classes dir: " + baseDir);
            }
        }
        if (classesDirs == null && libDirs == null) {
            throw new IllegalArgumentException("At least, one of the attributes classesDirs and libDirs is required to configured.");
        }
        this.classesDirs = classesDirs;
        this.libDirs = libDirs;
        this.serverInfo = serverInfo;
        this.bundleContext = bundleContext;
        this.name = name;
    }

    @Override
    public void doStart() throws Exception {
        String bundleLocation = "reference:" + baseFolder.toURI().toURL();
        //1. Double check the share library bundle is not installed
        for (Bundle b : bundleContext.getBundles()) {
            if (b.getLocation().equals(bundleLocation)) {
                if (logger.isDebugEnabled()) {
                    logger.debug(" Share library bundle is found installed, it might be caused by the server was not shutdown correctly last time, it will be reinstalled");
                }
                b.uninstall();
                break;
            }
        }
        //2. Generate the MANIFEST.MF file for the share library
        Manifest manifest = new Manifest();
        manifest.addConfiguredAttribute(new Manifest.Attribute(Constants.BUNDLE_MANIFESTVERSION, "2"));
        Artifact configId = name.getArtifact();
        manifest.addConfiguredAttribute(new Manifest.Attribute(Constants.BUNDLE_SYMBOLICNAME, configId.getGroupId() + "." + configId.getArtifactId() + "." + name.getNameProperty("name")));
        String versionString = "" + configId.getVersion().getMajorVersion() + "." + configId.getVersion().getMinorVersion() + "." + configId.getVersion().getIncrementalVersion();
        if (configId.getVersion().getQualifier() != null) {
            versionString += "." + configId.getVersion().getQualifier().replaceAll("[^-_\\w]{1}", "_");
        }
        manifest.addConfiguredAttribute(new Manifest.Attribute(Constants.BUNDLE_VERSION, versionString));
        Set bundleClassPaths = generateBundleClassPath();
        if (bundleClassPaths.size() > 0) {
            Manifest.Attribute bundleClassPath = new Manifest.Attribute(Manifest.Attribute.Separator.COMMA, Constants.BUNDLE_CLASSPATH, bundleClassPaths);
            manifest.addConfiguredAttribute(bundleClassPath);
        }
        //import packages, dynamic import packages and required bundles are from the configuration bundle.
        String importPackages = (String)bundleContext.getBundle().getHeaders().get(Constants.IMPORT_PACKAGE);
        if (importPackages != null) {
            manifest.addConfiguredAttribute(new Manifest.Attribute(Manifest.Attribute.Separator.COMMA, Constants.IMPORT_PACKAGE, importPackages));
        }
        String dynamicImportPackages = (String)bundleContext.getBundle().getHeaders().get(Constants.DYNAMICIMPORT_PACKAGE);
        if (dynamicImportPackages != null) {
            List headerElements = HeaderParser.parseHeader(dynamicImportPackages);
            //From shared library perspective, dynamic * should not be used
            /*for (Iterator it = headerElements.iterator(); it.hasNext();) {
                if (it.next().getName().equals("*")) {
                    it.remove();
                }
            }*/
            if (headerElements.size() > 0) {
                manifest.addConfiguredAttribute(new Manifest.Attribute(Manifest.Attribute.Separator.COMMA, Constants.DYNAMICIMPORT_PACKAGE, HeaderBuilder.build(headerElements)));
            }
        }
        String requiredBundles = (String)bundleContext.getBundle().getHeaders().get(Constants.REQUIRE_BUNDLE);
        if (requiredBundles != null) {
            manifest.addConfiguredAttribute(new Manifest.Attribute(Manifest.Attribute.Separator.COMMA, Constants.REQUIRE_BUNDLE, requiredBundles));
        }
        //3. Write the MANIFEST.MF file
        File metaInf = new File(baseFolder, "META-INF");
        metaInf.mkdirs();
        PrintWriter pw = null;
        try {
            pw = new PrintWriter(new FileWriter(new File(metaInf, "MANIFEST.MF")));
            manifest.write(pw);
        } finally {
            IOUtils.close(pw);
        }
        //4. Install the bundle
        sharedLibBundle = bundleContext.installBundle(bundleLocation);
        if (BundleUtils.isResolved(sharedLibBundle)) {
            BundleUtils.resolve(sharedLibBundle);
        }
        //5. register the shared library bundle to the shared library bundle extender
        ServiceReference sharedLibExtenderReference = null;
        try {
            sharedLibExtenderReference = bundleContext.getServiceReference(SharedLibExtender.class.getName());
            if (sharedLibExtenderReference != null) {
                SharedLibExtender shareLibExtender = (SharedLibExtender) bundleContext.getService(sharedLibExtenderReference);
                shareLibExtender.registerSharedLibBundle(name.getArtifact(), sharedLibBundle);
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to register the share lib bundle " + sharedLibBundle.getSymbolicName() + " in the ShareLibExtender");
                }
            }
        } finally {
            if (sharedLibExtenderReference != null) {
                try {
                    bundleContext.ungetService(sharedLibExtenderReference);
                } catch (Exception e) {
                }
            }
        }
    }

    protected Set generateBundleClassPath() {
        Set bundleClassPaths = new LinkedHashSet();
        if (classesDirs != null) {
            for (int i = 0; i < classesDirs.length; i++) {
                String classesDir = classesDirs[i];
                File dir = new File(baseFolder, classesDir);
                if (!dir.exists()) {
                    if (!dir.mkdirs()) {
                        throw new IllegalArgumentException("Failed to create classes dir: " + dir);
                    }
                }
                if (!dir.isDirectory()) {
                    throw new IllegalArgumentException("Shared classes dir is not a directory: " + dir);
                }
                if (classesDir.startsWith("/")) {
                    classesDir = classesDir.length() == 1 ? "." : classesDir.substring(1);
                }
                bundleClassPaths.add(classesDir);
            }
        }
        if (libDirs != null) {
            for (int i = 0; i < libDirs.length; i++) {
                String libDir = libDirs[i];
                File dir = new File(baseFolder, libDir);
                if (!dir.exists()) {
                    logger.warn("share library directory " + libDir + " is not found, it will be ingored");
                    break;
                }
                if (!dir.isDirectory()) {
                    throw new IllegalArgumentException("Shared lib dir is not a directory: " + dir);
                }

                File[] files = dir.listFiles();
                for (int j = 0; j < files.length; j++) {
                    File file = files[j];
                    if (file.canRead() && (file.getName().endsWith(".jar") || file.getName().endsWith(".zip"))) {
                        if (libDir.startsWith("/")) {
                            libDir = libDir.length() == 1 ? "" : libDir.substring(1);
                        }
                        if (!libDir.endsWith("/")) {
                            libDir = libDir + "/";
                        }
                        bundleClassPaths.add(libDir + file.getName());
                    }
                }
            }
        }
        return bundleClassPaths;
    }

    @Override
    public void doStop() throws Exception {
        if (sharedLibBundle == null) {
            return;
        }
        //1. remove the bundle from the parent DelegatingBundle
        Bundle configurationBundle = bundleContext.getBundle();
        if (configurationBundle instanceof DelegatingBundle) {
            DelegatingBundle delegatingBundle = (DelegatingBundle) configurationBundle;
            delegatingBundle.removeBundle(sharedLibBundle);
        }
        //2. unregister the share lib bundle to the share lib bundle extender
        ServiceReference sharedLibExtenderReference = null;
        try {
            sharedLibExtenderReference = bundleContext.getServiceReference(SharedLibExtender.class.getName());
            if (sharedLibExtenderReference != null) {
                SharedLibExtender sharedLibExtender = (SharedLibExtender) bundleContext.getService(sharedLibExtenderReference);
                sharedLibExtender.unregisterSharedLibBundle(name.getArtifact(), sharedLibBundle);
            }
        } finally {
            if (sharedLibExtenderReference != null) {
                try {
                    bundleContext.ungetService(sharedLibExtenderReference);
                } catch (Exception e) {
                }
            }
        }
        //3. uninstall the share library bundle
        if (sharedLibBundle != null) {
            try {
                sharedLibBundle.uninstall();
            } catch (Exception e) {
                //Sometimes, it is unable to uninstall the shared library bundle, as it is in the shutdown progress.
            }
        }
    }

    @Override
    public void doFail() {
        try {
            doStop();
        } catch (Exception e) {
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy