use of eu.esdihumboldt.hale.common.schema.model.ChildDefinition in project hale by halestudio.
the class CustomTypeContentHelper method applyConfiguration.
/**
* Apply a custom type configuration to the given schema.
*
* @param index the XML schema
* @param association the custom type configuration for an individual
* property
*/
public static void applyConfiguration(XmlIndex index, CustomTypeContentAssociation association) {
CustomTypeContent config = association.getConfig();
// property identified by a list of qualified names
List<QName> property = association.getProperty();
PropertyDefinition propDef = null;
DefinitionGroup propParent = null;
if (property != null && property.size() > 1) {
QName typeName = property.get(0);
TypeDefinition type = index.getType(typeName);
if (type != null) {
LinkedList<QName> nameQueue = new LinkedList<>(property.subList(1, property.size()));
Definition<?> parent = null;
Definition<?> child = type;
while (!nameQueue.isEmpty() && child != null) {
parent = child;
QName name = nameQueue.pollFirst();
child = DefinitionUtil.getChild(parent, name);
}
if (nameQueue.isEmpty() && child instanceof PropertyDefinition) {
propDef = (PropertyDefinition) child;
if (parent instanceof TypeDefinition) {
propParent = (DefinitionGroup) parent;
} else if (parent instanceof ChildDefinition<?>) {
ChildDefinition<?> pc = (ChildDefinition<?>) parent;
if (pc.asProperty() != null) {
propParent = pc.asProperty().getPropertyType();
} else if (pc.asGroup() != null) {
propParent = pc.asGroup();
}
} else {
log.error("Illegal parent for custom type content property");
return;
}
} else {
log.warn("Cannot apply custom type content configuration due to invalid property path");
return;
}
} else {
log.warn("Cannot apply custom type content configuration due because the type {} starting the property path could not be found", typeName);
return;
}
} else {
log.warn("Cannot apply custom type content configuration due to missing property path");
return;
}
switch(config.getMode()) {
case simple:
applySimpleMode(propDef, propParent, config);
case elements:
applyElementsMode(propDef, propParent, config, index);
default:
log.error("Unrecognized custom type content mode {}", config.getMode().name());
}
}
use of eu.esdihumboldt.hale.common.schema.model.ChildDefinition in project hale by halestudio.
the class OptionalPropertiesFilter method areChildrenOptional.
/**
* Determines if the given (nillable) entity can be considered optional in
* respect to its children.
*
* @param entityDef the entity definition which children to check
* @param alreadyChecked the set of definitions that have already been
* checked (excluding the given entity)
* @return if all children are optional
*/
private boolean areChildrenOptional(EntityDefinition entityDef, Set<Definition<?>> alreadyChecked) {
// get children without contexts
Collection<? extends EntityDefinition> children = AlignmentUtil.getChildrenWithoutContexts(entityDef);
if (children == null || children.isEmpty()) {
return true;
}
for (EntityDefinition child : children) {
Set<Definition<?>> checked = new HashSet<>(alreadyChecked);
checked.add(entityDef.getDefinition());
ChildDefinition<?> childDef = (ChildDefinition<?>) child.getDefinition();
/*
* XML: We only need to check children that are attributes, if they
* are optional.
*/
if (childDef.asProperty() != null && childDef.asProperty().getConstraint(XmlAttributeFlag.class).isEnabled()) {
// need to check if it is optional
if (!isOptional(child, checked)) {
return false;
}
}
/*
* XXX does other special handling need to be done for other kinds
* of schemas?
*/
}
return true;
}
use of eu.esdihumboldt.hale.common.schema.model.ChildDefinition in project hale by halestudio.
the class StyledDefinitionLabelProvider method update.
/**
* @see StyledCellLabelProvider#update(ViewerCell)
*/
@Override
public void update(ViewerCell cell) {
Object element = cell.getElement();
element = extractElement(element);
StyledString text = new StyledString(defaultLabels.getText(element));
cell.setImage(defaultLabels.getImage(element));
String contextText = null;
String countText = null;
if (element instanceof EntityDefinition) {
PopulationService ps = PlatformUI.getWorkbench().getService(PopulationService.class);
if (ps != null) {
Population pop = ps.getPopulation((EntityDefinition) element);
int count = pop.getOverallCount();
int parents = pop.getParentsCount();
switch(count) {
case Population.UNKNOWN:
countText = "\u00d7?";
break;
case 0:
break;
default:
countText = "\u00d7" + count;
if (parents != count) {
countText += " (" + parents + ")";
}
}
}
contextText = AlignmentUtil.getContextText((EntityDefinition) element);
element = ((EntityDefinition) element).getDefinition();
}
// append cardinality
if (!suppressCardinality && element instanceof ChildDefinition<?>) {
Cardinality cardinality = null;
if (((ChildDefinition<?>) element).asGroup() != null) {
cardinality = ((ChildDefinition<?>) element).asGroup().getConstraint(Cardinality.class);
} else if (((ChildDefinition<?>) element).asProperty() != null) {
cardinality = ((ChildDefinition<?>) element).asProperty().getConstraint(Cardinality.class);
}
if (cardinality != null) {
// only append cardinality if it isn't 1/1
if (cardinality.getMinOccurs() != 1 || cardinality.getMaxOccurs() != 1) {
String card = " " + MessageFormat.format("({0}..{1})", new Object[] { Long.valueOf(cardinality.getMinOccurs()), (cardinality.getMaxOccurs() == Cardinality.UNBOUNDED) ? ("n") : (Long.valueOf(cardinality.getMaxOccurs())) });
text.append(card, StyledString.COUNTER_STYLER);
}
}
}
if (contextText != null) {
contextText = " " + contextText;
text.append(contextText, StyledString.DECORATIONS_STYLER);
}
if (countText != null) {
countText = " " + countText;
text.append(countText, StyledString.QUALIFIER_STYLER);
}
cell.setText(text.toString());
cell.setStyleRanges(text.getStyleRanges());
Color foreground = getForeground(cell.getElement());
cell.setForeground(foreground);
Color background = getBackground(cell.getElement());
cell.setBackground(background);
super.update(cell);
}
use of eu.esdihumboldt.hale.common.schema.model.ChildDefinition in project hale by halestudio.
the class Pattern method match.
/**
* Matches the type against the encoding pattern.
*
* @param type the type definition
* @param path the definition path
* @param gmlNs the GML namespace
* @param checkedTypes the type definitions that have already been checked
* (to prevent cycles)
* @param remainingElements the remaining elements to match
*
* @return the new path if there is a match, <code>null</code> otherwise
*/
private static DefinitionPath match(TypeDefinition type, DefinitionPath path, String gmlNs, HashSet<TypeDefinition> checkedTypes, List<PatternElement> remainingElements) {
if (remainingElements == null || remainingElements.isEmpty()) {
return null;
}
if (checkedTypes.contains(type)) {
return null;
} else {
checkedTypes.add(type);
}
PatternElement first = remainingElements.get(0);
PatternElement checkAgainst;
boolean allowAttributeDescent;
boolean removeFirstForAttributeDescent = false;
boolean allowSubtypeDescent = true;
switch(first.getType()) {
case ONE_ELEMENT:
// only descend
checkAgainst = null;
allowAttributeDescent = true;
// first element may not be
removeFirstForAttributeDescent = true;
// special case: was last element
if (remainingElements.size() == 1) {
return path;
}
break;
case ANY_ELEMENTS:
// check against the next named element
PatternElement named = null;
for (int i = 1; i < remainingElements.size() && named == null; i++) {
PatternElement element = remainingElements.get(i);
if (element.getType().equals(ElementType.NAMED_ELEMENT)) {
named = element;
}
}
if (named == null) {
// no named element
return null;
} else {
checkAgainst = named;
}
allowAttributeDescent = true;
break;
case NAMED_ELEMENT:
// check the current
checkAgainst = first;
// only allow sub-type descent
allowAttributeDescent = false;
break;
default:
// $NON-NLS-1$
throw new IllegalStateException("Unknown pattern element type");
}
if (checkAgainst != null) {
// get the last path element
QName elementName = path.getLastName();
QName name = checkAgainst.getName();
// inject namespace if needed
if (name.getNamespaceURI() == GML_NAMESPACE_PLACEHOLDER) {
name = new QName(gmlNs, name.getLocalPart());
}
// check direct match
if (name.equals(elementName)) {
// match for the element name -> we are on the right track
int index = remainingElements.indexOf(checkAgainst);
if (index == remainingElements.size() - 1) {
// is last - we have a full match
return path;
}
// remove the element (and any leading wildcards) from the queue
remainingElements = remainingElements.subList(index + 1, remainingElements.size());
// for a name match, no sub-type descent is allowed
allowSubtypeDescent = false;
// but an attribute descent is ok
allowAttributeDescent = true;
} else {
// no name match
// sub-type descent is still allowed, don't remove element
}
}
if (allowSubtypeDescent) {
// step down sub-types
// XXX now represented in choices
// XXX sub-type must work through parent choice
// for (SchemaElement element : type.getSubstitutions(path.getLastName())) {
// DefinitionPath candidate = match(
// element.getType(),
// new DefinitionPath(path).addSubstitution(element),
// gmlNs,
// new HashSet<TypeDefinition>(checkedTypes),
// new ArrayList<PatternElement>(remainingElements));
//
// if (candidate != null) {
// return candidate;
// }
// }
}
if (allowAttributeDescent) {
if (removeFirstForAttributeDescent) {
remainingElements.remove(0);
}
// step down properties
@java.lang.SuppressWarnings("unchecked") Iterable<ChildDefinition<?>> children = (Iterable<ChildDefinition<?>>) ((path.isEmpty()) ? (type.getChildren()) : (type.getDeclaredChildren()));
Iterable<DefinitionPath> childPaths = GmlWriterUtil.collectPropertyPaths(children, path, true);
for (DefinitionPath childPath : childPaths) {
DefinitionPath candidate = match(childPath.getLastType(), childPath, gmlNs, new HashSet<TypeDefinition>(checkedTypes), new ArrayList<PatternElement>(remainingElements));
if (candidate != null) {
return candidate;
}
}
}
return null;
}
use of eu.esdihumboldt.hale.common.schema.model.ChildDefinition in project hale by halestudio.
the class TypeStructureTray method createSourceSample.
/**
* Create sample code for a single tree path specifying a source property.
*
* @param path the tree path
* @param types the types serving as input
* @return the sample code or <code>null</code>
*/
private String createSourceSample(TreePath path, Collection<? extends TypeDefinition> types) {
DefinitionGroup parent;
int startIndex = 0;
boolean hasPropDef = false;
StringBuilder access = new StringBuilder();
// determine parent type
if (path.getFirstSegment() instanceof TypeDefinition) {
// types are the top level elements
parent = (DefinitionGroup) path.getFirstSegment();
startIndex = 1;
access.append(GroovyConstants.BINDING_SOURCE);
} else {
// types are not in the tree, single type must be root
TypeDefinition type = types.iterator().next();
parent = type;
if (VARIABLES_TYPE_NAME.equals(type.getName())) {
// Groovy property transformation
// first segment is variable name
Definition<?> def = (Definition<?>) path.getFirstSegment();
startIndex++;
access.append(def.getName().getLocalPart());
// XXX add namespace if necessary
// XXX currently groovy transformation does not support multiple
// variables with the same name
parent = DefinitionUtil.getDefinitionGroup(def);
} else {
// assuming Retype/Merge
access.append(GroovyConstants.BINDING_SOURCE);
}
}
// is a property or list of inputs referenced -> use accessor
boolean propertyOrList = path.getSegmentCount() > startIndex || (path.getLastSegment() instanceof ChildDefinition<?> && canOccureMultipleTimes((ChildDefinition<?>) path.getLastSegment()));
if (!propertyOrList) {
if (parent instanceof TypeDefinition && canHaveValue((TypeDefinition) parent)) {
if (!DefinitionUtil.hasChildren((Definition<?>) path.getLastSegment())) {
// variable w/o children referenced
return "// access variable\ndef value = " + access;
} else {
// variable w/ children referenced
return "// access instance variable value\ndef value = " + access + ".value";
}
} else {
// return null;
}
}
if (path.getFirstSegment() instanceof TypeDefinition) {
access.append(".links." + ((TypeDefinition) path.getFirstSegment()).getDisplayName());
} else {
access.append(".p");
// check for encountering property definition, so that there should
// not be 2 'p's appended.
hasPropDef = true;
}
for (int i = startIndex; i < path.getSegmentCount(); i++) {
Definition<?> def = (Definition<?>) path.getSegment(i);
if (def instanceof PropertyDefinition) {
for (int j = i - 1; j >= 0; j--) {
Definition<?> def1 = (Definition<?>) path.getSegment(j);
if (def1 instanceof TypeDefinition) {
// do nothing
} else {
hasPropDef = true;
}
}
if (!hasPropDef) {
access.append(".p");
}
// property name
access.append('.');
access.append(def.getName().getLocalPart());
// test if uniquely accessible from parent
boolean useNamespace = true;
if (parent instanceof Definition<?>) {
useNamespace = namespaceNeeded((Definition<?>) parent, def);
}
// add namespace if necessary
if (useNamespace) {
access.append("('");
access.append(def.getName().getNamespaceURI());
access.append("')");
}
} else if (def instanceof TypeDefinition) {
access.append("." + ((TypeDefinition) def).getDisplayName());
}
// set the new parent
parent = DefinitionUtil.getDefinitionGroup(def);
}
if (parent instanceof TypeDefinition) {
// only properties at the end of the path are supported
TypeDefinition propertyType = (TypeDefinition) parent;
StringBuilder example = new StringBuilder();
boolean canOccurMultipleTimes = false;
if (path.getFirstSegment() instanceof TypeDefinition) {
canOccurMultipleTimes = true;
}
/*
* Instances/values may occur multiple times if any element in the
* path may occur multiple times.
*/
for (int i = path.getSegmentCount() - 1; i >= 0 && !canOccurMultipleTimes; i--) {
if (path.getSegment(i) instanceof ChildDefinition<?>) {
canOccurMultipleTimes = canOccureMultipleTimes((ChildDefinition<?>) path.getSegment(i));
}
}
if (canHaveValue(propertyType)) {
// single value
if (canOccurMultipleTimes) {
example.append("// access first value\n");
} else {
example.append("// access value\n");
}
example.append("def value = ");
example.append(access);
example.append(".value()\n\n");
// multiple values
if (canOccurMultipleTimes) {
example.append("// access all values as list\n");
example.append("def valueList = ");
example.append(access);
example.append(".values()\n\n");
}
}
if (DefinitionUtil.hasChildren(propertyType)) {
// single instance
if (canOccurMultipleTimes) {
example.append("// access first instance\n");
} else {
example.append("// access instance\n");
}
example.append("def instance = ");
example.append(access);
example.append(".first()\n\n");
if (canOccurMultipleTimes) {
// multiple values
example.append("// access all instances as list\n");
example.append("def instanceList = ");
example.append(access);
example.append(".list()\n\n");
// iterate over instances
example.append("// iterate over instances\n");
example.append(access);
example.append(".each {\n");
example.append("\tinstance ->\n");
example.append("}\n\n");
}
} else if (canOccurMultipleTimes && propertyType.getConstraint(HasValueFlag.class).isEnabled()) {
// iterate over values
example.append("// iterate over values\n");
example.append(access);
example.append(".each {\n");
example.append("\tvalue ->\n");
example.append("}\n\n");
}
return example.toString();
}
return null;
}
Aggregations