001: /* Copyright 2002 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.car;
007:
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.io.OutputStream;
011: import java.io.PrintWriter;
012: import java.io.StringWriter;
013: import java.net.URLDecoder;
014: import java.util.Enumeration;
015:
016: import javax.servlet.ServletContext;
017: import javax.servlet.http.HttpServletRequest;
018: import javax.servlet.http.HttpServletResponse;
019:
020: import org.jasig.portal.IWorkerRequestProcessor;
021: import org.jasig.portal.PortalControlStructures;
022: import org.jasig.portal.PortalException;
023: import org.jasig.portal.PortalSessionManager;
024: import org.jasig.portal.RequestParamWrapper;
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027:
028: /**
029: * Class to handle incoming portal requests with specified worker of
030: * "carrsrc". These request are for loading web elements out of an installed
031: * channel archive file. The form of the URL is the traditional UPFileSpec
032: * with a worker of "carrsrc" and a query parameter "carrsrc=<resourcePath>".
033: * The resourcePath is the path to the resource from within the channel
034: * archive.
035: *
036: * For example: if a channel existed with the directory structure of
037: * "org/jasig/uportal/channels/email/" and within the email channel
038: * base directory there was an "images" directory containing "mailbox.gif"
039: * then the browser could access that image from the installed email channel
040: * archive via "<uPFileSpecWithWorker.carrsrc>.uP?carrsrc=org/jasig/
041: * uportal/channels/email/images/mailbox.gif".
042: *
043: * See the ChannelRuntimeData.getBaseMediaURL methods from which channels
044: * can obtain the base URL dynamically without having to know if they are
045: * deployed as a traditional channel or as a channel archive.
046: * @author Mark Boyd {@link <a href="mailto:mark.boyd@engineer.com">mark.boyd@engineer.com</a>}
047: * @version $Revision: 36690 $
048: */
049: public class CarResourceWorker implements IWorkerRequestProcessor {
050: private static final Log log = LogFactory
051: .getLog(CarResourceWorker.class);
052: private static CarResources resources = CarResources.getInstance();
053: public final static String RCS_ID = "@(#) $Header$";
054:
055: /**
056: Create a CarResourceWorker.
057: */
058: public CarResourceWorker() {
059: }
060:
061: /**
062: Provides web access to channel resources stored in channel archive
063: files housing channels if the channels were installed in the portal
064: using a CAR.
065: */
066: public void processWorkerDispatch(PortalControlStructures pcs)
067: throws PortalException {
068: HttpServletRequest req = pcs.getHttpServletRequest();
069: HttpServletResponse res = pcs.getHttpServletResponse();
070:
071: // get the named resource
072: String resourceName = getResourceName(req);
073: InputStream in = resources.getResourceAsStream(resourceName);
074:
075: if (in == null) {
076: res.setStatus(HttpServletResponse.SC_NOT_FOUND);
077: return;
078: }
079: setContentType(res, resourceName);
080: long resourceSize = resources.getResourceSize(resourceName);
081:
082: if (resourceSize != -1)
083: res.setHeader("Content-Length", "" + resourceSize);
084:
085: OutputStream out = null;
086: try {
087: out = res.getOutputStream();
088: byte[] bytes = new byte[4096];
089: int bytesRead = 0;
090: bytesRead = in.read(bytes);
091:
092: while (bytesRead != -1) {
093: out.write(bytes, 0, bytesRead);
094: bytesRead = in.read(bytes);
095: }
096:
097: out.flush();
098: } catch (IOException ioe) {
099: throw new PortalException("Error writing resource");
100: } finally {
101: try {
102: in.close();
103: if (out != null)
104: out.close();
105: } catch (IOException ioe) {
106: log.error("CarResourceWorker::processWorkerDispatch() "
107: + "could not close IO Stream", ioe);
108: }
109: }
110: }
111:
112: /**
113: Set the content type for the resource being served back. The
114: ServletContext is used to obtain the proper mime-types.
115: New/unknown types are defined in the deployment descriptor of
116: the web application. In the future, channels could provide
117: their own override file of types that they wish to support
118: beyond the defaults.
119: */
120: private void setContentType(HttpServletResponse res,
121: String resourceName) throws PortalException {
122: resourceName = resourceName.toLowerCase();
123:
124: ServletContext sc = PortalSessionManager.getInstance()
125: .getServletConfig().getServletContext();
126:
127: String mimeType = MimeTypeCache.getMimeType(sc, resourceName);
128:
129: if (null != mimeType)
130: res.setContentType(mimeType);
131: else
132: throw new PortalException("Unsupported resource type"
133: + " '" + resourceName + "'");
134: }
135:
136: /**
137: Set the content type for the resource being served back.
138: */
139: private String getResourceName(HttpServletRequest req)
140: throws PortalException {
141: // check if the resource name has been passed via the
142: // query string parm 'car_rsrc'
143: String resourceName = req
144: .getParameter(CarResources.CAR_RESOURCE_PARM);
145:
146: if (resourceName == null) {
147: Enumeration e = req.getParameterNames();
148: if (e == null)
149: throw new PortalException(
150: "getParameterNames() is null.");
151: StringWriter sw = new StringWriter();
152: PrintWriter pw = new PrintWriter(sw);
153:
154: if (!e.hasMoreElements())
155: pw.print("getParameterNames() is empty."
156: + " Req class = " + req.getClass().getName());
157:
158: while (e.hasMoreElements()) {
159: String parm = (String) e.nextElement();
160: Object[] vals = req.getParameterValues(parm);
161: if (vals == null) {
162: pw.print(" " + parm + "(-)");
163: if (req instanceof RequestParamWrapper)
164: vals = ((RequestParamWrapper) req)
165: .getObjectParameterValues(parm);
166: if (vals == null)
167: pw.print(" " + parm + "(both)=[]");
168: else
169: pw.print(" " + parm + "(2nd)=[");
170: } else {
171: pw.print(" " + parm + "=[");
172: }
173: if (vals != null) {
174: for (int i = 0; i < vals.length; i++) {
175: if (i > 0)
176: pw.print(", ");
177: pw.print(vals[i]);
178: }
179: pw.print("]");
180: }
181: }
182: pw.flush();
183: pw.close();
184: throw new PortalException("Resource name not specified. "
185: + sw.toString());
186: }
187: try {
188: resourceName = URLDecoder.decode(resourceName, "UTF-8");
189: } catch (Exception ex) {
190: throw new PortalException(
191: "Unable to URLDecode the resource" + " name '"
192: + resourceName + "'");
193: }
194: return resourceName;
195: }
196: }
|