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
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
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
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
144 private void setActionParameters(
145 ActionState state, ActionExecutionContext actionContext
146 , Map<String, Object> actionParameters)
147 throws Exception
148 {
149
150 if (actionParameters!=null)
151 for (Entry<String, Object> param: actionParameters.entrySet())
152 actionContext.setActionParameterValue(
153 param.getKey(), param.getValue());
154
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 }