View Javadoc

1   package org.weda.action.impl;
2   
3   import java.beans.Introspector;
4   import java.lang.reflect.Method;
5   import java.util.ArrayList;
6   import java.util.HashMap;
7   import java.util.List;
8   import java.util.ListIterator;
9   import java.util.Map;
10  import java.util.Set;
11  import java.util.Stack;
12  import org.apache.commons.logging.Log;
13  import org.apache.commons.logging.LogFactory;
14  import org.weda.action.Action;
15  import org.weda.action.ActionContainer;
16  import org.weda.action.ActionDescriptor;
17  import org.weda.action.ActionEvent;
18  import org.weda.action.ActionExecutionContext;
19  import org.weda.action.ActionListener;
20  import org.weda.action.ActionListenerFilter;
21  import org.weda.action.ActionParameter;
22  import org.weda.action.ActionRegistry;
23  import org.weda.action.ActionRegistryException;
24  import org.weda.action.ActionState;
25  import org.weda.action.ActionTargetClass;
26  import org.weda.action.ExecutedActionInfo;
27  import org.weda.action.GlobalActionsProvider;
28  import org.weda.action.LinkedAction;
29  import org.weda.action.StateableObject;
30  import org.weda.message.Messages;
31  import org.weda.message.MessagesRegistry;
32  import org.weda.message.impl.MessagesSubset;
33  import org.weda.property.ObjectDescriptorRegistry;
34  import org.weda.enhance.ObjectEnhancer;
35  import org.weda.enhance.ObjectEnhancerException;
36  import org.weda.property.PropertyDescriptor;
37  import org.weda.property.PropertyValue;
38  import org.weda.action.Parameter;
39  import org.weda.action.Parameter.Direction;
40  import org.weda.cache.CacheEntity;
41  import org.weda.cache.CacheManager;
42  
43  /**Цель: сервис, предоставляющий доступ к действиям
44   *
45   * @author tim
46   */
47  public class ActionRegistryImpl implements ActionRegistry {
48      private final static Log log = 
49              LogFactory.getLog(ActionRegistryImpl.class);
50      
51      private Map<Class, List<ActionDescriptor>> targetClasses = 
52          new HashMap<Class, List<ActionDescriptor>>();
53      //Ассоция м/д классом действия и его расширенным представлением
54      private Map<Class/*action class*/, Class/*enhanced action class*/> 
55                  actionClasses = new HashMap<Class, Class>();    
56      private List<ActionDescriptor> actionDescriptors;
57      private Map<ActionListenerFilter, List<ActionListener>> listeners;
58      private List<ActionListener> actionListenersConfig;
59      private ObjectDescriptorRegistry objectDescriptorRegistry;
60      private PropertyValue propertyValue;
61      private CacheManager cacheManager;
62      private String messageCategory;
63      private MessagesRegistry messages;
64      private Messages actionsMessages;
65      private ObjectEnhancer enhancer;
66      
67      public void init() throws ActionRegistryException {
68          try{
69              actionsMessages = 
70                      new MessagesSubset(messages, getMessageCategory());
71              //initializing action listeners from config
72              for (ActionListener listener: actionListenersConfig)
73                  addActionListener(listener);
74              for (ActionDescriptor desc: actionDescriptors){
75                  Messages subset = new MessagesSubset(
76                          actionsMessages, desc.getActionClass().getName());
77                  desc.setMessages(subset);
78                  if (!actionClasses.containsKey(desc.getActionClass()))
79                      actionClasses.put(
80                              desc.getActionClass()
81                              , enhancer.enhanceClass(desc.getActionClass()));
82                  if (desc.getTargetClasses().size()==0){
83                      if (!targetClasses.containsKey(null))
84                          targetClasses.put(
85                              null
86                              , new ArrayList<ActionDescriptor>());
87                      targetClasses.get(null).add(desc);
88                  }else{
89                      for (ActionTargetClass targetClass
90                              : desc.getTargetClasses())
91                      {
92                          if (!targetClasses.containsKey(
93                                  targetClass.getTargetClass()))
94                          {
95                              targetClasses.put(
96                                  targetClass.getTargetClass()
97                                  , new ArrayList<ActionDescriptor>());
98                          }
99                          targetClasses.get(
100                                 targetClass.getTargetClass()).add(desc);
101                     }
102                 }
103                 extractActionParameters(desc);
104                 desc.init();
105             }
106         }catch(Exception e){
107             throw new ActionRegistryException(
108                     "Can't initialize action registry service", e);
109         }
110     }
111         
112     public synchronized boolean removeActionListener(ActionListener listener) {
113         if (listeners!=null){
114             ActionListenerFilter filter = listener.getFilter();
115             if (filter==null)
116                 filter = ActionListenerFilterImpl.EMPTY_FILTER;
117             List<ActionListener> filterListeners = listeners.get(filter);
118             if (filterListeners!=null)
119                 return filterListeners.remove(listener);
120         }
121         return false;
122     }
123 
124     public synchronized void addActionListener(ActionListener listener) {
125         if (listeners==null)
126             listeners = 
127                     new HashMap<ActionListenerFilter, List<ActionListener>>();
128         ActionListenerFilter filter = listener.getFilter();
129         if (filter==null)
130             filter = ActionListenerFilterImpl.EMPTY_FILTER;
131         List<ActionListener> filterListeners = listeners.get(filter);
132         if (filterListeners==null){
133             filterListeners = new ArrayList<ActionListener>();
134             listeners.put(filter, filterListeners);
135         }
136         filterListeners.add(listener);
137     }
138     
139     public synchronized List<ActionListener> collectListenersForAction(
140             ActionExecutionContext eContext)
141     {
142         List<ActionListener> actionListeners = null;
143         if (listeners!=null){
144             ActionListenerFilter[] filters = new ActionListenerFilter[4];
145             filters[0]=
146                     new ActionListenerFilterImpl(
147                         eContext.getActionDescriptor().getActionClass()
148                         , eContext.getTargetObject().getClass());
149             filters[1]= 
150                     new ActionListenerFilterImpl(
151                         null, filters[0].getTargetClass());
152             filters[2]=
153                     new ActionListenerFilterImpl(
154                         filters[0].getActionClass(), null);
155             filters[3]= ActionListenerFilterImpl.EMPTY_FILTER;
156             for (ActionListenerFilter filter: filters){
157                 List<ActionListener> filterListeners = listeners.get(filter);
158                 if (filterListeners!=null){
159                     for (ActionListener listener: filterListeners){
160                         if (   listener.getFilter()==null
161                             || listener.getFilter().getTargetNames()==null
162                             || listener.getFilter().getTargetNames()
163                                     .contains(
164                                         eContext.getTargetObject()
165                                                 .getActionContainerName()))
166                         {
167                             if (actionListeners==null)
168                                 actionListeners = 
169                                         new ArrayList<ActionListener>();
170                             actionListeners.add(listener);
171                         }
172                     }
173                 }
174             }
175         }
176         return actionListeners;
177     }
178     
179     private void fireActionEvent(
180             List<ActionListener> actionListeners
181             , ActionEvent event
182             , boolean isBeforeExecute)
183         throws Exception
184     {
185         if (actionListeners!=null)
186             for (ActionListener listener: actionListeners)
187                 if (isBeforeExecute)
188                     listener.beforeExecute(event);
189                 else
190                     listener.afterExecute(event);
191     }
192         
193     
194     public void setActionDescriptors(List<ActionDescriptor> actionDescriptors){
195         this.actionDescriptors=actionDescriptors;
196     }
197     
198     public boolean hasRegisteredActions(
199             Class targetClass, ActionContainer targetObject)
200     {        
201         return getActionDescriptors(targetClass, targetObject).size()>0;
202     }
203     
204     public List<ActionState> getActionsStates(
205             ActionContainer targetObject, Class targetClass) 
206         throws ActionRegistryException
207     {
208         try{
209             List<ActionDescriptor> descriptors = 
210                     getActionDescriptors(targetClass, targetObject);
211             List<ActionState> actionsStates = new ArrayList<ActionState>();
212             if (descriptors.size()>0){
213                 //actionsStates = new ArrayList<ActionState>();
214                 ActionState actionState;
215                 for (ActionDescriptor descriptor: descriptors){
216                     Action action = createAction(descriptor.getActionClass());
217                     actionState = action.getActionState(targetObject);
218                     if (actionState.isAvailable()){
219                         //считаем значения READABLE свойств
220                         for (ActionParameter parameter: 
221                                 descriptor.getActionParameters())
222                         {
223                             if (   parameter.getDirection()==Direction.READ 
224                                 || parameter.getDirection()==Direction.READ_WRITE)
225                             {
226                                 actionState.setParameterValue(
227                                         parameter.getName()
228                                         , propertyValue.getValue(
229                                                 action, parameter.getGetterId())
230                                 );
231                             }
232                         }
233                         actionState.setActionDescriptor(descriptor);
234                         actionState.setTargetFrame(descriptor.getTargetFrame());
235                         actionsStates.add(actionState);
236                     }
237                 }
238             }
239             return actionsStates;
240         }catch(Exception e){
241             throw new ActionRegistryException(
242                 String.format(
243                     "Can't determine avalaible actions for target class (%s)" +
244                     (targetObject==null?"":" and target object name (%s)")
245                     , targetClass.getName()
246                     , targetObject==null
247                         ? "null" : targetObject.getActionContainerName())
248                 , e);
249         }
250     }
251     
252     private List<ActionDescriptor> getActionDescriptors(
253             Class targetClass, ActionContainer targetObject)
254     {
255         Set<Class> disabledActions = null;
256         if (targetObject!=null)
257             disabledActions = targetObject.getDisabledActions();
258         //получим действия зарегистрированные для targetClass
259         List<ActionDescriptor> descriptors=targetClasses.get(targetClass);
260         if (descriptors==null)
261             descriptors = new ArrayList<ActionDescriptor>();
262         descriptors = new ArrayList<ActionDescriptor>(descriptors);
263         //добавим глобальных действий если есть необходимость.
264         if (targetObject instanceof GlobalActionsProvider){
265             List<ActionDescriptor> globalDescriptors = 
266                     targetClasses.get(null);
267             if (globalDescriptors!=null)
268                 descriptors.addAll(globalDescriptors);
269         }
270         boolean actionForObject;
271         for (ListIterator<ActionDescriptor> it = descriptors.listIterator()
272                 ; it.hasNext();)
273         {
274             ActionDescriptor descriptor = it.next();
275             actionForObject=false;
276             if (   disabledActions == null 
277                 || !disabledActions.contains(descriptor.getActionClass()))
278             {
279                 if (descriptor.getTargetClasses().size()==0)
280                     actionForObject=true;
281                 else{
282                     for(ActionTargetClass tac: descriptor.getTargetClasses())
283                         if (targetClass.equals(tac.getTargetClass())){
284                             if (   tac.getTagetObjectNames()==null
285                                 || tac.getTagetObjectNames().size()==0
286                                 || tac.getTagetObjectNames().contains(
287                                         targetObject.getActionContainerName()))
288                             {
289                                 actionForObject=true;
290                             }
291                             break;
292                         }
293                 }
294             }
295             if (!actionForObject)
296                 it.remove();
297         }
298         return descriptors;
299     }
300     
301     public ExecutedActionInfo executeAction(ActionExecutionContext context) 
302         throws ActionRegistryException
303     {
304         ActionDescriptor actionDescriptor = context.getActionDescriptor();
305         ActionContainer targetObject = context.getTargetObject();
306         Class actionClass = actionDescriptor.getActionClass();
307         Map<String, Object> parameterValues = context.getActionParameters();
308         ExecutedActionInfoImpl actionInfo = new ExecutedActionInfoImpl();
309         actionInfo.setActionClass(actionDescriptor.getActionClass());
310         actionInfo.setTargetClass(targetObject.getClass());
311         actionInfo.setTargetName(targetObject.getActionContainerName());
312         actionInfo.setSuccessExecution(true);
313         try{
314             try{
315                 ActionEvent actionEvent = null;
316                 List<ActionListener> actionListeners = 
317                         collectListenersForAction(context);
318                 if (actionListeners!=null){
319                     actionEvent = new ActionEventImpl(context);
320                     fireActionEvent(actionListeners, actionEvent, true);
321                 }
322                 Action action = createAction(actionClass);
323                 actionDescriptor.setActionParametersValues(action);
324                 if (parameterValues!=null){
325                     for (Map.Entry<String, Object> entry: 
326                                 parameterValues.entrySet())
327                     {
328                         Integer setterId=
329                                 actionDescriptor
330                                 .getActionParameter(entry.getKey())
331                                 .getSetterId();
332                         propertyValue.setValue(
333                                 action, setterId, entry.getValue());
334                     }
335                 }
336                 Object actionResult = action.execute(targetObject);
337                 fireActionEvent(actionListeners, actionEvent, false);
338                 actionInfo.setActionResult(actionResult);
339                 actionInfo = proccedLinkedActions(context, actionInfo);
340             }catch(Exception e){
341                 actionInfo.setSuccessExecution(false);
342                 actionInfo.setExecutionException(e);
343                 if (log.isErrorEnabled())
344                     log.error(
345                         String.format(
346                             "Can't execute action (name: %s, class: %s) " +
347                             "for target object (name: %s, class: %s)"
348                             , actionDescriptor.getName(), actionClass.getName()
349                             , targetObject.getActionContainerName()
350                             , targetObject.getClass().getName())
351                         , e);
352                             
353                 //return null;
354             }
355             return actionInfo;
356         }finally{
357             cacheExecutedActionInfo(actionInfo);
358         }
359     }
360     
361     protected ExecutedActionInfoImpl proccedLinkedActions(
362             ActionExecutionContext ctx, ExecutedActionInfoImpl actionInfo)
363         throws Exception
364     {
365         ActionDescriptor actionDescriptor = ctx.getActionDescriptor();
366         ActionContainer targetObject = ctx.getTargetObject();
367         Class actionClass = actionDescriptor.getActionClass();
368         Action action;
369         if (actionDescriptor.getLinkedActions().size()>0){
370             ActionStackEntity stackEntity = getActionStackEntity();
371             stackEntity.getActionStack().add(
372                     new StackElement(
373                         targetObject, actionDescriptor
374                         , actionInfo, ctx.getObjectState()));
375         }else{
376             ActionStackEntity stackEntity = getActionStackEntity();
377             boolean continueSearch = true;
378             while (stackEntity.getActionStack().size()>0 && continueSearch){
379                 boolean foundLinkedAction=false;
380                 boolean cancelAction=false;
381                 continueSearch = false;
382                 StackElement elem = stackEntity.getActionStack().peek();
383                 for (LinkedAction linkedAction
384                         : elem.getActionDescriptor().getLinkedActions()) 
385                 {
386                     if (actionClass.equals(linkedAction.getActionClass())) {
387                         foundLinkedAction=true;
388                         cancelAction = linkedAction.isCancelAction();
389                         break;
390                     }
391                 }
392                 if (foundLinkedAction){
393                     elem = stackEntity.getActionStack().pop();
394                     action = 
395                         createAction(
396                             elem.getActionDescriptor().getActionClass());
397                     ActionContainer target = elem.getTargetObject();
398                     if (target instanceof StateableObject)
399                         ((StateableObject)target).restoreState(
400                                 elem.getObjectState());
401                     try{
402                         action.afterLinkedActionExecute(
403                                 elem.getTargetObject()
404                                 , targetObject, cancelAction);
405                     }finally{
406                         if (target instanceof StateableObject)
407                             ((StateableObject)target).resetState(
408                                     elem.getObjectState());                        
409                     }
410                     actionInfo = elem.getExecutedActionInfo();
411                     actionClass = elem.getActionDescriptor().getActionClass();
412                     targetObject = elem.getTargetObject();
413                     continueSearch = true;
414                 }
415             }
416         }        
417         return actionInfo;
418     }
419     
420     protected void extractActionParameters(ActionDescriptor actionDescriptor)
421         throws ActionRegistryException
422     {
423         Class actionClass = actionDescriptor.getActionClass();
424         List<PropertyDescriptor> actionParameters = 
425             new ArrayList<PropertyDescriptor>();
426         String parameterName=null;
427         try{            
428             java.beans.PropertyDescriptor[] propDescs = 
429                 Introspector.getBeanInfo(actionClass).getPropertyDescriptors();
430             for (java.beans.PropertyDescriptor desc: propDescs){
431                 Method[] methods=new Method[]{
432                     desc.getReadMethod(), desc.getWriteMethod()};
433                 parameterName=desc.getName();
434                 Parameter parameter = null;
435                 //определим является ли текущее свойство объекта параметром 
436                 for (Method method: methods)
437                     if (   method!=null 
438                         && method.isAnnotationPresent(Parameter.class))
439                     {
440                         parameter = method.getAnnotation(Parameter.class);
441                         break;
442                     }
443                 if (parameter!=null){
444                     //формируем ActionParameter
445                     ActionParameterImpl actionParameter=
446                             new ActionParameterImpl();
447                     actionParameter.setParent(
448                             objectDescriptorRegistry.getPropertyDescriptor(
449                                 actionClass, parameterName));
450                     actionParameter.setDirection(parameter.direction());
451                     if (   actionParameter.getDirection() == Direction.READ 
452                         || actionParameter.getDirection() == Direction.READ_WRITE)
453                     {
454                         actionParameter.setGetterId(
455                                 propertyValue.compileGetter(
456                                     actionClass, parameterName));
457                     }
458                     if (   actionParameter.getDirection() == Direction.WRITE 
459                         || actionParameter.getDirection() == Direction.READ_WRITE)
460                     {
461                         actionParameter.setSetterId(
462                                 propertyValue.compileSetter(
463                                     actionClass, parameterName));
464                     }
465                     actionDescriptor.addActionParameter(actionParameter);
466                 }
467             }
468         }catch(Exception e){
469             if (parameterName==null)
470                 throw new ActionRegistryException(
471                     String.format(
472                         "Can't extract parameters from action class (%s)."
473                         , actionClass.getName())
474                     , e);
475             else
476                 throw new ActionRegistryException(
477                     String.format(
478                         "Can't extract parameters from action class (%s)" +
479                         ", parameter name (%s)."
480                         , actionClass.getName(), parameterName)
481                     , e);
482         }
483     }
484     
485     protected Action createAction(Class actionClass) 
486         throws ObjectEnhancerException 
487     {
488         Class enhancedActionClass = actionClasses.get(actionClass);
489         return (Action)enhancer.newInstance(enhancedActionClass);
490     }
491 
492     public void setObjectDescriptorRegistry(
493         ObjectDescriptorRegistry objectDescriptorRegistry) 
494     {
495         this.objectDescriptorRegistry = objectDescriptorRegistry;
496     }
497 
498     public void setPropertyValue(PropertyValue propertyValue) {
499         this.propertyValue = propertyValue;
500     }
501 
502     public void setCacheManager(CacheManager cacheManager) {
503         this.cacheManager = cacheManager;
504     }
505     
506     protected void cacheExecutedActionInfo(ExecutedActionInfoImpl actionInfo)
507     {
508         cacheManager.getCacheService().release(ActionInfoEntity.ID);
509         cacheManager.getCacheService().setCacheEntity(
510                 ActionInfoEntity.ID
511                 , new ActionInfoEntity(actionInfo));
512     }
513 
514     public ExecutedActionInfo getLastExecutedActionInfo() {
515         ActionInfoEntity entity = 
516                 (ActionInfoEntity)cacheManager
517                 .getCacheService()
518                 .get(ActionInfoEntity.ID);
519         if (entity==null){
520             return ExecutedActionInfoImpl.EMPTY_INFO;
521         }else
522             return entity.getExecutedActionInfo();
523     }
524     
525     protected ActionStackEntity getActionStackEntity(){
526         ActionStackEntity ent = (ActionStackEntity)
527                 cacheManager.getCacheService().get(ActionStackEntity.ID);
528         if (ent==null){
529             ent = new ActionStackEntity();
530             cacheManager.getCacheService().setCacheEntity(
531                     ActionStackEntity.ID, ent);
532         }
533         return ent;
534     }
535     
536     public String getMessageCategory() {
537         return messageCategory;
538     }
539 
540     public void setMessageCategory(String messageCategory) {
541         this.messageCategory = messageCategory;
542     }
543 
544     private static class StackElement {
545         private ActionContainer targetObject;
546         private ActionDescriptor actionDescriptor;
547         private ExecutedActionInfoImpl executedActionInfo;
548         private Map objectState;
549         
550         public StackElement(
551                 ActionContainer targetObject, ActionDescriptor actionDescriptor
552                 , ExecutedActionInfoImpl executedActionInfo
553                 , Map objectState)
554         {
555             this.targetObject = targetObject;
556             this.actionDescriptor = actionDescriptor;
557             this.executedActionInfo = executedActionInfo;
558             this.objectState = objectState;
559         }
560 
561         public ActionContainer getTargetObject() {
562             return targetObject;
563         }
564 
565         public ActionDescriptor getActionDescriptor() {
566             return actionDescriptor;
567         }
568 
569         public ExecutedActionInfoImpl getExecutedActionInfo() {
570             return executedActionInfo;
571         }
572 
573         public Map getObjectState() {
574             return objectState;
575         }
576     }
577         
578     private static class ActionInfoEntity implements CacheEntity{
579         public final static String ID = ActionInfoEntity.class.getName();
580         
581         private ExecutedActionInfoImpl executedActionInfo;
582         
583         public ActionInfoEntity(ExecutedActionInfoImpl executedActionInfo){
584             this.executedActionInfo = executedActionInfo;
585         }
586         
587         public void release() {
588         }
589 
590         public Object getValue() {
591             return getExecutedActionInfo();
592         }
593 
594         public ExecutedActionInfoImpl getExecutedActionInfo() {
595             return executedActionInfo;
596         }
597     }
598     
599     private static class ActionStackEntity implements CacheEntity {
600         public final static String ID = ActionStackEntity.class.getName();
601         private Stack<StackElement> actionStack = new Stack<StackElement>();
602         
603         public void release() {
604         }
605 
606         public Object getValue() {
607             return actionStack;
608         }
609         
610         public Stack<StackElement> getActionStack(){
611             return actionStack;
612         }
613         
614     }
615 
616     public void setObjectEnhancer(ObjectEnhancer objectEnhancer) {
617         this.enhancer = objectEnhancer;
618     }
619 
620     public void setMessages(MessagesRegistry messages) {
621         this.messages = messages;
622     }
623 
624     public void setActionListenersConfig(
625             List<ActionListener> actionListenersConfig)
626     {
627         this.actionListenersConfig = actionListenersConfig;
628     }
629 
630 }