/*==========================================================================*\ | $Id: WCFileUpload.java,v 1.2 2011/03/07 18:45:12 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2006-2011 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.ui; import org.apache.log4j.Logger; import org.webcat.ui._base.DojoElement; import com.webobjects.appserver.WOActionResults; import com.webobjects.appserver.WOAssociation; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOElement; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WOResponse; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSData; import com.webobjects.foundation.NSDictionary; //------------------------------------------------------------------------ /** * A replacement for WOFileUpload that uploads files immediately, in the * background, instead of waiting for a full page submit. Javascript callbacks * can be used to determine when the upload is completed. * * <h2>Bindings</h2> * * <dl> * * <dt>clearAfterUpload</dt> * <dd>If false, the name of the uploaded file will remain displayed in the * control when the file upload is complete. If true, the control will be * cleared. False is most appropriate when the control is being used to upload * a single file and the user is expected to be able to change their selection * later; true is most appropriate when the control is used as a sink for * multiple file uploads, and feedback about which files have been uploaded is * provided elsewhere on the page. Defaults to false.</dd> * * <dt>filePath</dt> * <dd>This binding will receive the name of the file that was uploaded.</dd> * * <dt>data</dt> * <dd>This binding will receive the data for the file that was uploaded.</dd> * * <dt>disabled</dt> * <dd>True to disable the control, otherwise false.</dd> * * <dt>mimeType</dt> * <dd>This binding will receive the MIME type of the file that is uploaded. * </dd> * * <dt>copyData</dt> * <dd>True if the data stored in the <b>data</b> binding should be copied; * false if it should use the same data object that makes up the request data, * which is only useful if you do not need to keep the data around beyond the * current request/response cycle because the data buffer is recycled. Defaults * to true. * </dd> * * <dt>action</dt> * <dd>The action that should be invoked when the file upload is complete. At * this point <b>filePath</b>, <b>data</b>, and <b>mimeType</b> can be assumed * to be set. The response to this action is like that of a remote action in * the sense that it should either be null (to do nothing further on the client * side), or a JavascriptGenerator that describes how to manipulate the page * DOM once the upload is complete.</dd> * * <dt>remoteValidator</dt> * <dd>A validator method used to validate the appropriateness of the uploaded * content before the form containing this element is submitted. This can be * used to ensure that that a file is uploaded before the user continues to the * next page, for instance. This method should take no arguments and return * null if validation is successful, or a String containing an error to relay * back to the user.</dd> * * </dl> * * @author Tony Allevato * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.2 $, $Date: 2011/03/07 18:45:12 $ */ public class WCFileUpload extends DojoElement { //~ Constructors .......................................................... // ---------------------------------------------------------- public WCFileUpload(String name, NSDictionary<String, WOAssociation> someAssociations, WOElement template) { super("span", someAssociations, template); _name = _associations.removeObjectForKey("name"); _disabled = _associations.removeObjectForKey("disabled"); _filePath = _associations.removeObjectForKey("filePath"); _data = _associations.removeObjectForKey("data"); _mimeType = _associations.removeObjectForKey("mimeType"); _copyData = _associations.removeObjectForKey("copyData"); _action = _associations.removeObjectForKey("action"); _remoteValidator = _associations.removeObjectForKey("remoteValidator"); } //~ Methods ............................................................... // ---------------------------------------------------------- @Override public String dojoType() { return "webcat.FileInput"; } // ---------------------------------------------------------- /** * Gets the value of the "type" attribute that should be written along with * the tag, if it is an <input> element. * @param context TODO * * @return the value of the element's "type" attribute */ protected String inputTypeInContext(WOContext context) { return "file"; } // ---------------------------------------------------------- /** * Gets the name of the element in the specified context. * * @param context * the context * @return the name of the element */ public String nameInContext(WOContext context) { if (_name != null) { Object value = _name.valueInComponent(context.component()); if (value != null) { return value.toString(); } } Object elementID = context.elementID(); if (elementID != null) { return elementID.toString(); } else { throw new IllegalStateException("<" + getClass().getName() + "> " + "Cannot evaluate 'name' attribute, and context element " + "ID is null."); } } // ---------------------------------------------------------- protected boolean isDisabledInContext(WOContext context) { if (_disabled != null) return _disabled.booleanValueInComponent(context.component()); else return false; } // ---------------------------------------------------------- protected boolean copyDataInContext(WOContext context) { if (_copyData != null) return _copyData.booleanValueInComponent(context.component()); else return true; } // ---------------------------------------------------------- protected void appendInputTypeAttributeToResponse(WOResponse response, WOContext context) { String inputType = inputTypeInContext(context); if (inputType != null && inputType.length() > 0) { _appendTagAttributeAndValueToResponse(response, "type", inputType, false); } } // ---------------------------------------------------------- protected void appendNameAttributeToResponse(WOResponse response, WOContext context) { String name = nameInContext(context); if (name != null && name.length() > 0) { _appendTagAttributeAndValueToResponse(response, "name", name, false); } } // ---------------------------------------------------------- protected void appendDisabledAttributeToResponse(WOResponse response, WOContext context) { if (isDisabledInContext(context)) { _appendTagAttributeAndValueToResponse(response, "disabled", "disabled", false); } } // ---------------------------------------------------------- protected void appendUrlAttributeToResponse(WOResponse response, WOContext context) { String actionUrl = context.componentActionURL(); _appendTagAttributeAndValueToResponse(response, "url", actionUrl, false); } // ---------------------------------------------------------- @Override public void appendAttributesToResponse(WOResponse response, WOContext context) { super.appendAttributesToResponse(response, context); appendInputTypeAttributeToResponse(response, context); appendDisabledAttributeToResponse(response, context); appendNameAttributeToResponse(response, context); appendUrlAttributeToResponse(response, context); } // ---------------------------------------------------------- @Override public void appendChildrenToResponse(WOResponse response, WOContext context) { super.appendChildrenToResponse(response, context); if (_remoteValidator != null) { WCForm.appendValidatorScriptToResponse(response, context); } } // ---------------------------------------------------------- @Override public void takeValuesFromRequest(WORequest request, WOContext context) { if (!isDisabledInContext(context)) { String nameString = nameInContext(context); Object aFilePath = null; if (_filePath != null) { aFilePath = request.formValueForKey(nameString + ".filename"); if ((aFilePath instanceof String) && ((String) aFilePath).length() > 0) { _filePath.setValue(aFilePath, context.component()); } else { aFilePath = null; } } if (_data != null && aFilePath != null) { NSArray<?> aValue = request.formValuesForKey(nameString); if (aValue != null) { NSData dataCopy = null; try { dataCopy = (NSData) aValue.objectAtIndex(0); } catch (ClassCastException cce) { throw new ClassCastException( "<WCFileUpload>: Value in request was of type '" + aValue.objectAtIndex(0).getClass().getName() + "' instead of NSData. Verify that the WOForm's " + "'enctype' binding is set to 'multipart/form-data'"); } if (copyDataInContext(context)) { dataCopy = new NSData(dataCopy); } _data.setValue(dataCopy, context.component()); } if (_mimeType != null) { Object aMimeType = request.formValueForKey( nameString + ".mimetype"); if ((aMimeType instanceof String) && ((String) aMimeType).length() > 0) { _mimeType.setValue(aMimeType, context.component()); } } } } } // ---------------------------------------------------------- @Override public WOActionResults invokeAction(WORequest request, WOContext context) { WOActionResults result = null; if (!isDisabledInContext(context)) { if (_remoteValidator != null) { WCForm.addValidatorToCurrentForm(context.elementID(), _remoteValidator); } String nameString = nameInContext(context); Object aValue = request.formValueForKey(nameString); // Only invoke the action if this element is the file input being // submitted. if (aValue != null) { if (_action != null) { result = (WOActionResults) _action.valueInComponent( context.component()); } WOResponse response = new WOResponse(); appendActionResultToResponse(result, response); result = response; } } return result; } // ---------------------------------------------------------- /** * <p> * Appends the upload element's action results to a response, embedding * them in an HTML document with a textarea, as required by the Dojo iframe * I/O framework. * </p><p> * Future versions of this component may want to check the content type of * the action response and remove the embedding if it is HTML or XML * content, but for now we only support Javascript responses that are * executed client-side. * </p> * * @param result the action result * @param response the response */ private void appendActionResultToResponse( WOActionResults result, WOResponse response) { response.appendContentString("<html><head></head><body><textarea>"); if (result != null) { response.appendContentString( result.generateResponse().contentString()); } response.appendContentString("</textarea></body></html>"); } //~ Static/instance variables ............................................. protected WOAssociation _disabled; protected WOAssociation _name; protected WOAssociation _filePath; protected WOAssociation _data; protected WOAssociation _mimeType; protected WOAssociation _copyData; protected WOAssociation _action; protected WOAssociation _remoteValidator; static final Logger log = Logger.getLogger(WCFileUpload.class); }