mirror of https://github.com/apache/archiva.git
add a new module for file locking
git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@1550396 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
074386d154
commit
6b23332e9d
|
@ -39,6 +39,16 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.archiva.redback.components.registry</groupId>
|
<groupId>org.apache.archiva.redback.components.registry</groupId>
|
||||||
<artifactId>spring-registry-commons</artifactId>
|
<artifactId>spring-registry-commons</artifactId>
|
||||||
|
@ -52,41 +62,41 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-configuration</groupId>
|
<groupId>commons-configuration</groupId>
|
||||||
<artifactId>commons-configuration</artifactId>
|
<artifactId>commons-configuration</artifactId>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-beanutils</groupId>
|
<groupId>commons-beanutils</groupId>
|
||||||
<artifactId>commons-beanutils-core</artifactId>
|
<artifactId>commons-beanutils-core</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<!-- targeting JDK 1.4, xml parser/apis not needed -->
|
<!-- targeting JDK 1.4, xml parser/apis not needed -->
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>xerces</groupId>
|
<groupId>xerces</groupId>
|
||||||
<artifactId>xerces</artifactId>
|
<artifactId>xerces</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>xerces</groupId>
|
<groupId>xerces</groupId>
|
||||||
<artifactId>xercesImpl</artifactId>
|
<artifactId>xercesImpl</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>xalan</groupId>
|
<groupId>xalan</groupId>
|
||||||
<artifactId>xalan</artifactId>
|
<artifactId>xalan</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>xml-apis</groupId>
|
<groupId>xml-apis</groupId>
|
||||||
<artifactId>xml-apis</artifactId>
|
<artifactId>xml-apis</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>servletapi</groupId>
|
<groupId>servletapi</groupId>
|
||||||
<artifactId>servletapi</artifactId>
|
<artifactId>servletapi</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>commons-logging</groupId>
|
||||||
<artifactId>commons-logging</artifactId>
|
<artifactId>commons-logging</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>ant</groupId>
|
<groupId>ant</groupId>
|
||||||
<artifactId>ant-optional</artifactId>
|
<artifactId>ant-optional</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ant</groupId>
|
<groupId>org.apache.ant</groupId>
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
<?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/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.apache.archiva</groupId>
|
||||||
|
<artifactId>archiva-base</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>archiva-filelock</artifactId>
|
||||||
|
<packaging>bundle</packaging>
|
||||||
|
<name>Archiva Base :: FileLock</name>
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.inject</groupId>
|
||||||
|
<artifactId>javax.inject</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-jcl</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.multithreadedtc</groupId>
|
||||||
|
<artifactId>multithreadedtc</artifactId>
|
||||||
|
<version>1.01</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Bundle-SymbolicName>org.apache.archiva.common</Bundle-SymbolicName>
|
||||||
|
<Bundle-Version>${project.version}</Bundle-Version>
|
||||||
|
<Export-Package>
|
||||||
|
org.apache.archiva.common*;version=${project.version}
|
||||||
|
</Export-Package>
|
||||||
|
<Import-Package>
|
||||||
|
|
||||||
|
</Import-Package>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<buildDirectory>${project.build.directory}</buildDirectory>
|
||||||
|
<java.io.tmpdir>${project.build.directory}</java.io.tmpdir>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.rat</groupId>
|
||||||
|
<artifactId>apache-rat-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,177 @@
|
||||||
|
package org.apache.archiva.common.filelock;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.nio.channels.OverlappingFileLockException;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Lamy
|
||||||
|
*/
|
||||||
|
@Service("fileLockManager#default")
|
||||||
|
public class DefaultFileLockManager
|
||||||
|
implements FileLockManager
|
||||||
|
{
|
||||||
|
private static final ConcurrentMap<File, Lock> lockFiles = new ConcurrentHashMap<File, Lock>( 64 );
|
||||||
|
|
||||||
|
private boolean skipLocking = false;
|
||||||
|
|
||||||
|
private Logger log = LoggerFactory.getLogger( getClass() );
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock readFileLock( File file )
|
||||||
|
throws FileLockException
|
||||||
|
{
|
||||||
|
if ( skipLocking )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new Lock( file, false );
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
throw new FileLockException( e.getMessage(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Lock lock = lockFiles.get( file );
|
||||||
|
if ( lock == null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock = new Lock( file, false );
|
||||||
|
Lock current = lockFiles.putIfAbsent( file, lock );
|
||||||
|
if ( current != null )
|
||||||
|
{
|
||||||
|
lock = current;
|
||||||
|
}
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
throw new FileLockException( e.getMessage(), e );
|
||||||
|
}
|
||||||
|
catch ( OverlappingFileLockException e )
|
||||||
|
{
|
||||||
|
log.debug( "OverlappingFileLockException: {}", e.getMessage() );
|
||||||
|
if ( lock == null )
|
||||||
|
{
|
||||||
|
lock = lockFiles.get( file );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME add a timeout on getting that!!!
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
log.debug( "wait read lock" );
|
||||||
|
synchronized ( lock )
|
||||||
|
{
|
||||||
|
if ( lock.getFileLock().isShared() || !lock.getFileLock().isValid() )
|
||||||
|
{
|
||||||
|
lock.addFileClient( Thread.currentThread() );
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lock writeFileLock( File file )
|
||||||
|
throws FileLockException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ( skipLocking )
|
||||||
|
{
|
||||||
|
return new Lock( file, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME add a timeout on getting that!!!
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
Lock lock = lockFiles.get( file );
|
||||||
|
log.debug( "wait write lock" );
|
||||||
|
if ( lock != null )
|
||||||
|
{
|
||||||
|
synchronized ( lock )
|
||||||
|
{
|
||||||
|
if ( lock.getFileLock().isValid() || lock.getFileClients().size() > 0 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock = new Lock( file, true );
|
||||||
|
}
|
||||||
|
catch ( OverlappingFileLockException e )
|
||||||
|
{
|
||||||
|
log.debug( "OverlappingFileLockException: {}", e.getMessage() );
|
||||||
|
if ( lock == null )
|
||||||
|
{
|
||||||
|
lock = lockFiles.get( file );
|
||||||
|
}
|
||||||
|
|
||||||
|
lock = lockFiles.get( file );
|
||||||
|
log.debug( "OverlappingFileLockException get: {}", lock );
|
||||||
|
}
|
||||||
|
Lock current = lockFiles.putIfAbsent( file, lock );
|
||||||
|
if ( current != null )
|
||||||
|
{
|
||||||
|
lock = current;
|
||||||
|
}
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
throw new FileLockException( e.getMessage(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release( Lock lock )
|
||||||
|
throws FileLockException
|
||||||
|
{
|
||||||
|
if ( lock == null )
|
||||||
|
{
|
||||||
|
log.debug( "skip releasing null" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( skipLocking )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ( lock.isWrite().get() )
|
||||||
|
{
|
||||||
|
lock.getFileLock().release();
|
||||||
|
}
|
||||||
|
synchronized ( lock )
|
||||||
|
{
|
||||||
|
lock.close();
|
||||||
|
if ( lock.getFileClients().size() < 1 )
|
||||||
|
{
|
||||||
|
lockFiles.remove( lock.getFile() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
throw new FileLockException( e.getMessage(), e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.apache.archiva.common.filelock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Lamy
|
||||||
|
*/
|
||||||
|
public class FileLockException
|
||||||
|
extends Exception
|
||||||
|
{
|
||||||
|
public FileLockException( String s, Throwable throwable )
|
||||||
|
{
|
||||||
|
super( s, throwable );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.apache.archiva.common.filelock;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Lamy
|
||||||
|
*/
|
||||||
|
public interface FileLockManager
|
||||||
|
{
|
||||||
|
Lock writeFileLock( File file )
|
||||||
|
throws FileLockException;
|
||||||
|
|
||||||
|
Lock readFileLock( File file )
|
||||||
|
throws FileLockException;
|
||||||
|
|
||||||
|
void release( Lock lock )
|
||||||
|
throws FileLockException;
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package org.apache.archiva.common.filelock;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Lamy
|
||||||
|
*/
|
||||||
|
public class Lock
|
||||||
|
{
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
private AtomicBoolean write;
|
||||||
|
|
||||||
|
private final Map<Thread, AtomicInteger> fileClients = new HashMap<Thread, AtomicInteger>();
|
||||||
|
|
||||||
|
private FileLock fileLock;
|
||||||
|
|
||||||
|
public Lock( File file, boolean write )
|
||||||
|
throws FileNotFoundException, IOException
|
||||||
|
{
|
||||||
|
this.file = file;
|
||||||
|
this.write = new AtomicBoolean( write );
|
||||||
|
this.openLock( write );
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile()
|
||||||
|
{
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtomicBoolean isWrite()
|
||||||
|
{
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFile( File file )
|
||||||
|
{
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWrite( boolean write )
|
||||||
|
{
|
||||||
|
this.write.set( write );
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileLock getFileLock()
|
||||||
|
{
|
||||||
|
return fileLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileLock( FileLock fileLock )
|
||||||
|
{
|
||||||
|
this.fileLock = fileLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Thread, AtomicInteger> getFileClients()
|
||||||
|
{
|
||||||
|
return fileClients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFileClient( Thread thread )
|
||||||
|
{
|
||||||
|
this.fileClients.put( thread, new AtomicInteger( 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeFileClient( Thread thread )
|
||||||
|
{
|
||||||
|
return this.fileClients.remove( thread ) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void close()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
if ( this.write.get() )
|
||||||
|
{
|
||||||
|
this.fileLock.release();
|
||||||
|
fileClients.remove( Thread.currentThread() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openLock( boolean write )
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
fileClients.put( Thread.currentThread(), new AtomicInteger( 1 ) );
|
||||||
|
RandomAccessFile raf = new RandomAccessFile( file, write ? "rw" : "r" );
|
||||||
|
this.fileLock = raf.getChannel().lock( 1, 1, !write );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
final StringBuilder sb = new StringBuilder( "Lock{" );
|
||||||
|
sb.append( "file=" ).append( file );
|
||||||
|
sb.append( '}' );
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:context="http://www.springframework.org/schema/context"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
|
http://www.springframework.org/schema/context
|
||||||
|
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
|
||||||
|
default-lazy-init="true">
|
||||||
|
|
||||||
|
<context:annotation-config/>
|
||||||
|
<context:component-scan base-package="org.apache.archiva.common.filelock"/>
|
||||||
|
|
||||||
|
|
||||||
|
</beans>
|
Binary file not shown.
|
@ -0,0 +1,208 @@
|
||||||
|
package org.apache.archiva.common.filelock;
|
||||||
|
|
||||||
|
import edu.umd.cs.mtc.MultithreadedTestCase;
|
||||||
|
import edu.umd.cs.mtc.TestFramework;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Olivier Lamy
|
||||||
|
*/
|
||||||
|
@RunWith( SpringJUnit4ClassRunner.class )
|
||||||
|
@ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml" } )
|
||||||
|
public class DefaultFileLockManagerTest
|
||||||
|
{
|
||||||
|
|
||||||
|
final Logger logger = LoggerFactory.getLogger( getClass() );
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Named( value = "fileLockManager#default" )
|
||||||
|
FileLockManager fileLockManager;
|
||||||
|
|
||||||
|
class ConcurentFileWrite
|
||||||
|
extends MultithreadedTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
FileLockManager fileLockManager;
|
||||||
|
|
||||||
|
File file = new File( System.getProperty( "buildDirectory" ), "foo.txt" );
|
||||||
|
|
||||||
|
File largeJar = new File( System.getProperty( "basedir" ), "src/test/cassandra-all-2.0.3.jar" );
|
||||||
|
|
||||||
|
ConcurentFileWrite( FileLockManager fileLockManager )
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
this.fileLockManager = fileLockManager;
|
||||||
|
file.createNewFile();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread1()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread1" );
|
||||||
|
Lock lock = fileLockManager.writeFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock.getFile().delete();
|
||||||
|
FileUtils.copyFile( largeJar, lock.getFile() );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread1 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread2()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread2" );
|
||||||
|
Lock lock = fileLockManager.writeFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock.getFile().delete();
|
||||||
|
FileUtils.copyFile( largeJar, lock.getFile() );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread2 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread3()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread3" );
|
||||||
|
Lock lock = fileLockManager.readFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IOUtils.copy( new FileInputStream( lock.getFile() ),
|
||||||
|
new FileOutputStream( File.createTempFile( "foo", ".jar" ) ) );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread3 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread4()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread4" );
|
||||||
|
Lock lock = fileLockManager.writeFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock.getFile().delete();
|
||||||
|
FileUtils.copyFile( largeJar, lock.getFile() );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread4 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread5()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread5" );
|
||||||
|
Lock lock = fileLockManager.writeFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock.getFile().delete();
|
||||||
|
FileUtils.copyFile( largeJar, lock.getFile() );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread5 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread6()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread6" );
|
||||||
|
Lock lock = fileLockManager.readFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IOUtils.copy( new FileInputStream( lock.getFile() ),
|
||||||
|
new FileOutputStream( File.createTempFile( "foo", ".jar" ) ) );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread6 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread7()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread7" );
|
||||||
|
Lock lock = fileLockManager.writeFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock.getFile().delete();
|
||||||
|
FileUtils.copyFile( largeJar, lock.getFile() );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread7 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void thread8()
|
||||||
|
throws FileLockException, IOException
|
||||||
|
{
|
||||||
|
logger.info( "thread8" );
|
||||||
|
Lock lock = fileLockManager.readFileLock( this.file );
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IOUtils.copy( new FileInputStream( lock.getFile() ),
|
||||||
|
new FileOutputStream( File.createTempFile( "foo", ".jar" ) ) );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileLockManager.release( lock );
|
||||||
|
}
|
||||||
|
logger.info( "thread8 ok" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrite()
|
||||||
|
throws Throwable
|
||||||
|
{
|
||||||
|
ConcurentFileWrite concurentFileWrite = new ConcurentFileWrite( fileLockManager );
|
||||||
|
//concurentFileWrite.setTrace( true );
|
||||||
|
TestFramework.runOnce( concurentFileWrite );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
<configuration status="debug">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<appenders>
|
||||||
|
<Console name="console" target="SYSTEM_OUT">
|
||||||
|
<!--PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/-->
|
||||||
|
<PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n}" />
|
||||||
|
</Console>
|
||||||
|
|
||||||
|
</appenders>
|
||||||
|
<loggers>
|
||||||
|
|
||||||
|
|
||||||
|
<logger name="org.apache.archiva.common.filelock" level="debug"/>
|
||||||
|
|
||||||
|
<root level="info" includeLocation="true">
|
||||||
|
<appender-ref ref="console"/>
|
||||||
|
</root>
|
||||||
|
</loggers>
|
||||||
|
</configuration>
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,7 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -1091,6 +1092,9 @@ public class DefaultRepositoryProxyConnectors
|
||||||
}
|
}
|
||||||
|
|
||||||
target.getParentFile().mkdirs();
|
target.getParentFile().mkdirs();
|
||||||
|
// TODO file lock library
|
||||||
|
RandomAccessFile raf;
|
||||||
|
|
||||||
if ( !temp.renameTo( target ) )
|
if ( !temp.renameTo( target ) )
|
||||||
{
|
{
|
||||||
log.warn( "Unable to rename tmp file to its final name... resorting to copy command." );
|
log.warn( "Unable to rename tmp file to its final name... resorting to copy command." );
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module>archiva-test-utils</module>
|
<module>archiva-test-utils</module>
|
||||||
<module>archiva-common</module>
|
<module>archiva-common</module>
|
||||||
|
<module>archiva-filelock</module>
|
||||||
<module>archiva-model</module>
|
<module>archiva-model</module>
|
||||||
<module>archiva-configuration</module>
|
<module>archiva-configuration</module>
|
||||||
<module>archiva-checksum</module>
|
<module>archiva-checksum</module>
|
||||||
|
|
|
@ -201,6 +201,7 @@ public class ArchivaDavResource
|
||||||
FileInputStream is = null;
|
FileInputStream is = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// TODO file lock library
|
||||||
// Write content to stream
|
// Write content to stream
|
||||||
is = new FileInputStream( localResource );
|
is = new FileInputStream( localResource );
|
||||||
IOUtils.copy( is, outputContext.getOutputStream() );
|
IOUtils.copy( is, outputContext.getOutputStream() );
|
||||||
|
|
5
pom.xml
5
pom.xml
|
@ -260,6 +260,11 @@
|
||||||
<artifactId>archiva-common</artifactId>
|
<artifactId>archiva-common</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.archiva</groupId>
|
||||||
|
<artifactId>archiva-filelock</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.archiva</groupId>
|
<groupId>org.apache.archiva</groupId>
|
||||||
<artifactId>archiva-configuration</artifactId>
|
<artifactId>archiva-configuration</artifactId>
|
||||||
|
|
Loading…
Reference in New Issue