blob: 0cbf261c1e062fee034d8ef7d64f344f34526c50 [file] [log] [blame]
package org.apache.archiva.repository;
/*
* 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 com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinition;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.parser.CronParser;
import org.apache.archiva.event.Event;
import org.apache.archiva.event.EventHandler;
import org.apache.archiva.event.EventManager;
import org.apache.archiva.event.EventType;
import org.apache.archiva.indexer.ArchivaIndexingContext;
import org.apache.archiva.repository.event.*;
import org.apache.archiva.repository.storage.RepositoryStorage;
import org.apache.archiva.repository.storage.StorageAsset;
import org.apache.archiva.repository.features.RepositoryFeature;
import org.apache.archiva.repository.features.StagingRepositoryFeature;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.CopyOption;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
/**
* Implementation of a repository with the necessary fields for a bare repository.
* No features are provided. Capabilities and features must be implemented by concrete classes.
*
*/
public abstract class AbstractRepository implements EditableRepository, EventHandler<RepositoryEvent>
{
Logger log = LoggerFactory.getLogger(AbstractRepository.class);
private final AtomicBoolean openStatus = new AtomicBoolean(false);
private final RepositoryType type;
private final String id;
private Map<Locale, String> names = new HashMap<>( );
private Map<Locale, String> descriptions = new HashMap<>( );
private Locale primaryLocale = new Locale("en_US");
protected URI location;
private URI baseUri;
private Set<URI> failoverLocations = new HashSet<>( );
private Set<URI> uFailoverLocations = Collections.unmodifiableSet( failoverLocations );
private boolean scanned = true;
String schedulingDefinition = "0 0 02 * * ?";
private String layout = "default";
public static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
private final EventManager eventManager;
Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> featureMap = new HashMap<>( );
private ArchivaIndexingContext indexingContext;
private RepositoryStorage storage;
public AbstractRepository(RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) {
this.id = id;
this.names.put( primaryLocale, name);
this.type = type;
this.storage = repositoryStorage;
this.location = repositoryStorage.getLocation();
this.openStatus.compareAndSet(false, true);
this.eventManager = new EventManager(this);
}
public AbstractRepository(Locale primaryLocale, RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) {
setPrimaryLocale( primaryLocale );
this.id = id;
this.names.put( primaryLocale, name);
this.type = type;
this.storage = repositoryStorage;
this.location = repositoryStorage.getLocation();
this.openStatus.compareAndSet(false, true);
this.eventManager = new EventManager(this);
}
protected void setPrimaryLocale(Locale locale) {
this.primaryLocale = locale;
}
@Override
public String getId( )
{
return id;
}
@Override
public String getName( )
{
return getName( primaryLocale );
}
@Override
public String getName( Locale locale )
{
return names.get(locale);
}
@Override
public String getDescription( )
{
return getDescription( primaryLocale );
}
@Override
public String getDescription( Locale locale )
{
return descriptions.get(primaryLocale);
}
@Override
public RepositoryType getType( )
{
return type;
}
@Override
public URI getLocation( )
{
return location;
}
@Override
public StorageAsset getLocalPath() {
return storage.getAsset("");
}
@Override
public Set<URI> getFailoverLocations( )
{
return uFailoverLocations;
}
@Override
public boolean isScanned( )
{
return scanned;
}
@Override
public String getSchedulingDefinition( )
{
return schedulingDefinition;
}
@Override
public abstract boolean hasIndex( );
@Override
public String getLayout( )
{
return layout;
}
@Override
public abstract RepositoryCapabilities getCapabilities( );
@SuppressWarnings( "unchecked" )
@Override
public <T extends RepositoryFeature<T>> RepositoryFeature<T> getFeature( Class<T> clazz ) throws UnsupportedFeatureException
{
if (featureMap.containsKey( clazz )) {
return (RepositoryFeature<T>) featureMap.get(clazz);
} else
{
throw new UnsupportedFeatureException( "Feature " + clazz + " not supported" );
}
}
@Override
public <T extends RepositoryFeature<T>> boolean supportsFeature( Class<T> clazz )
{
return featureMap.containsKey( clazz );
}
@Override
public Locale getPrimaryLocale( )
{
return primaryLocale;
}
@Override
public void setName( Locale locale, String name )
{
names.put(locale, name);
}
@Override
public void setDescription( Locale locale, String description )
{
descriptions.put(locale, description);
}
@Override
public void setLocation( final URI location )
{
if (location!=null && ( this.location == null || !this.location.equals(location))) {
try {
updateLocation(location);
} catch (IOException e) {
log.error("Could not update location of repository {} to {}", getId(), location, e);
}
}
}
@Override
public void updateLocation(URI newLocation) throws IOException {
storage.updateLocation(newLocation);
this.location = newLocation;
}
@Override
public void addFailoverLocation( URI location )
{
this.failoverLocations.add(location);
}
@Override
public void removeFailoverLocation( URI location )
{
this.failoverLocations.remove( location );
}
@Override
public void clearFailoverLocations( )
{
this.failoverLocations.clear();
}
@Override
public void setScanned( boolean scanned )
{
this.scanned = scanned;
}
@Override
public void setLayout( String layout )
{
this.layout = layout;
}
@Override
public void setBaseUri(URI baseUri) {
this.baseUri = baseUri;
}
@Override
public void setSchedulingDefinition(String cronExpression) {
if (StringUtils.isNotEmpty( cronExpression ))
{
CronParser parser = new CronParser( CRON_DEFINITION );
parser.parse( cronExpression ).validate( );
}
this.schedulingDefinition = cronExpression;
}
@SuppressWarnings( "unchecked" )
protected <T extends RepositoryFeature<T>> void addFeature(RepositoryFeature<T> feature) {
featureMap.put( (Class<? extends RepositoryFeature<?>>) feature.getClass(), feature);
}
@Override
public void setIndexingContext(ArchivaIndexingContext context) {
if (this.indexingContext!=null) {
}
this.indexingContext = context;
}
@Override
public ArchivaIndexingContext getIndexingContext() {
return indexingContext;
}
@Override
public void close() {
if (this.openStatus.compareAndSet(true, false)) {
ArchivaIndexingContext ctx = getIndexingContext();
if (ctx != null) {
try {
ctx.close();
} catch (IOException e) {
log.warn("Error during index context close.", e);
}
this.indexingContext = null;
}
if (supportsFeature(StagingRepositoryFeature.class)) {
StagingRepositoryFeature sf = getFeature(StagingRepositoryFeature.class).get();
if (sf.getStagingRepository() != null) {
sf.getStagingRepository().close();
}
}
}
}
@Override
public boolean isOpen() {
return openStatus.get();
}
@Override
public void handle(RepositoryEvent event) {
// We just rethrow the events
eventManager.fireEvent(event);
}
@Override
public <T extends Event> void registerEventHandler( EventType<T> eventType, EventHandler<? super T> eventHandler) {
if (!EventType.isInstanceOf(eventType, RepositoryEvent.ANY)) {
throw new IllegalArgumentException("Can only register RepositoryEvent Handlers");
}
eventManager.registerEventHandler(eventType, eventHandler);
}
@Override
public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) {
eventManager.unregisterEventHandler(type, eventHandler);
}
@Override
public StorageAsset getAsset(String path )
{
return storage.getAsset(path);
}
@Override
public StorageAsset addAsset( String path, boolean container )
{
return storage.addAsset(path, container);
}
@Override
public void removeAsset( StorageAsset asset ) throws IOException
{
storage.removeAsset(asset);
}
@Override
public StorageAsset moveAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
{
return storage.moveAsset(origin, destination);
}
@Override
public void moveAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
{
storage.moveAsset( origin, destination, copyOptions );
}
@Override
public StorageAsset copyAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
{
return storage.copyAsset(origin, destination);
}
@Override
public void copyAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
{
storage.copyAsset( origin, destination, copyOptions);
}
@Override
public void consumeData(StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException
{
storage.consumeData(asset, consumerFunction, readLock);
}
@Override
public void consumeDataFromChannel( StorageAsset asset, Consumer<ReadableByteChannel> consumerFunction, boolean readLock ) throws IOException
{
storage.consumeDataFromChannel( asset, consumerFunction, readLock );
}
@Override
public void writeData( StorageAsset asset, Consumer<OutputStream> consumerFunction, boolean writeLock ) throws IOException
{
storage.writeData( asset, consumerFunction, writeLock );
}
@Override
public void writeDataToChannel( StorageAsset asset, Consumer<WritableByteChannel> consumerFunction, boolean writeLock ) throws IOException
{
storage.writeDataToChannel( asset, consumerFunction, writeLock );
}
protected void setStorage( RepositoryStorage storage) {
this.storage = storage;
}
protected RepositoryStorage getStorage() {
return storage;
}
}