001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2008-2017 the original author or authors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.codehaus.griffon.runtime.core;
019
020 import griffon.core.Context;
021 import griffon.exceptions.FieldException;
022 import griffon.inject.Contextual;
023
024 import javax.annotation.Nonnull;
025 import javax.annotation.Nullable;
026 import java.beans.PropertyDescriptor;
027 import java.beans.PropertyEditor;
028 import java.lang.reflect.Field;
029 import java.lang.reflect.InvocationTargetException;
030 import java.lang.reflect.Method;
031
032 import static griffon.core.editors.PropertyEditorResolver.findEditor;
033 import static griffon.util.AnnotationUtils.annotationsOfMethodParameter;
034 import static griffon.util.AnnotationUtils.findAnnotation;
035 import static griffon.util.AnnotationUtils.nameFor;
036 import static griffon.util.GriffonClassUtils.getAllDeclaredFields;
037 import static griffon.util.GriffonClassUtils.getPropertyDescriptors;
038 import static griffon.util.GriffonClassUtils.setFieldValue;
039 import static griffon.util.TypeUtils.castToBoolean;
040 import static griffon.util.TypeUtils.castToDouble;
041 import static griffon.util.TypeUtils.castToFloat;
042 import static griffon.util.TypeUtils.castToInt;
043 import static griffon.util.TypeUtils.castToLong;
044 import static java.util.Objects.requireNonNull;
045
046 /**
047 * @author Andres Almiray
048 * @since 2.2.0
049 */
050 public abstract class AbstractContext implements Context {
051 protected Context parentContext;
052
053 public AbstractContext(@Nullable Context parentContext) {
054 this.parentContext = parentContext;
055 }
056
057 @Nullable
058 public Context getParentContext() {
059 return parentContext;
060 }
061
062 @Nullable
063 @Override
064 @SuppressWarnings("unchecked")
065 public <T> T get(@Nonnull String key, @Nullable T defaultValue) {
066 T value = (T) get(key);
067 return value != null ? value : defaultValue;
068 }
069
070 @Nullable
071 @Override
072 public Object getAt(@Nonnull String key) {
073 return get(key);
074 }
075
076 @Nullable
077 @Override
078 public <T> T getAt(@Nonnull String key, @Nullable T defaultValue) {
079 return get(key, defaultValue);
080 }
081
082 @Nullable
083 @Override
084 public Object get(@Nonnull String key) {
085 if (hasKey(key)) {
086 return doGet(key);
087 } else if (parentContext != null) {
088 return parentContext.get(key);
089 } else {
090 return null;
091 }
092 }
093
094 @Override
095 public void destroy() {
096 parentContext = null;
097 }
098
099 @Override
100 public boolean containsKey(@Nonnull String key) {
101 if (hasKey(key)) {
102 return true;
103 } else if (parentContext != null) {
104 return parentContext.containsKey(key);
105 }
106 return false;
107 }
108
109 @Nullable
110 protected abstract Object doGet(@Nonnull String key);
111
112 @Override
113 public boolean getAsBoolean(@Nonnull String key) {
114 return getAsBoolean(key, false);
115 }
116
117 @Override
118 public boolean getAsBoolean(@Nonnull String key, boolean defaultValue) {
119 return castToBoolean(get(key), defaultValue);
120 }
121
122 @Override
123 public int getAsInt(@Nonnull String key) {
124 return getAsInt(key, 0);
125 }
126
127 @Override
128 public int getAsInt(@Nonnull String key, int defaultValue) {
129 return castToInt(get(key), defaultValue);
130 }
131
132 @Override
133 public long getAsLong(@Nonnull String key) {
134 return getAsLong(key, 0L);
135 }
136
137 @Override
138 public long getAsLong(@Nonnull String key, long defaultValue) {
139 return castToLong(get(key), defaultValue);
140 }
141
142 @Override
143 public float getAsFloat(@Nonnull String key) {
144 return getAsFloat(key, 0f);
145 }
146
147 @Override
148 public float getAsFloat(@Nonnull String key, float defaultValue) {
149 return castToFloat(get(key), defaultValue);
150 }
151
152 @Override
153 public double getAsDouble(@Nonnull String key) {
154 return getAsDouble(key, 0d);
155 }
156
157 @Override
158 public double getAsDouble(@Nonnull String key, double defaultValue) {
159 return castToDouble(get(key), defaultValue);
160 }
161
162 @Nullable
163 @Override
164 public String getAsString(@Nonnull String key) {
165 return getAsString(key, null);
166 }
167
168 @Nullable
169 @Override
170 public String getAsString(@Nonnull String key, @Nullable String defaultValue) {
171 Object value = get(key);
172 return value != null ? String.valueOf(value) : defaultValue;
173 }
174
175 @Nullable
176 @Override
177 @SuppressWarnings("unchecked")
178 public <T> T getAs(@Nonnull String key) {
179 return (T) get(key);
180 }
181
182 @Nullable
183 @Override
184 @SuppressWarnings("unchecked")
185 public <T> T getAs(@Nonnull String key, @Nullable T defaultValue) {
186 Object value = get(key);
187 return (T) (value != null ? value : defaultValue);
188 }
189
190 @Nullable
191 @Override
192 public <T> T getConverted(@Nonnull String key, @Nonnull Class<T> type) {
193 requireNonNull(type, "Argument 'type' must not be null");
194 return convertValue(get(key), type);
195 }
196
197 @Nullable
198 @Override
199 public <T> T getConverted(@Nonnull String key, @Nonnull Class<T> type, @Nullable T defaultValue) {
200 T value = getConverted(key, type);
201 return type.cast(value != null ? value : defaultValue);
202 }
203
204 @SuppressWarnings("unchecked")
205 protected <T> T convertValue(@Nullable Object value, @Nonnull Class<T> type) {
206 if (value != null) {
207 if (type.isAssignableFrom(value.getClass())) {
208 return (T) value;
209 } else {
210 PropertyEditor editor = findEditor(type);
211 editor.setValue(value);
212 return (T) editor.getValue();
213 }
214 }
215 return null;
216 }
217
218 @Nonnull
219 @Override
220 public <T> T injectMembers(@Nonnull T instance) {
221 requireNonNull(instance, "Argument 'instance' must not be null");
222
223 for (PropertyDescriptor descriptor : getPropertyDescriptors(instance.getClass())) {
224 Method method = descriptor.getWriteMethod();
225 if (method != null && method.getAnnotation(Contextual.class) != null) {
226 String key = nameFor(method);
227 Object arg = get(key);
228
229 Nonnull nonNull = findAnnotation(annotationsOfMethodParameter(method, 0), Nonnull.class);
230 if (arg == null && nonNull != null) {
231 throw new IllegalStateException("Could not find an instance of type " +
232 method.getParameterTypes()[0].getName() + " under key '" + key +
233 "' to be injected on property '" + descriptor.getName() +
234 "' (" + instance.getClass().getName() + "). Property does not accept null values.");
235 }
236
237 try {
238 method.invoke(instance, arg);
239 } catch (IllegalAccessException | InvocationTargetException e) {
240 throw new IllegalStateException(e);
241 }
242 }
243 }
244
245 for (Field field : getAllDeclaredFields(instance.getClass())) {
246 if (field.getAnnotation(Contextual.class) != null) {
247 String key = nameFor(field);
248 Object arg = get(key);
249 if (arg == null && field.getAnnotation(Nonnull.class) != null) {
250 throw new IllegalStateException("Could not find an instance of type " +
251 field.getType().getName() + " under key '" + key +
252 "' to be injected on field '" + field.getName() +
253 "' (" + instance.getClass().getName() + "). Field does not accept null values.");
254 }
255
256 try {
257 setFieldValue(instance, field.getName(), arg);
258 } catch (FieldException e) {
259 throw new IllegalStateException(e);
260 }
261 }
262 }
263
264 return instance;
265 }
266 }
|