diff --git a/class-model/src/main/java/org/glassfish/hk2/classmodel/reflect/impl/EnumTypeImpl.java b/class-model/src/main/java/org/glassfish/hk2/classmodel/reflect/impl/EnumTypeImpl.java index 3fadca4752..9a78a4ebfb 100644 --- a/class-model/src/main/java/org/glassfish/hk2/classmodel/reflect/impl/EnumTypeImpl.java +++ b/class-model/src/main/java/org/glassfish/hk2/classmodel/reflect/impl/EnumTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -19,6 +19,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + import org.glassfish.hk2.classmodel.reflect.*; /** @@ -27,6 +29,7 @@ */ public class EnumTypeImpl extends ExtensibleTypeImpl implements EnumType { + private final ReentrantLock lock = new ReentrantLock(); final List fields = new ArrayList<>(); public EnumTypeImpl(String name, TypeProxy sink, TypeProxy parent) { @@ -34,8 +37,13 @@ public EnumTypeImpl(String name, TypeProxy sink, TypeProxy parent) { } @Override - synchronized void addField(FieldModel field) { - fields.add(field); + void addField(FieldModel field) { + lock.lock(); + try { + fields.add(field); + } finally { + lock.unlock(); + } } @Override diff --git a/hk2-api/src/main/java/org/glassfish/hk2/internal/ImmediateHelper.java b/hk2-api/src/main/java/org/glassfish/hk2/internal/ImmediateHelper.java index 661b3fda2b..6aacbca834 100755 --- a/hk2-api/src/main/java/org/glassfish/hk2/internal/ImmediateHelper.java +++ b/hk2-api/src/main/java/org/glassfish/hk2/internal/ImmediateHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -24,6 +24,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -85,7 +87,8 @@ public class ImmediateHelper implements DynamicConfigurationListener, Runnable, private final HashSet tidsWithWork = new HashSet(); - private final Object queueLock = new Object(); + private final ReentrantLock queueLock = new ReentrantLock(); + private final Condition condition = queueLock.newCondition(); private boolean threadAvailable; private boolean outstandingJob; private boolean waitingForWork; @@ -140,16 +143,19 @@ private void doWorkIfWeHaveSome() { currentExecutor.execute(this); } else if (waitingForWork) { - queueLock.notify(); + condition.signal(); } } @Override public void configurationChanged() { - synchronized (queueLock) { + queueLock.lock(); + try { if (currentState.equals(ImmediateServiceState.SUSPENDED)) return; doWorkIfWeHaveSome(); + } finally { + queueLock.unlock(); } } @@ -169,9 +175,11 @@ public void onFailure(ErrorInformation errorInformation) if (!(ErrorType.DYNAMIC_CONFIGURATION_FAILURE.equals(errorInformation.getErrorType()))) { // Only interested in dynamic configuration failures long tid = Thread.currentThread().getId(); - - synchronized (queueLock) { + queueLock.lock(); + try { tidsWithWork.remove(tid); + } finally { + queueLock.unlock(); } return; @@ -185,8 +193,11 @@ public boolean validate(ValidationInformation info) { info.getOperation().equals(Operation.UNBIND)) { long tid = Thread.currentThread().getId(); - synchronized (queueLock) { + queueLock.lock(); + try { tidsWithWork.add(tid); + } finally { + queueLock.unlock(); } } @@ -200,7 +211,8 @@ public boolean validate(ValidationInformation info) { @Override public void run() { for(;;) { - synchronized (queueLock) { + queueLock.lock(); + try { long decayTime = this.decayTime; while (currentState.equals(ImmediateServiceState.RUNNING) && @@ -209,7 +221,7 @@ public void run() { waitingForWork = true; long currentTime = System.currentTimeMillis(); try { - queueLock.wait(decayTime); + condition.await(decayTime, TimeUnit.MILLISECONDS); } catch (InterruptedException ie) { threadAvailable = false; @@ -228,6 +240,8 @@ public void run() { } outstandingJob = false; + } finally { + queueLock.unlock(); } immediateContext.doWork(); @@ -240,8 +254,11 @@ public void run() { */ @Override public Executor getExecutor() { - synchronized (queueLock) { + queueLock.lock(); + try { return currentExecutor; + } finally { + queueLock.unlock(); } } @@ -250,12 +267,15 @@ public Executor getExecutor() { */ @Override public void setExecutor(Executor executor) throws IllegalStateException { - synchronized (queueLock) { + queueLock.lock(); + try { if (currentState.equals(ImmediateServiceState.RUNNING)) { throw new IllegalStateException("ImmediateSerivce attempt made to change executor while in RUNNING state"); } currentExecutor = (executor == null) ? DEFAULT_EXECUTOR : executor ; + } finally { + queueLock.unlock(); } } @@ -265,8 +285,11 @@ public void setExecutor(Executor executor) throws IllegalStateException { */ @Override public long getThreadInactivityTimeout() { - synchronized (queueLock) { + queueLock.lock(); + try { return decayTime; + } finally { + queueLock.unlock(); } } @@ -276,12 +299,15 @@ public long getThreadInactivityTimeout() { @Override public void setThreadInactivityTimeout(long timeInMillis) throws IllegalStateException { - synchronized (queueLock) { + queueLock.lock(); + try { if (timeInMillis < 0) { throw new IllegalArgumentException(); } decayTime = timeInMillis; + } finally { + queueLock.unlock(); } } @@ -291,8 +317,11 @@ public void setThreadInactivityTimeout(long timeInMillis) */ @Override public ImmediateServiceState getImmediateState() { - synchronized (queueLock) { + queueLock.lock(); + try { return currentState; + } finally { + queueLock.unlock(); } } @@ -301,7 +330,8 @@ public ImmediateServiceState getImmediateState() { */ @Override public void setImmediateState(ImmediateServiceState state) { - synchronized (queueLock) { + queueLock.lock(); + try { if (state == null) throw new IllegalArgumentException(); if (state == currentState) return; @@ -310,6 +340,8 @@ public void setImmediateState(ImmediateServiceState state) { if (currentState.equals(ImmediateServiceState.RUNNING)) { doWorkIfWeHaveSome(); } + } finally { + queueLock.unlock(); } } diff --git a/hk2-configuration/persistence/hk2-xml/main/src/main/java/org/glassfish/hk2/xml/tools/Hk2XmlGenerator.java b/hk2-configuration/persistence/hk2-xml/main/src/main/java/org/glassfish/hk2/xml/tools/Hk2XmlGenerator.java index fd724a65fb..9c3a6cdd6e 100755 --- a/hk2-configuration/persistence/hk2-xml/main/src/main/java/org/glassfish/hk2/xml/tools/Hk2XmlGenerator.java +++ b/hk2-configuration/persistence/hk2-xml/main/src/main/java/org/glassfish/hk2/xml/tools/Hk2XmlGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -24,6 +24,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; import javassist.ClassPool; import javassist.CtClass; @@ -48,6 +49,7 @@ */ @SupportedAnnotationTypes("org.glassfish.hk2.xml.api.annotations.Hk2XmlPreGenerate") public class Hk2XmlGenerator extends AbstractProcessor { + private final ReentrantLock lock = new ReentrantLock(); private volatile boolean initialized; private ClassPool defaultClassPool; private CtClass superClazz; @@ -62,8 +64,8 @@ public SourceVersion getSupportedSourceVersion() { private void initializeHk2XmlGenerator() { if (initialized) return; - - synchronized (this) { + lock.lock(); + try { if (initialized) return; defaultClassPool = new ClassPool(true); @@ -103,6 +105,8 @@ private void initializeHk2XmlGenerator() { catch (NotFoundException e) { throw new RuntimeException(e); } + } finally { + lock.unlock(); } } diff --git a/hk2-extras/src/main/java/org/glassfish/hk2/extras/hk2bridge/internal/Hk2BridgeImpl.java b/hk2-extras/src/main/java/org/glassfish/hk2/extras/hk2bridge/internal/Hk2BridgeImpl.java index 79421d5361..f34a3e8a51 100755 --- a/hk2-extras/src/main/java/org/glassfish/hk2/extras/hk2bridge/internal/Hk2BridgeImpl.java +++ b/hk2-extras/src/main/java/org/glassfish/hk2/extras/hk2bridge/internal/Hk2BridgeImpl.java @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; import jakarta.annotation.PreDestroy; import jakarta.inject.Inject; @@ -44,6 +45,7 @@ @Singleton @Visibility(DescriptorVisibility.LOCAL) public class Hk2BridgeImpl implements DynamicConfigurationListener { + private final ReentrantLock lock = new ReentrantLock(); private final ServiceLocator local; private ServiceLocator remote; private Filter filter; @@ -56,46 +58,56 @@ private Hk2BridgeImpl(ServiceLocator local) { } - public synchronized void setRemote(ServiceLocator remote) { - this.remote = remote; - this.filter = new NoLocalNoRemoteFilter(remote.getLocatorId()); - - List> newDescriptors = local.getDescriptors(filter); - - handleChange(newDescriptors); + public void setRemote(ServiceLocator remote) { + lock.lock(); + try { + this.remote = remote; + this.filter = new NoLocalNoRemoteFilter(remote.getLocatorId()); + + List> newDescriptors = local.getDescriptors(filter); + + handleChange(newDescriptors); + } finally { + lock.unlock(); + } } @SuppressWarnings("unchecked") - private synchronized void handleChange(List> newDescriptors) { - if (remote == null) return; - - HashSet> toRemove = new HashSet>(mirroredDescriptors); - toRemove.removeAll(newDescriptors); - - HashSet> toAdd = new HashSet>(newDescriptors); - toAdd.removeAll(mirroredDescriptors); - - DynamicConfigurationService remoteDCS = remote.getService(DynamicConfigurationService.class); - DynamicConfiguration config = remoteDCS.createDynamicConfiguration(); - - boolean dirty = false; - for (ActiveDescriptor removeMe : toRemove) { - Filter removeFilter = new RemoveFilter(removeMe.getLocatorId(), removeMe.getServiceId()); - config.addUnbindFilter(removeFilter); - dirty = true; - } - - for (ActiveDescriptor addMe : toAdd) { - CrossOverDescriptor cod = new CrossOverDescriptor(local, (ActiveDescriptor) addMe); - config.addActiveDescriptor(cod); - dirty = true; - } - - if (dirty) { - config.commit(); + private void handleChange(List> newDescriptors) { + lock.lock(); + try { + if (remote == null) return; + + HashSet> toRemove = new HashSet>(mirroredDescriptors); + toRemove.removeAll(newDescriptors); + + HashSet> toAdd = new HashSet>(newDescriptors); + toAdd.removeAll(mirroredDescriptors); + + DynamicConfigurationService remoteDCS = remote.getService(DynamicConfigurationService.class); + DynamicConfiguration config = remoteDCS.createDynamicConfiguration(); + + boolean dirty = false; + for (ActiveDescriptor removeMe : toRemove) { + Filter removeFilter = new RemoveFilter(removeMe.getLocatorId(), removeMe.getServiceId()); + config.addUnbindFilter(removeFilter); + dirty = true; + } + + for (ActiveDescriptor addMe : toAdd) { + CrossOverDescriptor cod = new CrossOverDescriptor(local, (ActiveDescriptor) addMe); + config.addActiveDescriptor(cod); + dirty = true; + } + + if (dirty) { + config.commit(); + } + + mirroredDescriptors = newDescriptors; + } finally { + lock.unlock(); } - - mirroredDescriptors = newDescriptors; } /* (non-Javadoc) diff --git a/hk2-extras/src/main/java/org/glassfish/hk2/extras/operation/OperationContext.java b/hk2-extras/src/main/java/org/glassfish/hk2/extras/operation/OperationContext.java index 954ded7c8c..174fca2639 100755 --- a/hk2-extras/src/main/java/org/glassfish/hk2/extras/operation/OperationContext.java +++ b/hk2-extras/src/main/java/org/glassfish/hk2/extras/operation/OperationContext.java @@ -346,8 +346,13 @@ public boolean isActive() { return true; } - public synchronized void setOperationManager(SingleOperationManager manager) { - this.manager = manager; + public void setOperationManager(SingleOperationManager manager) { + lock.lock(); + try { + this.manager = manager; + } finally { + lock.unlock(); + } } @Override diff --git a/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesDescriptor.java b/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesDescriptor.java index 5caa04d8ae..97ac6c05bc 100644 --- a/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesDescriptor.java +++ b/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesDescriptor.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 TechEmpower. All rights reserved. + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -27,6 +28,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -48,6 +50,7 @@ * and {@link NoInstancesService}. */ final class ProvidesDescriptor implements ActiveDescriptor { + private final ReentrantLock lock = new ReentrantLock(); private final AnnotatedElement annotatedElement; private final Class implementationClass; private final Type implementationType; @@ -215,23 +218,33 @@ public Map> getMetadata() { private boolean initialRankingFound = false; @Override - public synchronized int getRanking() { - if (!initialRankingFound) { - Rank rank = annotatedElement.getAnnotation(Rank.class); - if (rank != null) - ranking = rank.value(); - - initialRankingFound = true; + public int getRanking() { + lock.lock(); + try { + if (!initialRankingFound) { + Rank rank = annotatedElement.getAnnotation(Rank.class); + if (rank != null) + ranking = rank.value(); + + initialRankingFound = true; + } + + return ranking; + } finally { + lock.unlock(); } - - return ranking; } @Override - public synchronized int setRanking(int ranking) { - int previousRanking = getRanking(); - this.ranking = ranking; - return previousRanking; + public int setRanking(int ranking) { + lock.lock(); + try { + int previousRanking = getRanking(); + this.ranking = ranking; + return previousRanking; + } finally { + lock.unlock(); + } } @Override @@ -270,28 +283,48 @@ public synchronized int setRanking(int ranking) { private boolean isCacheSet = false; @Override - public synchronized /*@Nullable*/ T getCache() { - if (!isCacheSet) - throw new IllegalStateException(); + public /*@Nullable*/ T getCache() { + lock.lock(); + try { + if (!isCacheSet) + throw new IllegalStateException(); - return cache; + return cache; + } finally { + lock.unlock(); + } } @Override - public synchronized boolean isCacheSet() { - return isCacheSet; + public boolean isCacheSet() { + lock.lock(); + try { + return isCacheSet; + } finally { + lock.unlock(); + } } @Override - public synchronized void setCache(T cacheMe) { - cache = cacheMe; - isCacheSet = true; + public void setCache(T cacheMe) { + lock.lock(); + try { + cache = cacheMe; + isCacheSet = true; + } finally { + lock.unlock(); + } } @Override - public synchronized void releaseCache() { - cache = null; - isCacheSet = false; + public void releaseCache() { + lock.lock(); + try { + cache = null; + isCacheSet = false; + } finally { + lock.unlock(); + } } @Override diff --git a/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesListener.java b/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesListener.java index f17cb3458f..6e08c2cdbc 100644 --- a/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesListener.java +++ b/hk2-extras/src/main/java/org/glassfish/hk2/extras/provides/ProvidesListener.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 TechEmpower. All rights reserved. + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -35,6 +36,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -71,6 +73,7 @@ public class ProvidesListener implements DynamicConfigurationListener { private final ServiceLocator locator; private final ProvidersSeen seen = new ProvidersSeen(); + private static final ReentrantLock slock = new ReentrantLock(); private static final Object UNIQUE = new Object() {}; @Inject @@ -80,7 +83,8 @@ public ProvidesListener(ServiceLocator locator) { // Two listeners registered with the same locator could cause a feedback // loop since they can't share the cache of the providers they have seen. // Defend against this by disallowing the second listener. - synchronized (UNIQUE) { + slock.lock(); + try { if (locator.getService(UNIQUE.getClass()) != null) { throw new IllegalStateException( "There is already a " @@ -88,6 +92,8 @@ public ProvidesListener(ServiceLocator locator) { + " registered with this locator"); } ServiceLocatorUtilities.addOneConstant(locator, UNIQUE); + } finally { + slock.unlock(); } } diff --git a/hk2-testing/hk2-mockito/pom.xml b/hk2-testing/hk2-mockito/pom.xml index ab9b30ae06..4aa0188d59 100644 --- a/hk2-testing/hk2-mockito/pom.xml +++ b/hk2-testing/hk2-mockito/pom.xml @@ -95,7 +95,7 @@ org.mockito mockito-core - 5.10.0 + 5.11.0 provided diff --git a/hk2-utils/src/main/java/org/glassfish/hk2/utilities/general/internal/WeakHashLRUImpl.java b/hk2-utils/src/main/java/org/glassfish/hk2/utilities/general/internal/WeakHashLRUImpl.java index b4df1a8ac1..d7be295f6b 100755 --- a/hk2-utils/src/main/java/org/glassfish/hk2/utilities/general/internal/WeakHashLRUImpl.java +++ b/hk2-utils/src/main/java/org/glassfish/hk2/utilities/general/internal/WeakHashLRUImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -20,6 +20,7 @@ import java.util.LinkedList; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; import org.glassfish.hk2.utilities.cache.CacheKeyFilter; import org.glassfish.hk2.utilities.general.WeakHashLRU; @@ -32,7 +33,8 @@ */ public class WeakHashLRUImpl implements WeakHashLRU { private final static Object VALUE = new Object(); - + + private final ReentrantLock lock = new ReentrantLock(); private final boolean isWeak; private final WeakHashMap> byKey; private final ConcurrentHashMap> byKeyNotWeak; @@ -98,32 +100,37 @@ private K remove(DoubleNode removeMe) { * @see org.glassfish.hk2.utilities.general.WeakHashLRU#add(java.lang.Object) */ @Override - public synchronized void add(K key) { - if (key == null) { - throw new IllegalArgumentException("key may not be null"); - } - - DoubleNode existing; - if (isWeak) { - clearStale(); + public void add(K key) { + lock.lock(); + try { + if (key == null) { + throw new IllegalArgumentException("key may not be null"); + } - existing = byKey.get(key); - } - else { - existing = byKeyNotWeak.get(key); - } - - if (existing != null) { - remove(existing); - } - - DoubleNode added = addToHead(key); - - if (isWeak) { - byKey.put(key, added); - } - else { - byKeyNotWeak.put(key, added); + DoubleNode existing; + if (isWeak) { + clearStale(); + + existing = byKey.get(key); + } + else { + existing = byKeyNotWeak.get(key); + } + + if (existing != null) { + remove(existing); + } + + DoubleNode added = addToHead(key); + + if (isWeak) { + byKey.put(key, added); + } + else { + byKeyNotWeak.put(key, added); + } + } finally { + lock.unlock(); } } @@ -133,10 +140,13 @@ public synchronized void add(K key) { @Override public boolean contains(K key) { if (isWeak) { - synchronized (this) { + lock.lock(); + try { clearStale(); return byKey.containsKey(key); + } finally { + lock.unlock(); } } @@ -147,12 +157,17 @@ public boolean contains(K key) { * @see org.glassfish.hk2.utilities.general.WeakHashLRU#remove(java.lang.Object) */ @Override - public synchronized boolean remove(K key) { - if (isWeak) { - clearStale(); + public boolean remove(K key) { + lock.lock(); + try { + if (isWeak) { + clearStale(); + } + + return removeNoClear(key); + } finally { + lock.unlock(); } - - return removeNoClear(key); } private boolean removeNoClear(K key) { @@ -178,10 +193,13 @@ private boolean removeNoClear(K key) { @Override public int size() { if (isWeak) { - synchronized (this) { + lock.lock(); + try { clearStale(); - + return byKey.size(); + } finally { + lock.unlock(); } } @@ -192,7 +210,8 @@ public int size() { * @see org.glassfish.hk2.utilities.general.WeakHashLRU#remove() */ @Override - public synchronized K remove() { + public K remove() { + lock.lock(); try { if (lru == null) return null; @@ -217,7 +236,11 @@ public synchronized K remove() { return null; } finally { - clearStale(); + try { + clearStale(); + } finally { + lock.unlock(); + } } } @@ -225,25 +248,30 @@ public synchronized K remove() { * @see org.glassfish.hk2.utilities.general.WeakHashLRU#releaseMatching(org.glassfish.hk2.utilities.cache.CacheKeyFilter) */ @Override - public synchronized void releaseMatching(CacheKeyFilter filter) { - if (filter == null) return; - if (isWeak) { - clearStale(); - } - - LinkedList removeMe = new LinkedList(); - DoubleNode current = mru; - while (current != null) { - K key = current.getWeakKey().get(); - if (key != null && filter.matches(key)) { - removeMe.add(key); + public void releaseMatching(CacheKeyFilter filter) { + lock.lock(); + try { + if (filter == null) return; + if (isWeak) { + clearStale(); } - current = current.getNext(); - } - - for (K removeKey : removeMe) { - removeNoClear(removeKey); + LinkedList removeMe = new LinkedList(); + DoubleNode current = mru; + while (current != null) { + K key = current.getWeakKey().get(); + if (key != null && filter.matches(key)) { + removeMe.add(key); + } + + current = current.getNext(); + } + + for (K removeKey : removeMe) { + removeNoClear(removeKey); + } + } finally { + lock.unlock(); } } @@ -251,26 +279,36 @@ public synchronized void releaseMatching(CacheKeyFilter filter) { * @see org.glassfish.hk2.utilities.general.WeakHashLRU#clear() */ @Override - public synchronized void clear() { - if (isWeak) { - clearStale(); + public void clear() { + lock.lock(); + try { + if (isWeak) { + clearStale(); + + byKey.clear(); + } + else { + byKeyNotWeak.clear(); + } - byKey.clear(); - } - else { - byKeyNotWeak.clear(); + mru = null; + lru = null; + } finally { + lock.unlock(); } - - mru = null; - lru = null; } /* (non-Javadoc) * @see org.glassfish.hk2.utilities.general.WeakHashLRU#clearStaleReferences() */ @Override - public synchronized void clearStaleReferences() { - clearStale(); + public void clearStaleReferences() { + lock.lock(); + try { + clearStale(); + } finally { + lock.unlock(); + } } private void clearStale() { @@ -296,29 +334,34 @@ private void clearStale() { } @Override - public synchronized String toString() { - StringBuffer sb = new StringBuffer("WeakHashLRUImpl({"); - - boolean first = true; - DoubleNode current = mru; - while (current != null) { - K key = current.getWeakKey().get(); - String keyString = (key == null) ? "null" : key.toString(); + public String toString() { + lock.lock(); + try { + StringBuffer sb = new StringBuffer("WeakHashLRUImpl({"); - if (first) { - first = false; + boolean first = true; + DoubleNode current = mru; + while (current != null) { + K key = current.getWeakKey().get(); + String keyString = (key == null) ? "null" : key.toString(); - sb.append(keyString); - } - else { - sb.append("," + keyString); + if (first) { + first = false; + + sb.append(keyString); + } + else { + sb.append("," + keyString); + } + + current = current.getNext(); } - current = current.getNext(); + sb.append("}," + System.identityHashCode(this) + ")"); + + return sb.toString(); + } finally { + lock.unlock(); } - - sb.append("}," + System.identityHashCode(this) + ")"); - - return sb.toString(); } } diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/AbstractOSGiModulesRegistryImpl.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/AbstractOSGiModulesRegistryImpl.java index 84bb9bd8d4..5f9107944d 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/AbstractOSGiModulesRegistryImpl.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/AbstractOSGiModulesRegistryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 Payara Services Ltd. * * This program and the accompanying materials are made available under the @@ -34,6 +34,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.*; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import static org.glassfish.hk2.utilities.ServiceLocatorUtilities.createDynamicConfiguration; @@ -51,6 +52,7 @@ public abstract class AbstractOSGiModulesRegistryImpl extends AbstractModulesReg protected PackageAdmin pa; private Map moduleChangeListeners = new HashMap<>(); private Map moduleLifecycleListeners = new HashMap<>(); + private final ReentrantLock lock = new ReentrantLock(); protected AbstractOSGiModulesRegistryImpl(BundleContext bctx) { super(null); @@ -138,9 +140,14 @@ public ModulesRegistry createChild() { } @Override - public synchronized void detachAll() { - for (HK2Module m : modules.values()) { - m.detach(); + public void detachAll() { + lock.lock(); + try { + for (HK2Module m : modules.values()) { + m.detach(); + } + } finally { + lock.unlock(); } } diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ModuleDefinitionCacheSingleton.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ModuleDefinitionCacheSingleton.java index d870e18e4e..5d8e3bbb0b 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ModuleDefinitionCacheSingleton.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ModuleDefinitionCacheSingleton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -24,6 +24,7 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -33,7 +34,9 @@ class ModuleDefinitionCacheSingleton { private static ModuleDefinitionCacheSingleton _instance; + private static final ReentrantLock slock = new ReentrantLock(); + private final ReentrantLock lock = new ReentrantLock(); private Map cachedData = new HashMap<>(); private boolean cacheInvalidated = false; @@ -45,27 +48,42 @@ private ModuleDefinitionCacheSingleton() { } } - public synchronized static ModuleDefinitionCacheSingleton getInstance() { - if (_instance == null) { - _instance = new ModuleDefinitionCacheSingleton(); - } + public static ModuleDefinitionCacheSingleton getInstance() { + slock.lock(); + try { + if (_instance == null) { + _instance = new ModuleDefinitionCacheSingleton(); + } - return _instance; + return _instance; + } finally { + slock.unlock(); + } } - public synchronized void cacheModuleDefinition(URI uri, ModuleDefinition md) { - if (!cachedData.containsKey(uri)) { - cacheInvalidated = true; - } else { - // should check if md is the same - } - - cachedData.put(uri, md); + public void cacheModuleDefinition(URI uri, ModuleDefinition md) { + lock.lock(); + try { + if (!cachedData.containsKey(uri)) { + cacheInvalidated = true; + } else { + // should check if md is the same + } + + cachedData.put(uri, md); + } finally { + lock.unlock(); + } } - public synchronized void remove(URI uri) { - if (cachedData.remove(uri) != null) { - cacheInvalidated =true; + public void remove(URI uri) { + lock.lock(); + try { + if (cachedData.remove(uri) != null) { + cacheInvalidated =true; + } + } finally { + lock.unlock(); } } /** @@ -94,32 +112,36 @@ private void loadCachedData() throws Exception { * Saves the inhabitants metadata to the cache in a file called inhabitants * @throws java.io.IOException if the file cannot be saved successfully */ - public synchronized void saveCache() throws IOException { - - if (!cacheInvalidated) { - return; - } - - String cacheLocation = getProperty(Constants.HK2_CACHE_DIR); - if (cacheLocation == null) { - return; - } - File io = new File(cacheLocation, Constants.INHABITANTS_CACHE); - if(logger.isLoggable(Level.FINE)) { - logger.logp(Level.INFO, getClass().getSimpleName(), "saveCache", "HK2 cache file = {0}", new Object[]{io}); - } - if (io.exists()) io.delete(); - io.createNewFile(); - Map data = new HashMap<>(); - for (ModuleDefinition m : cachedData.values()) { - data.put(m.getLocations()[0], m); + public void saveCache() throws IOException { + lock.lock(); + try { + if (!cacheInvalidated) { + return; + } + + String cacheLocation = getProperty(Constants.HK2_CACHE_DIR); + if (cacheLocation == null) { + return; + } + File io = new File(cacheLocation, Constants.INHABITANTS_CACHE); + if(logger.isLoggable(Level.FINE)) { + logger.logp(Level.INFO, getClass().getSimpleName(), "saveCache", "HK2 cache file = {0}", new Object[]{io}); + } + if (io.exists()) io.delete(); + io.createNewFile(); + Map data = new HashMap<>(); + for (ModuleDefinition m : cachedData.values()) { + data.put(m.getLocations()[0], m); + } + ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(io)), getBufferSize())); + + os.writeObject(data); + os.close(); + + cacheInvalidated =false; + } finally { + lock.unlock(); } - ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(io)), getBufferSize())); - - os.writeObject(data); - os.close(); - - cacheInvalidated =false; } private int getBufferSize() { @@ -134,10 +156,15 @@ private int getBufferSize() { return bufsize; } - public synchronized ModuleDefinition get(URI uri) { - ModuleDefinition md = cachedData.get(uri); + public ModuleDefinition get(URI uri) { + lock.lock(); + try { + ModuleDefinition md = cachedData.get(uri); - return md; + return md; + } finally { + lock.unlock(); + } } public void invalidate() { diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiFactoryImpl.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiFactoryImpl.java index a2d1d356f3..397064ff74 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiFactoryImpl.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 Payara Services Ltd. * * This program and the accompanying materials are made available under the @@ -23,6 +23,7 @@ import com.sun.enterprise.module.ModuleDefinition; import org.osgi.framework.BundleContext; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; /** @@ -30,15 +31,21 @@ */ public class OSGiFactoryImpl extends AbstractFactory { + private static final ReentrantLock slock = new ReentrantLock(); private BundleContext ctx; - public static synchronized void initialize(BundleContext ctx) { - if (Instance != null) { - // TODO : this is somehow invoked twice during gf startup, we need to investigate. - logger.logp(Level.FINE, "OSGiFactoryImpl", "initialize", - "Singleton already initialized as {0}", getInstance()); + public static void initialize(BundleContext ctx) { + slock.lock(); + try { + if (Instance != null) { + // TODO : this is somehow invoked twice during gf startup, we need to investigate. + logger.logp(Level.FINE, "OSGiFactoryImpl", "initialize", + "Singleton already initialized as {0}", getInstance()); + } + Instance = new OSGiFactoryImpl(ctx); + } finally { + slock.unlock(); } - Instance = new OSGiFactoryImpl(ctx); } private OSGiFactoryImpl(BundleContext ctx) { diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModuleImpl.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModuleImpl.java index de126da5fd..d88addc802 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModuleImpl.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModuleImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 Payara Services Ltd. * * This program and the accompanying materials are made available under the @@ -17,19 +17,14 @@ package org.jvnet.hk2.osgiadapter; -import static org.jvnet.hk2.osgiadapter.FelixPrettyPrinter.addBundleInfo; -import static org.jvnet.hk2.osgiadapter.FelixPrettyPrinter.prettyPrintExceptionMessage; import static org.jvnet.hk2.osgiadapter.FelixPrettyPrinter.prettyPrintFelixMessage; import static org.jvnet.hk2.osgiadapter.Logger.logger; import java.io.*; import java.net.URI; import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.util.*; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import org.glassfish.hk2.api.ActiveDescriptor; @@ -58,6 +53,7 @@ * @author Sanjeeb.Sahoo@Sun.COM */ public class OSGiModuleImpl implements HK2Module { + private final ReentrantLock lock = new ReentrantLock(); private volatile Bundle bundle; // made volatile as it is accessed from multiple threads private ModuleDefinition md; @@ -145,75 +141,69 @@ public ModuleState getState() { } @Override - public synchronized void resolve() throws ResolveError { + public void resolve() throws ResolveError { // Since OSGi bundle does not have a separate resolve method, // we use the same implementation as start(); - start(); + lock.lock(); + try { + start(); + } finally { + lock.unlock(); + } } @Override - public synchronized void start() throws ResolveError { - int state = bundle.getState(); - if (((Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING) & state) != 0) { - if (logger.isLoggable(Level.FINER)) { - logger.logp(Level.FINER, "OSGiModuleImpl", "start", - "Ignoring start of bundle {0} as it is in {1} state", - new Object[]{bundle, toString(bundle.getState())} ); - } - return; - } - if (registry.getPackageAdmin().getBundleType(bundle) == PackageAdmin.BUNDLE_TYPE_FRAGMENT) { - if (logger.isLoggable(Level.FINER)) { - logger.logp(Level.FINER, "OSGiModuleImpl", "start", - "Ignoring start of bundle {0} as it is a fragment bundle", - new Object[]{bundle} ); - } - return; - } + public void start() throws ResolveError { + lock.lock(); try { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction(){ - @Override - public Object run() throws BundleException - { - startBundle(); - return null; - } - }); - } catch (PrivilegedActionException e) { - throw (BundleException)e.getException(); + int state = bundle.getState(); + if (((Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING) & state) != 0) { + if (logger.isLoggable(Level.FINER)) { + logger.logp(Level.FINER, "OSGiModuleImpl", "start", + "Ignoring start of bundle {0} as it is in {1} state", + new Object[]{bundle, toString(bundle.getState())} ); } - } else { - startBundle(); + return; } - isTransientlyActive = true; - if (logger.isLoggable(Level.FINE)) { - logger.logp(Level.FINE, "OSGiModuleImpl", - "start", "Started bundle {0}", bundle); + if (registry.getPackageAdmin().getBundleType(bundle) == PackageAdmin.BUNDLE_TYPE_FRAGMENT) { + if (logger.isLoggable(Level.FINER)) { + logger.logp(Level.FINER, "OSGiModuleImpl", "start", + "Ignoring start of bundle {0} as it is a fragment bundle", + new Object[]{bundle} ); + } + return; } - } catch (BundleException e) { - throw new ResolveError( - "Failed to start " + this + prettyPrintFelixMessage(registry.getBundleContext(), e.getMessage()), - e); - } - - // TODO(Sahoo): Remove this when hk2-apt generates equivalent BundleActivator - // if there is a LifecyclePolicy, then instantiate and invoke. - if (md.getLifecyclePolicyClassName()!=null) { try { - Class lifecyclePolicyClass = - (Class) bundle.loadClass(md.getLifecyclePolicyClassName()); - lifecyclePolicy = lifecyclePolicyClass.newInstance(); - } catch(ClassNotFoundException e) { - throw new ResolveError("ClassNotFound : " + e.getMessage(), e); - } catch(java.lang.InstantiationException | IllegalAccessException e) { - throw new ResolveError(e); + startBundle(); + isTransientlyActive = true; + if (logger.isLoggable(Level.FINE)) { + logger.logp(Level.FINE, "OSGiModuleImpl", + "start", "Started bundle {0}", bundle); + } + } catch (BundleException e) { + throw new ResolveError( + "Failed to start " + this + prettyPrintFelixMessage(registry.getBundleContext(), e.getMessage()), + e); } - } - if (lifecyclePolicy!=null) { - lifecyclePolicy.start(this); + + // TODO(Sahoo): Remove this when hk2-apt generates equivalent BundleActivator + // if there is a LifecyclePolicy, then instantiate and invoke. + if (md.getLifecyclePolicyClassName()!=null) { + try { + Class lifecyclePolicyClass = + (Class) bundle.loadClass(md.getLifecyclePolicyClassName()); + lifecyclePolicy = lifecyclePolicyClass.newInstance(); + } catch(ClassNotFoundException e) { + throw new ResolveError("ClassNotFound : " + e.getMessage(), e); + } catch(java.lang.InstantiationException | IllegalAccessException e) { + throw new ResolveError(e); + } + } + if (lifecyclePolicy!=null) { + lifecyclePolicy.start(this); + } + } finally { + lock.unlock(); } } @@ -280,11 +270,16 @@ private String toString(int state) } @Override - public synchronized boolean stop() { - detach(); + public boolean stop() { + lock.lock(); + try { + detach(); // Don't refresh packages, as we are not uninstalling the bundle. // registry.getPackageAdmin().refreshPackages(new Bundle[]{bundle}); - return true; + return true; + } finally { + lock.unlock(); + } } @Override @@ -424,12 +419,7 @@ List parseInhabitants(String name, ServiceLocator serviceLocat * This method is used as the parent loader of the class loader that we return in {@link #getClassLoader} */ private ClassLoader getParentLoader() { - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ClassLoader run() { - return Bundle.class.getClassLoader(); - } - }); + return Bundle.class.getClassLoader(); } @Override @@ -446,22 +436,14 @@ public ClassLoader getClassLoader() { * class loader. */ return new ClassLoader(getParentLoader()) { - + private final ReentrantLock lock = new ReentrantLock(); @Override - protected synchronized Class loadClass(final String name, boolean resolve) throws ClassNotFoundException { + protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException { + lock.lock(); try { - //doprivileged needed for running with SecurityManager - return AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public Class run() throws ClassNotFoundException { - - Class c = bundle.loadClass(name); - - return c; - } - }); - } catch (PrivilegedActionException e) { - throw (ClassNotFoundException)e.getException(); + return bundle.loadClass(name); + } finally { + lock.unlock(); } } diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModulesRegistryImpl.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModulesRegistryImpl.java index 92bbaf7b3e..51da799b32 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModulesRegistryImpl.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiModulesRegistryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 Payara Services Ltd. * * This program and the accompanying materials are made available under the @@ -23,6 +23,7 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import org.osgi.framework.Bundle; @@ -44,6 +45,8 @@ public class OSGiModulesRegistryImpl extends AbstractOSGiModulesRegistryImpl implements SynchronousBundleListener { + private final ReentrantLock lock = new ReentrantLock(); + ModuleDefinitionCacheSingleton cache = ModuleDefinitionCacheSingleton.getInstance(); /*package*/ OSGiModulesRegistryImpl(BundleContext bctx) { @@ -164,25 +167,34 @@ private OSGiModuleDefinition makeModuleDef(Bundle bundle) } @Override - protected synchronized void add(HK2Module newModule) { - // It is overridden to make it synchronized as it is called from - // BundleListener. - super.add(newModule); - // don't set cacheInvalidated = true here, as this method is called while iterating initial - // set of bundles when this module is started. Instead, we invalidate the cache makeModuleDef(). + protected void add(HK2Module newModule) { + lock.lock(); + try { + // It is overridden to make it synchronized as it is called from + // BundleListener. + super.add(newModule); + // don't set cacheInvalidated = true here, as this method is called while iterating initial + // set of bundles when this module is started. Instead, we invalidate the cache makeModuleDef(). + } finally { + lock.unlock(); + } } @Override - public synchronized void remove(HK2Module module) { - - // It is overridden to make it synchronized as it is called from - // BundleListener. - super.remove(module); + public void remove(HK2Module module) { + lock.lock(); + try { + // It is overridden to make it synchronized as it is called from + // BundleListener. + super.remove(module); - // Update cache. - final URI location = module.getModuleDefinition().getLocations()[0]; + // Update cache. + final URI location = module.getModuleDefinition().getLocations()[0]; - cache.remove(location); + cache.remove(location); + } finally { + lock.unlock(); + } } // factory method @@ -210,26 +222,30 @@ protected HK2Module newModule(ModuleDefinition moduleDef) { } @Override - public synchronized void shutdown() { - - for (HK2Module m : modules.values()) { - // Only stop modules that were started after ModulesRegistry - // came into existence. - if (OSGiModuleImpl.class.cast(m).isTransientlyActive()) { - m.stop(); - } - } - - // Save the cache before clearing modules + public void shutdown() { + lock.lock(); try { - cache.saveCache(); - } catch (IOException e) { - Logger.logger.log(Level.WARNING, "Cannot save metadata to cache", e); + for (HK2Module m : modules.values()) { + // Only stop modules that were started after ModulesRegistry + // came into existence. + if (OSGiModuleImpl.class.cast(m).isTransientlyActive()) { + m.stop(); + } } + + // Save the cache before clearing modules + try { + cache.saveCache(); + } catch (IOException e) { + Logger.logger.log(Level.WARNING, "Cannot save metadata to cache", e); + } - bctx.removeBundleListener(this); + bctx.removeBundleListener(this); - super.shutdown(); + super.shutdown(); + } finally { + lock.unlock(); + } } protected String getProperty(String property) { diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiObrModuleImpl.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiObrModuleImpl.java index 1604d5690b..318e4c2815 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiObrModuleImpl.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/OSGiObrModuleImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020Payara Services Ltd. * * This program and the accompanying materials are made available under the @@ -33,12 +33,15 @@ import java.io.PrintStream; import java.util.Collections; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; /** * @author Sanjeeb.Sahoo@Sun.COM */ public class OSGiObrModuleImpl extends OSGiModuleImpl { + private final ReentrantLock lock = new ReentrantLock(); + public OSGiObrModuleImpl(OSGiObrModulesRegistryImpl registry, File file) throws IOException { this(registry, new OSGiModuleDefinition(file)); } @@ -51,21 +54,31 @@ public OSGiObrModuleImpl(OSGiObrModulesRegistryImpl registry, Bundle bundle, Mod super(registry, bundle, moduleDef); } - private synchronized boolean isUninitialized() { - return getBundle() == null; + private boolean isUninitialized() { + lock.lock(); + try { + return getBundle() == null; + } finally { + lock.unlock(); + } } - private synchronized void init() { - if (isUninitialized()) { - final ModuleDefinition moduleDefinition = getModuleDefinition(); - Bundle bundle = getRegistry().getObrHandler().deploy(moduleDefinition.getName(), moduleDefinition.getVersion()); - if (bundle != null) { - setBundle(bundle); - } else { - throw new RuntimeException("Unable to install module [ " - + this - + "] due to unsatisfied dependencies. See previous log messages."); + private void init() { + lock.lock(); + try { + if (isUninitialized()) { + final ModuleDefinition moduleDefinition = getModuleDefinition(); + Bundle bundle = getRegistry().getObrHandler().deploy(moduleDefinition.getName(), moduleDefinition.getVersion()); + if (bundle != null) { + setBundle(bundle); + } else { + throw new RuntimeException("Unable to install module [ " + + this + + "] due to unsatisfied dependencies. See previous log messages."); + } } + } finally { + lock.unlock(); } } diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ObrHandler.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ObrHandler.java index 7a090b9c06..c5a31202a5 100755 --- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ObrHandler.java +++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/ObrHandler.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Hashtable; import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import org.apache.felix.bundlerepository.DataModelHelper; @@ -54,6 +55,7 @@ class ObrHandler extends ServiceTracker { Implementation Note: This class has no dependency on HK2. */ + private final ReentrantLock lock = new ReentrantLock(); private boolean deployFragments = false; private boolean deployOptionalRequirements = false; // We maintain our own repository list which we use during resolution process. @@ -95,11 +97,16 @@ public RepositoryAdmin getRepositoryAdmin() { } } - public synchronized void addRepository(URI obrUri) throws Exception { - if (isDirectory(obrUri)) { - setupRepository(new File(obrUri), isSynchronous()); - } else { - repositories.add(getRepositoryAdmin().getHelper().repository(obrUri.toURL())); + public void addRepository(URI obrUri) throws Exception { + lock.lock(); + try { + if (isDirectory(obrUri)) { + setupRepository(new File(obrUri), isSynchronous()); + } else { + repositories.add(getRepositoryAdmin().getHelper().repository(obrUri.toURL())); + } + } finally { + lock.unlock(); } } @@ -134,24 +141,26 @@ private boolean isSynchronous() { return property == null || Boolean.TRUE.toString().equalsIgnoreCase(property); } - private synchronized void _setupRepository(File repoDir) throws Exception { - Repository repository; - File repoFile = getRepositoryFile(repoDir); - final long tid = Thread.currentThread().getId(); - if (repoFile != null && repoFile.exists()) { - long t = System.currentTimeMillis(); - repository = updateRepository(repoFile, repoDir); - long t2 = System.currentTimeMillis(); - logger.logp(Level.INFO, "ObrHandler", "_setupRepository", "Thread #{0}: updateRepository took {1} ms", - new Object[]{tid, t2 - t}); - } else { - long t = System.currentTimeMillis(); - repository = createRepository(repoFile, repoDir); - long t2 = System.currentTimeMillis(); - logger.logp(Level.INFO, "ObrHandler", "_setupRepository", "Thread #{0}: createRepository took {1} ms", - new Object[]{tid, t2 - t}); - } - repositories.add(repository); + private void _setupRepository(File repoDir) throws Exception { + lock.lock(); + try { + Repository repository; + File repoFile = getRepositoryFile(repoDir); + final long tid = Thread.currentThread().getId(); + if (repoFile != null && repoFile.exists()) { + long t = System.currentTimeMillis(); + repository = updateRepository(repoFile, repoDir); + long t2 = System.currentTimeMillis(); + logger.logp(Level.INFO, "ObrHandler", "_setupRepository", "Thread #{0}: updateRepository took {1} ms", + new Object[]{tid, t2 - t}); + } else { + long t = System.currentTimeMillis(); + repository = createRepository(repoFile, repoDir); + long t2 = System.currentTimeMillis(); + logger.logp(Level.INFO, "ObrHandler", "_setupRepository", "Thread #{0}: createRepository took {1} ms", + new Object[]{tid, t2 - t}); + } + repositories.add(repository); // We don't add repository to RepositoryAdmin, as we pass the list of repositories to use in resolver(). // final String repoUrl = repository.getURI(); // logger.logp(Level.INFO, "ObrHandler", "_setupRepository", "Thread #{0}: Adding repository = {1}", @@ -161,6 +170,9 @@ private synchronized void _setupRepository(File repoDir) throws Exception { // long t2 = System.currentTimeMillis(); // logger.logp(Level.INFO, "ObrHandler", "_setupRepository", "Thread #{0}: Adding repo took {1} ms", // new Object[]{tid, t2 - t}); + } finally { + lock.unlock(); + } } private File getRepositoryFile(File repoDir) { @@ -280,18 +292,23 @@ public boolean accept(File pathname) { } /* package */ - synchronized Bundle deploy(Resource resource) { - final Resolver resolver = getRepositoryAdmin().resolver(getRepositories()); - boolean resolved = resolve(resolver, resource); - if (resolved) { - final int flags = !deployOptionalRequirements ? Resolver.NO_OPTIONAL_RESOURCES : 0; - resolver.deploy(flags); - return getBundle(resource); - } else { - Reason[] reqs = resolver.getUnsatisfiedRequirements(); - logger.logp(Level.WARNING, "ObrHandler", "deploy", - "Unable to satisfy the requirements: {0}", new Object[]{Arrays.toString(reqs)}); - return null; + Bundle deploy(Resource resource) { + lock.lock(); + try { + final Resolver resolver = getRepositoryAdmin().resolver(getRepositories()); + boolean resolved = resolve(resolver, resource); + if (resolved) { + final int flags = !deployOptionalRequirements ? Resolver.NO_OPTIONAL_RESOURCES : 0; + resolver.deploy(flags); + return getBundle(resource); + } else { + Reason[] reqs = resolver.getUnsatisfiedRequirements(); + logger.logp(Level.WARNING, "ObrHandler", "deploy", + "Unable to satisfy the requirements: {0}", new Object[]{Arrays.toString(reqs)}); + return null; + } + } finally { + lock.unlock(); } } @@ -322,17 +339,22 @@ synchronized Bundle deploy(Resource resource) { } /* package */ - synchronized Bundle deploy(String name, String version) { - Resource resource = findResource(name, version); - if (resource == null) { - logger.logp(Level.INFO, "ObrHandler", "deploy", - "No resource matching name = {0} and version = {1} ", new Object[]{name, version}); - return null; - } - if (resource.isLocal()) { - return getBundle(resource); + Bundle deploy(String name, String version) { + lock.lock(); + try { + Resource resource = findResource(name, version); + if (resource == null) { + logger.logp(Level.INFO, "ObrHandler", "deploy", + "No resource matching name = {0} and version = {1} ", new Object[]{name, version}); + return null; + } + if (resource.isLocal()) { + return getBundle(resource); + } + return deploy(resource); + } finally { + lock.unlock(); } - return deploy(resource); } private Bundle getBundle(Resource resource) { diff --git a/pom.xml b/pom.xml index 163f71f7dd..af531ed68b 100644 --- a/pom.xml +++ b/pom.xml @@ -679,7 +679,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.1 + 3.5.2 org.apache.maven.plugins