From a5f49900f21a7f460aa43c1c59fd5d575722e011 Mon Sep 17 00:00:00 2001 From: John Dennis Casey Date: Fri, 29 Feb 2008 22:58:00 +0000 Subject: [PATCH] Adding the beginnings of a workspace to Maven, which is just a shared cache component for project, model, and POM file instances (for now). This allows fine-grained control over when such caches are cleared in environments where embedder instances may be reused multiple times, and will eventually enable new profile activators that require access to project information in the current build along with other advanced caching and cache-querying features. git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@632482 13f79535-47bb-0310-9956-ffa450edef68 --- maven-core/pom.xml | 5 + .../DefaultMavenExecutionRequest.java | 14 + .../execution/MavenExecutionRequest.java | 4 + .../lifecycle/DefaultLifecycleExecutor.java | 5 +- .../AbstractEmbedderLifecycleMonitor.java | 62 ++++ .../event/AbstractWorkspaceMonitor.java | 25 ++ .../event/MavenEmbedderLifecycleMonitor.java | 16 + .../monitor/event/MavenWorkspaceMonitor.java | 13 + .../event/PerCallWorkspaceMonitor.java | 23 ++ .../DefaultExtensionManagerTest.java | 3 + .../embedder/cache/CacheCleanerAspect.aj | 43 +-- .../event/EmbedderEventDispatcherAspect.aj | 61 ++++ .../apache/maven/embedder/Configuration.java | 15 + .../maven/embedder/DefaultConfiguration.java | 43 ++- .../apache/maven/embedder/MavenEmbedder.java | 15 + ...DefaultMavenExecutionRequestPopulator.java | 63 ++++ .../resources/META-INF/plexus/components.xml | 3 + .../eventing-projects/read-with-deps/pom.xml | 15 + .../read-with-deps/repo/tests/dep/1/dep-1.pom | 6 + .../simple-read-project/pom.xml | 6 + .../embedder/MavenEmbedderEventingTest.java | 261 ++++++++++++++++ maven-project/pom.xml | 5 + .../project/aspect/ProjectCacheAspect.aj | 84 ++--- .../project/DefaultMavenProjectBuilder.java | 4 + .../project/artifact/MavenMetadataSource.java | 20 +- .../model/DefaultModelLineageBuilder.java | 4 +- .../project/build/model/ModelAndFile.java | 2 +- .../workspace/DefaultProjectWorkspace.java | 148 +++++++++ .../project/workspace/ProjectWorkspace.java | 32 ++ .../resources/META-INF/plexus/components.xml | 17 ++ .../DefaultProjectWorkspaceTest.java | 83 +++++ .../workspace/ModelAndFileCachingTest.java | 234 ++++++++++++++ .../project/workspace/ProjectCachingTest.java | 286 ++++++++++++++++++ .../maven/project/ProjectClasspathTest.xml | 3 + .../canonical/CanonicalProjectBuilderTest.xml | 3 + .../project/workspace/buildFromFile/pom.xml | 8 + .../project-caching/1/project-caching-1.pom | 8 + .../project-caching/maven-metadata-local.xml | 11 + .../workspace/buildModelLineage/pom.xml | 7 + .../childAndParent/child/pom.xml | 10 + .../resolveParentPom/childAndParent/pom.xml | 7 + .../workspace/resolveParentPom/pom.xml | 10 + maven-workspace/pom.xml | 17 ++ .../workspace/DefaultMavenWorkspaceStore.java | 66 ++++ .../maven/workspace/MavenWorkspaceStore.java | 14 + .../resources/META-INF/plexus/components.xml | 9 + pom.xml | 1 + 47 files changed, 1678 insertions(+), 116 deletions(-) create mode 100644 maven-core/src/main/java/org/apache/maven/monitor/event/AbstractEmbedderLifecycleMonitor.java create mode 100644 maven-core/src/main/java/org/apache/maven/monitor/event/AbstractWorkspaceMonitor.java create mode 100644 maven-core/src/main/java/org/apache/maven/monitor/event/MavenEmbedderLifecycleMonitor.java create mode 100644 maven-core/src/main/java/org/apache/maven/monitor/event/MavenWorkspaceMonitor.java create mode 100644 maven-core/src/main/java/org/apache/maven/monitor/event/PerCallWorkspaceMonitor.java create mode 100644 maven-embedder/src/main/aspect/org/apache/maven/embedder/event/EmbedderEventDispatcherAspect.aj create mode 100644 maven-embedder/src/test/eventing-projects/read-with-deps/pom.xml create mode 100644 maven-embedder/src/test/eventing-projects/read-with-deps/repo/tests/dep/1/dep-1.pom create mode 100644 maven-embedder/src/test/eventing-projects/simple-read-project/pom.xml create mode 100644 maven-embedder/src/test/java/org/apache/maven/embedder/MavenEmbedderEventingTest.java create mode 100644 maven-project/src/main/java/org/apache/maven/project/workspace/DefaultProjectWorkspace.java create mode 100644 maven-project/src/main/java/org/apache/maven/project/workspace/ProjectWorkspace.java create mode 100644 maven-project/src/test/java/org/apache/maven/project/workspace/DefaultProjectWorkspaceTest.java create mode 100644 maven-project/src/test/java/org/apache/maven/project/workspace/ModelAndFileCachingTest.java create mode 100644 maven-project/src/test/java/org/apache/maven/project/workspace/ProjectCachingTest.java create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromFile/pom.xml create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/1/project-caching-1.pom create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/maven-metadata-local.xml create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/buildModelLineage/pom.xml create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/child/pom.xml create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/pom.xml create mode 100644 maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/pom.xml create mode 100644 maven-workspace/pom.xml create mode 100644 maven-workspace/src/main/java/org/apache/maven/workspace/DefaultMavenWorkspaceStore.java create mode 100644 maven-workspace/src/main/java/org/apache/maven/workspace/MavenWorkspaceStore.java create mode 100644 maven-workspace/src/main/resources/META-INF/plexus/components.xml diff --git a/maven-core/pom.xml b/maven-core/pom.xml index da100be1e1..70d5a0b1c6 100644 --- a/maven-core/pom.xml +++ b/maven-core/pom.xml @@ -31,6 +31,11 @@ under the License. maven-core Maven Core + + org.apache.maven + maven-workspace + 2.1-SNAPSHOT + org.apache.maven maven-lifecycle diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java index 93b2d62811..d87f4e07d1 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java @@ -22,6 +22,7 @@ package org.apache.maven.execution; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.errors.CoreErrorReporter; import org.apache.maven.monitor.event.EventMonitor; +import org.apache.maven.monitor.event.MavenWorkspaceMonitor; import org.apache.maven.profiles.ProfileManager; import org.apache.maven.profiles.activation.ProfileActivationContext; import org.apache.maven.realm.MavenRealmManager; @@ -97,6 +98,8 @@ public class DefaultMavenExecutionRequest private List eventMonitors; + private MavenWorkspaceMonitor workspaceMonitor; + private List activeProfiles; private List inactiveProfiles; @@ -694,4 +697,15 @@ public class DefaultMavenExecutionRequest this.profileActivationContext = profileActivationContext; return this; } + + public MavenWorkspaceMonitor getWorkspaceMonitor() + { + return workspaceMonitor; + } + + public MavenExecutionRequest setWorkspaceMonitor( MavenWorkspaceMonitor workspaceMonitor ) + { + this.workspaceMonitor = workspaceMonitor; + return this; + } } diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java index ae43d37ae6..9706eed8b6 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java @@ -23,6 +23,7 @@ import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; import org.apache.maven.errors.CoreErrorReporter; import org.apache.maven.monitor.event.EventMonitor; +import org.apache.maven.monitor.event.MavenWorkspaceMonitor; import org.apache.maven.profiles.ProfileManager; import org.apache.maven.profiles.activation.ProfileActivationContext; import org.apache.maven.realm.MavenRealmManager; @@ -216,4 +217,7 @@ public interface MavenExecutionRequest MavenExecutionRequest setErrorReporter( CoreErrorReporter reporter ); CoreErrorReporter getErrorReporter(); + + MavenExecutionRequest setWorkspaceMonitor( MavenWorkspaceMonitor workspaceMonitor ); + MavenWorkspaceMonitor getWorkspaceMonitor(); } diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java index 2810f60bd3..6e9ecbe21b 100644 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java +++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java @@ -305,7 +305,10 @@ public class DefaultLifecycleExecutor } } - dispatcher.dispatchEnd( MavenEvents.PHASE_EXECUTION, currentPhase ); + if ( currentPhase != null ) + { + dispatcher.dispatchEnd( MavenEvents.PHASE_EXECUTION, currentPhase ); + } } finally { diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/AbstractEmbedderLifecycleMonitor.java b/maven-core/src/main/java/org/apache/maven/monitor/event/AbstractEmbedderLifecycleMonitor.java new file mode 100644 index 0000000000..93e9d990d5 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/monitor/event/AbstractEmbedderLifecycleMonitor.java @@ -0,0 +1,62 @@ +package org.apache.maven.monitor.event; + + +public abstract class AbstractEmbedderLifecycleMonitor + extends AbstractSelectiveEventMonitor implements MavenEmbedderLifecycleMonitor +{ + + public static final String[] EMBEDDER_LIFECYCLE_EVENTS = { + MavenEvents.EMBEDDER_LIFECYCLE, + MavenEvents.EMBEDDER_METHOD + }; + + protected AbstractEmbedderLifecycleMonitor() + { + super( EMBEDDER_LIFECYCLE_EVENTS, EMBEDDER_LIFECYCLE_EVENTS, MavenEvents.NO_EVENTS ); + } + + public void embedderInitialized( long timestamp ) + { + } + + public void embedderStopped( long timestamp ) + { + } + + public void embedderMethodStarted( String method, long timestamp ) + { + } + + public void embedderMethodEnded( String method, long timestamp ) + { + } + + protected void doEndEvent( String eventName, + String target, + long timestamp ) + { + if ( MavenEvents.EMBEDDER_LIFECYCLE.equals( eventName ) ) + { + embedderStopped( timestamp ); + } + else if ( MavenEvents.EMBEDDER_METHOD.equals( eventName ) ) + { + embedderMethodEnded( target, timestamp ); + } + } + + protected void doStartEvent( String eventName, + String target, + long timestamp ) + { + if ( MavenEvents.EMBEDDER_LIFECYCLE.equals( eventName ) ) + { + embedderInitialized( timestamp ); + } + else if ( MavenEvents.EMBEDDER_METHOD.equals( eventName ) ) + { + embedderMethodStarted( target, timestamp ); + } + } + +} diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/AbstractWorkspaceMonitor.java b/maven-core/src/main/java/org/apache/maven/monitor/event/AbstractWorkspaceMonitor.java new file mode 100644 index 0000000000..91c7538686 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/monitor/event/AbstractWorkspaceMonitor.java @@ -0,0 +1,25 @@ +package org.apache.maven.monitor.event; + +import org.apache.maven.workspace.MavenWorkspaceStore; + +public abstract class AbstractWorkspaceMonitor + extends AbstractEmbedderLifecycleMonitor + implements MavenWorkspaceMonitor +{ + + private MavenWorkspaceStore workspaceManager; + + public void setWorkspaceStore( MavenWorkspaceStore workspaceManager ) + { + this.workspaceManager = workspaceManager; + } + + /* (non-Javadoc) + * @see org.apache.maven.embedder.lifecycle.MavenWorkspaceMonitor#clearCache() + */ + public void clearCache() + { + workspaceManager.clear(); + } + +} \ No newline at end of file diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/MavenEmbedderLifecycleMonitor.java b/maven-core/src/main/java/org/apache/maven/monitor/event/MavenEmbedderLifecycleMonitor.java new file mode 100644 index 0000000000..665630f0b7 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/monitor/event/MavenEmbedderLifecycleMonitor.java @@ -0,0 +1,16 @@ +package org.apache.maven.monitor.event; + +public interface MavenEmbedderLifecycleMonitor +{ + + public void embedderInitialized( long timestamp ); + + public void embedderStopped( long timestamp ); + + public void embedderMethodStarted( String method, + long timestamp ); + + public void embedderMethodEnded( String method, + long timestamp ); + +} \ No newline at end of file diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/MavenWorkspaceMonitor.java b/maven-core/src/main/java/org/apache/maven/monitor/event/MavenWorkspaceMonitor.java new file mode 100644 index 0000000000..c0cbc84ccd --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/monitor/event/MavenWorkspaceMonitor.java @@ -0,0 +1,13 @@ +package org.apache.maven.monitor.event; + +import org.apache.maven.workspace.MavenWorkspaceStore; + +public interface MavenWorkspaceMonitor + extends EventMonitor +{ + + void setWorkspaceStore( MavenWorkspaceStore workspaceStore ); + + void clearCache(); + +} diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/PerCallWorkspaceMonitor.java b/maven-core/src/main/java/org/apache/maven/monitor/event/PerCallWorkspaceMonitor.java new file mode 100644 index 0000000000..e0aea4fd87 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/monitor/event/PerCallWorkspaceMonitor.java @@ -0,0 +1,23 @@ +package org.apache.maven.monitor.event; + + + +public class PerCallWorkspaceMonitor + extends AbstractWorkspaceMonitor +{ + + public void embedderMethodEnded( String method, + long timestamp ) + { + clearCache(); + } + + // Be double-sure that the cache is cleared when the embedder stops. + public void embedderStopped( long timestamp ) + { + clearCache(); + } + + + +} diff --git a/maven-core/src/test/java/org/apache/maven/extension/DefaultExtensionManagerTest.java b/maven-core/src/test/java/org/apache/maven/extension/DefaultExtensionManagerTest.java index 7837afb0fd..e8f8451ade 100644 --- a/maven-core/src/test/java/org/apache/maven/extension/DefaultExtensionManagerTest.java +++ b/maven-core/src/test/java/org/apache/maven/extension/DefaultExtensionManagerTest.java @@ -102,6 +102,7 @@ public class DefaultExtensionManagerTest public void test_addExtension_usingModel_ShouldLoadExtensionComponent() throws Exception { + System.out.println( "\n\n\n\n\n\n\nSTART\n\n" ); File remoteRepoDir = findRemoteRepositoryDirectory(); File localRepo = createTempDir(); @@ -147,6 +148,8 @@ public class DefaultExtensionManagerTest assertNotNull( result ); getContainer().setLookupRealm( oldRealm ); + + System.out.println( "\n\nEND\n\n\n\n\n\n\n" ); } public void test_addExtension_usingModel_ShouldLoadCustomLifecycleMappingAndArtifactHandler() diff --git a/maven-embedder/src/main/aspect/org/apache/maven/embedder/cache/CacheCleanerAspect.aj b/maven-embedder/src/main/aspect/org/apache/maven/embedder/cache/CacheCleanerAspect.aj index b86f81e487..516230f00b 100644 --- a/maven-embedder/src/main/aspect/org/apache/maven/embedder/cache/CacheCleanerAspect.aj +++ b/maven-embedder/src/main/aspect/org/apache/maven/embedder/cache/CacheCleanerAspect.aj @@ -1,39 +1,11 @@ package org.apache.maven.embedder.cache; -import org.apache.maven.project.MavenProjectBuilder; -import org.apache.maven.project.DefaultMavenProjectBuilder; -import org.apache.maven.project.build.model.DefaultModelLineageBuilder; -import org.apache.maven.project.build.model.ModelLineageBuilder; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.embedder.MavenEmbedder; -import org.apache.maven.embedder.MavenEmbedderException; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; public privileged aspect CacheCleanerAspect { - private ModelLineageBuilder MavenEmbedder.modelLineageBuilder; - - private pointcut embedderStarted( MavenEmbedder embedder ): - execution( * MavenEmbedder.start( .. ) ) - && this( embedder ); - - void around( MavenEmbedder embedder ) - throws MavenEmbedderException: - embedderStarted( embedder ) - { - proceed( embedder ); - - try - { - embedder.modelLineageBuilder = (ModelLineageBuilder) embedder.container.lookup( ModelLineageBuilder.ROLE ); - } - catch ( ComponentLookupException e ) - { - throw new MavenEmbedderException( "Cannot lookup required component.", e ); - } - } - private pointcut requestAsLastParam( MavenExecutionRequest request, MavenEmbedder embedder ): execution( * MavenEmbedder.*( .., MavenExecutionRequest ) ) && args( .., request ) @@ -56,20 +28,9 @@ public privileged aspect CacheCleanerAspect private void cleanup( MavenExecutionRequest request, MavenEmbedder embedder ) { + // TODO: Add this to the eventing-control mechanism that the workspace uses now, + // once we can accommodate context in the event method calls. request.clearAccumulatedBuildState(); - - MavenProjectBuilder projectBuilder = embedder.mavenProjectBuilder; - ModelLineageBuilder lineageBuilder = embedder.modelLineageBuilder; - - if ( projectBuilder instanceof DefaultMavenProjectBuilder ) - { - ((DefaultMavenProjectBuilder) projectBuilder).clearProjectCache(); - } - - if ( lineageBuilder instanceof DefaultModelLineageBuilder ) - { - ((DefaultModelLineageBuilder) lineageBuilder).clearModelAndFileCache(); - } } } diff --git a/maven-embedder/src/main/aspect/org/apache/maven/embedder/event/EmbedderEventDispatcherAspect.aj b/maven-embedder/src/main/aspect/org/apache/maven/embedder/event/EmbedderEventDispatcherAspect.aj new file mode 100644 index 0000000000..16fc9db852 --- /dev/null +++ b/maven-embedder/src/main/aspect/org/apache/maven/embedder/event/EmbedderEventDispatcherAspect.aj @@ -0,0 +1,61 @@ +package org.apache.maven.embedder.event; + +import org.apache.maven.monitor.event.MavenEvents; +import org.apache.maven.embedder.MavenEmbedder; +import org.apache.maven.execution.MavenExecutionRequest; + +public privileged aspect EmbedderEventDispatcherAspect +{ + + after( MavenEmbedder embedder ): execution( * MavenEmbedder.start( .. ) ) && this( embedder ) + { + if ( embedder.dispatcher != null ) + { + embedder.dispatcher.dispatchStart( MavenEvents.EMBEDDER_LIFECYCLE, "" ); + } + } + + before( MavenEmbedder embedder ): execution( * MavenEmbedder.stop( .. ) ) && this( embedder ) + { + if ( embedder.dispatcher != null ) + { + embedder.dispatcher.dispatchEnd( MavenEvents.EMBEDDER_LIFECYCLE, "" ); + } + } + + private pointcut eventedMethods( MavenEmbedder embedder ): + ( + execution( * MavenEmbedder.*( .., MavenExecutionRequest ) ) + || execution( * MavenEmbedder.*( MavenExecutionRequest ) ) + || execution( * MavenEmbedder.*( MavenExecutionRequest, .. ) ) + || execution( * MavenEmbedder.resolve( .. ) ) + || execution( * MavenEmbedder.readProject( .. ) ) + || execution( * MavenEmbedder.verifyPlugin( .. ) ) + ) + && this( embedder ); + + before( MavenEmbedder embedder ): + eventedMethods( embedder ) + && !cflowbelow( eventedMethods( MavenEmbedder ) ) + { + if ( embedder.dispatcher != null ) + { + String target = thisJoinPointStaticPart.getSignature().getName(); + + embedder.dispatcher.dispatchStart( MavenEvents.EMBEDDER_METHOD, target ); + } + } + + after( MavenEmbedder embedder ): + eventedMethods( embedder ) + && !cflowbelow( eventedMethods( MavenEmbedder ) ) + { + if ( embedder.dispatcher != null ) + { + String target = thisJoinPointStaticPart.getSignature().getName(); + + embedder.dispatcher.dispatchEnd( MavenEvents.EMBEDDER_METHOD, target ); + } + } + +} diff --git a/maven-embedder/src/main/java/org/apache/maven/embedder/Configuration.java b/maven-embedder/src/main/java/org/apache/maven/embedder/Configuration.java index 92dafa58ad..ae5d8e976e 100644 --- a/maven-embedder/src/main/java/org/apache/maven/embedder/Configuration.java +++ b/maven-embedder/src/main/java/org/apache/maven/embedder/Configuration.java @@ -19,6 +19,8 @@ package org.apache.maven.embedder; */ import org.apache.maven.errors.CoreErrorReporter; +import org.apache.maven.monitor.event.EventMonitor; +import org.apache.maven.monitor.event.MavenWorkspaceMonitor; import org.apache.maven.realm.MavenRealmManager; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.classworlds.ClassWorld; @@ -141,4 +143,17 @@ public interface Configuration CoreErrorReporter getErrorReporter(); + // ---------------------------------------------------------------------------- + // Event Monitors + // ---------------------------------------------------------------------------- + + Configuration addEventMonitor( EventMonitor eventMonitor ); + + Configuration setEventMonitors( List eventMonitors ); + + List getEventMonitors(); + + Configuration setWorkspaceMonitor( MavenWorkspaceMonitor workspaceMonitor ); + + MavenWorkspaceMonitor getWorkspaceMonitor(); } diff --git a/maven-embedder/src/main/java/org/apache/maven/embedder/DefaultConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/embedder/DefaultConfiguration.java index 6d5250ce9f..2ecc3156e3 100644 --- a/maven-embedder/src/main/java/org/apache/maven/embedder/DefaultConfiguration.java +++ b/maven-embedder/src/main/java/org/apache/maven/embedder/DefaultConfiguration.java @@ -19,6 +19,8 @@ package org.apache.maven.embedder; */ import org.apache.maven.errors.CoreErrorReporter; +import org.apache.maven.monitor.event.EventMonitor; +import org.apache.maven.monitor.event.MavenWorkspaceMonitor; import org.apache.maven.realm.MavenRealmManager; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.classworlds.ClassWorld; @@ -49,7 +51,7 @@ public class DefaultConfiguration private Properties systemProperties; - /** List<URL>. */ + /** List<URL>. */ private List extensions = new ArrayList(); private MavenEmbedderLogger logger; @@ -64,6 +66,11 @@ public class DefaultConfiguration private CoreErrorReporter errorReporter; + /** List<EventMonitor>. */ + private List eventMonitors; + + private MavenWorkspaceMonitor workspaceMonitor; + /** Creates a new instance of DefaultConfiguration */ public DefaultConfiguration() { @@ -246,4 +253,38 @@ public class DefaultConfiguration this.errorReporter = errorReporter; return this; } + + public Configuration addEventMonitor( EventMonitor eventMonitor ) + { + if ( eventMonitors == null ) + { + eventMonitors = new ArrayList(); + } + + eventMonitors.add( eventMonitor ); + + return this; + } + + public List getEventMonitors() + { + return eventMonitors; + } + + public Configuration setEventMonitors( List eventMonitors ) + { + this.eventMonitors = eventMonitors; + return this; + } + + public MavenWorkspaceMonitor getWorkspaceMonitor() + { + return workspaceMonitor; + } + + public Configuration setWorkspaceMonitor( MavenWorkspaceMonitor workspaceMonitor ) + { + this.workspaceMonitor = workspaceMonitor; + return this; + } } diff --git a/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java b/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java index 8ca2629d0d..61da51695f 100644 --- a/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java +++ b/maven-embedder/src/main/java/org/apache/maven/embedder/MavenEmbedder.java @@ -74,6 +74,7 @@ import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer; import org.apache.maven.settings.validation.DefaultSettingsValidator; import org.apache.maven.settings.validation.SettingsValidationResult; import org.apache.maven.settings.validation.SettingsValidator; +import org.apache.maven.workspace.MavenWorkspaceStore; import org.codehaus.plexus.ContainerConfiguration; import org.codehaus.plexus.DefaultContainerConfiguration; import org.codehaus.plexus.DefaultPlexusContainer; @@ -164,6 +165,9 @@ public class MavenEmbedder private BuildPlanner buildPlanner; + // TODO: Remove this once we have better control over cache-cleaning. + private MavenWorkspaceStore workspaceStore; + // ---------------------------------------------------------------------- // Configuration // ---------------------------------------------------------------------- @@ -197,6 +201,11 @@ public class MavenEmbedder return request; } + protected MavenWorkspaceStore getWorkspaceStore() + { + return workspaceStore; + } + // ---------------------------------------------------------------------- // Accessors // ---------------------------------------------------------------------- @@ -596,6 +605,8 @@ public class MavenEmbedder private MavenExecutionRequest request; + private EventDispatcher dispatcher; + private void start( Configuration configuration ) throws MavenEmbedderException { @@ -690,6 +701,8 @@ public class MavenEmbedder buildPlanner = (BuildPlanner) container.lookup( BuildPlanner.class ); + workspaceStore = (MavenWorkspaceStore) container.lookup( MavenWorkspaceStore.class ); + artifactHandlerManager = (ArtifactHandlerManager) container.lookup( ArtifactHandlerManager.ROLE ); // This is temporary as we can probably cache a single request and use it for default values and @@ -697,6 +710,8 @@ public class MavenEmbedder request = new DefaultMavenExecutionRequest(); populator.populateDefaults( request, configuration ); + + dispatcher = new DefaultEventDispatcher( request.getEventMonitors() ); } catch ( ComponentLookupException e ) { diff --git a/maven-embedder/src/main/java/org/apache/maven/embedder/execution/DefaultMavenExecutionRequestPopulator.java b/maven-embedder/src/main/java/org/apache/maven/embedder/execution/DefaultMavenExecutionRequestPopulator.java index 80fc6a7321..6f98f842a5 100644 --- a/maven-embedder/src/main/java/org/apache/maven/embedder/execution/DefaultMavenExecutionRequestPopulator.java +++ b/maven-embedder/src/main/java/org/apache/maven/embedder/execution/DefaultMavenExecutionRequestPopulator.java @@ -33,6 +33,9 @@ import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.model.Profile; import org.apache.maven.model.Repository; import org.apache.maven.monitor.event.DefaultEventMonitor; +import org.apache.maven.monitor.event.EventMonitor; +import org.apache.maven.monitor.event.MavenWorkspaceMonitor; +import org.apache.maven.monitor.event.PerCallWorkspaceMonitor; import org.apache.maven.plugin.Mojo; import org.apache.maven.profiles.DefaultProfileManager; import org.apache.maven.profiles.ProfileManager; @@ -47,6 +50,7 @@ import org.apache.maven.settings.Settings; import org.apache.maven.settings.SettingsConfigurationException; import org.apache.maven.settings.SettingsUtils; import org.apache.maven.wagon.repository.RepositoryPermissions; +import org.apache.maven.workspace.MavenWorkspaceStore; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException; @@ -92,12 +96,18 @@ public class DefaultMavenExecutionRequestPopulator private WagonManager wagonManager; + private MavenWorkspaceStore workspaceManager; + private MavenSettingsBuilder settingsBuilder; public MavenExecutionRequest populateDefaults( MavenExecutionRequest request, Configuration configuration ) throws MavenEmbedderException { + eventMonitors( request, configuration ); + + workspaceMonitor( request, configuration ); + reporter( request, configuration ); executionProperties( request, configuration ); @@ -128,6 +138,59 @@ public class DefaultMavenExecutionRequestPopulator return request; } + private void workspaceMonitor( MavenExecutionRequest request, + Configuration configuration ) + { + MavenWorkspaceMonitor workspaceMonitor = request.getWorkspaceMonitor(); + + if ( workspaceMonitor == null ) + { + workspaceMonitor = configuration.getWorkspaceMonitor(); + } + + List requestEventMonitors = request.getEventMonitors(); + if ( ( requestEventMonitors != null ) && !requestEventMonitors.isEmpty() ) + { + for ( Iterator it = requestEventMonitors.iterator(); it.hasNext(); ) + { + Object monitor = it.next(); + if ( monitor instanceof MavenWorkspaceMonitor ) + { + if ( workspaceMonitor == null ) + { + workspaceMonitor = (MavenWorkspaceMonitor) monitor; + } + it.remove(); + break; + } + } + } + + if ( workspaceMonitor == null ) + { + workspaceMonitor = new PerCallWorkspaceMonitor(); + } + + workspaceMonitor.setWorkspaceStore( workspaceManager ); + + request.addEventMonitor( workspaceMonitor ); + } + + private void eventMonitors( MavenExecutionRequest request, + Configuration configuration ) + { + List configEventMonitors = configuration.getEventMonitors(); + + if ( ( configEventMonitors != null ) && !configEventMonitors.isEmpty() ) + { + for ( Iterator it = configEventMonitors.iterator(); it.hasNext(); ) + { + EventMonitor monitor = (EventMonitor) it.next(); + request.addEventMonitor( monitor ); + } + } + } + private void reporter( MavenExecutionRequest request, Configuration configuration ) { diff --git a/maven-embedder/src/main/resources/META-INF/plexus/components.xml b/maven-embedder/src/main/resources/META-INF/plexus/components.xml index bc361da78a..ad55db36ed 100644 --- a/maven-embedder/src/main/resources/META-INF/plexus/components.xml +++ b/maven-embedder/src/main/resources/META-INF/plexus/components.xml @@ -23,6 +23,9 @@ under the License. org.apache.maven.embedder.execution.MavenExecutionRequestPopulator org.apache.maven.embedder.execution.DefaultMavenExecutionRequestPopulator + + org.apache.maven.workspace.MavenWorkspaceStore + org.apache.maven.artifact.manager.WagonManager default diff --git a/maven-embedder/src/test/eventing-projects/read-with-deps/pom.xml b/maven-embedder/src/test/eventing-projects/read-with-deps/pom.xml new file mode 100644 index 0000000000..4bbef519be --- /dev/null +++ b/maven-embedder/src/test/eventing-projects/read-with-deps/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + testing + read-with-deps + 1 + + + + tests + dep + 1 + pom + + + \ No newline at end of file diff --git a/maven-embedder/src/test/eventing-projects/read-with-deps/repo/tests/dep/1/dep-1.pom b/maven-embedder/src/test/eventing-projects/read-with-deps/repo/tests/dep/1/dep-1.pom new file mode 100644 index 0000000000..175bf21087 --- /dev/null +++ b/maven-embedder/src/test/eventing-projects/read-with-deps/repo/tests/dep/1/dep-1.pom @@ -0,0 +1,6 @@ + + 4.0.0 + testing + dep + 1 + \ No newline at end of file diff --git a/maven-embedder/src/test/eventing-projects/simple-read-project/pom.xml b/maven-embedder/src/test/eventing-projects/simple-read-project/pom.xml new file mode 100644 index 0000000000..9a3f6be472 --- /dev/null +++ b/maven-embedder/src/test/eventing-projects/simple-read-project/pom.xml @@ -0,0 +1,6 @@ + + 4.0.0 + testing + simple-read-project + 1 + \ No newline at end of file diff --git a/maven-embedder/src/test/java/org/apache/maven/embedder/MavenEmbedderEventingTest.java b/maven-embedder/src/test/java/org/apache/maven/embedder/MavenEmbedderEventingTest.java new file mode 100644 index 0000000000..af01b46b0c --- /dev/null +++ b/maven-embedder/src/test/java/org/apache/maven/embedder/MavenEmbedderEventingTest.java @@ -0,0 +1,261 @@ +package org.apache.maven.embedder; + +import org.apache.maven.execution.DefaultMavenExecutionRequest; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.extension.ExtensionScanningException; +import org.apache.maven.monitor.event.AbstractWorkspaceMonitor; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.reactor.MavenExecutionException; +import org.apache.maven.workspace.MavenWorkspaceStore; +import org.codehaus.plexus.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; + +import junit.framework.TestCase; + +public class MavenEmbedderEventingTest + extends TestCase +{ + + protected String basedir; + + protected void setUp() + throws Exception + { + super.setUp(); + + basedir = System.getProperty( "basedir" ); + + if ( basedir == null ) + { + basedir = new File( "." ).getCanonicalPath(); + } + } + + public void testEmbedderInitializeAndStopEventsFired() + throws MavenEmbedderException + { + TestWorkspaceMonitor testWSMonitor = new TestWorkspaceMonitor(); + + Configuration config = new DefaultConfiguration(); + config.setWorkspaceMonitor( testWSMonitor ); + + assertEquals( 0, testWSMonitor.initializeCaught ); + assertEquals( 0, testWSMonitor.setManagerCaught ); + + MavenEmbedder embedder = new MavenEmbedder( config ); + + assertEquals( 1, testWSMonitor.initializeCaught ); + assertEquals( 1, testWSMonitor.setManagerCaught ); + + assertEquals( 0, testWSMonitor.stopCaught ); + assertEquals( 0, testWSMonitor.clearCaught ); + + assertSame( embedder.getWorkspaceStore(), testWSMonitor.workspaceManager ); + + embedder.stop(); + + assertEquals( 1, testWSMonitor.stopCaught ); + assertEquals( 1, testWSMonitor.clearCaught ); + + assertEquals( 0, testWSMonitor.startMethodCaught ); + assertEquals( 0, testWSMonitor.endMethodCaught ); + } + + public void testStartAndEndMethodEventsFiredOnSimpleReadProject() + throws IOException, MavenEmbedderException, ProjectBuildingException, + ExtensionScanningException, MavenExecutionException + { + EmbedderAndMonitor em = newEmbedder(); + + assertEquals( 0, em.monitor.startMethodCaught ); + assertEquals( 0, em.monitor.endMethodCaught ); + + File dir = getFile( "simple-read-project" ); + File pomFile = new File( dir, "pom.xml" ); + + em.embedder.readProject( pomFile ); + + assertEquals( 1, em.monitor.startMethodCaught ); + assertEquals( 1, em.monitor.endMethodCaught ); + assertEquals( 1, em.monitor.clearCaught ); + + assertSame( em.embedder.getWorkspaceStore(), em.monitor.workspaceManager ); + + em.embedder.stop(); + } + + public void testStartAndEndMethodEventsFiredOnReadWithDeps() + throws IOException, MavenEmbedderException, ProjectBuildingException, + ExtensionScanningException, MavenExecutionException + { + File dir = getFile( "read-with-deps" ); + File pomFile = new File( dir, "pom.xml" ); + File localRepoDir = new File( dir, "repo" ); + + EmbedderAndMonitor em = newEmbedder( localRepoDir ); + + assertEquals( 0, em.monitor.startMethodCaught ); + assertEquals( 0, em.monitor.endMethodCaught ); + + em.embedder.readProject( pomFile ); + + assertEquals( 1, em.monitor.startMethodCaught ); + assertEquals( 1, em.monitor.endMethodCaught ); + assertEquals( 1, em.monitor.clearCaught ); + + assertSame( em.embedder.getWorkspaceStore(), em.monitor.workspaceManager ); + + em.embedder.stop(); + } + + public void testStartAndEndMethodEventsFiredOnExecute() + throws IOException, MavenEmbedderException, ProjectBuildingException, + ExtensionScanningException, MavenExecutionException + { + EmbedderAndMonitor em = newEmbedder(); + + assertEquals( 0, em.monitor.startMethodCaught ); + assertEquals( 0, em.monitor.endMethodCaught ); + + File dir = getFile( "simple-read-project" ); + + MavenExecutionRequest request = new DefaultMavenExecutionRequest(); + request.setGoals( Collections.singletonList( "clean" ) ); + request.setBaseDirectory( dir ); + + em.embedder.execute( request ); + + assertEquals( 1, em.monitor.startMethodCaught ); + assertEquals( 1, em.monitor.endMethodCaught ); + assertEquals( 1, em.monitor.clearCaught ); + + assertSame( em.embedder.getWorkspaceStore(), em.monitor.workspaceManager ); + + em.embedder.stop(); + } + + private EmbedderAndMonitor newEmbedder() + throws MavenEmbedderException + { + return newEmbedder( null ); + } + + private EmbedderAndMonitor newEmbedder( File localRepoDir ) + throws MavenEmbedderException + { + TestWorkspaceMonitor testWSMonitor = new TestWorkspaceMonitor(); + + Configuration config = new DefaultConfiguration(); + config.setWorkspaceMonitor( testWSMonitor ); + config.setMavenEmbedderLogger( new MavenEmbedderConsoleLogger() ); + + if ( localRepoDir != null ) + { + config.setLocalRepository( localRepoDir ); + } + + return new EmbedderAndMonitor( new MavenEmbedder( config ), testWSMonitor ); + } + + private static final class EmbedderAndMonitor + { + private MavenEmbedder embedder; + + private TestWorkspaceMonitor monitor; + + private EmbedderAndMonitor( MavenEmbedder embedder, + TestWorkspaceMonitor monitor ) + { + this.embedder = embedder; + this.monitor = monitor; + } + } + + private File getFile( String path ) + throws IOException + { + File testDirectory = new File( basedir, "src/test/eventing-projects/" + path ); + + System.out.println( "Test source dir: " + testDirectory ); + + File targetDirectory = new File( basedir, "target/eventing-projects/" + path ); + + System.out.println( "Test temp dir: " + targetDirectory ); + + targetDirectory.getParentFile().mkdirs(); + + FileUtils.copyDirectoryStructure( testDirectory, targetDirectory ); + + return targetDirectory; + } + + private static final class TestWorkspaceMonitor + extends AbstractWorkspaceMonitor + { + + private int initializeCaught = 0; + + private int startMethodCaught = 0; + + private int endMethodCaught = 0; + + private int stopCaught = 0; + + private int setManagerCaught = 0; + + private int clearCaught = 0; + + private MavenWorkspaceStore workspaceManager; + + private boolean clearOnEndMethod = true; + + private boolean clearOnStop = true; + + public void embedderInitialized( long timestamp ) + { + initializeCaught++; + } + + public void embedderMethodEnded( String method, + long timestamp ) + { + endMethodCaught++; + if ( clearOnEndMethod ) + { + clearCache(); + } + } + + public void embedderMethodStarted( String method, + long timestamp ) + { + startMethodCaught++; + } + + public void embedderStopped( long timestamp ) + { + stopCaught++; + if ( clearOnStop ) + { + clearCache(); + } + } + + public void setWorkspaceStore( MavenWorkspaceStore workspaceManager ) + { + setManagerCaught++; + this.workspaceManager = workspaceManager; + super.setWorkspaceStore( workspaceManager ); + } + + public void clearCache() + { + clearCaught++; + super.clearCache(); + } + + } +} diff --git a/maven-project/pom.xml b/maven-project/pom.xml index a214ac8d17..5fc4db1896 100644 --- a/maven-project/pom.xml +++ b/maven-project/pom.xml @@ -32,6 +32,11 @@ under the License. This library is used to not only read Maven project object model files, but to assemble inheritence and to retrieve remote models as required. + + org.apache.maven + maven-workspace + 2.1-SNAPSHOT + org.apache.maven maven-profile diff --git a/maven-project/src/main/aspect/org/apache/maven/project/aspect/ProjectCacheAspect.aj b/maven-project/src/main/aspect/org/apache/maven/project/aspect/ProjectCacheAspect.aj index 6ef265c8a1..c46c4b72b2 100644 --- a/maven-project/src/main/aspect/org/apache/maven/project/aspect/ProjectCacheAspect.aj +++ b/maven-project/src/main/aspect/org/apache/maven/project/aspect/ProjectCacheAspect.aj @@ -13,21 +13,10 @@ import org.apache.maven.project.build.model.ModelAndFile; import org.codehaus.plexus.util.StringUtils; import java.io.File; -import java.util.HashMap; -import java.util.Map; public privileged aspect ProjectCacheAspect { - private Map DefaultMavenProjectBuilder.projectCache = new HashMap(); - - public void DefaultMavenProjectBuilder.clearProjectCache() - { - logger.debug( "Clearing project cache." ); - projectCache.clear(); - logger.debug( "After clearing, " + projectCache.size() + " items remain." ); - } - private pointcut mavenProjectBuilder( DefaultMavenProjectBuilder builder ): execution( * DefaultMavenProjectBuilder+.*( .. ) ) && this( builder ); @@ -63,19 +52,6 @@ public privileged aspect ProjectCacheAspect // proceed( child, parent, builder ); // } - private pointcut setMavenProjectFile( File pomFile, MavenProject project, DefaultMavenProjectBuilder builder ): - execution( void MavenProject.setFile( File ) ) - && cflow( mavenProjectBuilder( builder ) ) - && args( pomFile ) - && target( project ); - - after( File pomFile, MavenProject project, DefaultMavenProjectBuilder builder ): - setMavenProjectFile( pomFile, project, builder ) - { - builder.logger.debug( "Caching project: " + project.getId() + " by its file: " + pomFile ); - builder.projectCache.put( pomFile, project ); - } - private pointcut pbBuildFromRepository( Artifact artifact, DefaultMavenProjectBuilder builder ): execution( MavenProject DefaultMavenProjectBuilder+.buildFromRepository( Artifact, .. ) ) && args( artifact, .. ) @@ -89,15 +65,10 @@ public privileged aspect ProjectCacheAspect MavenProject project = null; boolean skipCache = false; - if ( Artifact.LATEST_VERSION.equals( artifact.getVersion() ) || Artifact.RELEASE_VERSION.equals( artifact.getVersion() ) ) - { - builder.logger.debug( "Skipping cache for meta-version: " + artifact.getVersion() ); - skipCache = true; - } - else + if ( !Artifact.LATEST_VERSION.equals( artifact.getVersion() ) && !Artifact.RELEASE_VERSION.equals( artifact.getVersion() ) ) { builder.logger.debug( "Checking cache for project (in buildFromRepository): " + key ); - project = (MavenProject) builder.projectCache.get( key ); + project = (MavenProject) builder.projectWorkspace.getProject( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() ); } if ( project == null ) @@ -108,8 +79,8 @@ public privileged aspect ProjectCacheAspect if ( !skipCache ) { builder.logger.debug( "Caching result for: " + key + " (also keyed by file: " + project.getFile() + ")" ); - builder.projectCache.put( key, project ); - builder.projectCache.put( project.getFile(), project ); + builder.projectWorkspace.storeProjectByCoordinate( project ); + builder.projectWorkspace.storeProjectByFile( project ); } } else @@ -131,7 +102,7 @@ public privileged aspect ProjectCacheAspect { builder.logger.debug( "Checking cache-hit on project (in build*): " + pomFile ); - MavenProject project = (MavenProject) builder.projectCache.get( pomFile ); + MavenProject project = (MavenProject) builder.projectWorkspace.getProject( pomFile ); if ( project == null ) { @@ -141,8 +112,8 @@ public privileged aspect ProjectCacheAspect String key = createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ); builder.logger.debug( "Caching result for: " + key + " (also keyed by file: " + pomFile + ")" ); - builder.projectCache.put( key, project ); - builder.projectCache.put( pomFile, project ); + builder.projectWorkspace.storeProjectByFile( project ); + builder.projectWorkspace.storeProjectByCoordinate( project ); } else { @@ -159,17 +130,6 @@ public privileged aspect ProjectCacheAspect return groupId + ":" + artifactId + ":" + version; } - private Map DefaultModelLineageBuilder.modelAndFileCache = new HashMap(); - - public void DefaultModelLineageBuilder.clearModelAndFileCache() - { - logger.debug( "Clearing model-and-file cache." ); - - modelAndFileCache.clear(); - - logger.debug( "After clearing, model-and-file cache has " + modelAndFileCache.size() + " entries." ); - } - private pointcut mlbResolveParentPom( ModelAndFile child, DefaultModelLineageBuilder builder ): execution( private ModelAndFile DefaultModelLineageBuilder.resolveParentPom( ModelAndFile, .. ) ) && args( child, .. ) @@ -192,7 +152,7 @@ public privileged aspect ProjectCacheAspect String key = createCacheKey( parentRef.getGroupId(), parentRef.getArtifactId(), parentRef.getVersion() ); builder.logger.debug( "Checking cache for parent model-and-file instance: " + key ); - parent = (ModelAndFile) builder.modelAndFileCache.get( key ); + parent = (ModelAndFile) builder.projectWorkspace.getModelAndFile( parentRef.getGroupId(), parentRef.getArtifactId(), parentRef.getVersion() ); if ( parent == null ) { @@ -202,8 +162,7 @@ public privileged aspect ProjectCacheAspect if ( parent != null ) { builder.logger.debug( "Caching parent model-and-file under: " + key + " and file: " + parent.getFile() + " (child is: " + childModel.getId() + ")" ); - builder.modelAndFileCache.put( key, parent ); - builder.modelAndFileCache.put( parent.getFile(), parent ); + builder.projectWorkspace.storeModelAndFile( parent ); } } else @@ -215,11 +174,9 @@ public privileged aspect ProjectCacheAspect return parent; } - private pointcut buildModelLineageExec(): execution( ModelLineage DefaultModelLineageBuilder.buildModelLineage( .. ) ); - private pointcut mlbReadModelCacheHit( File pomFile, DefaultModelLineageBuilder builder ): - execution( Model DefaultModelLineageBuilder.readModel( File ) ) - && cflowbelow( buildModelLineageExec() ) + call( Model DefaultModelLineageBuilder.readModel( File ) ) + && withincode( ModelLineage DefaultModelLineageBuilder.buildModelLineage( .. ) ) && args( pomFile ) && this( builder ); @@ -227,22 +184,21 @@ public privileged aspect ProjectCacheAspect throws ProjectBuildingException: mlbReadModelCacheHit( pomFile, builder ) { - builder.logger.debug( "Checking cache for model-and-file instance for parent-pom in file: " + pomFile ); - ModelAndFile cached = (ModelAndFile) builder.modelAndFileCache.get( pomFile ); + builder.logger.debug( "Checking cache for model-and-file instance for pom in file: " + pomFile ); + ModelAndFile cached = (ModelAndFile) builder.projectWorkspace.getModelAndFile( pomFile ); if ( cached != null ) { - builder.logger.debug( "Returning cached parent-pom instance." ); + builder.logger.debug( "Returning cached pom instance." ); return cached.getModel(); } - builder.logger.debug( "Allowing readModel(..) to proceed for parent-pom in file: " + pomFile ); + builder.logger.debug( "Allowing readModel(..) to proceed for pom in file: " + pomFile ); return proceed( pomFile, builder ); } private pointcut mlbCacheableModelAndFileConstruction( Model model, File pomFile, DefaultModelLineageBuilder builder ): call( ModelAndFile.new( Model, File, .. ) ) - && cflow( buildModelLineageExec() ) - && !cflowbelow( buildModelLineageExec() ) + && withincode( ModelLineage DefaultModelLineageBuilder.buildModelLineage( .. ) ) && args( model, pomFile, .. ) && this( builder ); @@ -250,16 +206,14 @@ public privileged aspect ProjectCacheAspect mlbCacheableModelAndFileConstruction( model, pomFile, builder ) { builder.logger.debug( "Checking cache for model-and-file instance for file: " + pomFile ); - ModelAndFile cached = (ModelAndFile) builder.modelAndFileCache.get( pomFile ); + ModelAndFile cached = (ModelAndFile) builder.projectWorkspace.getModelAndFile( pomFile ); if ( cached == null ) { builder.logger.debug( "Allowing construction to proceed for model-and-file with model: " + model.getId() + " and file: " + pomFile ); cached = proceed( model, pomFile, builder ); - String key = createCacheKey( model.getGroupId(), model.getArtifactId(), model.getVersion() ); - - builder.modelAndFileCache.put( key, cached ); - builder.modelAndFileCache.put( pomFile, cached ); + builder.logger.debug( "Storing: " + cached ); + builder.projectWorkspace.storeModelAndFile( cached ); } else { diff --git a/maven-project/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java b/maven-project/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java index 640a5799b9..dcf42c83e1 100644 --- a/maven-project/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java +++ b/maven-project/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java @@ -67,6 +67,7 @@ import org.apache.maven.project.interpolation.ModelInterpolator; import org.apache.maven.project.path.PathTranslator; import org.apache.maven.project.validation.ModelValidationResult; import org.apache.maven.project.validation.ModelValidator; +import org.apache.maven.project.workspace.ProjectWorkspace; import org.codehaus.plexus.logging.LogEnabled; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable; @@ -162,6 +163,8 @@ public class DefaultMavenProjectBuilder private MavenTools mavenTools; + private ProjectWorkspace projectWorkspace; + //DO NOT USE, it is here only for backward compatibility reasons. The existing // maven-assembly-plugin (2.2-beta-1) is accessing it via reflection. @@ -1047,6 +1050,7 @@ public class DefaultMavenProjectBuilder if ( lastProject != null ) { + // TODO: Use cached parent project here, and stop looping, if possible... lastProject.setParent( project ); project = lastProject.getParent(); diff --git a/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java b/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java index 4148286eb5..7b82403a53 100644 --- a/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java +++ b/maven-project/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java @@ -95,6 +95,11 @@ public class MavenMetadataSource public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories ) throws ArtifactMetadataRetrievalException { + if ( remoteRepositories == null ) + { + remoteRepositories = Collections.EMPTY_LIST; + } + try { loadProjectBuilder(); @@ -326,14 +331,17 @@ public class MavenMetadataSource } } - // this list should contain the super-POM repositories, so we don't have to explicitly add them back. - for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); ) + if ( remoteArtifactRepositories != null ) { - ArtifactRepository repository = (ArtifactRepository) it.next(); - - if ( !repositories.contains( repository ) ) + // this list should contain the super-POM repositories, so we don't have to explicitly add them back. + for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); ) { - repositories.add( repository ); + ArtifactRepository repository = (ArtifactRepository) it.next(); + + if ( !repositories.contains( repository ) ) + { + repositories.add( repository ); + } } } diff --git a/maven-project/src/main/java/org/apache/maven/project/build/model/DefaultModelLineageBuilder.java b/maven-project/src/main/java/org/apache/maven/project/build/model/DefaultModelLineageBuilder.java index 26fdfe8b89..918556e824 100644 --- a/maven-project/src/main/java/org/apache/maven/project/build/model/DefaultModelLineageBuilder.java +++ b/maven-project/src/main/java/org/apache/maven/project/build/model/DefaultModelLineageBuilder.java @@ -35,6 +35,7 @@ import org.apache.maven.profiles.activation.DefaultProfileActivationContext; import org.apache.maven.profiles.activation.ProfileActivationContext; import org.apache.maven.profiles.build.ProfileAdvisor; import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.workspace.ProjectWorkspace; import org.codehaus.plexus.logging.LogEnabled; import org.codehaus.plexus.logging.Logger; import org.codehaus.plexus.logging.console.ConsoleLogger; @@ -68,6 +69,8 @@ public class DefaultModelLineageBuilder private ProfileAdvisor profileAdvisor; + private ProjectWorkspace projectWorkspace; + private Logger logger; public DefaultModelLineageBuilder() @@ -97,7 +100,6 @@ public class DefaultModelLineageBuilder List currentRemoteRepositories = remoteRepositories == null ? new ArrayList() : new ArrayList( remoteRepositories ); - // TODO: Cache the result of this readModel(..) call. ModelAndFile current = new ModelAndFile( readModel( pom ), pom, validProfilesXmlLocation ); do diff --git a/maven-project/src/main/java/org/apache/maven/project/build/model/ModelAndFile.java b/maven-project/src/main/java/org/apache/maven/project/build/model/ModelAndFile.java index a2b023942c..d09f50b8d5 100644 --- a/maven-project/src/main/java/org/apache/maven/project/build/model/ModelAndFile.java +++ b/maven-project/src/main/java/org/apache/maven/project/build/model/ModelAndFile.java @@ -13,7 +13,7 @@ public class ModelAndFile private final boolean validProfilesXmlLocation; - ModelAndFile( Model model, + public ModelAndFile( Model model, File file, boolean validProfilesXmlLocation ) { diff --git a/maven-project/src/main/java/org/apache/maven/project/workspace/DefaultProjectWorkspace.java b/maven-project/src/main/java/org/apache/maven/project/workspace/DefaultProjectWorkspace.java new file mode 100644 index 0000000000..dce392c995 --- /dev/null +++ b/maven-project/src/main/java/org/apache/maven/project/workspace/DefaultProjectWorkspace.java @@ -0,0 +1,148 @@ +package org.apache.maven.project.workspace; + +import org.apache.maven.model.Model; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.build.model.ModelAndFile; +import org.apache.maven.workspace.MavenWorkspaceStore; +import org.codehaus.plexus.logging.LogEnabled; +import org.codehaus.plexus.logging.Logger; + +import java.io.File; +import java.net.URI; +import java.util.Map; + +public class DefaultProjectWorkspace + implements ProjectWorkspace, LogEnabled +{ + + private MavenWorkspaceStore workspaceStore; +// private Logger logger; + + public DefaultProjectWorkspace() + { + } + + protected DefaultProjectWorkspace( MavenWorkspaceStore workspaceStore ) + { + this.workspaceStore = workspaceStore; + } + + public ModelAndFile getModelAndFile( String groupId, + String artifactId, + String version ) + { + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.MODEL_AND_FILE_BYGAV_KEY ); + + String key = createCacheKey( groupId, artifactId, version ); + +// getLogger().debug( "Retrieving ModelAndFile instance for: " + key + " from workspace." ); + return (ModelAndFile) cache.get( key ); + } + + public ModelAndFile getModelAndFile( File modelFile ) + { + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.MODEL_AND_FILE_BYFILE_KEY ); + + Object pathKey = resolvePathKey( modelFile ); + +// getLogger().debug( "Retrieving ModelAndFile instance for: " + pathKey + " from workspace." ); + return (ModelAndFile) cache.get( pathKey ); + } + + private Object resolvePathKey( File file ) + { + if ( file == null ) + { + return null; + } + + URI path = file.toURI().normalize(); + + return path; + } + + public MavenProject getProject( File projectFile ) + { + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.PROJECT_INSTANCE_BYFILE_KEY ); + + Object pathKey = resolvePathKey( projectFile ); + +// getLogger().debug( "Retrieving MavenProject instance for: " + pathKey + " from workspace." ); + return (MavenProject) cache.get( pathKey ); + } + + public MavenProject getProject( String groupId, + String artifactId, + String version ) + { + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.PROJECT_INSTANCE_BYGAV_KEY ); + + String key = createCacheKey( groupId, artifactId, version ); + +// getLogger().debug( "Retrieving MavenProject instance for: " + key + " from workspace." ); + return (MavenProject) cache.get( key ); + } + + public void storeModelAndFile( ModelAndFile modelAndFile ) + { + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.MODEL_AND_FILE_BYFILE_KEY ); + + Object pathKey = resolvePathKey( modelAndFile.getFile() ); + +// getLogger().debug( "Storing ModelAndFile instance under: " + pathKey + " in workspace." ); + cache.put( pathKey, modelAndFile ); + + cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.MODEL_AND_FILE_BYGAV_KEY ); + + Model model = modelAndFile.getModel(); + String key = createCacheKey( model.getGroupId(), model.getArtifactId(), model.getVersion() ); + +// getLogger().debug( "Storing ModelAndFile instance under: " + key + " in workspace." ); + cache.put( key, modelAndFile ); + } + + public void storeProjectByFile( MavenProject project ) + { + if ( project.getFile() == null ){ + return; + } + + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.PROJECT_INSTANCE_BYFILE_KEY ); + + Object pathKey = resolvePathKey( project.getFile() ); + +// getLogger().debug( "Storing MavenProject instance under: " + pathKey + " in workspace." ); + cache.put( pathKey, project ); + } + + public void storeProjectByCoordinate( MavenProject project ) + { + Map cache = workspaceStore.getWorkspaceCache( ProjectWorkspace.PROJECT_INSTANCE_BYGAV_KEY ); + + String key = createCacheKey( project.getGroupId(), project.getArtifactId(), project.getVersion() ); + +// getLogger().debug( "Storing MavenProject instance under: " + key + " in workspace." ); + cache.put( key, project ); + } + + private String createCacheKey( String groupId, String artifactId, String version ) + { + return groupId + ":" + artifactId + ":" + version; + } + +// protected Logger getLogger() +// { +// if ( logger == null ) +// { +// logger = new ConsoleLogger( Logger.LEVEL_INFO, "internal" ); +// } +// +// return logger; +// } + + public void enableLogging( Logger logger ) + { +// this.logger = logger; + } + +} diff --git a/maven-project/src/main/java/org/apache/maven/project/workspace/ProjectWorkspace.java b/maven-project/src/main/java/org/apache/maven/project/workspace/ProjectWorkspace.java new file mode 100644 index 0000000000..ddbc4fe1f0 --- /dev/null +++ b/maven-project/src/main/java/org/apache/maven/project/workspace/ProjectWorkspace.java @@ -0,0 +1,32 @@ +package org.apache.maven.project.workspace; + +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.build.model.ModelAndFile; + +import java.io.File; + +public interface ProjectWorkspace +{ + + String PROJECT_INSTANCE_BYFILE_KEY = "maven:project:project:file"; + + String MODEL_AND_FILE_BYFILE_KEY = "maven:project:modelAndFile:file"; + + String PROJECT_INSTANCE_BYGAV_KEY = "maven:project:project:GAV"; + + String MODEL_AND_FILE_BYGAV_KEY = "maven:project:modelAndFile:GAV"; + + MavenProject getProject( File projectFile ); + + MavenProject getProject( String groupId, String artifactId, String version ); + + void storeProjectByFile( MavenProject project ); + + void storeProjectByCoordinate( MavenProject project ); + + ModelAndFile getModelAndFile( String groupId, String artifactId, String version ); + + ModelAndFile getModelAndFile( File modelFile ); + + void storeModelAndFile( ModelAndFile modelAndFile ); +} diff --git a/maven-project/src/main/resources/META-INF/plexus/components.xml b/maven-project/src/main/resources/META-INF/plexus/components.xml index 51afcef40d..ab15e3d33f 100644 --- a/maven-project/src/main/resources/META-INF/plexus/components.xml +++ b/maven-project/src/main/resources/META-INF/plexus/components.xml @@ -41,6 +41,9 @@ under the License. default org.apache.maven.project.build.model.DefaultModelLineageBuilder + + org.apache.maven.project.workspace.ProjectWorkspace + org.apache.maven.profiles.build.ProfileAdvisor default @@ -107,6 +110,9 @@ under the License. default org.apache.maven.project.DefaultMavenProjectBuilder + + org.apache.maven.project.workspace.ProjectWorkspace + org.apache.maven.artifact.metadata.ArtifactMetadataSource @@ -310,6 +316,17 @@ under the License. + + + org.apache.maven.project.workspace.ProjectWorkspace + default + org.apache.maven.project.workspace.DefaultProjectWorkspace + + + org.apache.maven.workspace.MavenWorkspaceStore + + + diff --git a/maven-project/src/test/java/org/apache/maven/project/workspace/DefaultProjectWorkspaceTest.java b/maven-project/src/test/java/org/apache/maven/project/workspace/DefaultProjectWorkspaceTest.java new file mode 100644 index 0000000000..02e11b1623 --- /dev/null +++ b/maven-project/src/test/java/org/apache/maven/project/workspace/DefaultProjectWorkspaceTest.java @@ -0,0 +1,83 @@ +package org.apache.maven.project.workspace; + +import org.apache.maven.model.Model; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.build.model.ModelAndFile; +import org.apache.maven.workspace.DefaultMavenWorkspaceStore; + +import java.io.File; + +import junit.framework.TestCase; + +public class DefaultProjectWorkspaceTest + extends TestCase +{ + + public void testStoreAndRetrieveModelAndFile() + { + ModelAndFile maf = newModelAndFile( "group", "artifact", "1" ); + + DefaultProjectWorkspace ws = new DefaultProjectWorkspace( new DefaultMavenWorkspaceStore() ); + ws.storeModelAndFile( maf ); + + ModelAndFile r1 = ws.getModelAndFile( maf.getFile() ); + + assertSame( maf, r1 ); + + ModelAndFile r2 = ws.getModelAndFile( maf.getModel().getGroupId(), maf.getModel().getArtifactId(), maf.getModel().getVersion() ); + + assertSame( maf, r2 ); + } + + public void testStoreAndRetrieveProjectByFile_CoordinateRetrievalReturnsNull() + { + MavenProject project = newProject( "group", "artifact", "1" ); + + DefaultProjectWorkspace ws = new DefaultProjectWorkspace( new DefaultMavenWorkspaceStore() ); + ws.storeProjectByFile( project ); + + assertSame( project, ws.getProject( project.getFile() ) ); + assertNull( ws.getProject( project.getGroupId(), project.getArtifactId(), project.getVersion() ) ); + } + + public void testStoreAndRetrieveProjectByCoordinate_FileRetrievalReturnsNull() + { + MavenProject project = newProject( "group", "artifact", "1" ); + + DefaultProjectWorkspace ws = new DefaultProjectWorkspace( new DefaultMavenWorkspaceStore() ); + ws.storeProjectByCoordinate( project ); + + assertNull( ws.getProject( project.getFile() ) ); + assertSame( project, ws.getProject( project.getGroupId(), project.getArtifactId(), project.getVersion() ) ); + } + + private MavenProject newProject( String gid, + String aid, + String ver ) + { + File f = new File( "test-project" ); + Model model = new Model(); + model.setGroupId( gid ); + model.setArtifactId( aid ); + model.setVersion( ver ); + + MavenProject project = new MavenProject( model ); + project.setFile( f ); + return project; + } + + private ModelAndFile newModelAndFile( String gid, + String aid, + String ver ) + { + File f = new File( "test-modelAndFile" ); + Model model = new Model(); + model.setGroupId( gid ); + model.setArtifactId( aid ); + model.setVersion( ver ); + + ModelAndFile maf = new ModelAndFile( model, f, false ); + return maf; + } + +} diff --git a/maven-project/src/test/java/org/apache/maven/project/workspace/ModelAndFileCachingTest.java b/maven-project/src/test/java/org/apache/maven/project/workspace/ModelAndFileCachingTest.java new file mode 100644 index 0000000000..30ac5d41d8 --- /dev/null +++ b/maven-project/src/test/java/org/apache/maven/project/workspace/ModelAndFileCachingTest.java @@ -0,0 +1,234 @@ +package org.apache.maven.project.workspace; + +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; +import org.apache.maven.model.Model; +import org.apache.maven.profiles.DefaultProfileManager; +import org.apache.maven.profiles.ProfileManager; +import org.apache.maven.profiles.activation.DefaultProfileActivationContext; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.build.model.ModelAndFile; +import org.apache.maven.project.build.model.ModelLineage; +import org.apache.maven.project.build.model.ModelLineageBuilder; +import org.apache.maven.workspace.MavenWorkspaceStore; +import org.codehaus.plexus.PlexusTestCase; +import org.codehaus.plexus.logging.Logger; +import org.codehaus.plexus.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class ModelAndFileCachingTest + extends PlexusTestCase +{ + private static final String MY_PATH = ModelAndFileCachingTest.class.getName() + .replace( '.', '/' ) + + ".class"; + + private ProjectWorkspace projectWorkspace; + + private MavenWorkspaceStore workspaceStore; + + private ModelLineageBuilder lineageBuilder; + + private ArtifactRepositoryFactory repoFactory; + + private ProfileManager profileManager; + + private ArtifactRepository localRepo; + + private ArtifactFactory artifactFactory; + + private List dirsToDelete = new ArrayList(); + + public void setUp() + throws Exception + { + super.setUp(); + getContainer().getLoggerManager().setThresholds( Logger.LEVEL_DEBUG ); + + projectWorkspace = (ProjectWorkspace) lookup( ProjectWorkspace.class ); + workspaceStore = (MavenWorkspaceStore) lookup( MavenWorkspaceStore.class ); + lineageBuilder = (ModelLineageBuilder) lookup( ModelLineageBuilder.class ); + repoFactory = (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.class ); + artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.class ); + + File localRepoDir = File.createTempFile( "local-repo.", ".tmp" ); + localRepoDir.delete(); + localRepoDir.mkdirs(); + + dirsToDelete.add( localRepoDir ); + + localRepo = repoFactory.createLocalRepository( localRepoDir ); + profileManager = new DefaultProfileManager( + getContainer(), + new DefaultProfileActivationContext( + System.getProperties(), + true ) ); + } + + public void tearDown() + throws Exception + { + workspaceStore.clear(); + + if ( !dirsToDelete.isEmpty() ) + { + for ( Iterator it = dirsToDelete.iterator(); it.hasNext(); ) + { + File dir = (File) it.next(); + try + { + FileUtils.deleteDirectory( dir ); + } + catch ( IOException e ) + { + // ignore. + } + } + } + + super.tearDown(); + } + + public void testResolveParentPom_PreferCachedInstance() + throws IOException, ProjectBuildingException + { + File childPomFile = getFile( "resolveParentPom/pom.xml" ); + + String gid = "tests"; + String aid = "resolve-parent-pom-parent"; + String ver = "1"; + + ModelAndFile maf = newModelAndFile( gid, aid, ver ); + projectWorkspace.storeModelAndFile( maf ); + + ModelLineage lineage = lineageBuilder.buildModelLineage( childPomFile, + localRepo, + Collections.EMPTY_LIST, + profileManager, + false, + false ); + + assertSame( maf.getModel(), lineage.getDeepestAncestorModel() ); + } + + public void testResolveParentPom_StoreByFileAndGAVIfUncached() + throws IOException, ProjectBuildingException + { + File childPomFile = getFile( "resolveParentPom/childAndParent/child/pom.xml" ); + File parentPomFile = new File( childPomFile.getParentFile().getParentFile(), "pom.xml" ); + + String gid = "tests"; + String aid = "childAndParent-parent"; + String ver = "1"; + + ModelLineage lineage = lineageBuilder.buildModelLineage( childPomFile, + localRepo, + Collections.EMPTY_LIST, + profileManager, + false, + false ); + + assertEquals( parentPomFile.getCanonicalPath(), lineage.getDeepestAncestorFile() + .getCanonicalPath() ); + + ModelAndFile maf1 = projectWorkspace.getModelAndFile( gid, aid, ver ); + assertNotNull( maf1 ); + assertSame( maf1.getModel(), lineage.getDeepestAncestorModel() ); + + ModelAndFile maf2 = projectWorkspace.getModelAndFile( parentPomFile ); + assertNotNull( maf2 ); + assertSame( maf2.getModel(), lineage.getDeepestAncestorModel() ); + } + + public void testReadModel_PreferModelInstanceCachedByFile() + throws IOException, ProjectBuildingException + { + File pomFile = new File( "test/pom.xml" ); + + String gid = "tests"; + String aid = "read-model"; + String ver = "1"; + + ModelAndFile maf = newModelAndFile( gid, aid, ver, pomFile ); + projectWorkspace.storeModelAndFile( maf ); + + ModelLineage lineage = lineageBuilder.buildModelLineage( pomFile, + localRepo, + Collections.EMPTY_LIST, + profileManager, + false, + false ); + + assertSame( maf.getModel(), lineage.getOriginatingModel() ); + } + + public void testBuildModelLineage_StoreByFileAndGAVIfUncached() + throws IOException, ProjectBuildingException + { + File pomFile = getFile( "buildModelLineage/pom.xml" ); + + String gid = "tests"; + String aid = "build-model-lineage"; + String ver = "1"; + + ModelLineage lineage = lineageBuilder.buildModelLineage( pomFile, + localRepo, + Collections.EMPTY_LIST, + profileManager, + false, + false ); + + assertEquals( pomFile.getCanonicalPath(), lineage.getOriginatingPOMFile() + .getCanonicalPath() ); + + ModelAndFile maf1 = projectWorkspace.getModelAndFile( gid, aid, ver ); + assertNotNull( maf1 ); + assertSame( maf1.getModel(), lineage.getOriginatingModel() ); + + ModelAndFile maf2 = projectWorkspace.getModelAndFile( pomFile ); + assertNotNull( maf2 ); + assertSame( maf2.getModel(), lineage.getOriginatingModel() ); + } + + private ModelAndFile newModelAndFile( String gid, + String aid, + String ver ) + throws IOException + { + return newModelAndFile( gid, aid, ver, File.createTempFile( "model-and-file.", ".tmp" ) ); + } + + private ModelAndFile newModelAndFile( String gid, + String aid, + String ver, + File file ) + { + Model model = new Model(); + model.setGroupId( gid ); + model.setArtifactId( aid ); + model.setVersion( ver ); + + ModelAndFile maf = new ModelAndFile( model, file, false ); + + return maf; + } + + private File getFile( String path ) + { + ClassLoader cloader = Thread.currentThread().getContextClassLoader(); + URL myRes = cloader.getResource( MY_PATH ); + + File myFile = new File( myRes.getPath() ); + + return new File( myFile.getParentFile(), path ); + } + +} diff --git a/maven-project/src/test/java/org/apache/maven/project/workspace/ProjectCachingTest.java b/maven-project/src/test/java/org/apache/maven/project/workspace/ProjectCachingTest.java new file mode 100644 index 0000000000..9280d5fced --- /dev/null +++ b/maven-project/src/test/java/org/apache/maven/project/workspace/ProjectCachingTest.java @@ -0,0 +1,286 @@ +package org.apache.maven.project.workspace; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.InvalidRepositoryException; +import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; +import org.apache.maven.model.Model; +import org.apache.maven.profiles.DefaultProfileManager; +import org.apache.maven.profiles.ProfileManager; +import org.apache.maven.profiles.activation.DefaultProfileActivationContext; +import org.apache.maven.project.MavenProject; +import org.apache.maven.project.MavenProjectBuilder; +import org.apache.maven.project.ProjectBuildingException; +import org.apache.maven.project.build.model.ModelLineageBuilder; +import org.apache.maven.workspace.MavenWorkspaceStore; +import org.codehaus.plexus.PlexusTestCase; +import org.codehaus.plexus.logging.Logger; +import org.codehaus.plexus.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +// TODO: Add conversion/tests for modelAndFileCache -> projectWorkspace stuff in simple cases. +// TODO: Add tests for project parents from cache (using model-and-file stuff, maybe?) +public class ProjectCachingTest + extends PlexusTestCase +{ + + private static final String MY_PATH = ProjectCachingTest.class.getName().replace( '.', '/' ) + + ".class"; + + private ProjectWorkspace projectWorkspace; + + private MavenWorkspaceStore workspaceStore; + + private MavenProjectBuilder projectBuilder; + + private ModelLineageBuilder lineageBuilder; + + private ArtifactRepositoryFactory repoFactory; + + private ProfileManager profileManager; + + private ArtifactRepository localRepo; + + private ArtifactFactory artifactFactory; + + private List dirsToDelete = new ArrayList(); + + public void setUp() + throws Exception + { + super.setUp(); + getContainer().getLoggerManager().setThresholds( Logger.LEVEL_DEBUG ); + + projectWorkspace = (ProjectWorkspace) lookup( ProjectWorkspace.class ); + workspaceStore = (MavenWorkspaceStore) lookup( MavenWorkspaceStore.class ); + projectBuilder = (MavenProjectBuilder) lookup( MavenProjectBuilder.class ); + lineageBuilder = (ModelLineageBuilder) lookup( ModelLineageBuilder.class ); + repoFactory = (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.class ); + artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.class ); + + File localRepoDir = File.createTempFile( "local-repo.", ".tmp" ); + localRepoDir.delete(); + localRepoDir.mkdirs(); + + dirsToDelete.add( localRepoDir ); + + localRepo = repoFactory.createLocalRepository( localRepoDir ); + profileManager = new DefaultProfileManager( + getContainer(), + new DefaultProfileActivationContext( + System.getProperties(), + true ) ); + } + + public void tearDown() + throws Exception + { + workspaceStore.clear(); + + if ( !dirsToDelete.isEmpty() ) + { + for ( Iterator it = dirsToDelete.iterator(); it.hasNext(); ) + { + File dir = (File) it.next(); + try + { + FileUtils.deleteDirectory( dir ); + } + catch ( IOException e ) + { + // ignore. + } + } + } + + super.tearDown(); + } + + public void testBuildFromRepository_PreferCachedProject() + throws ProjectBuildingException + { + String gid = "org.apache.maven.tests"; + String aid = "buildFromRepo-checkCacheFirst"; + String ver = "1"; + + MavenProject project = newProject( gid, aid, ver ); + projectWorkspace.storeProjectByCoordinate( project ); + + Artifact artifact = artifactFactory.createProjectArtifact( gid, aid, ver ); + + MavenProject result = projectBuilder.buildFromRepository( artifact, + Collections.EMPTY_LIST, + localRepo ); + + assertSame( project, result ); + } + + public void testBuildFromRepository_StoreProjectByCoordOnlyIfUncached() + throws ProjectBuildingException, InvalidRepositoryException + { + File lrDir = getFile( "buildFromRepo" ); + File pomFile = new File( lrDir, "tests/project-caching/1/project-caching-1.pom" ); + + String gid = "tests"; + String aid = "project-caching"; + String ver = "1"; + + Artifact artifact = artifactFactory.createProjectArtifact( gid, aid, ver ); + + ArtifactRepository localRepo = repoFactory.createLocalRepository( lrDir ); + + MavenProject project = projectBuilder.buildFromRepository( artifact, + Collections.EMPTY_LIST, + localRepo ); + + MavenProject r1 = projectWorkspace.getProject( pomFile ); + + MavenProject r2 = projectWorkspace.getProject( gid, aid, ver ); + + assertNull( r1 ); + + assertSame( project, r2 ); + } + + public void testBuildFromRepository_DontCheckCacheForRELEASEMetaVersion() + throws ProjectBuildingException, InvalidRepositoryException + { + File lrDir = getFile( "buildFromRepo" ); + File pomFile = new File( lrDir, "tests/project-caching/1/project-caching-1.pom" ); + + String gid = "tests"; + String aid = "project-caching"; + String ver = "1"; + + MavenProject seed = newProject( gid, aid, ver ); + + Artifact artifact = artifactFactory.createProjectArtifact( gid, + aid, + Artifact.RELEASE_VERSION ); + + ArtifactRepository localRepo = repoFactory.createLocalRepository( lrDir ); + + MavenProject project = projectBuilder.buildFromRepository( artifact, + Collections.EMPTY_LIST, + localRepo ); + + assertNotSame( seed, project ); + + MavenProject r1 = projectWorkspace.getProject( pomFile ); + + MavenProject r2 = projectWorkspace.getProject( gid, aid, ver ); + + assertNull( r1 ); + + assertSame( project, r2 ); + } + + public void testBuildFromRepository_DontCheckCacheForLATESTMetaVersion() + throws ProjectBuildingException, InvalidRepositoryException + { + File lrDir = getFile( "buildFromRepo" ); + File pomFile = new File( lrDir, "tests/project-caching/1/project-caching-1.pom" ); + + String gid = "tests"; + String aid = "project-caching"; + String ver = "1"; + + MavenProject seed = newProject( gid, aid, ver ); + projectWorkspace.storeProjectByCoordinate( seed ); + + Artifact artifact = artifactFactory.createProjectArtifact( gid, + aid, + Artifact.RELEASE_VERSION ); + + ArtifactRepository localRepo = repoFactory.createLocalRepository( lrDir ); + + MavenProject project = projectBuilder.buildFromRepository( artifact, + Collections.EMPTY_LIST, + localRepo ); + + assertNotSame( seed, project ); + + MavenProject r1 = projectWorkspace.getProject( pomFile ); + + MavenProject r2 = projectWorkspace.getProject( gid, aid, ver ); + + assertNull( r1 ); + + assertSame( project, r2 ); + } + + public void testBuildFromFile_PreferProjectCachedByFile() + throws ProjectBuildingException, InvalidRepositoryException + { + File pomFile = getFile( "buildFromFile/pom.xml" ); + + String gid = "org.apache.maven.tests"; + String aid = "build-from-file"; + String ver = "1"; + + MavenProject seed = newProject( gid, aid, ver ); + seed.setFile( pomFile ); + + projectWorkspace.storeProjectByFile( seed ); + + MavenProject project = projectBuilder.build( pomFile, localRepo, profileManager ); + + assertSame( seed, project ); + + assertNull( projectWorkspace.getProject( gid, aid, ver ) ); + } + + public void testBuildFromFile_StoreByCoordAndFileIfUncached() + throws ProjectBuildingException, InvalidRepositoryException + { + File pomFile = getFile( "buildFromFile/pom.xml" ); + + String gid = "org.apache.maven.tests"; + String aid = "build-from-file"; + String ver = "1"; + + assertNull( projectWorkspace.getProject( pomFile ) ); + assertNull( projectWorkspace.getProject( gid, aid, ver ) ); + + MavenProject project = projectBuilder.build( pomFile, localRepo, profileManager ); + + MavenProject byFile = projectWorkspace.getProject( pomFile ); + MavenProject byCoord = projectWorkspace.getProject( gid, aid, ver ); + + assertSame( project, byFile ); + assertSame( project, byCoord ); + } + + private MavenProject newProject( String gid, + String aid, + String ver ) + { + Model model = new Model(); + model.setGroupId( gid ); + model.setArtifactId( aid ); + model.setVersion( ver ); + + MavenProject project = new MavenProject( model ); + + return project; + } + + private File getFile( String path ) + { + ClassLoader cloader = Thread.currentThread().getContextClassLoader(); + URL myRes = cloader.getResource( MY_PATH ); + + File myFile = new File( myRes.getPath() ); + + return new File( myFile.getParentFile(), path ); + } + +} diff --git a/maven-project/src/test/resources/org/apache/maven/project/ProjectClasspathTest.xml b/maven-project/src/test/resources/org/apache/maven/project/ProjectClasspathTest.xml index f02fb46fe9..e74455e1c7 100644 --- a/maven-project/src/test/resources/org/apache/maven/project/ProjectClasspathTest.xml +++ b/maven-project/src/test/resources/org/apache/maven/project/ProjectClasspathTest.xml @@ -80,6 +80,9 @@ under the License. test org.apache.maven.project.TestProjectBuilder + + org.apache.maven.project.workspace.ProjectWorkspace + org.apache.maven.project.build.model.ModelLineageBuilder default diff --git a/maven-project/src/test/resources/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.xml b/maven-project/src/test/resources/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.xml index 4d5474bee7..b76f324e0a 100644 --- a/maven-project/src/test/resources/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.xml +++ b/maven-project/src/test/resources/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.xml @@ -78,6 +78,9 @@ under the License. test org.apache.maven.project.TestProjectBuilder + + org.apache.maven.project.workspace.ProjectWorkspace + org.apache.maven.project.build.model.ModelLineageBuilder default diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromFile/pom.xml b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromFile/pom.xml new file mode 100644 index 0000000000..45dc77d2a9 --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromFile/pom.xml @@ -0,0 +1,8 @@ + + 4.0.0 + + org.apache.maven.tests + build-from-file + 1 + + \ No newline at end of file diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/1/project-caching-1.pom b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/1/project-caching-1.pom new file mode 100644 index 0000000000..d42117656a --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/1/project-caching-1.pom @@ -0,0 +1,8 @@ + + 4.0.0 + + tests + project-caching + 1 + + \ No newline at end of file diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/maven-metadata-local.xml b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/maven-metadata-local.xml new file mode 100644 index 0000000000..a608b4f81d --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildFromRepo/tests/project-caching/maven-metadata-local.xml @@ -0,0 +1,11 @@ + + tests + project-caching + + 1 + 1 + + 1 + + + \ No newline at end of file diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/buildModelLineage/pom.xml b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildModelLineage/pom.xml new file mode 100644 index 0000000000..5c62a787cc --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/buildModelLineage/pom.xml @@ -0,0 +1,7 @@ + + 4.0.0 + + tests + build-model-lineage + 1 + \ No newline at end of file diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/child/pom.xml b/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/child/pom.xml new file mode 100644 index 0000000000..5953c32e2f --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/child/pom.xml @@ -0,0 +1,10 @@ + + 4.0.0 + + tests + childAndParent-parent + 1 + + + childAndParent-child + \ No newline at end of file diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/pom.xml b/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/pom.xml new file mode 100644 index 0000000000..365ec18388 --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/childAndParent/pom.xml @@ -0,0 +1,7 @@ + + 4.0.0 + + tests + childAndParent-parent + 1 + \ No newline at end of file diff --git a/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/pom.xml b/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/pom.xml new file mode 100644 index 0000000000..e0eec3a2b0 --- /dev/null +++ b/maven-project/src/test/resources/org/apache/maven/project/workspace/resolveParentPom/pom.xml @@ -0,0 +1,10 @@ + + 4.0.0 + + tests + resolve-parent-pom-parent + 1 + + + resolve-parent-pom + \ No newline at end of file diff --git a/maven-workspace/pom.xml b/maven-workspace/pom.xml new file mode 100644 index 0000000000..263a86787a --- /dev/null +++ b/maven-workspace/pom.xml @@ -0,0 +1,17 @@ + + + maven + org.apache.maven + 2.1-SNAPSHOT + + 4.0.0 + maven-workspace + maven-workspace + + + + org.codehaus.plexus + plexus-container-default + + + \ No newline at end of file diff --git a/maven-workspace/src/main/java/org/apache/maven/workspace/DefaultMavenWorkspaceStore.java b/maven-workspace/src/main/java/org/apache/maven/workspace/DefaultMavenWorkspaceStore.java new file mode 100644 index 0000000000..7f48202db8 --- /dev/null +++ b/maven-workspace/src/main/java/org/apache/maven/workspace/DefaultMavenWorkspaceStore.java @@ -0,0 +1,66 @@ +package org.apache.maven.workspace; + +import org.codehaus.plexus.logging.LogEnabled; +import org.codehaus.plexus.logging.Logger; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class DefaultMavenWorkspaceStore + implements MavenWorkspaceStore, LogEnabled +{ + + private Map caches = new HashMap(); +// private Logger logger; + + public void clear() + { + for ( Iterator it = caches.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it.next(); +// String cacheType = (String) entry.getKey(); + Map cache = (Map) entry.getValue(); + +// getLogger().debug( "Clearing workspace cache for: " + cacheType + " (" + cache.size() + " entries)" ); + cache.clear(); + } + } + + public Map getWorkspaceCache( String cacheType ) + { + Map result = (Map) caches.get( cacheType ); + + if ( result == null ) + { + result = new HashMap(); + initWorkspaceCache( cacheType, result ); + } + +// getLogger().debug( "Retrieving workspace cache for: " + cacheType + " (" + result.size() + " entries)" ); + return result; + } + + public void initWorkspaceCache( String cacheType, + Map cache ) + { +// getLogger().debug( "Initializing workspace cache for: " + cacheType + " (" + cache.size() + " entries)" ); + caches.put( cacheType, cache ); + } + +// protected Logger getLogger() +// { +// if ( logger == null ) +// { +// logger = new ConsoleLogger ( Logger.LEVEL_INFO, "internal" ); +// } +// +// return logger; +// } + + public void enableLogging( Logger logger ) + { +// this.logger = logger; + } + +} diff --git a/maven-workspace/src/main/java/org/apache/maven/workspace/MavenWorkspaceStore.java b/maven-workspace/src/main/java/org/apache/maven/workspace/MavenWorkspaceStore.java new file mode 100644 index 0000000000..44dd37645f --- /dev/null +++ b/maven-workspace/src/main/java/org/apache/maven/workspace/MavenWorkspaceStore.java @@ -0,0 +1,14 @@ +package org.apache.maven.workspace; + +import java.util.Map; + +public interface MavenWorkspaceStore +{ + + Map getWorkspaceCache( String cacheType ); + + void initWorkspaceCache( String cacheType, Map cache ); + + void clear(); + +} diff --git a/maven-workspace/src/main/resources/META-INF/plexus/components.xml b/maven-workspace/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 0000000000..a5c9b39208 --- /dev/null +++ b/maven-workspace/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,9 @@ + + + + org.apache.maven.workspace.MavenWorkspaceStore + default + org.apache.maven.workspace.DefaultMavenWorkspaceStore + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4034ff769e..8d69b86928 100644 --- a/pom.xml +++ b/pom.xml @@ -209,6 +209,7 @@ under the License. maven-project maven-reporting-api maven-embedder + maven-workspace