View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.api.engine;
17  
18  import java.io.Serializable;
19  import java.util.Collections;
20  import java.util.Comparator;
21  import java.util.Iterator;
22  import java.util.Map;
23  import java.util.Map.Entry;
24  import java.util.TreeMap;
25  
26  import org.springframework.util.CollectionUtils;
27  
28  /**
29   * Identifies a (hopefully) resolvable {@link Term}.  For resolution in the {@link TermResolutionEngine}, The
30   * appropriate {@link TermResolver} will be selected by matching the name and parameters of the {@link Term} with
31   * the output and parameter names of the {@link TermResolver}. 
32   * @author gilesp
33   *
34   */
35  public final class Term implements Comparable<Term> {
36  
37  	private final String name;
38  	
39  	private final Map<String, String> parameters;
40  	
41  	private static final TreeMapComparator<String,String> treeMapComparator = new TreeMapComparator<String, String>();
42  
43  	public Term(String name) {
44  		this(name, null);
45  	}	
46  	
47  	/**
48  	 * This constructs a Term, which is a named piece of data that is usually obtainable
49  	 * through the {@link TermResolutionEngine}
50  	 *
51       * @param name
52       * @param parameters an optional map of properties that may be used to allow a single TermResolver to resolve multiple Terms
53       */
54  	public Term(String name, Map<String, String> parameters) {
55  		this.name = name;
56  		if (parameters == null) {
57  			this.parameters = Collections.emptyMap();
58  		} else {
59  			// using TreeMap for ordered iteration since we're comparable
60  			this.parameters = Collections.unmodifiableMap(new TreeMap<String, String>(parameters));
61  		}
62  	}
63  	
64  	public String getName() { return this.name; }
65  	public Map<String, String> getProperties() { return parameters; }
66  
67  	/* (non-Javadoc)
68  	 * @see java.lang.Object#hashCode()
69  	 */
70  	@Override
71  	public int hashCode() {
72  		final int prime = 31;
73  		int result = 1;
74  		result = prime * result + ((name == null) ? 0 : name.hashCode());
75  		result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
76  		return result;
77  	}
78  
79  	/* (non-Javadoc)
80  	 * @see java.lang.Object#equals(java.lang.Object)
81  	 */
82  	@Override
83  	public boolean equals(Object obj) {
84  		if (this == obj)
85  			return true;
86  		if (obj == null)
87  			return false;
88  		if (getClass() != obj.getClass())
89  			return false;
90  		Term other = (Term) obj;
91  		return this.compareTo(other) == 0;
92  	}
93  
94  	@Override
95  	public int compareTo(Term o) {
96  		if (o == null) return 1;
97  		if (this == o) return 0;
98  		return (treeMapComparator.compare(this.parameters, o.parameters));
99  	}
100 	
101 	/**
102 	 * @return an unmodifiable Map of parameters specified on this Term.  Guaranteed non-null.
103 	 */
104 	public Map<String, String> getParameters() {
105 		return Collections.unmodifiableMap(parameters);
106 	}
107 
108 	@Override
109 	public String toString() {
110 		// TODO make this pretty
111 		StringBuilder sb = new StringBuilder();
112 		if (parameters != null) for (Entry<String,String> parameter : parameters.entrySet()) {
113 			sb.append(", ");
114 			sb.append(parameter.getKey());
115 			sb.append("=");
116 			sb.append(parameter.getValue());
117 		}
118 		return getClass().getSimpleName()+"(["+ name + "]" +  sb.toString() + ")";
119 	}
120 	
121 	@SuppressWarnings("rawtypes")
122 	private static class TreeMapComparator<T extends Comparable, V extends Comparable> implements Comparator<Map<T,V>>, Serializable {
123 		
124 		private static final long serialVersionUID = 1L;
125 
126 		/**
127 		 * This overridden method compares two {@link TreeMap}s whose keys and elements are both {@link Comparable}
128 		 * 
129 		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
130 		 */
131 		@SuppressWarnings("unchecked")
132 		public int compare(Map<T,V> o1, Map<T,V> o2) {
133 			if (CollectionUtils.isEmpty(o1)) {
134 				if (CollectionUtils.isEmpty(o2)) return 0;
135 				return -1;
136 			} else if (CollectionUtils.isEmpty(o2)) {
137 				return 1;
138 			}
139 			
140 			// neither one is empty.  Iterate through both.
141 
142 			Iterator<Entry<T,V>> o1Iter = o1.entrySet().iterator();
143 			Iterator<Entry<T,V>> o2Iter = o2.entrySet().iterator();
144 			
145 			while (o1Iter.hasNext() && o2Iter.hasNext()) {
146 				Entry<T,V> o1Elem = o1Iter.next(); 
147 				Entry<T,V> o2Elem = o2Iter.next();
148 				if (o1Elem == null) {
149 					if (o2Elem == null) continue;
150 					return -1;
151 				} 
152 				
153 				T o1ElemKey = o1Elem.getKey();
154 				T o2ElemKey = o2Elem.getKey();
155 				if (o1ElemKey == null) {
156 					if (o2ElemKey != null) return -1;
157 					// if they're both null, fall through
158 				} else {
159 					int elemKeyCompare = o1ElemKey.compareTo(o2ElemKey);
160 					if (elemKeyCompare != 0) return elemKeyCompare;
161 				}
162 				
163 				V o1ElemValue = o1Elem.getValue();
164 				V o2ElemValue = o2Elem.getValue();
165 				if (o1ElemValue == null) {
166 					if (o2ElemValue != null) return -1;
167 					// if they're both null, fall through
168 				} else {
169 					int elemValueCompare = o1ElemValue.compareTo(o2ElemValue);
170 					if (elemValueCompare != 0) return elemValueCompare;
171 				}
172 			}
173 			
174 			if (o1Iter.hasNext()) return 1;
175 			if (o2Iter.hasNext()) return -1;
176 			return 0;
177 		}
178 
179 	}
180 
181 	
182 }