| /* |
| * 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. |
| */ |
| package org.apache.sling.feature.cpconverter; |
| |
| import static java.util.Objects.requireNonNull; |
| import static org.apache.sling.feature.cpconverter.vltpkg.VaultPackageUtils.detectPackageType; |
| import static org.apache.sling.feature.cpconverter.vltpkg.VaultPackageUtils.getDependencies; |
| |
| import java.io.Closeable; |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.regex.Pattern; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.jackrabbit.vault.fs.io.Archive; |
| import org.apache.jackrabbit.vault.fs.io.Archive.Entry; |
| import org.apache.jackrabbit.vault.packaging.Dependency; |
| import org.apache.jackrabbit.vault.packaging.PackageId; |
| import org.apache.jackrabbit.vault.packaging.PackageProperties; |
| import org.apache.jackrabbit.vault.packaging.PackageType; |
| import org.apache.jackrabbit.vault.packaging.VaultPackage; |
| import org.apache.sling.feature.ArtifactId; |
| import org.apache.sling.feature.cpconverter.accesscontrol.AclManager; |
| import org.apache.sling.feature.cpconverter.accesscontrol.DefaultAclManager; |
| import org.apache.sling.feature.cpconverter.artifacts.ArtifactsDeployer; |
| import org.apache.sling.feature.cpconverter.artifacts.FileArtifactWriter; |
| import org.apache.sling.feature.cpconverter.features.FeaturesManager; |
| import org.apache.sling.feature.cpconverter.filtering.ResourceFilter; |
| import org.apache.sling.feature.cpconverter.handlers.DefaultHandler; |
| import org.apache.sling.feature.cpconverter.handlers.EntryHandler; |
| import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager; |
| import org.apache.sling.feature.cpconverter.handlers.NodeTypesEntryHandler; |
| import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.BundleSlingInitialContentExtractor; |
| import org.apache.sling.feature.cpconverter.index.DefaultIndexManager; |
| import org.apache.sling.feature.cpconverter.index.IndexManager; |
| import org.apache.sling.feature.cpconverter.vltpkg.BaseVaultPackageScanner; |
| import org.apache.sling.feature.cpconverter.vltpkg.PackagesEventsEmitter; |
| import org.apache.sling.feature.cpconverter.vltpkg.RecollectorVaultPackageScanner; |
| import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanner implements Closeable { |
| |
| public static final String ZIP_TYPE = "zip"; |
| |
| public static final String PACKAGE_CLASSIFIER = "cp2fm-converted"; |
| |
| private static final String DEFAULT_VERSION = "0.0.0"; |
| |
| private final Map<PackageId, String> subContentPackages = new HashMap<>(); |
| |
| private final List<VaultPackageAssembler> assemblers = new LinkedList<>(); |
| |
| private final Map<PackageId, Set<Dependency>> mutableContentsIds = new LinkedHashMap<>(); |
| |
| private EntryHandlersManager handlersManager; |
| |
| private AclManager aclManager = new DefaultAclManager(); |
| |
| private FeaturesManager featuresManager; |
| |
| private ResourceFilter resourceFilter; |
| |
| private ArtifactsDeployer artifactsDeployer; |
| |
| private ArtifactsDeployer unreferencedArtifactsDeployer; |
| |
| private VaultPackageAssembler mainPackageAssembler; |
| |
| private final RecollectorVaultPackageScanner recollectorVaultPackageScanner; |
| |
| private final List<PackagesEventsEmitter> emitters = new ArrayList<>(); |
| |
| private final List<Runnable> deployTasks = new ArrayList<>(); |
| |
| private final File tmpDirectory; |
| |
| private boolean failOnMixedPackages = false; |
| |
| private PackagePolicy contentTypePackagePolicy = PackagePolicy.REFERENCE; |
| |
| private boolean removeInstallHooks = false; |
| |
| private boolean disablePackageTypeRecalculation = false; |
| |
| private BundleSlingInitialContentExtractor bundleSlingInitialContentExtractor = new BundleSlingInitialContentExtractor(); |
| |
| private IndexManager indexManager = new DefaultIndexManager(); |
| |
| private RunModePolicy runModePolicy = RunModePolicy.DIRECT_ONLY; |
| |
| public enum RunModePolicy { |
| /** |
| * Only path within containing package is considered for run mode evaluation |
| */ |
| DIRECT_ONLY, |
| /** |
| * For nesting of multiple levels, run mode constraints are inherited down and prepended |
| */ |
| PREPEND_INHERITED |
| } |
| |
| public enum PackagePolicy { |
| /** |
| * References the content package in the feature model and deploys via the {@link ContentPackage2FeatureModelConverter#artifactsDeployer} |
| */ |
| REFERENCE, |
| /** |
| * Drops the content package completely (i.e. neither reference it in the feature model nor deploy anywhere) |
| * |
| * @deprecated |
| */ |
| DROP, |
| /** |
| * Deploys the content package via the {@link ContentPackage2FeatureModelConverter#unreferencedArtifactsDeployer} |
| */ |
| PUT_IN_DEDICATED_FOLDER |
| } |
| |
| public enum SlingInitialContentPolicy { |
| /** |
| * Keep in bundle and don't extract |
| */ |
| KEEP, |
| /** |
| * Extract from bundle into content-packages and feature model |
| */ |
| EXTRACT_AND_REMOVE, |
| /** |
| * Extract from bundle into content-packages and feature model but keep in bundle as well |
| */ |
| EXTRACT_AND_KEEP |
| } |
| |
| public ContentPackage2FeatureModelConverter() throws IOException { |
| this(false, SlingInitialContentPolicy.KEEP, false); |
| } |
| |
| public ContentPackage2FeatureModelConverter(boolean strictValidation, @NotNull SlingInitialContentPolicy slingInitialContentPolicy) throws IOException { |
| this(strictValidation, slingInitialContentPolicy, false); |
| } |
| |
| public ContentPackage2FeatureModelConverter(boolean strictValidation, @NotNull SlingInitialContentPolicy slingInitialContentPolicy, boolean disablePackageTypeRecalculation) throws IOException { |
| this(strictValidation, slingInitialContentPolicy, disablePackageTypeRecalculation, RunModePolicy.DIRECT_ONLY); |
| } |
| |
| public ContentPackage2FeatureModelConverter(boolean strictValidation, @NotNull SlingInitialContentPolicy slingInitialContentPolicy, boolean disablePackageTypeRecalculation, @NotNull RunModePolicy runModePolicy) throws IOException { |
| super(strictValidation); |
| this.disablePackageTypeRecalculation = disablePackageTypeRecalculation; |
| this.recollectorVaultPackageScanner = new RecollectorVaultPackageScanner(this, this.packageManager, strictValidation, subContentPackages, slingInitialContentPolicy); |
| this.tmpDirectory = Files.createTempDirectory("cp2fm-converter").toFile(); |
| this.runModePolicy = runModePolicy; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setEntryHandlersManager(@Nullable EntryHandlersManager handlersManager) { |
| this.handlersManager = handlersManager; |
| return this; |
| } |
| |
| public @Nullable FeaturesManager getFeaturesManager() { |
| return featuresManager; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setFeaturesManager(@NotNull FeaturesManager featuresManager) { |
| this.featuresManager = featuresManager; |
| if (featuresManager instanceof PackagesEventsEmitter) { |
| this.emitters.add((PackagesEventsEmitter) featuresManager); |
| } |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setResourceFilter(@Nullable ResourceFilter resourceFilter) { |
| this.resourceFilter = resourceFilter; |
| return this; |
| } |
| |
| public @Nullable ArtifactsDeployer getArtifactsDeployer() { |
| return artifactsDeployer; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setBundlesDeployer(@NotNull ArtifactsDeployer bundlesDeployer) { |
| this.artifactsDeployer = bundlesDeployer; |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setUnreferencedArtifactsDeployer(@NotNull ArtifactsDeployer unreferencedArtifactsDeployer) { |
| this.unreferencedArtifactsDeployer = unreferencedArtifactsDeployer; |
| return this; |
| } |
| |
| public @NotNull AclManager getAclManager() { |
| return aclManager; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setAclManager(@NotNull AclManager aclManager) { |
| this.aclManager = aclManager; |
| return this; |
| } |
| |
| public boolean hasMainPackageAssembler() { |
| return mainPackageAssembler != null; |
| } |
| |
| public @NotNull VaultPackageAssembler getMainPackageAssembler() { |
| // verify that mainPackageAssembler has been set before retrieving it |
| return Objects.requireNonNull(mainPackageAssembler); |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setMainPackageAssembler(@NotNull VaultPackageAssembler assembler) { |
| this.mainPackageAssembler = assembler; |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setEmitter(@NotNull PackagesEventsEmitter emitter) { |
| this.emitters.add(emitter); |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setContentTypePackagePolicy(@NotNull PackagePolicy contentTypePackagePolicy) { |
| this.contentTypePackagePolicy = contentTypePackagePolicy; |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setFailOnMixedPackages(boolean failOnMixedPackages) { |
| this.failOnMixedPackages = failOnMixedPackages; |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setRemoveInstallHooks(boolean removeInstallHook) { |
| this.removeInstallHooks = removeInstallHook; |
| return this; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setRunModePolicy(@NotNull RunModePolicy runModePolicy) { |
| this.runModePolicy = runModePolicy; |
| return this; |
| } |
| |
| public RunModePolicy getRunModePolicy() { |
| return this.runModePolicy; |
| } |
| |
| public @Nullable IndexManager getIndexManager() { |
| return indexManager; |
| } |
| |
| public @NotNull ContentPackage2FeatureModelConverter setIndexManager(IndexManager indexManager) { |
| this.indexManager = indexManager; |
| return this; |
| } |
| |
| public @NotNull File getTempDirectory() { |
| return this.tmpDirectory; |
| } |
| |
| public void cleanup() throws IOException { |
| if (this.tmpDirectory.exists()) { |
| logger.info("Cleaning up tmp directory {}", this.tmpDirectory); |
| |
| FileUtils.deleteDirectory(this.tmpDirectory); |
| } |
| } |
| |
| public void convert(@NotNull File... contentPackages) throws IOException, ConverterException { |
| requireNonNull(contentPackages, "Null content-package(s) can not be converted."); |
| secondPass(firstPass(contentPackages)); |
| } |
| |
| protected @NotNull Collection<VaultPackage> firstPass(@NotNull File... contentPackages) throws IOException, ConverterException { |
| Map<PackageId, VaultPackage> idFileMap = new LinkedHashMap<>(); |
| Map<PackageId, VaultPackage> idPackageMapping = new ConcurrentHashMap<>(); |
| |
| for (File contentPackage : contentPackages) { |
| requireNonNull(contentPackage, "Null content-package can not be converted."); |
| |
| if (!contentPackage.exists() || !contentPackage.isFile()) { |
| throw new IllegalArgumentException("File " + contentPackage + " does not exist or it is a directory"); |
| } |
| |
| logger.info("Reading content-package '{}'...", contentPackage); |
| |
| VaultPackage pack = open(contentPackage); |
| idPackageMapping.put(pack.getId(), pack); |
| |
| // analyze sub-content packages in order to filter out |
| // possible outdated conflicting packages |
| recollectorVaultPackageScanner.traverse(pack, null); |
| |
| logger.info("content-package '{}' successfully read!", contentPackage); |
| |
| aclManager.reset(); |
| bundleSlingInitialContentExtractor.reset(); |
| |
| } |
| |
| logger.info("Ordering input content-package(s) {}...", idPackageMapping.keySet()); |
| |
| for (VaultPackage pack : idPackageMapping.values()) { |
| orderDependencies(idFileMap, idPackageMapping, pack, new HashSet<>()); |
| } |
| |
| logger.info("New content-package(s) order: {}", idFileMap.keySet()); |
| |
| return idFileMap.values(); |
| } |
| |
| private void secondPass(@NotNull Collection<VaultPackage> orderedContentPackages) throws IOException, ConverterException { |
| emitters.stream().forEach(PackagesEventsEmitter::start); |
| |
| for (VaultPackage vaultPackage : orderedContentPackages) { |
| try { |
| emitters.stream().forEach(e -> e.startPackage(vaultPackage)); |
| setMainPackageAssembler(VaultPackageAssembler.create(this.getTempDirectory(), vaultPackage, removeInstallHooks, disablePackageTypeRecalculation)); |
| assemblers.add(getMainPackageAssembler()); |
| |
| ArtifactId mvnPackageId = toArtifactId(vaultPackage.getId(), vaultPackage.getFile()); |
| |
| featuresManager.init(mvnPackageId); |
| |
| logger.info("Converting content-package '{}'...", vaultPackage.getId()); |
| |
| traverse(vaultPackage, null); |
| |
| // retrieve the resulting zip-content-package and deploy it to the local mvn bundles dir. |
| try (VaultPackage result = processContentPackageArchive(getMainPackageAssembler(), null)) { |
| |
| // finally serialize the Feature Model(s) file(s) |
| |
| aclManager.addRepoinitExtension(assemblers, featuresManager); |
| bundleSlingInitialContentExtractor.addRepoInitExtension(assemblers, featuresManager); |
| indexManager.addRepoinitExtension(featuresManager); |
| |
| logger.info("Conversion complete!"); |
| |
| featuresManager.serialize(); |
| |
| emitters.stream().forEach(e -> e.endPackage(vaultPackage.getId(), result)); |
| } |
| } finally { |
| |
| aclManager.reset(); |
| bundleSlingInitialContentExtractor.reset(); |
| indexManager.reset(); |
| assemblers.clear(); |
| |
| try { |
| vaultPackage.close(); |
| } catch (Exception e) { |
| // close quietly |
| } |
| } |
| } |
| |
| deployPackages(); |
| mutableContentsIds.clear(); |
| |
| emitters.stream().forEach(PackagesEventsEmitter::end); |
| } |
| |
| private static void orderDependencies(@NotNull Map<PackageId, VaultPackage> idFileMap, |
| @NotNull Map<PackageId, VaultPackage> idPackageMapping, |
| @NotNull VaultPackage pack, |
| @NotNull Set<PackageId> visited) throws IOException, ConverterException { |
| if (!visited.add(pack.getId())) { |
| throw new ConverterException("Cyclic dependency detected, " + pack.getId() + " was previously visited already"); |
| } |
| |
| for (Dependency dep : pack.getDependencies()) { |
| for (java.util.Map.Entry<PackageId, VaultPackage> entry : idPackageMapping.entrySet()) { |
| if (dep.matches(entry.getKey())) { |
| orderDependencies(idFileMap, idPackageMapping, entry.getValue(), visited); |
| break; |
| } |
| } |
| } |
| |
| idFileMap.put(pack.getId(), pack); |
| idPackageMapping.remove(pack.getId()); |
| } |
| |
| public void processSubPackage(@NotNull String path, @Nullable String runMode, @NotNull VaultPackage vaultPackage, boolean isEmbeddedPackage) throws IOException, ConverterException { |
| requireNonNull(path, "Impossible to process a null vault package"); |
| requireNonNull(vaultPackage, "Impossible to process a null vault package"); |
| |
| if (!isSubContentPackageIncluded(path)) { |
| logger.info("Sub content-package {} is filtered out, so it won't be processed.", path); |
| return; |
| } |
| |
| emitters.stream().forEach(e -> e.startSubPackage(path, vaultPackage)); |
| |
| VaultPackageAssembler clonedPackage = VaultPackageAssembler.create(this.getTempDirectory(), vaultPackage, removeInstallHooks,disablePackageTypeRecalculation); |
| |
| // Please note: THIS IS A HACK to meet the new requirement without drastically change the original design |
| // temporary swap the main handler to collect stuff |
| VaultPackageAssembler handler = getMainPackageAssembler(); |
| |
| Properties parentProps = handler.getPackageProperties(); |
| String parentTypeStr = (String)parentProps.get(PackageProperties.NAME_PACKAGE_TYPE); |
| boolean isContainerPackage = StringUtils.isNotBlank(parentTypeStr) ? PackageType.CONTAINER.equals(PackageType.valueOf(parentTypeStr.toUpperCase(Locale.ENGLISH))) : false; |
| setMainPackageAssembler(clonedPackage); |
| assemblers.add(clonedPackage); |
| |
| // scan the detected package, first |
| traverse(vaultPackage, runMode); |
| |
| //set dependency to parent package if the parent package is an application package & subpackage is embedded |
| if (isEmbeddedPackage && !isContainerPackage) { |
| PackageId parentId = new PackageId((String) parentProps.get(PackageProperties.NAME_GROUP), |
| (String) parentProps.get(PackageProperties.NAME_NAME), |
| (String) parentProps.get(PackageProperties.NAME_VERSION)); |
| clonedPackage.addDependency(new Dependency(parentId)); |
| } |
| |
| // deploy the new content-package to the local mvn bundles dir and attach it to the feature |
| try (VaultPackage result = processContentPackageArchive(clonedPackage, runMode)) { |
| emitters.stream().forEach(e -> e.endSubPackage(path, vaultPackage.getId(), result)); |
| } |
| |
| // restore the previous assembler |
| setMainPackageAssembler(handler); |
| } |
| |
| private @NotNull VaultPackage processContentPackageArchive(@NotNull VaultPackageAssembler assembler, |
| @Nullable String runMode) throws IOException, ConverterException { |
| File contentPackageArchive = assembler.createPackage(); |
| |
| VaultPackage vaultPackage = open(contentPackageArchive); |
| |
| PackageType packageType = detectPackageType(vaultPackage); |
| |
| // SLING-8608 - Fail the conversion if the resulting attached content-package is MIXED type |
| if (PackageType.MIXED == packageType && failOnMixedPackages) { |
| throw new ConverterException("Generated content-package '" |
| + vaultPackage.getId() |
| + "' located in file " |
| + contentPackageArchive |
| + " is of MIXED type"); |
| } |
| |
| ArtifactId mvnPackageId = toArtifactId(vaultPackage.getId(), contentPackageArchive); |
| // special handling for converted packages of type content |
| if (PackageType.CONTENT == packageType) { |
| switch (contentTypePackagePolicy) { |
| case DROP: |
| mutableContentsIds.put(vaultPackage.getId(), getDependencies(vaultPackage)); |
| logger.info("Dropping package of PackageType.CONTENT {} (content-package id: {})", |
| mvnPackageId.getArtifactId(), vaultPackage.getId()); |
| break; |
| case PUT_IN_DEDICATED_FOLDER: |
| mutableContentsIds.put(vaultPackage.getId(), getDependencies(vaultPackage)); |
| // deploy the new content-package to the unreferenced artifacts deployer |
| if (unreferencedArtifactsDeployer == null) { |
| throw new IllegalStateException("ContentTypePackagePolicy PUT_IN_DEDICATED_FOLDER requires a valid deployer "); |
| } |
| final String location = unreferencedArtifactsDeployer.deploy(new FileArtifactWriter(contentPackageArchive), runMode, mvnPackageId); |
| logger.info("Put converted package of PackageType.CONTENT {} (content-package id: {}) at {} (not referenced in feature model)", |
| mvnPackageId.getArtifactId(), vaultPackage.getId(), location); |
| break; |
| case REFERENCE: |
| deploy(assembler, mvnPackageId, runMode); |
| } |
| } else { |
| deploy(assembler, mvnPackageId, runMode); |
| } |
| return vaultPackage; |
| } |
| |
| public void deployPackages() { |
| try { |
| mutableContentsIds.values().forEach( |
| value -> value.removeIf(dep -> mutableContentsIds.keySet().stream().anyMatch(dep::matches))); |
| |
| deployTasks.forEach(Runnable::run); |
| } catch (RuntimeException ex) { |
| if (ex.getCause() instanceof Exception) { |
| throw ex; |
| } |
| throw ex; |
| } |
| deployTasks.clear(); |
| } |
| |
| private void deploy(@NotNull VaultPackageAssembler assembler, @NotNull ArtifactId mvnPackageId, @Nullable String runMode) { |
| Objects.requireNonNull(getFeaturesManager()).addArtifact(runMode, mvnPackageId); |
| ArtifactsDeployer deployer = Objects.requireNonNull(getArtifactsDeployer()); |
| deployTasks.add(() -> { |
| assembler.updateDependencies(mutableContentsIds); |
| try { |
| File finalContentPackageArchive = assembler.createPackage(); |
| // deploy the new content-package to the local mvn bundles dir |
| deployer.deploy(new FileArtifactWriter(finalContentPackageArchive), runMode, mvnPackageId); |
| } catch (Exception ex) { |
| throw new RuntimeException(ex); |
| } |
| }); |
| } |
| |
| public boolean isSubContentPackageIncluded(@NotNull String path) { |
| return subContentPackages.containsValue(path); |
| } |
| |
| private void process(@NotNull String entryPath, @NotNull Archive archive, @Nullable Entry entry, String runMode) throws IOException, ConverterException { |
| if (resourceFilter != null && resourceFilter.isFilteredOut(entryPath)) { |
| throw new ConverterException("Path '" |
| + entryPath |
| + "' in archive " |
| + archive.getMetaInf().getPackageProperties().getId() |
| + " not allowed by user configuration, please check configured filtering patterns"); |
| } |
| |
| EntryHandler entryHandler = handlersManager.getEntryHandlerByEntryPath(entryPath); |
| if (entryHandler == null) { |
| entryHandler = new DefaultHandler(getMainPackageAssembler(), removeInstallHooks); |
| } |
| |
| if (entry == null) { |
| entry = archive.getEntry(entryPath); |
| if (entry == null) { |
| throw new IllegalArgumentException("Archive '" + archive.getMetaInf().getPackageProperties().getId() + "' does not contain entry with path '" + entryPath + "'"); |
| } |
| } |
| entryHandler.handle(entryPath, archive, entry, this, runMode); |
| if (!getMainPackageAssembler().recordEntryPath(entryPath)) { |
| logger.warn("Duplicate entry path {}", entryPath); |
| } |
| } |
| |
| public ContentPackage2FeatureModelConverter setBundleSlingInitialContentExtractor(BundleSlingInitialContentExtractor bundleSlingInitialContentExtractor) { |
| this.bundleSlingInitialContentExtractor = bundleSlingInitialContentExtractor; |
| return this; |
| } |
| |
| @Override |
| protected void onFile(@NotNull String entryPath, @NotNull Archive archive, @NotNull Entry entry, String runMode) throws IOException, ConverterException { |
| try { |
| process(entryPath, archive, entry, runMode); |
| } catch (ConverterException ex) { |
| throw new ConverterException("ConverterException occured on path " + entryPath + " with message: " + ex.getMessage(), ex); |
| } catch (IOException ex) { |
| throw new IOException("IOException occured on path " + entryPath + " with message: " + ex.getMessage(), ex); |
| } |
| } |
| |
| public static @NotNull ArtifactId toArtifactId(@NotNull PackageId packageId, @NotNull File file) { |
| String groupId = requireNonNull(packageId.getGroup(), |
| PackageProperties.NAME_GROUP |
| + " property not found in content-package " |
| + file |
| + ", please check META-INF/vault/properties.xml").replace('/', '.'); |
| // Replace any space with an underscore to adhere to Maven Group Id specification |
| groupId = groupId.replace(" ", "_"); |
| |
| String artifactId = requireNonNull(packageId.getName(), |
| PackageProperties.NAME_NAME |
| + " property not found in content-package " |
| + file |
| + ", please check META-INF/vault/properties.xml"); |
| // Replace any space with an underscore to adhere to Maven Artifact Id specification |
| artifactId = artifactId.replace(" ", "_"); |
| |
| // package versions may use suffix "-cp2fm-converted" which is redundant as for artifactIds this is set as dedicated classifier |
| String version = packageId.getVersionString(); |
| if (version.endsWith(VaultPackageAssembler.VERSION_SUFFIX)) { |
| version = version.substring(0, version.length() - VaultPackageAssembler.VERSION_SUFFIX.length()); |
| } |
| if (version.isEmpty()) { |
| version = DEFAULT_VERSION; |
| } |
| |
| return new ArtifactId(groupId, artifactId, version, PACKAGE_CLASSIFIER, ZIP_TYPE); |
| } |
| |
| @Override |
| protected void addCdnPattern(@NotNull Pattern cndPattern) { |
| handlersManager.addEntryHandler(NodeTypesEntryHandler.forCndPattern(cndPattern)); |
| } |
| |
| @Override |
| public void close() throws IOException { |
| cleanup(); |
| } |
| |
| public List<VaultPackageAssembler> getAssemblers() { |
| return new ArrayList<>(assemblers); |
| } |
| } |