001 /*
002 * Copyright 2008-2015 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.concurrent.GuardedBy;
020 import java.beans.PropertyEditor;
021 import java.beans.PropertyEditorSupport;
022 import java.lang.ref.WeakReference;
023 import java.util.ArrayList;
024 import java.util.List;
025
026 import static griffon.util.GriffonClassUtils.requireNonEmpty;
027 import static java.util.Objects.requireNonNull;
028
029 /**
030 * @author Andres Almiray
031 * @since 2.4.0
032 */
033 public class PropertyEditorChain extends PropertyEditorSupport {
034 private final Class<?> targetClass;
035 private final Object lock = new Object[0];
036 private final WeakReference<Class<? extends PropertyEditor>>[] propertyEditorClasses;
037 @GuardedBy("lock")
038 private WeakReference<PropertyEditor>[] propertyEditors;
039
040 @SuppressWarnings("unchecked")
041 public PropertyEditorChain(@Nonnull Class<?> targetClass, @Nonnull Class<? extends PropertyEditor>[] propertyEditorClasses) {
042 this.targetClass = requireNonNull(targetClass, "Argument 'targetClass' must not be null");
043 requireNonEmpty(propertyEditorClasses, "Argument 'propertyEditorClasses' must not be null nor empty");
044 this.propertyEditorClasses = new WeakReference[propertyEditorClasses.length];
045 for (int i = 0; i < propertyEditorClasses.length; i++) {
046 this.propertyEditorClasses[i] = new WeakReference<Class<? extends PropertyEditor>>(propertyEditorClasses[i]);
047 }
048 }
049
050 @SuppressWarnings("unchecked")
051 public PropertyEditorChain copyOf() {
052 List<Class<? extends PropertyEditor>> classes = new ArrayList<>();
053 for (WeakReference<Class<? extends PropertyEditor>> reference : propertyEditorClasses) {
054 if (reference.get() != null) {
055 classes.add(reference.get());
056 }
057 }
058 return new PropertyEditorChain(targetClass, classes.toArray(new Class[classes.size()]));
059 }
060
061 @SuppressWarnings("unchecked")
062 public PropertyEditorChain copyOf(Class<? extends PropertyEditor> propertyEditorClass) {
063 requireNonNull(propertyEditorClass, "Argument 'propertyEditorClass' must not be null");
064 List<Class<? extends PropertyEditor>> classes = new ArrayList<>();
065 for (WeakReference<Class<? extends PropertyEditor>> reference : propertyEditorClasses) {
066 if (reference.get() != null) {
067 classes.add(reference.get());
068 }
069 }
070 classes.add(propertyEditorClass);
071 return new PropertyEditorChain(targetClass, classes.toArray(new Class[classes.size()]));
072 }
073
074 @Override
075 public String toString() {
076 StringBuilder sb = new StringBuilder(super.toString());
077 sb.append("[").append(targetClass.getName()).append(']');
078 return sb.toString();
079 }
080
081 @Override
082 public Object getValue() {
083 initPropertyEditors();
084
085 Object value = super.getValue();
086 for (WeakReference<PropertyEditor> reference : propertyEditors) {
087 try {
088 PropertyEditor propertyEditor = reference.get();
089 if (propertyEditor != null) {
090 propertyEditor.setValue(value);
091 return propertyEditor.getValue();
092 }
093 } catch (Exception e) {
094 // ignore. next editor
095 }
096 }
097
098 throw illegalValue(value, targetClass);
099 }
100
101 @Override
102 public String getAsText() {
103 initPropertyEditors();
104
105 Object value = super.getValue();
106
107 for (WeakReference<PropertyEditor> reference : propertyEditors) {
108 try {
109 PropertyEditor propertyEditor = reference.get();
110 if (propertyEditor != null) {
111 propertyEditor.setValue(value);
112 return propertyEditor.getAsText();
113 }
114 } catch (Exception e) {
115 // ignore. next editor
116 }
117 }
118
119 throw illegalValue(value, targetClass);
120 }
121
122 @Override
123 public void setAsText(String text) throws IllegalArgumentException {
124 initPropertyEditors();
125
126 for (WeakReference<PropertyEditor> reference : propertyEditors) {
127 try {
128 PropertyEditor propertyEditor = reference.get();
129 if (propertyEditor != null) {
130 propertyEditor.setAsText(text);
131 super.setValue(propertyEditor.getValue());
132 return;
133 }
134 } catch (Exception e) {
135 // ignore. next editor
136 }
137 }
138
139 throw illegalValue(text, targetClass);
140 }
141
142 protected ValueConversionException illegalValue(Object value, Class<?> klass) {
143 throw new ValueConversionException(value, klass);
144 }
145
146 protected ValueConversionException illegalValue(Object value, Class<?> klass, Exception e) {
147 throw new ValueConversionException(value, klass, e);
148 }
149
150 @SuppressWarnings("unchecked")
151 private void initPropertyEditors() {
152 synchronized (lock) {
153 if (propertyEditors == null) {
154 List<WeakReference<PropertyEditor>> editors = new ArrayList<>();
155 for (WeakReference<Class<? extends PropertyEditor>> propertyEditorClass : propertyEditorClasses) {
156 try {
157 Class<? extends PropertyEditor> klass = propertyEditorClass.get();
158 if (klass != null) {
159 editors.add(new WeakReference<>(klass.newInstance()));
160 }
161 } catch (InstantiationException | IllegalAccessException e) {
162 throw new IllegalArgumentException("Can't create instance", e);
163 }
164 }
165
166 if (editors.size() > 0) {
167 propertyEditors = editors.toArray(new WeakReference[editors.size()]);
168 } else {
169 throw new IllegalStateException("No available PropertyEditors for " + this);
170 }
171 }
172 }
173 }
174 }
|