Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions biz.aQute.bndlib.tests/test/test/AttrsTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Arrays;
Expand All @@ -8,6 +9,7 @@
import org.junit.jupiter.api.Test;

import aQute.bnd.header.Attrs;
import aQute.bnd.header.OSGiHeader;
import aQute.bnd.version.Version;

public class AttrsTest {
Expand Down Expand Up @@ -65,4 +67,25 @@ public void testVersion() {
assertEquals("version:Version=\"1.2.3\";versions:List<Version>=\"1.2.3,2.1.0\"", attr.toString());
}

@Test
public void testSorting() {
assertThat(attrs("b=1;a=2;c=3;d=4;$:=0").sort()
.toString()).isEqualTo("$:=0;a=2;b=1;c=3;d=4");
}

@Test
public void testComparing() {
assertThat(attrs("a=1").compareTo(attrs("a=1"))).isEqualTo(0);
assertThat(attrs("a=1").compareTo(attrs("a=2"))).isEqualTo(-1);
assertThat(attrs("a=2").compareTo(attrs("a=1"))).isEqualTo(1);

assertThat(attrs("a=1").compareTo(attrs("a=1;b=1"))).isEqualTo(-1);
assertThat(attrs("a=1;b=1").compareTo(attrs("a=1"))).isEqualTo(1);
}

private Attrs attrs(String string) {
return OSGiHeader.parseHeader("x;" + string)
.get("x");
}

}
45 changes: 45 additions & 0 deletions biz.aQute.bndlib.tests/test/test/ProcessorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import aQute.bnd.osgi.resource.RequirementBuilder;
import aQute.bnd.osgi.resource.ResourceBuilder;
import aQute.bnd.osgi.resource.ResourceUtils;
import aQute.bnd.service.parameters.ConsolidateParameters;
import aQute.lib.collections.ExtList;
import aQute.lib.strings.Strings;
import aQute.service.reporter.Reporter.SetLocation;
Expand Down Expand Up @@ -529,4 +530,48 @@ public void testMergAndSuffixes() throws IOException {
}

}

@Test
public void testClauses() throws IOException {
try (Processor p = new Processor()) {
assertThat(p.getParameters("foo")).isNotNull()
.isEmpty();

p.addClause("FOO", "abc", new Attrs());
p.addClause("FOO", "def", new Attrs());
p.addClause("FOO", "abc", new Attrs());
assertThat(p.getParameters("FOO")).hasSize(3);
assertThat(p.getParameters("FOO")
.toString()).isEqualTo("abc,def,abc");
assertThat(p.getProperty("FOO")).isEqualTo("abc,def,abc");
p.addClause("FOO", "abc", new Attrs());
assertThat(p.getProperty("FOO")).isEqualTo("abc,def,abc,abc");

p.setProperty("FOO", "nothing");
assertThat(p.getParameters("FOO")
.toString()).isEqualTo("nothing");

assertThat(p.getParameters("FOO")).isNotNull()
.containsKey("nothing");

p.addBasicPlugin((ConsolidateParameters) (k, pars) -> {
if (!k.equals("FOO"))
return null;
return pars.sort();
});

p.addClause("FOO", "def", new Attrs().set("a", "2"));
p.addClause("FOO", "abc", new Attrs().set("a", "3"));
p.addClause("FOO", "def", new Attrs().set("a", "1"));
p.addClause("FOO", "def", new Attrs().set("a", "1")
.set("b", "1"));

assertThat(p.getParameters("FOO")
.toString()).isEqualTo("nothing,def;a=2,abc;a=3,def;a=1,def;a=1;b=1");

assertThat(p.getProperty("FOO")).isEqualTo("abc;a=3,def;a=1,def;a=1;b=1,def;a=2,nothing");

}
}

}
2 changes: 1 addition & 1 deletion biz.aQute.bndlib/src/aQute/bnd/build/package-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*/
@Version("4.3.0")
@Version("4.4.0")
package aQute.bnd.build;

import org.osgi.annotation.versioning.Version;
54 changes: 54 additions & 0 deletions biz.aQute.bndlib/src/aQute/bnd/header/Attrs.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -71,6 +73,8 @@ public interface DataType<T> {
public static final DataType<List<Double>> LIST_DOUBLE = () -> Type.DOUBLES;
public static final DataType<List<Version>> LIST_VERSION = () -> Type.VERSIONS;

public static Comparator<Attrs> COMPARATOR = Attrs::compareTo;

/**
* Pattern for List with list type
*/
Expand All @@ -87,6 +91,7 @@ private Attrs(Map<String, String> map, Map<String, Type> types) {
this.types = types;
}


public Attrs() {
this(new LinkedHashMap<>(), new HashMap<>());
}
Expand Down Expand Up @@ -634,4 +639,53 @@ public Attrs select(Predicate<String> predicate) {
});
return attrs;
}

/**
* Return a new Attributes that is sorted by key
*
* @return a sorted attributes
*/
public Attrs sort() {
Attrs attrs = new Attrs();
this.entrySet()
.stream()
.sorted((a, b) -> a.getKey()
.compareTo(b.getKey()))
.forEach(e -> attrs.put(e.getKey(), e.getValue()));
return attrs;
}

public Attrs set(String k, String v) {
put(k, v);
return this;
}

public int compareTo(Attrs b) {
Attrs a = this;
Iterator<Map.Entry<String, String>> ia = a.entrySet()
.iterator();
Iterator<Map.Entry<String, String>> ib = b.entrySet()
.iterator();
while (ia.hasNext()) {
if (!ib.hasNext())
return 1;

Entry<String, String> ea = ia.next();
Entry<String, String> eb = ib.next();
int n = ea.getKey()
.compareTo(eb.getKey());
if (n != 0)
return n;

n = ea.getValue()
.compareTo(eb.getValue());
if (n != 0)
return n;
}
if (ib.hasNext()) {
return -1;
}
return 0;
}

}
36 changes: 36 additions & 0 deletions biz.aQute.bndlib/src/aQute/bnd/header/Parameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collector;

import aQute.bnd.stream.MapStream;
import aQute.lib.collections.MultiMap;
import aQute.service.reporter.Reporter;

public class Parameters implements Map<String, Attrs> {
Expand Down Expand Up @@ -268,4 +270,38 @@ private static Parameters combiner(Parameters t, Parameters u) {
public Map<String, Map<String, String>> toBasic() {
return (Map) this;
}

/**
* A Parameters can contain the same key multiple times. This maps the
* clauses in the Parameters to a multi map with a clean key and a number of
* attributes.
*
* @return a fresh multi map
*/
public Map<String, List<Attrs>> flatten() {
MultiMap<String, Attrs> mmap = new MultiMap<>();
for (Map.Entry<String, Attrs> e : map.entrySet()) {
mmap.add(removeDuplicateMarker(e.getKey()), e.getValue());
}
return mmap;
}

/**
* Return a sorted Parameters that has the same keys and attributes but that
* is sorted by key and attributes.
*
* @return a sorted Parameters (this is a fresh instance)
*/
public Parameters sort() {
Map<String, List<Attrs>> flatten = flatten();
Parameters result = new Parameters();
for (String s : new TreeSet<>(flatten.keySet())) {
flatten.get(s)
.stream()
.map(a -> a.sort())
.sorted(Attrs.COMPARATOR)
.forEach(attrs -> result.add(s, attrs));
}
return result;
}
}
2 changes: 1 addition & 1 deletion biz.aQute.bndlib/src/aQute/bnd/header/package-info.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@Version("2.5.0")
@Version("2.6.0")
package aQute.bnd.header;

import org.osgi.annotation.versioning.Version;
2 changes: 1 addition & 1 deletion biz.aQute.bndlib/src/aQute/bnd/junit/package-info.java
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
@org.osgi.annotation.versioning.Version("2.1.0")
@org.osgi.annotation.versioning.Version("2.2.0")
package aQute.bnd.junit;
2 changes: 1 addition & 1 deletion biz.aQute.bndlib/src/aQute/bnd/maven/package-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*/
@Version("3.3.0")
@Version("3.4.0")
package aQute.bnd.maven;

import org.osgi.annotation.versioning.Version;
77 changes: 77 additions & 0 deletions biz.aQute.bndlib/src/aQute/bnd/osgi/ClauseManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package aQute.bnd.osgi;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.service.parameters.ConsolidateParameters;

class ClauseManager {
final static Logger logger = LoggerFactory.getLogger(ClauseManager.class);
final Processor processor;

final Map<String, Parameters> parameters = new HashMap<>();

ClauseManager(Processor processor) {
this.processor = processor;
}

void addClause(String key, String name, Attrs ps) {
Parameters p = getParameters(key);
p.add(name, ps);
}

Parameters getParameters(String key) {
return parameters.computeIfAbsent(key, k -> {
String property = processor.getProperty(key);
return new Parameters(property);
});
}

Optional<Parameters> getOptionalParameters(String key) {
return Optional.ofNullable(parameters.get(key));
}

void reset(String key) {
if (parameters.remove(key) != null) {
logger.info(
"a clause was set but then cleared due a property overwrite. This might indicate that not all code treats the header {} the same",
key);
}
}

void reset() {
parameters.clear();
}

void consolidate(String key) {
Parameters parameters = this.parameters.get(key);
if (parameters == null)
return;

try {
for (ConsolidateParameters cp : processor.getPlugins(ConsolidateParameters.class)) {
Parameters consolidated = cp.consolidate(key, parameters);
if (consolidated != null) {
processor.setProperty(key, consolidated.toString());
return;
}
}
processor.setProperty(key, parameters.toString());
} finally {
assert !this.parameters.containsKey(key) : "should be cleared by processor";
}
}

void consolidate() {
for (String key : new ArrayList<>(parameters.keySet())) {
consolidate(key);
}
}
}
31 changes: 30 additions & 1 deletion biz.aQute.bndlib/src/aQute/bnd/osgi/Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public class Processor extends Domain implements Reporter, Registry, Constants,
Collection<String> filter;
Boolean strict;
boolean fixupMessages;
final ClauseManager clauses = new ClauseManager(this);

public static class FileLine {
public static final FileLine DUMMY = new FileLine(null, 0, 0);
Expand Down Expand Up @@ -940,6 +941,7 @@ public void forceRefresh() {
}

public void propertiesChanged() {
clauses.reset();
Processor p = getParent();
if (p != null) {
updateModified(p.lastModified(), "propertiesChanged");
Expand Down Expand Up @@ -1068,6 +1070,8 @@ private String getLiteralProperty(String key, String deflt, Processor source, bo
String value = null;
// Use the key as is first, if found ok

clauses.consolidate(key);

for (Processor proc = source; proc != null; proc = proc.getParent()) {
Object raw = proc.getProperties()
.get(key);
Expand Down Expand Up @@ -1292,7 +1296,9 @@ public long lastModified() {
* @param value
*/
public void setProperty(String key, String value) {
getProperties().put(normalizeKey(key), value);
String normalizeKey = normalizeKey(key);
getProperties().put(normalizeKey, value);
clauses.reset(normalizeKey);
}

/**
Expand Down Expand Up @@ -2630,4 +2636,27 @@ private List<File> getSelfAndAncestors(List<File> l) {
public void setPropertiesFile(File source) {
this.propertiesFile = source;
}

/**
* Add a clause to a Parameters like header
*
* @param key the header key of the Parameters, e.g. Require-Capability
* @param name the name of the clause inside the parameters
* @param attrs the set of attributes
*/

public void addClause(String key, String name, Attrs attrs) {
clauses.addClause(key, name, attrs);
}

/**
* Get the parameters for a property.
*
* @param key the header key of the Parameters, e.g. Require-Capability
*/

@Override
public Parameters getParameters(String key) {
return clauses.getParameters(key);
}
}
Loading