...
Creating a combined metadata type
...
Different metadata types can be used together. For this, in the best case, a single class should be provided, that combines this data. Typically, this class just delegates to the base classes. In the following is an example with trust and timeinterval:
Code Block | ||||
---|---|---|---|---|
| ||||
public class IntervalTrust extends AbstractCombinedMetaAttribute implements ITimeInterval, ITrust {
private static final long serialVersionUID = 1599620389994530920L;
@SuppressWarnings("unchecked")
public final static Class<? extends IMetaAttribute>[] classes = new Class[] { ITimeInterval.class, ITrust.class };
@Override
public Class<? extends IMetaAttribute>[] getClasses() {
return classes;
}
public static final List<SDFMetaSchema> schema = new ArrayList<>(classes.length);
static {
schema.addAll(TimeInterval.schema);
schema.addAll(Trust.schema);
}
@Override
public List<SDFMetaSchema> getSchema() {
return schema;
}
@Override
public String getName() {
return "IntervalTrust";
}
|
The new class must extend AbstractCombinedMetaAttribute and implements the base interfaces for this combination.
The classes for this metadata is the same set of interfaces, and should be in lexical order.
The schema is simply a list containing the subschema of the containing metadata.
Code Block | ||||
---|---|---|---|---|
| ||||
private final ITrust trust;
private final ITimeInterval timeInterval;
public IntervalTrust() {
this.trust = new Trust();
this.timeInterval = new TimeInterval();
}
public IntervalTrust(IntervalTrust other) {
this.trust = (ITrust) other.trust.clone();
this.timeInterval = (ITimeInterval) other.timeInterval.clone();
}
@Override
public IntervalTrust clone() {
return new IntervalTrust(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof IntervalTrust)) {
return false;
}
IntervalTrust other = (IntervalTrust) obj;
return this.trust.equals(other.trust) && this.timeInterval.equals(other.timeInterval);
} |
Also similiar to the basetypes, there must be a default constructor, a copy constructor a clone-method and an equals method.
Code Block | ||||
---|---|---|---|---|
| ||||
// ------------------------------------------------------------------------------
// Methods that need to merge different types
// ------------------------------------------------------------------------------
@Override
public void retrieveValues(List<Tuple<?>> values) {
this.timeInterval.retrieveValues(values);
this.trust.retrieveValues(values);
}
@Override
public void writeValues(List<Tuple<?>> values) {
this.timeInterval.writeValue(values.get(0));
this.trust.writeValue(values.get(1));
}
@Override
public List<IInlineMetadataMergeFunction<? extends IMetaAttribute>> getInlineMergeFunctions() {
List<IInlineMetadataMergeFunction<? extends IMetaAttribute>> list = new ArrayList<>();
list.addAll(this.timeInterval.getInlineMergeFunctions());
list.addAll(this.trust.getInlineMergeFunctions());
return list;
}
@Override
public <K> K getValue(int subtype, int index) {
switch (subtype) {
case 0:
return this.timeInterval.getValue(0, index);
case 1:
return this.trust.getValue(0, index);
default:
return null;
}
}
@Override
public String toString() {
return "( i= " + this.timeInterval.toString() + " | " + " l=" + this.trust + ")";
} |
The next block contains methods to retrieve and set the combined values and merge functions. As you can see, here is always delegated to the base metadata. Important here is to keep the right order!
In getValue, the subtype, says from which metadata the value should be retrieved.
The last block just contains the getter and setter for the metadata and is always delegated to the base types:
Code Block | ||||
---|---|---|---|---|
| ||||
// ------------------------------------------------------------------------------
// Delegates for timeInterval
// ------------------------------------------------------------------------------
@Override
public PointInTime getStart() {
return this.timeInterval.getStart();
}
@Override
public PointInTime getEnd() {
return this.timeInterval.getEnd();
}
@Override
public void setStart(PointInTime point) {
this.timeInterval.setStart(point);
}
@Override
public void setEnd(PointInTime point) {
this.timeInterval.setEnd(point);
}
@Override
public void setStartAndEnd(PointInTime start, PointInTime end) {
this.timeInterval.setStartAndEnd(start, end);
}
@Override
public int compareTo(ITimeInterval o) {
return this.timeInterval.compareTo(o);
}
// ------------------------------------------------------------------------------
// Delegates for trust
// ------------------------------------------------------------------------------
@Override
public double getTrust() {
return this.trust.getTrust();
}
@Override
public void setTrust(double trustValue) {
this.trust.setTrust(trustValue);
}
|
When Odysseus at Runtime does not find such a combined metadata it will create a new one and compile it. This is slower and does not always work. So it is better to create a combination.
You could use:
GenerateMetadataClassCode (https://git.swl.informatik.uni-oldenburg.de/projects/ODY/repos/odysseus_core/browse/common/core/src/de/uniol/inf/is/odysseus/core/metadata/GenerateMetadataClassCode.java) as a generator for the combined metadata.
Remark: Typically, it is best to put each combination of metadata to an own bundle to avoid to many dependencies.
Finally, this class need to be registered as metadata, too:
Code Block | ||
---|---|---|
| ||
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="de.uniol.inf.is.odysseus.interval_trust.IntervalTrust">
<implementation class="de.uniol.inf.is.odysseus.interval_trust.IntervalTrust"/>
<service>
<provide interface="de.uniol.inf.is.odysseus.core.metadata.IMetaAttribute"/>
</service>
</scr:component> |