blob: 5f11b9286c8a52ca6865817070c3eeabf4cf87b2 [file] [log] [blame]
/*
* 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.scr.impl.helper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceObjects;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentServiceObjects;
/**
* Utility class for handling references using a ComponentServiceObjects
* to get services.
*/
public class ComponentServiceObjectsHelper
{
private final BundleContext bundleContext;
private final ConcurrentMap<ServiceReference<?>, ComponentServiceObjectsImpl> services = new ConcurrentHashMap<ServiceReference<?>, ComponentServiceObjectsImpl>();
private final List<ComponentServiceObjectsImpl> closedServices = new ArrayList<ComponentServiceObjectsImpl>();
private final ConcurrentMap<ServiceReference<?>, Object> prototypeInstances = new ConcurrentHashMap<ServiceReference<?>, Object>();
public ComponentServiceObjectsHelper(final BundleContext bundleContext)
{
this.bundleContext = bundleContext;
}
public void cleanup()
{
Collection<ComponentServiceObjectsImpl> csos = services.values();
services.clear();
for(final ComponentServiceObjectsImpl cso : csos)
{
cso.deactivate();
}
synchronized ( this.closedServices )
{
csos = new ArrayList<ComponentServiceObjectsImpl>(this.closedServices);
this.closedServices.clear();
}
for(final ComponentServiceObjectsImpl cso : csos)
{
cso.deactivate();
}
prototypeInstances.clear();
}
public ComponentServiceObjects getServiceObjects(final ServiceReference<?> ref)
{
ComponentServiceObjectsImpl cso = this.services.get(ref);
if ( cso == null )
{
final ServiceObjects serviceObjects = this.bundleContext.getServiceObjects(ref);
if ( serviceObjects != null )
{
cso = new ComponentServiceObjectsImpl(serviceObjects);
final ComponentServiceObjectsImpl oldCSO = this.services.putIfAbsent(ref, cso);
if ( oldCSO != null )
{
cso = oldCSO;
}
}
}
return cso;
}
public void closeServiceObjects(final ServiceReference<?> ref) {
ComponentServiceObjectsImpl cso = this.services.remove(ref);
if ( cso != null )
{
synchronized ( closedServices )
{
closedServices.add(cso);
}
cso.close();
}
}
public <T> T getPrototypeRefInstance(final ServiceReference<T> ref)
{
T service = (T) prototypeInstances.get(ref);
if ( service == null )
{
service = (T) getServiceObjects(ref).getService();
T oldService = (T)prototypeInstances.putIfAbsent(ref, service);
if ( oldService != null )
{
// another thread created the instance already
getServiceObjects(ref).ungetService(service);
service = oldService;
}
}
return service;
}
private static final class ComponentServiceObjectsImpl implements ComponentServiceObjects
{
private final List<Object> instances = new ArrayList<Object>();
private volatile ServiceObjects serviceObjects;
private volatile boolean deactivated = false;
public ComponentServiceObjectsImpl(final ServiceObjects so)
{
this.serviceObjects = so;
}
public void deactivate()
{
this.deactivated = true;
close();
}
/**
* Close this instance and unget all services.
*/
public void close()
{
final ServiceObjects so = this.serviceObjects;
this.serviceObjects = null;
if ( so != null )
{
final List<Object> localInstances = new ArrayList<Object>();
synchronized ( this.instances )
{
localInstances.addAll(this.instances);
this.instances.clear();
}
for(final Object obj : localInstances)
{
try
{
so.ungetService(obj);
}
catch ( final IllegalStateException ise )
{
// ignore (this happens if the bundle is not valid anymore)
}
catch ( final IllegalArgumentException iae )
{
// ignore (this happens if the service has not been returned by the service objects)
}
}
}
}
public Object getService()
{
if ( this.deactivated )
{
throw new IllegalStateException();
}
final ServiceObjects so = this.serviceObjects;
Object service = null;
if ( so != null )
{
service = so.getService();
if ( service != null )
{
synchronized ( this.instances )
{
this.instances.add(service);
}
}
}
return service;
}
public void ungetService(final Object service)
{
if ( this.deactivated )
{
throw new IllegalStateException();
}
final ServiceObjects so = this.serviceObjects;
if ( so != null )
{
boolean remove;
synchronized ( instances )
{
remove = instances.remove(service);
}
if ( remove ) {
so.ungetService(service);
}
}
}
public ServiceReference<?> getServiceReference()
{
final ServiceObjects so = this.serviceObjects;
if ( so != null )
{
return so.getServiceReference();
}
return null;
}
@Override
public String toString() {
return "ComponentServiceObjectsImpl [instances=" + instances + ", serviceObjects=" + serviceObjects
+ ", deactivated=" + deactivated + ", hashCode=" + this.hashCode() + "]";
}
}
}