All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xbean.kernel.standard.ServiceManagerRegistry Maven / Gradle / Ivy

The newest version!
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.xbean.kernel.standard;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.xbean.kernel.IllegalServiceStateException;
import org.apache.xbean.kernel.KernelErrorsError;
import org.apache.xbean.kernel.KernelOperationInterruptedException;
import org.apache.xbean.kernel.ServiceAlreadyExistsException;
import org.apache.xbean.kernel.ServiceFactory;
import org.apache.xbean.kernel.ServiceName;
import org.apache.xbean.kernel.ServiceNotFoundException;
import org.apache.xbean.kernel.ServiceRegistrationException;
import org.apache.xbean.kernel.StopStrategies;
import org.apache.xbean.kernel.StopStrategy;
import org.apache.xbean.kernel.UnsatisfiedConditionsException;

/**
 * The StandardServiceRegistry manages the registration of ServiceManagers for the kernel.
 *
 * @author Dain Sundstrom
 * @version $Id$
 * @since 2.0
 */
public class ServiceManagerRegistry {
    /**
     * The sequence used for the serviceId assigned to service managers.
     */
    private final AtomicLong serviceId = new AtomicLong(1);

    /**
     * The factory used to create service managers.
     */
    private final ServiceManagerFactory serviceManagerFactory;

    /**
     * The registered service managers.
     */
    private final Map serviceManagers = new HashMap();

    /**
     * The service managers indexed by the service type.  This map is populated when a service enters the running state.
     */
    private final Map serviceManagersByType = new HashMap();

    /**
     * Creates a ServiceManagerRegistry that uses the specified service manager factory to create new service managers.
     *
     * @param serviceManagerFactory the factory for new service managers
     */
    public ServiceManagerRegistry(ServiceManagerFactory serviceManagerFactory) {
        this.serviceManagerFactory = serviceManagerFactory;
    }

    /**
     * Stops and destroys all services service managers.  This method will FORCE stop the services if necessary.
     *
     * @throws KernelErrorsError if any errors occur while stopping or destroying the service managers
     */
    public void destroy() throws KernelErrorsError {
        // we gather all errors that occur during shutdown and throw them as on huge exception
        List errors = new ArrayList();

        List managerFutures;
        synchronized (serviceManagers) {
            managerFutures = new ArrayList(serviceManagers.values());
            serviceManagers.clear();

        }

        List managers = new ArrayList(managerFutures.size());
        for (Iterator iterator = managerFutures.iterator(); iterator.hasNext();) {
            RegistryFutureTask registryFutureTask = (RegistryFutureTask) iterator.next();
            try {
                managers.add(registryFutureTask.get());
            } catch (InterruptedException e) {
                // ignore -- this should not happen
                errors.add(new AssertionError(e));
            } catch (ExecutionException e) {
                // good -- one less manager to deal with
            }
        }

        // Be nice and try to stop asynchronously
        errors.addAll(stopAll(managers, StopStrategies.ASYNCHRONOUS));

        // Be really nice and try to stop asynchronously again
        errors.addAll(stopAll(managers, StopStrategies.ASYNCHRONOUS));

        // We have been nice enough now nuke them
        errors.addAll(stopAll(managers, StopStrategies.FORCE));

        // All managers are gaurenteed to be destroyed now
        for (Iterator iterator = managers.iterator(); iterator.hasNext();) {
            ServiceManager serviceManager = (ServiceManager) iterator.next();
            try {
                serviceManager.destroy(StopStrategies.FORCE);
            } catch (UnsatisfiedConditionsException e) {
                // this should not happen, because we force stopped
                errors.add(new AssertionError(e));
            } catch (IllegalServiceStateException e) {
                // this should not happen, because we force stopped
                errors.add(new AssertionError(e));
            } catch (RuntimeException e) {
                errors.add(new AssertionError(e));
            } catch (Error e) {
                errors.add(new AssertionError(e));
            }
        }

        if (!errors.isEmpty()) {
            throw new KernelErrorsError(errors);
        }
    }

    private List stopAll(List managers, StopStrategy stopStrategy) {
        List errors = new ArrayList();
        for (Iterator iterator = managers.iterator(); iterator.hasNext();) {
            ServiceManager serviceManager = (ServiceManager) iterator.next();
            try {
                serviceManager.stop(stopStrategy);
            } catch (UnsatisfiedConditionsException e) {
                // this should not happen in with an asynchronous strategy
                errors.add(new AssertionError(e));
            } catch (RuntimeException e) {
                errors.add(new AssertionError(e));
            } catch (Error e) {
                errors.add(new AssertionError(e));
            }
        }
        return errors;
    }

    /**
     * Determines if there is a service registered under the specified name.
     *
     * @param serviceName the unique name of the service
     * @return true if there is a service registered with the specified name; false otherwise
     */
    public boolean isRegistered(ServiceName serviceName) {
        if (serviceName == null) throw new NullPointerException("serviceName is null");

        RegistryFutureTask registryFutureTask;
        synchronized (serviceManagers) {
            registryFutureTask = (RegistryFutureTask) serviceManagers.get(serviceName);
        }
        try {
            // the service is registered if we have a non-null future value
            return registryFutureTask != null && registryFutureTask.get() != null;
        } catch (InterruptedException e) {
            throw new KernelOperationInterruptedException(e, serviceName, "isRegistered");
        } catch (ExecutionException e) {
            return false;
        }
    }

    /**
     * Gets the service manager registered under the specified name.
     *
     * @param serviceName the unique name of the service
     * @return the ServiceManager
     * @throws ServiceNotFoundException if there is no service registered under the specified name
     */
    public ServiceManager getServiceManager(ServiceName serviceName) throws ServiceNotFoundException {
        if (serviceName == null) throw new NullPointerException("serviceName is null");

        RegistryFutureTask registryFutureTask;
        synchronized (serviceManagers) {
            registryFutureTask = (RegistryFutureTask) serviceManagers.get(serviceName);
        }

        // this service has no future
        if (registryFutureTask == null) {
            throw new ServiceNotFoundException(serviceName);
        }

        try {
            ServiceManager serviceManager = (ServiceManager) registryFutureTask.get();
            if (serviceManager == null) {
                throw new ServiceNotFoundException(serviceName);
            }
            return serviceManager;
        } catch (InterruptedException e) {
            throw new KernelOperationInterruptedException(e, serviceName, "getServiceManager");
        } catch (ExecutionException e) {
            // registration threw an exception which means it didn't register
            throw new ServiceNotFoundException(serviceName);
        }
    }

    /**
     * Gets the first registered service manager that creates an instance of the specified type, or null if no service
     * managers create an instance of the specified type.
     *
     * @param type the of the desired service
     * @return the first registered service manager that creates an instance of the specified type, or null if none found
     */
    public ServiceManager getServiceManager(Class type) {
        SortedSet serviceManagerFutures = getServiceManagerFutures(type);
        for (Iterator iterator = serviceManagerFutures.iterator(); iterator.hasNext();) {
            RegistryFutureTask registryFutureTask = (RegistryFutureTask) iterator.next();
            try {
                ServiceManager serviceManager = (ServiceManager) registryFutureTask.get();
                if (serviceManager != null) {
                    return serviceManager;
                }
            } catch (InterruptedException e) {
                throw new KernelOperationInterruptedException(e, registryFutureTask.getServiceName(), "getServiceManagers(java.lang.Class)");
            } catch (ExecutionException ignored) {
                // registration threw an exception which means it didn't register
            }
        }
        return null;
    }

    /**
     * Gets all service managers that create an instances of the specified type, or an empty list if no service
     * managers create an instance of the specified type.
     *
     * @param type the of the desired service managers
     * @return all service managers that create an instances of the specified type, or an empty list if none found
     */
    public List getServiceManagers(Class type) {
        SortedSet serviceManagerFutures = getServiceManagerFutures(type);
        List serviceManagers = new ArrayList(serviceManagerFutures.size());
        for (Iterator iterator = serviceManagerFutures.iterator(); iterator.hasNext();) {
            RegistryFutureTask registryFutureTask = (RegistryFutureTask) iterator.next();
            try {
                ServiceManager serviceManager = (ServiceManager) registryFutureTask.get();
                if (serviceManager != null) {
                    serviceManagers.add(serviceManager);
                }
            } catch (InterruptedException e) {
                throw new KernelOperationInterruptedException(e, registryFutureTask.getServiceName(), "getServiceManagers(java.lang.Class)");
            } catch (ExecutionException ignored) {
                // registration threw an exception which means it didn't register
            }
        }
        return serviceManagers;
    }

    /**
     * Gets the first registed and running service that is an instance of the specified type, or null if no instances
     * of the specified type are running.
     *
     * @param type the of the desired service
     * @return the first registed and running service that is an instance of the specified type or null if none found
     */
    public synchronized Object getService(Class type) {
        SortedSet serviceManagerFutures = getServiceManagerFutures(type);
        for (Iterator iterator = serviceManagerFutures.iterator(); iterator.hasNext();) {
            RegistryFutureTask registryFutureTask = (RegistryFutureTask) iterator.next();
            try {
                ServiceManager serviceManager = (ServiceManager) registryFutureTask.get();
                if (serviceManager != null) {
                    Object service = serviceManager.getService();
                    if (service != null) {
                        return service;
                    }
                }
            } catch (InterruptedException e) {
                throw new KernelOperationInterruptedException(e, registryFutureTask.getServiceName(), "getService(java.lang.Class)");
            } catch (ExecutionException ignored) {
                // registration threw an exception which means it didn't register
            }
        }
        return null;
    }

    /**
     * Gets the all of running service that are an instances of the specified type, or an empty list if no instances
     * of the specified type are running.
     *
     * @param type the of the desired service
     * @return the all of running service that are an instances of the specified type, or an empty list if none found
     */
    public synchronized List getServices(Class type) {
        List serviceManagers = getServiceManagers(type);
        List services = new ArrayList(serviceManagers.size());
        for (Iterator iterator = serviceManagers.iterator(); iterator.hasNext();) {
            ServiceManager serviceManager = (ServiceManager) iterator.next();
            if (serviceManager != null) {
                Object service = serviceManager.getService();
                if (service != null) {
                    services.add(service);
                }
            }
        }
        return services;
    }

    private SortedSet getServiceManagerFutures(Class type) {
        SortedSet serviceManagerFutures;
        synchronized (serviceManagers) {
            serviceManagerFutures = (SortedSet) serviceManagersByType.get(type);
            if (serviceManagerFutures != null) {
                serviceManagerFutures = new TreeSet(serviceManagerFutures);
            } else {
                serviceManagerFutures = new TreeSet();
            }
        }
        return serviceManagerFutures;
    }

    /**
     * Creates a ServiceManager and registers it under the specified name.  If the service is restartable, it will
     * enter the server in the STOPPED state.  If a service is not restartable, the service manager will assure that all
     * dependencies are satisfied and service will immediately enter in the  RUNNING state.  If a
     * dependency for a non-restartable service is not immediately satisfiable, this method will throw a
     * ServiceRegistrationException.
     *
     * @param serviceName the unique name of the service
     * @param serviceFactory the factory used to create the service
     * @throws ServiceAlreadyExistsException if service is already registered with the specified name
     * @throws ServiceRegistrationException if the service is not restartable and an error occured while starting the service
     */
    public void registerService(ServiceName serviceName, ServiceFactory serviceFactory) throws ServiceAlreadyExistsException, ServiceRegistrationException {
        if (serviceName == null) throw new NullPointerException("serviceName is null");
        if (serviceFactory == null) throw new NullPointerException("serviceFactory is null");

        if (!serviceFactory.isEnabled()) {
            throw new ServiceRegistrationException(serviceName,
                    new IllegalServiceStateException("A disabled non-restartable service factory can not be registered", serviceName));
        }

        RegistryFutureTask registrationTask = null;

        //
        // This loop will continue until we put our registrationTask in the serviceManagers map.  If at any point,
        // we discover that there is already a service registered under the specified service name, we will throw
        // a ServiceAlreadyExistsException exiting this method.
        //
        while (registrationTask == null) {
            RegistryFutureTask existingRegistration;
            synchronized (serviceManagers) {
                existingRegistration = (RegistryFutureTask) serviceManagers.get(serviceName);

                // if we do not have an existing registration or the existing registration task is complete
                // we can create the new registration task; otherwise we need to wait for the existing registration to
                // finish out side of the synchronized lock on serviceManagers.
                if (existingRegistration == null || existingRegistration.isDone()) {
                    // if we have a valid existing registration, throw a ServiceAlreadyExistsException
                    if (existingRegistration != null) {
                        try {
                            boolean alreadyRegistered = (existingRegistration.get() != null);
                            if (alreadyRegistered) {
                                throw new ServiceAlreadyExistsException(serviceName);
                            }
                        } catch (InterruptedException e) {
                            throw new KernelOperationInterruptedException(e, serviceName, "registerService");
                        } catch (ExecutionException e) {
                            // the previous registration threw an exception.. we can continure as normal
                        }
                    }

                    // we are ready to register our serviceManager
                    existingRegistration = null;
                    ServiceManager serviceManager = serviceManagerFactory.createServiceManager(serviceId.getAndIncrement(),
                            serviceName,
                            serviceFactory);
                    registrationTask = RegistryFutureTask.createRegisterTask(serviceManager);
                    serviceManagers.put(serviceName, registrationTask);
                    addTypeIndex(serviceManager, registrationTask);
                }
            }

            // If there is an unfinished exiting registration task, wait until it is done executing
            if (existingRegistration != null) {
                try {
                    existingRegistration.get();
                    // we don't throw an error here because we want to check in the synchronized block that this
                    // future is still registered in the serviceManagers map
                } catch (InterruptedException e) {
                    throw new KernelOperationInterruptedException(e, serviceName, "registerService");
                } catch (ExecutionException e) {
                    // good
                }
            }
        }

        // run our registration task and check the results
        registrationTask.run();
        try {
            // if initialization completed successfully, this method will not throw an exception
            registrationTask.get();
        } catch (InterruptedException e) {
            throw new KernelOperationInterruptedException(e, serviceName, "registerService");
        } catch (ExecutionException e) {
            // registration failed, remove our task
            synchronized (serviceManagers) {
                // make sure our task is still the registered one
                if (serviceManagers.get(serviceName) == registrationTask) {
                    serviceManagers.remove(serviceName);
                    removeTypeIndex(registrationTask);
                }
            }
            throw new ServiceRegistrationException(serviceName, e.getCause());
        }
    }

    /**
     * Stops and destorys the ServiceManager and then unregisters it.  The ServiceManagerRegistry will attempt to stop
     * the service using the specified stop strategy, but if the service can not  be stopped a
     * ServiceRegistrationException will be thrown containing either an UnsatisfiedConditionsException or an
     * IllegalServiceStateException.
     *
     * @param serviceName the unique name of the service
     * @param stopStrategy the strategy that determines how unsatisfied conditions are handled
     * @throws ServiceNotFoundException if there is no service registered under the specified name
     * @throws ServiceRegistrationException if the service could not be stopped
     */
    public void unregisterService(ServiceName serviceName, StopStrategy stopStrategy) throws ServiceNotFoundException, ServiceRegistrationException {
        if (serviceName == null) throw new NullPointerException("serviceName is null");
        if (stopStrategy == null) throw new NullPointerException("stopStrategy is null");

        RegistryFutureTask unregistrationTask = null;

        //
        // This loop will continue until we put our unregistrationTask in the serviceManagers map.  If at any point,
        // we discover that there actually is not a service registered under the specified service name, we will throw
        // a ServiceNotFoundException exiting this method.
        //
        while (unregistrationTask == null) {
            RegistryFutureTask existingRegistration;
            synchronized (serviceManagers) {
                existingRegistration = (RegistryFutureTask) serviceManagers.get(serviceName);
                if (existingRegistration == null) {
                    throw new ServiceNotFoundException(serviceName);
                }

                // if existing registration is done running, we can destroy it
                if (existingRegistration.isDone()) {
                    ServiceManager serviceManager = null;
                    try {
                        serviceManager = (ServiceManager) existingRegistration.get();
                    } catch (InterruptedException e) {
                        throw new KernelOperationInterruptedException(e, serviceName, "unregisterService");
                    } catch (ExecutionException e) {
                        // good
                    }

                    // if there isn't a registered manager that is an exception
                    if (serviceManager == null) {
                        throw new ServiceNotFoundException(serviceName);
                    }

                    // we are ready to register our serviceManager
                    existingRegistration = null;
                    unregistrationTask = RegistryFutureTask.createUnregisterTask(serviceManager, stopStrategy);
                    serviceManagers.put(serviceName, unregistrationTask);
                    addTypeIndex(serviceManager, unregistrationTask);
                }
            }


            // If there is an unfinished exiting registration task, wait until it is done executing
            if (existingRegistration != null) {
                try {
                    existingRegistration.get();
                    // we don't throw an error here because we want to check in the synchronized block that this
                    // future is still registered in the serviceManagers map
                } catch (InterruptedException e) {
                    throw new KernelOperationInterruptedException(e, serviceName, "unregisterService");
                } catch (ExecutionException e) {
                    // good
                }
            }
        }

        unregistrationTask.run();
        try {
            // if get returns any value other then null, the unregistration failed
            if (unregistrationTask.get() == null) {
                // unregistration was successful, remove the furuture object
                synchronized (serviceManagers) {
                    // make sure our task is still the registered one
                    if (serviceManagers.get(serviceName) == unregistrationTask) {
                        serviceManagers.remove(serviceName);
                        removeTypeIndex(unregistrationTask);
                    }
                }
            } else {
                synchronized (unregistrationTask) {
                    // the root exception is contained in the exception handle
                    throw new ServiceRegistrationException(serviceName, unregistrationTask.getThrowable());
                }
            }
        } catch (InterruptedException e) {
            throw new KernelOperationInterruptedException(e, serviceName, "unregisterService");
        } catch (ExecutionException e) {
            // this won't happen
            throw new AssertionError(e);
        }
    }

    private void addTypeIndex(ServiceManager serviceManager, RegistryFutureTask registryFutureTask) {
        if (serviceManager == null) throw new NullPointerException("serviceManager is null");
        if (registryFutureTask == null) throw new NullPointerException("serviceManagerFuture is null");

        Set allTypes = new LinkedHashSet();
        for (Iterator iterator = serviceManager.getServiceTypes().iterator(); iterator.hasNext();) {
            Class serviceType = (Class) iterator.next();

            if (serviceType.isArray()) {
                throw new IllegalArgumentException("Service is an array: serviceName=" + serviceManager.getServiceName() +
                        ", serviceType=" + serviceManager.getServiceTypes());
            }

            allTypes.add(serviceType);
            allTypes.addAll(getAllSuperClasses(serviceType));
            allTypes.addAll(getAllInterfaces(serviceType));
        }

        synchronized (serviceManagers) {
            for (Iterator iterator = allTypes.iterator(); iterator.hasNext();) {
                Class type = (Class) iterator.next();
                Set futureServiceManagers = (Set) serviceManagersByType.get(type);
                if (futureServiceManagers == null) {
                    futureServiceManagers = new TreeSet();
                    serviceManagersByType.put(type, futureServiceManagers);
                }
                futureServiceManagers.add(registryFutureTask);
            }
        }
    }

    private void removeTypeIndex(RegistryFutureTask registryFutureTask) {
        if (registryFutureTask == null) throw new NullPointerException("serviceManagerFuture is null");
        synchronized (serviceManagers) {
            for (Iterator iterator = serviceManagersByType.entrySet().iterator(); iterator.hasNext();) {
                Map.Entry entry = (Map.Entry) iterator.next();
                Set serviceManagers = (Set) entry.getValue();
                serviceManagers.remove(registryFutureTask);
                if (serviceManagers.isEmpty()) {
                    iterator.remove();
                }
            }
        }
    }

    private static Set getAllSuperClasses(Class clazz) {
        Set allSuperClasses = new LinkedHashSet();
        for (Class superClass = clazz.getSuperclass(); superClass != null; superClass = superClass.getSuperclass()) {
            allSuperClasses.add(superClass);
        }
        return allSuperClasses;
    }

    private static Set getAllInterfaces(Class clazz) {
        Set allInterfaces = new LinkedHashSet();
        LinkedList stack = new LinkedList();
        stack.addAll(Arrays.asList(clazz.getInterfaces()));
        while (!stack.isEmpty()) {
            Class intf = (Class) stack.removeFirst();
            if (!allInterfaces.contains(intf)) {
                allInterfaces.add(intf);
                stack.addAll(Arrays.asList(intf.getInterfaces()));
            }
        }
        return allInterfaces;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy