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