001package org.apache.archiva.repository.base; 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 com.cronutils.model.CronType; 023import com.cronutils.model.definition.CronDefinition; 024import com.cronutils.model.definition.CronDefinitionBuilder; 025import com.cronutils.parser.CronParser; 026import org.apache.archiva.event.Event; 027import org.apache.archiva.event.EventHandler; 028import org.apache.archiva.event.EventManager; 029import org.apache.archiva.event.EventType; 030import org.apache.archiva.indexer.ArchivaIndexingContext; 031import org.apache.archiva.repository.EditableRepository; 032import org.apache.archiva.repository.RepositoryCapabilities; 033import org.apache.archiva.repository.RepositoryType; 034import org.apache.archiva.repository.UnsupportedFeatureException; 035import org.apache.archiva.repository.event.*; 036import org.apache.archiva.repository.storage.RepositoryStorage; 037import org.apache.archiva.repository.storage.StorageAsset; 038import org.apache.archiva.repository.features.RepositoryFeature; 039import org.apache.archiva.repository.features.StagingRepositoryFeature; 040import org.apache.commons.lang3.StringUtils; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044import java.io.IOException; 045import java.io.InputStream; 046import java.io.OutputStream; 047import java.net.URI; 048import java.nio.channels.ReadableByteChannel; 049import java.nio.channels.WritableByteChannel; 050import java.nio.file.CopyOption; 051import java.util.Collections; 052import java.util.HashMap; 053import java.util.HashSet; 054import java.util.Locale; 055import java.util.Map; 056import java.util.Set; 057import java.util.concurrent.atomic.AtomicBoolean; 058import java.util.function.Consumer; 059 060/** 061 * Implementation of a repository with the necessary fields for a bare repository. 062 * No features are provided. Capabilities and features must be implemented by concrete classes. 063 * 064 */ 065public abstract class AbstractRepository implements EditableRepository, EventHandler<RepositoryEvent> 066{ 067 068 069 Logger log = LoggerFactory.getLogger(AbstractRepository.class); 070 071 private final AtomicBoolean openStatus = new AtomicBoolean(false); 072 073 074 private final RepositoryType type; 075 private final String id; 076 private Map<Locale, String> names = new HashMap<>( ); 077 private Map<Locale, String> descriptions = new HashMap<>( ); 078 079 private Locale primaryLocale = new Locale("en_US"); 080 protected URI location; 081 private URI baseUri; 082 private Set<URI> failoverLocations = new HashSet<>( ); 083 private Set<URI> uFailoverLocations = Collections.unmodifiableSet( failoverLocations ); 084 private boolean scanned = true; 085 String schedulingDefinition = "0 0 02 * * ?"; 086 private String layout = "default"; 087 public static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ); 088 089 private final EventManager eventManager; 090 091 Map<Class<? extends RepositoryFeature<?>>, RepositoryFeature<?>> featureMap = new HashMap<>( ); 092 093 private ArchivaIndexingContext indexingContext; 094 private RepositoryStorage storage; 095 096 public AbstractRepository(RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) { 097 this.id = id; 098 this.names.put( primaryLocale, name); 099 this.type = type; 100 this.storage = repositoryStorage; 101 this.location = repositoryStorage.getLocation(); 102 this.openStatus.compareAndSet(false, true); 103 this.eventManager = new EventManager(this); 104 } 105 106 public AbstractRepository(Locale primaryLocale, RepositoryType type, String id, String name, RepositoryStorage repositoryStorage) { 107 setPrimaryLocale( primaryLocale ); 108 this.id = id; 109 this.names.put( primaryLocale, name); 110 this.type = type; 111 this.storage = repositoryStorage; 112 this.location = repositoryStorage.getLocation(); 113 this.openStatus.compareAndSet(false, true); 114 this.eventManager = new EventManager(this); 115 } 116 117 protected void setPrimaryLocale(Locale locale) { 118 this.primaryLocale = locale; 119 } 120 121 @Override 122 public String getId( ) 123 { 124 return id; 125 } 126 127 @Override 128 public String getName( ) 129 { 130 return getName( primaryLocale ); 131 } 132 133 @Override 134 public String getName( Locale locale ) 135 { 136 return names.get(locale); 137 } 138 139 @Override 140 public String getDescription( ) 141 { 142 return getDescription( primaryLocale ); 143 } 144 145 @Override 146 public String getDescription( Locale locale ) 147 { 148 return descriptions.get(primaryLocale); 149 } 150 151 @Override 152 public RepositoryType getType( ) 153 { 154 return type; 155 } 156 157 @Override 158 public URI getLocation( ) 159 { 160 return location; 161 } 162 163 @Override 164 public StorageAsset getLocalPath() { 165 return storage.getAsset(""); 166 } 167 168 @Override 169 public Set<URI> getFailoverLocations( ) 170 { 171 return uFailoverLocations; 172 } 173 174 @Override 175 public boolean isScanned( ) 176 { 177 return scanned; 178 } 179 180 @Override 181 public String getSchedulingDefinition( ) 182 { 183 return schedulingDefinition; 184 } 185 186 @Override 187 public abstract boolean hasIndex( ); 188 189 @Override 190 public String getLayout( ) 191 { 192 return layout; 193 } 194 195 @Override 196 public abstract RepositoryCapabilities getCapabilities( ); 197 198 @SuppressWarnings( "unchecked" ) 199 @Override 200 public <T extends RepositoryFeature<T>> RepositoryFeature<T> getFeature( Class<T> clazz ) throws UnsupportedFeatureException 201 { 202 if (featureMap.containsKey( clazz )) { 203 return (RepositoryFeature<T>) featureMap.get(clazz); 204 } else 205 { 206 throw new UnsupportedFeatureException( "Feature " + clazz + " not supported" ); 207 } 208 } 209 210 @Override 211 public <T extends RepositoryFeature<T>> boolean supportsFeature( Class<T> clazz ) 212 { 213 return featureMap.containsKey( clazz ); 214 } 215 216 @Override 217 public Locale getPrimaryLocale( ) 218 { 219 return primaryLocale; 220 } 221 222 @Override 223 public void setName( Locale locale, String name ) 224 { 225 names.put(locale, name); 226 } 227 228 @Override 229 public void setDescription( Locale locale, String description ) 230 { 231 descriptions.put(locale, description); 232 } 233 234 @Override 235 public void setLocation( final URI location ) 236 { 237 if (location!=null && ( this.location == null || !this.location.equals(location))) { 238 try { 239 updateLocation(location); 240 } catch (IOException e) { 241 log.error("Could not update location of repository {} to {}", getId(), location, e); 242 } 243 } 244 } 245 246 @Override 247 public void updateLocation(URI newLocation) throws IOException { 248 storage.updateLocation(newLocation); 249 this.location = newLocation; 250 } 251 252 @Override 253 public void addFailoverLocation( URI location ) 254 { 255 this.failoverLocations.add(location); 256 } 257 258 @Override 259 public void removeFailoverLocation( URI location ) 260 { 261 this.failoverLocations.remove( location ); 262 } 263 264 @Override 265 public void clearFailoverLocations( ) 266 { 267 this.failoverLocations.clear(); 268 } 269 270 @Override 271 public void setScanned( boolean scanned ) 272 { 273 this.scanned = scanned; 274 } 275 276 @Override 277 public void setLayout( String layout ) 278 { 279 this.layout = layout; 280 } 281 282 @Override 283 public void setBaseUri(URI baseUri) { 284 this.baseUri = baseUri; 285 } 286 287 @Override 288 public void setSchedulingDefinition(String cronExpression) { 289 if (StringUtils.isNotEmpty( cronExpression )) 290 { 291 CronParser parser = new CronParser( CRON_DEFINITION ); 292 parser.parse( cronExpression ).validate( ); 293 } 294 this.schedulingDefinition = cronExpression; 295 } 296 297 @SuppressWarnings( "unchecked" ) 298 protected <T extends RepositoryFeature<T>> void addFeature(RepositoryFeature<T> feature) { 299 featureMap.put( (Class<? extends RepositoryFeature<?>>) feature.getClass(), feature); 300 } 301 302 @Override 303 public void setIndexingContext(ArchivaIndexingContext context) { 304 if (this.indexingContext!=null) { 305 306 } 307 this.indexingContext = context; 308 } 309 310 @Override 311 public ArchivaIndexingContext getIndexingContext() { 312 return indexingContext; 313 } 314 315 @Override 316 public void close() { 317 if (this.openStatus.compareAndSet(true, false)) { 318 ArchivaIndexingContext ctx = getIndexingContext(); 319 if (ctx != null) { 320 try { 321 ctx.close(); 322 } catch (IOException e) { 323 log.warn("Error during index context close.", e); 324 } 325 this.indexingContext = null; 326 327 } 328 if (supportsFeature(StagingRepositoryFeature.class)) { 329 StagingRepositoryFeature sf = getFeature(StagingRepositoryFeature.class).get(); 330 if (sf.getStagingRepository() != null) { 331 sf.getStagingRepository().close(); 332 } 333 } 334 } 335 336 } 337 338 @Override 339 public boolean isOpen() { 340 return openStatus.get(); 341 } 342 343 @Override 344 public void handle(RepositoryEvent event) { 345 // We just rethrow the events 346 eventManager.fireEvent(event); 347 } 348 349 @Override 350 public <T extends Event> void registerEventHandler( EventType<T> eventType, EventHandler<? super T> eventHandler) { 351 if (!EventType.isInstanceOf(eventType, RepositoryEvent.ANY)) { 352 throw new IllegalArgumentException("Can only register RepositoryEvent Handlers"); 353 } 354 eventManager.registerEventHandler(eventType, eventHandler); 355 } 356 357 @Override 358 public <T extends Event> void unregisterEventHandler(EventType<T> type, EventHandler<? super T> eventHandler) { 359 eventManager.unregisterEventHandler(type, eventHandler); 360 } 361 362 @Override 363 public StorageAsset getAsset(String path ) 364 { 365 return storage.getAsset(path); 366 } 367 368 @Override 369 public StorageAsset addAsset( String path, boolean container ) 370 { 371 return storage.addAsset(path, container); 372 } 373 374 @Override 375 public void removeAsset( StorageAsset asset ) throws IOException 376 { 377 storage.removeAsset(asset); 378 } 379 380 @Override 381 public StorageAsset moveAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException 382 { 383 return storage.moveAsset(origin, destination); 384 } 385 386 @Override 387 public void moveAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException 388 { 389 storage.moveAsset( origin, destination, copyOptions ); 390 } 391 392 @Override 393 public StorageAsset copyAsset( StorageAsset origin, String destination, CopyOption... copyOptions ) throws IOException 394 { 395 return storage.copyAsset(origin, destination); 396 } 397 398 @Override 399 public void copyAsset( StorageAsset origin, StorageAsset destination, CopyOption... copyOptions ) throws IOException 400 { 401 storage.copyAsset( origin, destination, copyOptions); 402 } 403 404 @Override 405 public void consumeData(StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException 406 { 407 storage.consumeData(asset, consumerFunction, readLock); 408 } 409 410 @Override 411 public void consumeDataFromChannel( StorageAsset asset, Consumer<ReadableByteChannel> consumerFunction, boolean readLock ) throws IOException 412 { 413 storage.consumeDataFromChannel( asset, consumerFunction, readLock ); 414 } 415 416 @Override 417 public void writeData( StorageAsset asset, Consumer<OutputStream> consumerFunction, boolean writeLock ) throws IOException 418 { 419 storage.writeData( asset, consumerFunction, writeLock ); 420 } 421 422 @Override 423 public void writeDataToChannel( StorageAsset asset, Consumer<WritableByteChannel> consumerFunction, boolean writeLock ) throws IOException 424 { 425 storage.writeDataToChannel( asset, consumerFunction, writeLock ); 426 } 427 428 protected void setStorage( RepositoryStorage storage) { 429 this.storage = storage; 430 } 431 432 protected RepositoryStorage getStorage() { 433 return storage; 434 } 435}