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.indexer.ArchivaIndexingContext; 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.lang.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.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; 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, RepositoryEventListener { Logger log = LoggerFactory.getLogger(AbstractRepository.class); private final RepositoryType type; private final String id; private Map names = new HashMap<>( ); private Map descriptions = new HashMap<>( ); private Locale primaryLocale = new Locale("en_US"); protected URI location; private URI baseUri; private Set failoverLocations = new HashSet<>( ); private Set 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 List listeners = new ArrayList<>(); Map>, 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(); } 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(); } 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 Path getLocalPath() { return storage.getAsset("").getFilePath(); // Path localPath; // if (StringUtils.isEmpty(getLocation().getScheme()) || "file".equals(getLocation().getScheme()) ) { // localPath = PathUtil.getPathFromUri(getLocation()); // if (localPath.isAbsolute()) { // return localPath; // } else { // return repositoryBase.resolve(localPath); // } // } else { // return repositoryBase.resolve(getId()); // } } @Override public Set 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 > RepositoryFeature getFeature( Class clazz ) throws UnsupportedFeatureException { if (featureMap.containsKey( clazz )) { return (RepositoryFeature) featureMap.get(clazz); } else { throw new UnsupportedFeatureException( "Feature " + clazz + " not supported" ); } } @Override public > boolean supportsFeature( Class 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 > void addFeature(RepositoryFeature feature) { featureMap.put( (Class>) feature.getClass(), feature); } @Override public void setIndexingContext(ArchivaIndexingContext context) { this.indexingContext = context; } @Override public ArchivaIndexingContext getIndexingContext() { return indexingContext; } @Override public void close() { ArchivaIndexingContext ctx = getIndexingContext(); if (ctx!=null) { try { ctx.close(); } catch (IOException e) { log.warn("Error during index context close.",e); } } if (supportsFeature(StagingRepositoryFeature.class)) { StagingRepositoryFeature sf = getFeature(StagingRepositoryFeature.class).get(); if (sf.getStagingRepository()!=null) { sf.getStagingRepository().close(); } } clearListeners(); } @Override public void raise(RepositoryEvent event) { for(RepositoryEventListener listener : listeners) { listener.raise(event); } } public void addListener(RepositoryEventListener listener) { if (!this.listeners.contains(listener)) { this.listeners.add(listener); } } public void removeListener(RepositoryEventListener listener) { this.removeListener(listener); } public void clearListeners() { this.listeners.clear(); } @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 consumerFunction, boolean readLock ) throws IOException { storage.consumeData(asset, consumerFunction, readLock); } @Override public void consumeDataFromChannel( StorageAsset asset, Consumer consumerFunction, boolean readLock ) throws IOException { storage.consumeDataFromChannel( asset, consumerFunction, readLock ); } @Override public void writeData( StorageAsset asset, Consumer consumerFunction, boolean writeLock ) throws IOException { storage.writeData( asset, consumerFunction, writeLock ); } @Override public void writeDataToChannel( StorageAsset asset, Consumer consumerFunction, boolean writeLock ) throws IOException { storage.writeDataToChannel( asset, consumerFunction, writeLock ); } protected void setStorage( RepositoryStorage storage) { this.storage = storage; } protected RepositoryStorage getStorage() { return storage; } }