1   /*
2    * Copyright 2003 - 2013 The eFaps Team
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   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  package org.efaps.admin.event;
22  
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.util.HashMap;
26  
27  import org.efaps.admin.AbstractAdminObject;
28  import org.efaps.admin.datamodel.Type;
29  import org.efaps.admin.event.Parameter.ParameterValues;
30  import org.efaps.admin.program.esjp.EFapsClassLoader;
31  import org.efaps.ci.CIAdminCommon;
32  import org.efaps.ci.CIAdminEvent;
33  import org.efaps.ci.CIAdminProgram;
34  import org.efaps.db.Instance;
35  import org.efaps.db.MultiPrintQuery;
36  import org.efaps.db.QueryBuilder;
37  import org.efaps.db.SelectBuilder;
38  import org.efaps.util.EFapsException;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  /**
43   * In this Class a Event can be defined. <br/>
44   * On loading the Cache all EventDefenitions are initialized and assigned to the
45   * specific administrational type or command. On initialization of a
46   * EventDefinition, for faster access during runtime, the Class of the Program
47   * is instantiated and the Method stored.
48   *
49   * @author The eFaps Team
50   * @version $Id$
51   */
52  public final class EventDefinition
53      extends AbstractAdminObject
54      implements EventExecution
55  {
56      /**
57       * Needed for serialization.
58       */
59      private static final long serialVersionUID = 1L;
60  
61      /**
62       * Logger for this class.
63       */
64      private static final Logger LOG = LoggerFactory.getLogger(EventDefinition.class);
65  
66      /**
67       * The variable stores the position in a event pool (more than one event
68       * definition for one thrown event.
69       *
70       * @see #getIndexPos
71       */
72      private final int indexPos;
73  
74      /**
75       * The variable stores the Name of the JavaClass.
76       */
77      private final String resourceName;
78  
79      /**
80       * The variable stores the Name of the method to be invoked.
81       */
82      private final String methodName;
83  
84      /**
85       * @param _instance Instance of this EventDefinition
86       * @param _name name of this EventDefinition
87       * @param _indexPos index position of this EventDefinition
88       * @param _resourceName name of the resource of this EventDefinition
89       * @param _method method of this EventDefinition
90       * @throws EFapsException on error
91       */
92      private EventDefinition(final Instance _instance,
93                              final String _name,
94                              final int _indexPos,
95                              final String _resourceName,
96                              final String _method)
97          throws EFapsException
98      {
99          super(_instance.getId(), null, _name);
100         this.indexPos = _indexPos;
101         this.resourceName = _resourceName;
102         this.methodName = _method;
103         checkProgramInstance();
104         setProperties(_instance);
105     }
106 
107     /**
108      * Set the properties in the superclass.
109      *
110      * @param _instance Instance of this EventDefinition
111      * @throws EFapsException on error
112      */
113     private void setProperties(final Instance _instance)
114         throws EFapsException
115     {
116         final QueryBuilder queryBldr = new QueryBuilder(CIAdminCommon.Property);
117         queryBldr.addWhereAttrEqValue("Abstract", _instance.getId());
118         final MultiPrintQuery multi = queryBldr.getPrint();
119         multi.addAttribute("Name", "Value");
120         multi.executeWithoutAccessCheck();
121         while (multi.next()) {
122             super.setProperty(multi.<String>getAttribute("Name"), multi.<String>getAttribute("Value"));
123         }
124     }
125 
126     /**
127      * This is the getter method for instance variable {@link #indexPos}.
128      *
129      * @return value of instance variable {@link #indexPos}
130      * @see #indexPos
131      */
132     public long getIndexPos()
133     {
134         return this.indexPos;
135     }
136 
137     /**
138      * This is the getter method for instance variable {@link #resourceName}.
139      *
140      * @return value of instance variable {@link #resourceName}
141      * @see #resourceName
142      */
143     public String getResourceName()
144     {
145         return this.resourceName;
146     }
147 
148     /**
149      * Method to check if the instance of the esjp is valid.
150      */
151     private void checkProgramInstance()
152     {
153         try {
154             if (EventDefinition.LOG.isDebugEnabled()) {
155                 EventDefinition.LOG.debug("checking Instance: {} - {}", this.resourceName, this.methodName);
156             }
157             final Class<?> cls = Class.forName(this.resourceName, true, EFapsClassLoader.getInstance());
158             final Method method = cls.getMethod(this.methodName, new Class[] { Parameter.class });
159             final Object progInstance = cls.newInstance();
160             if (EventDefinition.LOG.isDebugEnabled()) {
161                 EventDefinition.LOG.debug("found Class: {} and method {}", progInstance, method);
162             }
163         } catch (final ClassNotFoundException e) {
164             EventDefinition.LOG.error("could not find Class: '{}'", this.resourceName, e);
165         } catch (final InstantiationException e) {
166             EventDefinition.LOG.error("could not instantiat Class: '{}'", this.resourceName, e);
167         } catch (final IllegalAccessException e) {
168             EventDefinition.LOG.error("could not access Class: '{}'", this.resourceName, e);
169         } catch (final SecurityException e) {
170             EventDefinition.LOG.error("could not access Class: '{}'", this.resourceName, e);
171         } catch (final NoSuchMethodException e) {
172             EventDefinition.LOG.error("could not find method: '{}' in class '{}'",
173                             new Object[] { this.methodName, this.resourceName, e });
174         }
175     }
176 
177     /**
178      * Method to execute the esjp.
179      *
180      * @param _parameter Parameter
181      * @return Return
182      * @throws EFapsException on error
183      */
184     public Return execute(final Parameter _parameter)
185         throws EFapsException
186     {
187         Return ret = null;
188         _parameter.put(ParameterValues.PROPERTIES, new HashMap<String, String>(super.getProperties()));
189         try {
190             EventDefinition.LOG.debug("Invoking method '{}' for Resource '{}'", this.methodName, this.resourceName);
191             final Class<?> cls = Class.forName(this.resourceName, true, EFapsClassLoader.getInstance());
192             final Method method = cls.getMethod(this.methodName, new Class[] { Parameter.class });
193             ret = (Return) method.invoke(cls.newInstance(), _parameter);
194             EventDefinition.LOG.debug("Terminated invokation of method '{}' for Resource '{}'",
195                             this.methodName, this.resourceName);
196         } catch (final SecurityException e) {
197             EventDefinition.LOG.error("security wrong: '{}'", this.resourceName, e);
198         } catch (final IllegalArgumentException e) {
199             EventDefinition.LOG.error("arguments invalid : '{}'- '{}'", this.resourceName, this.methodName, e);
200         } catch (final IllegalAccessException e) {
201             EventDefinition.LOG.error("could not access class: '{}'", this.resourceName, e);
202         } catch (final InvocationTargetException e) {
203             EventDefinition.LOG.error("could not invoke method: '{}' in class: '{}'", this.methodName,
204                             this.resourceName, e);
205             throw (EFapsException) e.getCause();
206         } catch (final ClassNotFoundException e) {
207             EventDefinition.LOG.error("class not found: '{}" + this.resourceName, e);
208         } catch (final NoSuchMethodException e) {
209             EventDefinition.LOG.error("could not find method: '{}' in class '{}'",
210                             new Object[] { this.methodName, this.resourceName, e });
211         } catch (final InstantiationException e) {
212             EventDefinition.LOG.error("could not instantiat Class: '{}'", this.resourceName, e);
213         }
214         return ret;
215     }
216 
217     @Override
218     public boolean equals(final Object _obj)
219     {
220         boolean ret;
221         if (_obj instanceof EventDefinition) {
222             ret = ((EventDefinition) _obj).getId() == getId();
223         } else {
224             ret = super.equals(_obj);
225         }
226         return ret;
227     }
228 
229     @Override
230     public int hashCode()
231     {
232         return Long.valueOf(getId()).intValue();
233     }
234 
235 
236     /**
237      * @param _adminObject Object the event is added to
238      * @throws EFapsException on error
239      */
240     public static void addEvents(final AbstractAdminObject _adminObject)
241         throws EFapsException
242     {
243         // check is necessary for the first time installation
244         if (CIAdminEvent.Definition.getType() != null && CIAdminEvent.Definition.getType().getMainTable() != null) {
245             final QueryBuilder queryBldr = new QueryBuilder(CIAdminEvent.Definition);
246             queryBldr.addWhereAttrEqValue(CIAdminEvent.Definition.Abstract, _adminObject.getId());
247             final MultiPrintQuery multi = queryBldr.getPrint();
248             final SelectBuilder selClass = new SelectBuilder().linkto(CIAdminEvent.Definition.JavaProg).attribute(
249                             CIAdminProgram.Java.Name);
250             multi.addSelect(selClass);
251             multi.addAttribute(CIAdminEvent.Definition.Type,
252                             CIAdminEvent.Definition.Name,
253                             CIAdminEvent.Definition.IndexPosition,
254                             CIAdminEvent.Definition.Method);
255             multi.executeWithoutAccessCheck();
256             while (multi.next()) {
257                 // define all variables here so that an error can be thrown
258                 // containing the
259                 // values that where set correctly
260                 Instance inst = null;
261                 Type eventType = null;
262                 String eventName = null;
263                 int eventPos = 0;
264                 final long abstractID = 0;
265                 String program = "";
266                 String method = null;
267                 try {
268                     inst = multi.getCurrentInstance();
269                     eventType = multi.<Type>getAttribute(CIAdminEvent.Definition.Type);
270                     eventName = multi.<String>getAttribute(CIAdminEvent.Definition.Name);
271                     eventPos = multi.<Integer>getAttribute(CIAdminEvent.Definition.IndexPosition);
272                     program = multi.<String>getSelect(selClass);
273                     method = multi.<String>getAttribute(CIAdminEvent.Definition.Method);
274 
275                     EventDefinition.LOG.debug("Reading EventDefinition for: ");
276                     EventDefinition.LOG.debug("   object = {}", _adminObject);
277                     EventDefinition.LOG.debug("   Instance = {}", inst);
278                     EventDefinition.LOG.debug("   eventType = {}", eventType);
279                     EventDefinition.LOG.debug("   eventName = {}", eventName);
280                     EventDefinition.LOG.debug("   eventPos = {}", eventPos);
281                     EventDefinition.LOG.debug("   parentId = {}", abstractID);
282                     EventDefinition.LOG.debug("   program = {}", program);
283                     EventDefinition.LOG.debug("   Method = {}", method);
284 
285                     EventType triggerEvent = null;
286                     for (final EventType trigger : EventType.values()) {
287                         final Type triggerClass = Type.get(trigger.getName());
288                         if (eventType.isKindOf(triggerClass)) {
289                             if (EventDefinition.LOG.isDebugEnabled()) {
290                                 EventDefinition.LOG.debug("     found trigger " + trigger + ":" + triggerClass);
291                             }
292                             triggerEvent = trigger;
293                             break;
294                         }
295                     }
296 
297                     _adminObject.addEvent(triggerEvent,
298                                     new EventDefinition(inst, eventName, eventPos, program, method));
299 
300                     // CHECKSTYLE:OFF
301                 } catch (final Exception e) {
302                     // CHECKSTYLE:ON
303                     EventDefinition.LOG.error(
304                                     "Instance: {}, eventType: {}, eventName: {}, eventPos: {}, parentId: {}, "
305                                                     + "programId: {}, MethodresName: {}, , arguments: {}",
306                                     inst, eventType, eventName, eventPos, abstractID, program, method, program);
307                     if (e instanceof EFapsException) {
308                         throw (EFapsException) e;
309                     } else {
310                         throw new EFapsException(EventDefinition.class, "initialize", e, inst, eventName, eventPos,
311                                         program, method);
312                     }
313                 }
314             }
315         }
316     }
317 
318     /**
319      * Loads all events from the database and assigns them to the specific
320      * administrational type or command.
321      *
322      * @throws EFapsException on error
323      */
324     public static void initialize()
325         throws EFapsException
326     {
327 
328     }
329 }