com.okidokiteam.gouken.kernel.CoreVault.java Source code

Java tutorial

Introduction

Here is the source code for com.okidokiteam.gouken.kernel.CoreVault.java

Source

/*
 * Copyright 2010 Toni Menzel.
 *
 * 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 com.okidokiteam.gouken.kernel;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.inject.Inject;
import com.okidokiteam.gouken.ArtifactReference;
import com.okidokiteam.gouken.GoukenResolver;
import com.okidokiteam.gouken.KernelException;
import com.okidokiteam.gouken.KernelWorkflowException;
import com.okidokiteam.gouken.ManagementAgent;
import com.okidokiteam.gouken.Vault;
import com.okidokiteam.gouken.VaultSettings;
import org.apache.commons.discovery.tools.DiscoverSingleton;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ops4j.pax.repository.RepositoryException;

/**
 * This Vault actually knows about OSGi, it actually boots a fw, provisions it and manages its lifecycle.
 * Beyond this, we should not have the notion of osgi other than DeploymentPackages. (also with another untyped as we probably just want a subset of that spec).
 * <p/>
 * This Vault uses an OSGi Core R 4.2+ compatible OSGi implementation
 * <p/> *
 *
 * @author Toni Menzel
 * @since Mar 4, 2010
 */
public class CoreVault<PUSHTYPE> implements Vault<PUSHTYPE> {

    private static final Logger LOG = LoggerFactory.getLogger(CoreVault.class);
    private static final String META_INF_GOUKEN_KERNEL_PROPERTIES = "/META-INF/gouken/kernel.properties";

    // accessed by shutdownhook and remote access
    private volatile Framework m_framework;
    private final VaultSettings m_settings;
    private Class<PUSHTYPE> m_pushServiceType;

    private GoukenResolver m_resolver = null;

    @Inject
    public CoreVault(GoukenResolver resolver, VaultSettings settings, Class<PUSHTYPE> pushService) {
        assert resolver != null : "resolver must not be null.";
        assert settings != null : "settings must not be null.";
        m_settings = settings;
        m_resolver = resolver;
        m_pushServiceType = pushService;
    }

    public PUSHTYPE start(ManagementAgent agent) throws KernelWorkflowException, KernelException {
        if (isRunning()) {
            throw new KernelWorkflowException("Vault is already running.");
        }

        ClassLoader parent = null;
        try {
            final Map<String, Object> p = getFrameworkConfig();
            parent = Thread.currentThread().getContextClassLoader();

            Thread.currentThread().setContextClassLoader(null);
            loadAndStartFramework(p);
            Thread.currentThread().setContextClassLoader(parent);

            installAgent(agent);

        } catch (Exception e) {
            // kind of a clean the mess up..
            tryShutdown();
            throw new KernelException("Problem starting the Vault", e);

        } finally {
            if (parent != null) {
                Thread.currentThread().setContextClassLoader(parent);
            }
        }

        // create a dynamic proxy for T that looks T up on demand and invokes stuff on it.
        if (m_framework == null) {
            throw new KernelWorkflowException("No framework installed.");

            //return (PUSHTYPE) new Object();
        }
        return createProxyService();
    }

    private void installAgent(ManagementAgent agent)

            throws KernelException {

        ArtifactReference[] artifacts;
        try {
            artifacts = agent.getRuntimeParts();
        } catch (RepositoryException e) {
            throw new KernelException("Problem getting artifacts from agent: " + agent, e);
        }

        int i = 0;
        List<Bundle> bundles = new ArrayList<Bundle>();

        for (ArtifactReference artifact : artifacts) {
            i++;
            try {
                bundles.add(
                        m_framework.getBundleContext().installBundle("MA" + i, m_resolver.find(artifact).get()));
            } catch (BundleException e) {
                throw new KernelException("Problem installing management agent resources. Artifact: " + artifact,
                        e);
            } catch (RepositoryException e) {
                throw new KernelException("Problem loading management agent resources. Artifact: " + artifact, e);
            }
        }

        for (Bundle b : bundles) {
            try {
                b.start();
            } catch (BundleException e) {
                throw new KernelException(
                        "One of the Management Agent Bundles could not be started. Bundle ID: " + b.getBundleId(),
                        e);
            }
        }
    }

    public synchronized void stop() throws KernelException {
        try {
            LOG.info("Stop hook triggered.");
            if (m_framework != null) {
                BundleContext ctx = m_framework.getBundleContext();
                Bundle systemBundle = ctx.getBundle(0);
                systemBundle.stop();
                m_framework = null;
            }
            System.gc();
            LOG.info("Shutdown complete.");
        } catch (BundleException e) {
            LOG.error("Problem stopping framework.", e);
        }

    }

    private Map<String, Object> getFrameworkConfig() throws IOException {
        InputStream ins = getClass().getResourceAsStream(META_INF_GOUKEN_KERNEL_PROPERTIES);
        Properties descriptor = new Properties();
        if (ins != null) {
            descriptor.load(ins);
        }

        final Map<String, Object> p = new HashMap<String, Object>();
        File worker = new File(m_settings.getWorkingFolder(), "framework");

        p.put("org.osgi.framework.storage", worker.getAbsolutePath());
        // p.put( "felix.log.level", "1" );

        configureBridgingServiceDelegation(p);

        for (Object key : descriptor.keySet()) {
            p.put((String) key, descriptor.getProperty((String) key));
        }
        return p;
    }

    private void configureBridgingServiceDelegation(Map<String, Object> p) {
        if (m_pushServiceType != null) {
            String pushServicePackage = m_pushServiceType.getPackage().getName();

            p.put("org.osgi.framework.system.packages.extra", pushServicePackage);
            p.put("org.osgi.framework.bootdelegation", pushServicePackage);
            p.put("org.osgi.framework.bundle.parent", "framework");
        } else {
            LOG.warn("No Pushtype registered. Thus no bridging of anything with the surounding class loader.");
        }
    }

    private void loadAndStartFramework(Map<String, Object> p)
            throws BundleException, IOException, RepositoryException, KernelException {
        FrameworkFactory factory = (FrameworkFactory) DiscoverSingleton.find(FrameworkFactory.class);
        m_framework = factory.newFramework(p);

        // p.put( FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, Arrays.asList( new Activator() ) );
        // m_framework = new Felix( p );
        m_framework.init();
        m_framework.start();
    }

    private void tryShutdown() {
        if (m_framework != null) {
            try {
                m_framework.stop();

            } catch (Exception e) {
                // dont care.
            }
        }
    }

    private boolean isRunning() {
        return (m_framework != null);
    }

    /**
     * Dynamic proxy around a service that is being used from the outside.
     * Its usually being used to provide some kind of push functionality of the management agent.
     *
     * @return proxy for t. Will delegate to underlying osgi service registry upon each call.
     */
    @SuppressWarnings("unchecked")
    private PUSHTYPE createProxyService() {
        return (PUSHTYPE) Proxy.newProxyInstance(m_framework.getClass().getClassLoader(),
                new Class<?>[] { m_pushServiceType }, new ProtectedInvocationHandler(
                        new OSGiServicePushHandler(m_pushServiceType, m_framework.getBundleContext())));
    }
}