From 444d29422cc9838c7913736a41517a6e0e161e42 Mon Sep 17 00:00:00 2001 From: Tom Watson Date: Thu, 7 Feb 2019 09:58:07 -0600 Subject: [PATCH] FELIX-6050 - Use common code for PrototypRefPair Add an AbstractPrototypeRefPair to allow the Single and Multiple implementations to share common code --- .../manager/AbstractPrototypeRefPair.java | 109 ++++++++++++++++++ .../manager/MultiplePrototypeRefPair.java | 78 +++---------- .../impl/manager/SinglePrototypeRefPair.java | 90 +++++---------- .../felix/scr/impl/manager/SingleRefPair.java | 2 +- 4 files changed, 153 insertions(+), 126 deletions(-) create mode 100644 scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractPrototypeRefPair.java diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractPrototypeRefPair.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractPrototypeRefPair.java new file mode 100644 index 00000000000..1832b228af6 --- /dev/null +++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractPrototypeRefPair.java @@ -0,0 +1,109 @@ +/* + * 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.manager; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogService; + +/** + * @version $Rev$ $Date$ + */ +public abstract class AbstractPrototypeRefPair extends RefPair +{ + public AbstractPrototypeRefPair( ServiceReference ref ) + { + super(ref); + } + + @Override + public abstract T getServiceObject(ComponentContextImpl key); + + @Override + public abstract boolean setServiceObject(ComponentContextImpl key, T serviceObject); + + protected abstract T remove(ComponentContextImpl key); + + protected abstract Collection, T>> clearEntries(); + + @Override + public final T ungetServiceObject(ComponentContextImpl key) + { + if ( key == null ) + { + Collection,T>> keys = clearEntries(); + for (Map.Entry,T> e : keys) + { + doUngetService( e.getKey(), e.getValue() ); + } + return null ; + } + T service = remove( key ); + if(service != null) { + doUngetService( key, service ); + } + return service; + } + + @Override + public final void ungetServiceObjects(BundleContext bundleContext) { + ungetServiceObject(null); + } + + @Override + public abstract String toString(); + + @Override + public final boolean getServiceObject(ComponentContextImpl key, BundleContext context) + { + final T service = key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef()); + if ( service == null ) + { + setFailed(); + key.getLogger().log( + LogService.LOG_WARNING, + "Could not get service from serviceobjects for ref {0}", null, getRef() ); + return false; + } + if (!setServiceObject(key, service)) + { + // Another thread got the service before, so unget our + doUngetService( key, service ); + } + return true; + } + + @SuppressWarnings("unchecked") + private void doUngetService(ComponentContextImpl key, final T service) { + try + { + key.getComponentServiceObjectsHelper().getServiceObjects(getRef()).ungetService( service ); + } + catch ( final IllegalStateException ise ) + { + // ignore + } + } +} diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java index 8e827381eda..96ca5b9116e 100644 --- a/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java +++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java @@ -20,19 +20,18 @@ package org.apache.felix.scr.impl.manager; -import java.util.Iterator; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -import org.osgi.service.log.LogService; /** * @version $Rev$ $Date$ */ -public class MultiplePrototypeRefPair extends RefPair +public class MultiplePrototypeRefPair extends AbstractPrototypeRefPair { private final ConcurrentMap, T> instances = new ConcurrentHashMap<>(); @@ -42,77 +41,30 @@ public MultiplePrototypeRefPair( ServiceReference ref ) } @Override - public T getServiceObject(ComponentContextImpl key) - { - return instances.get( key ); - } - - @Override - public boolean setServiceObject(ComponentContextImpl key, T serviceObject) + public String toString() { - return instances.putIfAbsent( key, serviceObject ) == null; + return "[MultiplePrototypeRefPair: ref: [" + getRef() + "] has service: [" + !instances.isEmpty() + "]]"; } @Override - public T ungetServiceObject(ComponentContextImpl key) - { - if ( key == null ) - { - final Iterator, T>> iter = instances.entrySet().iterator(); - while ( iter.hasNext() ) - { - Entry, T> e = iter.next(); - doUngetService( e.getKey(), e.getValue() ); - } - instances.clear(); - return null ; - } - T service = instances.remove( key ); - if(service != null) { - doUngetService( key, service ); - } - return service; + public T getServiceObject(ComponentContextImpl key) { + return instances.get(key); } @Override - public void ungetServiceObjects(BundleContext bundleContext) { - ungetServiceObject(null); + public boolean setServiceObject(ComponentContextImpl key, T serviceObject) { + return instances.putIfAbsent(key, serviceObject) == null; } @Override - public String toString() - { - return "[MultiplePrototypeRefPair: ref: [" + getRef() + "] has service: [" + !instances.isEmpty() + "]]"; + protected T remove(ComponentContextImpl key) { + return instances.remove(key); } @Override - public boolean getServiceObject(ComponentContextImpl key, BundleContext context) - { - final T service = key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef()); - if ( service == null ) - { - setFailed(); - key.getLogger().log( - LogService.LOG_WARNING, - "Could not get service from serviceobjects for ref {0}", null, getRef() ); - return false; - } - if (!setServiceObject(key, service)) - { - // Another thread got the service before, so unget our - doUngetService( key, service ); - } - return true; + protected Collection, T>> clearEntries() { + Collection, T>> result = new ArrayList<>(instances.entrySet()); + instances.clear(); + return result; } - - private void doUngetService(ComponentContextImpl key, final T service) { - try - { - key.getComponentServiceObjectsHelper().getServiceObjects(getRef()).ungetService( service ); - } - catch ( final IllegalStateException ise ) - { - // ignore - } - } } diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java index 76f552058c1..2da0a14d54d 100644 --- a/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java +++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java @@ -20,26 +20,21 @@ package org.apache.felix.scr.impl.manager; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; -import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; -import org.osgi.service.log.LogService; /** * @version $Rev$ $Date$ */ -public class SinglePrototypeRefPair extends RefPair +public class SinglePrototypeRefPair extends AbstractPrototypeRefPair { - class SingleKeyService { - final ComponentContextImpl key; - final T serviceObject; - SingleKeyService(ComponentContextImpl key, T serviceObject) { - this.key = key; - this.serviceObject = serviceObject; - } - } - protected AtomicReference serviceObjectRef = new AtomicReference<>(); + private final AtomicReference, T>> instance = new AtomicReference<>(); public SinglePrototypeRefPair( ServiceReference ref ) { @@ -47,71 +42,42 @@ public SinglePrototypeRefPair( ServiceReference ref ) } @Override - public T getServiceObject(ComponentContextImpl key) + public String toString() { - SingleKeyService service = serviceObjectRef.get(); - return service == null ? null : service.serviceObject; + return "[SinglePrototypeRefPair: ref: [" + getRef() + "] service: [" + getServiceObject(null) + "]]"; } @Override - public boolean setServiceObject(ComponentContextImpl key, T serviceObject) - { - return serviceObjectRef.compareAndSet(null, new SingleKeyService(key, serviceObject )); + public T getServiceObject(ComponentContextImpl key) { + return internalGetServiceObject(key, false); } @Override - public T ungetServiceObject(ComponentContextImpl key) - { - SingleKeyService service = serviceObjectRef.getAndSet(null); - if (service != null) { - if (key == null) { - key = service.key; - } - doUngetService(key, service.serviceObject); - return service.serviceObject; - } - return null; + public boolean setServiceObject(ComponentContextImpl key, T serviceObject) { + return instance.compareAndSet(null, new SimpleImmutableEntry<>(key, serviceObject)); } @Override - public void ungetServiceObjects(BundleContext bundleContext) { - ungetServiceObject(null); + protected T remove(ComponentContextImpl key) { + return internalGetServiceObject(key, true); } - @Override - public String toString() - { - return "[SinglePrototypeRefPair: ref: [" + getRef() + "] service: [" + getServiceObject(null) + "]]"; + private T internalGetServiceObject(ComponentContextImpl key, boolean remove) { + SimpleImmutableEntry, T> entry = instance.get(); + if (entry == null) { + return null; + } + T result = key == null || entry.getKey().equals(key) ? entry.getValue() : null; + if (remove && result != null) { + instance.compareAndSet(entry, null); + } + return result; } @Override - public boolean getServiceObject(ComponentContextImpl key, BundleContext context) - { - final T service = key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef()); - if ( service == null ) - { - setFailed(); - key.getLogger().log( - LogService.LOG_WARNING, - "Could not get service from serviceobjects for ref {0}", null, getRef() ); - return false; - } - if (!setServiceObject(key, service)) - { - // Another thread got the service before, so unget our - doUngetService( key, service ); - } - return true; + protected Collection, T>> clearEntries() { + Map.Entry, T> entry = instance.getAndSet(null); + return entry == null ? Collections., T>>emptyList() : Collections.singleton(entry); } - private void doUngetService(ComponentContextImpl key, final T service) { - try - { - key.getComponentServiceObjectsHelper().getServiceObjects(getRef()).ungetService( service ); - } - catch ( final IllegalStateException ise ) - { - // ignore - } - } } diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java index f9b8df55286..eec52d1263b 100644 --- a/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java +++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java @@ -31,7 +31,7 @@ */ public class SingleRefPair extends RefPair { - protected AtomicReference serviceObjectRef = new AtomicReference<>(); + private final AtomicReference serviceObjectRef = new AtomicReference<>(); public SingleRefPair( ServiceReference ref ) {