From 0c5678fa89485bbfa64746c5378100cf2bef2113 Mon Sep 17 00:00:00 2001 From: Jason van Zyl Date: Thu, 6 Feb 2014 16:27:15 -0500 Subject: [PATCH] Remove weave mode building from the core --- .../internal/builder/weave/BuildLogItem.java | 221 -------- .../builder/weave/ConcurrentBuildLogger.java | 124 ----- .../builder/weave/CurrentPhaseForThread.java | 44 -- .../builder/weave/ThreadLockedArtifact.java | 320 ----------- .../internal/builder/weave/WeaveBuilder.java | 521 ------------------ .../internal/ConcurrentBuildLoggerTest.java | 77 --- .../internal/LifecycleWeaveBuilderTest.java | 142 ----- .../java/org/apache/maven/cli/MavenCli.java | 9 +- 8 files changed, 1 insertion(+), 1457 deletions(-) delete mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/BuildLogItem.java delete mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ConcurrentBuildLogger.java delete mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/CurrentPhaseForThread.java delete mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ThreadLockedArtifact.java delete mode 100644 maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/WeaveBuilder.java delete mode 100644 maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrentBuildLoggerTest.java delete mode 100644 maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/BuildLogItem.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/BuildLogItem.java deleted file mode 100644 index 9b5b321e78..0000000000 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/BuildLogItem.java +++ /dev/null @@ -1,221 +0,0 @@ -package org.apache.maven.lifecycle.internal.builder.weave; - -/* - * 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.lifecycle.internal.ExecutionPlanItem; -import org.apache.maven.project.MavenProject; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * @since 3.0 - * @author Kristian Rosenvold - * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. - */ -public class BuildLogItem -{ - private final ExecutionPlanItem executionPlanItem; - - private final MavenProject project; - - private final long startTime; - - private long endTime; - - private final List dependencies = - Collections.synchronizedList( new ArrayList() ); - - public BuildLogItem( MavenProject project, ExecutionPlanItem executionPlanItem ) - { - this.executionPlanItem = executionPlanItem; - this.project = project; - startTime = System.currentTimeMillis(); - - } - - - public MavenProject getProject() - { - return project; - } - - public void setComplete() - { - endTime = System.currentTimeMillis(); - } - - public void addWait( MavenProject upstreamProject, ExecutionPlanItem inSchedule, long startWait ) - { - long now = System.currentTimeMillis(); - dependencies.add( new DependencyLogEntry( upstreamProject, inSchedule, startWait, now, null ) ); - } - - public void addDependency( MavenProject upstreamProject, String message ) - { - dependencies.add( new DependencyLogEntry( upstreamProject, message ) ); - } - - public String toString( long rootStart ) - { - StringBuilder result = new StringBuilder(); - result.append( String.format( "%1d %2d ", startTime - rootStart, endTime - rootStart ) ); - result.append( project.getName() ); - result.append( " " ); - result.append( getMojoExecutionDescription( executionPlanItem ) ); - if ( dependencies.size() > 0 ) - { - result.append( "\n" ); - for ( DependencyLogEntry waitLogEntry : dependencies ) - { - result.append( " " ); - result.append( waitLogEntry.toString() ); - result.append( "\n" ); - } - } - return result.toString(); - } - - - public Object toGraph( long rootStart ) - { - StringBuilder result = new StringBuilder(); - if ( dependencies.size() > 0 ) - { - for ( DependencyLogEntry waitLogEntry : dependencies ) - { - result.append( " " ); - result.append( nodeKey( project, executionPlanItem ) ); - result.append( " -> " ); - result.append( waitLogEntry.toNodeKey() ); - result.append( waitLogEntry.toNodeDescription( rootStart ) ); - result.append( "\n" ); - } - } - else - { - result.append( " " ); - result.append( nodeKey( project, executionPlanItem ) ); - result.append( "\n" ); - } - return result.toString(); - } - - private static String nodeKey( MavenProject mavenProject, ExecutionPlanItem executionPlanItem ) - { - String key = mavenProject.getArtifactId(); - if ( executionPlanItem != null ) - { - key += "_" + getMojoExecutionDescription( executionPlanItem ); - } - return key.replace( ".", "_" ).replace( ":", "_" ); - } - - private static String getMojoExecutionDescription( ExecutionPlanItem executionPlanItem ) - { - if ( executionPlanItem.getMojoExecution() != null ) - { - return executionPlanItem.getMojoExecution().getArtifactId() + getLifeCyclePhase( executionPlanItem ); - } - else - { - return ""; - } - } - - private static String getLifeCyclePhase( ExecutionPlanItem executionPlanItem ) - { - return executionPlanItem.getLifecyclePhase() != null ? "[" + executionPlanItem.getLifecyclePhase() + "]" : ""; - } - - - class DependencyLogEntry - { - private final ExecutionPlanItem executionPlanItem; - - private final MavenProject upstreamProject; - - private final Long start; - - private final Long stop; - - private final String message; - - DependencyLogEntry( MavenProject upstreamProject, ExecutionPlanItem executionPlanItem, Long start, Long stop, - String message ) - { - this.upstreamProject = upstreamProject; - this.executionPlanItem = executionPlanItem; - this.start = start; - this.stop = stop; - this.message = message; - } - - DependencyLogEntry( MavenProject upstreamProject, String message ) - { - this( upstreamProject, null, null, null, message ); - } - - public String toString() - { - return upstreamProject.getName() + ":" + getExecutionPlanItem() + getElapsed() + getMessage(); - } - - public String toNodeKey() - { - return nodeKey( upstreamProject, executionPlanItem ); - } - - public String toNodeDescription( long rootStart ) - { - return ""; - } - - - private String getMessage() - { - return message != null ? message : ""; - } - - private String getExecutionPlanItem() - { - if ( executionPlanItem != null ) - { - return getMojoExecutionDescription( executionPlanItem ); - } - else - { - return ""; - } - } - - private String getElapsed() - { - if ( start != null && stop != null ) - { - long elapsed = stop - start; - return elapsed > 0 ? ", wait=" + elapsed : ""; - } - return ""; - } - } - -} diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ConcurrentBuildLogger.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ConcurrentBuildLogger.java deleted file mode 100644 index 2dcd348941..0000000000 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ConcurrentBuildLogger.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.apache.maven.lifecycle.internal.builder.weave; - -/* - * 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.lifecycle.internal.ExecutionPlanItem; -import org.apache.maven.project.MavenProject; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Handles all concurrency-related logging. - *

- * The logging/diagnostic needs of a concurrent build are different from a linear build. This - * delta required to analyze a concurrent build is located here. - *

- * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. - * - * @since 3.0 - * @author Kristian Rosenvold - */ -public class ConcurrentBuildLogger -{ - private final long startTime; - - private final Map threadMap = new ConcurrentHashMap(); - - public ConcurrentBuildLogger() - { - startTime = System.currentTimeMillis(); - } - - - List items = Collections.synchronizedList( new ArrayList() ); - - public BuildLogItem createBuildLogItem( MavenProject project, ExecutionPlanItem current ) - { - threadMap.put( project, Thread.currentThread() ); - BuildLogItem result = new BuildLogItem( project, current ); - items.add( result ); - return result; - } - - public String toString() - { - StringBuilder result = new StringBuilder(); - for ( Map.Entry mavenProjectThreadEntry : threadMap.entrySet() ) - { - result.append( mavenProjectThreadEntry.getKey().getName() ); - result.append( " ran on " ); - result.append( mavenProjectThreadEntry.getValue().getName() ); - result.append( "\n" ); - } - - for ( BuildLogItem builtLogItem : items ) - { - result.append( builtLogItem.toString( startTime ) ); - result.append( "\n" ); - } - return result.toString(); - } - - public String toGraph() - { - StringBuilder result = new StringBuilder(); - - Map> multiMap = new HashMap>(); - for ( BuildLogItem builtLogItem : items ) - { - MavenProject project = builtLogItem.getProject(); - Collection bag = multiMap.get( project ); - if ( bag == null ) - { - bag = new ArrayList(); - multiMap.put( project, bag ); - } - bag.add( builtLogItem ); - } - - result.append( "digraph build" ); - result.append( " {\n " ); - - for ( MavenProject mavenProject : multiMap.keySet() ) - { - final Collection builtLogItems = multiMap.get( mavenProject ); - result.append( " subgraph " ); - result.append( mavenProject.getArtifactId() ); - result.append( " {\n" ); - - for ( BuildLogItem builtLogItem : builtLogItems ) - { - result.append( builtLogItem.toGraph( startTime ) ); - } - - result.append( "\n }\n" ); - } - - result.append( "\n}\n " ); - return result.toString(); - } - -} diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/CurrentPhaseForThread.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/CurrentPhaseForThread.java deleted file mode 100644 index f52f4e019f..0000000000 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/CurrentPhaseForThread.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.apache.maven.lifecycle.internal.builder.weave; - -/* - * 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. - *

- * This class is used in weave-mode only , there may be better ways of doing this once the dust settles. - * - * @since 3.0 - * @author Kristian Rosenvold - */ -class CurrentPhaseForThread -{ - private static final InheritableThreadLocal THREAD_PHASE = new InheritableThreadLocal(); - - public static void setPhase( String phase ) - { - THREAD_PHASE.set( phase ); - } - - public static boolean isPhase( String phase ) - { - return phase.equals( THREAD_PHASE.get() ); - } - -} diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ThreadLockedArtifact.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ThreadLockedArtifact.java deleted file mode 100644 index 7a0e117018..0000000000 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/ThreadLockedArtifact.java +++ /dev/null @@ -1,320 +0,0 @@ -package org.apache.maven.lifecycle.internal.builder.weave; - -/* - * 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 conditionally suspends on getFile for anything but the thread it is locked to. - * - * @since 3.0 - */ -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 THREAD_ARTIFACT = - new InheritableThreadLocal(); - - public void attachToThread() - { - THREAD_ARTIFACT.set( this ); - } - - public File getFile() - { - final ThreadLockedArtifact lockedArtifact = THREAD_ARTIFACT.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 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 getDependencyTrail() - { - return real.getDependencyTrail(); - } - - public void setDependencyTrail( List 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 getAvailableVersions() - { - return real.getAvailableVersions(); - } - - public void setAvailableVersions( List 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 ); - } -} diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/WeaveBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/WeaveBuilder.java deleted file mode 100644 index 193eca67f9..0000000000 --- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/weave/WeaveBuilder.java +++ /dev/null @@ -1,521 +0,0 @@ -package org.apache.maven.lifecycle.internal.builder.weave; - -/* - * 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.ArtifactUtils; -import org.apache.maven.execution.BuildSuccess; -import org.apache.maven.execution.ExecutionEvent; -import org.apache.maven.execution.MavenExecutionRequest; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.lifecycle.LifecycleExecutionException; -import org.apache.maven.lifecycle.MavenExecutionPlan; -import org.apache.maven.lifecycle.Schedule; -import org.apache.maven.lifecycle.internal.BuildThreadFactory; -import org.apache.maven.lifecycle.internal.DependencyContext; -import org.apache.maven.lifecycle.internal.ExecutionEventCatapult; -import org.apache.maven.lifecycle.internal.ExecutionPlanItem; -import org.apache.maven.lifecycle.internal.LifecycleDebugLogger; -import org.apache.maven.lifecycle.internal.MojoExecutor; -import org.apache.maven.lifecycle.internal.PhaseRecorder; -import org.apache.maven.lifecycle.internal.ProjectBuildList; -import org.apache.maven.lifecycle.internal.ProjectSegment; -import org.apache.maven.lifecycle.internal.ReactorBuildStatus; -import org.apache.maven.lifecycle.internal.ReactorContext; -import org.apache.maven.lifecycle.internal.TaskSegment; -import org.apache.maven.lifecycle.internal.builder.Builder; -import org.apache.maven.lifecycle.internal.builder.BuilderCommon; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.component.annotations.Component; -import org.codehaus.plexus.component.annotations.Requirement; -import org.codehaus.plexus.logging.Logger; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletionService; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * Builds the full lifecycle in weave-mode (phase by phase as opposed to project-by-project) - *

- * NOTE: Weave mode is still experimental. It may be either promoted to first class citizen at some later point in time, - * and it may also be removed entirely. Weave mode has much more aggressive concurrency behaviour than regular threaded - * mode, and as such is still under test wrt cross platform stability. - *

- * To remove weave mode from m3, the following should be removed: ExecutionPlanItem.schedule w/setters and getters - * DefaultLifeCycles.getScheduling() and all its use ReactorArtifactRepository has a reference to isWeave too. This - * class and its usage - * - * @since 3.0 - * @author Kristian Rosenvold Builds one or more lifecycles for a full module - *

- * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. - */ -@Component( role = Builder.class, hint = "weave" ) -public class WeaveBuilder - implements Builder -{ - - @Requirement - private MojoExecutor mojoExecutor; - - @Requirement - private BuilderCommon builderCommon; - - @Requirement - private Logger logger; - - @Requirement - private ExecutionEventCatapult eventCatapult; - - @Requirement - private LifecycleDebugLogger lifecycleDebugLogger; - - private Map executionPlans = new HashMap(); - - public WeaveBuilder() - { - } - - public WeaveBuilder( MojoExecutor mojoExecutor, BuilderCommon builderCommon, Logger logger, - ExecutionEventCatapult eventCatapult, LifecycleDebugLogger lifecycleDebugLogger ) - { - this.mojoExecutor = mojoExecutor; - this.builderCommon = builderCommon; - this.logger = logger; - this.eventCatapult = eventCatapult; - this.lifecycleDebugLogger = lifecycleDebugLogger; - } - - public void build( MavenSession session, ReactorContext buildContext, ProjectBuildList projectBuilds, - List taskSegments, ReactorBuildStatus reactorBuildStatus ) - throws ExecutionException, InterruptedException - { - lifecycleDebugLogger.logWeavePlan( session ); - - ExecutorService executor = - Executors.newFixedThreadPool( Math.min( session.getRequest().getDegreeOfConcurrency(), - session.getProjects().size() ), new BuildThreadFactory() ); - - try - { - - ConcurrentBuildLogger concurrentBuildLogger = new ConcurrentBuildLogger(); - CompletionService service = new ExecutorCompletionService( executor ); - - try - { - for ( MavenProject mavenProject : session.getProjects() ) - { - Artifact mainArtifact = mavenProject.getArtifact(); - if ( mainArtifact != null && !( mainArtifact instanceof ThreadLockedArtifact ) ) - { - ThreadLockedArtifact threadLockedArtifact = new ThreadLockedArtifact( mainArtifact ); - mavenProject.setArtifact( threadLockedArtifact ); - } - } - - final List> futures = new ArrayList>(); - final Map> plans = - new HashMap>(); - - for ( TaskSegment taskSegment : taskSegments ) - { - ProjectBuildList segmentChunks = projectBuilds.getByTaskSegment( taskSegment ); - Set projectArtifacts = new HashSet(); - for ( ProjectSegment segmentChunk : segmentChunks ) - { - Artifact artifact = segmentChunk.getProject().getArtifact(); - if ( artifact != null ) - { - projectArtifacts.add( artifact ); - } - } - for ( ProjectSegment projectBuild : segmentChunks ) - { - plans.put( projectBuild, executor.submit( createEPFuture( projectBuild, projectArtifacts ) ) ); - } - - for ( ProjectSegment projectSegment : plans.keySet() ) - { - executionPlans.put( projectSegment.getProject(), plans.get( projectSegment ).get() ); - - } - for ( ProjectSegment projectBuild : segmentChunks ) - { - try - { - final MavenExecutionPlan executionPlan = plans.get( projectBuild ).get(); - - DependencyContext dependencyContext = - mojoExecutor.newDependencyContext( session, executionPlan.getMojoExecutions() ); - - final Callable projectBuilder = - createCallableForBuildingOneFullModule( buildContext, session, reactorBuildStatus, - executionPlan, projectBuild, dependencyContext, - concurrentBuildLogger ); - - futures.add( service.submit( projectBuilder ) ); - } - catch ( Exception e ) - { - throw new ExecutionException( e ); - } - } - - for ( Future buildFuture : futures ) - { - buildFuture.get(); // At this point, this build *is* finished. - // Do not leak threads past here or evil gremlins will get you! - } - futures.clear(); - } - } - finally - { - projectBuilds.closeAll(); - } - logger.info( concurrentBuildLogger.toString() ); - } - finally - { - executor.shutdown(); - // If the builder has terminated with an exception we want to catch any stray threads before going - // to System.exit in the mavencli. - executor.awaitTermination( 5, TimeUnit.SECONDS ); - } - } - - private Callable createEPFuture( final ProjectSegment projectSegment, - final Set projectArtifacts ) - { - return new Callable() - { - public MavenExecutionPlan call() - throws Exception - { - return builderCommon.resolveBuildPlan( projectSegment.getSession(), projectSegment.getProject(), - projectSegment.getTaskSegment(), projectArtifacts ); - } - }; - } - - private Callable createCallableForBuildingOneFullModule( final ReactorContext reactorContext, - final MavenSession rootSession, - final ReactorBuildStatus reactorBuildStatus, - final MavenExecutionPlan executionPlan, - final ProjectSegment projectBuild, - final DependencyContext dependencyContext, - final ConcurrentBuildLogger concurrentBuildLogger ) - { - return new Callable() - { - public ProjectSegment call() - throws Exception - { - Iterator planItems = executionPlan.iterator(); - ExecutionPlanItem current = planItems.hasNext() ? planItems.next() : null; - ThreadLockedArtifact threadLockedArtifact = - (ThreadLockedArtifact) projectBuild.getProject().getArtifact(); - if ( threadLockedArtifact != null ) - { - threadLockedArtifact.attachToThread(); - } - long buildStartTime = System.currentTimeMillis(); - - // muxer.associateThreadWithProjectSegment( projectBuild ); - - if ( reactorBuildStatus.isHaltedOrBlacklisted( projectBuild.getProject() ) ) - { - eventCatapult.fire( ExecutionEvent.Type.ProjectSkipped, projectBuild.getSession(), null ); - return null; - } - - eventCatapult.fire( ExecutionEvent.Type.ProjectStarted, projectBuild.getSession(), null ); - - Collection dependencyLinks = getUpstreamReactorDependencies( projectBuild ); - - try - { - PhaseRecorder phaseRecorder = new PhaseRecorder( projectBuild.getProject() ); - long totalMojoTime = 0; - long mojoStart; - while ( current != null && !reactorBuildStatus.isHaltedOrBlacklisted( projectBuild.getProject() ) ) - { - - BuildLogItem builtLogItem = - concurrentBuildLogger.createBuildLogItem( projectBuild.getProject(), current ); - final Schedule schedule = current.getSchedule(); - - mojoStart = System.currentTimeMillis(); - buildExecutionPlanItem( current, phaseRecorder, schedule, reactorContext, projectBuild, - dependencyContext ); - totalMojoTime += ( System.currentTimeMillis() - mojoStart ); - - current.setComplete(); - builtLogItem.setComplete(); - - ExecutionPlanItem nextPlanItem = planItems.hasNext() ? planItems.next() : null; - if ( nextPlanItem != null && phaseRecorder.isDifferentPhase( nextPlanItem.getMojoExecution() ) ) - { - - final Schedule scheduleOfNext = nextPlanItem.getSchedule(); - if ( scheduleOfNext == null || !scheduleOfNext.isParallel() ) - { - waitForAppropriateUpstreamExecutionsToFinish( builtLogItem, nextPlanItem, projectBuild, - scheduleOfNext ); - } - - for ( ArtifactLink dependencyLink : dependencyLinks ) - { - dependencyLink.resolveFromUpstream(); - } - } - current = nextPlanItem; - } - - final BuildSuccess summary = new BuildSuccess( projectBuild.getProject(), totalMojoTime ); // - - // waitingTime - reactorContext.getResult().addBuildSummary( summary ); - eventCatapult.fire( ExecutionEvent.Type.ProjectSucceeded, projectBuild.getSession(), null ); - } - catch ( Exception e ) - { - builderCommon.handleBuildError( reactorContext, rootSession, projectBuild.getSession(), - projectBuild.getProject(), e, buildStartTime ); - } - finally - { - if ( current != null ) - { - executionPlan.forceAllComplete(); - } - // muxer.setThisModuleComplete( projectBuild ); - } - return null; - } - - }; - } - - private void waitForAppropriateUpstreamExecutionsToFinish( BuildLogItem builtLogItem, - ExecutionPlanItem nextPlanItem, - ProjectSegment projectBuild, Schedule scheduleOfNext ) - throws InterruptedException - { - for ( MavenProject upstreamProject : projectBuild.getImmediateUpstreamProjects() ) - { - final MavenExecutionPlan upstreamPlan = executionPlans.get( upstreamProject ); - final String nextPhase = - scheduleOfNext != null && scheduleOfNext.hasUpstreamPhaseDefined() ? scheduleOfNext.getUpstreamPhase() - : nextPlanItem.getLifecyclePhase(); - final ExecutionPlanItem upstream = upstreamPlan.findLastInPhase( nextPhase ); - - if ( upstream != null ) - { - long startWait = System.currentTimeMillis(); - upstream.waitUntilDone(); - builtLogItem.addWait( upstreamProject, upstream, startWait ); - } - else if ( !upstreamPlan.containsPhase( nextPhase ) ) - { - // Still a bit of a kludge; if we cannot connect in a sensible way to - // the upstream build plan we just revert to waiting for it all to - // complete. Real problem is per-mojo phase->lifecycle mapping - builtLogItem.addDependency( upstreamProject, "No phase tracking possible " ); - upstreamPlan.waitUntilAllDone(); - } - else - { - builtLogItem.addDependency( upstreamProject, "No schedule" ); - } - } - } - - private Collection getUpstreamReactorDependencies( ProjectSegment projectBuild ) - { - Collection result = new ArrayList(); - for ( MavenProject upstreamProject : projectBuild.getTransitiveUpstreamProjects() ) - { - Artifact upStreamArtifact = upstreamProject.getArtifact(); - if ( upStreamArtifact != null ) - { - Artifact dependencyArtifact = findDependency( projectBuild.getProject(), upStreamArtifact ); - if ( dependencyArtifact != null ) - { - result.add( new ArtifactLink( dependencyArtifact, upStreamArtifact ) ); - } - } - - Artifact upStreamTestScopedArtifact = findTestScopedArtifact( upstreamProject ); - if ( upStreamTestScopedArtifact != null ) - { - Artifact dependencyArtifact = findDependency( projectBuild.getProject(), upStreamArtifact ); - if ( dependencyArtifact != null ) - { - result.add( new ArtifactLink( dependencyArtifact, upStreamTestScopedArtifact ) ); - } - } - } - return result; - } - - private Artifact findTestScopedArtifact( MavenProject upstreamProject ) - { - if ( upstreamProject == null ) - { - return null; - } - - List artifactList = upstreamProject.getAttachedArtifacts(); - for ( Artifact artifact : artifactList ) - { - if ( Artifact.SCOPE_TEST.equals( artifact.getScope() ) ) - { - return artifact; - } - } - 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 || isThreadLockedAndEmpty( upStreamArtifact ) ) - { - return null; - } - - String key = - ArtifactUtils.key( upStreamArtifact.getGroupId(), upStreamArtifact.getArtifactId(), - upStreamArtifact.getVersion() ); - final Set deps = project.getDependencyArtifacts(); - for ( Artifact dep : deps ) - { - String depKey = ArtifactUtils.key( dep.getGroupId(), dep.getArtifactId(), dep.getVersion() ); - if ( key.equals( depKey ) ) - { - return dep; - } - } - return null; - - } - - private void buildExecutionPlanItem( ExecutionPlanItem current, PhaseRecorder phaseRecorder, Schedule schedule, - ReactorContext reactorContext, ProjectSegment projectBuild, - DependencyContext dependencyContext ) - throws LifecycleExecutionException - { - if ( schedule != null && schedule.isMojoSynchronized() ) - { - synchronized ( current.getPlugin() ) - { - buildExecutionPlanItem( reactorContext, current, projectBuild, dependencyContext, phaseRecorder ); - } - } - else - { - buildExecutionPlanItem( reactorContext, current, projectBuild, dependencyContext, phaseRecorder ); - } - } - - private void buildExecutionPlanItem( ReactorContext reactorContext, ExecutionPlanItem node, - ProjectSegment projectBuild, DependencyContext dependencyContext, - PhaseRecorder phaseRecorder ) - throws LifecycleExecutionException - { - - MavenProject currentProject = projectBuild.getProject(); - - long buildStartTime = System.currentTimeMillis(); - - CurrentPhaseForThread.setPhase( node.getLifecyclePhase() ); - - MavenSession sessionForThisModule = projectBuild.getSession(); - try - { - - if ( reactorContext.getReactorBuildStatus().isHaltedOrBlacklisted( currentProject ) ) - { - return; - } - - BuilderCommon.attachToThread( currentProject ); - - mojoExecutor.execute( sessionForThisModule, node.getMojoExecution(), reactorContext.getProjectIndex(), - dependencyContext, phaseRecorder ); - - final BuildSuccess summary = new BuildSuccess( currentProject, System.currentTimeMillis() - buildStartTime ); - reactorContext.getResult().addBuildSummary( summary ); - } - finally - { - Thread.currentThread().setContextClassLoader( reactorContext.getOriginalContextClassLoader() ); - } - } - - public static boolean isWeaveMode( MavenExecutionRequest request ) - { - return "true".equals( request.getUserProperties().getProperty( "maven3.weaveMode" ) ); - } - - public static void setWeaveMode( Properties properties ) - { - properties.setProperty( "maven3.weaveMode", "true" ); - } - - static class ArtifactLink - { - private final Artifact artifactInThis; - - private final Artifact upstream; - - ArtifactLink( Artifact artifactInThis, Artifact upstream ) - { - this.artifactInThis = artifactInThis; - this.upstream = upstream; - } - - public void resolveFromUpstream() - { - artifactInThis.setFile( upstream.getFile() ); - artifactInThis.setRepository( upstream.getRepository() ); - artifactInThis.setResolved( true ); // Or maybe upstream.isResolved().... - } - } -} diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrentBuildLoggerTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrentBuildLoggerTest.java deleted file mode 100644 index 5a7e105fa6..0000000000 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrentBuildLoggerTest.java +++ /dev/null @@ -1,77 +0,0 @@ -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 java.util.Iterator; - -import junit.framework.TestCase; - -import org.apache.maven.execution.MavenSession; -import org.apache.maven.lifecycle.MavenExecutionPlan; -import org.apache.maven.lifecycle.internal.builder.weave.BuildLogItem; -import org.apache.maven.lifecycle.internal.builder.weave.ConcurrentBuildLogger; -import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub; -import org.apache.maven.project.MavenProject; - -/** - * @author Kristian Rosenvold - */ -public class ConcurrentBuildLoggerTest - extends TestCase -{ - @SuppressWarnings( "unused" ) - public void testToGraph() - throws Exception - { - ConcurrentBuildLogger concurrentBuildLogger = new ConcurrentBuildLogger(); - - MojoDescriptorCreator mojoDescriptorCreator = - LifecycleExecutionPlanCalculatorTest.createMojoDescriptorCreator(); - LifecycleExecutionPlanCalculator lifecycleExecutionPlanCalculator = - LifecycleExecutionPlanCalculatorTest.createExecutionPlaceCalculator( mojoDescriptorCreator ); - - MavenProject A = ProjectDependencyGraphStub.B; - MavenProject B = ProjectDependencyGraphStub.C; - - final MavenSession session1 = ProjectDependencyGraphStub.getMavenSession( A ); - - final GoalTask goalTask1 = new GoalTask( "compiler:compile" ); - final GoalTask goalTask2 = new GoalTask( "surefire:test" ); - final TaskSegment taskSegment1 = new TaskSegment( false, goalTask1, goalTask2 ); - - MavenExecutionPlan executionPlan = - lifecycleExecutionPlanCalculator.calculateExecutionPlan( session1, A, taskSegment1.getTasks() ); - - MavenExecutionPlan executionPlan2 = - lifecycleExecutionPlanCalculator.calculateExecutionPlan( session1, B, taskSegment1.getTasks() ); - - final Iterator planItemIterator = executionPlan.iterator(); - final BuildLogItem a1 = concurrentBuildLogger.createBuildLogItem( A, planItemIterator.next() ); - - final BuildLogItem a2 = concurrentBuildLogger.createBuildLogItem( A, planItemIterator.next() ); - - final Iterator plan2ItemIterator = executionPlan.iterator(); - final BuildLogItem b1 = concurrentBuildLogger.createBuildLogItem( B, plan2ItemIterator.next() ); - final BuildLogItem b2 = concurrentBuildLogger.createBuildLogItem( B, plan2ItemIterator.next() ); - - b1.addDependency( A, "Project dependency" ); - final Iterator aPlan = executionPlan.iterator(); - b1.addWait( A, aPlan.next(), System.currentTimeMillis() ); - b2.addWait( A, aPlan.next(), System.currentTimeMillis() ); - final String response = concurrentBuildLogger.toGraph(); - assertTrue( response.contains( "digraph" ) ); - } -} diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java deleted file mode 100644 index 44f231123b..0000000000 --- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleWeaveBuilderTest.java +++ /dev/null @@ -1,142 +0,0 @@ -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 junit.framework.TestCase; - -import org.apache.maven.execution.DefaultMavenExecutionResult; -import org.apache.maven.execution.MavenExecutionResult; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.lifecycle.LifecycleNotFoundException; -import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException; -import org.apache.maven.lifecycle.internal.builder.BuilderCommon; -import org.apache.maven.lifecycle.internal.builder.weave.WeaveBuilder; -import org.apache.maven.lifecycle.internal.stub.ExecutionEventCatapultStub; -import org.apache.maven.lifecycle.internal.stub.LifecycleExecutionPlanCalculatorStub; -import org.apache.maven.lifecycle.internal.stub.LifecycleTaskSegmentCalculatorStub; -import org.apache.maven.lifecycle.internal.stub.LoggerStub; -import org.apache.maven.lifecycle.internal.stub.MojoExecutorStub; -import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub; -import org.apache.maven.plugin.InvalidPluginDescriptorException; -import org.apache.maven.plugin.MojoNotFoundException; -import org.apache.maven.plugin.PluginDescriptorParsingException; -import org.apache.maven.plugin.PluginNotFoundException; -import org.apache.maven.plugin.PluginResolutionException; -import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException; -import org.apache.maven.plugin.version.PluginVersionResolutionException; - -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorCompletionService; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * @author Kristian Rosenvold - */ -public class LifecycleWeaveBuilderTest - extends TestCase -{ - -/* public void testBuildProjectSynchronously() - throws Exception - { - final CompletionService service = new CompletionServiceStub( true ); - final ProjectBuildList projectBuildList = runWithCompletionService( service ); - assertEquals( "Expect all tasks to be scheduled", projectBuildList.size(), - ( (CompletionServiceStub) service ).size() ); - } - */ - - @SuppressWarnings( "unused" ) - public void testBuildProjectThreaded() - throws Exception - { - ExecutorService executor = Executors.newFixedThreadPool( 10 ); - ExecutorCompletionService service = new ExecutorCompletionService( executor ); - runWithCompletionService( executor ); - executor.shutdown(); - } - - @SuppressWarnings( "unused" ) - public void testBuildProjectThreadedAggressive() - throws Exception - { - ExecutorService executor = Executors.newFixedThreadPool( 10 ); - ExecutorCompletionService service = new ExecutorCompletionService( executor ); - runWithCompletionService( executor ); - executor.shutdown(); - } - - private ProjectBuildList runWithCompletionService( ExecutorService service ) - throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException, - MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException, - PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException, - ExecutionException, InterruptedException - { - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - try - { - BuildListCalculator buildListCalculator = new BuildListCalculator(); - final MavenSession session = ProjectDependencyGraphStub.getMavenSession(); - List taskSegments = getTaskSegmentCalculator().calculateTaskSegments( session ); - ProjectBuildList projectBuildList = buildListCalculator.calculateProjectBuilds( session, taskSegments ); - - final MojoExecutorStub mojoExecutorStub = new MojoExecutorStub(); - final WeaveBuilder builder = getWeaveBuilder( mojoExecutorStub ); - final ReactorContext buildContext = createBuildContext( session ); - ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() ); - builder.build( session, buildContext, projectBuildList, taskSegments, reactorBuildStatus ); - - LifecycleExecutionPlanCalculatorStub lifecycleExecutionPlanCalculatorStub = - new LifecycleExecutionPlanCalculatorStub(); - final int expected = lifecycleExecutionPlanCalculatorStub.getNumberOfExceutions( projectBuildList ); - assertEquals( "All executions should be scheduled", expected, mojoExecutorStub.executions.size() ); - return projectBuildList; - } - finally - { - Thread.currentThread().setContextClassLoader( loader ); - } - } - - - private static LifecycleTaskSegmentCalculator getTaskSegmentCalculator() - { - return new LifecycleTaskSegmentCalculatorStub(); - } - - private ReactorContext createBuildContext( MavenSession session ) - { - MavenExecutionResult mavenExecutionResult = new DefaultMavenExecutionResult(); - ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() ); - return new ReactorContext( mavenExecutionResult, null, null, reactorBuildStatus ); - } - - private WeaveBuilder getWeaveBuilder( MojoExecutor mojoExecutor ) - { - final BuilderCommon builderCommon = getBuilderCommon(); - final LoggerStub loggerStub = new LoggerStub(); - return new WeaveBuilder( mojoExecutor, builderCommon, loggerStub, new ExecutionEventCatapultStub(), new LifecycleDebugLogger( loggerStub ) ); - } - - private BuilderCommon getBuilderCommon() - { - final LifecycleDebugLogger logger = new LifecycleDebugLogger( new LoggerStub() ); - return new BuilderCommon( logger, new LifecycleExecutionPlanCalculatorStub(), - new LoggerStub() ); - } -} diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index 8ee2830bd0..79871df523 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -1087,14 +1087,7 @@ else if ( commandLine.hasOption( CLIManager.ALSO_MAKE ) if ( threadConfiguration != null ) { - if ( threadConfiguration.contains( "W" ) ) - { - request.setBuilderId( "weave" ); - } - else - { - request.setBuilderId( "multithreaded" ); - } + request.setBuilderId( "multithreaded" ); int threads = threadConfiguration.contains( "C" ) ? Integer.valueOf( threadConfiguration.replace( "C", "" ) )