001: //** Copyright Statement ***************************************************
002: //The Salmon Open Framework for Internet Applications (SOFIA)
003: // Copyright (C) 1999 - 2002, Salmon LLC
004: //
005: // This program is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU General Public License version 2
007: // as published by the Free Software Foundation;
008: //
009: // This program is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: // GNU General Public License for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // along with this program; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: //
018: // For more information please visit http://www.salmonllc.com
019: //** End Copyright Statement ***************************************************
020: package com.salmonllc.servlets;
021:
022: /////////////////////////
023: //$Archive: /SOFIA/SourceCode/com/salmonllc/servlets/Objectstore.java $
024: //$Author: Dan $
025: //$Revision: 7 $
026: //$Modtime: 8/24/04 4:26p $
027: /////////////////////////
028:
029: import java.io.*;
030: import java.util.StringTokenizer;
031:
032: import javax.servlet.ServletException;
033: import javax.servlet.ServletOutputStream;
034: import javax.servlet.http.*;
035:
036: import com.salmonllc.html.HtmlPage;
037: import com.salmonllc.html.ImageGenerator;
038: import com.salmonllc.jsp.JspServlet;
039: import com.salmonllc.properties.Props;
040: import com.salmonllc.util.*;
041:
042: /**
043: * This Servlet is used to serve up static files or dynamically generated images. The files that will be served are located in the path specified in the system properties file under the key ObjectStorePath.
044: */
045: public class Objectstore extends HttpServlet {
046: public String decode(String sFile) {
047: if (sFile == null)
048: return null;
049: int percentindex = sFile.indexOf('%');
050: int iLen = sFile.length();
051: StringBuffer sbFile = new StringBuffer();
052: if (percentindex > 0)
053: sbFile.append(sFile.substring(0, percentindex));
054: else
055: sbFile.append(sFile);
056: while (percentindex >= 0) {
057: if (percentindex + 3 < iLen) {
058: try {
059: char ascii = (char) Integer.parseInt(sFile
060: .substring(percentindex + 1,
061: percentindex + 3), 16);
062: sbFile.append(ascii);
063: int nextPercent = sFile.substring(percentindex + 3)
064: .indexOf('%');
065: if (nextPercent < 0) {
066: sbFile
067: .append(sFile
068: .substring(percentindex + 3));
069: break;
070: } else
071: sbFile.append(sFile.substring(percentindex + 3,
072: percentindex + nextPercent + 3));
073: percentindex += nextPercent + 3;
074: } catch (Exception e) {
075: sbFile.append('%');
076: int nextPercent = sFile.substring(percentindex + 1)
077: .indexOf('%');
078: if (nextPercent < 0) {
079: sbFile
080: .append(sFile
081: .substring(percentindex + 1));
082: break;
083: } else
084: sbFile.append(sFile.substring(percentindex + 1,
085: percentindex + nextPercent + 1));
086: percentindex += nextPercent + 1;
087: }
088: } else {
089: sbFile.append('%');
090: int nextPercent = sFile.substring(percentindex + 1)
091: .indexOf('%');
092: if (nextPercent < 0) {
093: sbFile.append(sFile.substring(percentindex + 1));
094: break;
095: } else
096: sbFile.append(sFile.substring(percentindex + 1,
097: percentindex + nextPercent + 1));
098: percentindex += nextPercent + 1;
099: }
100: }
101:
102: return sbFile.toString();
103: }
104:
105: public void doGet(HttpServletRequest req, HttpServletResponse res)
106: throws ServletException, java.io.IOException {
107: JspServlet.setUpApplicationContext(getServletContext(), req);
108: String path = decode(req.getPathInfo());
109: MessageLog.writeInfoMessage("doGet(): Path=" + path, this );
110:
111: boolean readFromFileSystem = true;
112:
113: ServletOutputStream out = res.getOutputStream();
114:
115: if (path != null) {
116: String filename = path.substring(1);
117: String type = "";
118: int pos = filename.lastIndexOf(".");
119: if (pos > -1)
120: type = filename.substring(pos + 1).toLowerCase();
121:
122: try {
123: Props p = Props.getSystemProps();
124:
125: StringBuffer s = new StringBuffer(filename.length());
126: for (int i = 0; i < filename.length(); i++) {
127: char c = filename.charAt(i);
128: if (c == '/')
129: s.append(File.separatorChar);
130: else
131: s.append(c);
132: }
133:
134: String contentType;
135: if (type.equals("jpg") || type.equals("jpeg"))
136: contentType = "image/jpeg";
137: else if (type.equals("gif"))
138: contentType = "image/gif";
139: else if (type.equals("htm") || type.equals("html"))
140: contentType = "text/html";
141: else if (type.equals("pdf"))
142: contentType = "application/pdf";
143: else if (type.equals("doc"))
144: contentType = "application/msword";
145: else if (type.equals("xls") || type.equals("xlw"))
146: contentType = "application/vnd.ms-excel";
147: else if (type.equals("txt") || type.equals("log")
148: || type.equals("lst") || type.equals("ini"))
149: contentType = "text/plain";
150: else if (type.equals("ppt"))
151: contentType = "application/powerpointn";
152: else if (type.equals("zip"))
153: contentType = "application/x-gzip";
154: else if (type.equals("tif") || type.equals("tiff"))
155: contentType = "image/tif";
156: else if (type.equals("dgif")) {
157: contentType = "image/gif";
158: readFromFileSystem = false;
159: } else
160: contentType = "application/octet-stream";
161:
162: // create a byte array for getting objectstore data
163: byte[] b = null;
164:
165: // chunck size is currently 8k we may want to play with tuning this to the filetype or taking
166: // the file size divideing it by a factor and if it to big then just default to 64k.
167: int chunkSize = (1024 * 8);
168:
169: //
170: if (readFromFileSystem) {
171: String filePath = p
172: .getProperty(Props.SYS_OBJECTSTORE_PATH)
173: + File.separatorChar + s.toString();
174: String range = req.getHeader("range");
175: res.setHeader("Accept-Ranges", "bytes");
176: File fi = new File(filePath);
177: if (range == null) {
178: FileInputStream f = new FileInputStream(fi);
179: res.setStatus(HttpServletResponse.SC_OK);
180: res.setContentLength((int) fi.length());
181: res.setContentType(contentType);
182: b = new byte[chunkSize];
183: while (true) {
184: if (f.available() < chunkSize) {
185: b = new byte[f.available()];
186: f.read(b);
187: out.write(b);
188: break;
189: } else {
190: f.read(b);
191: out.write(b);
192: }
193: }
194:
195: f.close();
196: out.close();
197: } else {
198: res
199: .setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
200: res
201: .setContentType("multipart/x-byteranges; boundary=multipart_boundary");
202: ByteRangeParser rp = new ByteRangeParser(range,
203: (int) fi.length());
204: RandomAccessFile f = new RandomAccessFile(fi,
205: "r");
206: // For performance reasons we will init variables here
207: String contentRange = null;
208: long start = -1;
209: long end = -1;
210:
211: while (rp.nextRange()) {
212: out.println();
213: out.println("--multipart_boundary");
214: out.println("Content-type: " + contentType);
215: contentRange = "Content-range: bytes "
216: + rp.getFirstByte() + "-"
217: + rp.getLastByte() + "/"
218: + fi.length();
219: out.println(contentRange);
220: out.println();
221: f.seek(rp.getFirstByte());
222: start = rp.getFirstByte();
223: end = rp.getLastByte();
224: b = new byte[chunkSize];
225: while (start <= end) {
226: int len = (int) ((end - start) + 1);
227: if (len > chunkSize)
228: len = chunkSize;
229: f.read(b, 0, len);
230: out.write(b, 0, len);
231: start += len;
232: }
233: }
234: f.close();
235: out.println();
236: out.println("--multipart_boundary");
237: out.close();
238: }
239: } else {
240: b = getImage(req);
241: if (b != null) {
242: res.setStatus(HttpServletResponse.SC_OK);
243: res.setContentType(contentType);
244: res.setContentLength(b.length);
245: out.write(b);
246: }
247: out.close();
248: }
249: } catch (FileNotFoundException e) {
250: MessageLog.writeInfoMessage(
251: "***com.salmonllc.servlets.Objectstore, file not found***"
252: + e.getMessage(), this );
253: res.setStatus(HttpServletResponse.SC_NOT_FOUND);
254: res.setContentLength(0);
255: res.setContentType("application/octet-stream");
256: out.close();
257: } catch (java.net.SocketException e) {
258: } catch (Exception e) {
259: MessageLog.writeErrorMessage(
260: "Error transferring file to browser", e, this );
261: }
262: }
263:
264: }
265:
266: private byte[] genImage(HtmlPage p, String comp, String image)
267: throws IOException {
268: ByteArrayOutputStream bout = new ByteArrayOutputStream();
269: p.generateImage(comp, image, bout);
270: bout.flush();
271: byte b[] = bout.toByteArray();
272: bout.close();
273: return b;
274:
275: }
276:
277: private byte[] getImage(HttpServletRequest req) throws Exception {
278: String app = null;
279: String page = null;
280: String comp = null;
281: String image = null;
282:
283: String path = req.getPathInfo();
284: HttpSession sess = req.getSession(false);
285:
286: try {
287: StringTokenizer t = new StringTokenizer(path, "/");
288: app = t.nextToken();
289: page = t.nextToken();
290: comp = t.nextToken();
291: image = t.nextToken();
292: int pos = image.indexOf(".");
293: image = image.substring(0, pos);
294: } catch (Exception e) {
295: return null;
296: }
297:
298: String sesName = "$$$XXX$$$";
299: Props p = Props.getProps(app, page);
300: boolean useCache = p.getBooleanProperty(
301: Props.SYS_OBJECTSTORE_USE_CACHE, true);
302:
303: if (app.equals("JSP")) {
304: sesName = "$jsp$" + page;
305: } else {
306: String cName = p.getProperty(Props.SYS_APP_PACKAGE);
307: if (cName == null)
308: cName = app + "." + page;
309: else
310: cName += "." + app + "." + page;
311: sesName = "$page$" + cName;
312: }
313:
314: Object o = sess.getAttribute(sesName);
315:
316: if (o != null) {
317: if (o instanceof HtmlPage) {
318: HtmlPage pg = (HtmlPage) o;
319: ImageGenerator gen = pg.getImageGenerator(comp);
320: if (gen != null) {
321: if (gen.getCacheKey() == 0)
322: gen.setCacheKey(System.currentTimeMillis());
323: if (useCache
324: && gen.getUseCache()
325: && (ObjectstoreCache.getLastCleared() <= gen
326: .getCacheKey() || gen.getCacheKey() == 0)) {
327: byte[] ret = ObjectstoreCache.getEntry(path);
328: if (ret != null) {
329: return ret;
330: } else {
331: ret = genImage(pg, comp, image);
332: ObjectstoreCache.addEntry(path, ret);
333: return ret;
334: }
335: } else {
336: return genImage(pg, comp, image);
337: }
338: }
339: }
340: }
341: return null;
342: }
343: }
|