1 package org.apache.archiva.repository;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import com.cronutils.model.CronType;
23 import com.cronutils.model.definition.CronDefinition;
24 import com.cronutils.model.definition.CronDefinitionBuilder;
25 import com.cronutils.parser.CronParser;
26 import org.apache.archiva.indexer.ArchivaIndexingContext;
27 import org.apache.archiva.repository.events.*;
28 import org.apache.archiva.repository.storage.RepositoryStorage;
29 import org.apache.archiva.repository.storage.StorageAsset;
30 import org.apache.archiva.repository.features.RepositoryFeature;
31 import org.apache.archiva.repository.features.StagingRepositoryFeature;
32 import org.apache.commons.lang3.StringUtils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
40 import java.nio.channels.ReadableByteChannel;
41 import java.nio.channels.WritableByteChannel;
42 import java.nio.file.CopyOption;
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Locale;
51 import java.util.concurrent.atomic.AtomicBoolean;
52 import java.util.function.Consumer;
55 * Implementation of a repository with the necessary fields for a bare repository.
56 * No features are provided. Capabilities and features must be implemented by concrete classes.
59 public abstract class AbstractRepository implements EditableRepository, RepositoryEventListener
63 Logger log = LoggerFactory.getLogger(AbstractRepository.class);
65 private final AtomicBoolean openStatus = new AtomicBoolean(false);
68 private final RepositoryType type;
69 private final String id;
70 private Map<Locale, String> names = new HashMap<>( );
71 private Map<Locale, String> descriptions = new HashMap<>( );
73 private Locale primaryLocale = new Locale("en_US");
74 protected URI location;
76 private Set<URI> failoverLocations = new HashSet<>( );
77 private Set<URI> uFailoverLocations = Collections.unmodifiableSet( failoverLocations );
78 private boolean scanned = true;
79 String schedulingDefinition = "0 0 02 * * ?";
80 private String layout = "default";
81 public static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
82 private List<RepositoryEventListener> listeners = new ArrayList<>();
83 private Map<EventType, List<RepositoryEventListener>> listenerTypeMap = new HashMap<>();
86 Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> featureMap = new HashMap<>( );
88 private ArchivaIndexingContext indexingContext;
89 private RepositoryStorage storage;
91 public AbstractRepository(RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) {
93 this.names.put( primaryLocale, name);
95 this.storage = repositoryStorage;
96 this.location = repositoryStorage.getLocation();
97 this.openStatus.compareAndSet(false, true);
100 public AbstractRepository(Locale primaryLocale, RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) {
101 setPrimaryLocale( primaryLocale );
103 this.names.put( primaryLocale, name);
105 this.storage = repositoryStorage;
106 this.location = repositoryStorage.getLocation();
107 this.openStatus.compareAndSet(false, true);
110 protected void setPrimaryLocale(Locale locale) {
111 this.primaryLocale = locale;
115 public String getId( )
121 public String getName( )
123 return getName( primaryLocale );
127 public String getName( Locale locale )
129 return names.get(locale);
133 public String getDescription( )
135 return getDescription( primaryLocale );
139 public String getDescription( Locale locale )
141 return descriptions.get(primaryLocale);
145 public RepositoryType getType( )
151 public URI getLocation( )
157 public StorageAsset getLocalPath() {
158 return storage.getAsset("");
162 public Set<URI> getFailoverLocations( )
164 return uFailoverLocations;
168 public boolean isScanned( )
174 public String getSchedulingDefinition( )
176 return schedulingDefinition;
180 public abstract boolean hasIndex( );
183 public String getLayout( )
189 public abstract RepositoryCapabilities getCapabilities( );
191 @SuppressWarnings( "unchecked" )
193 public <T extends RepositoryFeature<T>> RepositoryFeature<T> getFeature( Class<T> clazz ) throws UnsupportedFeatureException
195 if (featureMap.containsKey( clazz )) {
196 return (RepositoryFeature<T>) featureMap.get(clazz);
199 throw new UnsupportedFeatureException( "Feature " + clazz + " not supported" );
204 public <T extends RepositoryFeature<T>> boolean supportsFeature( Class<T> clazz )
206 return featureMap.containsKey( clazz );
210 public Locale getPrimaryLocale( )
212 return primaryLocale;
216 public void setName( Locale locale, String name )
218 names.put(locale, name);
222 public void setDescription( Locale locale, String description )
224 descriptions.put(locale, description);
228 public void setLocation( final URI location )
230 if (location!=null && ( this.location == null || !this.location.equals(location))) {
232 updateLocation(location);
233 } catch (IOException e) {
234 log.error("Could not update location of repository {} to {}", getId(), location, e);
240 public void updateLocation(URI newLocation) throws IOException {
241 storage.updateLocation(newLocation);
242 this.location = newLocation;
246 public void addFailoverLocation( URI location )
248 this.failoverLocations.add(location);
252 public void removeFailoverLocation( URI location )
254 this.failoverLocations.remove( location );
258 public void clearFailoverLocations( )
260 this.failoverLocations.clear();
264 public void setScanned( boolean scanned )
266 this.scanned = scanned;
270 public void setLayout( String layout )
272 this.layout = layout;
276 public void setBaseUri(URI baseUri) {
277 this.baseUri = baseUri;
281 public void setSchedulingDefinition(String cronExpression) {
282 if (StringUtils.isNotEmpty( cronExpression ))
284 CronParser parser = new CronParser( CRON_DEFINITION );
285 parser.parse( cronExpression ).validate( );
287 this.schedulingDefinition = cronExpression;
290 @SuppressWarnings( "unchecked" )
291 protected <T extends RepositoryFeature<T>> void addFeature(RepositoryFeature<T> feature) {
292 featureMap.put( (Class<? extends RepositoryFeature<?>>) feature.getClass(), feature);
296 public void setIndexingContext(ArchivaIndexingContext context) {
297 if (this.indexingContext!=null) {
300 this.indexingContext = context;
304 public ArchivaIndexingContext getIndexingContext() {
305 return indexingContext;
309 public void close() {
310 if (this.openStatus.compareAndSet(true, false)) {
311 ArchivaIndexingContext ctx = getIndexingContext();
315 } catch (IOException e) {
316 log.warn("Error during index context close.", e);
318 this.indexingContext = null;
321 if (supportsFeature(StagingRepositoryFeature.class)) {
322 StagingRepositoryFeature sf = getFeature(StagingRepositoryFeature.class).get();
323 if (sf.getStagingRepository() != null) {
324 sf.getStagingRepository().close();
332 public boolean isOpen() {
333 return openStatus.get();
337 public void raise(Event event) {
338 callListeners(event, listeners);
339 if (listenerTypeMap.containsKey(event.getType())) {
340 callListeners(event, listenerTypeMap.get(event.getType()));
344 private void callListeners(Event event, List<RepositoryEventListener> evtListeners) {
345 for(RepositoryEventListener listener : evtListeners) {
347 listener.raise(event.recreate(this));
348 } catch (Throwable e) {
349 log.error("Could not raise event {} on listener {}: {}", event, listener, e.getMessage());
356 public void register(RepositoryEventListener listener) {
357 if (!this.listeners.contains(listener)) {
358 this.listeners.add(listener);
363 public void register(RepositoryEventListener listener, EventType type) {
364 List<RepositoryEventListener> listeners;
365 if (listenerTypeMap.containsKey(type)) {
366 listeners = listenerTypeMap.get(type);
368 listeners = new ArrayList<>();
369 listenerTypeMap.put(type, listeners);
371 if (!listeners.contains(listener)) {
372 listeners.add(listener);
378 public void register(RepositoryEventListener listener, Set<? extends EventType> types) {
379 for (EventType type : types) {
380 register(listener, type);
385 public void unregister(RepositoryEventListener listener) {
386 listeners.remove(listener);
387 for (List<RepositoryEventListener> listeners : listenerTypeMap.values()) {
388 listeners.remove(listener);
393 public void clearListeners() {
394 this.listeners.clear();
395 this.listenerTypeMap.clear();
399 public StorageAsset getAsset(String path )
401 return storage.getAsset(path);
405 public StorageAsset addAsset( String path, boolean container )
407 return storage.addAsset(path, container);
411 public void removeAsset( StorageAsset asset ) throws IOException
413 storage.removeAsset(asset);
417 public StorageAsset moveAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
419 return storage.moveAsset(origin, destination);
423 public void moveAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
425 storage.moveAsset( origin, destination, copyOptions );
429 public StorageAsset copyAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException
431 return storage.copyAsset(origin, destination);
435 public void copyAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException
437 storage.copyAsset( origin, destination, copyOptions);
441 public void consumeData(StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException
443 storage.consumeData(asset, consumerFunction, readLock);
447 public void consumeDataFromChannel( StorageAsset asset, Consumer<ReadableByteChannel> consumerFunction, boolean readLock ) throws IOException
449 storage.consumeDataFromChannel( asset, consumerFunction, readLock );
453 public void writeData( StorageAsset asset, Consumer<OutputStream> consumerFunction, boolean writeLock ) throws IOException
455 storage.writeData( asset, consumerFunction, writeLock );
459 public void writeDataToChannel( StorageAsset asset, Consumer<WritableByteChannel> consumerFunction, boolean writeLock ) throws IOException
461 storage.writeDataToChannel( asset, consumerFunction, writeLock );
464 protected void setStorage( RepositoryStorage storage) {
465 this.storage = storage;
468 protected RepositoryStorage getStorage() {