View Javadoc

1   package org.lsst.ccs.bus;
2   
3   import org.lsst.ccs.bus.trending.Trendable;
4   import org.lsst.ccs.bus.trending.TrendingData;
5   import org.lsst.ccs.utilities.logging.Logger;
6   
7   import java.io.Serializable;
8   import java.lang.reflect.Field;
9   import java.util.HashMap;
10  import java.util.Map;
11  
12  /**
13   * this class is to replace <TT>ValueNotification</TT>
14   * which is temporarily kept for compatibility.
15   * <p/>
16   * Object that are not of a "well known type" (as of <TT>ObjectNType</TT> definition)
17   * are "crystallized" for explicit deserialization by the receiving code.
18   * They are also analyzed and if they are annotated with the <TT>Trending</TT> annotation
19   * their content is split in as many key/primitiveValue as needed (this is a recursive process).
20   *
21   * @author bamade
22   */
23  // Date: 05/04/13
24  
25  public class DataValueNotification extends ValueNotification {
26      private static final long serialVersionUID = -8279905150213869922L;
27      private Map<String, ObjectNType> trendingDesc;
28      static Logger CURLOG = Logger.getLogger("org.lsst.ccs.bus") ;
29  
30      public DataValueNotification(String name, Serializable object, long tStamp) {
31          this.name = name;
32          ObjectNType val = new ObjectNType(object);
33          this.data = val;
34          this.tStamp = tStamp;
35          if (!val.isOfWellKnownType()) {
36              createTrendingMap(name, object);
37          }
38      }
39  
40      public DataValueNotification(String name, Serializable object) {
41          this(name, object.getClass(), object);
42      }
43  
44      public DataValueNotification(String name, Class classOfData, Serializable object) {
45          this.name = name;
46          ObjectNType val = new ObjectNType(classOfData, object);
47          this.data = val;
48          this.tStamp = System.currentTimeMillis();
49          if (!val.isOfWellKnownType()) {
50              createTrendingMap(name, object);
51          }
52      }
53  
54      public DataValueNotification(String name, int val) {
55          this(name, Integer.TYPE, val);
56      }
57  
58      public DataValueNotification(String name, double val) {
59          this(name, Double.TYPE, val);
60      }
61  
62      public DataValueNotification(String name, float val) {
63          this(name, Float.TYPE, val);
64      }
65  
66      public DataValueNotification(String name, char val) {
67          this(name, Character.TYPE, val);
68      }
69  
70      // just for upward compatibility
71      public DataValueNotification(ValueNotification notification) {
72          //TODO : expand in readable code!
73          this(notification.getName(),
74                  (notification.getData() instanceof Serializable) ? (Serializable) notification.getData() : String.valueOf(notification.getData()),
75                  notification.gettStamp());
76      }
77  
78      //TODO: abstract this and enable for various annotations (for instance for Responses)
79      private boolean createTrendingMap(String name, Serializable obj) {
80          if (obj == null) return false;
81          Trendable trendable = obj.getClass().getAnnotation(Trendable.class);
82          if (trendable == null) {
83              return false;
84          }
85          trendingDesc = new HashMap<String, ObjectNType>();
86          updateTrendingMap(name, obj);
87          return true;
88      }
89  
90      //TODO: annotations on accessors is necessary
91      private void updateTrendingMap(String name, Serializable obj) {
92          Class clazz = obj.getClass(); // duplicate of previous call
93          Field[] fields = clazz.getDeclaredFields();
94          for (Field field : fields) {
95              TrendingData annotation = field.getAnnotation(TrendingData.class);
96              if (annotation != null) {
97                  try {
98                      field.setAccessible(true);
99                      Object value = field.get(obj);
100                     if (value == null) continue;
101                     Class<?> fieldClass = field.getType();
102                     String fieldName = annotation.key();
103                     if ("".equals(fieldName)) {
104                         fieldName = field.getName();
105                     }
106                     String newKey = name + "/" + fieldName;
107                     //what if value is not serializable!
108                     if (fieldClass.isPrimitive() || Serializable.class.isAssignableFrom(fieldClass)) {
109                         ObjectNType objNtype = new ObjectNType(fieldClass, (Serializable) value);
110                         if (objNtype.isOfWellKnownType()) {
111                             trendingDesc.put(newKey, objNtype);
112                         } else {
113                             Trendable trendable = fieldClass.getAnnotation(Trendable.class);
114                             if (trendable != null) {
115                                 updateTrendingMap(newKey, (Serializable) value);
116                             } else {
117                                 //TODO? what to do?
118                                 updateTrendingMapWithString(newKey, value);
119                             }
120                         }
121                     } else {
122                         updateTrendingMapWithString(newKey, value);
123                     }
124                 } catch (IllegalAccessException e) {
125                     //TODO log
126                     CURLOG.warning("Non Accessible field!" + name + " " + obj, e);
127                 }
128             }
129         }
130     }
131 
132     private void updateTrendingMapWithString(String name, Object obj) {
133         trendingDesc.put(name, new ObjectNType(String.class, String.valueOf(obj)));
134     }
135 
136 
137     public boolean isOfWellKnownType() {
138         if (data instanceof ObjectNType) {
139             return ((ObjectNType) data).isOfWellKnownType();
140         }
141         return true;
142     }
143 
144     public boolean isOfPrimitiveType() {
145         if (data instanceof ObjectNType) {
146             return ((ObjectNType) data).isOfPrimitiveType();
147         }
148         return false;
149     }
150 
151     /**
152      * Map of Trending key/values: the values are itself of type
153      * <TT>ObjectNType</TT> so you can get the real type to be used.
154      * @return
155      */
156     public Map<String, ObjectNType> getTrendingMap() {
157         //TODO: should be readOnly
158         return trendingDesc;
159     }
160 
161     /**
162      * to be used to retrieve the contained data.
163      * An Exception is thrown if the contained Object cannot be deserialized
164      *
165      * @return
166      * @throws ClassNotFoundException
167      */
168     public Object getRealData() throws ClassNotFoundException {
169         if (data instanceof ObjectNType) {
170             return ((ObjectNType) data).getData();
171         }
172         // should not happen
173         return data;
174     }
175 
176     /**
177      * kept for compatibility reasons (use getRealData instead).
178      *
179      * @return
180      */
181     @Deprecated
182     public Object getData() {
183         try {
184             return getRealData();
185         } catch (ClassNotFoundException e) {
186             if (data instanceof ObjectNType) {
187                 return null ;
188                 //return ((ObjectNType) data).getRawData();
189             }
190             // should not happen
191             return data;
192         }
193     }
194 
195     public ObjectNType getObjectNType() {
196         return (ObjectNType) data;
197     }
198 
199     @Override
200     public String toString() {
201         return "TrendingData(" + name + "=" + data + "@" + tStamp + ")";
202     }
203 }