001 /*
002 * Copyright 2008-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package griffon.core.editors;
017
018 import javax.annotation.Nonnull;
019 import javax.annotation.Nullable;
020 import javax.annotation.concurrent.GuardedBy;
021 import java.beans.PropertyEditor;
022 import java.beans.PropertyEditorSupport;
023 import java.lang.ref.WeakReference;
024 import java.util.ArrayList;
025 import java.util.Collections;
026 import java.util.LinkedHashSet;
027 import java.util.List;
028 import java.util.Set;
029
030 import static griffon.util.GriffonClassUtils.requireNonEmpty;
031 import static griffon.util.GriffonNameUtils.isBlank;
032 import static java.util.Objects.requireNonNull;
033
034 /**
035 * @author Andres Almiray
036 * @since 2.4.0
037 */
038 public class PropertyEditorChain extends PropertyEditorSupport implements ExtendedPropertyEditor {
039 private final Class<?> targetClass;
040 private final Object lock = new Object[0];
041 private final WeakReference<Class<? extends PropertyEditor>>[] propertyEditorClasses;
042 @GuardedBy("lock")
043 private WeakReference<PropertyEditor>[] propertyEditors;
044 private String format;
045
046 @SuppressWarnings("unchecked")
047 public PropertyEditorChain(@Nonnull Class<?> targetClass, @Nonnull Class<? extends PropertyEditor>[] propertyEditorClasses) {
048 this.targetClass = requireNonNull(targetClass, "Argument 'targetClass' must not be null");
049 requireNonEmpty(propertyEditorClasses, "Argument 'propertyEditorClasses' must not be null nor empty");
050 // let's make sure propertyEditorClasses contains unique elements
051 Set<Class<? extends PropertyEditor>> classes = new LinkedHashSet<>();
052 Collections.addAll(classes, propertyEditorClasses);
053
054 int i = 0;
055 this.propertyEditorClasses = new WeakReference[classes.size()];
056 for (Class<? extends PropertyEditor> klass : classes) {
057 this.propertyEditorClasses[i++] = new WeakReference<Class<? extends PropertyEditor>>(klass);
058 }
059 }
060
061 @Nullable
062 public String getFormat() {
063 return format;
064 }
065
066 public void setFormat(@Nullable String format) {
067 this.format = format;
068 }
069
070 public int getSize() {
071 return propertyEditorClasses.length;
072 }
073
074 @SuppressWarnings("unchecked")
075 public PropertyEditorChain copyOf() {
076 List<Class<? extends PropertyEditor>> classes = new ArrayList<>();
077 for (WeakReference<Class<? extends PropertyEditor>> reference : propertyEditorClasses) {
078 if (reference.get() != null) {
079 classes.add(reference.get());
080 }
081 }
082 return new PropertyEditorChain(targetClass, classes.toArray(new Class[classes.size()]));
083 }
084
085 @SuppressWarnings("unchecked")
086 public PropertyEditorChain copyOf(Class<? extends PropertyEditor> propertyEditorClass) {
087 requireNonNull(propertyEditorClass, "Argument 'propertyEditorClass' must not be null");
088 List<Class<? extends PropertyEditor>> classes = new ArrayList<>();
089 for (WeakReference<Class<? extends PropertyEditor>> reference : propertyEditorClasses) {
090 if (reference.get() != null) {
091 classes.add(reference.get());
092 }
093 }
094 if (!classes.contains(propertyEditorClass)) {
095 classes.add(propertyEditorClass);
096 }
097 return new PropertyEditorChain(targetClass, classes.toArray(new Class[classes.size()]));
098 }
099
100 @Override
101 public String toString() {
102 StringBuilder sb = new StringBuilder(super.toString());
103 sb.append("[").append(targetClass.getName()).append(']');
104 return sb.toString();
105 }
106
107 @Override
108 public String getAsText() {
109 return isBlank(getFormat()) ? getAsTextInternal() : getFormattedValue();
110 }
111
112 @Override
113 public void setAsText(String str) throws IllegalArgumentException {
114 if (isBlank(getFormat())) {
115 setAsTextInternal(str);
116 } else {
117 setFormattedValue(str);
118 }
119 }
120
121 @Override
122 public void setValue(Object value) {
123 if (value instanceof CharSequence) {
124 setFormattedValue(String.valueOf(value));
125 } else {
126 setValueInternal(value);
127 }
128 }
129
130 @SuppressWarnings({"unchecked", "rawtypes"})
131 public String getFormattedValue() {
132 initPropertyEditors();
133
134 Object value = super.getValue();
135 for (WeakReference<PropertyEditor> reference : propertyEditors) {
136 try {
137 PropertyEditor propertyEditor = reference.get();
138 if (propertyEditor != null && propertyEditor instanceof ExtendedPropertyEditor) {
139 ExtendedPropertyEditor extendedPropertyEditor = (ExtendedPropertyEditor) propertyEditor;
140 extendedPropertyEditor.setFormat(format);
141 extendedPropertyEditor.setValue(value);
142 return extendedPropertyEditor.getFormattedValue();
143 }
144 } catch (Exception e) {
145 // ignore. next editor
146 }
147 }
148
149 throw illegalValue(value, targetClass);
150 }
151
152 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
153 public void setFormattedValue(String value) {
154 initPropertyEditors();
155
156 for (WeakReference<PropertyEditor> reference : propertyEditors) {
157 try {
158 PropertyEditor propertyEditor = reference.get();
159 if (propertyEditor != null && propertyEditor instanceof ExtendedPropertyEditor) {
160 ExtendedPropertyEditor extendedPropertyEditor = (ExtendedPropertyEditor) propertyEditor;
161 extendedPropertyEditor.setFormat(format);
162 extendedPropertyEditor.setValue(value);
163 super.setValue(extendedPropertyEditor.getValue());
164 return;
165 }
166 } catch (Exception e) {
167 // ignore. next editor
168 }
169 }
170
171 throw illegalValue(value, targetClass);
172 }
173
174 protected void setValueInternal(Object value) throws IllegalArgumentException {
175 initPropertyEditors();
176
177 for (WeakReference<PropertyEditor> reference : propertyEditors) {
178 try {
179 PropertyEditor propertyEditor = reference.get();
180 if (propertyEditor != null) {
181 propertyEditor.setValue(value);
182 super.setValue(propertyEditor.getValue());
183 return;
184 }
185 } catch (Exception e) {
186 // ignore. next editor
187 }
188 }
189
190 throw illegalValue(value, targetClass);
191 }
192
193 protected Object getValueInternal() {
194 initPropertyEditors();
195
196 Object value = super.getValue();
197 for (WeakReference<PropertyEditor> reference : propertyEditors) {
198 try {
199 PropertyEditor propertyEditor = reference.get();
200 if (propertyEditor != null) {
201 propertyEditor.setValue(value);
202 return propertyEditor.getValue();
203 }
204 } catch (Exception e) {
205 // ignore. next editor
206 }
207 }
208
209 throw illegalValue(value, targetClass);
210 }
211
212 protected String getAsTextInternal() {
213 initPropertyEditors();
214
215 Object value = super.getValue();
216
217 for (WeakReference<PropertyEditor> reference : propertyEditors) {
218 try {
219 PropertyEditor propertyEditor = reference.get();
220 if (propertyEditor != null) {
221 propertyEditor.setValue(value);
222 return propertyEditor.getAsText();
223 }
224 } catch (Exception e) {
225 // ignore. next editor
226 }
227 }
228
229 throw illegalValue(value, targetClass);
230 }
231
232 protected void setAsTextInternal(String text) throws IllegalArgumentException {
233 initPropertyEditors();
234
235 for (WeakReference<PropertyEditor> reference : propertyEditors) {
236 try {
237 PropertyEditor propertyEditor = reference.get();
238 if (propertyEditor != null) {
239 propertyEditor.setAsText(text);
240 super.setValue(propertyEditor.getValue());
241 return;
242 }
243 } catch (Exception e) {
244 // ignore. next editor
245 }
246 }
247
248 throw illegalValue(text, targetClass);
249 }
250
251 protected ValueConversionException illegalValue(Object value, Class<?> klass) {
252 throw new ValueConversionException(value, klass);
253 }
254
255 protected ValueConversionException illegalValue(Object value, Class<?> klass, Exception e) {
256 throw new ValueConversionException(value, klass, e);
257 }
258
259 @SuppressWarnings("unchecked")
260 private void initPropertyEditors() {
261 synchronized (lock) {
262 if (propertyEditors == null) {
263 List<WeakReference<PropertyEditor>> editors = new ArrayList<>();
264 for (WeakReference<Class<? extends PropertyEditor>> propertyEditorClass : propertyEditorClasses) {
265 try {
266 Class<? extends PropertyEditor> klass = propertyEditorClass.get();
267 if (klass != null) {
268 editors.add(new WeakReference<>(klass.newInstance()));
269 }
270 } catch (InstantiationException | IllegalAccessException e) {
271 throw new IllegalArgumentException("Can't create instance", e);
272 }
273 }
274
275 if (editors.size() > 0) {
276 propertyEditors = editors.toArray(new WeakReference[editors.size()]);
277 } else {
278 throw new IllegalStateException("No available PropertyEditors for " + this);
279 }
280 }
281 }
282 }
283 }
|