Author: krosenvold Date: Fri Jul 23 18:25:04 2010 New Revision: 967190 URL: http://svn.apache.org/viewvc?rev=967190&view=rev Log: [MNG-4633] Added ThreadLockedArtifact, Implemented locking algorithm Fix affects weave mode only. Solves 3 different known problematic cases where downstream reactor modules access the file of the upstream module's artifact before it is ready (seem in ant-plugin, ear plugin and reported on issue). The basic premise of this fix is that only a few selected phases actually need access to the classes variant of artifact.getFile() which is set by the compiler plugin.
Added: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CurrentPhaseForThread.java (with props) maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadLockedArtifact.java (with props) Modified: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java Added: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CurrentPhaseForThread.java URL: http://svn.apache.org/viewvc/maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CurrentPhaseForThread.java?rev=967190&view=auto ============================================================================== --- maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CurrentPhaseForThread.java (added) +++ maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CurrentPhaseForThread.java Fri Jul 23 18:25:04 2010 @@ -0,0 +1,44 @@ +package org.apache.maven.lifecycle.internal; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Knows the phase the current thread is executing. + * <p/> + * There may be better ways of doing this once the dust settles. + * + * @author Kristian Rosenvold + */ +public class CurrentPhaseForThread +{ + private static final InheritableThreadLocal<String> threadPhase = new InheritableThreadLocal<String>(); + + + public static void setPhase( String phase ) + { + threadPhase.set( phase ); + } + + public static boolean isPhase( String phase ) + { + return phase.equals( threadPhase.get() ); + } + +} Propchange: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CurrentPhaseForThread.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java URL: http://svn.apache.org/viewvc/maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java?rev=967190&r1=967189&r2=967190&view=diff ============================================================================== --- maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java (original) +++ maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilder.java Fri Jul 23 18:25:04 2010 @@ -109,6 +109,15 @@ public class LifecycleWeaveBuilder try { + for ( MavenProject mavenProject : session.getProjects() ) + { + if ( !( mavenProject.getArtifact() instanceof ThreadLockedArtifact ) ) + { + ThreadLockedArtifact threadLockedArtifact = new ThreadLockedArtifact( mavenProject.getArtifact() ); + mavenProject.setArtifact( threadLockedArtifact ); + } + } + final List<Future<ProjectSegment>> futures = new ArrayList<Future<ProjectSegment>>(); final Map<ProjectSegment, Future<MavenExecutionPlan>> plans = new HashMap<ProjectSegment, Future<MavenExecutionPlan>>(); @@ -201,6 +210,8 @@ public class LifecycleWeaveBuilder { Iterator<ExecutionPlanItem> planItems = executionPlan.iterator(); ExecutionPlanItem current = planItems.hasNext() ? planItems.next() : null; + ThreadLockedArtifact threadLockedArtifact = (ThreadLockedArtifact)projectBuild.getProject().getArtifact(); + threadLockedArtifact.attachToThread(); long buildStartTime = System.currentTimeMillis(); //muxer.associateThreadWithProjectSegment( projectBuild ); @@ -359,9 +370,13 @@ public class LifecycleWeaveBuilder return null; } + private static boolean isThreadLockedAndEmpty(Artifact artifact){ + return artifact instanceof ThreadLockedArtifact && !((ThreadLockedArtifact) artifact).hasReal(); + } + private static Artifact findDependency( MavenProject project, Artifact upStreamArtifact ) { - if ( upStreamArtifact == null ) + if ( upStreamArtifact == null || isThreadLockedAndEmpty(upStreamArtifact)) { return null; } @@ -410,6 +425,8 @@ public class LifecycleWeaveBuilder long buildStartTime = System.currentTimeMillis(); + CurrentPhaseForThread.setPhase( node.getLifecyclePhase() ); + MavenSession sessionForThisModule = projectBuild.getSession(); try { Added: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadLockedArtifact.java URL: http://svn.apache.org/viewvc/maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadLockedArtifact.java?rev=967190&view=auto ============================================================================== --- maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadLockedArtifact.java (added) +++ maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadLockedArtifact.java Fri Jul 23 18:25:04 2010 @@ -0,0 +1,318 @@ +package org.apache.maven.lifecycle.internal; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.artifact.metadata.ArtifactMetadata; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.resolver.filter.ArtifactFilter; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.OverConstrainedVersionException; +import org.apache.maven.artifact.versioning.VersionRange; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +/** + * An artifact that suspends on getFile for anything but the thread it is locked to. + */ +class ThreadLockedArtifact + implements Artifact +{ + private final Artifact real; + + private final CountDownLatch artifactLocked = new CountDownLatch( 1 ); + + ThreadLockedArtifact( Artifact real ) + { + this.real = real; + } + + public boolean hasReal() + { + return real != null && + ( !( real instanceof ThreadLockedArtifact ) || ( (ThreadLockedArtifact) real ).hasReal() ); + } + + public String getGroupId() + { + return real.getGroupId(); + } + + public String getArtifactId() + { + return real.getArtifactId(); + } + + public String getVersion() + { + return real.getVersion(); + } + + public void setVersion( String version ) + { + real.setVersion( version ); + } + + public String getScope() + { + return real.getScope(); + } + + public String getType() + { + return real.getType(); + } + + public String getClassifier() + { + return real.getClassifier(); + } + + public boolean hasClassifier() + { + return real.hasClassifier(); + } + + private static final InheritableThreadLocal<ThreadLockedArtifact> threadArtifact = + new InheritableThreadLocal<ThreadLockedArtifact>(); + + public void attachToThread() + { + threadArtifact.set( this ); + } + + public File getFile() + { + final ThreadLockedArtifact lockedArtifact = threadArtifact.get(); + if ( lockedArtifact != null && this != lockedArtifact && mustLock() ) + { + try + { + artifactLocked.await(); + } + catch ( InterruptedException e ) + { + // Ignore and go on to real.getFile(); + } + } + return real.getFile(); + } + + private boolean mustLock() + { + boolean dontNeedLock = CurrentPhaseForThread.isPhase( "compile" ) || CurrentPhaseForThread.isPhase( "test" ); + return !dontNeedLock; + } + + public void setFile( File destination ) + { + if ( destination != null && destination.exists() && destination.isFile() ) + { + artifactLocked.countDown(); + } + real.setFile( destination ); + } + + public String getBaseVersion() + { + return real.getBaseVersion(); + } + + public void setBaseVersion( String baseVersion ) + { + real.setBaseVersion( baseVersion ); + } + + public String getId() + { + return real.getId(); + } + + public String getDependencyConflictId() + { + return real.getDependencyConflictId(); + } + + public void addMetadata( ArtifactMetadata metadata ) + { + real.addMetadata( metadata ); + } + + public Collection<ArtifactMetadata> getMetadataList() + { + return real.getMetadataList(); + } + + public void setRepository( ArtifactRepository remoteRepository ) + { + real.setRepository( remoteRepository ); + } + + public ArtifactRepository getRepository() + { + return real.getRepository(); + } + + public void updateVersion( String version, ArtifactRepository localRepository ) + { + real.updateVersion( version, localRepository ); + } + + public String getDownloadUrl() + { + return real.getDownloadUrl(); + } + + public void setDownloadUrl( String downloadUrl ) + { + real.setDownloadUrl( downloadUrl ); + } + + public ArtifactFilter getDependencyFilter() + { + return real.getDependencyFilter(); + } + + public void setDependencyFilter( ArtifactFilter artifactFilter ) + { + real.setDependencyFilter( artifactFilter ); + } + + public ArtifactHandler getArtifactHandler() + { + return real.getArtifactHandler(); + } + + public List<String> getDependencyTrail() + { + return real.getDependencyTrail(); + } + + public void setDependencyTrail( List<String> dependencyTrail ) + { + real.setDependencyTrail( dependencyTrail ); + } + + public void setScope( String scope ) + { + real.setScope( scope ); + } + + public VersionRange getVersionRange() + { + return real.getVersionRange(); + } + + public void setVersionRange( VersionRange newRange ) + { + real.setVersionRange( newRange ); + } + + public void selectVersion( String version ) + { + real.selectVersion( version ); + } + + public void setGroupId( String groupId ) + { + real.setGroupId( groupId ); + } + + public void setArtifactId( String artifactId ) + { + real.setArtifactId( artifactId ); + } + + public boolean isSnapshot() + { + return real.isSnapshot(); + } + + public void setResolved( boolean resolved ) + { + real.setResolved( resolved ); + } + + public boolean isResolved() + { + return real.isResolved(); + } + + public void setResolvedVersion( String version ) + { + real.setResolvedVersion( version ); + } + + public void setArtifactHandler( ArtifactHandler handler ) + { + real.setArtifactHandler( handler ); + } + + public boolean isRelease() + { + return real.isRelease(); + } + + public void setRelease( boolean release ) + { + real.setRelease( release ); + } + + public List<ArtifactVersion> getAvailableVersions() + { + return real.getAvailableVersions(); + } + + public void setAvailableVersions( List<ArtifactVersion> versions ) + { + real.setAvailableVersions( versions ); + } + + public boolean isOptional() + { + return real.isOptional(); + } + + public void setOptional( boolean optional ) + { + real.setOptional( optional ); + } + + public ArtifactVersion getSelectedVersion() + throws OverConstrainedVersionException + { + return real.getSelectedVersion(); + } + + public boolean isSelectedVersionKnown() + throws OverConstrainedVersionException + { + return real.isSelectedVersionKnown(); + } + + public int compareTo( Artifact o ) + { + return real.compareTo( o ); + } +} Propchange: maven/maven-3/trunk/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ThreadLockedArtifact.java ------------------------------------------------------------------------------ svn:eol-style = native