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
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
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
214 ActionState actionState;
215 for (ActionDescriptor descriptor: descriptors){
216 Action action = createAction(descriptor.getActionClass());
217 actionState = action.getActionState(targetObject);
218 if (actionState.isAvailable()){
219
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
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
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
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 }