blob: 6572e7594c7c3a57a703a86a4653c46148727a71 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015-2018 The University of York, Aston University.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
*
* Contributors:
* Antonio Garcia-Dominguez - initial API and implementation
******************************************************************************/
package org.eclipse.hawk.graph;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.NoSuchElementException;
import org.eclipse.hawk.core.graph.IGraphDatabase;
import org.eclipse.hawk.core.graph.IGraphTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Read-only abstraction of the known metadata about a slot (an attribute or a
* reference) in the graph populated by this updater.
*/
public class Slot {
public static final String ATTR_TYPE_TIMEANNOTATION = "TimelineAnnotation";
private static final Logger LOGGER = LoggerFactory.getLogger(Slot.class);
private final TypeNode typeNode;
private final String propertyName, propertyType;
private final PropertyCategory propertyCategory;
private final boolean isMany, isOrdered, isUnique, isIndexed;
// Only valid if this is derived
private final String derivationLanguage, derivationLogic;
public enum PropertyCategory {
ATTRIBUTE {
@Override
public String getLetter() {
return "a";
}
}, REFERENCE {
@Override
public String getLetter() {
return "r";
}
}, MIXED {
@Override
public String getLetter() {
return "m";
}
}, DERIVED {
@Override
public String getLetter() {
return "d";
}
};
public abstract String getLetter();
public static PropertyCategory fromLetter(String letter) {
for (PropertyCategory pc : PropertyCategory.values()) {
if (pc.getLetter().equals(letter)) {
return pc;
}
}
throw new NoSuchElementException(letter);
}
}
public static class MetadataBuilder {
private String propertyType, derivationLanguage, derivationLogic;
private PropertyCategory pCategory = PropertyCategory.ATTRIBUTE;
private boolean isMany, isOrdered, isUnique, isIndexed;
public MetadataBuilder attribute() { pCategory = PropertyCategory.ATTRIBUTE; return this; }
public MetadataBuilder reference() { pCategory = PropertyCategory.REFERENCE; return this; }
public MetadataBuilder mixed() { pCategory = PropertyCategory.MIXED; return this; }
public MetadataBuilder derived() { pCategory = PropertyCategory.DERIVED; return this; }
public MetadataBuilder type(String s) { propertyType = s; return this; }
public MetadataBuilder derivationLanguage(String s) { derivationLanguage = s; return this; }
public MetadataBuilder derivationLogic(String s) { derivationLogic = s; return this; }
public MetadataBuilder many(boolean b) { isMany = b; return this; }
public MetadataBuilder ordered(boolean b) { isOrdered = b; return this; }
public MetadataBuilder unique(boolean b) { isUnique = b; return this; }
public MetadataBuilder indexed(boolean b) { isIndexed = b; return this; }
public String[] build() {
String[] metadata = pCategory == PropertyCategory.DERIVED ? new String[7] : new String[6];
metadata[0] = pCategory.getLetter();
metadata[1] = boolString(isMany);
metadata[2] = boolString(isOrdered);
metadata[3] = boolString(isUnique);
metadata[4] = propertyType;
if (pCategory == PropertyCategory.DERIVED) {
metadata[5] = derivationLanguage;
metadata[6] = derivationLogic;
} else {
metadata[5] = boolString(pCategory == PropertyCategory.ATTRIBUTE && isIndexed);
}
return metadata;
}
}
private static String boolString(boolean b) {
return b ? "t" : "f";
}
private static boolean stringBool(String s) {
return "t".equals(s);
}
public Slot(TypeNode typeNode, String propertyName, String[] propertyMetadata) {
this.typeNode = typeNode;
this.propertyName = propertyName;
this.propertyCategory = PropertyCategory.fromLetter(propertyMetadata[0]);
this.isMany = stringBool(propertyMetadata[1]);
this.isOrdered = stringBool(propertyMetadata[2]);
this.isUnique = stringBool(propertyMetadata[3]);
this.propertyType = propertyMetadata[4];
this.isIndexed = propertyCategory == PropertyCategory.ATTRIBUTE && stringBool(propertyMetadata[5]);
if (propertyCategory == PropertyCategory.DERIVED) {
this.derivationLanguage = propertyMetadata[5];
this.derivationLogic = propertyMetadata[6];
} else {
this.derivationLanguage = null;
this.derivationLogic = null;
}
}
public Slot(TypeNode typeNode, String propertyName) {
this(typeNode, propertyName, (String[]) typeNode.getNode().getProperty(propertyName));
}
/**
* Returns the collection container that should be used for the value of
* this slot.
*/
protected Collection<Object> getCollection() {
if (isOrdered && isUnique) {
return new LinkedHashSet<Object>(); // ordered set
} else if (isOrdered) {
return new ArrayList<Object>(); // sequence
} else if (isUnique) {
return new HashSet<Object>(); // set
} else {
return new ArrayList<Object>(); // bag
}
}
public TypeNode getTypeNode() {
return typeNode;
}
public String getName() {
return propertyName;
}
public boolean isAttribute() {
return propertyCategory == PropertyCategory.ATTRIBUTE;
}
public boolean isReference() {
return propertyCategory == PropertyCategory.REFERENCE;
}
public boolean isMixed() {
return propertyCategory == PropertyCategory.MIXED;
}
public boolean isDerived() {
return propertyCategory == PropertyCategory.DERIVED;
}
public boolean isMany() {
return isMany;
}
public boolean isOrdered() {
return isOrdered;
}
public boolean isUnique() {
return isUnique;
}
public boolean isIndexed() {
return isIndexed;
}
public String getType() {
return propertyType;
}
/**
* Returns the full name of the node index that tracks this slot in all instances
* of this type, if any.
*/
public String getNodeIndexName() {
if (!isDerived() && !isIndexed()) {
return null;
}
String result = null;
final IGraphDatabase graph = typeNode.getNode().getGraph();
try (IGraphTransaction ignored = graph.beginTransaction()) {
final String indexname = String.format("%s##%s##%s", typeNode.getMetamodelURI(), typeNode.getTypeName(), this.propertyName);
if (graph.nodeIndexExists(indexname)) {
result = indexname;
}
ignored.success();
} catch (Exception e) {
LOGGER.warn("Error while locating the index for this derived property", e);
}
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((propertyName == null) ? 0 : propertyName.hashCode());
result = prime * result
+ ((typeNode == null) ? 0 : typeNode.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Slot other = (Slot) obj;
if (propertyName == null) {
if (other.propertyName != null)
return false;
} else if (!propertyName.equals(other.propertyName))
return false;
if (typeNode == null) {
if (other.typeNode != null)
return false;
} else if (!typeNode.equals(other.typeNode))
return false;
return true;
}
public String getDerivationLanguage() {
return derivationLanguage;
}
public String getDerivationLogic() {
return derivationLogic;
}
@Override
public String toString() {
return "Slot [typeNode=" + typeNode + ", propertyName=" + propertyName + ", propertyType=" + propertyType
+ ", propertyCategory=" + propertyCategory + ", isMany=" + isMany + ", isOrdered=" + isOrdered
+ ", isUnique=" + isUnique + ", isIndexed=" + isIndexed + ", derivationLanguage=" + derivationLanguage
+ ", derivationLogic=" + derivationLogic + "]";
}
}