/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.common.schema.model; import java.util.ArrayList; import java.util.Collection; import javax.xml.namespace.QName; import eu.esdihumboldt.hale.common.schema.model.constraint.property.Cardinality; import eu.esdihumboldt.hale.common.schema.model.impl.internal.RedeclareGroupProperty; import eu.esdihumboldt.hale.common.schema.model.impl.internal.RedeclareProperty; import eu.esdihumboldt.hale.common.schema.model.impl.internal.ReparentGroupProperty; import eu.esdihumboldt.hale.common.schema.model.impl.internal.ReparentProperty; /** * Definition utility methods * * @author Simon Templer */ public abstract class DefinitionUtil { /** * Create a proxy for the given child with another parent * * @param child the child * @param newParent the new parent type * @return the reparented child definition */ public static ChildDefinition<?> reparentChild(ChildDefinition<?> child, TypeDefinition newParent) { if (child.asProperty() != null) { return new ReparentProperty(child.asProperty(), newParent); } else if (child.asGroup() != null) { return new ReparentGroupProperty(child.asGroup(), newParent); } else { throw new IllegalStateException("Illegal child type."); } } /** * Create a proxy for the given child with another declaring group * * @param child the child * @param newParent the new declaring group * @return the redeclared child definition */ public static ChildDefinition<?> redeclareChild(ChildDefinition<?> child, DefinitionGroup newParent) { if (child.asProperty() != null) { return new RedeclareProperty(child.asProperty(), newParent); } else if (child.asGroup() != null) { return new RedeclareGroupProperty(child.asGroup(), newParent); } else { throw new IllegalStateException("Illegal child type."); } } /** * Get all children of a definition group. For {@link TypeDefinition} also * the inherited children will be returned. * * @param group the definition group * @return the children */ public static Collection<? extends ChildDefinition<?>> getAllChildren(DefinitionGroup group) { if (group instanceof TypeDefinition) { return ((TypeDefinition) group).getChildren(); } else { return group.getDeclaredChildren(); } } /** * Get all properties of a definition group. For {@link TypeDefinition} also * the inherited children will be returned. If there are children that are * groups, their properties are also added. * * @param group the definition group * @return the children */ public static Collection<? extends PropertyDefinition> getAllProperties(DefinitionGroup group) { Collection<PropertyDefinition> result = new ArrayList<PropertyDefinition>(); for (ChildDefinition<?> child : getAllChildren(group)) { if (child.asProperty() != null) { result.add(child.asProperty()); } else { result.addAll(getAllProperties(child.asGroup())); } } return result; } /** * Get the cardinality of a child definition. * * @param child the child definition * @return the cardinality */ public static Cardinality getCardinality(ChildDefinition<?> child) { if (child.asProperty() != null) { return child.asProperty().getConstraint(Cardinality.class); } if (child.asGroup() != null) { return child.asGroup().getConstraint(Cardinality.class); } throw new IllegalStateException("Illegal child type."); } /** * Returns the child definition of definition with the given name. * * @param definition the definition * @param name the name of the child * @return the child with the given name of the given definition, or * <code>null</code> if it doesn't exist * @throws IllegalStateException if the given definition isn't group nor * property nor type definition */ public static ChildDefinition<?> getChild(Definition<?> definition, QName name) { if (definition instanceof DefinitionGroup) { return ((DefinitionGroup) definition).getChild(name); } if (definition instanceof ChildDefinition<?>) { return getChild((ChildDefinition<?>) definition, name); } throw new IllegalStateException("Illegal definition."); } /** * Returns the child definition of definition with the given name. * * @param definition the definition * @param name the name of the child * @return the child with the given name of the given definition, or * <code>null</code> if it doesn't exist * @throws IllegalStateException if the given definition isn't group nor * property definition */ public static ChildDefinition<?> getChild(ChildDefinition<?> definition, QName name) { if (definition.asGroup() != null) return definition.asGroup().getChild(name); if (definition.asProperty() != null) return definition.asProperty().getPropertyType().getChild(name); throw new IllegalStateException("Illegal child definition."); } /** * Returns the child definition of definition with the given name. * * @param definition the definition * @param name the name of the child * @param allowIgnoreNamespace specifies if when the child with the exact * name is not present, a child with a similar local name should * be returned * @return the child with the given name if it exists, a child with a * similar local name if it exists or <code>null</code> * @throws IllegalStateException if the given definition isn't group nor * property definition */ public static ChildDefinition<?> getChild(ChildDefinition<?> definition, QName name, boolean allowIgnoreNamespace) { ChildDefinition<?> result = getChild(definition, name); if (result != null || !allowIgnoreNamespace) { return result; } // get all children Collection<? extends ChildDefinition<?>> children = DefinitionUtil .getAllChildren((definition.asGroup() != null) ? (definition.asGroup()) : (definition.asProperty().getPropertyType())); int rating = 0; for (ChildDefinition<?> child : children) { if (name.getLocalPart().equals(child.getName().getLocalPart())) { // same local name int childRating = namespaceEqualityRating(child.getName().getNamespaceURI(), name.getNamespaceURI()); if (result == null || childRating > rating) { result = child; rating = childRating; } } } return result; } /** * Determine a rating on namespace equality. * * @param ns1 the first namespace to compare * @param ns2 the second namespace to compare * @return the equality rating, the higher the more equal/compatible are the * namespaces */ private static int namespaceEqualityRating(String ns1, String ns2) { // we define the rating as how many characters are equal from the start int count; int commonLength = Math.min(ns1.length(), ns2.length()); for (count = 0; count < commonLength && ns1.charAt(count) == ns2.charAt(count); count++) { // counts up while the chars are equal } return count; } /** * Get the represented definition group of a definition. * * @param def the definition * @return for a property definition its property type, for a type * definition or a group property definition the definition itself */ public static DefinitionGroup getDefinitionGroup(Definition<?> def) { if (def instanceof TypeDefinition) { return (TypeDefinition) def; } if (def instanceof PropertyDefinition) { return ((PropertyDefinition) def).getPropertyType(); } if (def instanceof GroupPropertyDefinition) { return (GroupPropertyDefinition) def; } throw new IllegalStateException("Illegal definition type encountered"); } /** * Determines if the given definition may have children. * * @param def the definition * @return if the definition may have children */ public static boolean hasChildren(Definition<?> def) { return !getAllChildren(getDefinitionGroup(def)).isEmpty(); } /** * Checks whether <code>superType</code> is a super type of * <code>subType</code> or if they are the same. * * @param subType the type in question * @param superType the super type * @return whether superType is a super type of subType or they are the same * type */ public static boolean isSuperType(TypeDefinition subType, TypeDefinition superType) { do { if (subType.equals(superType)) return true; subType = subType.getSuperType(); } while (subType != null); return false; } /** * Checks whether two definitions are equal.<br> * <br> * The result is * <ul> * <li>{@code true} if {@code a} and {@code b} are both null. * <li>{@code true} if {@code a} and {@code b} are both non-null, their * names are equal and both are of the same: {@link TypeDefinition}, * {@link PropertyDefinition}, {@link GroupPropertyDefinition} or exactly * the same class. * <li>{@code false} in all other situations. * </ul> * * @param a the first definition * @param b the second definition * @return whether the definitions equal each other */ public static boolean equal(Definition<?> a, Definition<?> b) { if (a == null || b == null) return a == b; if (!a.getName().equals(b.getName())) return false; return (a instanceof TypeDefinition && b instanceof TypeDefinition) || (a instanceof PropertyDefinition && b instanceof PropertyDefinition) || (a instanceof GroupPropertyDefinition && b instanceof GroupPropertyDefinition) || a.getClass().equals(b.getClass()); } }