/* * 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.io.gml.reader.internal.instance; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import java.util.ArrayList; import java.util.List; import java.util.Stack; import javax.xml.namespace.QName; import eu.esdihumboldt.hale.common.instance.model.MutableGroup; import eu.esdihumboldt.hale.common.instance.model.impl.DefaultGroup; import eu.esdihumboldt.hale.common.schema.model.ChildDefinition; import eu.esdihumboldt.hale.common.schema.model.DefinitionGroup; import eu.esdihumboldt.hale.common.schema.model.GroupPropertyDefinition; import eu.esdihumboldt.hale.common.schema.model.constraint.property.ChoiceFlag; /** * Represents a path of groups in two parts, the existing parent * {@link MutableGroup}s and the non-existent children represented by a * {@link DefinitionGroup} * * @author Simon Templer */ public class GroupPath { private final List<MutableGroup> parents; private final List<DefinitionGroup> children; /** * Create a group path * * @param parents the list of parent groups, may neither be * <code>null</code> nor empty * @param children the list of child definition groups, may be * <code>null</code> */ public GroupPath(List<MutableGroup> parents, List<DefinitionGroup> children) { super(); checkNotNull(parents); checkArgument(!parents.isEmpty()); this.parents = parents; this.children = children; } /** * @return the parents */ public List<MutableGroup> getParents() { return parents; } /** * @return the children, may be <code>null</code> */ public List<DefinitionGroup> getChildren() { return children; } /** * Create groups for the children in the path (which are only represented as * definitions). May only be called if the path is valid. This will also * update the path to include the groups instead of the definitions. * * @return the list of created groups * * @see #isValid() */ protected List<MutableGroup> createChildGroups() { MutableGroup parent = parents.get(parents.size() - 1); final List<MutableGroup> result = new ArrayList<MutableGroup>(); for (DefinitionGroup child : children) { checkState(child instanceof GroupPropertyDefinition); // create group MutableGroup group = new DefaultGroup(child); // add to parent QName propertyName = ((GroupPropertyDefinition) child).getName(); parent.addProperty(propertyName, group); // add to result result.add(group); // prepare for next iteration parent = group; } // update children and parents children.clear(); parents.addAll(result); return result; } /** * Determines if the group path in this configuration is valid in respect to * the creation of new groups based on the contained definition groups. * * @return if the path is valid */ public boolean isValid() { if (children == null || children.isEmpty()) { return true; // parents is assumed to be valid } MutableGroup parentGroup = parents.get(parents.size() - 1); DefinitionGroup parentDef = parentGroup.getDefinition(); for (DefinitionGroup child : children) { if (child instanceof GroupPropertyDefinition) { if (!GroupUtil.allowAdd(parentGroup, parentDef, ((GroupPropertyDefinition) child).getName())) { return false; } } else { // XXX TypeDefinitions not supported in path return false; } // prepare next iteration parentGroup = null; parentDef = child; } return true; } /** * Determines if the adding a property value for the given property to the * last element in the path is allowed. * * @param propertyName the property name * @param strict states if additional checks are applied apart from whether * the property exists * @param ignoreNamespaces if a property with a differing namespace may be * accepted * @return if adding the property value to the last element in the path is * allowed */ public boolean allowAdd(QName propertyName, boolean strict, boolean ignoreNamespaces) { if (children == null || children.isEmpty()) { // check last parent MutableGroup parent = parents.get(parents.size() - 1); ChildDefinition<?> child = GroupUtil.findChild(parent.getDefinition(), propertyName, ignoreNamespaces); if (child.asProperty() != null) { return !strict || GroupUtil.allowAdd(parent, null, child.asProperty().getName()); } else { return false; } } else { // check last child DefinitionGroup child = children.get(children.size() - 1); ChildDefinition<?> property = GroupUtil .findChild(child, propertyName, ignoreNamespaces); if (property == null) { return false; } if (child instanceof GroupPropertyDefinition && ((GroupPropertyDefinition) child).getConstraint(ChoiceFlag.class) .isEnabled()) { // group is a choice return true; } return !strict || GroupUtil.allowAdd(null, child, property.getName()); } } /** * Get the last definition group in the path * * @return the last definition group */ public DefinitionGroup getLastDefinition() { if (children != null && !children.isEmpty()) { return children.get(children.size() - 1); } return parents.get(parents.size() - 1).getDefinition(); } /** * Get the last group in the path.<br> * <br> * Will create the child groups for which only definitions are present and * update the path accordingly before getting the last group object. * * @param strict if the path should be checked for validity * @return the last group in the path * @throws IllegalStateException if the path is not valid */ public MutableGroup getLast(boolean strict) throws IllegalStateException { return getAllGroups(strict).peek(); } /** * Get all groups in the path.<br> * <br> * Will create the child groups for which only definitions are present and * update the path accordingly before returning all group objects. * * @param strict if the path should be checked for validity * @return the all groups in the path * @throws IllegalStateException if the path is not valid */ public Stack<MutableGroup> getAllGroups(boolean strict) throws IllegalStateException { if (children != null && !children.isEmpty()) { if (strict && !isValid()) { throw new IllegalStateException("Attempt to create groups in an invalid path."); } createChildGroups(); } Stack<MutableGroup> result = new Stack<MutableGroup>(); result.addAll(parents); return result; } }