0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/velocity/tags/sakai_2-4-1/tool/src/java/org/sakaiproject/cheftool/VelocityPortletPaneledAction.java $
0003: * $Id: VelocityPortletPaneledAction.java 13671 2006-08-15 03:21:20Z ggolden@umich.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.cheftool;
0021:
0022: import java.io.IOException;
0023: import java.lang.reflect.InvocationTargetException;
0024: import java.lang.reflect.Method;
0025: import java.util.HashMap;
0026: import java.util.HashSet;
0027: import java.util.Iterator;
0028: import java.util.Map;
0029: import java.util.Set;
0030:
0031: import javax.servlet.ServletException;
0032: import javax.servlet.http.HttpServletRequest;
0033: import javax.servlet.http.HttpServletResponse;
0034:
0035: import org.apache.commons.logging.Log;
0036: import org.apache.commons.logging.LogFactory;
0037: import org.sakaiproject.authz.cover.SecurityService;
0038: import org.sakaiproject.cheftool.api.Alert;
0039: import org.sakaiproject.cheftool.api.Menu;
0040: import org.sakaiproject.cheftool.menu.MenuEntry;
0041: import org.sakaiproject.component.cover.ServerConfigurationService;
0042: import org.sakaiproject.content.cover.ContentHostingService;
0043: import org.sakaiproject.courier.api.ObservingCourier;
0044: import org.sakaiproject.event.api.SessionState;
0045: import org.sakaiproject.event.api.UsageSession;
0046: import org.sakaiproject.event.cover.UsageSessionService;
0047: import org.sakaiproject.tool.api.Placement;
0048: import org.sakaiproject.tool.api.Session;
0049: import org.sakaiproject.tool.api.Tool;
0050: import org.sakaiproject.tool.api.ToolException;
0051: import org.sakaiproject.tool.api.ToolSession;
0052: import org.sakaiproject.tool.cover.SessionManager;
0053: import org.sakaiproject.tool.cover.ToolManager;
0054: import org.sakaiproject.util.ParameterParser;
0055: import org.sakaiproject.util.ResourceLoader;
0056: import org.sakaiproject.util.Validator;
0057: import org.sakaiproject.util.Web;
0058: import org.sakaiproject.vm.ActionURL;
0059:
0060: /**
0061: * <p>
0062: * VelocityPortletPaneledAction ...
0063: * </p>
0064: */
0065: public abstract class VelocityPortletPaneledAction extends ToolServlet {
0066: /** Our logger. */
0067: private static Log M_log = LogFactory
0068: .getLog(VelocityPortletPaneledAction.class);
0069:
0070: /** message bundle */
0071: private static ResourceLoader rb = new ResourceLoader(
0072: "velocity-tool");
0073:
0074: protected static final String BUTTON = "eventSubmit_";
0075:
0076: /** The currently active helper mode static class. */
0077: public static final String STATE_HELPER = "vppa.helper";
0078:
0079: protected static final String STATE_MODE = "mode";
0080:
0081: protected static final String STATE_OBSERVER = "obsever";
0082:
0083: protected static final String STATE_ACTION = "action";
0084:
0085: /** The name of the context variable containing the identifier for the site's root content collection */
0086: protected static final String CONTEXT_SITE_COLLECTION_ID = "vppa_site_collection_id";
0087:
0088: /** The name of the context variable containing the access URL for the site's root content collection */
0089: protected static final String CONTEXT_SITE_COLLECTION_URL = "vppa_site_collection_url";
0090:
0091: /** The panel name of the main panel - append the tool's id. */
0092: protected static final String LAYOUT_MAIN = "Main";
0093:
0094: protected class MyLogger {
0095: public void warn(String channel, String msg) {
0096: M_log.warn(msg);
0097: }
0098:
0099: public void warn(String channel, String msg, Throwable e) {
0100: M_log.warn(msg, e);
0101: }
0102:
0103: public void debug(String channel, String msg) {
0104: M_log.debug(msg);
0105: }
0106:
0107: public void debug(String channel, String msg, Throwable e) {
0108: M_log.debug(msg, e);
0109: }
0110:
0111: public void info(String channel, String msg) {
0112: M_log.info(msg);
0113: }
0114:
0115: public void info(String channel, String msg, Throwable e) {
0116: M_log.info(msg, e);
0117: }
0118:
0119: public void error(String channel, String msg) {
0120: M_log.error(msg);
0121: }
0122:
0123: public void error(String channel, String msg, Throwable e) {
0124: M_log.error(msg, e);
0125: }
0126:
0127: // to support: if (Log.getLogger("chef").isDebugEnabled())
0128: public MyLogger getLogger(String name) {
0129: return this ;
0130: }
0131:
0132: public boolean isDebugEnabled() {
0133: return M_log.isDebugEnabled();
0134: }
0135:
0136: public boolean isWarnEnabled() {
0137: return M_log.isWarnEnabled();
0138: }
0139:
0140: public boolean isInfoEnabled() {
0141: return M_log.isInfoEnabled();
0142: }
0143: }
0144:
0145: protected MyLogger Log = new MyLogger();
0146:
0147: protected void initState(SessionState state,
0148: VelocityPortlet portlet, JetspeedRunData rundata) {
0149: }
0150:
0151: /**
0152: * Compute the deliver address for the current request. Compute the client window id, based on the float state
0153: *
0154: * @param state
0155: * The tool state.
0156: * @param toolId
0157: * The tool instance id, which might be used as part of the client window id if floating.
0158: * @return The client window id, based on the float state.
0159: */
0160: protected String clientWindowId(SessionState state, String toolId) {
0161: // TODO: drop the params
0162:
0163: // get the Sakai session
0164: Session session = SessionManager.getCurrentSession();
0165:
0166: // get the current tool placement
0167: Placement placement = ToolManager.getCurrentPlacement();
0168:
0169: // compute our courier delivery address: this placement in this session
0170: String deliveryId = session.getId() + placement.getId();
0171:
0172: return deliveryId;
0173:
0174: } // clientWindowId
0175:
0176: /**
0177: * Compute the courier update html element id for the main panel - add "." and other names for inner panels.
0178: *
0179: * @param toolId
0180: * The tool (portlet) id.
0181: * @return The courier update html element id for the main panel.
0182: */
0183: public static String mainPanelUpdateId(String toolId) {
0184: // TODO: who should be responsible for "Main" here? It's a Portal thing... -ggolden
0185: return Validator.escapeJavascript("Main" + toolId);
0186:
0187: } // mainPanelUpdateId
0188:
0189: /**
0190: * Compute the courier update html element id for the title panel.
0191: *
0192: * @param toolId
0193: * The tool (portlet) id.
0194: * @return The courier update html element id for the title panel.
0195: */
0196: public static String titlePanelUpdateId(String toolId) {
0197: // TODO: who should be responsible for "Title" here? It's a Portal thing... -ggolden
0198: return Validator.escapeJavascript("Title" + toolId);
0199:
0200: } // titlePanelUpdateId
0201:
0202: // Note: this is the "new" way - but the old code needs the "old" way
0203: // /**
0204: // * Add another string to the alert message.
0205: // * @param state The session state.
0206: // * @param message The string to add.
0207: // */
0208: // protected void addAlert(SessionState state, String message)
0209: // {
0210: // getAlert(state).add(message);
0211: // }
0212:
0213: /**
0214: * Add another string to the alert message.
0215: *
0216: * @param state
0217: * The session state.
0218: * @param message
0219: * The string to add.
0220: */
0221: public static void addAlert(SessionState state, String message) {
0222: String soFar = (String) state.getAttribute(STATE_MESSAGE);
0223: if (soFar != null) {
0224: soFar = soFar + " " + message;
0225: } else {
0226: soFar = message;
0227: }
0228: state.setAttribute(STATE_MESSAGE, soFar);
0229:
0230: } // addAlert
0231:
0232: /**
0233: * Initialize for the first time the session state for this session. If overridden in a sub-class, make sure to call super.
0234: *
0235: * @param state
0236: * The session state.
0237: * @param req
0238: * The current portlet request.
0239: * @param res
0240: * The current portlet response.
0241: */
0242: protected void initState(SessionState state,
0243: HttpServletRequest req, HttpServletResponse res) {
0244: super .initState(state, req, res);
0245:
0246: // call the old initState:
0247: PortletConfig config = (PortletConfig) req
0248: .getAttribute(ATTR_CONFIG);
0249: VelocityPortlet portlet = (VelocityPortlet) req
0250: .getAttribute(ATTR_PORTLET);
0251: JetspeedRunData rundata = (JetspeedRunData) req
0252: .getAttribute(ATTR_RUNDATA);
0253:
0254: initState(state, portlet, rundata);
0255:
0256: } // initState
0257:
0258: /**
0259: * Update for this request processing the session state. If overridden in a sub-class, make sure to call super.
0260: *
0261: * @param state
0262: * The session state.
0263: * @param req
0264: * The current portlet request.
0265: * @param res
0266: * The current portlet response.
0267: */
0268: protected void updateState(SessionState state,
0269: HttpServletRequest req, HttpServletResponse res) {
0270: super .updateState(state, req, res);
0271:
0272: // the old way has just initState, so...
0273: PortletConfig config = (PortletConfig) req
0274: .getAttribute(ATTR_CONFIG);
0275: VelocityPortlet portlet = (VelocityPortlet) req
0276: .getAttribute(ATTR_PORTLET);
0277: JetspeedRunData rundata = (JetspeedRunData) req
0278: .getAttribute(ATTR_RUNDATA);
0279:
0280: initState(state, portlet, rundata);
0281:
0282: } // updateState
0283:
0284: /**
0285: * Dispatch to a "do" method based on reflection. Override ToolServlet to support the old "build" ways.
0286: *
0287: * @param methodBase
0288: * The base name of the method to call.
0289: * @param methodExt
0290: * The end name of the method to call.
0291: * @param req
0292: * The HttpServletRequest.
0293: * @param res
0294: * The HttpServletResponse
0295: */
0296: protected void toolModeDispatch(String methodBase,
0297: String methodExt, HttpServletRequest req,
0298: HttpServletResponse res) throws ToolException {
0299: // the context wraps our real vm attribute set
0300: Context context = (Context) req.getAttribute(ATTR_CONTEXT);
0301:
0302: // other wrappers
0303: PortletConfig config = (PortletConfig) req
0304: .getAttribute(ATTR_CONFIG);
0305: VelocityPortlet portlet = (VelocityPortlet) req
0306: .getAttribute(ATTR_PORTLET);
0307: JetspeedRunData rundata = (JetspeedRunData) req
0308: .getAttribute(ATTR_RUNDATA);
0309:
0310: // "panel" is used to identify the specific panel in the URL
0311: context.put("param_panel", ActionURL.PARAM_PANEL);
0312:
0313: // set the "action"
0314: context.put("action", getState(req).getAttribute(STATE_ACTION));
0315:
0316: // set the "pid"
0317: context.put("param_pid", ActionURL.PARAM_PID);
0318: context.put("pid", getPid(req));
0319:
0320: String collectionId = ContentHostingService
0321: .getSiteCollection(ToolManager.getCurrentPlacement()
0322: .getContext());
0323: context.put(CONTEXT_SITE_COLLECTION_ID, collectionId);
0324:
0325: // String collectionUrl = ContentHostingService.getUrl(collectionId);
0326: // context.put(CONTEXT_SITE_COLLECTION_URL, collectionUrl);
0327:
0328: // indicate which WYSIWYG editor to use in legacy tools
0329: String editor = ServerConfigurationService
0330: .getString("wysiwyg.editor");
0331: context.put("sakai_editor", editor);
0332: String twinpeaks = ServerConfigurationService
0333: .getString("wysiwyg.twinpeaks");
0334: if (Boolean.TRUE.toString().equalsIgnoreCase(twinpeaks)) {
0335: context.put("twinpeaks", "true");
0336: }
0337:
0338: UsageSession session = UsageSessionService.getSession();
0339: if (session != null) {
0340: String browserId = session.getBrowserId();
0341: if (UsageSession.WIN_IE.equals(browserId)
0342: || UsageSession.WIN_MZ.equals(browserId)
0343: || UsageSession.WIN_NN.equals(browserId)
0344: || UsageSession.MAC_MZ.equals(browserId)
0345: || UsageSession.MAC_NN.equals(browserId)) {
0346: context.put("wysiwyg", "true");
0347: }
0348: }
0349:
0350: try {
0351: // dispatch panels (Note: panel must be in the URL, not the body - this is not from the parsed params)
0352: String panel = ((ParameterParser) req
0353: .getAttribute(ATTR_PARAMS))
0354: .getString(ActionURL.PARAM_PANEL);
0355:
0356: /*
0357: * TODO: float support from before... // special case for floating and the Main panel: if (LAYOUT_MAIN.equals(panel)) { if (handleFloat(portlet, context, rundata, state)) return; }
0358: */
0359: if (panel == null || "".equals(panel)
0360: || "null".equals(panel)) {
0361: // default to main panel
0362: panel = LAYOUT_MAIN;
0363: }
0364:
0365: context.put("panel", panel);
0366:
0367: // form a method name "build" + panel name (first letter caps) + "PanelContext"
0368: // buildPanelContext( VelocityPortlet, Context, ControllerState, RunData )
0369: Class[] types = new Class[4];
0370: types[0] = VelocityPortlet.class;
0371: types[1] = Context.class;
0372: types[2] = RunData.class;
0373: types[3] = SessionState.class;
0374:
0375: // let our extension classes override the pannel name for the method
0376: String methodName = panelMethodName(panel);
0377:
0378: Method method = getClass().getMethod(methodName, types);
0379:
0380: Object[] args = new Object[4];
0381: args[0] = portlet;
0382: args[1] = context;
0383: args[2] = rundata;
0384: args[3] = getState(req);
0385: String template = (String) method.invoke(this , args);
0386:
0387: // if the method did something like a redirect, we don't want to try to put out any more
0388: if (!res.isCommitted()) {
0389: if (template == null) {
0390: // pick the template for the panel - the base + "-" + panel
0391: template = (String) getContext(rundata).get(
0392: "template")
0393: + "-" + panel;
0394: }
0395:
0396: // the vm file needs a path and an extension
0397: template = "/vm/" + template + ".vm";
0398:
0399: // setup for old style alert
0400: StringBuffer buf = new StringBuffer();
0401: String msg = (String) getState(req).getAttribute(
0402: STATE_MESSAGE);
0403: if (msg != null) {
0404: buf.append(msg);
0405: getState(req).removeAttribute(STATE_MESSAGE);
0406: }
0407: Alert alert = getAlert(req);
0408: if (!alert.isEmpty()) {
0409: buf.append(alert.peekAlert());
0410: setVmReference(ALERT_ATTR, alert, req);
0411: }
0412: if (buf.length() > 0) {
0413: setVmReference("alertMessage", buf.toString(), req);
0414: }
0415:
0416: // setup for old style validator
0417: setVmReference("validator", m_validator, req);
0418:
0419: // set standard no-cache headers
0420: setNoCacheHeaders(res);
0421:
0422: // add a standard header
0423: includeVm("chef_header.vm", req, res);
0424:
0425: includeVm(template, req, res);
0426:
0427: // add a standard footer
0428: includeVm("chef_footer.vm", req, res);
0429: }
0430: } catch (NoSuchMethodException e) {
0431: throw new ToolException(e);
0432: } catch (IllegalAccessException e) {
0433: throw new ToolException(e);
0434: } catch (InvocationTargetException e) {
0435: throw new ToolException(e);
0436: } catch (ServletException e) {
0437: throw new ToolException(e);
0438: }
0439:
0440: } // toolModeDispatch
0441:
0442: /**
0443: * Allow extension classes to control which build method gets called for this pannel
0444: * @param panel
0445: * @return
0446: */
0447: protected String panelMethodName(String panel) {
0448: return "build" + panel + "PanelContext";
0449: }
0450:
0451: /**
0452: * Process a Portlet action.
0453: */
0454: public void processAction(HttpServletRequest req,
0455: HttpServletResponse res) {
0456: // lets use the parsed params
0457: JetspeedRunData rundata = (JetspeedRunData) req
0458: .getAttribute(ATTR_RUNDATA);
0459: ParameterParser params = rundata.getParameters();
0460:
0461: // see if there's an action parameter, whose value has the action to use
0462: String action = params.get(PARAM_ACTION);
0463:
0464: // if that's not present, see if there's a combination name with the action encoded in the name
0465: if (action == null) {
0466: Iterator names = params.getNames();
0467: while (names.hasNext()) {
0468: String name = (String) names.next();
0469: if (name.startsWith(BUTTON)) {
0470: action = name.substring(BUTTON.length());
0471: break;
0472: }
0473: }
0474: }
0475:
0476: // process the action if present
0477: if (action != null) {
0478: // if we have an active helper, send the action there
0479: String helperClass = (String) getState(req).getAttribute(
0480: STATE_HELPER);
0481: if (helperClass != null) {
0482: helperActionDispatch("", action, req, res, helperClass);
0483: } else {
0484: actionDispatch("", action, req, res);
0485: }
0486:
0487: // redirect to the tool's registration's url, with the tool id (pid) and panel
0488: // Tool tool = (Tool) req.getAttribute(ATTR_TOOL);
0489: // TODO: redirect url? pannel? placement id?
0490: String url = Web.returnUrl(req, null);
0491: String redirect = url
0492: + "?"
0493: + /* ActionURL.PARAM_PID + "=" + tool.getId() + "&" + */ActionURL.PARAM_PANEL
0494: + "="
0495: + ((ParameterParser) req.getAttribute(ATTR_PARAMS))
0496: .getString(ActionURL.PARAM_PANEL);
0497: // Logger.info(this + " ** redirect to: " + redirect);
0498:
0499: try {
0500: res.sendRedirect(redirect);
0501: } catch (IOException e) {
0502: }
0503: } else {
0504: M_log.debug("processAction: no action");
0505: }
0506:
0507: } // processAction
0508:
0509: /**
0510: * Dispatch to a "processAction" method based on reflection.
0511: *
0512: * @param methodBase
0513: * The base name of the method to call.
0514: * @param methodExt
0515: * The end name of the method to call.
0516: * @param req
0517: * The HttpServletRequest.
0518: * @param res
0519: * The HttpServletResponse
0520: * @throws PortletExcption,
0521: * IOException, just like the "do" methods.
0522: */
0523: protected void actionDispatch(String methodBase, String methodExt,
0524: HttpServletRequest req, HttpServletResponse res) {
0525: String methodName = null;
0526: try {
0527: // the method signature
0528: Class[] signature = new Class[2];
0529: signature[0] = RunData.class;
0530: signature[1] = Context.class;
0531:
0532: // the method name
0533: methodName = methodBase + methodExt;
0534:
0535: // find a method of this class with this name and signature
0536: Method method = getClass().getMethod(methodName, signature);
0537:
0538: // parameters - the context for a "do" should not be used, so we will send in null
0539: Object[] args = new Object[2];
0540: args[0] = (JetspeedRunData) req.getAttribute(ATTR_RUNDATA);
0541: args[1] = null;
0542:
0543: // make the call
0544: method.invoke(this , args);
0545: } catch (NoSuchMethodException e) {
0546: // try for a single parameter call
0547: try {
0548: // the method signature
0549: Class[] signature = new Class[1];
0550: signature[0] = RunData.class;
0551:
0552: // the method name
0553: methodName = methodBase + methodExt;
0554:
0555: // find a method of this class with this name and signature
0556: Method method = getClass().getMethod(methodName,
0557: signature);
0558:
0559: // parameters - the context for a "do" should not be used, so we will send in null
0560: Object[] args = new Object[1];
0561: args[0] = (JetspeedRunData) req
0562: .getAttribute(ATTR_RUNDATA);
0563:
0564: // make the call
0565: method.invoke(this , args);
0566: } catch (NoSuchMethodException e2) {
0567: M_log.warn("Exception calling method " + methodName
0568: + " " + e2);
0569: } catch (IllegalAccessException e2) {
0570: M_log.warn("Exception calling method " + methodName
0571: + " " + e2);
0572: } catch (InvocationTargetException e2) {
0573: String xtra = "";
0574: if (e2.getCause() != null)
0575: xtra = " (Caused by " + e2.getCause() + ")";
0576: M_log.warn("Exception calling method " + methodName
0577: + " " + e2 + xtra);
0578:
0579: }
0580: } catch (IllegalAccessException e) {
0581: M_log.warn("Exception calling method " + methodName + " "
0582: + e);
0583: } catch (InvocationTargetException e) {
0584: String xtra = "";
0585: if (e.getCause() != null)
0586: xtra = " (Caused by " + e.getCause() + ")";
0587: M_log.warn("Exception calling method " + methodName + " "
0588: + e + xtra);
0589: }
0590:
0591: } // actionDispatch
0592:
0593: /**
0594: * Dispatch to a "processAction" method based on reflection in a helper class.
0595: *
0596: * @param methodBase
0597: * The base name of the method to call.
0598: * @param methodExt
0599: * The end name of the method to call.
0600: * @param req
0601: * The HttpServletRequest.
0602: * @param res
0603: * The HttpServletResponse
0604: * @throws PortletExcption,
0605: * IOException, just like the "do" methods.
0606: */
0607: protected void helperActionDispatch(String methodBase,
0608: String methodExt, HttpServletRequest req,
0609: HttpServletResponse res, String className) {
0610: String methodName = null;
0611: try {
0612: // the method signature
0613: Class[] signature = new Class[1];
0614: signature[0] = RunData.class;
0615:
0616: // the method name
0617: methodName = methodBase + methodExt;
0618:
0619: Class cls = Class.forName(className);
0620:
0621: // find a method of this class with this name and signature
0622: Method method = cls.getMethod(methodName, signature);
0623:
0624: // parameters - the context for a "do" should not be used, so we will send in null
0625: Object[] args = new Object[1];
0626: args[0] = (JetspeedRunData) req.getAttribute(ATTR_RUNDATA);
0627:
0628: // make the call
0629: method.invoke(this , args);
0630: } catch (ClassNotFoundException e) {
0631: M_log.warn("Exception helper class not found " + e);
0632: } catch (NoSuchMethodException e) {
0633: M_log.warn("Exception calling method " + methodName + " "
0634: + e);
0635: } catch (IllegalAccessException e) {
0636: M_log.warn("Exception calling method " + methodName + " "
0637: + e);
0638: } catch (InvocationTargetException e) {
0639: String xtra = "";
0640: if (e.getCause() != null)
0641: xtra = " (Caused by " + e.getCause() + ")";
0642: M_log.warn("Exception calling method " + methodName + " "
0643: + e + xtra);
0644: }
0645:
0646: } // helperActionDispatch
0647:
0648: /**
0649: * This is used to get "template" from the map, the default template registered for the tool in chef_tools.xreg.
0650: */
0651: protected Map getContext(RunData data) {
0652: // get template from the servlet config
0653: String template = getServletConfig().getInitParameter(
0654: "template");
0655: Map rv = new HashMap();
0656: rv.put("template", template);
0657:
0658: return rv;
0659: }
0660:
0661: // OPTIONS SUPPORT
0662: public static final String STATE_OBSERVER2 = "obsever2";
0663:
0664: public static final String STATE_PRESENCE_OBSERVER = "presence_observer";
0665:
0666: public static final String STATE_FLOAT = "float";
0667:
0668: public static final String STATE_TOOL = "tool";
0669:
0670: public static final String STATE_MESSAGE = "message";
0671:
0672: /** Standard modes. */
0673: public static final String MODE_OPTIONS = "options";
0674:
0675: /**
0676: * Handle a request to set options.
0677: */
0678: public void doOptions(RunData runData, Context context) {
0679: // ignore if not allowed
0680: if (!allowedToOptions()) {
0681: return;
0682: //msg = "you do not have permission to set options for this Worksite.";
0683: }
0684:
0685: Placement placement = ToolManager.getCurrentPlacement();
0686: String pid = null;
0687: if (placement != null)
0688: pid = placement.getId();
0689: SessionState state = ((JetspeedRunData) runData)
0690: .getPortletSessionState(pid);
0691:
0692: // go into options mode
0693: state.setAttribute(STATE_MODE, MODE_OPTIONS);
0694:
0695: // disable auto-updates while editing
0696: disableObservers(state);
0697:
0698: // if we're not in the main panel for this tool, schedule an update of the main panel
0699: String currentPanelId = runData.getParameters().getString(
0700: ActionURL.PARAM_PANEL);
0701: if (!LAYOUT_MAIN.equals(currentPanelId)) {
0702: String mainPanelId = mainPanelUpdateId(pid);
0703: schedulePeerFrameRefresh(mainPanelId);
0704: }
0705:
0706: } // doOptions
0707:
0708: /**
0709: * Complete the options process with a save.
0710: */
0711: protected void saveOptions() {
0712: // ask the current placement to save
0713: Placement placement = ToolManager.getCurrentPlacement();
0714: if (placement != null) {
0715: placement.save();
0716: }
0717:
0718: } // saveOptions
0719:
0720: /**
0721: * Cancel the options process.
0722: */
0723: protected void cancelOptions() {
0724: // TODO: how to indicate that we need to get clean placement options into the current tool?
0725:
0726: } // cancelOptions
0727:
0728: /**
0729: * Add the options to the menu bar, if allowed.
0730: *
0731: * @param bar
0732: * The menu bar to add to,
0733: * @param ref
0734: * The resource reference to base the security decision upon.
0735: */
0736: protected void addOptionsMenu(Menu bar, JetspeedRunData data) // %%% don't need data -ggolden
0737: {
0738: if (allowedToOptions()) {
0739: bar
0740: .add(new MenuEntry(rb.getString("options"),
0741: "doOptions"));
0742: }
0743:
0744: } // addOptionsMenu
0745:
0746: /**
0747: * Check if the current user is allowed to do options for the current context (site based)
0748: * @return true if the user is allowed to modify the current context's options, false if not.
0749: */
0750: protected boolean allowedToOptions() {
0751: Placement placement = ToolManager.getCurrentPlacement();
0752: String context = null;
0753: if (placement != null)
0754: context = placement.getContext();
0755:
0756: // TODO: stolen from site -ggolden
0757: if (SecurityService.unlock("site.upd", "/site/" + context)) {
0758: return true;
0759: }
0760:
0761: return false;
0762: }
0763:
0764: /**
0765: * Disable any observers registered in state in STATE_OBSERVER or STATE_OBSERVER2
0766: *
0767: * @param state
0768: * The session state.
0769: */
0770: public static void disableObservers(SessionState state) {
0771: ObservingCourier observer = (ObservingCourier) state
0772: .getAttribute(STATE_OBSERVER);
0773: if (observer != null) {
0774: observer.disable();
0775: }
0776:
0777: observer = (ObservingCourier) state
0778: .getAttribute(STATE_OBSERVER2);
0779: if (observer != null) {
0780: observer.disable();
0781: }
0782:
0783: } // disableObservers
0784:
0785: /**
0786: * Enable any observers registered in state in STATE_OBSERVER or STATE_OBSERVER2
0787: *
0788: * @param state
0789: * The session state.
0790: */
0791: public static void enableObservers(SessionState state) {
0792: ObservingCourier observer = (ObservingCourier) state
0793: .getAttribute(STATE_OBSERVER);
0794: if (observer != null) {
0795: observer.enable();
0796: }
0797:
0798: observer = (ObservingCourier) state
0799: .getAttribute(STATE_OBSERVER2);
0800: if (observer != null) {
0801: observer.enable();
0802: }
0803:
0804: } // enableObservers
0805:
0806: /**
0807: * Tell the main observer we have just delivered.
0808: *
0809: * @param state
0810: * The session state.
0811: */
0812: public static void justDelivered(SessionState state) {
0813: ObservingCourier observer = (ObservingCourier) state
0814: .getAttribute(STATE_OBSERVER);
0815: if (observer != null) {
0816: observer.justDelivered();
0817: }
0818: }
0819:
0820: /**
0821: * Handle the "reset tool" option from the Title bar.
0822: */
0823: public void doReset(RunData runData, Context context) {
0824: // access the portlet element id to find "our" state (i.e. the state for this portlet)
0825: String peid = ((JetspeedRunData) runData).getJs_peid();
0826: SessionState state = ((JetspeedRunData) runData)
0827: .getPortletSessionState(peid);
0828:
0829: // preserve floating, if we are
0830: // boolean floating = state.getAttribute(STATE_FLOAT) != null;
0831:
0832: // clear this state
0833: resetTool(state);
0834:
0835: String windowToolId = null;
0836:
0837: // // restore the floating
0838: // if (floating)
0839: // {
0840: // state.setAttribute(STATE_FLOAT, "float");
0841: //
0842: // // we need to tell the window with this tool id (i.e. the floating one) what's going on
0843: // windowToolId = peid;
0844: // }
0845:
0846: // // make sure the Main panel is updated
0847: String main = VelocityPortletPaneledAction
0848: .mainPanelUpdateId(peid);
0849: // CourierService.deliver(PortalService.getCurrentClientWindowId(windowToolId), main);
0850: schedulePeerFrameRefresh(main);
0851:
0852: } // doReset
0853:
0854: /**
0855: * Reset the tool (state) to "home" conditions. Default here is to clear everything from state.
0856: *
0857: * @param state
0858: * The tool's session state.
0859: */
0860: protected void resetTool(SessionState state) {
0861: state.clear();
0862:
0863: } // resetTool
0864:
0865: /**
0866: * Add some standard references to the vm context.
0867: *
0868: * @param request
0869: * The render request.
0870: * @param response
0871: * The render response.
0872: */
0873: protected void setVmStdRef(HttpServletRequest request,
0874: HttpServletResponse response) {
0875: // pick up all the super ones
0876: super .setVmStdRef(request, response);
0877:
0878: // add a "$config" which accesses the config service
0879: setVmReference("config", ServerConfigurationService
0880: .getInstance(), request);
0881:
0882: // add the pid
0883: setVmReference("pid", getPid(request), request);
0884:
0885: // check for a scheduled peer frame or focus refresh
0886: ToolSession session = SessionManager.getCurrentToolSession();
0887: if (session != null) {
0888: if (session.getAttribute(ATTR_TOP_REFRESH) != null) {
0889: setVmReference("topRefresh", Boolean.TRUE, request);
0890: session.removeAttribute(ATTR_TOP_REFRESH);
0891: }
0892:
0893: Set ids = (Set) session.getAttribute(ATTR_FRAME_REFRESH);
0894: if (ids != null) {
0895: setVmReference("frameRefresh", ids, request);
0896: session.removeAttribute(ATTR_FRAME_REFRESH);
0897: }
0898:
0899: String focusPath = (String) session
0900: .getAttribute(ATTR_FRAME_FOCUS);
0901: if (focusPath != null) {
0902: setVmReference("focusChange", focusPath, request);
0903: session.removeAttribute(ATTR_FRAME_FOCUS);
0904: }
0905: }
0906: Tool tool = ToolManager.getCurrentTool();
0907: if (tool != null) {
0908: setVmReference("toolTitle", tool.getTitle(), request);
0909: }
0910: }
0911:
0912: /**
0913: * Setup the vm context for a courier
0914: *
0915: * @param request
0916: */
0917: protected void setVmCourier(HttpServletRequest request, int refresh) {
0918: // the url for the chat courier
0919: Placement placement = ToolManager.getCurrentPlacement();
0920: if (placement != null) {
0921: setVmReference("courier", Web.serverUrl(request)
0922: + "/courier/" + placement.getId(), request);
0923: setVmReference("courierTimeout", Integer.toString(refresh),
0924: request);
0925: }
0926: }
0927:
0928: /** A Context bound into the request attributes. */
0929:
0930: protected final static String ATTR_CONTEXT = "sakai.wrapper.context";
0931:
0932: /** A PortletConfig bound into the request attributes. */
0933: protected final static String ATTR_CONFIG = "sakai.wrapper.config";
0934:
0935: /** A VelocityPortlet bound into the request attributes. */
0936: protected final static String ATTR_PORTLET = "sakai.wrapper.portlet";
0937:
0938: /** A JetspeedRunData bound into the request attributes. */
0939: protected final static String ATTR_RUNDATA = "sakai.wrapper.rundata";
0940:
0941: /**
0942: * Respond to a request by dispatching to a portlet like "do" method based on the portlet mode and tool mode
0943: */
0944: protected void doGet(HttpServletRequest req, HttpServletResponse res)
0945: throws ServletException {
0946: // set in VmServlet
0947: ParameterParser params = (ParameterParser) req
0948: .getAttribute(ATTR_PARAMS);
0949:
0950: // we will need some covers... Note: parameters are parsed (i.e. files are read) here
0951: Context context = new Context(this , req);
0952: Placement placement = ToolManager.getCurrentPlacement();
0953: PortletConfig config = new PortletConfig(getServletConfig(),
0954: placement.getPlacementConfig(), placement.getTool()
0955: .getRegisteredConfig(), placement);
0956: VelocityPortlet portlet = new VelocityPortlet(getPid(req),
0957: config);
0958: JetspeedRunData rundata = new JetspeedRunData(req,
0959: getState(req), getPid(req), params);
0960:
0961: req.setAttribute(ATTR_CONTEXT, context);
0962: req.setAttribute(ATTR_CONFIG, config);
0963: req.setAttribute(ATTR_PORTLET, portlet);
0964: req.setAttribute(ATTR_RUNDATA, rundata);
0965:
0966: super .doGet(req, res);
0967: }
0968:
0969: /** Tool session attribute name used to schedule a peer frame refresh. */
0970: public static final String ATTR_FRAME_REFRESH = "sakai.vppa.frame.refresh";
0971:
0972: /** Tool session attribute name used to schedule a whole page refresh. */
0973: public static final String ATTR_TOP_REFRESH = "sakai.vppa.top.refresh";
0974:
0975: /** Tool session attribute name used to schedule a focus change. */
0976: public static final String ATTR_FRAME_FOCUS = "sakai.vppa.frame.focus";
0977:
0978: /**
0979: * Schedule a refresh for whole page
0980: */
0981: protected void scheduleTopRefresh() {
0982: ToolSession session = SessionManager.getCurrentToolSession();
0983:
0984: // add to (or create) our set of ids to refresh
0985: if (session.getAttribute(ATTR_TOP_REFRESH) == null) {
0986: session.setAttribute(ATTR_TOP_REFRESH, Boolean.TRUE);
0987: }
0988: }
0989:
0990: /**
0991: * Schedule a refresh for a peer frame.
0992: *
0993: * @param id
0994: * The peer frame's id.
0995: */
0996: protected void schedulePeerFrameRefresh(String id) {
0997: ToolSession session = SessionManager.getCurrentToolSession();
0998:
0999: // add to (or create) our set of ids to refresh
1000: Set soFar = (Set) session.getAttribute(ATTR_FRAME_REFRESH);
1001: if (soFar == null) {
1002: soFar = new HashSet();
1003: session.setAttribute(ATTR_FRAME_REFRESH, soFar);
1004: }
1005: soFar.add(id);
1006: }
1007:
1008: /**
1009: * Schedule a focus change.
1010: *
1011: * @param path
1012: * The desired focus path elements
1013: */
1014: protected void scheduleFocusRefresh(String[] path) {
1015: ToolSession session = SessionManager.getCurrentToolSession();
1016:
1017: // make the js string from the elements
1018: String jsArray = "[";
1019: for (int i = 0; i < path.length; i++) {
1020: if (i > 0) {
1021: jsArray = jsArray + ",";
1022: }
1023: jsArray = jsArray + " \"" + path[i] + "\"";
1024: }
1025: jsArray = jsArray + " ]";
1026:
1027: // save it for the next display
1028: session.setAttribute(ATTR_FRAME_FOCUS, jsArray);
1029: }
1030:
1031: } // class VelocityPortletPaneledAction
|