aQute.bnd.osgi.resource.PersistentResource Maven / Gradle / Ivy
The newest version!
package aQute.bnd.osgi.resource;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.osgi.framework.Version;
import org.osgi.resource.Capability;
import org.osgi.resource.Requirement;
import org.osgi.resource.Resource;
import aQute.bnd.util.dto.DTO;
import aQute.lib.collections.MultiMap;
import aQute.lib.converter.Converter;
import aQute.lib.hex.Hex;
/**
* This class provides an efficient way to store a resource through JSON
* serialization. It stores the requirements and provides in a structure of
* Resource 1 -> * Namespace 1 -> * Req/Cap. It optimizes
*/
public class PersistentResource extends DTO implements Resource {
public Namespace[] namespaces;
transient Resource resource;
public byte[] sha;
public static class Namespace extends DTO implements Comparable {
public String name;
public RCData[] capabilities;
public RCData[] requirements;
@Override
public int compareTo(Namespace o) {
return name.compareTo(o.name);
}
}
public static class RCData extends DTO {
public boolean require;
public Attr[] properties;
public int directives;
}
public enum DataType {
STRING,
LONG,
DOUBLE,
VERSION;
}
public static class Attr extends DTO implements Comparable {
public String key;
public int type;
public Object value;
public boolean directive = false;
transient Object converted;
@Override
public int compareTo(Attr o) {
return key.compareTo(o.key);
}
public Object getValue() {
if (converted == null && value != null) {
DataType t = DataType.values()[type];
if (value instanceof Collection) {
Object[] cnv = ((Collection>) value).toArray();
for (int i = 0; i < cnv.length; i++) {
cnv[i] = convert(t, cnv[i]);
}
converted = cnv;
} else
converted = convert(t, value);
}
return converted;
}
private Object convert(DataType t, Object value) {
try {
switch (t) {
case DOUBLE :
return Converter.cnv(Double.class, value);
case LONG :
return Converter.cnv(Long.class, value);
case STRING :
return Converter.cnv(String.class, value);
case VERSION :
if (value instanceof String)
return Version.parseVersion((String) value);
return Converter.cnv(Version.class, value);
default :
return null;
}
} catch (Exception e) {
return null;
}
}
}
public PersistentResource() {}
public PersistentResource(Resource resource) {
MultiMap capMap = new MultiMap<>();
for (Capability cap : resource.getCapabilities(null))
capMap.add(cap.getNamespace(), cap);
MultiMap reqMap = new MultiMap<>();
for (Requirement req : resource.getRequirements(null))
reqMap.add(req.getNamespace(), req);
Set names = new HashSet<>(capMap.keySet());
names.addAll(reqMap.keySet());
namespaces = new Namespace[names.size()];
int i = 0;
for (String name : names) {
Namespace ns = new Namespace();
ns.name = name;
List requirements = reqMap.get(name);
if (requirements != null && requirements.size() > 0) {
ns.requirements = new RCData[requirements.size()];
int rqi = 0;
for (Requirement r : requirements)
ns.requirements[rqi++] = getData(true, r.getAttributes(), r.getDirectives());
;
}
List capabilities = capMap.get(name);
if (capabilities != null && capabilities.size() > 0) {
ns.capabilities = new RCData[capabilities.size()];
int rci = 0;
for (Capability c : capabilities)
ns.capabilities[rci++] = getData(false, c.getAttributes(), c.getDirectives());
}
namespaces[i++] = ns;
}
Arrays.sort(namespaces);
}
public Resource getResource() throws Exception {
if (resource == null) {
ResourceBuilder rb = new ResourceBuilder();
for (Namespace ns : namespaces) {
if (ns.capabilities != null)
for (RCData rcdata : ns.capabilities) {
CapReqBuilder capb = new CapReqBuilder(ns.name);
for (Attr attrs : rcdata.properties) {
if (attrs.directive)
capb.addDirective(attrs.key, (String) attrs.value);
else
capb.addAttribute(attrs.key, attrs.getValue());
}
rb.addCapability(capb);
}
if (ns.requirements != null)
for (RCData rcdata : ns.requirements) {
CapReqBuilder reqb = new CapReqBuilder(ns.name);
for (Attr attrs : rcdata.properties) {
if (attrs.directive)
reqb.addDirective(attrs.key, (String) attrs.value);
else
reqb.addAttribute(attrs.key, attrs.getValue());
}
rb.addRequirement(reqb);
}
}
resource = rb.build();
}
return resource;
}
private static int getType(Object value) {
if (value == null || value instanceof String)
return DataType.STRING.ordinal();
if (value instanceof Version)
return DataType.VERSION.ordinal();
if (value instanceof Long)
return DataType.LONG.ordinal();
if (value instanceof Double)
return DataType.DOUBLE.ordinal();
return DataType.STRING.ordinal();
}
private static Attr getAttr(String key, Object value, boolean directive) {
Attr attr = new Attr();
attr.key = key;
if (directive) {
attr.type = DataType.STRING.ordinal();
attr.value = value.toString();
attr.directive = true;
return attr;
}
attr.value = value;
if (value instanceof Collection) {
if (((Collection>) value).size() > 0) {
Object member = ((Collection>) value).iterator()
.next();
attr.type = getType(member);
} else {
attr.type = DataType.STRING.ordinal();
}
return attr;
}
if (value.getClass()
.isArray()) {
int length = Array.getLength(value);
if (length > 0) {
Object member = Array.get(value, 0);
attr.type = getType(member);
} else {
attr.type = DataType.STRING.ordinal();
}
}
attr.type = getType(value);
return attr;
}
private static RCData getData(boolean require, Map attributes, Map directives) {
RCData data = new RCData();
data.require = require;
List props = new ArrayList<>(attributes.size() + directives.size());
for (Entry entry : attributes.entrySet()) {
props.add(getAttr(entry.getKey(), entry.getValue(), false));
}
for (Entry entry : directives.entrySet()) {
props.add(getAttr(entry.getKey(), entry.getValue(), true));
data.directives++;
}
Collections.sort(props);
data.properties = props.toArray(new Attr[0]);
return data;
}
@Override
public String toString() {
try {
return "P-" + getResource();
} catch (Exception e) {
return "P-" + Hex.toHexString(sha);
}
}
@Override
@Deprecated
public List getCapabilities(String ns) {
return null;
}
@Override
@Deprecated
public List getRequirements(String ns) {
return null;
}
@Deprecated
public static RCData getData(Map attributes, Map directives) {
return null;
}
@Deprecated
public PersistentResource(byte[] digest, List caps, List reqs) {}
@Deprecated
public class RC implements Requirement, Capability {
public RC(RCData data, String ns) {}
@Override
public String getNamespace() {
return null;
}
@Override
public Resource getResource() {
return null;
}
@Override
public Map getAttributes() {
return null;
}
@Override
public Map getDirectives() {
return null;
}
}
}