Java tutorial
package org.apache.archiva.converter.artifact; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.archiva.common.plexusbridge.DigesterUtils; import org.apache.archiva.common.plexusbridge.PlexusSisuBridge; import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException; import org.apache.archiva.transaction.FileTransaction; import org.apache.archiva.transaction.TransactionException; import org.apache.commons.io.FileUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata; import org.apache.maven.artifact.repository.metadata.Metadata; import org.apache.maven.artifact.repository.metadata.RepositoryMetadata; import org.apache.maven.artifact.repository.metadata.Snapshot; import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata; import org.apache.maven.artifact.repository.metadata.Versioning; import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer; import org.apache.maven.model.DistributionManagement; import org.apache.maven.model.Model; import org.apache.maven.model.Relocation; import org.apache.maven.model.converter.ModelConverter; import org.apache.maven.model.converter.PomTranslationException; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.codehaus.plexus.digest.Digester; import org.codehaus.plexus.digest.DigesterException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.regex.Matcher; /** * LegacyToDefaultConverter */ @Service("artifactConverter#legacy-to-default") public class LegacyToDefaultConverter implements ArtifactConverter { /** * {@link List}<{@link Digester} */ private List<? extends Digester> digesters; @Inject private PlexusSisuBridge plexusSisuBridge; @Inject private DigesterUtils digesterUtils; private ModelConverter translator; private ArtifactFactory artifactFactory; private ArtifactHandlerManager artifactHandlerManager; private boolean force; private boolean dryrun; private Map<Artifact, List<String>> warnings = new HashMap<>(); @PostConstruct public void initialize() throws PlexusSisuBridgeException { this.digesters = digesterUtils.getAllDigesters(); translator = plexusSisuBridge.lookup(ModelConverter.class); artifactFactory = plexusSisuBridge.lookup(ArtifactFactory.class); artifactHandlerManager = plexusSisuBridge.lookup(ArtifactHandlerManager.class); } @Override public void convert(Artifact artifact, ArtifactRepository targetRepository) throws ArtifactConversionException { if (artifact.getRepository().getUrl().equals(targetRepository.getUrl())) { throw new ArtifactConversionException(Messages.getString("exception.repositories.match")); //$NON-NLS-1$ } if (!validateMetadata(artifact)) { addWarning(artifact, Messages.getString("unable.to.validate.metadata")); //$NON-NLS-1$ return; } FileTransaction transaction = new FileTransaction(); if (!copyPom(artifact, targetRepository, transaction)) { addWarning(artifact, Messages.getString("unable.to.copy.pom")); //$NON-NLS-1$ return; } if (!copyArtifact(artifact, targetRepository, transaction)) { addWarning(artifact, Messages.getString("unable.to.copy.artifact")); //$NON-NLS-1$ return; } Metadata metadata = createBaseMetadata(artifact); Versioning versioning = new Versioning(); versioning.addVersion(artifact.getBaseVersion()); metadata.setVersioning(versioning); updateMetadata(new ArtifactRepositoryMetadata(artifact), targetRepository, metadata, transaction); metadata = createBaseMetadata(artifact); metadata.setVersion(artifact.getBaseVersion()); versioning = new Versioning(); Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher(artifact.getVersion()); if (matcher.matches()) { Snapshot snapshot = new Snapshot(); snapshot.setBuildNumber(Integer.parseInt(matcher.group(3))); snapshot.setTimestamp(matcher.group(2)); versioning.setSnapshot(snapshot); } // TODO: merge latest/release/snapshot from source instead metadata.setVersioning(versioning); updateMetadata(new SnapshotArtifactRepositoryMetadata(artifact), targetRepository, metadata, transaction); if (!dryrun) { try { transaction.commit(); } catch (TransactionException e) { throw new ArtifactConversionException(Messages.getString("transaction.failure", e.getMessage()), e); //$NON-NLS-1$ } } } @SuppressWarnings("unchecked") private boolean copyPom(Artifact artifact, ArtifactRepository targetRepository, FileTransaction transaction) throws ArtifactConversionException { Artifact pom = artifactFactory.createProjectArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); pom.setBaseVersion(artifact.getBaseVersion()); ArtifactRepository repository = artifact.getRepository(); File file = new File(repository.getBasedir(), repository.pathOf(pom)); boolean result = true; if (file.exists()) { File targetFile = new File(targetRepository.getBasedir(), targetRepository.pathOf(pom)); String contents = null; boolean checksumsValid = false; try { if (testChecksums(artifact, file)) { checksumsValid = true; } // Even if the checksums for the POM are invalid we should still convert the POM contents = FileUtils.readFileToString(file, Charset.defaultCharset()); } catch (IOException e) { throw new ArtifactConversionException( Messages.getString("unable.to.read.source.pom", e.getMessage()), e); //$NON-NLS-1$ } if (checksumsValid && contents.indexOf("modelVersion") >= 0) //$NON-NLS-1$ { // v4 POM try { boolean matching = false; if (!force && targetFile.exists()) { String targetContents = FileUtils.readFileToString(targetFile, Charset.defaultCharset()); matching = targetContents.equals(contents); } if (force || !matching) { transaction.createFile(contents, targetFile, digesters); } } catch (IOException e) { throw new ArtifactConversionException( Messages.getString("unable.to.write.target.pom", e.getMessage()), e); //$NON-NLS-1$ } } else { // v3 POM try (StringReader stringReader = new StringReader(contents)) { try (StringWriter writer = new StringWriter()) { org.apache.maven.model.v3_0_0.io.xpp3.MavenXpp3Reader v3Reader = new org.apache.maven.model.v3_0_0.io.xpp3.MavenXpp3Reader(); org.apache.maven.model.v3_0_0.Model v3Model = v3Reader.read(stringReader); if (doRelocation(artifact, v3Model, targetRepository, transaction)) { Artifact relocatedPom = artifactFactory.createProjectArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); targetFile = new File(targetRepository.getBasedir(), targetRepository.pathOf(relocatedPom)); } Model v4Model = translator.translate(v3Model); translator.validateV4Basics(v4Model, v3Model.getGroupId(), v3Model.getArtifactId(), v3Model.getVersion(), v3Model.getPackage()); MavenXpp3Writer xpp3Writer = new MavenXpp3Writer(); xpp3Writer.write(writer, v4Model); transaction.createFile(writer.toString(), targetFile, digesters); List<String> warnings = translator.getWarnings(); for (String message : warnings) { addWarning(artifact, message); } } catch (XmlPullParserException e) { addWarning(artifact, Messages.getString("invalid.source.pom", e.getMessage())); //$NON-NLS-1$ result = false; } catch (IOException e) { throw new ArtifactConversionException(Messages.getString("unable.to.write.converted.pom"), e); //$NON-NLS-1$ } catch (PomTranslationException e) { addWarning(artifact, Messages.getString("invalid.source.pom", e.getMessage())); //$NON-NLS-1$ result = false; } } } } else { addWarning(artifact, Messages.getString("warning.missing.pom")); //$NON-NLS-1$ } return result; } private boolean testChecksums(Artifact artifact, File file) throws IOException { boolean result = true; for (Digester digester : digesters) { result &= verifyChecksum(file, file.getName() + "." + getDigesterFileExtension(digester), digester, //$NON-NLS-1$ artifact, "failure.incorrect." + getDigesterFileExtension(digester)); //$NON-NLS-1$ } return result; } private boolean verifyChecksum(File file, String fileName, Digester digester, Artifact artifact, String key) throws IOException { boolean result = true; File checksumFile = new File(file.getParentFile(), fileName); if (checksumFile.exists()) { String checksum = FileUtils.readFileToString(checksumFile, Charset.defaultCharset()); try { digester.verify(file, checksum); } catch (DigesterException e) { addWarning(artifact, Messages.getString(key)); result = false; } } return result; } /** * File extension for checksums * TODO should be moved to plexus-digester ? */ private String getDigesterFileExtension(Digester digester) { return digester.getAlgorithm().toLowerCase().replaceAll("-", ""); //$NON-NLS-1$ //$NON-NLS-2$ } private boolean copyArtifact(Artifact artifact, ArtifactRepository targetRepository, FileTransaction transaction) throws ArtifactConversionException { File sourceFile = artifact.getFile(); if (sourceFile.getAbsolutePath().indexOf("/plugins/") > -1) //$NON-NLS-1$ { artifact.setArtifactHandler(artifactHandlerManager.getArtifactHandler("maven-plugin")); //$NON-NLS-1$ } File targetFile = new File(targetRepository.getBasedir(), targetRepository.pathOf(artifact)); boolean result = true; try { boolean matching = false; if (!force && targetFile.exists()) { matching = FileUtils.contentEquals(sourceFile, targetFile); if (!matching) { addWarning(artifact, Messages.getString("failure.target.already.exists")); //$NON-NLS-1$ result = false; } } if (result) { if (force || !matching) { if (testChecksums(artifact, sourceFile)) { transaction.copyFile(sourceFile, targetFile, digesters); } else { result = false; } } } } catch (IOException e) { throw new ArtifactConversionException(Messages.getString("error.copying.artifact"), e); //$NON-NLS-1$ } return result; } private Metadata createBaseMetadata(Artifact artifact) { Metadata metadata = new Metadata(); metadata.setArtifactId(artifact.getArtifactId()); metadata.setGroupId(artifact.getGroupId()); return metadata; } private Metadata readMetadata(File file) throws ArtifactConversionException { MetadataXpp3Reader reader = new MetadataXpp3Reader(); try (Reader fileReader = Files.newBufferedReader(file.toPath(), Charset.defaultCharset())) { return reader.read(fileReader); } catch (IOException | XmlPullParserException e) { throw new ArtifactConversionException(Messages.getString("error.reading.target.metadata"), e); //$NON-NLS-1$ } } private boolean validateMetadata(Artifact artifact) throws ArtifactConversionException { ArtifactRepository repository = artifact.getRepository(); boolean result = true; RepositoryMetadata repositoryMetadata = new ArtifactRepositoryMetadata(artifact); File file = new File(repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata(repositoryMetadata)); if (file.exists()) { Metadata metadata = readMetadata(file); result = validateMetadata(metadata, repositoryMetadata, artifact); } repositoryMetadata = new SnapshotArtifactRepositoryMetadata(artifact); file = new File(repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata(repositoryMetadata)); if (file.exists()) { Metadata metadata = readMetadata(file); result = result && validateMetadata(metadata, repositoryMetadata, artifact); } return result; } @SuppressWarnings("unchecked") private boolean validateMetadata(Metadata metadata, RepositoryMetadata repositoryMetadata, Artifact artifact) { String groupIdKey; String artifactIdKey = null; String snapshotKey = null; String versionKey = null; String versionsKey = null; if (repositoryMetadata.storedInGroupDirectory()) { groupIdKey = "failure.incorrect.groupMetadata.groupId"; //$NON-NLS-1$ } else if (repositoryMetadata.storedInArtifactVersionDirectory()) { groupIdKey = "failure.incorrect.snapshotMetadata.groupId"; //$NON-NLS-1$ artifactIdKey = "failure.incorrect.snapshotMetadata.artifactId"; //$NON-NLS-1$ versionKey = "failure.incorrect.snapshotMetadata.version"; //$NON-NLS-1$ snapshotKey = "failure.incorrect.snapshotMetadata.snapshot"; //$NON-NLS-1$ } else { groupIdKey = "failure.incorrect.artifactMetadata.groupId"; //$NON-NLS-1$ artifactIdKey = "failure.incorrect.artifactMetadata.artifactId"; //$NON-NLS-1$ versionsKey = "failure.incorrect.artifactMetadata.versions"; //$NON-NLS-1$ } boolean result = true; if (metadata.getGroupId() == null || !metadata.getGroupId().equals(artifact.getGroupId())) { addWarning(artifact, Messages.getString(groupIdKey)); result = false; } if (!repositoryMetadata.storedInGroupDirectory()) { if (metadata.getGroupId() == null || !metadata.getArtifactId().equals(artifact.getArtifactId())) { addWarning(artifact, Messages.getString(artifactIdKey)); result = false; } if (!repositoryMetadata.storedInArtifactVersionDirectory()) { // artifact metadata boolean foundVersion = false; if (metadata.getVersioning() != null) { for (String version : (List<String>) metadata.getVersioning().getVersions()) { if (version.equals(artifact.getBaseVersion())) { foundVersion = true; break; } } } if (!foundVersion) { addWarning(artifact, Messages.getString(versionsKey)); result = false; } } else { // snapshot metadata if (!artifact.getBaseVersion().equals(metadata.getVersion())) { addWarning(artifact, Messages.getString(versionKey)); result = false; } if (artifact.isSnapshot()) { Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher(artifact.getVersion()); if (matcher.matches()) { boolean correct = false; if (metadata.getVersioning() != null && metadata.getVersioning().getSnapshot() != null) { Snapshot snapshot = metadata.getVersioning().getSnapshot(); int build = Integer.parseInt(matcher.group(3)); String ts = matcher.group(2); if (build == snapshot.getBuildNumber() && ts.equals(snapshot.getTimestamp())) { correct = true; } } if (!correct) { addWarning(artifact, Messages.getString(snapshotKey)); result = false; } } } } } return result; } private void updateMetadata(RepositoryMetadata artifactMetadata, ArtifactRepository targetRepository, Metadata newMetadata, FileTransaction transaction) throws ArtifactConversionException { File file = new File(targetRepository.getBasedir(), targetRepository.pathOfRemoteRepositoryMetadata(artifactMetadata)); Metadata metadata; boolean changed; if (file.exists()) { metadata = readMetadata(file); changed = metadata.merge(newMetadata); } else { changed = true; metadata = newMetadata; } if (changed) { try (StringWriter writer = new StringWriter()) { MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer(); mappingWriter.write(writer, metadata); transaction.createFile(writer.toString(), file, digesters); } catch (IOException e) { throw new ArtifactConversionException(Messages.getString("error.writing.target.metadata"), e); //$NON-NLS-1$ } } } private boolean doRelocation(Artifact artifact, org.apache.maven.model.v3_0_0.Model v3Model, ArtifactRepository repository, FileTransaction transaction) throws IOException { Properties properties = v3Model.getProperties(); if (properties.containsKey("relocated.groupId") || properties.containsKey("relocated.artifactId") //$NON-NLS-1$ //$NON-NLS-2$ || properties.containsKey("relocated.version")) //$NON-NLS-1$ { String newGroupId = properties.getProperty("relocated.groupId", v3Model.getGroupId()); //$NON-NLS-1$ properties.remove("relocated.groupId"); //$NON-NLS-1$ String newArtifactId = properties.getProperty("relocated.artifactId", v3Model.getArtifactId()); //$NON-NLS-1$ properties.remove("relocated.artifactId"); //$NON-NLS-1$ String newVersion = properties.getProperty("relocated.version", v3Model.getVersion()); //$NON-NLS-1$ properties.remove("relocated.version"); //$NON-NLS-1$ String message = properties.getProperty("relocated.message", ""); //$NON-NLS-1$ //$NON-NLS-2$ properties.remove("relocated.message"); //$NON-NLS-1$ if (properties.isEmpty()) { v3Model.setProperties(null); } writeRelocationPom(v3Model.getGroupId(), v3Model.getArtifactId(), v3Model.getVersion(), newGroupId, newArtifactId, newVersion, message, repository, transaction); v3Model.setGroupId(newGroupId); v3Model.setArtifactId(newArtifactId); v3Model.setVersion(newVersion); artifact.setGroupId(newGroupId); artifact.setArtifactId(newArtifactId); artifact.setVersion(newVersion); return true; } else { return false; } } private void writeRelocationPom(String groupId, String artifactId, String version, String newGroupId, String newArtifactId, String newVersion, String message, ArtifactRepository repository, FileTransaction transaction) throws IOException { Model pom = new Model(); pom.setGroupId(groupId); pom.setArtifactId(artifactId); pom.setVersion(version); DistributionManagement dMngt = new DistributionManagement(); Relocation relocation = new Relocation(); relocation.setGroupId(newGroupId); relocation.setArtifactId(newArtifactId); relocation.setVersion(newVersion); if (message != null && message.length() > 0) { relocation.setMessage(message); } dMngt.setRelocation(relocation); pom.setDistributionManagement(dMngt); Artifact artifact = artifactFactory.createBuildArtifact(groupId, artifactId, version, "pom"); //$NON-NLS-1$ File pomFile = new File(repository.getBasedir(), repository.pathOf(artifact)); StringWriter strWriter = new StringWriter(); MavenXpp3Writer pomWriter = new MavenXpp3Writer(); pomWriter.write(strWriter, pom); transaction.createFile(strWriter.toString(), pomFile, digesters); } private void addWarning(Artifact artifact, String message) { List<String> messages = warnings.get(artifact); if (messages == null) { messages = new ArrayList<>(1); } messages.add(message); warnings.put(artifact, messages); } @Override public void clearWarnings() { warnings.clear(); } @Override public Map<Artifact, List<String>> getWarnings() { return warnings; } public List<? extends Digester> getDigesters() { return digesters; } public void setDigesters(List<Digester> digesters) { this.digesters = digesters; } public ModelConverter getTranslator() { return translator; } public void setTranslator(ModelConverter translator) { this.translator = translator; } public ArtifactFactory getArtifactFactory() { return artifactFactory; } public void setArtifactFactory(ArtifactFactory artifactFactory) { this.artifactFactory = artifactFactory; } public ArtifactHandlerManager getArtifactHandlerManager() { return artifactHandlerManager; } public void setArtifactHandlerManager(ArtifactHandlerManager artifactHandlerManager) { this.artifactHandlerManager = artifactHandlerManager; } public boolean isForce() { return force; } public void setForce(boolean force) { this.force = force; } public boolean isDryrun() { return dryrun; } public void setDryrun(boolean dryrun) { this.dryrun = dryrun; } }