View Javadoc
1   /*
2    * Copyright 2016 Function1. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package tools.gsf.config.inject;
17  
18  import COM.FutureTense.Interfaces.ICS;
19  import COM.FutureTense.Util.ftErrors;
20  import com.fatwire.assetapi.data.AssetId;
21  import com.openmarket.xcelerate.asset.AssetIdImpl;
22  import org.apache.commons.lang3.StringUtils;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import tools.gsf.facade.assetapi.AssetIdWithSite;
26  import tools.gsf.mapping.AssetName;
27  import tools.gsf.mapping.AssetNameImpl;
28  import tools.gsf.mapping.Mapping;
29  import tools.gsf.mapping.MappingService;
30  import tools.gsf.mapping.MappingValue;
31  import tools.gsf.runtime.CSRuntimeException;
32  
33  import java.lang.annotation.Annotation;
34  import java.lang.reflect.Field;
35  import java.util.ArrayList;
36  import java.util.List;
37  import java.util.Map;
38  
39  /**
40   * @author Tony Field
41   * @since 2016-07-21
42   */
43  public final class MappingInjector implements Injector {
44      private static final Logger LOG = LoggerFactory.getLogger("tools.gsf.config.inject.MappingInjector");
45  
46      private final ICS ics;
47      private final MappingService mappingService;
48  
49      public MappingInjector(ICS ics, MappingService mappingService) {
50          this.ics = ics;
51          this.mappingService = mappingService;
52      }
53  
54      @Override
55      public void inject(Object dependent) {
56          if (dependent == null) {
57              throw new IllegalArgumentException("object cannot be null.");
58          }
59          String pagename = ics.GetVar("pagename");
60          if (pagename == null) {
61              throw new IllegalArgumentException("pagename cannot be identified");
62          }
63          final Field[] fields = findFieldsWithAnnotation(dependent, Mapping.class);
64          if (fields.length > 0) {
65              AssetIdWithSite id = mappingService.resolveMapped(pagename);
66              if (id != null) {
67  	            final Map<String, MappingValue> map = mappingService.readMapping(id);
68  	            for (final Field field : fields) {
69  	                injectIntoField(dependent, map, field, id);
70  	            }
71              } else {
72              	LOG.warn("Cannot determine eid / tid for current code element (CSElement / Template) based on pagename '" + pagename + "', @Mapping annotations will be ignored.");
73              }
74          }
75      }
76  
77      private static void injectIntoField(final Object object, final Map<String, MappingValue> map, final Field field,
78                                          final AssetIdWithSite id) throws SecurityException {
79  
80          final Mapping ifr = field.getAnnotation(Mapping.class);
81  
82          String name = ifr.value();
83          if (StringUtils.isBlank(name)) {
84              name = field.getName();
85          }
86  
87          final MappingValue value = map.get(name);
88          if (value == null) {
89              throw new CSRuntimeException("Can't find a value for mapping " + name + " for asset " + id, ftErrors.badparams);
90          }
91          Object injectionValue;
92          // Handle MappingVulue and AssetId special
93          if (MappingValue.class.isAssignableFrom(field.getType())) {
94              injectionValue = value;
95          } else if (AssetId.class.isAssignableFrom(field.getType()) && value.getType() == MappingValue.Type.asset) {
96              injectionValue = new AssetIdImpl(value.getLeft(), Long.parseLong(value.getRight()));
97          } else if (AssetName.class.isAssignableFrom(field.getType()) && value.getType() == MappingValue.Type.assetname) {
98              injectionValue = new AssetNameImpl(value.getLeft(), value.getRight());
99          } else {
100             injectionValue = value.getValue();
101             final Mapping.Match what = ifr.match();
102             switch (what) {
103                 case left:
104                     injectionValue = value.getLeft();
105                     break;
106                 case right:
107                     injectionValue = value.getRight();
108                     break;
109                 case all:
110                     break;
111                 default:
112                     break;
113             }
114         }
115         if (injectionValue == null) {
116             throw new CSRuntimeException("No value found to map  '" + field.getType().getName() + "' into the field '"
117                     + field.getName() + "' for an action " + object.getClass().getName(), ftErrors.badparams);
118         }
119         field.setAccessible(true); // make private fields accessible
120         LOG.debug("Injecting {} into field {} of type {} for {}", injectionValue.getClass().getName(), field.getName(), field.getType().getName(), object.getClass().getName());
121         try {
122             field.set(object, injectionValue);
123         } catch (final IllegalArgumentException e) {
124             throw new CSRuntimeException("IllegalArgumentException injecting " + injectionValue + " into field " + field.getName(), ftErrors.exceptionerr, e);
125         } catch (final IllegalAccessException e) {
126             throw new CSRuntimeException("IllegalAccessException injecting " + injectionValue + " into field " + field.getName(), ftErrors.exceptionerr, e);
127         }
128     }
129 
130     /**
131      * Finds the fields in the class or super class that are annotated with the
132      * <tt>annnotationClass</tt> annotation.
133      *
134      * @param object           the object to inspect.
135      * @param annnotationClass the annotation to find.
136      * @return the array of fields with the annotation, never null.
137      */
138     private static Field[] findFieldsWithAnnotation(final Object object,
139                                                     final Class<? extends Annotation> annnotationClass) {
140         if (object == null) {
141             throw new IllegalArgumentException("object must not be null.");
142         }
143         if (annnotationClass == null) {
144             throw new IllegalArgumentException("clazz must not be null.");
145         }
146         final List<Field> x = new ArrayList<>();
147         Class<?> c = object.getClass();
148         while (c != Object.class && c != null) {
149             for (final Field field : c.getDeclaredFields()) {
150                 if (field.isAnnotationPresent(annnotationClass)) {
151                     x.add(field);
152                 }
153             }
154             c = c.getSuperclass();
155         }
156         return x.toArray(new Field[x.size()]);
157     }
158 }