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.

Maven2RepositoryStorage.java 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. package org.apache.archiva.metadata.repository.storage.maven2;
  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.RepositoryAdminException;
  21. import org.apache.archiva.admin.model.beans.ManagedRepository;
  22. import org.apache.archiva.admin.model.beans.NetworkProxy;
  23. import org.apache.archiva.admin.model.beans.ProxyConnector;
  24. import org.apache.archiva.admin.model.beans.RemoteRepository;
  25. import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
  26. import org.apache.archiva.admin.model.networkproxy.NetworkProxyAdmin;
  27. import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
  28. import org.apache.archiva.admin.model.remote.RemoteRepositoryAdmin;
  29. import org.apache.archiva.checksum.ChecksumAlgorithm;
  30. import org.apache.archiva.checksum.ChecksummedFile;
  31. import org.apache.archiva.common.utils.VersionUtil;
  32. import org.apache.archiva.metadata.model.ArtifactMetadata;
  33. import org.apache.archiva.metadata.model.ProjectMetadata;
  34. import org.apache.archiva.metadata.model.ProjectVersionMetadata;
  35. import org.apache.archiva.metadata.repository.filter.Filter;
  36. import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
  37. import org.apache.archiva.metadata.repository.storage.RepositoryStorage;
  38. import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataInvalidException;
  39. import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataNotFoundException;
  40. import org.apache.archiva.metadata.repository.storage.RepositoryStorageRuntimeException;
  41. import org.apache.archiva.proxy.common.WagonFactory;
  42. import org.apache.archiva.reports.RepositoryProblemFacet;
  43. import org.apache.archiva.xml.XMLException;
  44. import org.apache.commons.lang.StringUtils;
  45. import org.apache.maven.model.CiManagement;
  46. import org.apache.maven.model.Dependency;
  47. import org.apache.maven.model.IssueManagement;
  48. import org.apache.maven.model.License;
  49. import org.apache.maven.model.MailingList;
  50. import org.apache.maven.model.Model;
  51. import org.apache.maven.model.Organization;
  52. import org.apache.maven.model.Scm;
  53. import org.apache.maven.model.building.DefaultModelBuilderFactory;
  54. import org.apache.maven.model.building.DefaultModelBuildingRequest;
  55. import org.apache.maven.model.building.ModelBuilder;
  56. import org.apache.maven.model.building.ModelBuildingException;
  57. import org.apache.maven.model.building.ModelBuildingRequest;
  58. import org.apache.maven.model.building.ModelProblem;
  59. import org.slf4j.Logger;
  60. import org.slf4j.LoggerFactory;
  61. import org.springframework.stereotype.Service;
  62. import javax.annotation.PostConstruct;
  63. import javax.inject.Inject;
  64. import javax.inject.Named;
  65. import java.io.File;
  66. import java.io.FileNotFoundException;
  67. import java.io.FilenameFilter;
  68. import java.io.IOException;
  69. import java.util.ArrayList;
  70. import java.util.Arrays;
  71. import java.util.Collection;
  72. import java.util.Collections;
  73. import java.util.Date;
  74. import java.util.HashMap;
  75. import java.util.List;
  76. import java.util.Map;
  77. /**
  78. * Maven 2 repository format storage implementation. This class currently takes parameters to indicate the repository to
  79. * deal with rather than being instantiated per-repository.
  80. * FIXME: instantiate one per repository and allocate permanently from a factory (which can be obtained within the session).
  81. * TODO: finish Maven 1 implementation to prove this API
  82. * <p/>
  83. * The session is passed in as an argument to obtain any necessary resources, rather than the class being instantiated
  84. * within the session in the context of a single managed repository's resolution needs.
  85. * <p/>
  86. */
  87. @Service( "repositoryStorage#maven2" )
  88. public class Maven2RepositoryStorage
  89. implements RepositoryStorage
  90. {
  91. /**
  92. *
  93. */
  94. private ModelBuilder builder;
  95. /**
  96. *
  97. */
  98. @Inject
  99. private RemoteRepositoryAdmin remoteRepositoryAdmin;
  100. @Inject
  101. private ManagedRepositoryAdmin managedRepositoryAdmin;
  102. @Inject
  103. private ProxyConnectorAdmin proxyConnectorAdmin;
  104. @Inject
  105. private NetworkProxyAdmin networkProxyAdmin;
  106. /**
  107. *
  108. */
  109. @Inject
  110. @Named( value = "repositoryPathTranslator#maven2" )
  111. private RepositoryPathTranslator pathTranslator;
  112. @Inject
  113. private WagonFactory wagonFactory;
  114. private final static Logger log = LoggerFactory.getLogger( Maven2RepositoryStorage.class );
  115. private static final String METADATA_FILENAME = "maven-metadata.xml";
  116. @PostConstruct
  117. public void initialize()
  118. {
  119. DefaultModelBuilderFactory defaultModelBuilderFactory = new DefaultModelBuilderFactory();
  120. builder = defaultModelBuilderFactory.newInstance();
  121. }
  122. public ProjectMetadata readProjectMetadata( String repoId, String namespace, String projectId )
  123. {
  124. // TODO: could natively implement the "shared model" concept from the browse action to avoid needing it there?
  125. return null;
  126. }
  127. public ProjectVersionMetadata readProjectVersionMetadata( String repoId, String namespace, String projectId,
  128. String projectVersion )
  129. throws RepositoryStorageMetadataNotFoundException, RepositoryStorageMetadataInvalidException,
  130. RepositoryStorageRuntimeException
  131. {
  132. try
  133. {
  134. ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
  135. String artifactVersion = projectVersion;
  136. File basedir = new File( managedRepository.getLocation() );
  137. if ( VersionUtil.isSnapshot( projectVersion ) )
  138. {
  139. File metadataFile =
  140. pathTranslator.toFile( basedir, namespace, projectId, projectVersion, METADATA_FILENAME );
  141. try
  142. {
  143. MavenRepositoryMetadata metadata = MavenRepositoryMetadataReader.read( metadataFile );
  144. // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
  145. MavenRepositoryMetadata.Snapshot snapshotVersion = metadata.getSnapshotVersion();
  146. if ( snapshotVersion != null )
  147. {
  148. artifactVersion =
  149. artifactVersion.substring( 0, artifactVersion.length() - 8 ); // remove SNAPSHOT from end
  150. artifactVersion =
  151. artifactVersion + snapshotVersion.getTimestamp() + "-" + snapshotVersion.getBuildNumber();
  152. }
  153. }
  154. catch ( XMLException e )
  155. {
  156. // unable to parse metadata - log it, and continue with the version as the original SNAPSHOT version
  157. log.warn( "Invalid metadata: " + metadataFile + " - " + e.getMessage() );
  158. }
  159. }
  160. // TODO: won't work well with some other layouts, might need to convert artifact parts to ID by path translator
  161. String id = projectId + "-" + artifactVersion + ".pom";
  162. File file = pathTranslator.toFile( basedir, namespace, projectId, projectVersion, id );
  163. if ( !file.exists() )
  164. {
  165. // metadata could not be resolved
  166. throw new RepositoryStorageMetadataNotFoundException(
  167. "The artifact's POM file '" + file.getAbsolutePath() + "' was missing" );
  168. }
  169. // TODO: this is a workaround until we can properly resolve using proxies as well - this doesn't cache
  170. // anything locally!
  171. List<RemoteRepository> remoteRepositories = new ArrayList<RemoteRepository>();
  172. Map<String, NetworkProxy> networkProxies = new HashMap<String, NetworkProxy>();
  173. Map<String, List<ProxyConnector>> proxyConnectorsMap = proxyConnectorAdmin.getProxyConnectorAsMap();
  174. List<ProxyConnector> proxyConnectors = proxyConnectorsMap.get( repoId );
  175. if ( proxyConnectors != null )
  176. {
  177. for ( ProxyConnector proxyConnector : proxyConnectors )
  178. {
  179. RemoteRepository remoteRepoConfig =
  180. remoteRepositoryAdmin.getRemoteRepository( proxyConnector.getTargetRepoId() );
  181. if ( remoteRepoConfig != null )
  182. {
  183. remoteRepositories.add( remoteRepoConfig );
  184. NetworkProxy networkProxyConfig =
  185. networkProxyAdmin.getNetworkProxy( proxyConnector.getProxyId() );
  186. if ( networkProxyConfig != null )
  187. {
  188. // key/value: remote repo ID/proxy info
  189. networkProxies.put( proxyConnector.getTargetRepoId(), networkProxyConfig );
  190. }
  191. }
  192. }
  193. }
  194. ModelBuildingRequest req =
  195. new DefaultModelBuildingRequest()
  196. .setProcessPlugins( false )
  197. .setPomFile( file )
  198. .setTwoPhaseBuilding( false )
  199. .setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
  200. //MRM-1607. olamy this will resolve jdk profiles on the current running archiva jvm
  201. req.setSystemProperties( System.getProperties() );
  202. // MRM-1411
  203. req.setModelResolver(
  204. new RepositoryModelResolver( managedRepository, pathTranslator, wagonFactory, remoteRepositories, networkProxies,
  205. managedRepository ) );
  206. Model model;
  207. try
  208. {
  209. model = builder.build( req ).getEffectiveModel();
  210. }
  211. catch ( ModelBuildingException e )
  212. {
  213. String msg = "The artifact's POM file '" + file + "' was invalid: " + e.getMessage();
  214. List<ModelProblem> modelProblems = e.getProblems();
  215. for ( ModelProblem problem : modelProblems )
  216. {
  217. // MRM-1411, related to MRM-1335
  218. // this means that the problem was that the parent wasn't resolved!
  219. // olamy really hackhish but fail with java profile so use error message
  220. // || ( StringUtils.startsWith( problem.getMessage(), "Failed to determine Java version for profile" ) )
  221. // but setTwoPhaseBuilding(true) fix that
  222. if ( ( problem.getException() instanceof FileNotFoundException && e.getModelId() != null &&
  223. !e.getModelId().equals( problem.getModelId() ) ) )
  224. {
  225. log.warn( "The artifact's parent POM file '" + file + "' cannot be resolved. " +
  226. "Using defaults for project version metadata.." );
  227. ProjectVersionMetadata metadata = new ProjectVersionMetadata();
  228. metadata.setId( projectVersion );
  229. MavenProjectFacet facet = new MavenProjectFacet();
  230. facet.setGroupId( namespace );
  231. facet.setArtifactId( projectId );
  232. facet.setPackaging( "jar" );
  233. metadata.addFacet( facet );
  234. String errMsg =
  235. "Error in resolving artifact's parent POM file. " + ( problem.getException() == null
  236. ? problem.getMessage()
  237. : problem.getException().getMessage() );
  238. RepositoryProblemFacet repoProblemFacet = new RepositoryProblemFacet();
  239. repoProblemFacet.setRepositoryId( repoId );
  240. repoProblemFacet.setId( repoId );
  241. repoProblemFacet.setMessage( errMsg );
  242. repoProblemFacet.setProblem( errMsg );
  243. repoProblemFacet.setProject( projectId );
  244. repoProblemFacet.setVersion( projectVersion );
  245. repoProblemFacet.setNamespace( namespace );
  246. metadata.addFacet( repoProblemFacet );
  247. return metadata;
  248. }
  249. }
  250. throw new RepositoryStorageMetadataInvalidException( "invalid-pom", msg, e );
  251. }
  252. // Check if the POM is in the correct location
  253. boolean correctGroupId = namespace.equals( model.getGroupId() );
  254. boolean correctArtifactId = projectId.equals( model.getArtifactId() );
  255. boolean correctVersion = projectVersion.equals( model.getVersion() );
  256. if ( !correctGroupId || !correctArtifactId || !correctVersion )
  257. {
  258. StringBuilder message = new StringBuilder( "Incorrect POM coordinates in '" + file + "':" );
  259. if ( !correctGroupId )
  260. {
  261. message.append( "\nIncorrect group ID: " ).append( model.getGroupId() );
  262. }
  263. if ( !correctArtifactId )
  264. {
  265. message.append( "\nIncorrect artifact ID: " ).append( model.getArtifactId() );
  266. }
  267. if ( !correctVersion )
  268. {
  269. message.append( "\nIncorrect version: " ).append( model.getVersion() );
  270. }
  271. throw new RepositoryStorageMetadataInvalidException( "mislocated-pom", message.toString() );
  272. }
  273. ProjectVersionMetadata metadata = new ProjectVersionMetadata();
  274. metadata.setCiManagement( convertCiManagement( model.getCiManagement() ) );
  275. metadata.setDescription( model.getDescription() );
  276. metadata.setId( projectVersion );
  277. metadata.setIssueManagement( convertIssueManagement( model.getIssueManagement() ) );
  278. metadata.setLicenses( convertLicenses( model.getLicenses() ) );
  279. metadata.setMailingLists( convertMailingLists( model.getMailingLists() ) );
  280. metadata.setDependencies( convertDependencies( model.getDependencies() ) );
  281. metadata.setName( model.getName() );
  282. metadata.setOrganization( convertOrganization( model.getOrganization() ) );
  283. metadata.setScm( convertScm( model.getScm() ) );
  284. metadata.setUrl( model.getUrl() );
  285. MavenProjectFacet facet = new MavenProjectFacet();
  286. facet.setGroupId( model.getGroupId() != null ? model.getGroupId() : model.getParent().getGroupId() );
  287. facet.setArtifactId( model.getArtifactId() );
  288. facet.setPackaging( model.getPackaging() );
  289. if ( model.getParent() != null )
  290. {
  291. MavenProjectParent parent = new MavenProjectParent();
  292. parent.setGroupId( model.getParent().getGroupId() );
  293. parent.setArtifactId( model.getParent().getArtifactId() );
  294. parent.setVersion( model.getParent().getVersion() );
  295. facet.setParent( parent );
  296. }
  297. metadata.addFacet( facet );
  298. return metadata;
  299. }
  300. catch ( RepositoryAdminException e )
  301. {
  302. throw new RepositoryStorageRuntimeException( "repo-admin", e.getMessage() );
  303. }
  304. }
  305. public void setWagonFactory( WagonFactory wagonFactory )
  306. {
  307. this.wagonFactory = wagonFactory;
  308. }
  309. private List<org.apache.archiva.metadata.model.Dependency> convertDependencies( List<Dependency> dependencies )
  310. {
  311. List<org.apache.archiva.metadata.model.Dependency> l =
  312. new ArrayList<org.apache.archiva.metadata.model.Dependency>();
  313. for ( Dependency dependency : dependencies )
  314. {
  315. org.apache.archiva.metadata.model.Dependency newDependency =
  316. new org.apache.archiva.metadata.model.Dependency();
  317. newDependency.setArtifactId( dependency.getArtifactId() );
  318. newDependency.setClassifier( dependency.getClassifier() );
  319. newDependency.setGroupId( dependency.getGroupId() );
  320. newDependency.setOptional( dependency.isOptional() );
  321. newDependency.setScope( dependency.getScope() );
  322. newDependency.setSystemPath( dependency.getSystemPath() );
  323. newDependency.setType( dependency.getType() );
  324. newDependency.setVersion( dependency.getVersion() );
  325. l.add( newDependency );
  326. }
  327. return l;
  328. }
  329. private org.apache.archiva.metadata.model.Scm convertScm( Scm scm )
  330. {
  331. org.apache.archiva.metadata.model.Scm newScm = null;
  332. if ( scm != null )
  333. {
  334. newScm = new org.apache.archiva.metadata.model.Scm();
  335. newScm.setConnection( scm.getConnection() );
  336. newScm.setDeveloperConnection( scm.getDeveloperConnection() );
  337. newScm.setUrl( scm.getUrl() );
  338. }
  339. return newScm;
  340. }
  341. private org.apache.archiva.metadata.model.Organization convertOrganization( Organization organization )
  342. {
  343. org.apache.archiva.metadata.model.Organization org = null;
  344. if ( organization != null )
  345. {
  346. org = new org.apache.archiva.metadata.model.Organization();
  347. org.setName( organization.getName() );
  348. org.setUrl( organization.getUrl() );
  349. }
  350. return org;
  351. }
  352. private List<org.apache.archiva.metadata.model.License> convertLicenses( List<License> licenses )
  353. {
  354. List<org.apache.archiva.metadata.model.License> l = new ArrayList<org.apache.archiva.metadata.model.License>();
  355. for ( License license : licenses )
  356. {
  357. org.apache.archiva.metadata.model.License newLicense = new org.apache.archiva.metadata.model.License();
  358. newLicense.setName( license.getName() );
  359. newLicense.setUrl( license.getUrl() );
  360. l.add( newLicense );
  361. }
  362. return l;
  363. }
  364. private List<org.apache.archiva.metadata.model.MailingList> convertMailingLists( List<MailingList> mailingLists )
  365. {
  366. List<org.apache.archiva.metadata.model.MailingList> l =
  367. new ArrayList<org.apache.archiva.metadata.model.MailingList>();
  368. for ( MailingList mailingList : mailingLists )
  369. {
  370. org.apache.archiva.metadata.model.MailingList newMailingList =
  371. new org.apache.archiva.metadata.model.MailingList();
  372. newMailingList.setName( mailingList.getName() );
  373. newMailingList.setMainArchiveUrl( mailingList.getArchive() );
  374. newMailingList.setPostAddress( mailingList.getPost() );
  375. newMailingList.setSubscribeAddress( mailingList.getSubscribe() );
  376. newMailingList.setUnsubscribeAddress( mailingList.getUnsubscribe() );
  377. newMailingList.setOtherArchives( mailingList.getOtherArchives() );
  378. l.add( newMailingList );
  379. }
  380. return l;
  381. }
  382. private org.apache.archiva.metadata.model.IssueManagement convertIssueManagement( IssueManagement issueManagement )
  383. {
  384. org.apache.archiva.metadata.model.IssueManagement im = null;
  385. if ( issueManagement != null )
  386. {
  387. im = new org.apache.archiva.metadata.model.IssueManagement();
  388. im.setSystem( issueManagement.getSystem() );
  389. im.setUrl( issueManagement.getUrl() );
  390. }
  391. return im;
  392. }
  393. private org.apache.archiva.metadata.model.CiManagement convertCiManagement( CiManagement ciManagement )
  394. {
  395. org.apache.archiva.metadata.model.CiManagement ci = null;
  396. if ( ciManagement != null )
  397. {
  398. ci = new org.apache.archiva.metadata.model.CiManagement();
  399. ci.setSystem( ciManagement.getSystem() );
  400. ci.setUrl( ciManagement.getUrl() );
  401. }
  402. return ci;
  403. }
  404. public Collection<String> listRootNamespaces( String repoId, Filter<String> filter )
  405. throws RepositoryStorageRuntimeException
  406. {
  407. File dir = getRepositoryBasedir( repoId );
  408. return getSortedFiles( dir, filter );
  409. }
  410. private static Collection<String> getSortedFiles( File dir, Filter<String> filter )
  411. {
  412. List<String> fileNames;
  413. String[] files = dir.list( new DirectoryFilter( filter ) );
  414. if ( files != null )
  415. {
  416. fileNames = new ArrayList<String>( Arrays.asList( files ) );
  417. Collections.sort( fileNames );
  418. }
  419. else
  420. {
  421. fileNames = Collections.emptyList();
  422. }
  423. return fileNames;
  424. }
  425. private File getRepositoryBasedir( String repoId )
  426. throws RepositoryStorageRuntimeException
  427. {
  428. try
  429. {
  430. ManagedRepository repositoryConfiguration = managedRepositoryAdmin.getManagedRepository( repoId );
  431. return new File( repositoryConfiguration.getLocation() );
  432. }
  433. catch ( RepositoryAdminException e )
  434. {
  435. throw new RepositoryStorageRuntimeException( "repo-admin", e.getMessage() );
  436. }
  437. }
  438. public Collection<String> listNamespaces( String repoId, String namespace, Filter<String> filter )
  439. throws RepositoryStorageRuntimeException
  440. {
  441. File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
  442. // scan all the directories which are potential namespaces. Any directories known to be projects are excluded
  443. List<String> namespaces = new ArrayList<String>();
  444. File[] files = dir.listFiles( new DirectoryFilter( filter ) );
  445. if ( files != null )
  446. {
  447. for ( File file : files )
  448. {
  449. if ( !isProject( file, filter ) )
  450. {
  451. namespaces.add( file.getName() );
  452. }
  453. }
  454. }
  455. Collections.sort( namespaces );
  456. return namespaces;
  457. }
  458. public Collection<String> listProjects( String repoId, String namespace, Filter<String> filter )
  459. throws RepositoryStorageRuntimeException
  460. {
  461. File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace );
  462. // scan all directories in the namespace, and only include those that are known to be projects
  463. List<String> projects = new ArrayList<String>();
  464. File[] files = dir.listFiles( new DirectoryFilter( filter ) );
  465. if ( files != null )
  466. {
  467. for ( File file : files )
  468. {
  469. if ( isProject( file, filter ) )
  470. {
  471. projects.add( file.getName() );
  472. }
  473. }
  474. }
  475. Collections.sort( projects );
  476. return projects;
  477. }
  478. public Collection<String> listProjectVersions( String repoId, String namespace, String projectId,
  479. Filter<String> filter )
  480. throws RepositoryStorageRuntimeException
  481. {
  482. File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId );
  483. // all directories in a project directory can be considered a version
  484. return getSortedFiles( dir, filter );
  485. }
  486. public Collection<ArtifactMetadata> readArtifactsMetadata( String repoId, String namespace, String projectId,
  487. String projectVersion, Filter<String> filter )
  488. throws RepositoryStorageRuntimeException
  489. {
  490. File dir = pathTranslator.toFile( getRepositoryBasedir( repoId ), namespace, projectId, projectVersion );
  491. // all files that are not metadata and not a checksum / signature are considered artifacts
  492. File[] files = dir.listFiles( new ArtifactDirectoryFilter( filter ) );
  493. List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>();
  494. if ( files != null )
  495. {
  496. for ( File file : files )
  497. {
  498. ArtifactMetadata metadata = getArtifactFromFile( repoId, namespace, projectId, projectVersion, file );
  499. artifacts.add( metadata );
  500. }
  501. }
  502. return artifacts;
  503. }
  504. public ArtifactMetadata readArtifactMetadataFromPath( String repoId, String path )
  505. throws RepositoryStorageRuntimeException
  506. {
  507. ArtifactMetadata metadata = pathTranslator.getArtifactForPath( repoId, path );
  508. populateArtifactMetadataFromFile( metadata, new File( getRepositoryBasedir( repoId ), path ) );
  509. return metadata;
  510. }
  511. private ArtifactMetadata getArtifactFromFile( String repoId, String namespace, String projectId,
  512. String projectVersion, File file )
  513. {
  514. ArtifactMetadata metadata =
  515. pathTranslator.getArtifactFromId( repoId, namespace, projectId, projectVersion, file.getName() );
  516. populateArtifactMetadataFromFile( metadata, file );
  517. return metadata;
  518. }
  519. private static void populateArtifactMetadataFromFile( ArtifactMetadata metadata, File file )
  520. {
  521. metadata.setWhenGathered( new Date() );
  522. metadata.setFileLastModified( file.lastModified() );
  523. ChecksummedFile checksummedFile = new ChecksummedFile( file );
  524. try
  525. {
  526. metadata.setMd5( checksummedFile.calculateChecksum( ChecksumAlgorithm.MD5 ) );
  527. }
  528. catch ( IOException e )
  529. {
  530. log.error( "Unable to checksum file " + file + ": " + e.getMessage() );
  531. }
  532. try
  533. {
  534. metadata.setSha1( checksummedFile.calculateChecksum( ChecksumAlgorithm.SHA1 ) );
  535. }
  536. catch ( IOException e )
  537. {
  538. log.error( "Unable to checksum file " + file + ": " + e.getMessage() );
  539. }
  540. metadata.setSize( file.length() );
  541. }
  542. private boolean isProject( File dir, Filter<String> filter )
  543. {
  544. // scan directories for a valid project version subdirectory, meaning this must be a project directory
  545. File[] files = dir.listFiles( new DirectoryFilter( filter ) );
  546. if ( files != null )
  547. {
  548. for ( File file : files )
  549. {
  550. if ( isProjectVersion( file ) )
  551. {
  552. return true;
  553. }
  554. }
  555. }
  556. // if a metadata file is present, check if this is the "artifactId" directory, marking it as a project
  557. MavenRepositoryMetadata metadata = readMetadata( dir );
  558. if ( metadata != null && dir.getName().equals( metadata.getArtifactId() ) )
  559. {
  560. return true;
  561. }
  562. return false;
  563. }
  564. private boolean isProjectVersion( File dir )
  565. {
  566. final String artifactId = dir.getParentFile().getName();
  567. final String projectVersion = dir.getName();
  568. // check if there is a POM artifact file to ensure it is a version directory
  569. File[] files;
  570. if ( VersionUtil.isSnapshot( projectVersion ) )
  571. {
  572. files = dir.listFiles( new FilenameFilter()
  573. {
  574. public boolean accept( File dir, String name )
  575. {
  576. if ( name.startsWith( artifactId + "-" ) && name.endsWith( ".pom" ) )
  577. {
  578. String v = name.substring( artifactId.length() + 1, name.length() - 4 );
  579. v = VersionUtil.getBaseVersion( v );
  580. if ( v.equals( projectVersion ) )
  581. {
  582. return true;
  583. }
  584. }
  585. return false;
  586. }
  587. } );
  588. }
  589. else
  590. {
  591. final String pomFile = artifactId + "-" + projectVersion + ".pom";
  592. files = dir.listFiles( new FilenameFilter()
  593. {
  594. public boolean accept( File dir, String name )
  595. {
  596. return pomFile.equals( name );
  597. }
  598. } );
  599. }
  600. if ( files != null && files.length > 0 )
  601. {
  602. return true;
  603. }
  604. // if a metadata file is present, check if this is the "version" directory, marking it as a project version
  605. MavenRepositoryMetadata metadata = readMetadata( dir );
  606. if ( metadata != null && projectVersion.equals( metadata.getVersion() ) )
  607. {
  608. return true;
  609. }
  610. return false;
  611. }
  612. private MavenRepositoryMetadata readMetadata( File directory )
  613. {
  614. MavenRepositoryMetadata metadata = null;
  615. File metadataFile = new File( directory, METADATA_FILENAME );
  616. if ( metadataFile.exists() )
  617. {
  618. try
  619. {
  620. metadata = MavenRepositoryMetadataReader.read( metadataFile );
  621. }
  622. catch ( XMLException e )
  623. {
  624. // ignore missing or invalid metadata
  625. }
  626. }
  627. return metadata;
  628. }
  629. private static class DirectoryFilter
  630. implements FilenameFilter
  631. {
  632. private final Filter<String> filter;
  633. public DirectoryFilter( Filter<String> filter )
  634. {
  635. this.filter = filter;
  636. }
  637. public boolean accept( File dir, String name )
  638. {
  639. if ( !filter.accept( name ) )
  640. {
  641. return false;
  642. }
  643. else if ( name.startsWith( "." ) )
  644. {
  645. return false;
  646. }
  647. else if ( !new File( dir, name ).isDirectory() )
  648. {
  649. return false;
  650. }
  651. return true;
  652. }
  653. }
  654. private class ArtifactDirectoryFilter
  655. implements FilenameFilter
  656. {
  657. private final Filter<String> filter;
  658. public ArtifactDirectoryFilter( Filter<String> filter )
  659. {
  660. this.filter = filter;
  661. }
  662. public boolean accept( File dir, String name )
  663. {
  664. // TODO compare to logic in maven-repository-layer
  665. if ( !filter.accept( name ) )
  666. {
  667. return false;
  668. }
  669. else if ( name.startsWith( "." ) )
  670. {
  671. return false;
  672. }
  673. else if ( name.endsWith( ".md5" ) || name.endsWith( ".sha1" ) || name.endsWith( ".asc" ) )
  674. {
  675. return false;
  676. }
  677. else if ( name.equals( METADATA_FILENAME ) )
  678. {
  679. return false;
  680. }
  681. else if ( new File( dir, name ).isDirectory() )
  682. {
  683. return false;
  684. }
  685. return true;
  686. }
  687. }
  688. }