View Javadoc

1   package org.weda.tapestry.component;
2   
3   import java.util.ArrayList;
4   import java.util.Arrays;
5   import java.util.Collection;
6   import java.util.HashSet;
7   import java.util.List;
8   import java.util.Map;
9   import java.util.Map.Entry;
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.apache.hivemind.ApplicationRuntimeException;
15  import org.apache.tapestry.BaseComponent;
16  import org.apache.tapestry.IComponent;
17  import org.apache.tapestry.IMarkupWriter;
18  import org.apache.tapestry.INamespace;
19  import org.apache.tapestry.IRender;
20  import org.apache.tapestry.IRequestCycle;
21  import org.apache.tapestry.NestedMarkupWriter;
22  import org.apache.tapestry.annotations.Bean;
23  import org.apache.tapestry.annotations.ComponentClass;
24  import org.apache.tapestry.annotations.InjectObject;
25  import org.apache.tapestry.annotations.Lifecycle;
26  import org.apache.tapestry.annotations.Parameter;
27  import org.apache.tapestry.annotations.Persist;
28  import org.apache.tapestry.binding.BindingFactory;
29  import org.weda.action.ActionContainer;
30  import org.weda.action.ActionContainerProvider;
31  import org.weda.action.ActionDescriptor;
32  import org.weda.action.ActionExecutionContext;
33  import org.weda.action.ActionListener;
34  import org.weda.action.ActionParameter;
35  import org.weda.action.ActionRegistry;
36  import org.weda.action.ActionState;
37  import org.weda.action.ExecutedActionInfo;
38  import org.weda.action.StateableObject;
39  import org.weda.converter.ValueTypeConverter;
40  import org.weda.converter.ValueTypeConverterException;
41  import org.weda.action.Parameter.Direction;
42  import org.weda.action.impl.ActionExecutionContextImpl;
43  import org.weda.tapestry.Utils;
44  import org.weda.action.impl.ActionUtil;
45  import org.weda.workflow.Workflow;
46  
47  /**Цель: отображение действий доступных для заданого компонента
48   *
49   * @author tim
50   */
51  @ComponentClass(allowBody=true,allowInformalParameters=false)
52  public abstract class ActionPanel extends BaseComponent {
53      private static final Log log = LogFactory.getLog(ActionPanel.class);
54      /**Имя аттрибута в IRequestCycle в котором храниться стек ActionPanel'ов.
55       * (Stack<ActionPanel>)
56       */
57      public final static String ACTION_PANEL_ATTRIBUTE_NAME = 
58              ActionPanel.class.getName();
59      //TODO: переделать на
60      public final static String TOP_POSITION="top";
61      public final static String LEFT_POSITION="left";
62      public final static String BOTTOM_POSITION="bottom";
63      public final static String RIGHT_POSITION="right";
64      
65      public int index;
66      
67      private int actionIndex;
68      private ActionPanel parentActionPanel;
69      private NestedMarkupWriter bodyWriter;
70      
71      @Persist()
72      public abstract ExecutedActionInfo getExecutedActionInfo();
73      public abstract void setExecutedActionInfo(ExecutedActionInfo info);
74      
75      @Parameter()
76      public abstract String getStyle();
77      //TODO: переделать на horizontalPosition(top, bottom) и verticalPosition (left, right)
78      @Parameter(defaultValue="literal:top")
79      public abstract String getPosition();
80      @Parameter(required=false)
81      public abstract Object[] getActionContainers();
82      @Parameter(required=false, defaultValue="ognl:false")
83      public abstract boolean isRenderActionAsLink();
84      @Parameter(required=false)
85      public abstract Map<String, Object> getActionParameters();
86      //
87      @InjectObject("service:org.weda.action.ActionRegistry")
88      public abstract ActionRegistry getActionRegistry();
89      @InjectObject("service:org.weda.converter.ValueTypeConverter")
90      public abstract ValueTypeConverter getValueTypeConverter();
91      @InjectObject("service:org.weda.workflow.Workflow")
92      public abstract Workflow getWorkflow();
93      @InjectObject("service:tapestry.bindings.OGNLBindingFactory")
94      public abstract BindingFactory getOgnlService();
95      
96      @Bean(value=ArrayList.class)
97      public abstract List<ActionContainerProvider> getActionContainerProviders();
98      @Bean(value=ArrayList.class)
99      public abstract List<ActionListener> getActionListeners();
100     @Bean(value=ArrayList.class)
101     public abstract List<List> getContainers();    
102 
103     /**Метод выполняет действие.
104      */
105     public void executeAction(
106             ActionContainer container, ActionState state
107             , Map<String, Object> actionParameters
108             , Map objectState) 
109         throws Exception 
110     {
111         log.debug("action index: "+index);
112         if (log.isDebugEnabled())
113             log.debug(String.format(
114                     "Executing action (name: %s; class: %s) " +
115                     "for action container (name: %s; class: %s)"
116                     , state.getActionDescriptor().getName()
117                     , state.getActionDescriptor().getActionClass()
118                     , container.getActionContainerName()
119                     , container.getClass().getName()));
120         if (container instanceof StateableObject)
121             ((StateableObject)container).restoreState(objectState);
122         ActionExecutionContextImpl context = 
123                 new ActionExecutionContextImpl();
124         context.setObjectState(objectState);
125         context.setActionDescriptor(state.getActionDescriptor());
126         //через параметр actionParameters
127         setActionParameters(state, context, actionParameters);
128         context.setTargetObject(container);
129         for (ActionListener listener: getActionListeners())
130             getActionRegistry().addActionListener(listener);
131         try{
132             ExecutedActionInfo info = container.executeAction(context);
133             if (container instanceof StateableObject)
134                 ((StateableObject)container).resetState(objectState);
135             setExecutedActionInfo(info);
136             getWorkflow().getNextPage(getPage().getPageName(), null);
137         }finally{
138             for (ActionListener listener: getActionListeners())
139                 getActionRegistry().removeActionListener(listener);
140         }
141     }    
142     
143     //TODO: перенести в ActionRegistry
144     private void setActionParameters(
145             ActionState state, ActionExecutionContext actionContext
146             , Map<String, Object> actionParameters) 
147         throws Exception
148     {
149         //установим параметры переданные actionPanel на прямую 
150         if (actionParameters!=null)
151             for (Entry<String, Object> param: actionParameters.entrySet())
152                 actionContext.setActionParameterValue(
153                     param.getKey(), param.getValue());
154         //установим параметры устновленные для действия в UI
155         for (Map.Entry<String, Object> parameter
156                 : state.getParameterValues().entrySet())
157         {                
158             ActionParameter actionParameter = 
159                     state.getActionDescriptor()
160                     .getActionParameter(parameter.getKey());
161             if (actionParameter.getDirection()==Direction.READ_WRITE){
162                 actionContext.setActionParameterValue(
163                         parameter.getKey()
164                       , getValueTypeConverter().convert(
165                             actionParameter.getPropertyClass()
166                           , parameter.getValue()
167                           , null));
168             }
169         }
170     }
171     
172     public void addActionListeners(Collection<ActionListener> listeners){
173         getActionListeners().addAll(listeners);
174     }
175     
176     public void addActionListener(ActionListener listener){
177         getActionListeners().add(listener);
178     }
179     
180     public void addActionContainerProvider(ActionContainerProvider provider){
181         getActionContainerProviders().add(provider);
182     }
183     
184     private void addContainerActions(
185             ActionContainer container, Set<ActionDescriptor> descriptors) 
186         throws Exception
187     {
188         if (container!=null){
189             Map objectState = null;
190             if (container instanceof StateableObject)
191                 objectState = ((StateableObject)container).getState();
192             List<ActionState> states=container.getActionsStates();
193             if (states!=null)
194                 for (ActionState state: states)
195                     if (!descriptors.contains(state.getActionDescriptor())){
196                         getContainers().add(
197                                 Arrays.asList(container, state, objectState));
198                         descriptors.add(state.getActionDescriptor());
199                     }
200         }
201     }
202     
203     public void setActionIndex(int actionIndex) {
204         this.actionIndex = actionIndex;
205         log.debug(String.format("action index (%d) setted", actionIndex));
206     }
207     
208     protected void prepareActionPanel(
209             IRequestCycle cycle)
210     {
211         try{
212             if (parentActionPanel!=null)
213                 parentActionPanel.addActionListeners(getActionListeners());
214             Set<ActionDescriptor> descriptors = new HashSet<ActionDescriptor>();
215             if (getActionContainers()!=null)
216                 for (Object obj: getActionContainers())
217                     addContainerActions((ActionContainer)obj, descriptors);
218             for (ActionContainerProvider provider
219                         : getActionContainerProviders())
220             {
221                 List<ActionContainer> providerContainers = 
222                         ActionUtil.getActionContainersTree(provider);
223                 if (providerContainers!=null)
224                     for (ActionContainer container: providerContainers)
225                         addContainerActions(container, descriptors);
226             }
227             if (log.isDebugEnabled()){
228                 log.debug(String.format(
229                         "Added (%d) containers actions to the action panel: "
230                         , getContainers().size()));
231                 for (List pair: getContainers()){
232                     ActionContainer container=(ActionContainer)pair.get(0);
233                     ActionDescriptor descriptor=
234                             ((ActionState)pair.get(1)).getActionDescriptor();
235                     log.debug(String.format(
236                         "-- container (name: %s, class: %s)" +
237                         ", action (name: %s, class: %s)"
238                         , container.getActionContainerName()
239                         , container.getClass().getName()
240                         , descriptor.getName()
241                         , descriptor.getActionClass().getName()));
242                 }
243             }            
244         }catch(Exception e){
245             log.error("Action panel prepare for render error", e);
246             throw new ApplicationRuntimeException(e);
247         }            
248     }
249 
250     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) {
251         getActionContainerProviders().clear();
252         getActionListeners().clear();
253         getContainers().clear();
254         
255         setParentActionPanel(null);
256         Stack<ActionPanel> actionPanels = 
257                 (Stack<ActionPanel>)
258                     cycle.getAttribute(ACTION_PANEL_ATTRIBUTE_NAME);
259         if (actionPanels==null){
260             actionPanels = new Stack<ActionPanel>();
261             cycle.setAttribute(ACTION_PANEL_ATTRIBUTE_NAME, actionPanels);
262         }
263         ActionPanel parentActionPanel = null;
264         if (actionPanels.size()>0)
265             setParentActionPanel(actionPanels.peek());        
266         actionPanels.push(this);                
267         
268         super.renderComponent(writer, cycle);
269         
270         actionPanels.pop();
271     }
272     
273     public void startRenderBody(IMarkupWriter writer, IRequestCycle cycle){
274         bodyWriter = writer.getNestedWriter();
275         renderBody(bodyWriter, cycle);        
276         prepareActionPanel(cycle);        
277     }
278     
279     public void finishRenderBody(){
280         bodyWriter.close();
281     }
282 
283     public ActionPanel getParentActionPanel() {
284         return parentActionPanel;
285     }
286 
287     public void setParentActionPanel(ActionPanel parentActionPanel) {
288         this.parentActionPanel = parentActionPanel;
289     }
290 
291 }