001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.layout.impl;
018:
019: import java.io.InputStream;
020: import java.io.InputStreamReader;
021: import java.io.Reader;
022: import java.io.StringWriter;
023: import java.util.ArrayList;
024: import java.util.HashMap;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.StringTokenizer;
028:
029: import org.apache.jetspeed.ajax.AJAXException;
030: import org.apache.jetspeed.ajax.AjaxAction;
031: import org.apache.jetspeed.ajax.AjaxBuilder;
032: import org.apache.jetspeed.ajax.AjaxRequestService;
033: import org.apache.jetspeed.layout.PortletActionSecurityBehavior;
034: import org.apache.jetspeed.page.PageManager;
035: import org.apache.jetspeed.request.JetspeedRequestContext;
036: import org.apache.jetspeed.request.RequestContext;
037: import org.apache.velocity.VelocityContext;
038: import org.apache.velocity.app.VelocityEngine;
039: import org.apache.velocity.context.Context;
040: import org.springframework.beans.BeansException;
041: import org.springframework.beans.factory.BeanFactory;
042: import org.springframework.beans.factory.BeanFactoryAware;
043:
044: /**
045: *
046: * @author David Gurney
047: *
048: * The purpose of this object is to run several AJAX actions and aggregate the
049: * results into a single response. This is useful when the client needs to make
050: * more than one call as the result of a single user action.
051: *
052: * The sample request URL is shown below:
053: *
054: * http://host:port/ajaxapi?action=multiple&commands=(action;name,value;name,value)(action;name,value)
055: *
056: * The constructor accepts a map of the actions that are available to be run.
057: * The name,value pairs are parameter values needed by the action. The actions
058: * are run in the order that they are found on the URL string
059: *
060: */
061: public class MultipleAction extends BasePortletAction implements
062: AjaxAction, AjaxBuilder, BeanFactoryAware {
063:
064: protected static final String ALL_RESULTS = "results";
065:
066: protected static final String BUILD_RESULTS = "buildresults";
067:
068: protected static final String MULTIPLE_ACTION_PROCESSOR = "Multiple Action Processor";
069:
070: protected static final String COMMANDS = "commands";
071:
072: protected static final String COMMAND_TOKEN = ")";
073:
074: protected static final String PARAM_TOKEN = ";";
075:
076: protected static final String VALUE_TOKEN = ",";
077:
078: protected Map actionMap = null;
079:
080: protected VelocityEngine m_oVelocityEngine = null;
081:
082: public MultipleAction(AjaxRequestService requestService,
083: String p_sTemplate, String p_sErrorTemplate,
084: PageManager p_oPageManager,
085: PortletActionSecurityBehavior p_oSecurityBehavior,
086: VelocityEngine p_oVelocityEngine) {
087: super (p_sTemplate, p_sErrorTemplate, p_oPageManager,
088: p_oSecurityBehavior);
089: actionMap = requestService.getActionMap();
090: m_oVelocityEngine = p_oVelocityEngine;
091: }
092:
093: public void setBeanFactory(BeanFactory beanFactory)
094: throws BeansException {
095: // get the proxied object for this, and put it in the map to avoid circular dep
096: Object proxy = beanFactory.getBean("AjaxMultipleAction");
097: actionMap.put("multiple", proxy);
098: }
099:
100: public boolean run(RequestContext p_oRequestContext,
101: Map p_oResultMap) throws AJAXException {
102: boolean a_bReturnSuccess = true;
103: List a_oResultArray = new ArrayList();
104:
105: p_oResultMap.put(ACTION, "multiple");
106: p_oResultMap.put(STATUS, "success");
107:
108: // Get the command string
109: String a_sCommands = p_oRequestContext
110: .getRequestParameter(COMMANDS);
111: if (a_sCommands == null || a_sCommands.length() <= 0) {
112: buildErrorContext(p_oRequestContext, p_oResultMap);
113: p_oResultMap.put(STATUS, "failure");
114: p_oResultMap.put(REASON, "command parameters not found");
115:
116: throw new AJAXException("command parameters not found");
117: }
118:
119: // Tokenize the commands into single commands
120: StringTokenizer a_oCommandTok = new StringTokenizer(
121: a_sCommands, COMMAND_TOKEN);
122:
123: // Process each command
124: while (a_oCommandTok.hasMoreTokens()) {
125: // Get the token
126: String a_sCommand = a_oCommandTok.nextToken();
127:
128: // Strip off the opening (
129: a_sCommand = a_sCommand.substring(1);
130:
131: // Tokenize the single commands into parameters
132: StringTokenizer a_oParamTok = new StringTokenizer(
133: a_sCommand, PARAM_TOKEN);
134: if (a_oParamTok == null
135: || a_oParamTok.hasMoreTokens() == false) {
136: buildErrorContext(p_oRequestContext, p_oResultMap);
137: p_oResultMap.put(STATUS, "failure");
138: p_oResultMap.put(REASON, "incorrect url request");
139:
140: throw new AJAXException("incorrect url request");
141: }
142:
143: // Get the action - which is the first item in the list
144: String a_sAction = a_oParamTok.nextToken();
145:
146: // Lookup the action from the action map
147: Object a_oActionObject = actionMap.get(a_sAction);
148: if (a_oActionObject == null
149: && !(a_oActionObject instanceof AjaxAction)) {
150: buildErrorContext(p_oRequestContext, p_oResultMap);
151: p_oResultMap.put(REASON, "unknown action requested==>"
152: + a_sAction);
153:
154: throw new AJAXException("unknown action requested==>"
155: + a_sAction);
156: }
157:
158: AjaxAction a_oAction = (AjaxAction) a_oActionObject;
159:
160: JetspeedRequestContext a_oJetspeedRequestContext = (JetspeedRequestContext) p_oRequestContext;
161:
162: // Process each parameter for this action
163: while (a_oParamTok.hasMoreTokens()) {
164: String a_sName = a_oParamTok.nextToken(VALUE_TOKEN);
165: // Strip of the leading ; if present
166: if (a_sName.indexOf(';') >= 0) {
167: a_sName = a_sName.substring(1);
168: }
169:
170: String a_sValue = a_oParamTok.nextToken();
171:
172: // Put the parameters on the request context
173: a_oJetspeedRequestContext.setAttribute(a_sName,
174: a_sValue);
175: }
176:
177: // Invoke the action
178: Map a_oResultMap = new HashMap();
179: boolean a_bSuccess;
180:
181: try {
182: a_bSuccess = a_oAction.runBatch(
183: a_oJetspeedRequestContext, a_oResultMap);
184: } catch (Exception e) {
185: // Move the reason into the return map
186: p_oResultMap.put(REASON, a_oResultMap.get(REASON));
187:
188: throw new AJAXException(e);
189: }
190:
191: // Check for success
192: if (a_bSuccess) {
193: // Invoke the builder for this action if possible
194: if (a_oAction instanceof AjaxBuilder) {
195: processBuilder((AjaxBuilder) a_oAction,
196: a_oResultMap, p_oRequestContext, a_bSuccess);
197: }
198:
199: // Get the build results
200: String a_sBuildResults = (String) a_oResultMap
201: .get(BUILD_RESULTS);
202:
203: // Look for an xml tag and strip it off
204: int a_iStartIndex = a_sBuildResults.indexOf("<?xml");
205: if (a_iStartIndex >= 0) {
206: // Look for the end of the tag
207: int a_iEndIndex = a_sBuildResults.indexOf(">",
208: a_iStartIndex);
209: if (a_iEndIndex >= 0) {
210: String a_sStart = a_sBuildResults.substring(0,
211: a_iStartIndex);
212: String a_sEnd = a_sBuildResults.substring(
213: a_iEndIndex + 1, a_sBuildResults
214: .length());
215: a_sBuildResults = a_sStart + a_sEnd;
216: }
217: }
218:
219: if (a_sBuildResults != null) {
220: // Save the results
221: a_oResultArray.add(a_sBuildResults);
222: }
223: } else {
224: // Move the reason into the return map
225: p_oResultMap.put(REASON, a_oResultMap.get(REASON));
226:
227: // Exit the loop
228: a_bReturnSuccess = false;
229: break;
230: }
231: }
232:
233: // Save the results for later building into the response
234: p_oResultMap.put(ALL_RESULTS, a_oResultArray);
235:
236: return a_bReturnSuccess;
237: }
238:
239: // Process the builder if provided
240: protected void processBuilder(AjaxBuilder p_oBuilder,
241: Map p_oInputMap, RequestContext p_oRequestContext,
242: boolean p_oActionSuccessFlag) {
243: try {
244: // Ask the builder to construct the context
245: // Add the input map to the velocity context
246: boolean result = true;
247:
248: if (p_oActionSuccessFlag == true) {
249: result = p_oBuilder.buildContext(p_oRequestContext,
250: p_oInputMap);
251: } else {
252: result = p_oBuilder.buildErrorContext(
253: p_oRequestContext, p_oInputMap);
254: }
255:
256: Context a_oContext = new VelocityContext(p_oInputMap);
257:
258: // Check to see if we have a valid context
259: if (result) {
260: // Get the name of the template from the builder
261: String a_sTemplateName = null;
262:
263: if (p_oActionSuccessFlag == true) {
264: a_sTemplateName = p_oBuilder.getTemplate();
265: } else {
266: a_sTemplateName = p_oBuilder.getErrorTemplate();
267: }
268:
269: // Get a reader to the velocity template
270: final InputStream a_oTemplateStream = this .getClass()
271: .getClassLoader().getResourceAsStream(
272: a_sTemplateName);
273:
274: Reader a_oTemplate = new InputStreamReader(
275: a_oTemplateStream);
276:
277: // The results of the velocity template will be stored here
278: StringWriter a_oStringWriter = new StringWriter();
279:
280: // Run the velocity template
281: m_oVelocityEngine.evaluate(a_oContext, a_oStringWriter,
282: MULTIPLE_ACTION_PROCESSOR, a_oTemplate);
283:
284: // Get the results from the velocity processing
285: String a_sResults = a_oStringWriter.getBuffer()
286: .toString();
287:
288: // Save the results on the input map
289: p_oInputMap.put(BUILD_RESULTS, a_sResults);
290: } else {
291: log.error("could not create builder context");
292: }
293: } catch (Exception e) {
294: log.error("builder failed", e);
295: p_oInputMap.put(Constants.REASON, e.toString());
296: }
297: }
298:
299: public boolean buildContext(RequestContext p_oRequestContext,
300: Map p_oInputMap) {
301: boolean a_bResults = true;
302:
303: a_bResults = super.buildContext(p_oRequestContext, p_oInputMap);
304:
305: return a_bResults;
306: }
307:
308: }
|