Author: pauls
Date: Mon Jul 31 17:22:58 2017
New Revision: 1803557
URL: http://svn.apache.org/viewvc?rev=1803557&view=rev
Log:
Move parsing into feature-support, add Requirement/Capability matching and
parsing to feature-support, and create basic check task for Req/Cap in analyser
(still needs testing).
Added:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckRequirementsCapabilities.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/
- copied from r1803556,
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/LambdaUtil.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/ManifestParser.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/ManifestUtil.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/PackageInfo.java
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/json/
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONReaderTest.java
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/json/FeatureJSONWriterTest.java
sling/whiteboard/cziegeler/feature-support/src/test/java/org/apache/sling/feature/support/json/U.java
sling/whiteboard/cziegeler/feature-support/src/test/resources/
sling/whiteboard/cziegeler/feature-support/src/test/resources/features/
sling/whiteboard/cziegeler/feature-support/src/test/resources/features/test.json
Removed:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/PackageInfo.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/ManifestUtil.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/
sling/whiteboard/cziegeler/feature/src/test/java/org/apache/sling/feature/json/
sling/whiteboard/cziegeler/feature/src/test/resources/features/
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/BundleDescriptor.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Descriptor.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/BundleDescriptorImpl.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckBundleExportsImports.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/ContainerDescriptorImpl.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTask.java
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
sling/whiteboard/cziegeler/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
sling/whiteboard/cziegeler/feature-support/pom.xml
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ConfigurationUtil.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONReader.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONWriter.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONReader.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONWriter.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONConstants.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONReaderBase.java
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
sling/whiteboard/cziegeler/feature/pom.xml
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Capability.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Requirement.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
sling/whiteboard/cziegeler/osgifeature-maven-plugin/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/BundleDescriptor.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/BundleDescriptor.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/BundleDescriptor.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/BundleDescriptor.java
Mon Jul 31 17:22:58 2017
@@ -16,6 +16,8 @@
*/
package org.apache.sling.feature.analyser;
+import org.apache.sling.feature.support.util.PackageInfo;
+
/**
* Information about a bundle
*/
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Descriptor.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Descriptor.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Descriptor.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/Descriptor.java
Mon Jul 31 17:22:58 2017
@@ -21,6 +21,7 @@ import java.util.Set;
import org.apache.sling.feature.Capability;
import org.apache.sling.feature.Requirement;
+import org.apache.sling.feature.support.util.PackageInfo;
/**
* A descriptor holds information about requirements and capabilities
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/BundleDescriptorImpl.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/BundleDescriptorImpl.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/BundleDescriptorImpl.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/BundleDescriptorImpl.java
Mon Jul 31 17:22:58 2017
@@ -24,8 +24,12 @@ import java.util.Set;
import java.util.jar.Manifest;
import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.Capability;
+import org.apache.sling.feature.Requirement;
import org.apache.sling.feature.analyser.BundleDescriptor;
-import org.apache.sling.feature.analyser.PackageInfo;
+import org.apache.sling.feature.support.util.PackageInfo;
+import org.apache.sling.feature.support.util.ManifestParser;
+import org.apache.sling.feature.support.util.ManifestUtil;
import org.osgi.framework.Constants;
/**
@@ -61,6 +65,10 @@ public class BundleDescriptorImpl
/** The corresponding artifact from the feature. */
private final Artifact artifact;
+ private final Set<Capability> capabilities = new HashSet<>();
+
+ private final Set<Requirement> requirements = new HashSet<>();
+
public BundleDescriptorImpl(final Artifact a,
final File file,
final int startLevel) throws IOException {
@@ -169,6 +177,16 @@ public class BundleDescriptorImpl
return Collections.unmodifiableSet(this.dynamicImportedPackages);
}
+ @Override
+ public Set<Capability> getCapabilities() {
+ return Collections.unmodifiableSet(capabilities);
+ }
+
+ @Override
+ public Set<Requirement> getRequirements() {
+ return Collections.unmodifiableSet(requirements);
+ }
+
protected void analyze() throws IOException {
final String name =
this.manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
if ( name != null ) {
@@ -186,7 +204,13 @@ public class BundleDescriptorImpl
this.exportedPackages.addAll(ManifestUtil.extractExportedPackages(this.manifest));
this.importedPackages.addAll(ManifestUtil.extractImportedPackages(this.manifest));
this.dynamicImportedPackages.addAll(ManifestUtil.extractDynamicImportedPackages(this.manifest));
-
+ try {
+ ManifestParser parser = new ManifestParser(this.manifest);
+
this.capabilities.addAll(ManifestUtil.extractCapabilities(parser));
+
this.requirements.addAll(ManifestUtil.extractRequirements(parser));
+ } catch (Exception ex) {
+ throw new IOException(ex);
+ }
} else {
throw new IOException("Unable to get bundle symbolic name from
artifact " + getArtifact().getId().toMvnId());
}
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckBundleExportsImports.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckBundleExportsImports.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckBundleExportsImports.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckBundleExportsImports.java
Mon Jul 31 17:22:58 2017
@@ -28,7 +28,7 @@ import java.util.TreeMap;
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.analyser.BundleDescriptor;
-import org.apache.sling.feature.analyser.PackageInfo;
+import org.apache.sling.feature.support.util.PackageInfo;
import org.apache.sling.feature.analyser.task.AnalyserTask;
import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
import org.osgi.framework.Version;
Added:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckRequirementsCapabilities.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckRequirementsCapabilities.java?rev=1803557&view=auto
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckRequirementsCapabilities.java
(added)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/CheckRequirementsCapabilities.java
Mon Jul 31 17:22:58 2017
@@ -0,0 +1,108 @@
+/*
+ * 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.analyser.impl;
+
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.Capability;
+import org.apache.sling.feature.Requirement;
+import org.apache.sling.feature.analyser.ArtifactDescriptor;
+import org.apache.sling.feature.analyser.BundleDescriptor;
+import org.apache.sling.feature.analyser.task.AnalyserTask;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.support.impl.CapabilityMatcher;
+import org.osgi.framework.Constants;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class CheckRequirementsCapabilities implements AnalyserTask {
+ private final String format = "Artifact %s:%s requires %s in start level
%d but %s";
+
+ @Override
+ public void execute(AnalyserTaskContext ctx) throws Exception {
+ final SortedMap<Integer, List<ArtifactDescriptor>> artifactsMap = new
TreeMap<>();
+ for(final BundleDescriptor bi :
ctx.getDescriptor().getBundleDescriptors()) {
+ List<ArtifactDescriptor> list =
artifactsMap.get(bi.getBundleStartLevel());
+ if ( list == null ) {
+ list = new ArrayList<>();
+ artifactsMap.put(bi.getBundleStartLevel(), list);
+ }
+ list.add(bi);
+ }
+
+ if (!ctx.getDescriptor().getArtifactDescriptors().isEmpty()) {
+ artifactsMap.put(
+ (artifactsMap.isEmpty() ? 0 : artifactsMap.lastKey()) + 1,
+ new
ArrayList<>(ctx.getDescriptor().getArtifactDescriptors())
+ );
+ }
+
+ // create a synthetic bundle info for the system bundle
+ final ArtifactDescriptor system = new BundleDescriptorImpl(new
Artifact(ctx.getApplication().getFramework()),
ctx.getDescriptor().getFrameworkDescriptor().getExportedPackages()) {
+ @Override
+ public Set<Requirement> getRequirements() {
+ return
ctx.getDescriptor().getFrameworkDescriptor().getRequirements();
+ }
+
+ @Override
+ public Set<Capability> getCapabilities() {
+ return
ctx.getDescriptor().getFrameworkDescriptor().getCapabilities();
+ }
+ };
+
+ // add system artifact
+ final List<ArtifactDescriptor> artifacts = new ArrayList<>();
+ artifacts.add(system);
+
+ for(final Map.Entry<Integer, List<ArtifactDescriptor>> entry :
artifactsMap.entrySet()) {
+ // first add all providing artifacts
+ for (final ArtifactDescriptor info : entry.getValue()) {
+ if (info.getCapabilities() != null) {
+ artifacts.add(info);
+ }
+ }
+ // check requiring artifacts
+ for (final ArtifactDescriptor info : entry.getValue()) {
+ if (info.getRequirements() != null)
+ {
+ for (Requirement requirement : info.getRequirements()) {
+ List<ArtifactDescriptor> candidates =
getCandidates(artifacts, requirement);
+
+ if (candidates.isEmpty()) {
+ if (!CapabilityMatcher.isOptional(requirement)) {
+ ctx.reportError(String.format(format,
info.toString(), entry.getKey(), "no artifact is providing a matching
capability in this start level."));
+ }
+ else {
+ ctx.reportWarning(String.format(format,
info.toString(), entry.getKey(), "while the requirement is optional no artifact
is providing a matching capability in this start level."));
+ }
+ }
+ else if ( candidates.size() > 1 ) {
+ ctx.reportWarning(String.format(format,
info.toString(), entry.getKey(), "there is more than one matching capability in
this start level."));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private List<ArtifactDescriptor> getCandidates(List<ArtifactDescriptor>
artifactDescriptors, Requirement requirement) {
+ return artifactDescriptors.stream()
+ .filter(artifactDescriptor ->
artifactDescriptor.getCapabilities() != null)
+ .filter(artifactDescriptor ->
artifactDescriptor.getCapabilities().stream().anyMatch(capability ->
CapabilityMatcher.matches(capability, requirement)))
+ .collect(Collectors.toList());
+ }
+}
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/ContainerDescriptorImpl.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/ContainerDescriptorImpl.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/ContainerDescriptorImpl.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/impl/ContainerDescriptorImpl.java
Mon Jul 31 17:22:58 2017
@@ -24,7 +24,7 @@ import org.apache.sling.feature.Requirem
import org.apache.sling.feature.analyser.ArtifactDescriptor;
import org.apache.sling.feature.analyser.BundleDescriptor;
import org.apache.sling.feature.analyser.ContainerDescriptor;
-import org.apache.sling.feature.analyser.PackageInfo;
+import org.apache.sling.feature.support.util.PackageInfo;
/**
* Information about a container (feature/application).
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/main/Main.java
Mon Jul 31 17:22:58 2017
@@ -23,7 +23,7 @@ import java.io.IOException;
import org.apache.sling.feature.Application;
import org.apache.sling.feature.analyser.Analyser;
import org.apache.sling.feature.analyser.Scanner;
-import org.apache.sling.feature.json.ApplicationJSONReader;
+import org.apache.sling.feature.support.json.ApplicationJSONReader;
import org.apache.sling.feature.support.ArtifactManagerConfig;
import org.apache.sling.feature.support.FeatureUtil;
import org.slf4j.Logger;
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTask.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTask.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTask.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/analyser/task/AnalyserTask.java
Mon Jul 31 17:22:58 2017
@@ -23,10 +23,14 @@ package org.apache.sling.feature.analyse
public interface AnalyserTask {
/** A unique (short) id. */
- String getId();
+ default String getId() {
+ return getClass().getName();
+ };
/** A human readable name to identify the task. */
- String getName();
+ default String getName() {
+ return getClass().getSimpleName();
+ };
/** Execute the task. */
void execute(AnalyserTaskContext ctx) throws Exception;
Modified:
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
(original)
+++
sling/whiteboard/cziegeler/feature-analyser/src/main/java/org/apache/sling/feature/scanner/impl/FelixFrameworkScanner.java
Mon Jul 31 17:22:58 2017
@@ -31,7 +31,7 @@ import org.apache.sling.commons.osgi.Man
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.KeyValueMap;
import org.apache.sling.feature.analyser.Descriptor;
-import org.apache.sling.feature.analyser.PackageInfo;
+import org.apache.sling.feature.support.util.PackageInfo;
import org.apache.sling.feature.scanner.FrameworkScanner;
import org.osgi.framework.Constants;
Modified:
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
(original)
+++
sling/whiteboard/cziegeler/feature-launcher/src/main/java/org/apache/sling/feature/launcher/impl/FeatureProcessor.java
Mon Jul 31 17:22:58 2017
@@ -28,8 +28,8 @@ import org.apache.sling.feature.Artifact
import org.apache.sling.feature.Configuration;
import org.apache.sling.feature.Extension;
import org.apache.sling.feature.ExtensionType;
-import org.apache.sling.feature.json.ApplicationJSONReader;
-import org.apache.sling.feature.json.ApplicationJSONWriter;
+import org.apache.sling.feature.support.json.ApplicationJSONReader;
+import org.apache.sling.feature.support.json.ApplicationJSONWriter;
import org.apache.sling.feature.launcher.impl.LauncherConfig.StartupMode;
import org.apache.sling.feature.support.ArtifactHandler;
import org.apache.sling.feature.support.ArtifactManager;
Modified:
sling/whiteboard/cziegeler/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
(original)
+++
sling/whiteboard/cziegeler/feature-modelconverter/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
Mon Jul 31 17:22:58 2017
@@ -43,8 +43,8 @@ import org.apache.sling.feature.Extensio
import org.apache.sling.feature.ExtensionType;
import org.apache.sling.feature.Extensions;
import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.json.ApplicationJSONWriter;
-import org.apache.sling.feature.json.FeatureJSONWriter;
+import org.apache.sling.feature.support.json.ApplicationJSONWriter;
+import org.apache.sling.feature.support.json.FeatureJSONWriter;
import org.apache.sling.feature.support.ArtifactHandler;
import org.apache.sling.feature.support.ArtifactManager;
import org.apache.sling.feature.support.ArtifactManagerConfig;
Modified: sling/whiteboard/cziegeler/feature-support/pom.xml
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/pom.xml?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
--- sling/whiteboard/cziegeler/feature-support/pom.xml (original)
+++ sling/whiteboard/cziegeler/feature-support/pom.xml Mon Jul 31 17:22:58 2017
@@ -65,6 +65,32 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.osgi</artifactId>
+ <version>2.4.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.converter</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configurator</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-json_1.0_spec</artifactId>
+ <version>1.0-alpha-1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Testing -->
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
@@ -74,5 +100,11 @@
<version>2.8.9</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.johnzon</groupId>
+ <artifactId>johnzon-core</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ConfigurationUtil.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ConfigurationUtil.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ConfigurationUtil.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/ConfigurationUtil.java
Mon Jul 31 17:22:58 2017
@@ -26,7 +26,7 @@ import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.apache.sling.feature.Configurations;
-import org.apache.sling.feature.json.ConfigurationJSONWriter;
+import org.apache.sling.feature.support.json.ConfigurationJSONWriter;
import org.osgi.framework.Constants;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/FeatureUtil.java
Mon Jul 31 17:22:58 2017
@@ -28,7 +28,7 @@ import java.util.List;
import org.apache.sling.feature.Application;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Feature;
-import org.apache.sling.feature.json.FeatureJSONReader;
+import org.apache.sling.feature.support.json.FeatureJSONReader;
import org.apache.sling.feature.process.ApplicationBuilder;
import org.apache.sling.feature.process.FeatureProvider;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONReader.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONReader.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONReader.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONReader.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Reader;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONWriter.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONWriter.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONWriter.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ApplicationJSONWriter.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
under
* the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Writer;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONReader.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONReader.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONReader.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONReader.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Reader;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONWriter.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONWriter.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONWriter.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/ConfigurationJSONWriter.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
under
* the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Writer;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONReader.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Reader;
@@ -32,6 +32,7 @@ import org.apache.sling.feature.Capabili
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.Include;
import org.apache.sling.feature.Requirement;
+import org.apache.sling.feature.support.util.ManifestUtil;
/**
* This class offers a method to read a {@code Feature} using a {@code Reader}
instance.
@@ -283,18 +284,14 @@ public class FeatureJSONReader extends J
checkType("Requirement attributes",
obj.get(JSONConstants.REQCAP_ATTRIBUTES), Map.class);
@SuppressWarnings("unchecked")
final Map<String, Object> attrs = (Map<String,
Object>)obj.get(JSONConstants.REQCAP_ATTRIBUTES);
- for(final Map.Entry<String, Object> entry :
attrs.entrySet()) {
- r.getAttributes().put(entry.getKey(),
entry.getValue().toString());
- }
+ attrs.forEach((key, value) ->
ManifestUtil.unmarshallAttribute(key, value, r.getAttributes()::put));
}
if ( obj.containsKey(JSONConstants.REQCAP_DIRECTIVES) ) {
checkType("Requirement directives",
obj.get(JSONConstants.REQCAP_DIRECTIVES), Map.class);
@SuppressWarnings("unchecked")
final Map<String, Object> dirs = (Map<String,
Object>)obj.get(JSONConstants.REQCAP_DIRECTIVES);
- for(final Map.Entry<String, Object> entry :
dirs.entrySet()) {
- r.getDirectives().put(entry.getKey(),
entry.getValue().toString());
- }
+ dirs.forEach((key, value) ->
ManifestUtil.unmarshallDirective(key, value, r.getDirectives()::put));
}
}
}
@@ -324,18 +321,14 @@ public class FeatureJSONReader extends J
checkType("Capability attributes",
obj.get(JSONConstants.REQCAP_ATTRIBUTES), Map.class);
@SuppressWarnings("unchecked")
final Map<String, Object> attrs = (Map<String,
Object>)obj.get(JSONConstants.REQCAP_ATTRIBUTES);
- for(final Map.Entry<String, Object> entry :
attrs.entrySet()) {
- c.getAttributes().put(entry.getKey(),
entry.getValue().toString());
- }
+ attrs.forEach((key, value) ->
ManifestUtil.unmarshallAttribute(key, value, c.getAttributes()::put));
}
if ( obj.containsKey(JSONConstants.REQCAP_DIRECTIVES) ) {
checkType("Capability directives",
obj.get(JSONConstants.REQCAP_DIRECTIVES), Map.class);
@SuppressWarnings("unchecked")
- final Map<String, Object> dirs = (Map<String,
Object>)obj.get(JSONConstants.REQCAP_DIRECTIVES);
- for(final Map.Entry<String, Object> entry :
dirs.entrySet()) {
- c.getDirectives().put(entry.getKey(),
entry.getValue().toString());
- }
+ final Map<String, Object> dirs = (Map<String, Object>)
obj.get(JSONConstants.REQCAP_DIRECTIVES);
+ dirs.forEach((key, value) ->
ManifestUtil.unmarshallDirective(key, value, c.getDirectives()::put));
}
}
}
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/FeatureJSONWriter.java
Mon Jul 31 17:22:58 2017
@@ -14,12 +14,13 @@
* License for the specific language governing permissions and limitations
under
* the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import java.util.Map;
+import java.util.function.BiFunction;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
@@ -31,6 +32,7 @@ import org.apache.sling.feature.Configur
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.Include;
import org.apache.sling.feature.Requirement;
+import org.apache.sling.feature.support.util.ManifestUtil;
/**
@@ -152,16 +154,12 @@ public class FeatureJSONWriter extends J
w.write(JSONConstants.REQCAP_NAMESPACE, req.getNamespace());
if ( !req.getAttributes().isEmpty() ) {
w.writeStartObject(JSONConstants.REQCAP_ATTRIBUTES);
- for(final Map.Entry<String, String> entry :
req.getAttributes()) {
- w.write(entry.getKey(), entry.getValue());
- }
+ req.getAttributes().forEach((key, value) ->
ManifestUtil.marshallAttribute(key, value, w::write));
w.writeEnd();
}
if ( !req.getDirectives().isEmpty() ) {
w.writeStartObject(JSONConstants.REQCAP_DIRECTIVES);
- for(final Map.Entry<String, String> entry :
req.getDirectives()) {
- w.write(entry.getKey(), entry.getValue());
- }
+ req.getDirectives().forEach((key, value) ->
ManifestUtil.marshallDirective(key, value, w::write));
w.writeEnd();
}
w.writeEnd();
@@ -178,16 +176,12 @@ public class FeatureJSONWriter extends J
w.write(JSONConstants.REQCAP_NAMESPACE, cap.getNamespace());
if ( !cap.getAttributes().isEmpty() ) {
w.writeStartObject(JSONConstants.REQCAP_ATTRIBUTES);
- for(final Map.Entry<String, String> entry :
cap.getAttributes()) {
- w.write(entry.getKey(), entry.getValue());
- }
+ cap.getAttributes().forEach((key, value) ->
ManifestUtil.marshallAttribute(key, value, w::write));
w.writeEnd();
}
if ( !cap.getDirectives().isEmpty() ) {
w.writeStartObject(JSONConstants.REQCAP_DIRECTIVES);
- for(final Map.Entry<String, String> entry :
cap.getDirectives()) {
- w.write(entry.getKey(), entry.getValue());
- }
+ cap.getDirectives().forEach((key, value) ->
ManifestUtil.marshallDirective(key, value, w::write));
w.writeEnd();
}
w.writeEnd();
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONConstants.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONConstants.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONConstants.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONConstants.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.util.Arrays;
import java.util.List;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONReaderBase.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONReaderBase.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONReaderBase.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONReaderBase.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.IOException;
import java.io.Reader;
Modified:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java?rev=1803557&r1=1803556&r2=1803557&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
(original)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/json/JSONWriterBase.java
Mon Jul 31 17:22:58 2017
@@ -14,7 +14,7 @@
* License for the specific language governing permissions and limitations
under
* the License.
*/
-package org.apache.sling.feature.json;
+package org.apache.sling.feature.support.json;
import java.io.StringReader;
import java.lang.reflect.Array;
Added:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/LambdaUtil.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/LambdaUtil.java?rev=1803557&view=auto
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/LambdaUtil.java
(added)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/LambdaUtil.java
Mon Jul 31 17:22:58 2017
@@ -0,0 +1,99 @@
+/*
+ * 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.support.util;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+
+public final class LambdaUtil {
+
+ @FunctionalInterface
+ public interface Consumer_WithExceptions<T, E extends Exception> {
+ void accept(T t) throws E;
+ }
+
+ @FunctionalInterface
+ public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
+ void accept(T t, U u) throws E;
+ }
+
+ @FunctionalInterface
+ public interface Function_WithExceptions<T, R, E extends Exception> {
+ R apply(T t) throws E;
+ }
+
+ @FunctionalInterface
+ public interface Supplier_WithExceptions<T, E extends Exception> {
+ T get() throws E;
+ }
+
+ @FunctionalInterface
+ public interface Runnable_WithExceptions<E extends Exception> {
+ void run() throws E;
+ }
+
+ public static <T, E extends Exception> Consumer<T>
rethrowConsumer(Consumer_WithExceptions<T, E> consumer) {
+ return t -> {
+ try { consumer.accept(t); }
+ catch (Exception exception) { throwAsUnchecked(exception); }
+ };
+ }
+
+ public static <T, U, E extends Exception> BiConsumer<T, U>
rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) {
+ return (t, u) -> {
+ try { biConsumer.accept(t, u); }
+ catch (Exception exception) { throwAsUnchecked(exception); }
+ };
+ }
+
+ public static <T, R, E extends Exception> Function<T, R>
rethrowFunction(Function_WithExceptions<T, R, E> function) {
+ return t -> {
+ try { return function.apply(t); }
+ catch (Exception exception) { throwAsUnchecked(exception); return
null; }
+ };
+ }
+
+ public static <T, E extends Exception> Supplier<T>
rethrowSupplier(Supplier_WithExceptions<T, E> function) {
+ return () -> {
+ try { return function.get(); }
+ catch (Exception exception) { throwAsUnchecked(exception); return
null; }
+ };
+ }
+
+ public static void uncheck(Runnable_WithExceptions t)
+ {
+ try { t.run(); }
+ catch (Exception exception) { throwAsUnchecked(exception); }
+ }
+
+ public static <R, E extends Exception> R
uncheck(Supplier_WithExceptions<R, E> supplier)
+ {
+ try { return supplier.get(); }
+ catch (Exception exception) { throwAsUnchecked(exception); return
null; }
+ }
+
+ public static <T, R, E extends Exception> R
uncheck(Function_WithExceptions<T, R, E> function, T t) {
+ try { return function.apply(t); }
+ catch (Exception exception) { throwAsUnchecked(exception); return
null; }
+ }
+
+ @SuppressWarnings ("unchecked")
+ private static <E extends Throwable> void throwAsUnchecked(Exception
exception) throws E { throw (E)exception; }
+}
Added:
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/ManifestParser.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/ManifestParser.java?rev=1803557&view=auto
==============================================================================
---
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/ManifestParser.java
(added)
+++
sling/whiteboard/cziegeler/feature-support/src/main/java/org/apache/sling/feature/support/util/ManifestParser.java
Mon Jul 31 17:22:58 2017
@@ -0,0 +1,1038 @@
+/*
+ * 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.support.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.jar.Manifest;
+
+import org.apache.sling.feature.Capability;
+import org.apache.sling.feature.Requirement;
+import org.apache.sling.feature.support.impl.SimpleFilter;
+import org.apache.sling.feature.support.impl.VersionRange;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.namespace.BundleNamespace;
+import org.osgi.framework.namespace.ExecutionEnvironmentNamespace;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.wiring.BundleRevision;
+
+public class ManifestParser
+{
+ private static final String BUNDLE_LICENSE_HEADER = "Bundle-License"; //
No constant defined by OSGi...
+
+ private final Manifest m_headerMap;
+ private volatile String m_bundleSymbolicName;
+ private volatile Version m_bundleVersion;
+ private volatile List<Capability> m_capabilities;
+ private volatile List<Requirement> m_requirements;
+
+ public ManifestParser(Manifest m)
+ throws BundleException
+ {
+ m_headerMap = m;
+
+ // Verify that only manifest version 2 is specified.
+ String manifestVersion = getManifestVersion(m_headerMap);
+ if ((manifestVersion != null) && !manifestVersion.equals("2"))
+ {
+ throw new BundleException(
+ "Unknown 'Bundle-ManifestVersion' value: " +
manifestVersion);
+ }
+
+ List<Capability> capList = new ArrayList<>();
+
+ //
+ // Parse bundle version.
+ //
+
+ m_bundleVersion = Version.emptyVersion;
+ if (m_headerMap.getMainAttributes().getValue(Constants.BUNDLE_VERSION)
!= null)
+ {
+ try
+ {
+ m_bundleVersion =
Version.parseVersion(m_headerMap.getMainAttributes().getValue(Constants.BUNDLE_VERSION));
+ }
+ catch (RuntimeException ex)
+ {
+ // R4 bundle versions must parse, R3 bundle version may not.
+ if (getManifestVersion().equals("2"))
+ {
+ throw ex;
+ }
+ m_bundleVersion = Version.emptyVersion;
+ }
+ }
+
+ //
+ // Parse bundle symbolic name.
+ //
+
+ Capability bundleCap = parseBundleSymbolicName(m_headerMap);
+ if (bundleCap != null)
+ {
+ m_bundleSymbolicName = (String)
+
bundleCap.getAttributes().get(BundleRevision.BUNDLE_NAMESPACE);
+
+ // Add a bundle capability and a host capability to all
+ // non-fragment bundles. A host capability is the same
+ // as a require capability, but with a different capability
+ // namespace. Bundle capabilities resolve required-bundle
+ // dependencies, while host capabilities resolve fragment-host
+ // dependencies.
+ if
(m_headerMap.getMainAttributes().getValue(Constants.FRAGMENT_HOST) == null)
+ {
+ // All non-fragment bundles have host capabilities.
+ capList.add(bundleCap);
+ // A non-fragment bundle can choose to not have a host
capability.
+ String attachment =
+ (String)
bundleCap.getDirectives().get(Constants.FRAGMENT_ATTACHMENT_DIRECTIVE);
+ attachment = (attachment == null)
+ ? Constants.FRAGMENT_ATTACHMENT_RESOLVETIME
+ : attachment;
+ if
(!attachment.equalsIgnoreCase(Constants.FRAGMENT_ATTACHMENT_NEVER))
+ {
+ Map<String, Object> hostAttrs =
+ new HashMap<String,
Object>(bundleCap.getAttributes());
+ Object value =
hostAttrs.remove(BundleRevision.BUNDLE_NAMESPACE);
+ hostAttrs.put(BundleRevision.HOST_NAMESPACE, value);
+ Capability cap = new
Capability(BundleRevision.HOST_NAMESPACE);
+ cap.getAttributes().putAll(hostAttrs);
+ cap.getDirectives().putAll(bundleCap.getDirectives());
+ capList.add(cap);
+ }
+ }
+
+ //
+ // Add the osgi.identity capability.
+ //
+ capList.add(addIdentityCapability(m_headerMap, bundleCap));
+ }
+
+ // Verify that bundle symbolic name is specified.
+ if (getManifestVersion().equals("2") && (m_bundleSymbolicName == null))
+ {
+ throw new BundleException(
+ "R4 bundle manifests must include bundle symbolic name.");
+ }
+
+ //
+ // Parse Fragment-Host.
+ //
+
+ List<Requirement> hostReqs = parseFragmentHost(m_headerMap);
+
+ //
+ // Parse Require-Bundle
+ //
+
+ List<ParsedHeaderClause> rbClauses =
+
parseStandardHeader(m_headerMap.getMainAttributes().getValue(Constants.REQUIRE_BUNDLE));
+ rbClauses = normalizeRequireClauses(rbClauses, getManifestVersion());
+ List<Requirement> rbReqs = convertRequires(rbClauses);
+
+
+ //
+ // Parse Require-Capability.
+ //
+
+ List<ParsedHeaderClause> requireClauses =
+
parseStandardHeader(m_headerMap.getMainAttributes().getValue(Constants.REQUIRE_CAPABILITY));
+ List<Requirement> requireReqs =
convertRequireCapabilities(normalizeCapabilityClauses( requireClauses,
getManifestVersion()));
+
+ //
+ // Parse Provide-Capability.
+ //
+
+ List<ParsedHeaderClause> provideClauses =
+
parseStandardHeader(m_headerMap.getMainAttributes().getValue(Constants.PROVIDE_CAPABILITY));
+
+ List<Capability> provideCaps =
convertProvideCapabilities(normalizeCapabilityClauses(provideClauses,
getManifestVersion()));
+
+ // Combine all requirements.
+ m_requirements = new ArrayList<>();
+ m_requirements.addAll(hostReqs);
+ m_requirements.addAll(rbReqs);
+ m_requirements.addAll(requireReqs);
+
+ // Combine all capabilities.
+ m_capabilities = new ArrayList<>();
+ m_capabilities.addAll(capList);
+ m_capabilities.addAll(provideCaps);
+ }
+
+
+ private static List<Requirement> convertRequireCapabilities(
+ List<ParsedHeaderClause> clauses)
+ throws BundleException
+ {
+ // Now convert generic header clauses into requirements.
+ List<Requirement> reqList = new ArrayList<>();
+ for (ParsedHeaderClause clause : clauses)
+ {
+ for (String path : clause.m_paths)
+ {
+ if (path.startsWith("osgi.wiring."))
+ {
+ throw new BundleException("Manifest cannot use
Require-Capability for '"
+ + path
+ + "' namespace.");
+ }
+
+ Requirement req = new Requirement(path);
+ req.getAttributes().putAll(clause.m_attrs);
+ req.getDirectives().putAll(clause.m_dirs);
+ // Create requirement and add to requirement list.
+ reqList.add(req);
+ }
+ }
+
+ return reqList;
+ }
+
+ private static List<ParsedHeaderClause> normalizeCapabilityClauses(
+ List<ParsedHeaderClause> clauses, String mv)
+ throws BundleException
+ {
+
+ if (!mv.equals("2") && !clauses.isEmpty())
+ {
+ // Should we error here if we are not an R4 bundle?
+ }
+
+ // Convert attributes into specified types.
+ for (ParsedHeaderClause clause : clauses)
+ {
+ for (Entry<String, String> entry : clause.m_types.entrySet())
+ {
+ String type = entry.getValue();
+ if (!type.equals("String"))
+ {
+ if (type.equals("Double"))
+ {
+ clause.m_attrs.put(
+ entry.getKey(),
+ new
Double(clause.m_attrs.get(entry.getKey()).toString().trim()));
+ }
+ else if (type.equals("Version"))
+ {
+ clause.m_attrs.put(
+ entry.getKey(),
+ new
Version(clause.m_attrs.get(entry.getKey()).toString().trim()));
+ }
+ else if (type.equals("Long"))
+ {
+ clause.m_attrs.put(
+ entry.getKey(),
+ new
Long(clause.m_attrs.get(entry.getKey()).toString().trim()));
+ }
+ else if (type.startsWith("List"))
+ {
+ int startIdx = type.indexOf('<');
+ int endIdx = type.indexOf('>');
+ if (((startIdx > 0) && (endIdx <= startIdx))
+ || ((startIdx < 0) && (endIdx > 0)))
+ {
+ throw new BundleException(
+ "Invalid Provide-Capability attribute list
type for '"
+ + entry.getKey()
+ + "' : "
+ + type);
+ }
+
+ String listType = "String";
+ if (endIdx > startIdx)
+ {
+ listType = type.substring(startIdx + 1,
endIdx).trim();
+ }
+
+ List<String> tokens = parseDelimitedString(
+ clause.m_attrs.get(entry.getKey()).toString(),
",", false);
+ List<Object> values = new
ArrayList<Object>(tokens.size());
+ for (String token : tokens)
+ {
+ if (listType.equals("String"))
+ {
+ values.add(token);
+ }
+ else if (listType.equals("Double"))
+ {
+ values.add(new Double(token.trim()));
+ }
+ else if (listType.equals("Version"))
+ {
+ values.add(new Version(token.trim()));
+ }
+ else if (listType.equals("Long"))
+ {
+ values.add(new Long(token.trim()));
+ }
+ else
+ {
+ throw new BundleException(
+ "Unknown Provide-Capability attribute
list type for '"
+ + entry.getKey()
+ + "' : "
+ + type);
+ }
+ }
+ clause.m_attrs.put(
+ entry.getKey(),
+ values);
+ }
+ else
+ {
+ throw new BundleException(
+ "Unknown Provide-Capability attribute type for
'"
+ + entry.getKey()
+ + "' : "
+ + type);
+ }
+ }
+ }
+ }
+
+ return clauses;
+ }
+
+ private static List<Capability> convertProvideCapabilities(
+ List<ParsedHeaderClause> clauses)
+ throws BundleException
+ {
+ List<Capability> capList = new ArrayList<Capability>();
+ for (ParsedHeaderClause clause : clauses)
+ {
+ for (String path : clause.m_paths)
+ {
+ if (path.startsWith("osgi.wiring."))
+ {
+ throw new BundleException("Manifest cannot use
Provide-Capability for '"
+ + path
+ + "' namespace.");
+ }
+
+ Capability capability = new Capability(path);
+ capability.getAttributes().putAll(clause.m_attrs);
+ capability.getDirectives().putAll(clause.m_dirs);
+ // Create package capability and add to capability list.
+ capList.add(capability);
+ }
+ }
+
+ return capList;
+ }
+
+
+ public String getManifestVersion()
+ {
+ String manifestVersion = getManifestVersion(m_headerMap);
+ return (manifestVersion == null) ? "1" : manifestVersion;
+ }
+
+ private static String getManifestVersion(Manifest headerMap)
+ {
+ String manifestVersion =
headerMap.getMainAttributes().getValue(Constants.BUNDLE_MANIFESTVERSION);
+ return (manifestVersion == null) ? null : manifestVersion.trim();
+ }
+
+ public String getSymbolicName()
+ {
+ return m_bundleSymbolicName;
+ }
+
+ public Version getBundleVersion()
+ {
+ return m_bundleVersion;
+ }
+
+ public List<Capability> getCapabilities()
+ {
+ return m_capabilities;
+ }
+
+ public List<Requirement> getRequirements()
+ {
+ return m_requirements;
+ }
+
+
+ static class ParsedHeaderClause
+ {
+ public final List<String> m_paths;
+ public final Map<String, String> m_dirs;
+ public final Map<String, Object> m_attrs;
+ public final Map<String, String> m_types;
+
+ public ParsedHeaderClause(
+ List<String> paths, Map<String, String> dirs, Map<String,
Object> attrs,
+ Map<String, String> types)
+ {
+ m_paths = paths;
+ m_dirs = dirs;
+ m_attrs = attrs;
+ m_types = types;
+ }
+ }
+
+ private static Capability parseBundleSymbolicName(
+ Manifest headerMap)
+ throws BundleException
+ {
+ List<ParsedHeaderClause> clauses =
parseStandardHeader(headerMap.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME));
+ if (clauses.size() > 0)
+ {
+ if (clauses.size() > 1)
+ {
+ throw new BundleException(
+ "Cannot have multiple symbolic names: "
+ +
headerMap.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME));
+ }
+ else if (clauses.get(0).m_paths.size() > 1)
+ {
+ throw new BundleException(
+ "Cannot have multiple symbolic names: "
+ +
headerMap.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME));
+ }
+
+ // Get bundle version.
+ Version bundleVersion = Version.emptyVersion;
+ if
(headerMap.getMainAttributes().getValue(Constants.BUNDLE_VERSION) != null)
+ {
+ try
+ {
+ bundleVersion = Version.parseVersion(
+
headerMap.getMainAttributes().getValue(Constants.BUNDLE_VERSION));
+ }
+ catch (RuntimeException ex)
+ {
+ // R4 bundle versions must parse, R3 bundle version may
not.
+ String mv = getManifestVersion(headerMap);
+ if (mv != null)
+ {
+ throw ex;
+ }
+ bundleVersion = Version.emptyVersion;
+ }
+ }
+
+ // Create a require capability and return it.
+ String symName = clauses.get(0).m_paths.get(0);
+ clauses.get(0).m_attrs.put(BundleRevision.BUNDLE_NAMESPACE,
symName);
+ clauses.get(0).m_attrs.put(Constants.BUNDLE_VERSION_ATTRIBUTE,
bundleVersion);
+ Capability cap = new Capability(BundleRevision.BUNDLE_NAMESPACE);
+ cap.getAttributes().putAll(clauses.get(0).m_attrs);
+ cap.getAttributes().putAll(clauses.get(0).m_dirs);
+ }
+
+ return null;
+ }
+
+ private static Capability addIdentityCapability(Manifest headerMap,
Capability bundleCap)
+ {
+ Map<String, Object> attrs = new HashMap<String, Object>();
+
+ attrs.put(IdentityNamespace.IDENTITY_NAMESPACE,
+
bundleCap.getAttributes().get(BundleNamespace.BUNDLE_NAMESPACE));
+ attrs.put(IdentityNamespace.CAPABILITY_TYPE_ATTRIBUTE,
+
headerMap.getMainAttributes().getValue(Constants.FRAGMENT_HOST) == null
+ ? IdentityNamespace.TYPE_BUNDLE
+ : IdentityNamespace.TYPE_FRAGMENT);
+ attrs.put(IdentityNamespace.CAPABILITY_VERSION_ATTRIBUTE,
+
bundleCap.getAttributes().get(Constants.BUNDLE_VERSION_ATTRIBUTE));
+
+ if (headerMap.getMainAttributes().getValue(Constants.BUNDLE_COPYRIGHT)
!= null)
+ {
+ attrs.put(IdentityNamespace.CAPABILITY_COPYRIGHT_ATTRIBUTE,
+
headerMap.getMainAttributes().getValue(Constants.BUNDLE_COPYRIGHT));
+ }
+
+ if
(headerMap.getMainAttributes().getValue(Constants.BUNDLE_DESCRIPTION) != null)
+ {
+ attrs.put(IdentityNamespace.CAPABILITY_DESCRIPTION_ATTRIBUTE,
+
headerMap.getMainAttributes().getValue(Constants.BUNDLE_DESCRIPTION));
+ }
+ if (headerMap.getMainAttributes().getValue(Constants.BUNDLE_DOCURL) !=
null)
+ {
+ attrs.put(IdentityNamespace.CAPABILITY_DOCUMENTATION_ATTRIBUTE,
+
headerMap.getMainAttributes().getValue(Constants.BUNDLE_DOCURL));
+ }
+ if (headerMap.getMainAttributes().getValue(BUNDLE_LICENSE_HEADER) !=
null)
+ {
+ attrs.put(IdentityNamespace.CAPABILITY_LICENSE_ATTRIBUTE,
+
headerMap.getMainAttributes().getValue(BUNDLE_LICENSE_HEADER));
+ }
+
+ Map<String, String> dirs;
+ if (bundleCap.getDirectives().get(Constants.SINGLETON_DIRECTIVE) !=
null)
+ {
+ dirs =
Collections.singletonMap(IdentityNamespace.CAPABILITY_SINGLETON_DIRECTIVE,
+ (String)
bundleCap.getDirectives().get(Constants.SINGLETON_DIRECTIVE));
+ }
+ else
+ {
+ dirs = Collections.emptyMap();
+ }
+ Capability cap = new Capability(IdentityNamespace.IDENTITY_NAMESPACE);
+ cap.getAttributes().putAll(attrs);
+ cap.getDirectives().putAll(dirs);
+ return cap;
+ }
+
+ private static List<Requirement> parseFragmentHost(
+ Manifest headerMap)
+ throws BundleException
+ {
+ List<Requirement> reqs = new ArrayList<>();
+
+ String mv = getManifestVersion(headerMap);
+ if ((mv != null) && mv.equals("2"))
+ {
+ List<ParsedHeaderClause> clauses = parseStandardHeader(
+
headerMap.getMainAttributes().getValue(Constants.FRAGMENT_HOST));
+ if (clauses.size() > 0)
+ {
+ // Make sure that only one fragment host symbolic name is
specified.
+ if (clauses.size() > 1)
+ {
+ throw new BundleException(
+ "Fragments cannot have multiple hosts: "
+ +
headerMap.getMainAttributes().getValue(Constants.FRAGMENT_HOST));
+ }
+ else if (clauses.get(0).m_paths.size() > 1)
+ {
+ throw new BundleException(
+ "Fragments cannot have multiple hosts: "
+ +
headerMap.getMainAttributes().getValue(Constants.FRAGMENT_HOST));
+ }
+
+ // If the bundle-version attribute is specified, then convert
+ // it to the proper type.
+ Object value =
clauses.get(0).m_attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+ value = (value == null) ? "0.0.0" : value;
+ if (value != null)
+ {
+ clauses.get(0).m_attrs.put(
+ Constants.BUNDLE_VERSION_ATTRIBUTE,
+ VersionRange.parse(value.toString()));
+ }
+
+ // Note that we use a linked hash map here to ensure the
+ // host symbolic name is first, which will make indexing
+ // more efficient.
+// TODO: OSGi R4.3 - This is ordering is kind of hacky.
+ // Prepend the host symbolic name to the map of attributes.
+ Map<String, Object> attrs = clauses.get(0).m_attrs;
+ Map<String, Object> newAttrs = new LinkedHashMap<String,
Object>(attrs.size() + 1);
+ // We want this first from an indexing perspective.
+ newAttrs.put(
+ BundleRevision.HOST_NAMESPACE,
+ clauses.get(0).m_paths.get(0));
+ newAttrs.putAll(attrs);
+ // But we need to put it again to make sure it wasn't
overwritten.
+ newAttrs.put(
+ BundleRevision.HOST_NAMESPACE,
+ clauses.get(0).m_paths.get(0));
+
+ // Create filter now so we can inject filter directive.
+ SimpleFilter sf = SimpleFilter.convert(newAttrs);
+
+ // Inject filter directive.
+// TODO: OSGi R4.3 - Can we insert this on demand somehow?
+ Map<String, String> dirs = clauses.get(0).m_dirs;
+ Map<String, String> newDirs = new HashMap<String,
String>(dirs.size() + 1);
+ newDirs.putAll(dirs);
+ newDirs.put(
+ Constants.FILTER_DIRECTIVE,
+ sf.toString());
+
+ Requirement req = new
Requirement(BundleRevision.HOST_NAMESPACE);
+ req.getAttributes().putAll(newAttrs);
+ req.getDirectives().putAll(newDirs);
+ reqs.add(req);
+ }
+ }
+ else if
(headerMap.getMainAttributes().getValue(Constants.FRAGMENT_HOST) != null)
+ {
+ String s =
headerMap.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+ s = (s == null) ?
headerMap.getMainAttributes().getValue(Constants.BUNDLE_NAME) : s;
+ s = (s == null) ? headerMap.toString() : s;
+ }
+
+ return reqs;
+ }
+
+
+ private static List<Requirement> parseBreeHeader(String header)
+ {
+ List<String> filters = new ArrayList<String>();
+ for (String entry : parseDelimitedString(header, ","))
+ {
+ List<String> names = parseDelimitedString(entry, "/");
+ List<String> left = parseDelimitedString(names.get(0), "-");
+
+ String lName = left.get(0);
+ Version lVer;
+ try
+ {
+ lVer = Version.parseVersion(left.get(1));
+ }
+ catch (Exception ex)
+ {
+ // Version doesn't parse. Make it part of the name.
+ lName = names.get(0);
+ lVer = null;
+ }
+
+ String rName = null;
+ Version rVer = null;
+ if (names.size() > 1)
+ {
+ List<String> right = parseDelimitedString(names.get(1), "-");
+ rName = right.get(0);
+ try
+ {
+ rVer = Version.parseVersion(right.get(1));
+ }
+ catch (Exception ex)
+ {
+ rName = names.get(1);
+ rVer = null;
+ }
+ }
+
+ String versionClause;
+ if (lVer != null)
+ {
+ if ((rVer != null) && (!rVer.equals(lVer)))
+ {
+ // Both versions are defined, but different. Make each of
them part of the name
+ lName = names.get(0);
+ rName = names.get(1);
+ versionClause = null;
+ }
+ else
+ {
+ versionClause = getBreeVersionClause(lVer);
+ }
+ }
+ else
+ {
+ versionClause = getBreeVersionClause(rVer);
+ }
+
+ if ("J2SE".equals(lName))
+ {
+ // J2SE is not used in the Capability variant of BREE, use
JavaSE here
+ // This can only happen with the lName part...
+ lName = "JavaSE";
+ }
+
+ String nameClause;
+ if (rName != null)
+ nameClause = "(" +
ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE + "=" + lName +
"/" + rName + ")";
+ else
+ nameClause = "(" +
ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE + "=" + lName +
")";
+
+ String filter;
+ if (versionClause != null)
+ filter = "(&" + nameClause + versionClause + ")";
+ else
+ filter = nameClause;
+
+ filters.add(filter);
+ }
+
+ if (filters.size() == 0)
+ {
+ return Collections.emptyList();
+ }
+ else
+ {
+ String reqFilter;
+ if (filters.size() == 1)
+ {
+ reqFilter = filters.get(0);
+ }
+ else
+ {
+ // If there are more BREE filters, we need to or them together
+ StringBuilder sb = new StringBuilder("(|");
+ for (String f : filters)
+ {
+ sb.append(f);
+ }
+ sb.append(")");
+ reqFilter = sb.toString();
+ }
+
+ SimpleFilter sf = SimpleFilter.parse(reqFilter);
+ Requirement req = new
Requirement(ExecutionEnvironmentNamespace.EXECUTION_ENVIRONMENT_NAMESPACE);
+
req.getDirectives().put(ExecutionEnvironmentNamespace.REQUIREMENT_FILTER_DIRECTIVE,
reqFilter);
+ return Collections.<Requirement>singletonList(req);
+ }
+ }
+
+ private static String getBreeVersionClause(Version ver) {
+ if (ver == null)
+ return null;
+
+ return "(" +
ExecutionEnvironmentNamespace.CAPABILITY_VERSION_ATTRIBUTE + "=" + ver + ")";
+ }
+
+ private static List<ParsedHeaderClause>
normalizeRequireClauses(List<ParsedHeaderClause> clauses, String mv)
+ {
+ // R3 bundles cannot require other bundles.
+ if (!mv.equals("2"))
+ {
+ clauses.clear();
+ }
+ else
+ {
+ // Convert bundle version attribute to VersionRange type.
+ for (ParsedHeaderClause clause : clauses)
+ {
+ Object value =
clause.m_attrs.get(Constants.BUNDLE_VERSION_ATTRIBUTE);
+ if (value != null)
+ {
+ clause.m_attrs.put(
+ Constants.BUNDLE_VERSION_ATTRIBUTE,
+ VersionRange.parse(value.toString()));
+ }
+ }
+ }
+
+ return clauses;
+ }
+
+ private static List<Requirement> convertRequires(
+ List<ParsedHeaderClause> clauses)
+ {
+ List<Requirement> reqList = new ArrayList<>();
+ for (ParsedHeaderClause clause : clauses)
+ {
+ for (String path : clause.m_paths)
+ {
+ // Prepend the bundle symbolic name to the array of attributes.
+ Map<String, Object> attrs = clause.m_attrs;
+ // Note that we use a linked hash map here to ensure the
+ // symbolic name attribute is first, which will make indexing
+ // more efficient.
+// TODO: OSGi R4.3 - This is ordering is kind of hacky.
+ // Prepend the symbolic name to the array of attributes.
+ Map<String, Object> newAttrs = new LinkedHashMap<String,
Object>(attrs.size() + 1);
+ // We want this first from an indexing perspective.
+ newAttrs.put(
+ BundleRevision.BUNDLE_NAMESPACE,
+ path);
+ newAttrs.putAll(attrs);
+ // But we need to put it again to make sure it wasn't
overwritten.
+ newAttrs.put(
+ BundleRevision.BUNDLE_NAMESPACE,
+ path);
+
+ // Create filter now so we can inject filter directive.
+ SimpleFilter sf = SimpleFilter.convert(newAttrs);
+
+ // Inject filter directive.
+// TODO: OSGi R4.3 - Can we insert this on demand somehow?
+ Map<String, String> dirs = clause.m_dirs;
+ Map<String, String> newDirs = new HashMap<String,
String>(dirs.size() + 1);
+ newDirs.putAll(dirs);
+ newDirs.put(
+ Constants.FILTER_DIRECTIVE,
+ sf.toString());
+
+ Requirement req = new
Requirement(BundleRevision.BUNDLE_NAMESPACE);
+ req.getAttributes().putAll(newAttrs);
+ req.getDirectives().putAll(newDirs);
+ reqList.add(req);
+ }
+ }
+
+ return reqList;
+ }
+
+ private static final char EOF = (char) -1;
+
+ private static char charAt(int pos, String headers, int length)
+ {
+ if (pos >= length)
+ {
+ return EOF;
+ }
+ return headers.charAt(pos);
+ }
+
+ private static final int CLAUSE_START = 0;
+ private static final int PARAMETER_START = 1;
+ private static final int KEY = 2;
+ private static final int DIRECTIVE_OR_TYPEDATTRIBUTE = 4;
+ private static final int ARGUMENT = 8;
+ private static final int VALUE = 16;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static List<ParsedHeaderClause> parseStandardHeader(String header)
+ {
+ List<ParsedHeaderClause> clauses = new ArrayList<ParsedHeaderClause>();
+ if (header == null)
+ {
+ return clauses;
+ }
+ ParsedHeaderClause clause = null;
+ String key = null;
+ Map targetMap = null;
+ int state = CLAUSE_START;
+ int currentPosition = 0;
+ int startPosition = 0;
+ int length = header.length();
+ boolean quoted = false;
+ boolean escaped = false;
+
+ char currentChar = EOF;
+ do
+ {
+ currentChar = charAt(currentPosition, header, length);
+ switch (state)
+ {
+ case CLAUSE_START:
+ clause = new ParsedHeaderClause(
+ new ArrayList<>(),
+ new HashMap<>(),
+ new HashMap<>(),
+ new HashMap<>());
+ clauses.add(clause);
+ state = PARAMETER_START;
+ case PARAMETER_START:
+ startPosition = currentPosition;
+ state = KEY;
+ case KEY:
+ switch (currentChar)
+ {
+ case ':':
+ case '=':
+ key = header.substring(startPosition,
currentPosition).trim();
+ startPosition = currentPosition + 1;
+ targetMap = clause.m_attrs;
+ state = currentChar == ':' ?
DIRECTIVE_OR_TYPEDATTRIBUTE : ARGUMENT;
+ break;
+ case EOF:
+ case ',':
+ case ';':
+ clause.m_paths.add(header.substring(startPosition,
currentPosition).trim());
+ state = currentChar == ',' ? CLAUSE_START :
PARAMETER_START;
+ break;
+ default:
+ break;
+ }
+ currentPosition++;
+ break;
+ case DIRECTIVE_OR_TYPEDATTRIBUTE:
+ switch(currentChar)
+ {
+ case '=':
+ if (startPosition != currentPosition)
+ {
+ clause.m_types.put(key,
header.substring(startPosition, currentPosition).trim());
+ }
+ else
+ {
+ targetMap = clause.m_dirs;
+ }
+ state = ARGUMENT;
+ startPosition = currentPosition + 1;
+ break;
+ default:
+ break;
+ }
+ currentPosition++;
+ break;
+ case ARGUMENT:
+ if (currentChar == '\"')
+ {
+ quoted = true;
+ currentPosition++;
+ }
+ else
+ {
+ quoted = false;
+ }
+ if (!Character.isWhitespace(currentChar)) {
+ state = VALUE;
+ }
+ else {
+ currentPosition++;
+ }
+ break;
+ case VALUE:
+ if (escaped)
+ {
+ escaped = false;
+ }
+ else
+ {
+ if (currentChar == '\\' )
+ {
+ escaped = true;
+ }
+ else if (quoted && currentChar == '\"')
+ {
+ quoted = false;
+ }
+ else if (!quoted)
+ {
+ String value = null;
+ switch(currentChar)
+ {
+ case EOF:
+ case ';':
+ case ',':
+ value = header.substring(startPosition,
currentPosition).trim();
+ if (value.startsWith("\"") &&
value.endsWith("\""))
+ {
+ value = value.substring(1,
value.length() - 1);
+ }
+ if (targetMap.put(key, value) != null)
+ {
+ throw new IllegalArgumentException(
+ "Duplicate '" + key + "' in: "
+ header);
+ }
+ state = currentChar == ';' ?
PARAMETER_START : CLAUSE_START;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ currentPosition++;
+ break;
+ default:
+ break;
+ }
+ } while ( currentChar != EOF);
+
+ if (state > PARAMETER_START)
+ {
+ throw new IllegalArgumentException("Unable to parse header: " +
header);
+ }
+ return clauses;
+ }
+
+ public static List<String> parseDelimitedString(String value, String delim)
+ {
+ return parseDelimitedString(value, delim, true);
+ }
+
+ /**
+ * Parses delimited string and returns an array containing the tokens. This
+ * parser obeys quotes, so the delimiter character will be ignored if it is
+ * inside of a quote. This method assumes that the quote character is not
+ * included in the set of delimiter characters.
+ * @param value the delimited string to parse.
+ * @param delim the characters delimiting the tokens.
+ * @return a list of string or an empty list if there are none.
+ **/
+ public static List<String> parseDelimitedString(String value, String
delim, boolean trim)
+ {
+ if (value == null)
+ {
+ value = "";
+ }
+
+ List<String> list = new ArrayList<String>();
+
+ int CHAR = 1;
+ int DELIMITER = 2;
+ int STARTQUOTE = 4;
+ int ENDQUOTE = 8;
+
+ StringBuffer sb = new StringBuffer();
+
+ int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+ boolean isEscaped = false;
+ for (int i = 0; i < value.length(); i++)
+ {
+ char c = value.charAt(i);
+
+ boolean isDelimiter = (delim.indexOf(c) >= 0);
+
+ if (!isEscaped && (c == '\\'))
+ {
+ isEscaped = true;
+ continue;
+ }
+
+ if (isEscaped)
+ {
+ sb.append(c);
+ }
+ else if (isDelimiter && ((expecting & DELIMITER) > 0))
+ {
+ if (trim)
+ {
+ list.add(sb.toString().trim());
+ }
+ else
+ {
+ list.add(sb.toString());
+ }
+ sb.delete(0, sb.length());
+ expecting = (CHAR | DELIMITER | STARTQUOTE);
+ }
+ else if ((c == '"') && ((expecting & STARTQUOTE) > 0))
+ {
+ sb.append(c);
+ expecting = CHAR | ENDQUOTE;
+ }
+ else if ((c == '"') && ((expecting & ENDQUOTE) > 0))
+ {
+ sb.append(c);
+ expecting = (CHAR | STARTQUOTE | DELIMITER);
+ }
+ else if ((expecting & CHAR) > 0)
+ {
+ sb.append(c);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Invalid delimited string:
" + value);
+ }
+
+ isEscaped = false;
+ }
+
+ if (sb.length() > 0)
+ {
+ if (trim)
+ {
+ list.add(sb.toString().trim());
+ }
+ else
+ {
+ list.add(sb.toString());
+ }
+ }
+
+ return list;
+ }
+}