001package org.eclipse.aether.synccontext;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.Collection;
023import java.util.concurrent.locks.Lock;
024import java.util.concurrent.locks.ReentrantReadWriteLock;
025
026import javax.annotation.Priority;
027import javax.inject.Named;
028import javax.inject.Singleton;
029
030import org.eclipse.aether.RepositorySystemSession;
031import org.eclipse.aether.SyncContext;
032import org.eclipse.aether.artifact.Artifact;
033import org.eclipse.aether.impl.SyncContextFactory;
034import org.eclipse.aether.metadata.Metadata;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038/**
039 * A singleton factory to create synchronization contexts using a global lock based on
040 * {@link ReentrantReadWriteLock}. Explicit artifacts and metadata passed are ignored.
041 * <p>
042 * <strong>Note: This component is still considered to be experimental, use with caution!</strong>
043 */
044@Named
045@Priority( Integer.MAX_VALUE )
046@Singleton
047public class GlobalSyncContextFactory
048    implements SyncContextFactory
049{
050    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
051
052    public SyncContext newInstance( RepositorySystemSession session, boolean shared )
053    {
054        return new GlobalSyncContext( shared ? lock.readLock() : lock.writeLock(), shared );
055    }
056
057    static class GlobalSyncContext
058        implements SyncContext
059    {
060        private static final Logger LOGGER = LoggerFactory.getLogger( GlobalSyncContext.class );
061
062        private final Lock lock;
063        private final boolean shared;
064        private int lockHoldCount;
065
066        private GlobalSyncContext( Lock lock, boolean shared )
067        {
068            this.lock = lock;
069            this.shared = shared;
070        }
071
072        public void acquire( Collection<? extends Artifact> artifact, Collection<? extends Metadata> metadata )
073        {
074            LOGGER.trace( "Acquiring global {} lock (currently held: {})",
075                          shared ? "read" : "write", lockHoldCount );
076            lock.lock();
077            lockHoldCount++;
078        }
079
080        public void close()
081        {
082            while ( lockHoldCount > 0 )
083            {
084                LOGGER.trace( "Releasing global {} lock (currently held: {})",
085                              shared ? "read" : "write", lockHoldCount );
086                lock.unlock();
087                lockHoldCount--;
088            }
089        }
090
091    }
092
093}