org.ops4j.pax.exam.rbc.internal.RemoteBundleContextImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.exam.rbc.internal.RemoteBundleContextImpl.java

Source

/*
 * Copyright 2008 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 org.ops4j.pax.exam.rbc.internal;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.util.Dictionary;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.startlevel.StartLevel;
import static org.ops4j.lang.NullArgumentException.*;

/**
 * {@link RemoteBundleContext} implementaton.
 *
 * @author Toni Menzel (tonit)
 * @author Alin Dreghiciu (adreghiciu@gmail.com)
 * @since 0.1.0, June 10, 2008
 */
public class RemoteBundleContextImpl implements RemoteBundleContext, Serializable {

    /**
     * JCL Logger.
     */
    private static final Log LOG = LogFactory.getLog(RemoteBundleContextImpl.class);
    /**
     * Bundle context (cannot be null).
     */
    private final transient BundleContext m_bundleContext;

    /**
     * Constructor.
     *
     * @param bundleContext bundle context (cannot be null)
     *
     * @throws IllegalArgumentException - If bundle context is null
     */
    public RemoteBundleContextImpl(final BundleContext bundleContext) {
        validateNotNull(bundleContext, "Bundle context");
        m_bundleContext = bundleContext;
    }

    /**
     * {@inheritDoc}
     */
    public Object remoteCall(final Class<?> serviceType, final String methodName, final Class<?>[] methodParams,
            final long timeoutInMillis, final Object... actualParams) throws NoSuchServiceException,
            NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        LOG.info("Remote call of [" + serviceType.getName() + "." + methodName + "]");
        return serviceType.getMethod(methodName, methodParams).invoke(getService(serviceType, timeoutInMillis),
                actualParams);
    }

    /**
     * {@inheritDoc}
     */
    public long installBundle(final String bundleUrl) throws BundleException {
        LOG.info("Install bundle from URL [" + bundleUrl + "]");
        return m_bundleContext.installBundle(bundleUrl).getBundleId();
    }

    /**
     * {@inheritDoc}
     */
    public long installBundle(final String bundleLocation, final byte[] bundle) throws BundleException {
        LOG.info("Install bundle [" + bundleLocation + "] from byte array");
        final ByteArrayInputStream inp = new ByteArrayInputStream(bundle);
        try {
            return m_bundleContext.installBundle(bundleLocation, inp).getBundleId();
        } finally {
            try {
                inp.close();
            } catch (IOException e) {
                // ignore.
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void startBundle(long bundleId) throws BundleException {
        startBundle(m_bundleContext.getBundle(bundleId));
    }

    /**
     * {@inheritDoc}
     */
    public void stopBundle(long bundleId) throws BundleException {
        m_bundleContext.getBundle(bundleId).stop();
    }

    /**
     * {@inheritDoc}
     */
    public void setBundleStartLevel(long bundleId, int startLevel) throws RemoteException, BundleException {
        try {
            final StartLevel startLevelService = getService(StartLevel.class, 0);
            startLevelService.setBundleStartLevel(m_bundleContext.getBundle(bundleId), startLevel);
        } catch (NoSuchServiceException e) {
            throw new BundleException("Cannot get the start level service to set bundle start level");
        }
    }

    /**
     * {@inheritDoc}
     */
    public void waitForState(final long bundleId, final int state, final long timeoutInMillis)
            throws TimeoutException {
        Bundle bundle = m_bundleContext.getBundle(bundleId);
        if (timeoutInMillis == NO_WAIT && (bundle == null || bundle.getState() < state)) {
            throw new TimeoutException("There is no waiting timeout set and bundle has state '"
                    + bundleStateToString(bundle.getState()) + "' not '" + bundleStateToString(state)
                    + "' as expected");
        }
        long startedTrying = System.currentTimeMillis();
        do {
            bundle = m_bundleContext.getBundle(bundleId);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        } while ((bundle == null || bundle.getState() < state) && (timeoutInMillis == WAIT_FOREVER
                || System.currentTimeMillis() < startedTrying + timeoutInMillis));
        // bundle != null && bundle.getState() >= state
        // or
        // timeoutInMillis != WAIT_FOREVER && System.currentTimeMillis() >= startedTrying + timeoutInMillis
        if (bundle == null || bundle.getState() < state) {
            throw new TimeoutException(
                    "Timeout passed and bundle has state '" + bundleStateToString(bundle.getState()) + "' not '"
                            + bundleStateToString(state) + "' as expected");
        }
    }

    /**
     * Lookup a service in the service registry.
     *
     * @param serviceType     service class
     * @param timeoutInMillis number of milliseconds to wait for service before failing
     *                        TODO timeout is not used!
     *
     * @return a service published under the required service type
     *
     * @throws NoSuchServiceException - If service cannot be found in the service registry
     */
    private <T> T getService(final Class<T> serviceType, final long timeoutInMillis) throws NoSuchServiceException {
        LOG.info("Look up service [" + serviceType.getName() + "], timeout in " + timeoutInMillis + " millis");
        final ServiceReference ref = m_bundleContext.getServiceReference(serviceType.getName());
        if (ref != null) {
            final Object service = m_bundleContext.getService(ref);
            if (service == null) {
                throw new NoSuchServiceException(serviceType);
            }
            return (T) service;
        } else {
            throw new NoSuchServiceException(serviceType);
        }
    }

    /**
     * Starts a bundle.
     *
     * @param bundle bundle to be started
     *
     * @throws BundleException - If bundle cannot be started
     */
    private void startBundle(final Bundle bundle) throws BundleException {
        // Don't start if bundle already active
        int bundleState = bundle.getState();
        if (bundleState == Bundle.ACTIVE) {
            return;
        }

        // Don't start if bundle is a fragment bundle
        Dictionary bundleHeaders = bundle.getHeaders();
        if (bundleHeaders.get(Constants.FRAGMENT_HOST) != null) {
            return;
        }

        // Start bundle
        bundle.start();

        bundleState = bundle.getState();
        if (bundleState != Bundle.ACTIVE) {
            long bundleId = bundle.getBundleId();
            String bundleName = bundle.getSymbolicName();
            String bundleStateStr = bundleStateToString(bundleState);
            throw new BundleException(
                    "Bundle (" + bundleId + ", " + bundleName + ") not started (still " + bundleStateStr + ")");
        }
    }

    /**
     * Coverts a bundle state to its string form.
     *
     * @param bundleState bundle state
     *
     * @return bundle state as string
     */
    private static String bundleStateToString(int bundleState) {
        switch (bundleState) {
        case Bundle.ACTIVE:
            return "active";
        case Bundle.INSTALLED:
            return "installed";
        case Bundle.RESOLVED:
            return "resolved";
        case Bundle.STARTING:
            return "starting";
        case Bundle.STOPPING:
            return "stopping";
        case Bundle.UNINSTALLED:
            return "uninstalled";
        default:
            return "unknown (" + bundleState + ")";
        }
    }

}