1 package org.apache.archiva.admin.repository.remote;
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 import org.apache.archiva.admin.model.AuditInformation;
22 import org.apache.archiva.admin.model.RepositoryAdminException;
23 import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
24 import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
25 import org.apache.archiva.configuration.Configuration;
26 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
27 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
28 import org.apache.archiva.configuration.RepositoryCheckPath;
29 import org.apache.archiva.indexer.UnsupportedBaseContextException;
30 import org.apache.archiva.metadata.model.facets.AuditEvent;
31 import org.apache.archiva.repository.RemoteRepository;
32 import org.apache.archiva.repository.PasswordCredentials;
33 import org.apache.archiva.repository.RepositoryCredentials;
34 import org.apache.archiva.repository.RepositoryException;
35 import org.apache.archiva.repository.RepositoryRegistry;
36 import org.apache.archiva.repository.features.RemoteIndexFeature;
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.maven.index.NexusIndexer;
39 import org.apache.maven.index.context.IndexCreator;
40 import org.apache.maven.index.context.IndexingContext;
41 import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
42 import org.apache.maven.index_shaded.lucene.index.IndexFormatTooOldException;
43 import org.springframework.stereotype.Service;
45 import javax.annotation.PostConstruct;
46 import javax.annotation.PreDestroy;
47 import javax.inject.Inject;
48 import java.io.IOException;
49 import java.nio.file.Files;
50 import java.nio.file.Path;
51 import java.nio.file.Paths;
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.List;
56 import java.util.stream.Collectors;
59 * @author Olivier Lamy
62 @Service("remoteRepositoryAdmin#default")
63 public class DefaultRemoteRepositoryAdmin
64 extends AbstractRepositoryAdmin
65 implements RemoteRepositoryAdmin
69 RepositoryRegistry repositoryRegistry;
72 private List<? extends IndexCreator> indexCreators;
75 private NexusIndexer indexer;
78 private void initialize()
79 throws RepositoryAdminException
81 for ( org.apache.archiva.admin.model.beans.RemoteRepository remoteRepository : getRemoteRepositories() )
83 createIndexContext( remoteRepository );
88 private void shutdown()
89 throws RepositoryAdminException
93 List<org.apache.archiva.admin.model.beans.RemoteRepository> remoteRepositories = getRemoteRepositories();
94 // close index on shutdown
95 for ( org.apache.archiva.admin.model.beans.RemoteRepository remoteRepository : remoteRepositories )
97 IndexingContext context = indexer.getIndexingContexts().get( remoteRepository.getId() );
98 if ( context != null )
100 indexer.removeIndexingContext( context, false );
104 catch ( IOException e )
106 throw new RepositoryAdminException( e.getMessage(), e );
112 * Conversion between the repository from the registry and the serialized DTO for the admin API
114 private org.apache.archiva.admin.model.beans.RemoteRepository convertRepo( RemoteRepository repo ) {
118 org.apache.archiva.admin.model.beans.RemoteRepository adminRepo = new org.apache.archiva.admin.model.beans.RemoteRepository( getArchivaConfiguration().getDefaultLocale() );
119 setBaseRepoAttributes( adminRepo, repo );
120 adminRepo.setUrl( convertUriToString( repo.getLocation() ));
121 adminRepo.setCronExpression( repo.getSchedulingDefinition() );
122 adminRepo.setCheckPath( repo.getCheckPath() );
123 adminRepo.setExtraHeaders( repo.getExtraHeaders() );
124 adminRepo.setExtraParameters( repo.getExtraParameters() );
125 adminRepo.setTimeout( (int) repo.getTimeout().getSeconds() );
126 RepositoryCredentials creds = repo.getLoginCredentials();
127 if (creds!=null && creds instanceof PasswordCredentials) {
128 PasswordCredentials pCreds = (PasswordCredentials) creds;
129 adminRepo.setUserName( pCreds.getUsername() );
130 adminRepo.setPassword( new String(pCreds.getPassword()!=null ? pCreds.getPassword() : new char[0]) );
132 if (repo.supportsFeature( RemoteIndexFeature.class )) {
133 RemoteIndexFeature rif = repo.getFeature( RemoteIndexFeature.class ).get();
134 adminRepo.setRemoteIndexUrl( convertUriToString( rif.getIndexUri() ) );
135 adminRepo.setDownloadRemoteIndex( rif.isDownloadRemoteIndex() );
136 adminRepo.setRemoteDownloadNetworkProxyId( rif.getProxyId() );
137 adminRepo.setDownloadRemoteIndexOnStartup( rif.isDownloadRemoteIndexOnStartup() );
138 adminRepo.setRemoteDownloadTimeout( (int) rif.getDownloadTimeout().getSeconds() );
143 private RemoteRepositoryConfiguration getRepositoryConfiguration( org.apache.archiva.admin.model.beans.RemoteRepository repo) {
144 RemoteRepositoryConfiguration repoConfig = new RemoteRepositoryConfiguration();
145 setBaseRepoAttributes( repoConfig, repo );
146 repoConfig.setUrl( getRepositoryCommonValidator().removeExpressions( repo.getUrl() ) );
147 repoConfig.setRefreshCronExpression( repo.getCronExpression() );
148 repoConfig.setCheckPath( repo.getCheckPath() );
149 repoConfig.setExtraHeaders( repo.getExtraHeaders() );
150 repoConfig.setExtraParameters( repo.getExtraParameters() );
151 repoConfig.setUsername( repo.getUserName() );
152 repoConfig.setPassword( repo.getPassword() );
153 repoConfig.setTimeout( repo.getTimeout() );
154 repoConfig.setRemoteIndexUrl( repo.getRemoteIndexUrl() );
155 repoConfig.setDownloadRemoteIndex( repo.isDownloadRemoteIndex() );
156 repoConfig.setRemoteDownloadNetworkProxyId( repo.getRemoteDownloadNetworkProxyId() );
157 repoConfig.setDownloadRemoteIndexOnStartup( repo.isDownloadRemoteIndexOnStartup() );
158 repoConfig.setRemoteDownloadTimeout( repo.getRemoteDownloadTimeout() );
163 public List<org.apache.archiva.admin.model.beans.RemoteRepository> getRemoteRepositories()
164 throws RepositoryAdminException
167 return repositoryRegistry.getRemoteRepositories().stream().map( repo -> convertRepo( repo ) ).collect( Collectors.toList());
171 public org.apache.archiva.admin.model.beans.RemoteRepository getRemoteRepository( String repositoryId )
172 throws RepositoryAdminException
174 return convertRepo( repositoryRegistry.getRemoteRepository( repositoryId ));
178 public Boolean addRemoteRepository( org.apache.archiva.admin.model.beans.RemoteRepository remoteRepository, AuditInformation auditInformation )
179 throws RepositoryAdminException
181 triggerAuditEvent( remoteRepository.getId(), null, AuditEvent.ADD_REMOTE_REPO, auditInformation );
182 getRepositoryCommonValidator().basicValidation( remoteRepository, false );
184 //TODO we can validate it's a good uri/url
185 if ( StringUtils.isEmpty( remoteRepository.getUrl() ) )
187 throw new RepositoryAdminException( "url cannot be null" );
190 //MRM-752 - url needs trimming
191 //MRM-1940 - URL should not end with a slash
192 remoteRepository.setUrl( StringUtils.stripEnd(StringUtils.trim( remoteRepository.getUrl() ), "/"));
194 if (StringUtils.isEmpty(remoteRepository.getCheckPath())) {
195 String checkUrl = remoteRepository.getUrl().toLowerCase();
196 for (RepositoryCheckPath path : getArchivaConfiguration ().getConfiguration().getArchivaDefaultConfiguration().getDefaultCheckPaths()) {
197 log.debug("Checking path for urls: {} <-> {}", checkUrl, path.getUrl());
198 if (checkUrl.startsWith(path.getUrl())) {
199 remoteRepository.setCheckPath(path.getPath());
205 Configuration configuration = getArchivaConfiguration().getConfiguration();
206 RemoteRepositoryConfiguration remoteRepositoryConfiguration =
207 getRepositoryConfiguration( remoteRepository );
211 repositoryRegistry.putRepository( remoteRepositoryConfiguration, configuration );
213 catch ( RepositoryException e )
215 log.error("Could not add remote repository {}: {}", remoteRepositoryConfiguration.getId(), e.getMessage(), e);
216 throw new RepositoryAdminException( "Adding of remote repository failed"+(e.getMessage()==null?"":": "+e.getMessage()) );
220 saveConfiguration( configuration );
226 public Boolean deleteRemoteRepository( String repositoryId, AuditInformation auditInformation )
227 throws RepositoryAdminException
230 triggerAuditEvent( repositoryId, null, AuditEvent.DELETE_REMOTE_REPO, auditInformation );
232 Configuration configuration = getArchivaConfiguration().getConfiguration();
234 RemoteRepository repo = repositoryRegistry.getRemoteRepository( repositoryId );
236 throw new RepositoryAdminException( "Could not delete repository "+repositoryId+". The repository does not exist." );
240 repositoryRegistry.removeRepository( repo, configuration );
242 catch ( RepositoryException e )
244 log.error("Deletion of remote repository failed {}: {}", repo.getId(), e.getMessage(), e);
245 throw new RepositoryAdminException( "Could not delete remote repository"+(e.getMessage()==null?"":": "+e.getMessage()) );
248 // TODO use ProxyConnectorAdmin interface ?
249 // [MRM-520] Proxy Connectors are not deleted with the deletion of a Repository.
250 List<ProxyConnectorConfiguration> proxyConnectors = new ArrayList<>( configuration.getProxyConnectors() );
251 for ( ProxyConnectorConfiguration proxyConnector : proxyConnectors )
253 if ( StringUtils.equals( proxyConnector.getTargetRepoId(), repositoryId ) )
255 configuration.removeProxyConnector( proxyConnector );
259 saveConfiguration( configuration );
265 public Boolean updateRemoteRepository( org.apache.archiva.admin.model.beans.RemoteRepository remoteRepository, AuditInformation auditInformation )
266 throws RepositoryAdminException
269 String repositoryId = remoteRepository.getId();
271 triggerAuditEvent( repositoryId, null, AuditEvent.MODIFY_REMOTE_REPO, auditInformation );
273 // update means : remove and add
275 Configuration configuration = getArchivaConfiguration().getConfiguration();
277 RemoteRepositoryConfiguration remoteRepositoryConfiguration = getRepositoryConfiguration( remoteRepository );
280 repositoryRegistry.putRepository( remoteRepositoryConfiguration, configuration );
282 catch ( RepositoryException e )
284 log.error("Could not update remote repository {}: {}", remoteRepositoryConfiguration.getId(), e.getMessage(), e);
285 throw new RepositoryAdminException( "Update of remote repository failed"+(e.getMessage()==null?"":": "+e.getMessage()) );
287 saveConfiguration( configuration );
292 public Map<String, org.apache.archiva.admin.model.beans.RemoteRepository> getRemoteRepositoriesAsMap()
293 throws RepositoryAdminException
295 java.util.Map<String, org.apache.archiva.admin.model.beans.RemoteRepository> map = new HashMap<>();
297 for ( org.apache.archiva.admin.model.beans.RemoteRepository repo : getRemoteRepositories() )
299 map.put( repo.getId(), repo );
306 public IndexingContext createIndexContext( org.apache.archiva.admin.model.beans.RemoteRepository remoteRepository )
307 throws RepositoryAdminException
311 RemoteRepository repo = repositoryRegistry.getRemoteRepository(remoteRepository.getId());
312 return repo.getIndexingContext().getBaseContext(IndexingContext.class);
313 /*String appServerBase = getRegistry().getString( "appserver.base" );
315 String contextKey = "remote-" + remoteRepository.getId();
316 IndexingContext indexingContext = indexer.getIndexingContexts().get( contextKey );
317 if ( indexingContext != null )
319 return indexingContext;
321 // create remote repository path
322 Path repoDir = Paths.get( appServerBase, "data/remotes/" + remoteRepository.getId() );
323 if ( !Files.exists(repoDir) )
325 Files.createDirectories(repoDir);
328 Path indexDirectory = null;
330 // is there configured indexDirectory ?
331 String indexDirectoryPath = remoteRepository.getIndexDirectory();
333 if ( StringUtils.isNotBlank( indexDirectoryPath ) )
335 repoDir.resolve( indexDirectoryPath );
337 // if not configured use a default value
338 if ( indexDirectory == null )
340 indexDirectory = repoDir.resolve(".index" );
342 if ( !Files.exists(indexDirectory) )
344 Files.createDirectories(indexDirectory);
350 return indexer.addIndexingContext( contextKey, remoteRepository.getId(), repoDir.toFile(), indexDirectory.toFile(),
351 remoteRepository.getUrl(), calculateIndexRemoteUrl( remoteRepository ),
354 catch ( IndexFormatTooOldException e )
356 // existing index with an old lucene format so we need to delete it!!!
357 // delete it first then recreate it.
358 log.warn( "the index of repository {} is too old we have to delete and recreate it", //
359 remoteRepository.getId() );
360 org.apache.archiva.common.utils.FileUtils.deleteDirectory( indexDirectory );
361 return indexer.addIndexingContext( contextKey, remoteRepository.getId(), repoDir.toFile(), indexDirectory.toFile(),
362 remoteRepository.getUrl(), calculateIndexRemoteUrl( remoteRepository ),
366 } catch (UnsupportedBaseContextException e) {
367 throw new RepositoryAdminException( e.getMessage(), e);
372 protected String calculateIndexRemoteUrl( org.apache.archiva.admin.model.beans.RemoteRepository remoteRepository )
374 if ( StringUtils.startsWith( remoteRepository.getRemoteIndexUrl(), "http" ) )
376 String baseUrl = remoteRepository.getRemoteIndexUrl();
377 return baseUrl.endsWith( "/" ) ? StringUtils.substringBeforeLast( baseUrl, "/" ) : baseUrl;
379 String baseUrl = StringUtils.endsWith( remoteRepository.getUrl(), "/" ) ? StringUtils.substringBeforeLast(
380 remoteRepository.getUrl(), "/" ) : remoteRepository.getUrl();
382 baseUrl = StringUtils.isEmpty( remoteRepository.getRemoteIndexUrl() )
383 ? baseUrl + "/.index"
384 : baseUrl + "/" + remoteRepository.getRemoteIndexUrl();