Package org.apache.aries.blueprint.container

Source Code of org.apache.aries.blueprint.container.ReferenceRecipe$ServiceDispatcher

/*
* 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.aries.blueprint.container;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;

import org.apache.aries.blueprint.ExtendedReferenceMetadata;
import org.apache.aries.blueprint.di.CollectionRecipe;
import org.apache.aries.blueprint.di.Recipe;
import org.apache.aries.blueprint.di.ValueRecipe;
import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
import org.osgi.framework.ServiceReference;
import org.osgi.service.blueprint.container.BlueprintEvent;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
import org.osgi.service.blueprint.container.ReifiedType;
import org.osgi.service.blueprint.container.ServiceUnavailableException;
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
import org.osgi.service.blueprint.reflect.ServiceReferenceMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A recipe to create an unary OSGi service reference.
*
* TODO: check synchronization / thread safety
*
* TODO: looks there is a potential problem if the service is unregistered between a call
*        to ServiceDispatcher#loadObject() and when the actual invocation finish
*
* @version $Rev: 1509205 $, $Date: 2013-08-01 08:34:18 -0400 (Thu, 01 Aug 2013) $
*/
public class ReferenceRecipe extends AbstractServiceReferenceRecipe {

    private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceRecipe.class);

    private final ReferenceMetadata metadata;
    private Object proxy;

    private final Object monitor = new Object();
    private volatile ServiceReference trackedServiceReference;
    private volatile Object trackedService;
    private Object defaultBean;

    private final Collection<Class<?>> proxyChildBeanClasses;
    private final Collection<WeakReference<Voidable>> proxiedChildren;
   
    public ReferenceRecipe(String name,
                           ExtendedBlueprintContainer blueprintContainer,
                           ReferenceMetadata metadata,
                           ValueRecipe filterRecipe,
                           CollectionRecipe listenersRecipe,
                           List<Recipe> explicitDependencies) {
        super(name, blueprintContainer, metadata, filterRecipe, listenersRecipe, explicitDependencies);
        this.metadata = metadata;
        if(metadata instanceof ExtendedReferenceMetadata)
            proxyChildBeanClasses = ((ExtendedReferenceMetadata) metadata).getProxyChildBeanClasses();
        else
            proxyChildBeanClasses = null;
       
        if (proxyChildBeanClasses != null)
            proxiedChildren = new ArrayList<WeakReference<Voidable>>();
        else
            proxiedChildren = null;
    }

    @Override
    protected Object internalCreate() throws ComponentDefinitionException {
        try {
            if (explicitDependencies != null) {
                for (Recipe recipe : explicitDependencies) {
                    recipe.create();
                }
            }
            // Create the proxy
            Set<Class<?>> interfaces = new HashSet<Class<?>>();
            Class<?> clz = getInterfaceClass();
            if (clz != null) interfaces.add(clz);

            proxy = createProxy(new ServiceDispatcher(), interfaces);

            // Add partially created proxy to the context
            ServiceProxyWrapper wrapper = new ServiceProxyWrapper();

            addPartialObject(wrapper);

            // Handle initial references
            createListeners();
            updateListeners();           

            // Return a ServiceProxy that can injection of references or proxies can be done correctly
            return wrapper;
        } catch (ComponentDefinitionException e) {
            throw e;
        } catch (Throwable t) {
            throw new ComponentDefinitionException(t);
        }
    }

    protected void doStop() {
        synchronized (monitor) {
            unbind();
            monitor.notifyAll();
        }
    }

    protected void retrack() {
        ServiceReference ref = getBestServiceReference();
        if (ref != null) {
            bind(ref);
        } else {
            unbind();
        }
    }

    protected void track(ServiceReference ref) {
        // TODO: make this behavior configurable through a custom attribute
        // TODO:      policy = sticky | replace
        synchronized (monitor) {
            if (trackedServiceReference == null) {
                retrack();
            }
        }
    }

    protected void untrack(ServiceReference ref) {
        // TODO: make this behavior configurable through a custom attribute
        // TODO:      policy = sticky | replace
        synchronized (monitor) {
            if (trackedServiceReference == ref) {
                retrack();
            }
        }
    }

    private void bind(ServiceReference ref) {
        LOGGER.debug("Binding reference {} to {}", getName(), ref);
        synchronized (monitor) {
            ServiceReference oldReference = trackedServiceReference;
            trackedServiceReference = ref;
            voidProxiedChildren();
            bind(trackedServiceReference, proxy);
            if (ref != oldReference) {
              if (oldReference != null && trackedService != null) {
                try {
                  blueprintContainer.getBundleContext().ungetService(oldReference);
                } catch (IllegalStateException ise) {
                  // In case the service no longer exists lets just cope and ignore.
                }
              }
              trackedService = null;
            }
            monitor.notifyAll();
        }
    }

    private void unbind() {
        LOGGER.debug("Unbinding reference {}", getName());
        synchronized (monitor) {
            if (trackedServiceReference != null) {
                unbind(trackedServiceReference, proxy);
                ServiceReference oldReference = trackedServiceReference;
                trackedServiceReference = null;
                voidProxiedChildren();
                if(trackedService != null){
                  try {
                    getBundleContextForServiceLookup().ungetService(oldReference);
                  } catch (IllegalStateException ise) {
                    // In case the service no longer exists lets just cope and ignore.
                  }
                  trackedService = null;
                }
                monitor.notifyAll();
            }
        }
    }

    private Object getService() throws InterruptedException {
        synchronized (monitor) {
            if (isStarted() && trackedServiceReference == null && metadata.getTimeout() > 0
                    && metadata.getAvailability() == ServiceReferenceMetadata.AVAILABILITY_MANDATORY) {
                //Here we want to get the blueprint bundle itself, so don't use #getBundleContextForServiceLookup()
                blueprintContainer.getEventDispatcher().blueprintEvent(new BlueprintEvent(BlueprintEvent.WAITING, blueprintContainer.getBundleContext().getBundle(), blueprintContainer.getExtenderBundle(), new String[] { getOsgiFilter() }));
                monitor.wait(metadata.getTimeout());
            }
            Object result = null;
            if (trackedServiceReference == null) {
                if (isStarted()) {
                  boolean failed = true;
                  if (metadata.getAvailability() == ReferenceMetadata.AVAILABILITY_OPTIONAL &&
                      metadata instanceof ExtendedReferenceMetadata) {
                     if (defaultBean == null) {
                         String defaultBeanId = ((ExtendedReferenceMetadata)metadata).getDefaultBean();
                         if (defaultBeanId != null) {
                           defaultBean = blueprintContainer.getComponentInstance(defaultBeanId);
                           failed = false;
                         }
                     } else {
                         failed = false;
                     }
                     result = defaultBean;
                  }
                 
                  if (failed) {
                    if (metadata.getAvailability() == ServiceReferenceMetadata.AVAILABILITY_MANDATORY) {
                        LOGGER.info("Timeout expired when waiting for mandatory OSGi service reference {}", getOsgiFilter());
                        throw new ServiceUnavailableException("Timeout expired when waiting for mandatory OSGi service reference: " + getOsgiFilter(), getOsgiFilter());
                    } else {
                        LOGGER.info("No matching service for optional OSGi service reference {}", getOsgiFilter());
                        throw new ServiceUnavailableException("No matching service for optional OSGi service reference: " + getOsgiFilter(), getOsgiFilter());
                    }
                  }
                } else {
                    throw new ServiceUnavailableException("The Blueprint container is being or has been destroyed: " + getOsgiFilter(), getOsgiFilter());
                }
            } else {
           
              if (trackedService == null) {
                trackedService = getServiceSecurely(trackedServiceReference);
              }
             
              if (trackedService == null) {
                  throw new IllegalStateException("getService() returned null for " + trackedServiceReference);
              }
             
              result = trackedService;
            }
            return result;
        }
    }

    private ServiceReference getServiceReference() throws InterruptedException {
        synchronized (monitor) {
            if (!optional) {
                getService();
            }
            return trackedServiceReference;
        }
    }
   
    private void voidProxiedChildren() {
        if(proxyChildBeanClasses != null) {
            synchronized(proxiedChildren) {
                for(Iterator<WeakReference<Voidable>> it = proxiedChildren.iterator(); it.hasNext();) {
                    Voidable v = it.next().get();
                    if(v == null)
                        it.remove();
                    else
                      v.voidReference();
                }
            }
        }
    }
   
    public void addVoidableChild(Voidable v) {
        if(proxyChildBeanClasses != null) {
            synchronized (proxiedChildren) {
                proxiedChildren.add(new WeakReference<Voidable>(v));
            }
        } else {
            throw new IllegalStateException("Proxying of child beans is disabled for this recipe");
        }
    }
   
    public Collection<Class<?>> getProxyChildBeanClasses() {
        return proxyChildBeanClasses;
    }

    public class ServiceDispatcher implements Callable<Object> {

        public Object call() throws Exception {
            return getService();
        }

    }

    public class ServiceProxyWrapper implements AggregateConverter.Convertible {

        public Object convert(ReifiedType type) throws Exception {
            if (type.getRawClass() == ServiceReference.class) {
                return getServiceReference();
            } else if (type.getRawClass().isInstance(proxy)) {
                return proxy;
            } else {
                throw new ComponentDefinitionException("Unable to convert to " + type);
            }
        }

    }

}
TOP

Related Classes of org.apache.aries.blueprint.container.ReferenceRecipe$ServiceDispatcher

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.