1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.integration.beans;
21
22 import java.beans.PropertyEditor;
23 import java.util.Collection;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29
30
31
32
33
34
35 public class MapEditor extends AbstractPropertyEditor {
36 static final Pattern ELEMENT = Pattern.compile(
37 "([,\\s]+)|" +
38 "(\\s*=\\s*)|" +
39 "(?<=\")((?:\\\\\"|\\\\'|\\\\\\\\|\\\\ |[^\"])*)(?=\")|" +
40 "(?<=')((?:\\\\\"|\\\\'|\\\\\\\\|\\\\ |[^'])*)(?=')|" +
41 "((?:[^\\\\\\s'\",]|\\\\ |\\\\\"|\\\\')+)");
42
43 private final Class<?> keyType;
44 private final Class<?> valueType;
45
46 public MapEditor(Class<?> keyType, Class<?> valueType) {
47 if (keyType == null) {
48 throw new NullPointerException("keyType");
49 }
50 if (valueType == null) {
51 throw new NullPointerException("valueType");
52 }
53 this.keyType = keyType;
54 this.valueType = valueType;
55 getKeyEditor();
56 getValueEditor();
57 setTrimText(false);
58 }
59
60 private PropertyEditor getKeyEditor() {
61 PropertyEditor e = PropertyEditorFactory.getInstance(keyType);
62 if (e == null) {
63 throw new IllegalArgumentException(
64 "No key " + PropertyEditor.class.getSimpleName() +
65 " found for " + keyType.getSimpleName() + '.');
66 }
67 return e;
68 }
69
70 private PropertyEditor getValueEditor() {
71 PropertyEditor e = PropertyEditorFactory.getInstance(valueType);
72 if (e == null) {
73 throw new IllegalArgumentException(
74 "No value " + PropertyEditor.class.getSimpleName() +
75 " found for " + valueType.getSimpleName() + '.');
76 }
77 return e;
78 }
79
80 @Override
81 @SuppressWarnings("unchecked")
82 protected final String toText(Object value) {
83 StringBuilder buf = new StringBuilder();
84 for (Object o: ((Map) value).entrySet()) {
85 Map.Entry entry = (Map.Entry) o;
86 Object ekey = entry.getKey();
87 Object evalue = entry.getValue();
88
89 PropertyEditor ekeyEditor = PropertyEditorFactory.getInstance(ekey);
90 if (ekeyEditor == null) {
91 throw new IllegalArgumentException(
92 "No key " + PropertyEditor.class.getSimpleName() +
93 " found for " + ekey.getClass().getSimpleName() + '.');
94 }
95 ekeyEditor.setValue(ekey);
96
97 PropertyEditor evalueEditor = PropertyEditorFactory.getInstance(evalue);
98 if (evalueEditor == null) {
99 throw new IllegalArgumentException(
100 "No value " + PropertyEditor.class.getSimpleName() +
101 " found for " + evalue.getClass().getSimpleName() + '.');
102 }
103 ekeyEditor.setValue(ekey);
104 evalueEditor.setValue(evalue);
105
106
107 String keyString = ekeyEditor.getAsText();
108 String valueString = evalueEditor.getAsText();
109 buf.append(keyString);
110 buf.append(" = ");
111 buf.append(valueString);
112 buf.append(", ");
113 }
114
115
116 if (buf.length() >= 2) {
117 buf.setLength(buf.length() - 2);
118 }
119 return buf.toString();
120 }
121
122 @Override
123 protected final Object toValue(String text) throws IllegalArgumentException {
124 PropertyEditor keyEditor = getKeyEditor();
125 PropertyEditor valueEditor = getValueEditor();
126 Map<Object, Object> answer = newMap();
127 Matcher m = ELEMENT.matcher(text);
128 TokenType lastTokenType = TokenType.ENTRY_DELIM;
129 Object key = null;
130 Object value = null;
131
132 while (m.find()) {
133 if (m.group(1) != null) {
134 switch (lastTokenType) {
135 case VALUE: case ENTRY_DELIM:
136 break;
137 default:
138 throw new IllegalArgumentException(
139 "Unexpected entry delimiter: " + text);
140 }
141
142 lastTokenType = TokenType.ENTRY_DELIM;
143 continue;
144 }
145
146 if (m.group(2) != null) {
147 if (lastTokenType != TokenType.KEY) {
148 throw new IllegalArgumentException(
149 "Unexpected key-value delimiter: " + text);
150 }
151
152 lastTokenType = TokenType.KEY_VALUE_DELIM;
153 continue;
154 }
155
156
157
158 String region = m.group();
159
160 if (m.group(3) != null || m.group(4) != null) {
161
162 m.region(m.end() + 1, m.regionEnd());
163 }
164
165 switch (lastTokenType) {
166 case ENTRY_DELIM:
167 keyEditor.setAsText(region);
168 key = keyEditor.getValue();
169 lastTokenType = TokenType.KEY;
170 break;
171 case KEY_VALUE_DELIM:
172 valueEditor.setAsText(region);
173 value = valueEditor.getValue();
174 lastTokenType = TokenType.VALUE;
175 answer.put(key, value);
176 break;
177 case KEY: case VALUE:
178 throw new IllegalArgumentException(
179 "Unexpected key or value: " + text);
180 }
181 }
182
183 return answer;
184 }
185
186 protected Map<Object, Object> newMap() {
187 return new LinkedHashMap<Object, Object>();
188 }
189
190 private static enum TokenType {
191 ENTRY_DELIM,
192 KEY_VALUE_DELIM,
193 KEY,
194 VALUE,
195 }
196 }