/* * 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.felix.ipojo.handler.temporal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.osgi.framework.ServiceReference; /** * Maintains a service object collection. * This collection wrap the temporal dependency to be accessible from a * {@link Collection}, that can be passed to helper objects (Collaborators). * * The onTimeout policies are executed when the {@link Collection#iterator()}, * {@link Collection#toArray(Object[])} and {@link Collection#toArray()} methods * are called. * * The {@link Collection#iterator()} method returns an {@link Iterator} iterating * on a cached copy of available service objects. In the case that there are no * available services when the timeout is reached, the policies act as follows: * <ul> * <li>'null' returns a null iterator</li> * <li>'nullable' and default-implementation returns an iterator iterating on one object (the * nullable or default-implementation object</li> * <li>'empty' returns an empty iterator.</li> * <li>'no policy' throws runtime exception</li> * </ul> * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class ServiceCollection implements Collection { /** * The wrapped temporal dependencies. */ private TemporalDependency m_dependency; /** * Creates a Service Collection. * @param dep the wrapped temporal dependencies */ public ServiceCollection(TemporalDependency dep) { m_dependency = dep; } /** * Unsupported method. * @param o an object * @return N/A * @see java.util.Collection#add(java.lang.Object) */ public boolean add(Object o) { throw new UnsupportedOperationException("Cannot add elements inside this collection"); } /** * Unsupported method. * @param c an object * @return N/A * @see java.util.Collection#addAll(java.util.Collection) */ public boolean addAll(Collection c) { throw new UnsupportedOperationException("Cannot add elements inside this collection"); } /** * Unsupported method. * @see java.util.Collection#clear() */ public void clear() { throw new UnsupportedOperationException("Cannot remove elements from this collection"); } /** * Checks if the wrapped temporal dependencies has always access to the * given service object.The method allows knowing if the provider returning the * service object has leaved. * @param o the service object * @return <code>true</code> if the object is still available, * <code>false</code> otherwise. * @see java.util.Collection#contains(java.lang.Object) */ public boolean contains(Object o) { return getAvailableObjects().contains(o); } /** * Checks if the wrapped temporal dependencies has always access to the * given service objects.The method allows knowing if providers returning the * service objects have leaved. * @param c the set of service object * @return <code>true</code> if the objects are still available, * <code>false</code> otherwise. * @see java.util.Collection#contains(java.lang.Object) */ public boolean containsAll(Collection c) { return getAvailableObjects().containsAll(c); } /** * Checks if at least one provider matching with the dependency * is available. * @return <code>true</code> if one provider or more satisfying the * dependency are available. Otherwise, returns <code>false</code> * @see java.util.Collection#isEmpty() */ public boolean isEmpty() { return m_dependency.getSize() == 0; } /** * Helper method creating a list of available service objects. * @return the list of available service objects. */ private List getAvailableObjects() { List list = new ArrayList(); ServiceReference[] refs = m_dependency.getServiceReferences(); if (refs != null) { for (int i = 0; i < refs.length; i++) { list.add(m_dependency.getService(refs[i])); } } return list; } /** * Gets an iterator on the actual list of available service objects. * This method applies on timeout policies is no services are * available after the timeout. * The returned iterator iterates on a cached copy of the service * objects. * @return a iterator giving access to service objects. * @see java.util.Collection#iterator() */ public Iterator iterator() { ServiceReference[] refs = m_dependency.getServiceReferences(); if (refs != null) { // Immediate return. return new ServiceIterator(refs); // Create the service iterator with the service reference list. } else { // Begin to wait ... long enter = System.currentTimeMillis(); boolean exhausted = false; synchronized (this) { while (m_dependency.getServiceReference() == null && !exhausted) { try { wait(1); } catch (InterruptedException e) { // We was interrupted .... } finally { long end = System.currentTimeMillis(); exhausted = (end - enter) > m_dependency.getTimeout(); } } } // Check if (exhausted) { Object oto = m_dependency.onTimeout(); // Throws the RuntimeException if (oto == null) { // If null, return null return null; } else { // oto is an instance of collection containing either empty or with only one element return new ServiceIterator((Collection) oto); } } else { refs = m_dependency.getServiceReferences(); return new ServiceIterator(refs); } } } /** * Unsupported method. * @param o a object * @return N/A * @see java.util.Collection#remove(java.lang.Object) */ public boolean remove(Object o) { throw new UnsupportedOperationException("Cannot remove elements from this collection"); } /** * Unsupported method. * @param c a set of objects * @return N/A * @see java.util.Collection#removeAll(java.util.Collection) */ public boolean removeAll(Collection c) { throw new UnsupportedOperationException("Cannot remove elements from this collection"); } /** *Unsupported method. * @param c a set of objects * @return N/A * @see java.util.Collection#retainAll(java.util.Collection) */ public boolean retainAll(Collection c) { throw new UnsupportedOperationException("Cannot remove elements from this collection"); } /** * Gets the number of available providers. * @return the number of matching service providers. * @see java.util.Collection#size() */ public int size() { return m_dependency.getSize(); } /** * Returns an array containing available service objects. * This method executed on timeout policies if no matching * providers when the timeout is reached. * @return a array containing available service objects. * depending on the timeout policy, this array can also be <code>null</code>, * be empty, or can contain only one element (a default-implementation * object, or a nullable object). * @see java.util.Collection#toArray() */ public Object[] toArray() { return toArray(new Object[0]); } /** * Returns an array containing available service objects. * This method executed on timeout policies if no matching * providers when the timeout is reached. * @param a the array into which the elements of this collection * are to be stored, if it is big enough; otherwise, a new array * of the same runtime type is allocated for this purpose. * @return a array containing available service objects. * depending on the timeout policy, this array can also be <code>null</code>, * be empty, or can contain only one element (a default-implementation * object, or a nullable object). * @see java.util.Collection#toArray(java.lang.Object[]) */ public Object[] toArray(Object[] a) { Iterator it = iterator(); // Can throw an exception. if (it == null) { return null; } // Else we get an iterator. List list = new ArrayList(size()); while (it.hasNext()) { list.add(it.next()); } return list.toArray(a); } /** * Iterator on a set of service objects. * This iterator iterates on a cached copy of service objects. */ private final class ServiceIterator implements Iterator { /** * Underlying iterator. */ private Iterator m_iterator; /** * Creates a Service Iterator iterating * on the given set of providers. * @param refs the available service providers */ private ServiceIterator(ServiceReference[] refs) { List objects = new ArrayList(refs.length); for (int i = 0; i < refs.length; i++) { objects.add(m_dependency.getService(refs[i])); } m_iterator = objects.iterator(); } /** * Creates a Service Iterator iterating * on service object contained in the given * collection. * @param col a collection containing service objects. */ private ServiceIterator(Collection col) { m_iterator = col.iterator(); } /** * Returns <code>true</code> if the iteration has * more service objects. * @return <code>true</code> if the iterator has more elements. * @see java.util.Iterator#hasNext() */ public boolean hasNext() { return m_iterator.hasNext(); } /** * Returns the next service objects in the iteration. * @return the next service object in the iteration. * @see java.util.Iterator#next() */ public Object next() { return m_iterator.next(); } /** * Unsupported operation. * @see java.util.Iterator#remove() */ public void remove() { throw new UnsupportedOperationException(); } } }