You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2020/08/17 19:29:20 UTC
[maven-resolver] branch master updated: [MRESOLVER-130] Move
GlobalSyncContextFactory to a separate module
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/master by this push:
new 9670c14 [MRESOLVER-130] Move GlobalSyncContextFactory to a separate module
9670c14 is described below
commit 9670c1474e7591521eb40ed511ebbeddad6b5cc3
Author: Michael Osipov <mi...@apache.org>
AuthorDate: Thu Aug 6 20:50:27 2020 +0200
[MRESOLVER-130] Move GlobalSyncContextFactory to a separate module
This closes #66
---
.../internal/impl/DefaultSyncContextFactory.java | 36 +----
maven-resolver-synccontext-global/pom.xml | 91 +++++++++++++
.../aether/internal/impl/TrackingFileManager.java | 151 +++++++++++++++++++++
.../synccontext/GlobalSyncContextFactory.java | 27 ++--
.../src/site/markdown/index.md.vm | 62 +++++++++
.../src/site/site.xml | 37 +++++
pom.xml | 9 ++
7 files changed, 368 insertions(+), 45 deletions(-)
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java
index be89735..1efefe7 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java
@@ -20,8 +20,6 @@ package org.eclipse.aether.internal.impl;
*/
import java.util.Collection;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.inject.Named;
@@ -30,59 +28,31 @@ import org.eclipse.aether.SyncContext;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.impl.SyncContextFactory;
import org.eclipse.aether.metadata.Metadata;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.inject.Singleton;
/**
- * A factory to create synchronization contexts. This default implementation uses fair global locking
- * based on {@link ReentrantReadWriteLock}. Explicit artifacts and metadata passed are ignored.
+ * A factory to create synchronization contexts. This default implementation does not provide any real
+ * synchronization but merely completes the repository system.
*/
@Named
-@Singleton
public class DefaultSyncContextFactory
implements SyncContextFactory
{
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock( true );
public SyncContext newInstance( RepositorySystemSession session, boolean shared )
{
- return new DefaultSyncContext( shared ? lock.readLock() : lock.writeLock(), shared );
+ return new DefaultSyncContext();
}
static class DefaultSyncContext
implements SyncContext
{
- private static final Logger LOGGER = LoggerFactory.getLogger( DefaultSyncContext.class );
-
- private final Lock lock;
- private final boolean shared;
- private int lockHoldCount;
-
- DefaultSyncContext( Lock lock, boolean shared )
- {
- this.lock = lock;
- this.shared = shared;
- }
public void acquire( Collection<? extends Artifact> artifact, Collection<? extends Metadata> metadata )
{
- LOGGER.trace( "Acquiring global {} lock (currently held: {})",
- shared ? "read" : "write", lockHoldCount );
- lock.lock();
- lockHoldCount++;
}
public void close()
{
- while ( lockHoldCount != 0 )
- {
- LOGGER.trace( "Releasing global {} lock (currently held: {})",
- shared ? "read" : "write", lockHoldCount );
- lock.unlock();
- lockHoldCount--;
- }
}
}
diff --git a/maven-resolver-synccontext-global/pom.xml b/maven-resolver-synccontext-global/pom.xml
new file mode 100644
index 0000000..60d755f
--- /dev/null
+++ b/maven-resolver-synccontext-global/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.maven.resolver</groupId>
+ <artifactId>maven-resolver</artifactId>
+ <version>1.5.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>maven-resolver-synccontext-global</artifactId>
+
+ <name>Maven Artifact Resolver Sync Context Global</name>
+ <description>
+ A synchronization context implementation using a global lock.
+ </description>
+
+ <properties>
+ <javaVersion>8</javaVersion>
+ <Automatic-Module-Name>org.apache.maven.resolver.synccontext.global</Automatic-Module-Name>
+ <Bundle-SymbolicName>${Automatic-Module-Name}</Bundle-SymbolicName>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.resolver</groupId>
+ <artifactId>maven-resolver-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.resolver</groupId>
+ <artifactId>maven-resolver-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>javax.annotation-api</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.sisu</groupId>
+ <artifactId>sisu-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.directory}/osgi/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/maven-resolver-synccontext-global/src/main/java/org/eclipse/aether/internal/impl/TrackingFileManager.java b/maven-resolver-synccontext-global/src/main/java/org/eclipse/aether/internal/impl/TrackingFileManager.java
new file mode 100644
index 0000000..ffc200f
--- /dev/null
+++ b/maven-resolver-synccontext-global/src/main/java/org/eclipse/aether/internal/impl/TrackingFileManager.java
@@ -0,0 +1,151 @@
+package org.eclipse.aether.internal.impl;
+
+/*
+ * 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.eclipse.aether.SyncContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Manages access to a properties file. This override drops internal synchronization becauses it
+ * relies on external synchronization provided by outer {@link SyncContext} instances.
+ */
+class TrackingFileManager
+{
+
+ private static final Logger LOGGER = LoggerFactory.getLogger( TrackingFileManager.class );
+
+ public Properties read( File file )
+ {
+ FileInputStream stream = null;
+ try
+ {
+ if ( !file.exists() )
+ {
+ return null;
+ }
+
+ stream = new FileInputStream( file );
+
+ Properties props = new Properties();
+ props.load( stream );
+
+ return props;
+ }
+ catch ( IOException e )
+ {
+ LOGGER.warn( "Failed to read tracking file {}", file, e );
+ }
+ finally
+ {
+ close( stream, file );
+ }
+
+ return null;
+ }
+
+ public Properties update( File file, Map<String, String> updates )
+ {
+ Properties props = new Properties();
+
+ File directory = file.getParentFile();
+ if ( !directory.mkdirs() && !directory.exists() )
+ {
+ LOGGER.warn( "Failed to create parent directories for tracking file {}", file );
+ return props;
+ }
+
+ RandomAccessFile raf = null;
+ try
+ {
+ raf = new RandomAccessFile( file, "rw" );
+
+ if ( file.canRead() )
+ {
+ byte[] buffer = new byte[(int) raf.length()];
+
+ raf.readFully( buffer );
+
+ ByteArrayInputStream stream = new ByteArrayInputStream( buffer );
+
+ props.load( stream );
+ }
+
+ for ( Map.Entry<String, String> update : updates.entrySet() )
+ {
+ if ( update.getValue() == null )
+ {
+ props.remove( update.getKey() );
+ }
+ else
+ {
+ props.setProperty( update.getKey(), update.getValue() );
+ }
+ }
+
+ ByteArrayOutputStream stream = new ByteArrayOutputStream( 1024 * 2 );
+
+ LOGGER.debug( "Writing tracking file {}", file );
+ props.store( stream, "NOTE: This is a Maven Resolver internal implementation file"
+ + ", its format can be changed without prior notice." );
+
+ raf.seek( 0 );
+ raf.write( stream.toByteArray() );
+ raf.setLength( raf.getFilePointer() );
+ }
+ catch ( IOException e )
+ {
+ LOGGER.warn( "Failed to write tracking file {}", file, e );
+ }
+ finally
+ {
+ close( raf, file );
+ }
+
+ return props;
+ }
+
+ private void close( Closeable closeable, File file )
+ {
+ if ( closeable != null )
+ {
+ try
+ {
+ closeable.close();
+ }
+ catch ( IOException e )
+ {
+ LOGGER.warn( "Error closing tracking file {}", file, e );
+ }
+ }
+ }
+
+}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java b/maven-resolver-synccontext-global/src/main/java/org/eclipse/aether/synccontext/GlobalSyncContextFactory.java
similarity index 76%
copy from maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java
copy to maven-resolver-synccontext-global/src/main/java/org/eclipse/aether/synccontext/GlobalSyncContextFactory.java
index be89735..dcef3a1 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultSyncContextFactory.java
+++ b/maven-resolver-synccontext-global/src/main/java/org/eclipse/aether/synccontext/GlobalSyncContextFactory.java
@@ -1,4 +1,4 @@
-package org.eclipse.aether.internal.impl;
+package org.eclipse.aether.synccontext;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -23,7 +23,9 @@ import java.util.Collection;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.annotation.Priority;
import javax.inject.Named;
+import javax.inject.Singleton;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.SyncContext;
@@ -33,34 +35,35 @@ import org.eclipse.aether.metadata.Metadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.inject.Singleton;
-
/**
- * A factory to create synchronization contexts. This default implementation uses fair global locking
- * based on {@link ReentrantReadWriteLock}. Explicit artifacts and metadata passed are ignored.
+ * A singleton factory to create synchronization contexts using a global lock based on
+ * {@link ReentrantReadWriteLock}. Explicit artifacts and metadata passed are ignored.
+ * <p>
+ * <strong>Note: This component is still considered to be experimental, use with caution!</strong>
*/
@Named
+@Priority( Integer.MAX_VALUE )
@Singleton
-public class DefaultSyncContextFactory
+public class GlobalSyncContextFactory
implements SyncContextFactory
{
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock( true );
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public SyncContext newInstance( RepositorySystemSession session, boolean shared )
{
- return new DefaultSyncContext( shared ? lock.readLock() : lock.writeLock(), shared );
+ return new GlobalSyncContext( shared ? lock.readLock() : lock.writeLock(), shared );
}
- static class DefaultSyncContext
+ static class GlobalSyncContext
implements SyncContext
{
- private static final Logger LOGGER = LoggerFactory.getLogger( DefaultSyncContext.class );
+ private static final Logger LOGGER = LoggerFactory.getLogger( GlobalSyncContext.class );
private final Lock lock;
private final boolean shared;
private int lockHoldCount;
- DefaultSyncContext( Lock lock, boolean shared )
+ private GlobalSyncContext( Lock lock, boolean shared )
{
this.lock = lock;
this.shared = shared;
@@ -76,7 +79,7 @@ public class DefaultSyncContextFactory
public void close()
{
- while ( lockHoldCount != 0 )
+ while ( lockHoldCount > 0 )
{
LOGGER.trace( "Releasing global {} lock (currently held: {})",
shared ? "read" : "write", lockHoldCount );
diff --git a/maven-resolver-synccontext-global/src/site/markdown/index.md.vm b/maven-resolver-synccontext-global/src/site/markdown/index.md.vm
new file mode 100644
index 0000000..0990de7
--- /dev/null
+++ b/maven-resolver-synccontext-global/src/site/markdown/index.md.vm
@@ -0,0 +1,62 @@
+${esc.hash} Global Sync Context for Maven Resolver
+
+<!--
+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.
+-->
+
+<span style="color: red; font-size: 16pt">***Note***: *This component is still considered to be experimental, use with caution!*</span>
+
+The Global Sync Context is Java global lock factory for Maven Resolver to provide a concurrent-safe
+access from a single Maven instance to the same local Maven repository.
+
+For further details about the factory read the [Javadoc](./apidocs/org/eclipse/aether/synccontext/GlobalSyncContextFactory.html).
+
+${esc.hash}${esc.hash} Open Issues/Notes
+
+- It only works when dependency injection is used and not the bundled `AetherModule` or
+ `ServiceLocator` (Maven uses dependency injection).
+- Usage from plugins has not been tested yet.
+- The `furnace-maven-plugin` does not work this implementation because it uses `ServiceLocator` instead
+ of dependency injection.
+- The installation process has not been streamlined yet.
+
+${esc.hash}${esc.hash} Installation/Testing
+
+- Clone Maven Resolver and perform `mvn install`.
+- Clone Maven, change the Resolver version in Maven's parent POM to `${project.version}` and perform `mvn install`.
+- Extract `apache-maven-3.7.0-SNAPSHOT-bin.tar.gz` to a location of your choice.
+- Add/modify the following entries in `${maven.home}/conf/logging/simplelogger.properties`:
+ ```
+ org.slf4j.simpleLogger.showDateTime=true
+ org.slf4j.simpleLogger.showThreadName=true
+ org.slf4j.simpleLogger.showShortLogName=true
+ org.slf4j.simpleLogger.log.org.eclipse.aether=trace
+ ```
+- Go back to Resolver and run `mvn dependency:copy-dependencies -pl maven-resolver-synccontext-global`.
+- Copy the following dependencies from `maven-resolver-synccontext-global/target/dependency`
+ to `${maven.home}/lib/ext/`:
+ ```
+ ├── javax.annotation-api-1.3.2.jar
+ └── maven-resolver-synccontext-global-${project.version}.jar
+ ```
+ Dependencies which are already bundled with Maven have been omitted.
+- Now start a multithreaded Maven (`3.7.0-SNAPSHOT`) build on your project and you should see at least these lines:
+ ```
+ 4626 [main] [TRACE] GlobalSyncContextFactory$GlobalSyncContext - Acquiring global...
+ 35318 [main] [TRACE] GlobalSyncContextFactory$GlobalSyncContext - Releasing global...
+ ```
diff --git a/maven-resolver-synccontext-global/src/site/site.xml b/maven-resolver-synccontext-global/src/site/site.xml
new file mode 100644
index 0000000..8183b5d
--- /dev/null
+++ b/maven-resolver-synccontext-global/src/site/site.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd"
+ name="GlobalSyncContext">
+ <body>
+ <menu name="Overview">
+ <item name="Introduction" href="index.html"/>
+ <item name="Javadoc" href="apidocs/index.html"/>
+ <item name="Source Xref" href="xref/index.html"/>
+ <!--item name="FAQ" href="faq.html"/-->
+ </menu>
+
+ <menu ref="parent"/>
+ <menu ref="reports"/>
+ </body>
+</project>
diff --git a/pom.xml b/pom.xml
index 757d117..2174ccd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -510,5 +510,14 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>java8-modules</id>
+ <activation>
+ <jdk>[1.8,)</jdk>
+ </activation>
+ <modules>
+ <module>maven-resolver-synccontext-global</module>
+ </modules>
+ </profile>
</profiles>
</project>