Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor Fedorenko2014-08-18 00:26:02 -0400
committerIgor Fedorenko2014-08-18 00:26:02 -0400
commit601873ec322a27fdf1b785e00592b8db2e8892af (patch)
treed7e8dd59ddb93f6dfb0aaec0cc79229d38a6f5d3
parentd4cb56da64054930c176bffc6eb0308fcb843d13 (diff)
downloadm2e-core-601873ec322a27fdf1b785e00592b8db2e8892af.tar.gz
m2e-core-601873ec322a27fdf1b785e00592b8db2e8892af.tar.xz
m2e-core-601873ec322a27fdf1b785e00592b8db2e8892af.zip
441254 backported update patch to m2e
Change-Id: Iccea517d08e5101e25002a614ea185849a101535 Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
-rw-r--r--m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/codehaus/plexus/DefaultPlexusContainer.java35
-rw-r--r--m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/DefaultBeanLocator.java173
-rw-r--r--m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/RankedBindings.java185
-rw-r--r--m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/plexus/ClassRealmUtils.java142
4 files changed, 523 insertions, 12 deletions
diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/codehaus/plexus/DefaultPlexusContainer.java b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/codehaus/plexus/DefaultPlexusContainer.java
index da65437a..bbe47055 100644
--- a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/codehaus/plexus/DefaultPlexusContainer.java
+++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/codehaus/plexus/DefaultPlexusContainer.java
@@ -18,6 +18,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
@@ -113,7 +114,7 @@ public final class DefaultPlexusContainer
// Implementation fields
// ----------------------------------------------------------------------
- final Set<String> realmIds = new HashSet<String>();
+ final Map<String, Injector> realmsInjectors = new HashMap<String, Injector>();
final AtomicInteger plexusRank = new AtomicInteger();
@@ -154,7 +155,8 @@ public final class DefaultPlexusContainer
private final ClassWorld classWorld;
- private final ClassWorldListener realmCleaner = new ClassWorldListener() {
+ private final ClassWorldListener realmCleaner = new ClassWorldListener()
+ {
public void realmCreated( ClassRealm realm )
{
@@ -162,10 +164,17 @@ public final class DefaultPlexusContainer
public void realmDisposed( ClassRealm realm )
{
+ final Injector injector;
synchronized ( descriptorMap )
{
- realmIds.remove( realm.getId() );
+ injector = realmsInjectors.remove( realm.getId() );
+ }
+ if ( injector != null )
+ {
+ // igorf: could not find a way to avoid this deprecated call
+ qualifiedBeanLocator.remove( injector );
}
+ ClassRealmUtils.flushCaches( realm );
}
};
@@ -209,7 +218,6 @@ public final class DefaultPlexusContainer
plexusBeanManager = new PlexusLifecycleManager( Providers.of( context ), loggerManagerProvider, //
new SLF4JLoggerFactoryProvider() ); // SLF4J (optional)
- realmIds.add( containerRealm.getId() );
setLookupRealm( containerRealm );
final List<PlexusBeanModule> beanModules = new ArrayList<PlexusBeanModule>();
@@ -221,7 +229,8 @@ public final class DefaultPlexusContainer
try
{
- addPlexusInjector( beanModules, new BootModule( customModules ) );
+ realmsInjectors.put( containerRealm.getId(),
+ addPlexusInjector( beanModules, new BootModule( customModules ) ) );
}
catch ( final RuntimeException e )
{
@@ -466,16 +475,17 @@ public final class DefaultPlexusContainer
{
beanModules.add( new ComponentDescriptorBeanModule( space, descriptors ) );
}
- if ( realmIds.add( realm.getId() ) )
+ if ( !realmsInjectors.containsKey( realm.getId() ) )
{
beanModules.add( new PlexusXmlBeanModule( space, variables ) );
final BeanScanning local = BeanScanning.GLOBAL_INDEX == scanning ? BeanScanning.INDEX : scanning;
beanModules.add( new PlexusAnnotatedBeanModule( space, variables, local ) );
}
- }
- if ( !beanModules.isEmpty() )
- {
- addPlexusInjector( beanModules, customModules );
+ // igorf: this used to be outside of synchronized(descriptorMap){} block, not sure about implications
+ if ( !beanModules.isEmpty() )
+ {
+ realmsInjectors.put( realm.getId(), addPlexusInjector( beanModules, customModules ) );
+ }
}
}
catch ( final RuntimeException e )
@@ -486,7 +496,8 @@ public final class DefaultPlexusContainer
return null; // no-one actually seems to use or check the returned component list!
}
- public void addPlexusInjector( final List<? extends PlexusBeanModule> beanModules, final Module... customModules )
+ public Injector addPlexusInjector( final List<? extends PlexusBeanModule> beanModules,
+ final Module... customModules )
{
final List<Module> modules = new ArrayList<Module>();
@@ -495,7 +506,7 @@ public final class DefaultPlexusContainer
modules.add( new PlexusBindingModule( plexusBeanManager, beanModules ) );
modules.add( defaultsModule );
- Guice.createInjector( isAutoWiringEnabled ? new WireModule( modules ) : new MergedModule( modules ) );
+ return Guice.createInjector( isAutoWiringEnabled ? new WireModule( modules ) : new MergedModule( modules ) );
}
// ----------------------------------------------------------------------
diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/DefaultBeanLocator.java b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/DefaultBeanLocator.java
new file mode 100644
index 00000000..84fd772a
--- /dev/null
+++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/DefaultBeanLocator.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sisu.inject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.eclipse.sisu.BeanEntry;
+import org.eclipse.sisu.Mediator;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Default {@link MutableBeanLocator} that locates qualified beans across a dynamic group of {@link BindingPublisher}s.
+ */
+@Singleton
+@SuppressWarnings( { "rawtypes", "unchecked" } )
+public final class DefaultBeanLocator
+ implements MutableBeanLocator
+{
+ // ----------------------------------------------------------------------
+ // Implementation fields
+ // ----------------------------------------------------------------------
+
+ private final RankedSequence<BindingPublisher> publishers = new RankedSequence<BindingPublisher>();
+
+ private final ConcurrentMap<TypeLiteral, RankedBindings> cachedBindings = Soft.concurrentValues( 256, 8 );
+
+ // reverse mapping; can't use watcher as key since it may not be unique
+ private final Map<WatchedBeans, Object> cachedWatchers = Weak.values();
+
+ private final ImplicitBindings implicitBindings = new ImplicitBindings( publishers );
+
+ // ----------------------------------------------------------------------
+ // Public methods
+ // ----------------------------------------------------------------------
+
+ public Iterable<BeanEntry> locate( final Key key )
+ {
+ final TypeLiteral type = key.getTypeLiteral();
+ RankedBindings bindings = cachedBindings.get( type );
+ if ( null == bindings )
+ {
+ synchronized ( this )
+ {
+ bindings = new RankedBindings( type, publishers );
+ final RankedBindings oldBindings = cachedBindings.putIfAbsent( type, bindings );
+ if ( null != oldBindings )
+ {
+ bindings = oldBindings;
+ }
+ }
+ }
+ final boolean isImplicit = key.getAnnotationType() == null && TypeArguments.isImplicit( type );
+ return new LocatedBeans( key, bindings, isImplicit ? implicitBindings : null );
+ }
+
+ public synchronized void watch( final Key key, final Mediator mediator, final Object watcher )
+ {
+ final WatchedBeans beans = new WatchedBeans( key, mediator, watcher );
+ for ( final BindingPublisher p : publishers.snapshot() )
+ {
+ p.subscribe( beans );
+ }
+ cachedWatchers.put( beans, watcher );
+ }
+
+ public synchronized void add( final BindingPublisher publisher, final int rank )
+ {
+ if ( !publishers.contains( publisher ) )
+ {
+ Logs.trace( "Add publisher: {}", publisher, null );
+ publishers.insert( publisher, rank );
+ for ( final RankedBindings bindings : cachedBindings.values() )
+ {
+ bindings.add( publisher, rank );
+ }
+ for ( final WatchedBeans beans : cachedWatchers.keySet() )
+ {
+ publisher.subscribe( beans );
+ }
+ }
+ }
+
+ public synchronized void remove( final BindingPublisher publisher )
+ {
+ if ( publishers.remove( publisher ) )
+ {
+ Logs.trace( "Remove publisher: {}", publisher, null );
+ // igorf: I question the use of Soft.concurrentValues for cachedBindings.
+ // Seems over-engineered and does not correctly implement Map interface.
+ // entrySet().iterator().remove() does not modify the map for example
+ Map<TypeLiteral, RankedBindings> emptyBindings = new HashMap<TypeLiteral, RankedBindings>();
+ Iterator<Map.Entry<TypeLiteral, RankedBindings>> iter = cachedBindings.entrySet().iterator();
+ while ( iter.hasNext() )
+ {
+ final Entry<TypeLiteral, RankedBindings> entry = iter.next();
+ final RankedBindings bindings = entry.getValue();
+ bindings.remove( publisher );
+ if ( bindings.isEmpty() )
+ {
+ // iter.remove(); does nothing :-(
+ emptyBindings.put( entry.getKey(), entry.getValue() );
+ }
+ }
+ for ( Map.Entry<TypeLiteral, RankedBindings> entry : emptyBindings.entrySet() )
+ {
+ cachedBindings.remove( entry.getKey() );
+ }
+ for ( final WatchedBeans beans : cachedWatchers.keySet() )
+ {
+ publisher.unsubscribe( beans );
+ }
+ }
+ }
+
+ public synchronized void clear()
+ {
+ for ( final BindingPublisher p : publishers.snapshot() )
+ {
+ remove( p );
+ }
+ }
+
+ public void add( final Injector injector, final int rank )
+ {
+ add( new InjectorPublisher( injector, new DefaultRankingFunction( rank ) ), rank );
+ }
+
+ public void remove( final Injector injector )
+ {
+ remove( new InjectorPublisher( injector, null ) );
+ }
+
+ // ----------------------------------------------------------------------
+ // Implementation methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * Automatically publishes any {@link Injector} that contains a binding to this {@link BeanLocator}.
+ *
+ * @param injector The injector
+ */
+ @Inject
+ void autoPublish( final Injector injector )
+ {
+ staticAutoPublish( this, injector );
+ }
+
+ @Inject
+ static void staticAutoPublish( final MutableBeanLocator locator, final Injector injector )
+ {
+ final RankingFunction function = injector.getInstance( RankingFunction.class );
+ locator.add( new InjectorPublisher( injector, function ), function.maxRank() );
+ }
+}
diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/RankedBindings.java b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/RankedBindings.java
new file mode 100644
index 00000000..971763e2
--- /dev/null
+++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/inject/RankedBindings.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sisu.inject;
+
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.Iterator;
+
+import com.google.inject.Binding;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Ordered sequence of {@link Binding}s of a given type; subscribes to {@link BindingPublisher}s on demand.
+ */
+final class RankedBindings<T>
+ implements Iterable<Binding<T>>, BindingSubscriber<T>
+{
+ // ----------------------------------------------------------------------
+ // Implementation fields
+ // ----------------------------------------------------------------------
+
+ final transient RankedSequence<Binding<T>> bindings = new RankedSequence<Binding<T>>();
+
+ final transient TypeLiteral<T> type;
+
+ final transient RankedSequence<BindingPublisher> pendingPublishers;
+
+ final Collection<BeanCache<?, T>> cachedBeans = Weak.elements();
+
+ volatile int topRank = Integer.MAX_VALUE;
+
+ // ----------------------------------------------------------------------
+ // Constructors
+ // ----------------------------------------------------------------------
+
+ RankedBindings( final TypeLiteral<T> type, final RankedSequence<BindingPublisher> publishers )
+ {
+ this.type = type;
+ this.pendingPublishers = new RankedSequence<BindingPublisher>( publishers );
+ }
+
+ // ----------------------------------------------------------------------
+ // Public methods
+ // ----------------------------------------------------------------------
+
+ public TypeLiteral<T> type()
+ {
+ return type;
+ }
+
+ public void add( final Binding<T> binding, final int rank )
+ {
+ bindings.insert( binding, rank );
+ }
+
+ public void remove( final Binding<T> binding )
+ {
+ if ( bindings.removeThis( binding ) )
+ {
+ synchronized ( cachedBeans )
+ {
+ for ( final BeanCache<?, T> beans : cachedBeans )
+ {
+ beans.remove( binding );
+ }
+ }
+ }
+ }
+
+ public Iterable<Binding<T>> bindings()
+ {
+ return bindings.snapshot();
+ }
+
+ public Itr iterator()
+ {
+ return new Itr();
+ }
+
+ // ----------------------------------------------------------------------
+ // Local methods
+ // ----------------------------------------------------------------------
+
+ <Q extends Annotation> BeanCache<Q, T> newBeanCache()
+ {
+ final BeanCache<Q, T> beans = new BeanCache<Q, T>();
+ synchronized ( cachedBeans )
+ {
+ cachedBeans.add( beans );
+ }
+ return beans;
+ }
+
+ void add( final BindingPublisher publisher, final int rank )
+ {
+ /*
+ * No need to lock; ranked sequence is thread-safe.
+ */
+ pendingPublishers.insert( publisher, rank );
+ if ( rank > topRank )
+ {
+ topRank = rank;
+ }
+ }
+
+ void remove( final BindingPublisher publisher )
+ {
+ /*
+ * Lock just to prevent subscription race condition.
+ */
+ synchronized ( pendingPublishers )
+ {
+ if ( !pendingPublishers.remove( publisher ) )
+ {
+ publisher.unsubscribe( this );
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Implementation types
+ // ----------------------------------------------------------------------
+
+ /**
+ * {@link Binding} iterator that only subscribes to {@link BindingPublisher}s as required.
+ */
+ final class Itr
+ implements Iterator<Binding<T>>
+ {
+ // ----------------------------------------------------------------------
+ // Implementation fields
+ // ----------------------------------------------------------------------
+
+ private final RankedSequence<Binding<T>>.Itr itr = bindings.iterator();
+
+ // ----------------------------------------------------------------------
+ // Public methods
+ // ----------------------------------------------------------------------
+
+ public boolean hasNext()
+ {
+ int rank = topRank;
+ if ( rank > Integer.MIN_VALUE && rank > itr.peekNextRank() )
+ {
+ synchronized ( pendingPublishers )
+ {
+ while ( ( rank = pendingPublishers.topRank() ) > Integer.MIN_VALUE && rank > itr.peekNextRank() )
+ {
+ pendingPublishers.poll().subscribe( RankedBindings.this );
+ }
+ topRank = rank;
+ }
+ }
+ return itr.hasNext();
+ }
+
+ public Binding<T> next()
+ {
+ return itr.next();
+ }
+
+ public int rank()
+ {
+ return itr.rank();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public boolean isEmpty()
+ {
+ return bindings.isEmpty();
+ }
+}
diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/plexus/ClassRealmUtils.java b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/plexus/ClassRealmUtils.java
new file mode 100644
index 00000000..ae008c9c
--- /dev/null
+++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/sisu/plexus/ClassRealmUtils.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sisu.plexus;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.eclipse.sisu.inject.Weak;
+
+/**
+ * Utility methods for dealing with Plexus {@link ClassRealm}s.
+ */
+public final class ClassRealmUtils
+{
+ // ----------------------------------------------------------------------
+ // Static initialization
+ // ----------------------------------------------------------------------
+
+ static
+ {
+ boolean getImportRealmsSupported = true;
+ try
+ {
+ // support both old and new forms of Plexus class realms
+ ClassRealm.class.getDeclaredMethod( "getImportRealms" );
+ }
+ catch ( final Exception e )
+ {
+ getImportRealmsSupported = false;
+ }
+ catch ( final LinkageError e )
+ {
+ getImportRealmsSupported = false;
+ }
+ GET_IMPORT_REALMS_SUPPORTED = getImportRealmsSupported;
+ }
+
+ // ----------------------------------------------------------------------
+ // Constants
+ // ----------------------------------------------------------------------
+
+ private static final boolean GET_IMPORT_REALMS_SUPPORTED;
+
+ // ----------------------------------------------------------------------
+ // Constructors
+ // ----------------------------------------------------------------------
+
+ private ClassRealmUtils()
+ {
+ // static utility class, not allowed to create instances
+ }
+
+ // ----------------------------------------------------------------------
+ // Implementation fields
+ // ----------------------------------------------------------------------
+
+ private static Map<ClassRealm, Set<String>> namesCache = Weak.concurrentKeys();
+
+ // ----------------------------------------------------------------------
+ // Utility methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * @return Current context realm
+ */
+ public static ClassRealm contextRealm()
+ {
+ for ( ClassLoader tccl = Thread.currentThread().getContextClassLoader(); tccl != null; tccl = tccl.getParent() )
+ {
+ if ( tccl instanceof ClassRealm )
+ {
+ return (ClassRealm) tccl;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Walks the {@link ClassRealm} import graph to find all realms visible from the given realm.
+ *
+ * @param contextRealm The initial realm
+ * @return Names of all realms visible from the given realm
+ */
+ public static Set<String> visibleRealmNames( final ClassRealm contextRealm )
+ {
+ if ( GET_IMPORT_REALMS_SUPPORTED && null != contextRealm )
+ {
+ Set<String> names = namesCache.get( contextRealm );
+ if ( null == names )
+ {
+ namesCache.put( contextRealm, names = computeVisibleNames( contextRealm ) );
+ }
+ return names;
+ }
+ return null;
+ }
+
+ public static void flushCaches( final ClassRealm realm )
+ {
+ // igorf: static caches are almost never a good idea. consider moving the cache to a component
+ namesCache.remove( realm );
+ }
+
+ // ----------------------------------------------------------------------
+ // Implementation methods
+ // ----------------------------------------------------------------------
+
+ @SuppressWarnings( "unchecked" )
+ private static Set<String> computeVisibleNames( final ClassRealm forRealm )
+ {
+ final Set<String> visibleRealmNames = new HashSet<String>();
+ final List<ClassRealm> searchRealms = new ArrayList<ClassRealm>();
+
+ searchRealms.add( forRealm );
+ for ( int i = 0; i < searchRealms.size(); i++ )
+ {
+ final ClassRealm realm = searchRealms.get( i );
+ if ( visibleRealmNames.add( realm.toString() ) )
+ {
+ searchRealms.addAll( realm.getImportRealms() );
+ final ClassRealm parent = realm.getParentRealm();
+ if ( null != parent )
+ {
+ searchRealms.add( parent );
+ }
+ }
+ }
+ return visibleRealmNames;
+ }
+}

Back to the top