You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DefaultRepositoryGroupAdmin.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package org.apache.archiva.admin.repository.group;
  2. /*
  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
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  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
  18. * under the License.
  19. */
  20. import org.apache.archiva.admin.model.AuditInformation;
  21. import org.apache.archiva.admin.model.RepositoryAdminException;
  22. import org.apache.archiva.admin.model.beans.ManagedRepository;
  23. import org.apache.archiva.admin.model.beans.RepositoryGroup;
  24. import org.apache.archiva.admin.model.group.RepositoryGroupAdmin;
  25. import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
  26. import org.apache.archiva.admin.repository.AbstractRepositoryAdmin;
  27. import org.apache.archiva.configuration.Configuration;
  28. import org.apache.archiva.configuration.RepositoryGroupConfiguration;
  29. import org.apache.archiva.metadata.model.facets.AuditEvent;
  30. import org.apache.archiva.indexer.merger.MergedRemoteIndexesScheduler;
  31. import org.apache.archiva.repository.EditableRepositoryGroup;
  32. import org.apache.archiva.repository.RepositoryException;
  33. import org.apache.archiva.repository.RepositoryRegistry;
  34. import org.apache.archiva.repository.features.IndexCreationFeature;
  35. import org.apache.archiva.repository.storage.StorageAsset;
  36. import org.apache.commons.lang.StringUtils;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;
  39. import org.springframework.stereotype.Service;
  40. import javax.annotation.PostConstruct;
  41. import javax.inject.Inject;
  42. import javax.inject.Named;
  43. import java.io.IOException;
  44. import java.nio.file.Files;
  45. import java.nio.file.Path;
  46. import java.nio.file.Paths;
  47. import java.util.ArrayList;
  48. import java.util.HashMap;
  49. import java.util.List;
  50. import java.util.Map;
  51. import java.util.regex.Matcher;
  52. import java.util.regex.Pattern;
  53. import java.util.stream.Collectors;
  54. /**
  55. * @author Olivier Lamy
  56. */
  57. @Service("repositoryGroupAdmin#default")
  58. public class DefaultRepositoryGroupAdmin
  59. extends AbstractRepositoryAdmin
  60. implements RepositoryGroupAdmin
  61. {
  62. private Logger log = LoggerFactory.getLogger( getClass() );
  63. private static final Pattern REPO_GROUP_ID_PATTERN = Pattern.compile( "[A-Za-z0-9\\._\\-]+" );
  64. @Inject
  65. private ManagedRepositoryAdmin managedRepositoryAdmin;
  66. @Inject
  67. @Named("mergedRemoteIndexesScheduler#default")
  68. private MergedRemoteIndexesScheduler mergedRemoteIndexesScheduler;
  69. @Inject
  70. private RepositoryRegistry repositoryRegistry;
  71. private Path groupsDirectory;
  72. @PostConstruct
  73. public void initialize()
  74. {
  75. String appServerBase = getRegistry().getString( "appserver.base" );
  76. groupsDirectory = Paths.get( appServerBase, "groups" );
  77. if ( !Files.exists(groupsDirectory) )
  78. {
  79. Files.exists(groupsDirectory);
  80. }
  81. for ( org.apache.archiva.repository.RepositoryGroup repositoryGroup : repositoryRegistry.getRepositoryGroups() )
  82. {
  83. mergedRemoteIndexesScheduler.schedule( repositoryGroup,
  84. getMergedIndexDirectory( repositoryGroup.getId() ));
  85. // create the directory for each group if not exists
  86. Path groupPath = groupsDirectory.resolve(repositoryGroup.getId() );
  87. if ( !Files.exists(groupPath) )
  88. {
  89. try {
  90. Files.createDirectories(groupPath);
  91. } catch (IOException e) {
  92. log.error("Could not create directory {}", groupPath);
  93. }
  94. }
  95. }
  96. }
  97. @Override
  98. public StorageAsset getMergedIndexDirectory(String repositoryGroupId )
  99. {
  100. org.apache.archiva.repository.RepositoryGroup group = repositoryRegistry.getRepositoryGroup(repositoryGroupId);
  101. if (group!=null) {
  102. return group.getFeature(IndexCreationFeature.class).get().getLocalIndexPath();
  103. } else {
  104. return null;
  105. }
  106. }
  107. @Override
  108. public List<RepositoryGroup> getRepositoriesGroups() {
  109. return repositoryRegistry.getRepositoryGroups().stream().map( r -> convertRepositoryGroupObject( r ) ).collect( Collectors.toList());
  110. }
  111. @Override
  112. public RepositoryGroup getRepositoryGroup( String repositoryGroupId ) {
  113. return convertRepositoryGroupObject( repositoryRegistry.getRepositoryGroup( repositoryGroupId ) );
  114. }
  115. @Override
  116. public Boolean addRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
  117. throws RepositoryAdminException
  118. {
  119. validateRepositoryGroup( repositoryGroup, false );
  120. validateManagedRepositoriesExists( repositoryGroup.getRepositories() );
  121. RepositoryGroupConfiguration repositoryGroupConfiguration = new RepositoryGroupConfiguration();
  122. repositoryGroupConfiguration.setId( repositoryGroup.getId() );
  123. repositoryGroupConfiguration.setRepositories( repositoryGroup.getRepositories() );
  124. repositoryGroupConfiguration.setMergedIndexPath( repositoryGroup.getMergedIndexPath() );
  125. repositoryGroupConfiguration.setMergedIndexTtl( repositoryGroup.getMergedIndexTtl() );
  126. repositoryGroupConfiguration.setCronExpression( StringUtils.isEmpty(repositoryGroup.getCronExpression()) ? "0 0 03 ? * MON" : repositoryGroup.getCronExpression() );
  127. try {
  128. repositoryRegistry.putRepositoryGroup(repositoryGroupConfiguration);
  129. } catch (RepositoryException e) {
  130. e.printStackTrace();
  131. }
  132. triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_GROUP, auditInformation );
  133. mergedRemoteIndexesScheduler.schedule( repositoryRegistry.getRepositoryGroup( repositoryGroup.getId()), getMergedIndexDirectory( repositoryGroup.getId() ) );
  134. return Boolean.TRUE;
  135. }
  136. @Override
  137. public Boolean deleteRepositoryGroup( String repositoryGroupId, AuditInformation auditInformation )
  138. throws RepositoryAdminException
  139. {
  140. org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup(repositoryGroupId);
  141. try {
  142. repositoryRegistry.removeRepositoryGroup(repositoryGroup);
  143. } catch (RepositoryException e) {
  144. log.error("Removal of repository group {} failed: {}", repositoryGroup.getId(), e.getMessage(), e);
  145. throw new RepositoryAdminException("Removal of repository failed: " + e.getMessage(), e);
  146. }
  147. mergedRemoteIndexesScheduler.unschedule(
  148. repositoryGroup );
  149. triggerAuditEvent( repositoryGroupId, null, AuditEvent.DELETE_REPO_GROUP, auditInformation );
  150. return Boolean.TRUE;
  151. }
  152. @Override
  153. public Boolean updateRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation )
  154. throws RepositoryAdminException
  155. {
  156. return updateRepositoryGroup( repositoryGroup, auditInformation, true );
  157. }
  158. private Boolean updateRepositoryGroup( RepositoryGroup repositoryGroup, AuditInformation auditInformation,
  159. boolean triggerAuditEvent )
  160. throws RepositoryAdminException
  161. {
  162. validateRepositoryGroup( repositoryGroup, true );
  163. validateManagedRepositoriesExists( repositoryGroup.getRepositories() );
  164. Configuration configuration = getArchivaConfiguration().getConfiguration();
  165. RepositoryGroupConfiguration repositoryGroupConfiguration =
  166. configuration.getRepositoryGroupsAsMap().get( repositoryGroup.getId() );
  167. repositoryGroupConfiguration.setRepositories( repositoryGroup.getRepositories() );
  168. repositoryGroupConfiguration.setMergedIndexPath( repositoryGroup.getMergedIndexPath() );
  169. repositoryGroupConfiguration.setMergedIndexTtl( repositoryGroup.getMergedIndexTtl() );
  170. repositoryGroupConfiguration.setCronExpression( repositoryGroup.getCronExpression() );
  171. try {
  172. repositoryRegistry.putRepositoryGroup(repositoryGroupConfiguration);
  173. } catch (RepositoryException e) {
  174. e.printStackTrace();
  175. }
  176. org.apache.archiva.repository.RepositoryGroup rg = repositoryRegistry.getRepositoryGroup( repositoryGroup.getId( ) );
  177. mergedRemoteIndexesScheduler.unschedule( rg );
  178. mergedRemoteIndexesScheduler.schedule( rg, getMergedIndexDirectory( repositoryGroup.getId() ) );
  179. triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.MODIFY_REPO_GROUP, auditInformation );
  180. return Boolean.TRUE;
  181. }
  182. @Override
  183. public Boolean addRepositoryToGroup( String repositoryGroupId, String repositoryId,
  184. AuditInformation auditInformation )
  185. throws RepositoryAdminException
  186. {
  187. org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
  188. if ( repositoryGroup == null )
  189. {
  190. throw new RepositoryAdminException(
  191. "repositoryGroup with id " + repositoryGroupId + " doesn't not exists so cannot add repository to it" );
  192. }
  193. if (!(repositoryGroup instanceof EditableRepositoryGroup)) {
  194. throw new RepositoryAdminException("The repository group is not editable "+repositoryGroupId);
  195. }
  196. EditableRepositoryGroup editableRepositoryGroup = (EditableRepositoryGroup) repositoryGroup;
  197. if ( editableRepositoryGroup.getRepositories().stream().anyMatch( repo -> repositoryId.equals(repo.getId())) )
  198. {
  199. throw new RepositoryAdminException(
  200. "repositoryGroup with id " + repositoryGroupId + " already contain repository with id" + repositoryId );
  201. }
  202. org.apache.archiva.repository.ManagedRepository managedRepo = repositoryRegistry.getManagedRepository(repositoryId);
  203. if (managedRepo==null) {
  204. throw new RepositoryAdminException("Repository with id "+repositoryId+" does not exist" );
  205. }
  206. editableRepositoryGroup.addRepository( managedRepo );
  207. try {
  208. repositoryRegistry.putRepositoryGroup(editableRepositoryGroup);
  209. } catch (RepositoryException e) {
  210. throw new RepositoryAdminException("Could not store the repository group "+repositoryGroupId, e);
  211. }
  212. triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.ADD_REPO_TO_GROUP, auditInformation );
  213. return Boolean.TRUE;
  214. }
  215. @Override
  216. public Boolean deleteRepositoryFromGroup( String repositoryGroupId, String repositoryId,
  217. AuditInformation auditInformation )
  218. throws RepositoryAdminException
  219. {
  220. org.apache.archiva.repository.RepositoryGroup repositoryGroup = repositoryRegistry.getRepositoryGroup( repositoryGroupId );
  221. if ( repositoryGroup == null )
  222. {
  223. throw new RepositoryAdminException( "repositoryGroup with id " + repositoryGroupId
  224. + " doesn't not exists so cannot remove repository from it" );
  225. }
  226. if ( !repositoryGroup.getRepositories().stream().anyMatch( repo -> repositoryId.equals(repo.getId()) ) )
  227. {
  228. throw new RepositoryAdminException(
  229. "repositoryGroup with id " + repositoryGroupId + " doesn't not contains repository with id"
  230. + repositoryId
  231. );
  232. }
  233. if (!(repositoryGroup instanceof EditableRepositoryGroup)) {
  234. throw new RepositoryAdminException("Repository group is not editable " + repositoryGroupId);
  235. }
  236. EditableRepositoryGroup editableRepositoryGroup = (EditableRepositoryGroup) repositoryGroup;
  237. editableRepositoryGroup.removeRepository( repositoryId );
  238. try {
  239. repositoryRegistry.putRepositoryGroup(editableRepositoryGroup);
  240. } catch (RepositoryException e) {
  241. throw new RepositoryAdminException("Could not store repository group " + repositoryGroupId, e);
  242. }
  243. triggerAuditEvent( repositoryGroup.getId(), null, AuditEvent.DELETE_REPO_FROM_GROUP, auditInformation );
  244. return Boolean.TRUE;
  245. }
  246. @Override
  247. public Map<String, RepositoryGroup> getRepositoryGroupsAsMap()
  248. throws RepositoryAdminException
  249. {
  250. List<RepositoryGroup> repositoriesGroups = getRepositoriesGroups();
  251. Map<String, RepositoryGroup> map = new HashMap<>( repositoriesGroups.size() );
  252. for ( RepositoryGroup repositoryGroup : repositoriesGroups )
  253. {
  254. map.put( repositoryGroup.getId(), repositoryGroup );
  255. }
  256. return map;
  257. }
  258. @Override
  259. public Map<String, List<String>> getGroupToRepositoryMap()
  260. throws RepositoryAdminException
  261. {
  262. Map<String, List<String>> map = new HashMap<>();
  263. for ( ManagedRepository repo : getManagedRepositoryAdmin().getManagedRepositories() )
  264. {
  265. for ( RepositoryGroup group : getRepositoriesGroups() )
  266. {
  267. if ( !group.getRepositories().contains( repo.getId() ) )
  268. {
  269. String groupId = group.getId();
  270. List<String> repos = map.get( groupId );
  271. if ( repos == null )
  272. {
  273. repos = new ArrayList<>();
  274. map.put( groupId, repos );
  275. }
  276. repos.add( repo.getId() );
  277. }
  278. }
  279. }
  280. return map;
  281. }
  282. @Override
  283. public Map<String, List<String>> getRepositoryToGroupMap()
  284. throws RepositoryAdminException
  285. {
  286. Map<String, List<String>> map = new HashMap<>();
  287. for ( RepositoryGroup group : getRepositoriesGroups() )
  288. {
  289. for ( String repositoryId : group.getRepositories() )
  290. {
  291. List<String> groups = map.get( repositoryId );
  292. if ( groups == null )
  293. {
  294. groups = new ArrayList<>();
  295. map.put( repositoryId, groups );
  296. }
  297. groups.add( group.getId() );
  298. }
  299. }
  300. return map;
  301. }
  302. public Boolean validateRepositoryGroup( RepositoryGroup repositoryGroup, boolean updateMode )
  303. throws RepositoryAdminException
  304. {
  305. String repoGroupId = repositoryGroup.getId();
  306. if ( StringUtils.isBlank( repoGroupId ) )
  307. {
  308. throw new RepositoryAdminException( "repositoryGroup id cannot be empty" );
  309. }
  310. if ( repoGroupId.length() > 100 )
  311. {
  312. throw new RepositoryAdminException(
  313. "Identifier [" + repoGroupId + "] is over the maximum limit of 100 characters" );
  314. }
  315. Matcher matcher = REPO_GROUP_ID_PATTERN.matcher( repoGroupId );
  316. if ( !matcher.matches() )
  317. {
  318. throw new RepositoryAdminException(
  319. "Invalid character(s) found in identifier. Only the following characters are allowed: alphanumeric, '.', '-' and '_'" );
  320. }
  321. if ( repositoryGroup.getMergedIndexTtl() <= 0 )
  322. {
  323. throw new RepositoryAdminException( "Merged Index TTL must be greater than 0." );
  324. }
  325. Configuration configuration = getArchivaConfiguration().getConfiguration();
  326. if ( configuration.getRepositoryGroupsAsMap().containsKey( repoGroupId ) )
  327. {
  328. if ( !updateMode )
  329. {
  330. throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
  331. + "], that id already exists as a repository group." );
  332. }
  333. }
  334. else if ( configuration.getManagedRepositoriesAsMap().containsKey( repoGroupId ) )
  335. {
  336. throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
  337. + "], that id already exists as a managed repository." );
  338. }
  339. else if ( configuration.getRemoteRepositoriesAsMap().containsKey( repoGroupId ) )
  340. {
  341. throw new RepositoryAdminException( "Unable to add new repository group with id [" + repoGroupId
  342. + "], that id already exists as a remote repository." );
  343. }
  344. return Boolean.TRUE;
  345. }
  346. private void validateManagedRepositoriesExists( List<String> managedRepositoriesIds )
  347. throws RepositoryAdminException
  348. {
  349. for ( String id : managedRepositoriesIds )
  350. {
  351. if ( getManagedRepositoryAdmin().getManagedRepository( id ) == null )
  352. {
  353. throw new RepositoryAdminException(
  354. "managedRepository with id " + id + " not exists so cannot be used in a repositoryGroup" );
  355. }
  356. }
  357. }
  358. public ManagedRepositoryAdmin getManagedRepositoryAdmin()
  359. {
  360. return managedRepositoryAdmin;
  361. }
  362. public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
  363. {
  364. this.managedRepositoryAdmin = managedRepositoryAdmin;
  365. }
  366. private RepositoryGroup convertRepositoryGroupObject( org.apache.archiva.repository.RepositoryGroup group ) {
  367. RepositoryGroup rg = new RepositoryGroup( group.getId( ), group.getRepositories().stream().map(r -> r.getId()).collect( Collectors.toList()) );
  368. if (group.supportsFeature( IndexCreationFeature.class ))
  369. {
  370. IndexCreationFeature indexCreationFeature = group.getFeature( IndexCreationFeature.class ).get();
  371. rg.setMergedIndexPath( indexCreationFeature.getIndexPath().getPath() );
  372. }
  373. rg.setCronExpression( group.getSchedulingDefinition() );
  374. rg.setMergedIndexTtl( group.getMergedIndexTTL() );
  375. return rg;
  376. }
  377. }