1 /*
2 * #%L
3 * Nuiton Decorator
4 * %%
5 * Copyright (C) 2011 CodeLutin, Tony Chemit
6 * %%
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Lesser Public License for more details.
16 *
17 * You should have received a copy of the GNU General Lesser Public
18 * License along with this program. If not, see
19 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20 * #L%
21 */
22 package org.nuiton.decorator;
23
24 import org.apache.commons.jxpath.DynamicPropertyHandler;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27
28 import java.util.Collection;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.Set;
32
33 /**
34 * A extended handler to deal with map in JXPath contexts.
35 * <p/>
36 * The basic one in JXPath api only deals with map keys as string.
37 * <p/>
38 * We offers a hook in method {@link #getKey(Object)} to obtain a string
39 * representation of a real object in map (key or value).
40 * <p/>
41 * More over, you can also access directly to a key or a value, using this
42 * syntax :
43 * <p/>
44 * <pre>context.getValue(".[@name='key:programme2']")</pre>
45 * <pre>context.getValue(".[@name='value:programme2']")</pre>
46 * <p/>
47 * If the values are iterable, then will scan inot it when looking for a direct
48 * value.
49 *
50 * @author tchemit <chemit@codelutin.com>
51 * @see DynamicPropertyHandler
52 * @since 2.3
53 */
54 public class MapPropertyHandler implements DynamicPropertyHandler {
55
56 /** Logger */
57 private static final Log log =
58 LogFactory.getLog(MapPropertyHandler.class);
59
60 @Override
61 public String[] getPropertyNames(Object object) {
62 Map<?, ?> map = (Map<?, ?>) object;
63 Set<?> set = map.keySet();
64 String[] names = new String[set.size()];
65 Iterator<?> it = set.iterator();
66 for (int i = 0; i < names.length; i++) {
67 Object o = it.next();
68 names[i] = getKey(o);
69 }
70 return names;
71 }
72
73 @Override
74 public Object getProperty(Object object, String propertyName) {
75 Map<?, ?> map = (Map<?, ?>) object;
76 boolean getKey = false;
77 Object property0;
78 if (propertyName.startsWith("value:")) {
79 propertyName = propertyName.substring(6);
80 if (log.isDebugEnabled()) {
81 log.debug("property value name " + propertyName);
82 }
83 property0 = getPropertyValue(map, propertyName);
84 if (log.isDebugEnabled()) {
85 log.debug("property value = " + property0);
86 }
87 return property0;
88 }
89 if (propertyName.startsWith("key:")) {
90 propertyName = propertyName.substring(4);
91 getKey = true;
92 }
93 property0 = getPropertyKey(map, propertyName);
94 Object result = null;
95 if (property0 != null) {
96 if (getKey) {
97 result = property0;
98 } else {
99 result = map.get(property0);
100 }
101 }
102 return result;
103 }
104
105 @Override
106 public void setProperty(Object object, String propertyName, Object value) {
107 Map map = (Map) object;
108 Object property0 = getPropertyKey(map, propertyName);
109 if (property0 != null) {
110 map.put(property0, value);
111 }
112 }
113
114 /**
115 * Obtain the key from the map keys which matches the given {@code key}.
116 * <p/>
117 * To compare object ot string, please refers to the method {@link
118 * #getKey(Object)}.
119 *
120 * @param map the map to scan
121 * @param key the string representation of the required key as object
122 * @return the found key, or {@code null} if not found.
123 */
124 public Object getPropertyKey(Map<?, ?> map, String key) {
125 Set<?> set = map.keySet();
126 for (Object o : set) {
127 String k = getKey(o);
128 if (key.equals(k)) {
129 return o;
130 }
131 }
132 return null;
133 }
134
135 /**
136 * Obtain the value from the map values which matches the given {@code
137 * value}.
138 * <p/>
139 * To compare object to string, please refer to the method {@link
140 * #getKey(Object)}.
141 *
142 * @param map the map to scan
143 * @param value the string representation of the value
144 * @return the found value, or {@code null} if not found.}
145 */
146 public Object getPropertyValue(Map<?, ?> map, String value) {
147 Collection<?> set = map.values();
148 for (Object o : set) {
149 if (o instanceof Iterable<?>) {
150 Iterable<?> c = (Iterable<?>) o;
151 for (Object oo : c) {
152 String k = getKey(oo);
153 if (value.equals(k)) {
154 return oo;
155 }
156 }
157 continue;
158 }
159 String k = getKey(o);
160 if (value.equals(k)) {
161 return o;
162 }
163 }
164 return null;
165 }
166
167 /**
168 * Obtain a string representation of an object.
169 *
170 * @param o the object to decorate
171 * @return the string representation of the object
172 */
173 protected String getKey(Object o) {
174 String k = String.valueOf(o);
175 return k;
176 }
177 }