Package org.jboss.gravia.runtime.embedded.internal

Source Code of org.jboss.gravia.runtime.embedded.internal.RuntimeServicesManager

/*
* #%L
* Gravia :: Runtime :: Embedded
* %%
* Copyright (C) 2013 - 2014 JBoss by Red Hat
* %%
* 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.
* #L%
*/
package org.jboss.gravia.runtime.embedded.internal;

import static org.jboss.gravia.runtime.spi.RuntimeLogger.LOGGER;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;

import org.jboss.gravia.runtime.Filter;
import org.jboss.gravia.runtime.Module;
import org.jboss.gravia.runtime.ModuleContext;
import org.jboss.gravia.runtime.ServiceEvent;
import org.jboss.gravia.runtime.ServiceFactory;
import org.jboss.gravia.runtime.ServiceReference;
import org.jboss.gravia.runtime.spi.AbstractModule;
import org.jboss.gravia.runtime.spi.NoFilter;
import org.jboss.gravia.runtime.spi.RuntimeEventsManager;
import org.osgi.framework.Bundle;

/**
* Manages the services in hte runtime
*
* @author thomas.diesler@jboss.com
* @since 27-Sep-2013
*
* @ThreadSafe
*/
final class RuntimeServicesManager {

    private final RuntimeEventsManager frameworkEvents;
    private final Map<String, List<ServiceState<?>>> serviceMap = new ConcurrentHashMap<String, List<ServiceState<?>>>();
    private final AtomicLong identityGenerator = new AtomicLong();

    RuntimeServicesManager(RuntimeEventsManager frameworkEvents) {
        this.frameworkEvents = frameworkEvents;
    }

    void fireServiceEvent(Module module, int type, ServiceState<?> serviceState) {
        frameworkEvents.fireServiceEvent(module, type, serviceState);
    }

    private long getNextServiceId() {
        return identityGenerator.incrementAndGet();
    }

    /**
     * Registers the specified service object with the specified properties under the specified class names into the Framework.
     * A <code>ServiceRegistration</code> object is returned. The <code>ServiceRegistration</code> object is for the private use
     * of the module registering the service and should not be shared with other modules. The registering module is defined to
     * be the context module.
     *
     * @param classNames The class names under which the service can be located.
     * @param serviceValue The service object or a <code>ServiceFactory</code> object.
     * @param properties The properties for this service.
     * @return A <code>ServiceRegistration</code> object for use by the module registering the service
     */
    @SuppressWarnings({ "rawtypes" })
    ServiceState registerService(ModuleContext context, String[] classNames, final Object serviceValue, Dictionary properties) {
        assert classNames != null && classNames.length > 0 : "Null service classes";

        ServiceState.ValueProvider<Object> valueProvider = new ServiceState.ValueProvider<Object>() {

            @Override
            public boolean isFactoryValue() {
                return serviceValue instanceof ServiceFactory;
            }

            @Override
            public Object getValue() {
                return serviceValue;
            }
        };

        long serviceId = getNextServiceId();
        ServiceState<?> serviceState = new ServiceState<Object>(this, context.getModule(), serviceId, classNames, valueProvider, properties);
        LOGGER.debug("Register service: {}", serviceState);

        for (String className : classNames) {
            List<ServiceState<?>> serviceStates;
            synchronized (serviceMap) {
                serviceStates = serviceMap.get(className);
                if (serviceStates == null) {
                    serviceStates = new CopyOnWriteArrayList<ServiceState<?>>();
                    serviceMap.put(className, serviceStates);
                }
            }
            serviceStates.add(serviceState);
        }
        //module.addRegisteredService(serviceState);

        // This event is synchronously delivered after the service has been registered with the Framework.
        frameworkEvents.fireServiceEvent(context.getModule(), ServiceEvent.REGISTERED, serviceState);

        return serviceState;
    }

    /**
     * Returns a <code>ServiceReference</code> object for a service that implements and was registered under the specified
     * class.
     *
     * @param clazz The class name with which the service was registered.
     * @return A <code>ServiceReference</code> object, or <code>null</code>
     */
    ServiceState<?> getServiceReference(ModuleContext context, String clazz) {
        assert clazz != null : "Null clazz";

        List<ServiceState<?>> result = getServiceReferencesInternal(context, clazz, NoFilter.INSTANCE, true);
        if (result.isEmpty())
            return null;

        int lastIndex = result.size() - 1;
        return result.get(lastIndex);
    }

    /**
     * Returns an array of <code>ServiceReference</code> objects. The returned array of <code>ServiceReference</code> objects
     * contains services that were registered under the specified class, match the specified filter expression.
     *
     * If checkAssignable is true, the packages for the class names under which the services were registered match the context
     * module's packages as defined in {@link ServiceReference#isAssignableTo(Bundle, String)}.
     *
     *
     * @param clazz The class name with which the service was registered or <code>null</code> for all services.
     * @param filterStr The filter expression or <code>null</code> for all services.
     * @return A potentially empty list of <code>ServiceReference</code> objects.
     */
    List<ServiceState<?>> getServiceReferences(ModuleContext context, String clazz, String filterStr, boolean checkAssignable) {
        Filter filter = NoFilter.INSTANCE;
        if (filterStr != null)
            filter = context.createFilter(filterStr);

        List<ServiceState<?>> result = getServiceReferencesInternal(context, clazz, filter, checkAssignable);
        return result;
    }

    private List<ServiceState<?>> getServiceReferencesInternal(final ModuleContext module, String className, Filter filter, boolean checkAssignable) {
        assert module != null : "Null module";
        assert filter != null : "Null filter";

        Set<ServiceState<?>> initialSet = new HashSet<ServiceState<?>>();
        if (className != null) {
            List<ServiceState<?>> list = serviceMap.get(className);
            if (list != null) {
                initialSet.addAll(list);
            }
        } else {
            for (List<ServiceState<?>> list : serviceMap.values()) {
                initialSet.addAll(list);
            }
        }

        if (initialSet.isEmpty())
            return Collections.emptyList();

        Set<ServiceState<?>> resultset = new HashSet<ServiceState<?>>();
        for (ServiceState<?> serviceState : initialSet) {
            if (isMatchingService(module, serviceState, className, filter, checkAssignable)) {
                resultset.add(serviceState);
            }
        }

        // Sort the result
        List<ServiceState<?>> resultList = new ArrayList<ServiceState<?>>(resultset);
        if (resultList.size() > 1)
            Collections.sort(resultList, ServiceReferenceComparator.getInstance());

        return Collections.unmodifiableList(resultList);
    }

    private boolean isMatchingService(ModuleContext context, ServiceState<?> serviceState, String clazzName, Filter filter, boolean checkAssignable) {
        if (serviceState.isUnregistered() || filter.match(serviceState) == false)
            return false;
        if (checkAssignable == false || clazzName == null)
            return true;

        return serviceState.isAssignableTo(context.getModule(), clazzName);
    }

    /**
     * Returns the service object referenced by the specified <code>ServiceReference</code> object.
     *
     * @return A service object for the service associated with <code>reference</code> or <code>null</code>
     */
    <S> S getService(ModuleContext context, ServiceState<S> serviceState) {
        // If the service has been unregistered, null is returned.
        if (serviceState.isUnregistered())
            return null;

        // Add the given service ref to the list of used services
        serviceState.addUsingModule((AbstractModule) context.getModule());

        S value = serviceState.getScopedValue(context.getModule());

        // If the factory returned an invalid value
        // restore the service usage counts
        if (value == null) {
            serviceState.removeUsingModule((AbstractModule) context.getModule());
        }

        return value;
    }

    /**
     * Unregister the given service.
     */
    void unregisterService(ServiceState<?> serviceState) {
        if (serviceState.isUnregistered())
            return;

        LOGGER.debug("Unregister service: {}", serviceState);
        for (String className : serviceState.getClassNames()) {
            try {
                List<ServiceState<?>> serviceStates = serviceMap.get(className);
                if (serviceStates != null) {
                    serviceStates.remove(serviceState);
                }
            } catch (RuntimeException ex) {
                LOGGER.error("Cannot unregister service: " + className, ex);
            }
        }

        Module serviceOwner = serviceState.getServiceOwner();

        // This event is synchronously delivered before the service has completed unregistering.
        frameworkEvents.fireServiceEvent(serviceOwner, ServiceEvent.UNREGISTERING, serviceState);

        // Remove from using modules
        for (AbstractModule module : serviceState.getUsingModulesInternal()) {
            while (ungetService(module, serviceState)) {
            }
        }
    }

    /**
     * Releases the service object referenced by the specified <code>ServiceReference</code> object. If the context module's use
     * count for the service is zero, this method returns <code>false</code>. Otherwise, the context module's use count for the
     * service is decremented by one.
     *
     * @return <code>false</code> if the context module's use count for the service is zero or if the service has been
     *         unregistered; <code>true</code> otherwise.
     */
    boolean ungetService(AbstractModule module, ServiceState<?> serviceState) {
        serviceState.ungetScopedValue(module);
        int useCount = module.removeServiceInUse(serviceState);
        if (useCount == 0) {
            serviceState.removeUsingModule(module);
        }
        return useCount >= 0;
    }
}
TOP

Related Classes of org.jboss.gravia.runtime.embedded.internal.RuntimeServicesManager

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.