001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064: package com.jcorporate.expresso.services.controller.dbmaint;
065:
066: import com.jcorporate.expresso.core.controller.ControllerException;
067: import com.jcorporate.expresso.core.controller.ControllerRequest;
068: import com.jcorporate.expresso.core.controller.ControllerResponse;
069: import com.jcorporate.expresso.core.controller.ErrorCollection;
070: import com.jcorporate.expresso.core.controller.NonHandleableException;
071: import com.jcorporate.expresso.core.controller.ServletControllerRequest;
072: import com.jcorporate.expresso.core.dataobjects.DataObject;
073: import com.jcorporate.expresso.core.dataobjects.NestableDataObject;
074: import com.jcorporate.expresso.core.dataobjects.Securable;
075: import com.jcorporate.expresso.core.dataobjects.jdbc.JDBCDataObject;
076: import com.jcorporate.expresso.core.dataobjects.jdbc.LobField;
077: import com.jcorporate.expresso.core.db.DBException;
078: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
079: import com.jcorporate.expresso.core.misc.StringUtil;
080: import com.jcorporate.expresso.core.security.User;
081: import com.jcorporate.expresso.services.dbobj.MediaDBObject;
082: import com.jcorporate.expresso.services.dbobj.MimeTypes;
083: import com.jcorporate.expresso.services.dbobj.Setup;
084: import org.apache.log4j.Logger;
085:
086: import javax.servlet.ServletOutputStream;
087: import javax.servlet.ServletResponse;
088: import javax.servlet.http.HttpServletResponse;
089: import java.io.InputStream;
090:
091: /**
092: * This state allows for viewing of BLOB data types. It supports standard
093: * blob types by sending a mime type of application/x-unknown, and is supports
094: * MediaDbObjects be setting MIME type, file name, and size to that of the
095: * file that was originally uploaded to the database table.
096: *
097: * @author Michael Rimov
098: * @version $Revision: 1.11 $ on $Date: 2004/11/17 20:48:18 $
099: */
100:
101: public class ViewBlob extends DynamicCmd {
102:
103: /**
104: * The log4j Logger.
105: */
106: private static Logger log = Logger.getLogger(ViewBlob.class);
107:
108: /**
109: * Constructor that sets the necessary description and key name.
110: */
111: public ViewBlob() {
112: super ("ViewBlob", "Binary File Contents");
113: this .addRequiredParameter("fieldName");
114: }
115:
116: /**
117: * Download the BLOB field.
118: *
119: * @param newRequest The ControllerRequest Object
120: * @param newResponse The ControllerREsponse OBject
121: */
122: public void run(ControllerRequest newRequest,
123: ControllerResponse newResponse)
124: throws com.jcorporate.expresso.core.controller.NonHandleableException,
125: com.jcorporate.expresso.core.controller.ControllerException {
126: super .run(newRequest, newResponse);
127:
128: DataObject curDBObj = null;
129: try {
130: curDBObj = this .retrieveMyDBObject();
131:
132: //
133: //Check = Is curDBObj an instance of JDBCDataObject OR if it is
134: //a nested object, then is the embedded data object that we're going to
135: //use a JDBCDataObject?
136: //
137:
138: if (curDBObj instanceof NestableDataObject) {
139: if (!(((NestableDataObject) curDBObj)
140: .getNestedFromFieldName(newRequest
141: .getParameter("fieldName")) instanceof JDBCDataObject)) {
142: ErrorCollection ee = new ErrorCollection();
143: ee
144: .addError("Blob viewing is only possible under nested JDBC dataobjects.");
145: newResponse.saveErrors(ee);
146: this .transition("Update", newRequest, newResponse);
147: return;
148: }
149: } else if (!(curDBObj instanceof JDBCDataObject)) {
150: ErrorCollection ee = new ErrorCollection();
151: ee
152: .addError("Blob viewing is only possible under JDBC dataobjects.");
153: newResponse.saveErrors(ee);
154: this .transition("Update", newRequest, newResponse);
155: return;
156: }
157: } catch (DBException ex) {
158: ErrorCollection ee = new ErrorCollection();
159: ee.addError(ex);
160: newResponse.saveErrors(ee);
161: this .transition("Update", newRequest, newResponse);
162: return;
163: }
164:
165: if (!(newRequest instanceof ServletControllerRequest)) {
166: throw new ControllerException("This state can only be"
167: + " run inside an HTTP Servlet Environment");
168: }
169:
170: try {
171: //Check Security
172: if (curDBObj instanceof Securable) {
173: ((Securable) curDBObj).isAllowed("S");
174: } else {
175: if (getUid() == SecuredDBObject.SYSTEM_ACCOUNT
176: || User.getUserFromId(
177: getUid(),
178: this .getControllerRequest()
179: .getDataContext()).isAdmin()) {
180: // all access ok
181: } else {
182: String allowInsecure = Setup
183: .getValue(
184: newRequest.getDataContext(),
185: com.jcorporate.expresso.core.ExpressoSchema.class
186: .getName(),
187: "insecureDBMaint");
188: if (!(StringUtil.toBoolean(allowInsecure))) {
189: throw new SecurityException(
190: "Access to unsecured Objects not allowed");
191: }
192: }
193: }
194: } catch (DBException ex) {
195: throw new ControllerException("Not allowed.", ex);
196: }
197:
198: //
199: //Get the field Name
200: //
201: String fieldName = newRequest.getParameter("fieldName");
202:
203: DataObject curDataObjectToUse = curDBObj;
204: if (curDataObjectToUse instanceof NestableDataObject) {
205: String fullFieldName = fieldName;
206: fieldName = ((NestableDataObject) curDataObjectToUse)
207: .getFieldFromNestedName(fieldName);
208: curDataObjectToUse = ((NestableDataObject) curDataObjectToUse)
209: .getNestedFromFieldName(fullFieldName);
210: }
211:
212: //
213: //Parameter and environment Checks
214: //
215: if (curDataObjectToUse instanceof MediaDBObject) {
216: sendMediaObjectField(newRequest, newResponse,
217: (MediaDBObject) curDataObjectToUse, fieldName);
218: return;
219: } else {
220: sendBlobField(newRequest, newResponse,
221: (JDBCDataObject) curDataObjectToUse, fieldName);
222: return;
223: }
224:
225: }
226:
227: /**
228: * Sends a BLOB field to the client browser.
229: *
230: * @param newRequest The ControllerRequest object
231: * @param newResponse The ControllerResponse object
232: * @param dbobj the DBObject to get the BLOB field from.
233: * @param fieldName the name of the field in the DBObject to send
234: * @throws ControllerException upon error
235: * @throws NonHandleableException upon fatal error
236: */
237: protected void sendBlobField(ControllerRequest newRequest,
238: ControllerResponse newResponse, JDBCDataObject dbobj,
239: String fieldName) throws ControllerException,
240: NonHandleableException {
241: ServletControllerRequest request = (ServletControllerRequest) newRequest;
242: ServletResponse sResponse = request.getServletResponse();
243:
244: LobField lf = new LobField();
245: try {
246: lf.setCriteria(dbobj);
247:
248: InputStream theBlob = lf.getBlobStream(fieldName);
249: if (theBlob == null) {
250: newResponse.addError("No Data Saved For This Record");
251: this .transition("Update", newRequest, newResponse);
252: lf.close();
253: return;
254: }
255:
256: String fileName = (String) dbobj.getDataField(fieldName)
257: .getAttribute("fileName");
258: if (fileName == null || fileName.length() == 0) {
259: fileName = fieldName;
260: }
261:
262: ((HttpServletResponse) sResponse).setHeader(
263: "Content-Disposition", "inline;filename="
264: + fileName);
265: newResponse.setCustomResponse(true);
266:
267: String mimeType = (String) dbobj.getDataField(fieldName)
268: .getAttribute("mimeType");
269: if (mimeType == null || mimeType.length() == 0) {
270: sResponse.setContentType("application/x-unknown");
271: } else {
272: sResponse.setContentType(mimeType);
273: }
274:
275: sendStream(theBlob, sResponse);
276: } catch (DBException ex) {
277: throw new ControllerException("Error getting BLOB field: ",
278: ex);
279: } catch (java.io.IOException ex) {
280: log.error("I/O Error transferring BLOB", ex);
281: } finally {
282: lf.close();
283: }
284: }
285:
286: /**
287: * Sends a Media DBObject's BLOB fields to the client.
288: *
289: * @param newRequest the controller request object
290: * @param newResponse the controller response object (Must be in a Servlet
291: * environment)
292: * @param dbobj THe Media DBObject derived class to send
293: * @param fieldName the field name in the dbobject to send
294: * @throws ControllerException upon error
295: * @throws NonHandleableException upon fatal error
296: */
297: protected void sendMediaObjectField(ControllerRequest newRequest,
298: ControllerResponse newResponse, MediaDBObject dbobj,
299: String fieldName) throws ControllerException,
300: NonHandleableException {
301: ServletControllerRequest request = (ServletControllerRequest) newRequest;
302: ServletResponse sResponse = request.getServletResponse();
303: try {
304:
305: //
306: //Attempt to get the BLOB stream
307: //
308: InputStream theBlob = dbobj.retrieveBlob(fieldName);
309: if (theBlob == null) {
310: dbobj.release();
311: newResponse.addError("No Data Saved For This Record");
312: this .transition("Update", newRequest, newResponse);
313: return;
314: }
315:
316: String fileName = dbobj.getField(fieldName
317: + MediaDBObject.FLD_FILE_SUFFIX);
318:
319: newResponse.setCustomResponse(true);
320:
321: //
322: //Set the file name if it exists.
323: //
324: if (fileName != null && fileName.length() > 0) {
325: ((HttpServletResponse) sResponse).setHeader(
326: "Content-Disposition", "inline;filename="
327: + fileName);
328: }
329:
330: //
331: //Set the application mime type
332: //
333: int mimeNumber = dbobj.getFieldInt(fieldName
334: + MediaDBObject.FLD_MIME_SUFFIX);
335:
336: if (mimeNumber <= 0) {
337: sResponse.setContentType("application/x-unknown");
338: } else {
339: try {
340: MimeTypes contentType = new MimeTypes(
341: SecuredDBObject.SYSTEM_ACCOUNT);
342: contentType.setField("MimeNumber", mimeNumber);
343: contentType.retrieve();
344: sResponse.setContentType(contentType
345: .getField("MimeType"));
346: } catch (DBException ex) {
347: sResponse.setContentType("application/x-unknown");
348: }
349: }
350:
351: //
352: //Check to see if we have the file size stored in memory. If we
353: //do, then set the content length to the size of the object. Makes
354: //downloading the streams more browser friendly.
355: //
356: int tempLength = dbobj.getFieldInt(fieldName
357: + MediaDBObject.FLD_SIZE_SUFFIX);
358:
359: //Set the content length if we can cope with it. This will have
360: //a max length of 2 Gb.
361: if (tempLength > 0) {
362: sResponse.setContentLength(tempLength);
363: }
364:
365: sendStream(theBlob, sResponse);
366:
367: } catch (DBException ex) {
368: throw new ControllerException("Error getting BLOB field: ",
369: ex);
370: } catch (java.io.IOException ex) {
371: log.error("I/O Error transferring BLOB", ex);
372: } finally {
373: dbobj.release();
374: }
375:
376: }
377:
378: /**
379: * Sends the given stream to the client servlet output stream.
380: *
381: * @param is The InputStream to send to the client.
382: * @param response The ServletResponse by which to get the OutputStream.
383: * @throws java.io.IOException upon error getting the OutputStream to
384: * the client.
385: */
386: protected void sendStream(InputStream is, ServletResponse response)
387: throws java.io.IOException {
388: //
389: //Now send the file
390: //
391: ServletOutputStream out = response.getOutputStream();
392: byte[] buf = new byte[4096]; // 4K buffer
393: int bytesRead;
394:
395: while ((bytesRead = is.read(buf)) != -1) {
396: out.write(buf, 0, bytesRead);
397: }
398:
399: try {
400: out.flush();
401: } catch (java.io.IOException ex) {
402: log.error("I/O Error flushing BLOB stream", ex);
403: }
404:
405: try {
406: out.close();
407: } catch (java.io.IOException ex) {
408: log.error("I/O Error closing BLOB output stream", ex);
409: }
410:
411: }
412: }
|