001 package org.apache.commons.contract.constraints;
002
003 import java.util.ArrayList;
004 import java.util.HashMap;
005 import java.util.Iterator;
006 import java.util.List;
007 import java.util.Map;
008
009 import org.apache.commons.contract.Context;
010 import org.apache.commons.contract.descriptor.ParameterDescriptor;
011 import org.apache.commons.contract.i18n.ParameterBundle;
012 import org.apache.commons.i18n.bundles.ErrorBundle;
013 import org.apache.commons.i18n.bundles.TextBundle;
014
015 public class MapConstraints implements Constraints {
016 public final static MapConstraints UNCONSTRAINED = new MapConstraints(new ParameterDescriptor(MapConstraints.ALL, new ParameterBundle("mapEntry/any"), Unconstrained.UNCONSTRAINED));
017 public final static String ALL = "*";
018
019 protected List entryConstraints = new ArrayList();
020
021 public MapConstraints() {
022 }
023
024 public MapConstraints(List entryDescriptors) {
025 this.entryConstraints = entryDescriptors;
026 }
027
028 public MapConstraints(ParameterDescriptor parameterDescriptor) {
029 entryConstraints.add(parameterDescriptor);
030 }
031
032 public MapConstraints(ParameterDescriptor[] parameterDescriptors) {
033 for ( int i = 0; i < parameterDescriptors.length; i++ ) {
034 entryConstraints.add(parameterDescriptors[i]);
035 }
036 }
037
038 public void addEntryDescriptor(ParameterDescriptor parameterDescriptor) {
039 entryConstraints.add(parameterDescriptor);
040 }
041
042 public List getEntryDescriptors() {
043 return entryConstraints;
044 }
045
046 public Object cast(Object value, Context context) throws CastException {
047 if ( entryConstraints.isEmpty() ) {
048 throw new CastException(new ErrorBundle("noMapEntryDescriptorsFound"));
049 }
050 if ( value instanceof Map ) {
051 return castedMap((Map)value, context);
052 } else if ( value instanceof Map ) {
053 return castedMap((Map)value, context);
054 } else {
055 throw new CastException(new ErrorBundle("uncastableMapValue", new Object[] { value }));
056 }
057 }
058
059 protected Map castedMap(Map map, Context context) throws CastException {
060 Map castedMap = new HashMap(map);
061 for ( Iterator i = entryConstraints.iterator(); i.hasNext(); ) {
062 ParameterDescriptor parameterDescriptor = (ParameterDescriptor)i.next();
063 Constraints entryDescriptor = parameterDescriptor.getConstraints();
064 String key = parameterDescriptor.getName();
065 if ( key.equals(ALL) ) {
066 for ( Iterator j = castedMap.entrySet().iterator(); j.hasNext(); ) {
067 Map.Entry entry = (Map.Entry)j.next();
068 Object value = entry.getValue();
069 if ( value instanceof Evaluatable ) {
070 try {
071 value = ((Evaluatable)value).evaluate(context);
072 } catch (Exception e) {
073 throw new CastException(new ErrorBundle("evaluatingAnyFailed"), e);
074 }
075 }
076 castedMap.put(entry.getKey(), entryDescriptor.cast(value, context));
077 }
078 } else {
079 if ( !castedMap.containsKey(key) ) {
080 if ( !parameterDescriptor.isRequired() ) {
081 castedMap.put(key, parameterDescriptor.getDefaultValue());
082 }
083 } else {
084 Object object = castedMap.get(key);
085 if ( object == null && parameterDescriptor.getDefaultValue() == null || object.equals(parameterDescriptor.getDefaultValue())) {
086 castedMap.put(key, object);
087 } else {
088 if ( object instanceof Evaluatable ) {
089 try {
090 object = ((Evaluatable)object).evaluate(context);
091 } catch (Exception e) {
092 throw new CastException(new ErrorBundle("evaluatingAnyFailed"), e);
093 }
094 }
095 castedMap.put(key, entryDescriptor.cast(object, context));
096 }
097 }
098 }
099 }
100 return castedMap;
101 }
102
103 public void validate(Object value, Context context) throws ValidationException {
104 Map map = (Map)value;
105 for ( Iterator i = entryConstraints.iterator(); i.hasNext(); ) {
106 ParameterDescriptor parameterDescriptor = (ParameterDescriptor)i.next();
107 Constraints entryDescriptor = parameterDescriptor.getConstraints();
108 String key = parameterDescriptor.getName();
109 if ( key.equals(ALL) ) {
110 for ( Iterator j = map.values().iterator(); j.hasNext(); ) {
111 Object entryValue = j.next();
112 if ( entryValue != null ) {
113 entryDescriptor.validate(entryValue, context);
114 }
115 }
116 } else {
117 if ( !map.containsKey(key) ) {
118 if ( parameterDescriptor.isRequired() ) {
119 throw new ValidationException(new ErrorBundle("mapEntryMissing", new String[] { key }));
120 }
121 } else {
122 Object entryValue = map.get(key);
123 if ( entryValue != null ) {
124 entryDescriptor.validate(entryValue, context);
125 }
126 }
127 }
128 }
129 }
130
131 public TextBundle verboseConstraints() {
132 if ( entryConstraints.isEmpty() ) {
133 return new TextBundle("invalidMapConstraints");
134 }
135 return new TextBundle("unconstrainedMap");
136 }
137
138 }