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 }