Package org.jvnet.hk2.osgiadapter

Source Code of org.jvnet.hk2.osgiadapter.HK2Main$HabitatInfo

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/


package org.jvnet.hk2.osgiadapter;

import com.sun.enterprise.module.ModulesRegistry;
import com.sun.enterprise.module.bootstrap.BootException;
import com.sun.enterprise.module.bootstrap.Main;
import com.sun.enterprise.module.bootstrap.ModuleStartup;
import com.sun.enterprise.module.bootstrap.StartupContext;
import com.sun.enterprise.module.common_impl.AbstractFactory;
import com.sun.enterprise.module.common_impl.TracingUtilities;
import com.sun.hk2.component.ExistingSingletonInhabitant;
import org.jvnet.hk2.component.Habitat;
import org.jvnet.hk2.component.Inhabitant;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

import static org.jvnet.hk2.osgiadapter.BundleEventType.valueOf;
import static org.jvnet.hk2.osgiadapter.Logger.logger;

/**
* {@link org.osgi.framework.BundleActivator} that launches a Habitat.
* A habitat is a collection of inhabitants, which are configured in a certain way.
* So, there is a one-to-one mapping between habitat and configuration file used to configure the inhabitants.
*
* @author Sanjeeb.Sahoo@Sun.COM
*/
public class HK2Main extends Main implements
        BundleActivator,
        SynchronousBundleListener {

    // TODO(Sahoo): Change to use ServiceTracker for all ServiceRegistrations

    private BundleContext ctx;

    private ServiceRegistration mrReg;
    private Map<Habitat, HabitatInfo> habitatInfos = new HashMap<Habitat, HabitatInfo>();

    /**
     * Stores additional artifacts corresponding to each Habitat created by us.
     */
    private class HabitatInfo {
        private Habitat habitat;
        private ServiceRegistration habitatRegistration;
        private ServiceTracker osgiServiceTracker;
        private ServiceRegistration moduleStartupRegistration;
    }

    public Habitat createHabitat(ModulesRegistry registry, StartupContext context) throws BootException {
        HabitatInfo habitatInfo = new HabitatInfo();
        habitatInfo.habitat = super.createHabitat(registry, context);
        createHK2ServiceTracker(habitatInfo);
        // register Habitat as an OSGi service
        habitatInfo.habitatRegistration = ctx.registerService(Habitat.class.getName(), habitatInfo.habitat, context.getArguments());
        habitatInfos.put(habitatInfo.habitat, habitatInfo);
        return habitatInfo.habitat;
    }

    private void destroyHabitat(Habitat habitat) {
        HabitatInfo habitatInfo = habitatInfos.get(habitat);
        if (habitatInfo == null) {
            return;
        }

        // run code in the reverse order
        habitatInfo.habitatRegistration.unregister();
        stopHK2ServiceTracker(habitatInfo);
        // AMX i shaving trouble if we release inhabitants. So temporarily disable this.
        // habitat.release();
        habitatInfo = null;
        habitatInfos.remove(habitat);
    }

    private void createHK2ServiceTracker(HabitatInfo habitatInfo) {
        habitatInfo.osgiServiceTracker = new ServiceTracker(
                ctx, new NonHK2ServiceFilter(), new HK2ServiceTrackerCustomizer(habitatInfo.habitat));
        habitatInfo.osgiServiceTracker.open(true);
    }

    /**
     * Stop service tracker associated with the given habitat
     *
     * @param habitatInfo
     */
    private void stopHK2ServiceTracker(HabitatInfo habitatInfo) {
        if (habitatInfo.osgiServiceTracker != null) {
            habitatInfo.osgiServiceTracker.close();
            habitatInfo.osgiServiceTracker = null;
        }
    }

    public void start(BundleContext context) throws Exception {
        this.ctx = context;
        logger.entering("HK2Main", "start", new Object[]{context});

//        ctx.addBundleListener(this); // used for debugging purpose

        OSGiFactoryImpl.initialize(ctx);

        ModulesRegistry mr = createModulesRegistry();
        if (TracingUtilities.isEnabled())
            registerBundleDumper(mr);

        ctx.registerService(Main.class.getName(), this, null);
    }

    private void registerBundleDumper(final ModulesRegistry mr) {

        ctx.addBundleListener(new SynchronousBundleListener() {
            public void bundleChanged(final BundleEvent event) {
                switch (event.getType()) {
                    case BundleEvent.RESOLVED:
                        TracingUtilities.traceResolution(mr,
                                event.getBundle().getBundleId(),
                                event.getBundle().getSymbolicName(),
                                new TracingUtilities.Loader() {
                                    @Override
                                    public Class loadClass(String type) throws ClassNotFoundException {
                                        return event.getBundle().loadClass(type);
                                    }
                                });
                        break;

                    case BundleEvent.STARTED:
                        TracingUtilities.traceStarted(mr,
                                event.getBundle().getBundleId(),
                                event.getBundle().getSymbolicName(),
                                new TracingUtilities.Loader() {
                                    @Override
                                    public Class loadClass(String type) throws ClassNotFoundException {
                                        return event.getBundle().loadClass(type);
                                    }
                                });

                        break;
                }
            }
        });
    }

    protected ModulesRegistry createModulesRegistry() {
        assert (mrReg == null);
        ModulesRegistry mr = AbstractFactory.getInstance().createModulesRegistry();
        mrReg = ctx.registerService(ModulesRegistry.class.getName(), mr, null);
        return mr;
    }

    @Override
    protected void setParentClassLoader(StartupContext context, ModulesRegistry mr) throws BootException {
        // OSGi doesn't have this feature, so ignore it for now.
    }

    public void stop(BundleContext context) throws Exception {
        // When OSGi framework shuts down, it shuts down all started bundles, but the order is unspecified.
        // So, since we are going to shutdown the registry, it's better that we stop startup service just incase it is still running.
        // Similarly, we can release the habitat.

        // Execute code in reverse order w.r.t. start()

        for (HabitatInfo habitatInfo : habitatInfos.values()) {
            ModuleStartup startupService =
                    habitatInfo.habitat.getComponent(ModuleStartup.class, habitatInfo.habitat.DEFAULT_NAME);
            if (startupService != null) {
                try {
                    logger.info("Stopping " + startupService);
                    startupService.stop();
                } catch (Exception e) {
                    logger.log(Level.WARNING, "HK2Main:stop():Exception while stopping ModuleStartup service.", e);
                }
            }
            destroyHabitat(habitatInfo.habitat);
        }

        ModulesRegistry mr = (ModulesRegistry) ctx.getService(mrReg.getReference());
        if (mr != null) {
            mr.shutdown();
            mr = null;
        }
//        ctx.removeBundleListener(this); // used for debugging only. see start method

    }

    public void bundleChanged(BundleEvent event) {
        if (logger.isLoggable(Level.FINE)) {
            logger.logp(Level.FINE, "HK2Main", "bundleChanged",
                "source= {0}, type= {1}", new Object[]{event.getSource(),
                        valueOf(event.getType())});
        }
    }

    private class NonHK2ServiceFilter implements Filter {
        public boolean match(ServiceReference serviceReference) {
            return (!ctx.getBundle().equals(serviceReference.getBundle()));
        }

        public boolean match(Dictionary dictionary) {
            throw new RuntimeException("Unexpected method called");
        }

        public boolean matchCase(Dictionary dictionary) {
            throw new RuntimeException("Unexpected method called");
        }

        public String toString() {
            return "(objectClass=*)";
        }
    }

    private class HK2ServiceTrackerCustomizer implements ServiceTrackerCustomizer {
        private final Habitat habitat;

        private HK2ServiceTrackerCustomizer(Habitat habitat) {
            this.habitat = habitat;
        }

        public Object addingService(final ServiceReference reference) {
            final Object object = ctx.getService(reference);

            if (object == null) {
                // service obuject can be null if the service is created using a factory and the factory fails to
                // create for whatever reason. In such a case, gracefully handle the situation instead of us failing.
                // See GLASSFISH-17398 for example.
                String objectDetails = reference.toString();
                logger.logp(Level.INFO, "HK2Main$HK2ServiceTrackerCustomizer", "addingService",
                        "Skipping registration of inhabitant for service reference {0} " +
                                "as the service object could not be obtained.", new Object[]{objectDetails});
                return null;
            }

            // let's get the list of implemented contracts
            String[] contractNames = (String[]) reference.getProperty("objectclass");
            if (contractNames != null && contractNames.length > 0) {
                // we will register this service under each contract it implements
                for (String contractName : contractNames) {
                    String name = (String) reference.getProperty("component.name");
                    if (name == null) {
                        // let's get a name if possible, that will only work with Spring OSGi services
                        // we may need to find a better way to get a potential name.
                        name = (String) reference.getProperty("org.springframework.osgi.bean.name");
                    }
                    habitat.addIndex(new ExistingSingletonInhabitant(object), contractName, name);
                    if (logger.isLoggable(Level.FINE)) {
                        String objectDetails = object.toString();
                        logger.logp(Level.FINE, "HK2Main$HK2ServiceTrackerCustomizer",
                            "addingService", "registering service = {0}, contract = {1}, name = {2}", new Object[]{
                                    objectDetails, contractName, name});
                    }
                }
            } else {
                // this service does not implement a specific contract, let's register it by its type.
                habitat.add(new ExistingSingletonInhabitant(object));
                if (logger.isLoggable(Level.FINE)) {
                    String objectDetails = object.toString();
                    logger.logp(Level.FINE, "HK2Main$HK2ServiceTrackerCustomizer",
                        "addingService", "registering service = {0}", objectDetails);
                }
            }
            return object;
        }

        public void modifiedService(ServiceReference reference, Object service) {
        }

        public void removedService(ServiceReference reference, Object service) {
            // we need to unregister the service for each contract it implements.
            String[] contractNames = (String[]) reference.getProperty("objectclass");
            if (contractNames != null && contractNames.length > 0) {
                for (String contractName : contractNames) {
                    habitat.removeIndex(contractName, service);
                    if (logger.isLoggable(Level.FINE)) {
                        String serviceDetails = service.toString();
                        logger.logp(Level.FINE, "HK2Main$HK2ServiceTrackerCustomizer",
                            "removingService", "removing service = {0}, contract = {1}",
                            new Object[]{serviceDetails, contractName});
                    }

                }
            } else {
                // it was registered by type
                Inhabitant<?> inhabitant = habitat.getInhabitantByType(service.getClass());
                if (inhabitant != null) {
                    habitat.remove(inhabitant);
                } else {
                    String serviceDetails = service.toString();
                    logger.logp(Level.WARNING, "HK2Main$HK2ServiceTrackerCustomizer",
                            "removedService", "cannot removed singleton service = {0}", serviceDetails);
                }
            }
        }

    }

}
TOP

Related Classes of org.jvnet.hk2.osgiadapter.HK2Main$HabitatInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.