AbstractContext.java
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 = (Tget(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 (Tget(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 (Tvalue;
209             else {
210                 PropertyEditor editor = findEditor(type);
211                 editor.setValue(value);
212                 return (Teditor.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 }