001    /*
002     * Copyright 2002-2004 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.rules.constraint.property;
017    
018    import java.util.Collection;
019    import java.util.HashMap;
020    import java.util.Iterator;
021    import java.util.Map;
022    
023    import org.springframework.binding.MutablePropertyAccessStrategy;
024    import org.springframework.binding.support.BeanPropertyAccessStrategy;
025    import org.springframework.rules.constraint.AbstractConstraint;
026    
027    public class UniquePropertyValueConstraint extends AbstractConstraint implements PropertyConstraint {
028            private String propertyName;
029    
030            private Map distinctValueTable;
031    
032            public UniquePropertyValueConstraint(String propertyName) {
033                    this.propertyName = propertyName;
034            }
035    
036            public String getPropertyName() {
037                    return propertyName;
038            }
039    
040            public boolean isDependentOn(String propertyName) {
041                    return getPropertyName().equals(propertyName);
042            }
043            
044            public boolean isCompoundRule() {
045                    return false;
046            }
047    
048    
049            /**
050             * Returns <code>true</code> if each domain object in the provided collection has a unique
051             * value for the configured property.
052             */
053            public boolean test(Object o) {
054                    Collection domainObjects = (Collection)o;
055                    distinctValueTable = new HashMap((int)(domainObjects.size() * .75));
056                    Iterator it = domainObjects.iterator();
057                    MutablePropertyAccessStrategy accessor = null;
058                    while (it.hasNext()) {
059                            Object domainObject = it.next();
060                            if (accessor == null) {
061                                    accessor = createPropertyAccessStrategy(domainObject);
062                            }
063                            else {
064                                    accessor.getDomainObjectHolder().setValue(domainObject);
065                            }
066                            Object propertyValue = accessor.getPropertyValue(propertyName);
067                            Integer hashCode;
068                            if (propertyValue == null) {
069                                    hashCode = new Integer(0);
070                            }
071                            else {
072                                    hashCode = new Integer(propertyValue.hashCode());
073                            }
074                            if (distinctValueTable.containsKey(hashCode)) {
075                                    return false;
076                            }
077    
078                distinctValueTable.put(hashCode, propertyValue);
079                    }
080                    return true;
081            }
082    
083            protected MutablePropertyAccessStrategy createPropertyAccessStrategy(Object o) {
084                    return new BeanPropertyAccessStrategy(o);
085            }
086    
087    }