001: /**********************************************************************************
002: * $URL:https://source.sakaiproject.org/svn/osp/trunk/common/tool-lib/src/java/org/theospi/portfolio/shared/control/servlet/HelperAwareJsfTool.java $
003: * $Id:HelperAwareJsfTool.java 9134 2006-05-08 20:28:42Z chmaurer@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.jsf.util;
021:
022: import org.sakaiproject.jsf.util.JsfTool;
023: import org.sakaiproject.tool.api.ActiveTool;
024: import org.sakaiproject.tool.api.Tool;
025: import org.sakaiproject.tool.api.ToolException;
026: import org.sakaiproject.tool.api.ToolSession;
027: import org.sakaiproject.tool.cover.ActiveToolManager;
028: import org.sakaiproject.tool.cover.SessionManager;
029: import org.sakaiproject.util.Web; //import org.sakaiproject.metaobj.shared.control.ToolFinishedView;
030:
031: import javax.servlet.RequestDispatcher;
032: import javax.servlet.ServletException;
033: import javax.servlet.http.HttpServletRequest;
034: import javax.servlet.http.HttpServletResponse;
035: import java.io.IOException;
036: import java.util.Enumeration;
037:
038: /**
039: * Created by IntelliJ IDEA.
040: * User: John Ellis
041: * Date: Nov 11, 2005
042: * Time: 4:17:18 PM
043: * To change this template use File | Settings | File Templates.
044: */
045: public class HelperAwareJsfTool extends JsfTool {
046:
047: private static final String HELPER_EXT = ".helper";
048:
049: private static final String HELPER_SESSION_PREFIX = "session.";
050:
051: /** the alternate next view */
052: public static final String ALTERNATE_DONE_URL = "altDoneURL";
053:
054: /** the set of alternate views */
055: public static final String ALTERNATE_DONE_URL_MAP = "altDoneURLSet";
056:
057: protected void dispatch(HttpServletRequest req,
058: HttpServletResponse res) throws ServletException,
059: IOException {
060: // NOTE: this is a simple path dispatching, taking the path as the view id = jsp file name for the view,
061: // with default used if no path and a path prefix as configured.
062: // TODO: need to allow other sorts of dispatching, such as pulling out drill-down ids and making them
063: // available to the JSF
064:
065: // build up the target that will be dispatched to
066: String target = req.getPathInfo();
067:
068: // see if we have a helper request
069: if (sendToHelper(req, res, target)) {
070: return;
071: }
072:
073: // see if we have a resource request - i.e. a path with an extension, and one that is not the JSF_EXT
074: if (isResourceRequest(target)) {
075: // get a dispatcher to the path
076: RequestDispatcher resourceDispatcher = getServletContext()
077: .getRequestDispatcher(target);
078: if (resourceDispatcher != null) {
079: resourceDispatcher.forward(req, res);
080: return;
081: }
082: }
083:
084: if ("Title".equals(req.getParameter("panel"))) {
085: // This allows only one Title JSF for each tool
086: target = "/title.jsf";
087: }
088:
089: else {
090: ToolSession session = SessionManager
091: .getCurrentToolSession();
092:
093: if (target == null || "/".equals(target)
094: || target.length() == 0) {
095: if (!m_defaultToLastView) {
096: // make sure tool session is clean
097: session.clearAttributes();
098: }
099:
100: target = computeDefaultTarget();
101:
102: // make sure it's a valid path
103: if (!target.startsWith("/")) {
104: target = "/" + target;
105: }
106:
107: // now that we've messed with the URL, send a redirect to make it official
108: res.sendRedirect(Web.returnUrl(req, target));
109: return;
110: }
111:
112: // see if we want to change the specifically requested view
113: String newTarget = redirectRequestedTarget(target);
114:
115: // make sure it's a valid path
116: if (!newTarget.startsWith("/")) {
117: newTarget = "/" + newTarget;
118: }
119:
120: if (!newTarget.equals(target)) {
121: // now that we've messed with the URL, send a redirect to make it official
122: res.sendRedirect(Web.returnUrl(req, newTarget));
123: return;
124: }
125: target = newTarget;
126:
127: // store this
128: session.setAttribute(LAST_VIEW_VISITED, target);
129: }
130:
131: // add the configured folder root and extension (if missing)
132: target = m_path + target;
133:
134: // add the default JSF extension (if we have no extension)
135: int lastSlash = target.lastIndexOf("/");
136: int lastDot = target.lastIndexOf(".");
137: if (lastDot < 0 || lastDot < lastSlash) {
138: target += JSF_EXT;
139: }
140:
141: // set the information that can be removed from return URLs
142: req.setAttribute(URL_PATH, m_path);
143: req.setAttribute(URL_EXT, ".jsp");
144:
145: // set the sakai request object wrappers to provide the native, not Sakai set up, URL information
146: // - this assures that the FacesServlet can dispatch to the proper view based on the path info
147: req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL);
148:
149: // TODO: Should setting the HTTP headers be moved up to the portal level as well?
150: res.setContentType("text/html; charset=UTF-8");
151: res.addDateHeader("Expires", System.currentTimeMillis()
152: - (1000L * 60L * 60L * 24L * 365L));
153: res.addDateHeader("Last-Modified", System.currentTimeMillis());
154: res
155: .addHeader("Cache-Control",
156: "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
157: res.addHeader("Pragma", "no-cache");
158:
159: // dispatch to the target
160: /*M_log.debug("dispatching path: " + req.getPathInfo() + " to: " + target + " context: "
161: + getServletContext().getServletContextName());*/
162: RequestDispatcher dispatcher = getServletContext()
163: .getRequestDispatcher(target);
164: dispatcher.forward(req, res);
165:
166: // restore the request object
167: req.removeAttribute(Tool.NATIVE_URL);
168: req.removeAttribute(URL_PATH);
169: req.removeAttribute(URL_EXT);
170: }
171:
172: protected boolean sendToHelper(HttpServletRequest req,
173: HttpServletResponse res, String target) {
174: String path = req.getPathInfo();
175: if (path == null)
176: path = "/";
177:
178: // 0 parts means the path was just "/", otherwise parts[0] = "", parts[1] = item id, parts[2] if present is "edit"...
179: String[] parts = path.split("/");
180:
181: if (parts.length < 2) {
182: return false;
183: }
184:
185: if (!parts[1].endsWith(HELPER_EXT)) {
186: return false;
187: }
188:
189: ToolSession toolSession = SessionManager
190: .getCurrentToolSession();
191:
192: Enumeration params = req.getParameterNames();
193: while (params.hasMoreElements()) {
194: String paramName = (String) params.nextElement();
195: if (paramName.startsWith(HELPER_SESSION_PREFIX)) {
196: String attributeName = paramName
197: .substring(HELPER_SESSION_PREFIX.length());
198: toolSession.setAttribute(attributeName, req
199: .getParameter(paramName));
200: }
201: }
202:
203: // calc helper id
204: int posEnd = parts[1].lastIndexOf(".");
205:
206: String helperId = target.substring(1, posEnd + 1);
207: ActiveTool helperTool = ActiveToolManager
208: .getActiveTool(helperId);
209:
210: //get the current location (if one doesn't exist) and save it for when we return from the helper
211: if (toolSession.getAttribute(helperTool.getId()
212: + Tool.HELPER_DONE_URL) == null) {
213: toolSession
214: .setAttribute(helperTool.getId()
215: + Tool.HELPER_DONE_URL, req
216: .getContextPath()
217: + req.getServletPath()
218: + computeDefaultTarget(true));
219: }
220: toolSession.setAttribute(helperTool.getId() + "thetoolPath",
221: req.getContextPath() + req.getServletPath());
222:
223: // saves the alternate done url map into a tool specific attribute
224: if (toolSession.getAttribute(helperTool.getId()
225: + ALTERNATE_DONE_URL) == null) {
226: toolSession.setAttribute(helperTool.getId()
227: + ALTERNATE_DONE_URL, toolSession
228: .getAttribute(ALTERNATE_DONE_URL));
229: toolSession.setAttribute(helperTool.getId()
230: + ALTERNATE_DONE_URL_MAP, toolSession
231: .getAttribute(ALTERNATE_DONE_URL_MAP));
232: toolSession.removeAttribute(ALTERNATE_DONE_URL);
233: toolSession.removeAttribute(ALTERNATE_DONE_URL_MAP);
234: }
235:
236: /*comment out for using the global parameter rather than tool-by-tool setting
237: SessionState state = UsageSessionService.getSessionState(toolSession.getPlacementId());
238: boolean show_other_sites = ServerConfigurationService.getBoolean("syllabus.resources.show_all_collections.helper", true);
239: state.setAttribute("resources.allow_user_to_see_all_sites", (new Boolean(show_other_sites)).toString());
240: state.setAttribute("resources.user_chooses_to_see_other_sites", (new Boolean(show_other_sites)).toString());
241: */
242: String context = req.getContextPath() + req.getServletPath()
243: + Web.makePath(parts, 1, 2);
244: String toolPath = Web.makePath(parts, 2, parts.length);
245: try {
246: helperTool.help(req, res, context, toolPath);
247: } catch (ToolException e) {
248: throw new RuntimeException(e);
249: }
250:
251: return true; // was handled as helper call
252: }
253:
254: protected String computeDefaultTarget(boolean lastVisited) {
255: // setup for the default view as configured
256: String target = "/" + m_default;
257:
258: // if we are doing lastVisit and there's a last-visited view, for this tool placement / user, use that
259: if (lastVisited) {
260: ToolSession session = SessionManager
261: .getCurrentToolSession();
262: String last = (String) session
263: .getAttribute(LAST_VIEW_VISITED);
264: if (last != null) {
265: target = last;
266: }
267: }
268:
269: return target;
270: }
271: }
|