001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/sam/tags/sakai_2-4-1/samigo-app/src/java/org/sakaiproject/jsf/util/SamigoJsfTool.java $
003: * $Id: SamigoJsfTool.java 18540 2006-11-29 19:09:54Z ktsao@stanford.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 java.io.IOException;
023: import java.util.Enumeration;
024:
025: import javax.servlet.RequestDispatcher;
026: import javax.servlet.ServletException;
027: import javax.servlet.http.HttpServletRequest;
028: import javax.servlet.http.HttpServletResponse;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.sakaiproject.jsf.util.JsfTool;
033: import org.sakaiproject.tool.api.ActiveTool;
034: import org.sakaiproject.tool.api.Tool;
035: import org.sakaiproject.tool.api.ToolException;
036: import org.sakaiproject.tool.api.ToolSession;
037: import org.sakaiproject.tool.cover.ActiveToolManager;
038: import org.sakaiproject.tool.cover.SessionManager;
039: import org.sakaiproject.util.Web;
040: import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil;
041: import org.sakaiproject.tool.assessment.ui.bean.author.ItemAuthorBean;
042: import org.sakaiproject.tool.assessment.ui.bean.author.SectionBean;
043: import org.sakaiproject.tool.assessment.ui.bean.author.AssessmentSettingsBean;
044: import org.sakaiproject.tool.assessment.ui.bean.util.EmailBean;
045:
046: /**
047: * <p>
048: * Customized JsfTool for Samigo - just to workaround the fact that Samigo
049: * has the JSF URL mapping "*.faces" hard-coded in several places. If
050: * all instances of "*.faces" were changed to "*.jsf", this class could be removed.
051: * </p>
052: *
053: */
054: public class SamigoJsfTool extends JsfTool {
055: private static final String HELPER_EXT = ".helper";
056: private static final String HELPER_SESSION_PREFIX = "session.";
057: private static Log log = LogFactory.getLog(SamigoJsfTool.class);
058:
059: /**
060: * Recognize a path that is a resource request. It must have an "extension", i.e. a dot followed by characters that do not include a slash.
061: *
062: * @param path
063: * The path to check
064: * @return true if the path is a resource request, false if not.
065: */
066:
067: protected boolean isResourceRequest(String path) {
068: log.debug("****0. inside isResourceRequest, path=" + path);
069: // we need some path
070: if ((path == null) || (path.length() == 0))
071: return false;
072:
073: // we need a last dot
074: int pos = path.lastIndexOf(".");
075: if (pos == -1)
076: return false;
077:
078: // we need that last dot to be the end of the path, not burried in the path somewhere (i.e. no more slashes after the last dot)
079: String ext = path.substring(pos);
080: log.debug("****1. inside isResourceRequest, ext=" + ext);
081: if (ext.indexOf("/") != -1)
082: return false;
083:
084: // these are JSF pages, not resources
085: // THESE LINES OF CODE IS THE ONLY REASON THIS CLASS EXISTS!
086: if (ext.equals(".jsf"))
087: return false;
088: if (ext.equals(".faces"))
089: return false;
090: if (path.startsWith("/faces/"))
091: return false;
092: if (path.indexOf(".helper") > -1)
093: return false;
094:
095: // ok, it's a resource request
096: return true;
097: }
098:
099: protected void dispatch(HttpServletRequest req,
100: HttpServletResponse res) throws ServletException,
101: IOException {
102: // NOTE: this is a simple path dispatching, taking the path as the view id = jsp file name for the view,
103: // with default used if no path and a path prefix as configured.
104:
105: // build up the target that will be dispatched to
106: String target = req.getPathInfo();
107: log.debug("***0. dispatch, target =" + target);
108:
109: boolean sendToHelper = sendToHelper(req, res);
110: boolean isResourceRequest = isResourceRequest(target);
111: log.debug("***1. dispatch, send to helper =" + sendToHelper);
112: log.debug("***2. dispatch, isResourceRequest ="
113: + isResourceRequest);
114:
115: // see if we have a helper request
116: if (sendToHelper) {
117: return;
118: }
119:
120: if (isResourceRequest) {
121: // get a dispatcher to the path
122: RequestDispatcher resourceDispatcher = getServletContext()
123: .getRequestDispatcher(target);
124: if (resourceDispatcher != null) {
125: resourceDispatcher.forward(req, res);
126: return;
127: }
128: }
129:
130: if (target == null || "/".equals(target)) {
131: target = computeDefaultTarget();
132:
133: // make sure it's a valid path
134: if (!target.startsWith("/")) {
135: target = "/" + target;
136: }
137:
138: // now that we've messed with the URL, send a redirect to make it official
139: res.sendRedirect(Web.returnUrl(req, target));
140: return;
141: }
142:
143: // see if we want to change the specifically requested view
144: String newTarget = redirectRequestedTarget(target);
145:
146: // make sure it's a valid path
147: if (!newTarget.startsWith("/")) {
148: newTarget = "/" + newTarget;
149: }
150:
151: if (!newTarget.equals(target)) {
152: // now that we've messed with the URL, send a redirect to make it official
153: res.sendRedirect(Web.returnUrl(req, newTarget));
154: return;
155: }
156: target = newTarget;
157:
158: // store this
159: ToolSession toolSession = SessionManager
160: .getCurrentToolSession();
161: if (toolSession != null) {
162: toolSession.setAttribute(LAST_VIEW_VISITED, target);
163: }
164: log.debug("3a. dispatch: toolSession=" + toolSession);
165: log.debug("3b. dispatch: target=" + target);
166: log.debug("3c. dispatch: lastview?" + m_defaultToLastView);
167:
168: // add the configured folder root and extension (if missing)
169: target = m_path + target;
170:
171: // add the default JSF extension (if we have no extension)
172: int lastSlash = target.lastIndexOf("/");
173: int lastDot = target.lastIndexOf(".");
174: if (lastDot < 0 || lastDot < lastSlash) {
175: target += JSF_EXT;
176: }
177:
178: // set the information that can be removed from return URLs
179: req.setAttribute(URL_PATH, m_path);
180: req.setAttribute(URL_EXT, ".jsp");
181:
182: // set the sakai request object wrappers to provide the native, not Sakai set up, URL information
183: // - this assures that the FacesServlet can dispatch to the proper view based on the path info
184: req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL);
185:
186: // TODO: Should setting the HTTP headers be moved up to the portal level as well?
187: res.setContentType("text/html; charset=UTF-8");
188: res.addDateHeader("Expires", System.currentTimeMillis()
189: - (1000L * 60L * 60L * 24L * 365L));
190: res.addDateHeader("Last-Modified", System.currentTimeMillis());
191: res
192: .addHeader("Cache-Control",
193: "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
194: res.addHeader("Pragma", "no-cache");
195:
196: // dispatch to the target
197: log.debug("***4. dispatch, dispatching path: "
198: + req.getPathInfo() + " to: " + target + " context: "
199: + getServletContext().getServletContextName());
200: // if this is a return from the file picker and going back to
201: // case 1: item mofification, then set
202: // itemAuthorbean.attachmentlist = filepicker list
203: if (target.indexOf("/jsf/author/item/") > -1
204: && ("true").equals(toolSession
205: .getAttribute("SENT_TO_FILEPICKER_HELPER"))) {
206: ItemAuthorBean bean = (ItemAuthorBean) ContextUtil
207: .lookupBeanFromExternalServlet("itemauthor", req,
208: res);
209: bean.setItemAttachment();
210: toolSession.removeAttribute("SENT_TO_FILEPICKER_HELPER");
211: }
212:
213: // case 2: part mofification, then set
214: // sectionBean.attachmentList = filepicker list
215: if (target.indexOf("/jsf/author/editPart") > -1
216: && ("true").equals(toolSession
217: .getAttribute("SENT_TO_FILEPICKER_HELPER"))) {
218: SectionBean bean = (SectionBean) ContextUtil
219: .lookupBeanFromExternalServlet("sectionBean", req,
220: res);
221: bean.setPartAttachment();
222: toolSession.removeAttribute("SENT_TO_FILEPICKER_HELPER");
223: }
224:
225: // case 3: assessment settings mofification, then set
226: // assessmentSettingsBean.attachmentList = filepicker list
227: if (target.indexOf("/jsf/author/authorSettings") > -1
228: && ("true").equals(toolSession
229: .getAttribute("SENT_TO_FILEPICKER_HELPER"))) {
230: AssessmentSettingsBean bean = (AssessmentSettingsBean) ContextUtil
231: .lookupBeanFromExternalServlet(
232: "assessmentSettings", req, res);
233: bean.setAssessmentAttachment();
234: toolSession.removeAttribute("SENT_TO_FILEPICKER_HELPER");
235: }
236:
237: // case 4: create new mail, then set
238: // emailBean.attachmentList = filepicker list
239: if (target.indexOf("/jsf/evaluation/createNewEmail") > -1
240: && ("true").equals(toolSession
241: .getAttribute("SENT_TO_FILEPICKER_HELPER"))) {
242: EmailBean bean = (EmailBean) ContextUtil
243: .lookupBeanFromExternalServlet("email", req, res);
244: bean.prepareAttachment();
245: toolSession.removeAttribute("SENT_TO_FILEPICKER_HELPER");
246: }
247:
248: RequestDispatcher dispatcher = getServletContext()
249: .getRequestDispatcher(target);
250: dispatcher.forward(req, res);
251:
252: // restore the request object
253: req.removeAttribute(Tool.NATIVE_URL);
254: req.removeAttribute(URL_PATH);
255: req.removeAttribute(URL_EXT);
256:
257: }
258:
259: protected boolean sendToHelper(HttpServletRequest req,
260: HttpServletResponse res) throws ToolException {
261: String path = req.getPathInfo();
262: if (path == null)
263: path = "/";
264:
265: // 0 parts means the path was just "/", otherwise parts[0] = "", parts[1] = item id, parts[2]
266: // if present is "edit"...
267: String[] parts = path.split("/");
268:
269: log.debug("***a. sendToHelper.partLength=" + parts.length);
270: String helperPath = null;
271: String toolPath = null;
272:
273: // e.g. helper url in Samigo can be /jsf/author/item/sakai.filepicker.helper/tool
274: // or /sakai.filepicker.helper
275: if (parts.length > 2) {
276: log.debug("***b. sendToHelper.partLength=" + parts.length);
277: helperPath = parts[parts.length - 2];
278: toolPath = parts[parts.length - 1];
279: } else if (parts.length == 2) {
280: log.debug("***c. sendToHelper.partLength=" + parts.length);
281: helperPath = parts[1];
282: } else
283: return false;
284:
285: if (!helperPath.endsWith(HELPER_EXT))
286: return false;
287: log.debug("****d. sendToHelper, part #1=" + helperPath);
288: log.debug("****e. sendToHelper, part #2=" + toolPath);
289:
290: ToolSession toolSession = SessionManager
291: .getCurrentToolSession();
292: toolSession.setAttribute("SENT_TO_FILEPICKER_HELPER", "true");
293:
294: Enumeration params = req.getParameterNames();
295: while (params.hasMoreElements()) {
296: String paramName = (String) params.nextElement();
297: if (paramName.startsWith(HELPER_SESSION_PREFIX)) {
298: String attributeName = paramName
299: .substring(HELPER_SESSION_PREFIX.length());
300: toolSession.setAttribute(attributeName, req
301: .getParameter(paramName));
302: }
303: }
304:
305: // calc helper id
306: int posEnd = helperPath.lastIndexOf(".");
307: String helperId = helperPath.substring(0, posEnd);
308: log.debug("****f. sendToHelper, helperId=" + helperId);
309: ActiveTool helperTool = ActiveToolManager
310: .getActiveTool(helperId);
311:
312: String url = req.getContextPath() + req.getServletPath();
313: if (toolSession.getAttribute(helperTool.getId()
314: + Tool.HELPER_DONE_URL) == null) {
315: toolSession.setAttribute(helperTool.getId()
316: + Tool.HELPER_DONE_URL, url
317: + computeDefaultTarget(true));
318: }
319:
320: log.debug("****g. sendToHelper, url=" + url);
321: String context = url + "/" + helperPath;
322: log.debug("****h. sendToHelper, context=" + context);
323: if (toolPath != null)
324: helperTool.help(req, res, context, "/" + toolPath);
325: else
326: helperTool.help(req, res, context, "");
327:
328: return true; // was handled as helper call
329: }
330:
331: protected String computeDefaultTarget(boolean lastVisited) {
332: // setup for the default view as configured
333: ToolSession session = SessionManager.getCurrentToolSession();
334: String target = "/" + m_default;
335:
336: // if we are doing lastVisit and there's a last-visited view, for this tool placement / user, use that
337: if (lastVisited) {
338: String last = (String) session
339: .getAttribute(LAST_VIEW_VISITED);
340: if (last != null) {
341: target = last;
342: }
343: }
344: session.removeAttribute(LAST_VIEW_VISITED);
345: log.debug("***3. computeDefaultTarget()=" + target);
346: return target;
347: }
348: }
|