use of org.apache.karaf.features.internal.model.Features in project karaf by apache.
the class Builder method bootStage.
private Set<Feature> bootStage(Profile bootProfile, Profile startupEffective, FeaturesProcessor processor) throws Exception {
LOGGER.info("Boot stage");
//
// Handle boot profiles
//
Profile bootOverlay = Profiles.getOverlay(bootProfile, allProfiles, environment);
Profile bootEffective = Profiles.getEffective(bootOverlay, false);
// Load startup repositories
LOGGER.info(" Loading boot repositories");
Map<String, Features> bootRepositories = loadRepositories(manager, bootEffective.getRepositories(), true, processor);
// Compute startup feature dependencies
Set<Feature> allBootFeatures = new HashSet<>();
for (Features repo : bootRepositories.values()) {
allBootFeatures.addAll(repo.getFeature());
}
// Generate a global feature
Map<String, Dependency> generatedDep = new HashMap<>();
Feature generated = new Feature();
generated.setName(UUID.randomUUID().toString());
// Add feature dependencies
for (String nameOrPattern : bootEffective.getFeatures()) {
// KARAF-5273: feature may be a pattern
for (String dependency : FeatureSelector.getMatchingFeatures(nameOrPattern, bootRepositories.values())) {
Dependency dep = generatedDep.get(dependency);
if (dep == null) {
dep = createDependency(dependency);
generated.getFeature().add(dep);
generatedDep.put(dep.getName(), dep);
}
dep.setDependency(false);
}
}
// Add bundles
for (String location : bootEffective.getBundles()) {
location = location.replace("profile:", "file:etc/");
Bundle bun = new Bundle();
bun.setLocation(location);
generated.getBundle().add(bun);
}
Features rep = new Features();
rep.setName(UUID.randomUUID().toString());
rep.getRepository().addAll(bootEffective.getRepositories());
rep.getFeature().add(generated);
allBootFeatures.add(generated);
Downloader downloader = manager.createDownloader();
// Compute startup feature dependencies
FeatureSelector selector = new FeatureSelector(allBootFeatures);
Set<Feature> bootFeatures = selector.getMatching(singletonList(generated.getName()));
for (Feature feature : bootFeatures) {
if (feature.isBlacklisted()) {
LOGGER.info(" Feature " + feature.getId() + " is blacklisted, ignoring");
continue;
}
LOGGER.info(" Feature " + feature.getId() + " is defined as a boot feature");
// add the feature in the system folder
Set<BundleInfo> bundleInfos = new HashSet<>();
for (Bundle bundle : feature.getBundle()) {
if (!ignoreDependencyFlag || !bundle.isDependency()) {
bundleInfos.add(bundle);
}
}
for (Conditional cond : feature.getConditional()) {
if (cond.isBlacklisted()) {
LOGGER.info(" Conditionial " + cond.getConditionId() + " is blacklisted, ignoring");
}
for (Bundle bundle : cond.getBundle()) {
if (!ignoreDependencyFlag || !bundle.isDependency()) {
bundleInfos.add(bundle);
}
}
}
// 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:", Collections.singletonList("wrap"));
prereqs.put("war:", Collections.singletonList("war"));
ArtifactInstaller installer = new ArtifactInstaller(systemDirectory, downloader, blacklist);
for (BundleInfo bundleInfo : bundleInfos) {
installer.installArtifact(bundleInfo);
for (Map.Entry<String, List<String>> entry : prereqs.entrySet()) {
if (bundleInfo.getLocation().trim().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);
}
}
}
}
new ConfigInstaller(etcDirectory, pidsToExtract).installConfigs(feature, downloader, installer);
// Install libraries
List<String> libraries = new ArrayList<>();
for (Library library : feature.getLibraries()) {
String lib = library.getLocation() + ";type:=" + library.getType() + ";export:=" + library.isExport() + ";delegate:=" + library.isDelegate();
libraries.add(lib);
}
Path configPropertiesPath = etcDirectory.resolve("config.properties");
Properties configProperties = new Properties(configPropertiesPath.toFile());
downloadLibraries(downloader, configProperties, libraries, " ");
downloader.await();
// Reformat clauses
reformatClauses(configProperties, Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
reformatClauses(configProperties, Constants.FRAMEWORK_BOOTDELEGATION);
configProperties.save();
}
// If there are bundles to install, we can't use the boot features only
// so keep the generated feature
Path featuresCfgFile = etcDirectory.resolve("org.apache.karaf.features.cfg");
if (!generated.getBundle().isEmpty()) {
File output = etcDirectory.resolve(rep.getName() + ".xml").toFile();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JaxbUtil.marshal(rep, baos);
ByteArrayInputStream bais;
String repoUrl;
if (karafVersion == KarafVersion.v24) {
String str = baos.toString();
str = str.replace("http://karaf.apache.org/xmlns/features/v1.3.0", "http://karaf.apache.org/xmlns/features/v1.2.0");
str = str.replaceAll(" dependency=\".*?\"", "");
str = str.replaceAll(" prerequisite=\".*?\"", "");
for (Feature f : rep.getFeature()) {
for (Dependency d : f.getFeature()) {
if (d.isPrerequisite()) {
if (!startupEffective.getFeatures().contains(d.getName())) {
LOGGER.warn("Feature " + d.getName() + " is a prerequisite and should be installed as a startup feature.");
}
}
}
}
bais = new ByteArrayInputStream(str.getBytes());
repoUrl = "file:etc/" + output.getName();
} else {
bais = new ByteArrayInputStream(baos.toByteArray());
repoUrl = "file:${karaf.home}/etc/" + output.getName();
}
Files.copy(bais, output.toPath());
Properties featuresProperties = new Properties(featuresCfgFile.toFile());
featuresProperties.put(FEATURES_REPOSITORIES, repoUrl);
featuresProperties.put(FEATURES_BOOT, generated.getName());
featuresProperties.save();
} else {
String repos = getRepos(rep);
String boot = getBootFeatures(generatedDep);
Properties featuresProperties = new Properties(featuresCfgFile.toFile());
featuresProperties.put(FEATURES_REPOSITORIES, repos);
featuresProperties.put(FEATURES_BOOT, boot);
reformatClauses(featuresProperties, FEATURES_REPOSITORIES);
reformatClauses(featuresProperties, FEATURES_BOOT);
featuresProperties.save();
}
downloader.await();
return allBootFeatures;
}
use of org.apache.karaf.features.internal.model.Features in project karaf by apache.
the class Builder method startupStage.
private Profile startupStage(Profile startupProfile, FeaturesProcessor processor) throws Exception {
LOGGER.info("Startup stage");
//
// Compute startup
//
Profile startupOverlay = Profiles.getOverlay(startupProfile, allProfiles, environment);
Profile startupEffective = Profiles.getEffective(startupOverlay, false);
// Load startup repositories
LOGGER.info(" Loading startup repositories");
Map<String, Features> startupRepositories = loadRepositories(manager, startupEffective.getRepositories(), false, processor);
//
// Resolve
//
LOGGER.info(" Resolving startup features and bundles");
LOGGER.info(" Features: " + startupEffective.getFeatures().stream().collect(Collectors.joining(", ")));
LOGGER.info(" Bundles: " + startupEffective.getBundles().stream().collect(Collectors.joining(", ")));
Map<String, Integer> bundles = resolve(manager, resolver, startupRepositories.values(), startupEffective.getFeatures(), startupEffective.getBundles(), startupEffective.getOptionals(), processor);
//
// Generate startup.properties
//
Properties startup = new Properties();
startup.setHeader(Collections.singletonList("# Bundles to be started on startup, with startlevel"));
Map<Integer, Set<String>> invertedStartupBundles = MapUtils.invert(bundles);
for (Map.Entry<Integer, Set<String>> entry : new TreeMap<>(invertedStartupBundles).entrySet()) {
String startLevel = Integer.toString(entry.getKey());
for (String location : new TreeSet<>(entry.getValue())) {
if (useReferenceUrls) {
if (location.startsWith("mvn:")) {
location = "file:" + Parser.pathFromMaven(location);
}
if (location.startsWith("file:")) {
location = "reference:" + location;
}
}
if (location.startsWith("file:") && karafVersion == KarafVersion.v24) {
location = location.substring("file:".length());
}
startup.put(location, startLevel);
}
}
Path startupProperties = etcDirectory.resolve("startup.properties");
startup.save(startupProperties.toFile());
return startupEffective;
}
use of org.apache.karaf.features.internal.model.Features in project karaf by apache.
the class Builder method generateConsistencyReport.
/**
* Produces human readable XML with <em>feature consistency report</em>.
* @param repositories
* @param result
*/
public void generateConsistencyReport(Map<String, Features> repositories, File result, boolean full) {
Map<String, String> featureId2repository = new HashMap<>();
// list of feature IDs containing given bundle URIs
Map<String, Set<String>> bundle2featureId = new TreeMap<>(new URIAwareComparator());
// map of groupId/artifactId to full URI list to detect "duplicates"
Map<String, List<String>> ga2uri = new TreeMap<>();
Set<String> haveDuplicates = new HashSet<>();
// collect closure of bundles and features
repositories.forEach((name, features) -> {
if (full || !features.isBlacklisted()) {
features.getFeature().forEach(feature -> {
if (full || !feature.isBlacklisted()) {
featureId2repository.put(feature.getId(), name);
feature.getBundle().forEach(bundle -> {
// normal bundles of feature
bundle2featureId.computeIfAbsent(bundle.getLocation().trim(), k -> new TreeSet<>()).add(feature.getId());
});
feature.getConditional().forEach(cond -> {
cond.asFeature().getBundles().forEach(bundle -> {
// conditional bundles of feature
bundle2featureId.computeIfAbsent(bundle.getLocation().trim(), k -> new TreeSet<>()).add(feature.getId());
});
});
}
});
}
});
// collect bundle URIs - for now, only wrap:mvn: and mvn: are interesting
bundle2featureId.keySet().forEach(uri -> {
String originalUri = uri;
if (uri.startsWith("wrap:mvn:")) {
uri = uri.substring(5);
if (uri.indexOf(";") > 0) {
uri = uri.substring(0, uri.indexOf(";"));
}
if (uri.indexOf("$") > 0) {
uri = uri.substring(0, uri.indexOf("$"));
}
}
if (uri.startsWith("mvn:")) {
try {
LocationPattern pattern = new LocationPattern(uri);
String ga = String.format("%s/%s", pattern.getGroupId(), pattern.getArtifactId());
ga2uri.computeIfAbsent(ga, k -> new LinkedList<>()).add(originalUri);
} catch (IllegalArgumentException ignored) {
/*
<!-- hibernate-validator-osgi-karaf-features-5.3.4.Final-features.xml -->
<feature name="hibernate-validator-paranamer" version="5.3.4.Final">
<feature>hibernate-validator</feature>
<bundle>wrap:mvn:com.thoughtworks.paranamer:paranamer:2.8</bundle>
</feature>
*/
}
}
});
ga2uri.values().forEach(l -> {
if (l.size() > 1) {
haveDuplicates.addAll(l);
}
});
if (result == null) {
return;
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(result))) {
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
writer.write("<?xml-stylesheet type=\"text/xsl\" href=\"bundle-report.xslt\"?>\n");
writer.write("<consistency-report xmlns=\"urn:apache:karaf:consistency:1.0\">\n");
writer.write(" <duplicates>\n");
ga2uri.forEach((key, uris) -> {
if (uris.size() > 1) {
try {
writer.write(String.format(" <duplicate ga=\"%s\">\n", key));
for (String uri : uris) {
writer.write(String.format(" <bundle uri=\"%s\">\n", sanitize(uri)));
for (String fid : bundle2featureId.get(uri)) {
writer.write(String.format(" <feature repository=\"%s\">%s</feature>\n", featureId2repository.get(fid), fid));
}
writer.write(" </bundle>\n");
}
writer.write(" </duplicate>\n");
} catch (IOException e) {
}
}
});
writer.write(" </duplicates>\n");
writer.write(" <bundles>\n");
for (String uri : bundle2featureId.keySet()) {
writer.write(String.format(" <bundle uri=\"%s\" duplicate=\"%b\">\n", sanitize(uri), haveDuplicates.contains(uri)));
for (String fid : bundle2featureId.get(uri)) {
writer.write(String.format(" <feature>%s</feature>\n", fid));
}
writer.write(" </bundle>\n");
}
writer.write(" </bundles>\n");
writer.write("</consistency-report>\n");
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
use of org.apache.karaf.features.internal.model.Features in project karaf by apache.
the class FeatureSelector method getMatchingFeatures.
/**
* Assuming <code>idOrPattern</code> may be a pattern (with glob and version range), get all matching features
* @param idOrPattern
* @param repositories
* @return
*/
public static Collection<String> getMatchingFeatures(String idOrPattern, Collection<Features> repositories) {
List<String> result = new LinkedList<>();
FeaturePattern pattern = new FeaturePattern(idOrPattern);
for (Features features : repositories) {
for (Feature feature : features.getFeature()) {
// blacklisting will be applied anyway, so no need to do it here
if (/*!feature.isBlacklisted() && */
pattern.matches(feature.getName(), feature.getVersion())) {
result.add(feature.getId());
}
}
}
return result;
}
use of org.apache.karaf.features.internal.model.Features in project karaf by apache.
the class GenerateDescriptorMojo method writeFeatures.
/*
* Write all project dependencies as feature
*/
private void writeFeatures(PrintStream out) throws ArtifactResolutionException, ArtifactNotFoundException, IOException, JAXBException, SAXException, ParserConfigurationException, XMLStreamException, MojoExecutionException {
getLog().info("Generating feature descriptor file " + outputFile.getAbsolutePath());
// read in an existing feature.xml
ObjectFactory objectFactory = new ObjectFactory();
Features features;
if (inputFile.exists()) {
filter(inputFile, filteredInputFile);
features = readFeaturesFile(filteredInputFile);
} else {
features = objectFactory.createFeaturesRoot();
}
if (features.getName() == null) {
features.setName(project.getArtifactId());
}
Feature feature = null;
for (Feature test : features.getFeature()) {
if (test.getName().equals(primaryFeatureName)) {
feature = test;
}
}
if (feature == null) {
feature = objectFactory.createFeature();
feature.setName(primaryFeatureName);
}
if (!feature.hasVersion()) {
feature.setVersion(project.getArtifact().getBaseVersion());
}
if (feature.getDescription() == null) {
feature.setDescription(project.getName());
}
if (installMode != null) {
feature.setInstall(installMode);
}
if (project.getDescription() != null && feature.getDetails() == null) {
feature.setDetails(project.getDescription());
}
if (includeProjectArtifact) {
Bundle bundle = objectFactory.createBundle();
bundle.setLocation(this.dependencyHelper.artifactToMvn(project.getArtifact(), project.getVersion()));
if (startLevel != null) {
bundle.setStartLevel(startLevel);
}
feature.getBundle().add(bundle);
}
boolean needWrap = false;
// First pass to look for features
// Track other features we depend on and their repositories (we track repositories instead of building them from
// the feature's Maven artifact to allow for multi-feature repositories)
// TODO Initialise the repositories from the existing feature file if any
Map<Dependency, Feature> otherFeatures = new HashMap<>();
Map<Feature, String> featureRepositories = new HashMap<>();
FeaturesCache cache = new FeaturesCache(featuresCacheSize, artifactCacheSize);
for (final LocalDependency entry : localDependencies) {
Object artifact = entry.getArtifact();
if (excludedArtifactIds.contains(this.dependencyHelper.getArtifactId(artifact))) {
continue;
}
processFeatureArtifact(features, feature, otherFeatures, featureRepositories, cache, artifact, entry.getParent(), true);
}
// Do not retain cache beyond this point
cache = null;
// Second pass to look for bundles
if (addBundlesToPrimaryFeature) {
localDependency: for (final LocalDependency entry : localDependencies) {
Object artifact = entry.getArtifact();
if (excludedArtifactIds.contains(this.dependencyHelper.getArtifactId(artifact))) {
continue;
}
if (!this.dependencyHelper.isArtifactAFeature(artifact)) {
String bundleName = this.dependencyHelper.artifactToMvn(artifact, getVersionOrRange(entry.getParent(), artifact));
for (ConfigFile cf : feature.getConfigfile()) {
if (bundleName.equals(cf.getLocation().replace('\n', ' ').trim())) {
// The bundle matches a configfile, ignore it
continue localDependency;
}
}
File bundleFile = this.dependencyHelper.resolve(artifact, getLog());
Manifest manifest = getManifest(bundleFile);
if (manifest == null || !ManifestUtils.isBundle(manifest)) {
bundleName = "wrap:" + bundleName;
needWrap = true;
}
Bundle bundle = null;
for (Bundle b : feature.getBundle()) {
if (bundleName.equals(b.getLocation())) {
bundle = b;
break;
}
}
if (bundle == null) {
bundle = objectFactory.createBundle();
bundle.setLocation(bundleName);
// Check the features this feature depends on don't already contain the dependency
// TODO Perhaps only for transitive dependencies?
boolean includedTransitively = simplifyBundleDependencies && isBundleIncludedTransitively(feature, otherFeatures, bundle);
if (!includedTransitively && (!"provided".equals(entry.getScope()) || !ignoreScopeProvided)) {
feature.getBundle().add(bundle);
}
}
if ("runtime".equals(entry.getScope())) {
bundle.setDependency(true);
}
if (startLevel != null && bundle.getStartLevel() == 0) {
bundle.setStartLevel(startLevel);
}
}
}
}
if (needWrap) {
Dependency wrapDependency = new Dependency();
wrapDependency.setName("wrap");
wrapDependency.setDependency(false);
wrapDependency.setPrerequisite(true);
feature.getFeature().add(wrapDependency);
}
if ((!feature.getBundle().isEmpty() || !feature.getFeature().isEmpty()) && !features.getFeature().contains(feature)) {
features.getFeature().add(feature);
}
// Add any missing repositories for the included features
for (Feature includedFeature : features.getFeature()) {
for (Dependency dependency : includedFeature.getFeature()) {
Feature dependedFeature = otherFeatures.get(dependency);
if (dependedFeature != null && !features.getFeature().contains(dependedFeature)) {
String repository = featureRepositories.get(dependedFeature);
if (repository != null && !features.getRepository().contains(repository)) {
features.getRepository().add(repository);
}
}
}
}
JaxbUtil.marshal(features, out);
try {
checkChanges(features, objectFactory);
} catch (Exception e) {
throw new MojoExecutionException("Features contents have changed", e);
}
getLog().info("...done!");
}
Aggregations