http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java index 4306f17..bc238ab 100644 --- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java @@ -19,24 +19,46 @@ package org.apache.karaf.tooling.features; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.URI; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; - +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; + +import org.apache.felix.utils.properties.InterpolationHelper; import org.apache.felix.utils.properties.Properties; -import org.apache.karaf.features.BundleInfo; -import org.apache.karaf.features.ConfigFileInfo; -import org.apache.karaf.features.ConfigInfo; -import org.apache.karaf.features.Dependency; -import org.apache.karaf.features.internal.model.*; +import org.apache.karaf.features.internal.download.impl.DownloadManagerHelper; +import org.apache.karaf.features.internal.model.Bundle; +import org.apache.karaf.features.internal.model.Conditional; +import org.apache.karaf.features.internal.model.Config; +import org.apache.karaf.features.internal.model.ConfigFile; +import org.apache.karaf.features.internal.model.Dependency; +import org.apache.karaf.features.internal.model.Feature; +import org.apache.karaf.features.internal.model.Features; +import org.apache.karaf.features.internal.model.JaxbUtil; +import org.apache.karaf.features.internal.util.MapUtils; import org.apache.karaf.kar.internal.Kar; +import org.apache.karaf.profile.Profile; +import org.apache.karaf.profile.ProfileBuilder; +import org.apache.karaf.profile.impl.Profiles; +import org.apache.karaf.tooling.url.CustomBundleURLStreamHandlerFactory; +import org.apache.karaf.tooling.utils.InternalMavenResolver; +import org.apache.karaf.tooling.utils.IoUtils; import org.apache.karaf.tooling.utils.MojoSupport; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.MojoExecutionException; @@ -45,6 +67,7 @@ import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; +import org.ops4j.pax.url.mvn.MavenResolver; /** * Installs kar dependencies into a server-under-construction in target/assembly @@ -56,7 +79,7 @@ public class InstallKarsMojo extends MojoSupport { * Base directory used to copy the resources during the build (working directory). */ @Parameter(defaultValue = "${project.build.directory}/assembly") - protected String workDirectory; + protected File workDirectory; /** * Features configuration file (etc/org.apache.karaf.features.cfg). @@ -71,16 +94,23 @@ public class InstallKarsMojo extends MojoSupport { protected File startupPropertiesFile; /** + * Directory used during build to construction the Karaf system repository. + */ + @Parameter(defaultValue="${project.build.directory}/assembly/system") + protected File systemDirectory; + + /** * default start level for bundles in features that don't specify it. */ @Parameter protected int defaultStartLevel = 30; - /** - * Directory used during build to construction the Karaf system repository. - */ - @Parameter(defaultValue="${project.build.directory}/assembly/system") - protected File systemDirectory; + @Parameter + private List<String> startupRepositories; + @Parameter + private List<String> bootRepositories; + @Parameter + private List<String> installedRepositories; /** * List of features from runtime-scope features xml and kars to be installed into system and listed in startup.properties. @@ -100,6 +130,25 @@ public class InstallKarsMojo extends MojoSupport { @Parameter private List<String> installedFeatures; + @Parameter + private List<String> startupBundles; + @Parameter + private List<String> bootBundles; + @Parameter + private List<String> installedBundles; + + @Parameter + private File profilesDirectory; + + @Parameter + private List<String> bootProfiles; + + @Parameter + private List<String> startupProfiles; + + @Parameter + private List<String> installedProfiles; + /** * Ignore the dependency attribute (dependency="[true|false]") on bundle */ @@ -118,8 +167,8 @@ public class InstallKarsMojo extends MojoSupport { @Parameter(defaultValue = "false") protected boolean useReferenceUrls; - private URI system; - private Properties startupProperties = new Properties(); + @Parameter + protected boolean installAllFeaturesByDefault = true; // an access layer for available Aether implementation protected DependencyHelper dependencyHelper; @@ -127,429 +176,569 @@ public class InstallKarsMojo extends MojoSupport { private static final String FEATURES_REPOSITORIES = "featuresRepositories"; private static final String FEATURES_BOOT = "featuresBoot"; - @SuppressWarnings("deprecation") @Override public void execute() throws MojoExecutionException, MojoFailureException { + + this.dependencyHelper = DependencyHelperFactory.createDependencyHelper(this.container, this.project, this.mavenSession, getLog()); + MavenResolver resolver = new InternalMavenResolver(dependencyHelper, getLog()); + CustomBundleURLStreamHandlerFactory.install(resolver); + + try { + doExecute(); + } + catch (MojoExecutionException | MojoFailureException e) { + throw e; + } + catch (Exception e) { + throw new MojoExecutionException("Unable to build assembly", e); + } + finally { + CustomBundleURLStreamHandlerFactory.uninstall(); + } + } + + protected void doExecute() throws Exception { this.dependencyHelper = DependencyHelperFactory.createDependencyHelper(this.container, this.project, this.mavenSession, getLog()); // creating system directory getLog().info("Creating system directory"); systemDirectory.mkdirs(); - system = systemDirectory.toURI(); - if (startupPropertiesFile.exists()) { - getLog().info("Loading startup.properties"); - try { - InputStream in = new FileInputStream(startupPropertiesFile); - try { - startupProperties.load(in); - } finally { - in.close(); - } - } catch (IOException e) { - throw new MojoFailureException("Could not open existing startup.properties file at " + startupPropertiesFile, e); + IoUtils.deleteRecursive(new File(systemDirectory, "generated")); + + startupRepositories = nonNullList(startupRepositories); + bootRepositories = nonNullList(bootRepositories); + installedRepositories = nonNullList(installedRepositories); + startupBundles = nonNullList(startupBundles); + bootBundles = nonNullList(bootBundles); + installedBundles = nonNullList(installedBundles); + startupFeatures = nonNullList(startupFeatures); + bootFeatures = nonNullList(bootFeatures); + installedFeatures = nonNullList(installedFeatures); + startupProfiles = nonNullList(startupProfiles); + bootProfiles = nonNullList(bootProfiles); + installedProfiles = nonNullList(installedProfiles); + + if (!startupProfiles.isEmpty() || !bootProfiles.isEmpty() || !installedProfiles.isEmpty()) { + if (profilesDirectory == null) { + throw new IllegalArgumentException("profilesDirectory must be specified"); } - } else { - getLog().info("Creating startup.properties"); - startupProperties.setHeader(Collections.singletonList("#Bundles to be started on startup, with startlevel")); - if (!startupPropertiesFile.getParentFile().exists()) { - startupPropertiesFile.getParentFile().mkdirs(); - } - } - - Set<String> repositories = new HashSet<>(); - Map<Feature, Boolean> features = new HashMap<>(); - - // loading kar and features repositories - getLog().info("Loading kar and features repositories dependencies with compile or runtime scopes"); - getLog().info("The startup.properties file is updated using kar and features dependency with a scope different from runtime, or defined in the <startupFeatures/> plugin configuration"); - Collection<Artifact> dependencies = project.getDependencyArtifacts(); - for (Artifact artifact : dependencies) { - boolean addToStartup = !artifact.getScope().equals("runtime"); - if (artifact.getScope().equals("compile") || artifact.getScope().equals("runtime")) { - if (artifact.getType().equals("kar")) { - File karFile = artifact.getFile(); - getLog().info("Extracting " + artifact.toString() + " kar"); - try { - Kar kar = new Kar(karFile.toURI()); - kar.extract(new File(system.getPath()), new File(workDirectory)); - for (URI repositoryUri : kar.getFeatureRepos()) { - resolveRepository(repositoryUri.getPath(), repositories, features, false, addToStartup); - } - } catch (Exception e) { - throw new RuntimeException("Can not install " + artifact.toString() + " kar", e); - } - } else { - if (artifact.getClassifier() != null && artifact.getClassifier().equals("features")) { - getLog().info("Resolving " + artifact.toString() + " features repository"); - String repositoryUri = dependencyHelper.artifactToMvn(artifact); - try { - resolveRepository(repositoryUri, repositories, features, true, addToStartup); - } catch (Exception e) { - throw new MojoFailureException("Can not install " + artifact.toString() + " features repository", e); + } + + if (featureRepositories != null && !featureRepositories.isEmpty()) { + getLog().warn("Use of featureRepositories is deprecated, use startupRepositories, bootRepositories or installedRepositories instead"); + startupRepositories.addAll(featureRepositories); + bootRepositories.addAll(featureRepositories); + installedRepositories.addAll(featureRepositories); + } + + // Build optional features and known prerequisites + Map<String, List<String>> prereqs = new HashMap<>(); + prereqs.put("blueprint:", Arrays.asList("deployer", "aries-blueprint")); + prereqs.put("spring:", Arrays.asList("deployer", "spring")); + prereqs.put("wrap:", Arrays.asList("wrap")); + prereqs.put("war:", Arrays.asList("war")); + + + // Loading kars and features repositories + getLog().info("Loading kar and features repositories dependencies"); + for (Artifact artifact : project.getDependencyArtifacts()) { + if ("kar".equals(artifact.getType())) { + File karFile = artifact.getFile(); + getLog().info("Extracting " + artifact.toString() + " kar"); + try { + Kar kar = new Kar(karFile.toURI()); + kar.extract(systemDirectory, workDirectory); + for (URI repositoryUri : kar.getFeatureRepos()) { + switch (artifact.getScope()) { + case "compile": + startupRepositories.add(repositoryUri.getPath()); + break; + case "runtime": + bootRepositories.add(repositoryUri.getPath()); + break; + case "provided": + installedRepositories.add(repositoryUri.getPath()); + break; } } + } catch (Exception e) { + throw new RuntimeException("Can not install " + artifact.toString() + " kar", e); + } + } else if ("features".equals(artifact.getClassifier())) { + String repositoryUri = dependencyHelper.artifactToMvn(artifact); + switch (artifact.getScope()) { + case "compile": + startupRepositories.add(repositoryUri); + break; + case "runtime": + bootRepositories.add(repositoryUri); + break; + case "provided": + installedRepositories.add(repositoryUri); + break; + } + } else if ("jar".equals(artifact.getType()) || "bundle".equals(artifact.getType())) { + String bundleUri = dependencyHelper.artifactToMvn(artifact); + switch (artifact.getScope()) { + case "compile": + startupBundles.add(bundleUri); + break; + case "runtime": + bootBundles.add(bundleUri); + break; + case "provided": + installedBundles.add(bundleUri); + break; } } } - if (featureRepositories != null) { - for (String repositoryUri : featureRepositories) { - try { - resolveRepository(repositoryUri, repositories, features, true, false); - } catch (Exception e) { - throw new MojoFailureException("Can not install " + repositoryUri + " features repository", e); - } + + // Load profiles + Map<String, Profile> allProfiles; + if (profilesDirectory != null) { + allProfiles = Profiles.loadProfiles(profilesDirectory.toPath()); + } else { + allProfiles = new HashMap<>(); + } + // Generate profiles + Profile startupProfile = generateProfile(allProfiles, startupProfiles, startupRepositories, startupFeatures, startupBundles); + Profile bootProfile = generateProfile(allProfiles, bootProfiles, bootRepositories, bootFeatures, bootBundles); + Profile installedProfile = generateProfile(allProfiles, installedProfiles, installedRepositories, installedFeatures, installedBundles); + + // + // Compute overall profile + // + Profile overallProfile = ProfileBuilder.Factory.create(UUID.randomUUID().toString()) + .setParents(Arrays.asList(startupProfile.getId(), bootProfile.getId(), installedProfile.getId())) + .getProfile(); + Profile overallOverlay = Profiles.getOverlay(overallProfile, allProfiles); + Profile overallEffective = Profiles.getEffective(overallOverlay, false); + + Hashtable<String, String> agentProps = new Hashtable<>(overallEffective.getConfiguration("org.ops4j.pax.url.mvn")); + final Map<String, String> properties = new HashMap<>(); + properties.put("karaf.default.repository", "system"); + InterpolationHelper.performSubstitution(agentProps, new InterpolationHelper.SubstitutionCallback() { + @Override + public String getValue(String key) { + return properties.get(key); } + }, false, false, true); + + // + // Write all configuration files + // + for (Map.Entry<String, byte[]> config : overallEffective.getFileConfigurations().entrySet()) { + Path configFile = workDirectory.toPath().resolve("etc/" + config.getKey()); + Files.write(configFile, config.getValue()); } - // checking if all startup, installed, and boot features have been resolved - getLog().info("Checking features resolution"); - List<String> resolvedFeaturesNames = new ArrayList<>(); - for (Feature feature : features.keySet()) { - resolvedFeaturesNames.add(feature.getName()); + // + // Compute startup + // + Profile startupOverlay = Profiles.getOverlay(startupProfile, allProfiles); + Profile startupEffective = Profiles.getEffective(startupOverlay, false); + // Load startup repositories + Map<String, Features> startupRepositories = loadRepositories(startupEffective.getRepositories()); + // Compute startup feature dependencies + Set<Feature> allStartupFeatures = new HashSet<>(); + for (Features repo : startupRepositories.values()) { + allStartupFeatures.addAll(repo.getFeature()); } - if (startupFeatures != null) { - for (String startupFeature : startupFeatures) { - if (!resolvedFeaturesNames.contains(startupFeature)) { - throw new MojoFailureException("Feature " + startupFeature + " is not resolved. Check that <dependencies/> provide the kar of features repository providing this feature (with compile or runtime scope)"); - } + Set<Feature> startupFeatures = new LinkedHashSet<>(); + if (startupEffective.getFeatures().isEmpty() && installAllFeaturesByDefault) { + startupFeatures.addAll(allStartupFeatures); + } else { + for (String feature : startupEffective.getFeatures()) { + addFeatures(startupFeatures, allStartupFeatures, feature); } } - if (bootFeatures != null) { - for (String bootFeature : bootFeatures) { - if (!resolvedFeaturesNames.contains(bootFeature)) { - throw new MojoFailureException("Feature " + bootFeature + " is not resolved. Check that <dependencies/> provide the kar of features repository providing this feature (with compile or runtime scope)"); + // Compute all bundles + Map<String, Integer> allStartupBundles = new LinkedHashMap<>(); + for (Feature feature : startupFeatures) { + for (Bundle bundleInfo : feature.getBundle()) { + String bundleLocation = bundleInfo.getLocation(); + int bundleStartLevel = bundleInfo.getStartLevel() == 0 ? defaultStartLevel : bundleInfo.getStartLevel(); + if (allStartupBundles.containsKey(bundleLocation)) { + bundleStartLevel = Math.min(bundleStartLevel, allStartupBundles.get(bundleLocation)); } + allStartupBundles.put(bundleLocation, bundleStartLevel); } - } - if (installedFeatures != null) { - for (String installedFeature : installedFeatures) { - if (!resolvedFeaturesNames.contains(installedFeature)) { - throw new MojoFailureException("Feature " + installedFeature + " is not resolved. Check that <dependencies/> provide the kar of features repository providing this feature (with compile or runtime scope)"); + // Install config + for (Config config : feature.getConfig()) { + installConfig(config); + } + for (Conditional cond : feature.getConditional()) { + for (Config config : cond.getConfig()) { + installConfig(config); } } - } - - // install features/bundles - getLog().info("Installing features"); - for (Feature feature : features.keySet()) { - try { - if (features.get(feature) || (startupFeatures != null && startupFeatures.contains(feature.getName()))) { - // the feature is a startup feature, updating startup.properties file - getLog().info("Feature " + feature.getName() + " is defined as a startup feature"); - getLog().info("= Updating startup.properties file"); - List<String> comment = Arrays.asList("", "# feature: " + feature.getName() + " version: " + feature.getVersion()); - for (BundleInfo bundleInfo : feature.getBundles()) { - String bundleLocation = bundleInfo.getLocation(); - String bundleStartLevel = Integer.toString(bundleInfo.getStartLevel() == 0 ? defaultStartLevel : bundleInfo.getStartLevel()); - if (useReferenceUrls) { - bundleLocation = "reference:file:" + dependencyHelper.pathFromMaven(bundleLocation); - } - if (startupProperties.containsKey(bundleLocation)) { - int oldStartLevel = Integer.decode(startupProperties.get(bundleLocation)); - if (oldStartLevel > bundleInfo.getStartLevel()) { - startupProperties.put(bundleLocation, bundleStartLevel); - } - } else { - if (comment == null) { - startupProperties.put(bundleLocation, bundleStartLevel); - } else { - startupProperties.put(bundleLocation, comment, bundleStartLevel); - comment = null; - } - } + // Install config files + for (ConfigFile configFile : feature.getConfigfile()) { + try (InputStream is = new URL(configFile.getLocation()).openStream()) { + String path = configFile.getFinalname(); + if (path.startsWith("/")) { + path = path.substring(1); } - // add the feature in the system folder - resolveFeature(feature, features, true); - } else if (bootFeatures != null && bootFeatures.contains(feature.getName())) { - // the feature is a boot feature, updating the etc/org.apache.karaf.features.cfg file - getLog().info("Feature " + feature.getName() + " is defined as a boot feature"); - if (featuresCfgFile.exists()) { - getLog().info("= Updating " + featuresCfgFile.getPath()); - Properties featuresProperties = new Properties(featuresCfgFile); - String featuresBoot = featuresProperties.getProperty(FEATURES_BOOT); - featuresBoot = featuresBoot != null && featuresBoot.length() > 0 ? featuresBoot + "," : ""; - if (!featuresBoot.contains(feature.getName())) { - featuresBoot = featuresBoot + feature.getName(); - featuresProperties.put(FEATURES_BOOT, featuresBoot); - featuresProperties.save(); - } - } - // add the feature in the system folder - resolveFeature(feature, features, false); - } else if (installedFeatures != null && installedFeatures.contains(feature.getName())) { - getLog().info("Feature " + feature.getName() + " is defined as a installed feature"); - // add the feature in the system folder - resolveFeature(feature, features, false); - } else { - getLog().debug("Feature " + feature.getName() + " is not installed"); - } - } catch (Exception e) { - throw new MojoFailureException("Can not install " + feature.getName() + " feature", e); - } - } - - // install bundles defined in startup.properties - getLog().info("Installing bundles defined in startup.properties in the system"); - Set<String> startupBundles = startupProperties.keySet(); - for (String startupBundle : startupBundles) { - if (startupBundle.startsWith("mvn:")) { - String bundlePath = this.dependencyHelper.pathFromMaven(startupBundle); - File bundleFile = new File(system.resolve(bundlePath)); - if (!bundleFile.exists()) { - File bundleSource = this.dependencyHelper.resolveById(startupBundle, getLog()); - bundleFile.getParentFile().mkdirs(); - copy(bundleSource, bundleFile); + Path output = workDirectory.toPath().resolve(path); + Files.copy(is, output, StandardCopyOption.REPLACE_EXISTING); // TODO: be smarter about overwrites } - } else if (startupBundle.startsWith("reference:file:")) { - String bundlePath = startupBundle.substring("reference:file:".length()); - File bundleFile = new File(system.resolve(bundlePath)); - if (!bundleFile.exists()) { - File bundleSource = this.dependencyHelper.resolveById(MavenUtil.pathToMvn(bundlePath), getLog()); - bundleFile.getParentFile().mkdirs(); - copy(bundleSource, bundleFile); + } + for (Conditional cond : feature.getConditional()) { + for (ConfigFile configFile : cond.getConfigfile()) { + try (InputStream is = new URL(configFile.getLocation()).openStream()) { + Path output = workDirectory.toPath().resolve(configFile.getFinalname()); + Files.copy(is, output, StandardCopyOption.REPLACE_EXISTING); // TODO: be smarter about overwrites + } } } } - - // generate the startup.properties file - getLog().info("Generating the startup.properties file"); - try { - OutputStream out = new FileOutputStream(startupPropertiesFile); - try { - startupProperties.save(out); - } finally { - out.close(); + for (String bundleLocation : startupEffective.getBundles()) { + int bundleStartLevel = defaultStartLevel; + if (allStartupBundles.containsKey(bundleLocation)) { + bundleStartLevel = Math.min(bundleStartLevel, allStartupBundles.get(bundleLocation)); } - } catch (IOException e) { - throw new MojoFailureException("Can not write " + startupPropertiesFile, e); + allStartupBundles.put(bundleLocation, bundleStartLevel); } - } - - private void resolveRepository(String repository, Set<String> repositories, Map<Feature, Boolean> features, boolean updateFeaturesCfgFile, boolean updateStartupProperties) throws Exception { - // check if the repository has not been processed - if (repositories.contains(repository)) { - return; - } - getLog().info("Resolving " + repository + " features repository"); - repositories.add(repository); - // update etc/org.apache.karaf.features.cfg file - if (updateFeaturesCfgFile && featuresCfgFile.exists()) { - Properties featuresProperties = new Properties(); - InputStream in = new FileInputStream(featuresCfgFile); - try { - featuresProperties.load(in); - } finally { - in.close(); - } - String featureRepos = featuresProperties.getProperty(FEATURES_REPOSITORIES); - featureRepos = featureRepos != null && featureRepos.length() > 0 ? featureRepos + "," : ""; - if (!featureRepos.contains(repository)) { - featureRepos = featureRepos + repository; - featuresProperties.put(FEATURES_REPOSITORIES, featureRepos); - featuresProperties.save(featuresCfgFile); - } - } - // resolving repository location - File repositoryFile; - if (repository.startsWith("mvn")) { - repositoryFile = dependencyHelper.resolveById(repository, getLog()); - repository = dependencyHelper.pathFromMaven(repository); - } else { - repositoryFile = new File(repository); + // Load startup.properties + startupPropertiesFile.getParentFile().mkdirs(); + Properties startupProperties = new Properties(startupPropertiesFile); + if (!startupPropertiesFile.exists()) { + startupProperties.setHeader(Collections.singletonList("# Bundles to be started on startup, with startlevel")); } - // copy the repository file in system folder - File repositoryFileInSystemFolder = new File(system.resolve(repository)); - if (!repositoryFileInSystemFolder.exists()) { - repositoryFileInSystemFolder.getParentFile().mkdirs(); - copy(repositoryFile, repositoryFileInSystemFolder); - // add metadata for snapshot - if (repository.startsWith("mvn")) { - Artifact repositoryArtifact = dependencyHelper.mvnToArtifact(repository); - if (repositoryArtifact.isSnapshot()) { - File metadataTarget = new File(repositoryFileInSystemFolder.getParentFile(), "maven-metadata-local.xml"); - try { - MavenUtil.generateMavenMetadata(repositoryArtifact, metadataTarget); - } catch (Exception e) { - getLog().warn("Could not create maven-metadata-local.xml", e); - getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories"); - } + // Install bundles and update startup.properties + Map<Integer, Set<String>> invertedStartupBundles = MapUtils.invert(allStartupBundles); + for (Map.Entry<Integer, Set<String>> entry : invertedStartupBundles.entrySet()) { + String startLevel = Integer.toString(entry.getKey()); + for (String location : new TreeSet<>(entry.getValue())) { + location = installStartupArtifact(location, useReferenceUrls); + if (location.startsWith("file:") && useReferenceUrls) { + location = "reference:" + location; } + startupProperties.put(location, startLevel); } } - // loading the model - Features featuresModel = JaxbUtil.unmarshal(repositoryFile.toURI().toString(), new FileInputStream(repositoryFile), false); - // recursively process the inner repositories - for (String innerRepository : featuresModel.getRepository()) { - resolveRepository(innerRepository, repositories, features, false, updateStartupProperties); + // generate the startup.properties file + startupProperties.save(); + + + // + // Handle boot profiles + // + Profile bootOverlay = Profiles.getOverlay(bootProfile, allProfiles); + Profile bootEffective = Profiles.getEffective(bootOverlay, false); + // Load startup repositories + Map<String, Features> bootRepositories = loadRepositories(bootEffective.getRepositories()); + // Compute startup feature dependencies + Set<Feature> allBootFeatures = new HashSet<>(); + for (Features repo : bootRepositories.values()) { + allBootFeatures.addAll(repo.getFeature()); } - // update features - for (Feature feature : featuresModel.getFeature()) { - features.put(feature, updateStartupProperties); + // Install all repositories + for (String repository : bootRepositories.keySet()) { + installArtifact(repository); } - } - - private void resolveFeature(Feature feature, Map<Feature, Boolean> features, boolean installConfig) throws Exception { - for (Dependency dependency : feature.getFeature()) { - for (Feature f : features.keySet()) { - if (f.getName().equals(dependency.getName())) { - resolveFeature(f, features, installConfig); + // Generate a global feature + Map<String, Dependency> generatedDep = new HashMap<>(); + Feature generated = new Feature(); + generated.setName(UUID.randomUUID().toString()); + // Add feature dependencies + if (bootEffective.getFeatures().isEmpty()) { + if (installAllFeaturesByDefault) { + for (Features repo : bootRepositories.values()) { + for (Feature feature : repo.getFeature()) { + Dependency dep = generatedDep.get(feature.getName()); + if (dep == null) { + dep = new Dependency(); + dep.setName(feature.getName()); + generated.getFeature().add(dep); + generatedDep.put(dep.getName(), dep); + } + dep.setDependency(false); + } + } + } + } else { + for (String dependency : bootEffective.getFeatures()) { + Dependency dep = generatedDep.get(dependency); + if (dep == null) { + dep = new Dependency(); + dep.setName(dependency); + generated.getFeature().add(dep); + generatedDep.put(dep.getName(), dep); } + dep.setDependency(false); } } - - getLog().info("Resolving feature " + feature.getName()); - - // installing feature bundles - getLog().info("= Installing bundles from " + feature.getName() + " feature"); - for (Bundle bundle : feature.getBundle()) { - installBundle(bundle); + // Add bundles + for (String location : bootEffective.getBundles()) { + location = location.replace("profile:", "file:etc/"); + Bundle bun = new Bundle(); + bun.setLocation(location); + generated.getBundle().add(bun); } - - // installing feature config files - getLog().info("= Installing configuration files from " + feature.getName() + " feature"); - if (installConfig) { - for (Config config : feature.getConfig()) { - installConfig(config); + Features rep = new Features(); + rep.setName(UUID.randomUUID().toString()); + rep.getRepository().addAll(bootEffective.getRepositories()); + rep.getFeature().add(generated); + allBootFeatures.add(generated); + + // Compute startup feature dependencies + Set<Feature> bootFeatures = new HashSet<>(); + addFeatures(bootFeatures, allBootFeatures, generated.getName()); + for (Feature feature : bootFeatures) { + // the feature is a startup feature, updating startup.properties file + getLog().info("Feature " + feature.getName() + " is defined as a boot feature"); + // add the feature in the system folder + Set<String> locations = new HashSet<>(); + for (Bundle bundle : feature.getBundle()) { + if (!ignoreDependencyFlag || !bundle.isDependency()) { + locations.add(bundle.getLocation()); + } } - } - for (ConfigFile configFile : feature.getConfigfile()) { - installConfigFile(configFile, installConfig); - } - - // installing condition features - for (Conditional conditional : feature.getConditional()) { -// boolean found = true; -// for (String condition : conditional.getCondition()) { -// if (!condition.startsWith("req:")) { -// if ((installedFeatures != null && !installedFeatures.contains(condition)) && (bootFeatures != null && !bootFeatures.contains(condition))) { -// found = false; -// break; -// } -// } -// } -// if (found) { - getLog().info("= Installing conditional " + conditional.getCondition().toString()); - getLog().debug("== Conditional features ..."); - for (Dependency dependency : conditional.getFeature()) { - for (Feature f : features.keySet()) { - if (f.getName().equals(dependency.getName())) { - resolveFeature(f, features, installConfig); - } + for (Conditional cond : feature.getConditional()) { + for (Bundle bundle : cond.getBundle()) { + if (!ignoreDependencyFlag || !bundle.isDependency()) { + locations.add(bundle.getLocation()); } } - getLog().debug("== Conditional bundles"); - for (Bundle bundle : conditional.getBundle()) { - installBundle(bundle); - } - getLog().debug("== Conditional configuration files"); - if (installConfig) { - for (Config config : conditional.getConfig()) { - installConfig(config); + } + for (String location : locations) { + installArtifact(location); + for (Map.Entry<String, List<String>> entry : prereqs.entrySet()) { + if (location.startsWith(entry.getKey())) { + for (String prereq : entry.getValue()) { + Dependency dep = generatedDep.get(prereq); + if (dep == null) { + dep = new Dependency(); + dep.setName(prereq); + generated.getFeature().add(dep); + generatedDep.put(dep.getName(), dep); + } + dep.setPrerequisite(true); + } } } - for (ConfigFile configFile : conditional.getConfigfile()) { - installConfigFile(configFile, installConfig); + } + // Install config files + for (ConfigFile configFile : feature.getConfigfile()) { + installArtifact(configFile.getLocation()); + } + for (Conditional cond : feature.getConditional()) { + for (ConfigFile configFile : cond.getConfigfile()) { + installArtifact(configFile.getLocation()); } -// } + } } - } - private void installBundle(Bundle bundle) throws Exception { - if (!ignoreDependencyFlag && bundle.isDependency()) { - getLog().warn("== Bundle " + bundle.getLocation() + " is defined as dependency, so it's not installed"); - } else { - getLog().info("== Installing bundle " + bundle.getLocation()); - String bundleLocation = bundle.getLocation(); - // cleanup prefixes - if (bundleLocation.startsWith("wrap:")) { - bundleLocation = bundleLocation.substring("wrap:".length()); - int index = bundleLocation.indexOf("$"); - if (index != -1) { - bundleLocation = bundleLocation.substring(0, index); - } + // If there are bundles to install, we can't use the boot features only + // so keep the generated feature + if (!generated.getBundle().isEmpty()) { + File output = new File(workDirectory, "etc/" + rep.getName() + ".xml"); + try (FileOutputStream os = new FileOutputStream(output)) { + JaxbUtil.marshal(rep, os); } - if (bundleLocation.startsWith("blueprint:")) { - bundleLocation = bundleLocation.substring("blueprint:".length()); + Properties featuresProperties = new Properties(featuresCfgFile); + featuresProperties.put(FEATURES_REPOSITORIES, "file:${karaf.home}/etc/" + output.getName()); + featuresProperties.put(FEATURES_BOOT, generated.getName()); + featuresProperties.save(); + } + else { + String boot = ""; + for (Dependency dep : generatedDep.values()) { + if (dep.isPrerequisite()) { + if (boot.isEmpty()) { + boot = "("; + } else { + boot = boot + ","; + } + boot = boot + dep.getName(); + } } - if (bundleLocation.startsWith("webbundle:")) { - bundleLocation = bundleLocation.substring("webbundle:".length()); + if (!boot.isEmpty()) { + boot = boot + ")"; } - if (bundleLocation.startsWith("war:")) { - bundleLocation = bundleLocation.substring("war:".length()); + // TODO: for dependencies, we'd need to resolve the features completely + for (Dependency dep : generatedDep.values()) { + if (!dep.isPrerequisite() && !dep.isDependency()) { + if (!boot.isEmpty()) { + boot = boot + ","; + } + boot = boot + dep.getName(); + } } - File bundleFile; - if (bundleLocation.startsWith("mvn:")) { - if (bundleLocation.endsWith("/")) { - // for bad formed URL (like in Camel for mustache-compiler), we remove the trailing / - bundleLocation = bundleLocation.substring(0, bundleLocation.length() - 1); + String repos = ""; + for (String repo : new HashSet<>(rep.getRepository())) { + if (!repos.isEmpty()) { + repos = repos + ","; } - if (bundleLocation.startsWith("mvn:http")) { - // cleanup the URL containing the repository location directly in the URL - int index = bundleLocation.indexOf("!"); - if (index != -1) { - bundleLocation = bundleLocation.substring(index + 1); - bundleLocation = "mvn:" + bundleLocation; - } + repos = repos + repo; + } + + Properties featuresProperties = new Properties(featuresCfgFile); + featuresProperties.put(FEATURES_REPOSITORIES, repos); + featuresProperties.put(FEATURES_BOOT, boot); + featuresProperties.save(); + } + + + // + // Handle installed profiles + // + Profile installedOverlay = Profiles.getOverlay(installedProfile, allProfiles); + Profile installedEffective = Profiles.getEffective(installedOverlay, false); + + // Load startup repositories + Map<String, Features> installedRepositories = loadRepositories(installedEffective.getRepositories()); + // Install all repositories + for (String repository : installedRepositories.keySet()) { + installArtifact(repository); + } + // Compute startup feature dependencies + Set<Feature> allInstalledFeatures = new HashSet<>(); + for (Features repo : installedRepositories.values()) { + allInstalledFeatures.addAll(repo.getFeature()); + } + Set<Feature> installedFeatures = new LinkedHashSet<>(); + if (installedEffective.getFeatures().isEmpty() && installAllFeaturesByDefault) { + installedFeatures.addAll(allInstalledFeatures); + } else { + // Add boot features for search + allInstalledFeatures.addAll(allBootFeatures); + for (String feature : installedEffective.getFeatures()) { + addFeatures(installedFeatures, allInstalledFeatures, feature); + } + } + for (Feature feature : installedFeatures) { + for (Bundle bundle : feature.getBundle()) { + if (!ignoreDependencyFlag || !bundle.isDependency()) { + installArtifact(bundle.getLocation()); } - bundleFile = dependencyHelper.resolveById(bundleLocation, getLog()); - bundleLocation = dependencyHelper.pathFromMaven(bundleLocation); - } else { - bundleFile = new File(new URI(bundleLocation)); } - File bundleSystemFile = new File(system.resolve(bundleLocation)); - copy(bundleFile, bundleSystemFile); - // add metadata for snapshot - if (bundleLocation.startsWith("mvn")) { - Artifact bundleArtifact = dependencyHelper.mvnToArtifact(bundleLocation); - if (bundleArtifact.isSnapshot()) { - File metadataTarget = new File(bundleSystemFile.getParentFile(), "maven-metadata-local.xml"); - try { - MavenUtil.generateMavenMetadata(bundleArtifact, metadataTarget); - } catch (Exception e) { - getLog().warn("Could not create maven-metadata-local.xml", e); - getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories"); + for (Conditional cond : feature.getConditional()) { + for (Bundle bundle : cond.getBundle()) { + if (!ignoreDependencyFlag || !bundle.isDependency()) { + installArtifact(bundle.getLocation()); } } } } + for (String location : installedEffective.getBundles()) { + installArtifact(location); + } + // TODO: install config files } - private void installConfig(Config config) throws Exception { - getLog().info("== Installing configuration " + config.getName()); + private Map<String, Features> loadRepositories(List<String> repositories) throws Exception { + Map<String, Features> loaded = new HashMap<>(); + for (String repository : repositories) { + doLoadRepository(loaded, repository); + } + return loaded; + } - Path configFile = Paths.get(workDirectory, "etc", config.getName()); - Files.write(configFile, config.getValue().getBytes()); + private void doLoadRepository(Map<String, Features> loaded, String repository) throws Exception { + if (!loaded.containsKey(repository)) { + Features featuresModel = JaxbUtil.unmarshal(repository, false); + loaded.put(repository, featuresModel); + // recursively process the inner repositories + for (String innerRepository : featuresModel.getRepository()) { + doLoadRepository(loaded, innerRepository); + } + } } - private void installConfigFile(ConfigFile configFile, boolean installConfig) throws Exception { - getLog().info("== Installing configuration file " + configFile.getLocation()); - String configFileLocation = configFile.getLocation(); - File configFileFile; - if (configFileLocation.startsWith("mvn:")) { - configFileFile = dependencyHelper.resolveById(configFileLocation, getLog()); - configFileLocation = dependencyHelper.pathFromMaven(configFileLocation); - } else { - configFileFile = new File(new URI(configFileLocation)); + private Profile generateProfile(Map<String, Profile> allProfiles, List<String> profiles, List<String> repositories, List<String> features, List<String> bundles) { + Profile profile = ProfileBuilder.Factory.create(UUID.randomUUID().toString()) + .setParents(profiles) + .setRepositories(repositories) + .setFeatures(features) + .setBundles(bundles) + .getProfile(); + allProfiles.put(profile.getId(), profile); + return profile; + } + + private List<String> nonNullList(List<String> list) { + return list == null ? new ArrayList<String>() : list; + } + + private void addFeatures(Set<Feature> startupFeatures, Set<Feature> features, String feature) { + int nbFound = 0; + for (Feature f : features) { + if (feature.equals(f.getName())) { + for (Dependency dep : f.getFeature()) { + addFeatures(startupFeatures, features, dep.getName()); + } + startupFeatures.add(f); + nbFound++; + } + } + if (nbFound == 0) { + throw new IllegalStateException("Could not find matching feature for " + feature); } - if (installConfig) { - copy(configFileFile, new File(workDirectory + "/" + configFile.getFinalname())); + } + + private String installStartupArtifact(String location, boolean asFile) throws Exception { + getLog().info("== Installing artifact " + location); + String url; + String path; + if (location.startsWith("mvn:")) { + url = location; + path = dependencyHelper.pathFromMaven(location); + if (asFile) { + location = "file:" + path ; + } } else { - File configFileSystemFile = new File(system.resolve(configFileLocation)); - copy(configFileFile, configFileSystemFile); + url = location.replace("profile:", "file:" + workDirectory.getAbsolutePath() + "/etc/"); + path = "generated/" + location.replaceAll("[^0-9a-zA-Z.\\-_]+", "_"); + location = "file:" + path; + } + File bundleSystemFile = new File(systemDirectory, path); + if (!bundleSystemFile.exists()) { + bundleSystemFile.getParentFile().mkdirs(); + try (InputStream is = new URL(url).openStream()) { + Files.copy(is, bundleSystemFile.toPath()); + } + } + return location; + } + + private void installArtifact(String location) throws Exception { + getLog().info("== Installing artifact " + location); + location = DownloadManagerHelper.stripUrl(location); + location = DownloadManagerHelper.removeInlinedMavenRepositoryUrl(location); + if (location.startsWith("mvn:")) { + if (location.endsWith("/")) { + // for bad formed URL (like in Camel for mustache-compiler), we remove the trailing / + location = location.substring(0, location.length() - 1); + } + File inputFile = dependencyHelper.resolveById(location, getLog()); + File targetFile = new File(systemDirectory, dependencyHelper.pathFromMaven(location)); + copy(inputFile, targetFile); // add metadata for snapshot - if (configFileLocation.startsWith("mvn")) { - Artifact configFileArtifact = dependencyHelper.mvnToArtifact(configFileLocation); - if (configFileArtifact.isSnapshot()) { - File metadataTarget = new File(configFileSystemFile.getParentFile(), "maven-metadata-local.xml"); - try { - MavenUtil.generateMavenMetadata(configFileArtifact, metadataTarget); - } catch (Exception e) { - getLog().warn("Could not create maven-metadata-local.xml", e); - getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories"); - } + Artifact artifact = dependencyHelper.mvnToArtifact(location); + if (artifact.isSnapshot()) { + File metadataTarget = new File(targetFile.getParentFile(), "maven-metadata-local.xml"); + try { + MavenUtil.generateMavenMetadata(artifact, metadataTarget); + } catch (Exception e) { + getLog().warn("Could not create maven-metadata-local.xml", e); + getLog().warn("It means that this SNAPSHOT could be overwritten by an older one present on remote repositories"); } } + } else { + getLog().warn("Ignoring artifact " + location); + } + } + + private void installConfig(Config config) throws Exception { + getLog().info("== Installing configuration " + config.getName()); + Path configFile = workDirectory.toPath().resolve("etc/" + config.getName()); + if (!Files.exists(configFile)) { + Files.write(configFile, config.getValue().getBytes()); + } else if (config.isAppend()) { + // TODO } }
http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java index f03d923..0692b53 100644 --- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/VerifyFeatureResolutionMojo.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Dictionary; import java.util.EnumSet; import java.util.Enumeration; import java.util.HashMap; @@ -48,6 +49,8 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicLong; import java.util.jar.Attributes; import java.util.jar.Manifest; @@ -66,7 +69,7 @@ import org.apache.karaf.features.FeatureEvent; import org.apache.karaf.features.FeaturesService; import org.apache.karaf.features.Repository; import org.apache.karaf.features.internal.download.DownloadManager; -import org.apache.karaf.features.internal.download.simple.SimpleDownloader; +import org.apache.karaf.features.internal.download.DownloadManagers; import org.apache.karaf.features.internal.resolver.ResourceBuilder; import org.apache.karaf.features.internal.resolver.ResourceImpl; import org.apache.karaf.features.internal.resolver.ResourceUtils; @@ -75,6 +78,9 @@ import org.apache.karaf.features.internal.service.RepositoryImpl; import org.apache.karaf.features.internal.service.State; import org.apache.karaf.features.internal.util.MapUtils; import org.apache.karaf.features.internal.util.MultiException; +import org.apache.karaf.tooling.url.CustomBundleURLStreamHandlerFactory; +import org.apache.karaf.tooling.utils.InternalMavenResolver; +import org.apache.karaf.tooling.utils.MojoSupport; import org.apache.karaf.tooling.utils.PropertiesLoader; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; @@ -84,7 +90,10 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.ops4j.pax.url.mvn.MavenResolver; +import org.ops4j.pax.url.mvn.MavenResolvers; import org.ops4j.pax.url.mvn.ServiceConstants; +import org.ops4j.pax.url.mvn.internal.AetherBasedResolver; import org.ops4j.pax.url.mvn.internal.Connection; import org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl; import org.osgi.framework.Bundle; @@ -105,7 +114,7 @@ import shaded.org.ops4j.util.property.PropertiesPropertyResolver; import static java.util.jar.JarFile.MANIFEST_NAME; @Mojo(name = "verify-features", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) -public class VerifyFeatureResolutionMojo extends AbstractMojo { +public class VerifyFeatureResolutionMojo extends MojoSupport { @Parameter(property = "descriptors") protected Set<String> descriptors; @@ -143,21 +152,24 @@ public class VerifyFeatureResolutionMojo extends AbstractMojo { @Parameter(defaultValue = "${project}", readonly = true) protected MavenProject project; + protected MavenResolver resolver; + @Override public void execute() throws MojoExecutionException, MojoFailureException { + DependencyHelper helper = DependencyHelperFactory.createDependencyHelper(this.container, this.project, this.mavenSession, getLog()); + resolver = new InternalMavenResolver(helper, getLog()); + CustomBundleURLStreamHandlerFactory.install(resolver); try { - Field field = URL.class.getDeclaredField("factory"); - field.setAccessible(true); - field.set(null, null); - } catch (Exception e) { - e.printStackTrace(); + doExecute(); + } finally { + CustomBundleURLStreamHandlerFactory.uninstall(); } - URL.setURLStreamHandlerFactory(new CustomBundleURLStreamHandlerFactory()); + } + protected void doExecute() throws MojoExecutionException, MojoFailureException { System.setProperty("karaf.home", "target/karaf"); System.setProperty("karaf.data", "target/karaf/data"); - Hashtable<String, String> properties = new Hashtable<>(); if (additionalMetadata != null) { @@ -174,7 +186,9 @@ public class VerifyFeatureResolutionMojo extends AbstractMojo { } } - DownloadManager manager = new SimpleDownloader(); + // TODO: allow using external configuration ? + ScheduledExecutorService executor = Executors.newScheduledThreadPool(8); + DownloadManager manager = DownloadManagers.createDownloadManager(resolver, executor); final Map<String, Repository> repositories; Map<String, Feature[]> allFeatures = new HashMap<>(); try { @@ -489,32 +503,6 @@ public class VerifyFeatureResolutionMojo extends AbstractMojo { return result; } - public static class CustomBundleURLStreamHandlerFactory implements URLStreamHandlerFactory { - - public URLStreamHandler createURLStreamHandler(String protocol) { - switch (protocol) { - case "mvn": - return new URLStreamHandler() { - @Override - protected URLConnection openConnection(URL url) throws IOException { - PropertiesPropertyResolver propertyResolver = new PropertiesPropertyResolver(System.getProperties()); - final MavenConfigurationImpl config = new MavenConfigurationImpl(propertyResolver, ServiceConstants.PID); - return new Connection(url, config); - } - }; - case "wrap": - return new org.ops4j.pax.url.wrap.Handler(); - case "blueprint": - return new org.apache.karaf.deployer.blueprint.BlueprintURLHandler(); - case "war": - return new org.ops4j.pax.url.war.Handler(); - default: - return null; - } - } - - } - public static Map<String, Map<VersionRange, Map<String, String>>> getMetadata(Map<String, String> properties, String prefix) { Map<String, Map<VersionRange, Map<String, String>>> result = new HashMap<>(); for (String key : properties.keySet()) { http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java index 422d680..d6fc156 100644 --- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/url/CustomBundleURLStreamHandlerFactory.java @@ -17,8 +17,21 @@ */ package org.apache.karaf.tooling.url; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.net.URLConnection; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; +import java.util.Hashtable; + +import org.ops4j.pax.url.mvn.MavenResolver; +import org.ops4j.pax.url.mvn.MavenResolvers; +import org.ops4j.pax.url.mvn.ServiceConstants; +import org.ops4j.pax.url.mvn.internal.AetherBasedResolver; +import org.ops4j.pax.url.mvn.internal.Connection; +import org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl; +import shaded.org.ops4j.util.property.PropertiesPropertyResolver; public class CustomBundleURLStreamHandlerFactory implements URLStreamHandlerFactory { @@ -29,9 +42,30 @@ public class CustomBundleURLStreamHandlerFactory implements URLStreamHandlerFact private static final String BLUEPRINT_URI_PREFIX = "blueprint"; private static final String WAR_URI_PREFIX = "war"; - public URLStreamHandler createURLStreamHandler(String protocol) { + private final MavenResolver mavenResolver; + + public CustomBundleURLStreamHandlerFactory() { + this(null); + } + + public CustomBundleURLStreamHandlerFactory(MavenResolver mavenResolver) { + this.mavenResolver = mavenResolver; + } + + public URLStreamHandler createURLStreamHandler(String protocol) { if (protocol.equals(MVN_URI_PREFIX)) { - return new org.ops4j.pax.url.mvn.Handler(); + return new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + MavenResolver resolver = mavenResolver; + if (resolver == null) { + PropertiesPropertyResolver propertyResolver = new PropertiesPropertyResolver(System.getProperties()); + final MavenConfigurationImpl config = new MavenConfigurationImpl(propertyResolver, ServiceConstants.PID); + resolver = new AetherBasedResolver(config); + } + return new Connection(u, resolver); + } + }; } else if (protocol.equals(WRAP_URI_PREFIX)){ return new org.ops4j.pax.url.wrap.Handler(); } else if (protocol.equals(FEATURE_URI_PREFIX)){ @@ -47,4 +81,26 @@ public class CustomBundleURLStreamHandlerFactory implements URLStreamHandlerFact } } + public static void install() { + install(null); + } + + public static void install(MavenResolver mavenResolver) { + uninstall(); + URL.setURLStreamHandlerFactory(new CustomBundleURLStreamHandlerFactory(mavenResolver)); + } + + public static void uninstall() { + try { + Field handlersField = URL.class.getDeclaredField("handlers"); + Field factoryField = URL.class.getDeclaredField("factory"); + factoryField.setAccessible(true); + factoryField.set(null, null); + handlersField.setAccessible(true); + handlersField.set(null, new Hashtable()); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java new file mode 100644 index 0000000..8d4b3f4 --- /dev/null +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/InternalMavenResolver.java @@ -0,0 +1,70 @@ +/** + * + * 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.karaf.tooling.utils; + +import java.io.File; +import java.io.IOException; + +import org.apache.karaf.tooling.features.DependencyHelper; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.ops4j.pax.url.mvn.MavenResolver; + +public class InternalMavenResolver implements MavenResolver { + + private final DependencyHelper dependencyHelper; + private final Log log; + + public InternalMavenResolver(DependencyHelper dependencyHelper, Log log) { + this.dependencyHelper = dependencyHelper; + this.log = log; + } + + @Override + public File resolve(String url) throws IOException { + try { + return dependencyHelper.resolveById(url, log); + } catch (MojoFailureException e) { + throw new IOException(e); + } + } + + @Override + public File resolve(String groupId, String artifactId, String classifier, String extension, String version) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public File resolveMetadata(String groupId, String artifactId, String type, String version) throws IOException { + return null; + } + + @Override + public void upload(String groupId, String artifactId, String classifier, String extension, String version, File artifact) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void uploadMetadata(String groupId, String artifactId, String type, String version, File artifact) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() throws IOException { + } +} http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java new file mode 100644 index 0000000..3069608 --- /dev/null +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/utils/IoUtils.java @@ -0,0 +1,38 @@ +/** + * + * 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.karaf.tooling.utils; + +import java.io.File; + +public class IoUtils { + + public static void deleteRecursive(File file) { + if (file != null) { + if (file.isDirectory()) { + File[] children = file.listFiles(); + if (children != null) { + for (File child : children) { + deleteRecursive(child); + } + } + } + file.delete(); + } + } + +} http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java b/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java index 46d7252..eea50c0 100644 --- a/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java +++ b/tooling/karaf-services-maven-plugin/src/main/java/org/apache/karaf/tooling/tracker/GenerateServiceMetadata.java @@ -17,7 +17,6 @@ package org.apache.karaf.tooling.tracker; import java.io.File; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -27,7 +26,6 @@ import org.apache.karaf.util.tracker.ProvideService; import org.apache.karaf.util.tracker.RequireService; import org.apache.karaf.util.tracker.Services; import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; http://git-wip-us.apache.org/repos/asf/karaf/blob/90cb480d/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java ---------------------------------------------------------------------- diff --git a/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java b/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java index d55a7de..149947c 100644 --- a/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java +++ b/util/src/main/java/org/apache/karaf/util/tracker/BaseActivator.java @@ -136,6 +136,9 @@ public class BaseActivator implements BundleActivator, SingleServiceTracker.Sing reconfigure(); } + protected Dictionary<String, ?> getConfiguration() { + return configuration; + } /** * Called in {@link #doStart()} */
