org.eclipse.gyrex.model.common.provider.BaseModelManager.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.gyrex.model.common.provider.BaseModelManager.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2011 Gunnar Wagenknecht and others.
 * All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html.
 *
 * Contributors:
 *     Gunnar Wagenknecht - initial API and implementation
 *******************************************************************************/
package org.eclipse.gyrex.model.common.provider;

import java.util.Dictionary;
import java.util.Hashtable;

import org.eclipse.gyrex.context.IRuntimeContext;
import org.eclipse.gyrex.context.IRuntimeContextConstants;
import org.eclipse.gyrex.model.common.IModelManager;
import org.eclipse.gyrex.monitoring.metrics.MetricSet;
import org.eclipse.gyrex.persistence.storage.IRepositoryContstants;
import org.eclipse.gyrex.persistence.storage.Repository;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.PlatformObject;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;

import org.apache.commons.lang.StringUtils;

/**
 * Base class for {@link IModelManager model managers}.
 * <p>
 * In addition to the {@link IModelManager} interface it enforces model manager
 * implementors to include central Gyrex concepts (eg., monitoring and metrics).
 * </p>
 * <p>
 * A {@link BaseModelManager} indicates if modifications are supported by the
 * back-end.
 * </p>
 * <p>
 * Clients that want to contribute a model manager implementation must subclass
 * this base class to be backwards compatible.
 * </p>
 * 
 * @see ModelProvider
 * @param <T>
 *            the repository type the manager expects
 */
public abstract class BaseModelManager<T extends Repository> extends PlatformObject implements IModelManager {

    private final IRuntimeContext context;
    private final T repository;

    /** indicates if the service has been closed */
    private volatile boolean closed;

    /** the repository metrics */
    private final MetricSet metrics;

    /** the repository metrics registration */
    private volatile ServiceRegistration metricsRegistration;

    /**
     * Protected constructor typically called by sub classes (through
     * {@link ModelProvider providers}) to provide the context and repository
     * passed through {@link ModelProvider}.
     * <p>
     * Note, each manager is required to provide metrics so that it can be
     * monitored by Gyrex. The metrics will be registered automatically with the
     * platform using the bundle which provides the actual {@link #getClass()
     * class}.
     * </p>
     * 
     * @param context
     *            the context the manager operates in
     * @param repository
     *            the repository the manager must use
     * @param metrics
     *            the manager metrics
     */
    protected BaseModelManager(final IRuntimeContext context, final T repository, final MetricSet metrics) {
        if (null == context) {
            throw new IllegalArgumentException("context must not be null");
        }
        if (null == repository) {
            throw new IllegalArgumentException("repository must not be null");
        }
        if (null == metrics) {
            throw new IllegalArgumentException("metrics must not be null");
        }
        this.context = context;
        this.repository = repository;
        this.metrics = metrics;

        // register metrics
        registerMetrics();
    }

    /**
     * Called by the platform when a model manager is no longer needed and all
     * held resources must be released.
     * <p>
     * The implementation sets the {@link #isClosed() closed} state, calls
     * {@link #doClose()} and unregisters the repository metrics. Subclasses
     * should extend {@link #doClose()} and permanently release any resources.
     * </p>
     * 
     * @noreference This method is not intended to be referenced by clients.
     */
    public final void close() {
        closed = true;
        try {
            doClose();
        } finally {
            metricsRegistration.unregister();
            metricsRegistration = null;
        }
    }

    /**
     * Called by the platform when a model manager is no longer needed and all
     * held resources should be released.
     * <p>
     * The default implementation does nothing. Subclasses may overwrite and
     * extend.
     * </p>
     * 
     * @noreference This method is not intended to be referenced by clients.
     */
    protected void doClose() {
        // empty
    }

    /**
     * Returns an object which is an instance of the given class associated with
     * this object. Returns <code>null</code> if no such object can be found.
     * <p>
     * This implementation of the method declared by <code>IAdaptable</code>
     * passes the request along to the context and then to theplatform's adapter
     * manager; roughly <code>getContext().getAdapter(adapter)</code> and if the
     * first call returned <code>null</code>
     * <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>.
     * Subclasses may override this method (however, if they do so, they must
     * invoke the method on their superclass to ensure that the context and the
     * Platform's adapter manager are consulted).
     * </p>
     * 
     * @param adapter
     *            the class to adapt to
     * @return the adapted object or <code>null</code>
     * @see IAdaptable#getAdapter(Class)
     */
    @Override
    public Object getAdapter(final Class adapter) {
        // check if already implemented
        if (adapter.isInstance(this)) {
            return this;
        }

        // ask the context first
        final Object contextAdapter = getContext().getAdapter(adapter);
        if (null != contextAdapter) {
            return contextAdapter;
        }

        // fallback to adapter manager
        return super.getAdapter(adapter);
    }

    /* (non-Javadoc)
     * @see org.eclipse.gyrex.model.common.IModelManager#getContext()
     */
    @Override
    public final IRuntimeContext getContext() {
        return context;
    }

    /**
     * Returns the metrics of the service.
     * 
     * @return the metrics
     */
    protected final MetricSet getMetrics() {
        return metrics;
    }

    /**
     * Returns the repository the manager must use.
     * 
     * @return the repository
     */
    protected final T getRepository() {
        return repository;
    }

    /**
     * Indicates if this service object has been closed.
     * <p>
     * This method is guaranteed to return <code>true</code> only when it is
     * called after the method {@link #close()} has been called.
     * </p>
     * 
     * @return <code>true</code> if the repository is closed; <code>false</code>
     *         otherwise
     */
    public final boolean isClosed() {
        return closed;
    }

    /**
     * Registers the metrics on behalf of the bundle which loaded this class.
     * 
     * @throws IllegalArgumentException
     *             if the class was not loaded by a bundle class loader
     * @throws IllegalStateException
     *             if the bundle which loaded the class has no valid bundle
     *             context
     */
    private void registerMetrics() throws IllegalArgumentException, IllegalStateException {
        // get bundle context
        // TODO: we might need to wrap this into a privileged call
        final Bundle bundle = FrameworkUtil.getBundle(getClass());
        final BundleContext bundleContext = null != bundle ? bundle.getBundleContext() : null;
        if (null == bundleContext) {
            throw new IllegalStateException("Unable to determin bundle context for class '" + getClass().getName()
                    + "'. Please ensure that this class was loaded by a bundle which is either STARTING, ACTIVE or STOPPING.");
        }

        // create properties
        final Dictionary<String, Object> properties = new Hashtable<String, Object>(2);
        properties.put(Constants.SERVICE_VENDOR, this.getClass().getName());
        properties.put(Constants.SERVICE_DESCRIPTION,
                "Metrics for model manager implementation '" + this.getClass().getName() + "'.");
        properties.put(IRepositoryContstants.SERVICE_PROPERTY_REPOSITORY_ID, getRepository().getRepositoryId());
        if (StringUtils.isNotBlank(getRepository().getDescription())) {
            properties.put(IRepositoryContstants.SERVICE_PROPERTY_REPOSITORY_DESCRIPTION,
                    getRepository().getDescription());
        }
        properties.put(IRuntimeContextConstants.SERVICE_PROPERTY_CONTEXT_PATH,
                getContext().getContextPath().toString());

        // register service
        metricsRegistration = bundleContext.registerService(MetricSet.class.getName(), metrics, properties);
    }
}