| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.validation.client.impl; |
| |
| import com.google.gwt.validation.client.impl.metadata.ValidationGroupsMetadata; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.validation.GroupDefinitionException; |
| import javax.validation.ValidationException; |
| |
| /** |
| * Helper class used to resolve groups and sequences into a single chain of groups which can then |
| * be validated. |
| * <p> |
| * Modified from the Hibernate validator for use with GWT. |
| */ |
| public class GroupChainGenerator { |
| private final ValidationGroupsMetadata validationGroupsMetadata; |
| |
| private final Map<Class<?>, List<Group>> resolvedSequences = new HashMap<Class<?>, List<Group>>(); |
| |
| public GroupChainGenerator(ValidationGroupsMetadata validationGroupsMetadata) { |
| this.validationGroupsMetadata = validationGroupsMetadata; |
| } |
| |
| /** |
| * Generates a chain of groups to be validated given the specified validation groups. |
| * |
| * @param groups The groups specified at the validation call. |
| * |
| * @return an instance of {@code GroupChain} defining the order in which validation has to occur. |
| */ |
| public GroupChain getGroupChainFor(Collection<Class<?>> groups) { |
| if (groups == null || groups.size() == 0) { |
| throw new IllegalArgumentException("At least one group has to be specified."); |
| } |
| |
| for (Class<?> clazz : groups) { |
| if (!validationGroupsMetadata.containsGroup(clazz) |
| && !validationGroupsMetadata.isSeqeuence(clazz)) { |
| throw new ValidationException("The class " + clazz + " is not a valid group or sequence."); |
| } |
| } |
| |
| GroupChain chain = new GroupChain(); |
| for (Class<?> clazz : groups) { |
| if (isGroupSequence(clazz)) { |
| insertSequence(clazz, chain); |
| } |
| else { |
| Group group = new Group(clazz); |
| chain.insertGroup(group); |
| insertInheritedGroups(clazz, chain); |
| } |
| } |
| |
| return chain; |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append("GroupChainGenerator"); |
| sb.append("{resolvedSequences=").append(resolvedSequences); |
| sb.append('}'); |
| return sb.toString(); |
| } |
| |
| private void addGroups(List<Group> resolvedGroupSequence, List<Group> groups) { |
| for (Group tmpGroup : groups) { |
| if (resolvedGroupSequence.contains(tmpGroup) |
| && resolvedGroupSequence.indexOf(tmpGroup) < resolvedGroupSequence.size() - 1) { |
| throw new GroupDefinitionException("Unable to expand group sequence."); |
| } |
| resolvedGroupSequence.add(tmpGroup); |
| } |
| } |
| |
| private void addInheritedGroups(Group group, List<Group> expandedGroups) { |
| Set<Class<?>> inheritedGroups = validationGroupsMetadata.getParentsOfGroup(group.getGroup()); |
| if (inheritedGroups != null) { |
| for (Class<?> inheritedGroup : inheritedGroups) { |
| if (isGroupSequence(inheritedGroup)) { |
| throw new GroupDefinitionException("Sequence definitions are not allowed as composing " + |
| "parts of a sequence."); |
| } |
| Group g = new Group(inheritedGroup, group.getSequence()); |
| expandedGroups.add(g); |
| addInheritedGroups(g, expandedGroups); |
| } |
| } |
| } |
| |
| private List<Group> expandInhertitedGroups(List<Group> sequence) { |
| List<Group> expandedGroup = new ArrayList<Group>(); |
| for (Group group : sequence) { |
| expandedGroup.add(group); |
| addInheritedGroups(group, expandedGroup); |
| } |
| return expandedGroup; |
| } |
| |
| /** |
| * Recursively add inherited groups into the group chain. |
| * |
| * @param clazz The group interface |
| * @param chain The group chain we are currently building. |
| */ |
| private void insertInheritedGroups(Class<?> clazz, GroupChain chain) { |
| for (Class<?> inheritedGroup : validationGroupsMetadata.getParentsOfGroup(clazz)) { |
| Group group = new Group(inheritedGroup); |
| chain.insertGroup(group); |
| insertInheritedGroups(inheritedGroup, chain); |
| } |
| } |
| |
| private void insertSequence(Class<?> clazz, GroupChain chain) { |
| List<Group> sequence; |
| if (resolvedSequences.containsKey(clazz)) { |
| sequence = resolvedSequences.get(clazz); |
| } else { |
| sequence = resolveSequence(clazz, new ArrayList<Class<?>>()); |
| // we expand the inherited groups only after we determined whether the sequence is expandable |
| sequence = expandInhertitedGroups(sequence); |
| } |
| chain.insertSequence(sequence); |
| } |
| |
| private boolean isGroupSequence(Class<?> clazz) { |
| return validationGroupsMetadata.isSeqeuence(clazz); |
| } |
| |
| private List<Group> resolveSequence(Class<?> group, List<Class<?>> processedSequences) { |
| if (processedSequences.contains(group)) { |
| throw new GroupDefinitionException("Cyclic dependency in groups definition"); |
| } else { |
| processedSequences.add(group); |
| } |
| List<Group> resolvedGroupSequence = new ArrayList<Group>(); |
| List<Class<?>> sequenceList = validationGroupsMetadata.getSequenceList(group); |
| for (Class<?> clazz : sequenceList ) { |
| if (isGroupSequence(clazz)) { |
| List<Group> tmpSequence = resolveSequence(clazz, processedSequences); |
| addGroups(resolvedGroupSequence, tmpSequence); |
| } |
| else { |
| List<Group> list = new ArrayList<Group>(); |
| list.add(new Group(clazz, group)); |
| addGroups(resolvedGroupSequence, list); |
| } |
| } |
| resolvedSequences.put(group, resolvedGroupSequence); |
| return resolvedGroupSequence; |
| } |
| } |