On Sun, Sep 14, 2003 at 08:33:01AM -0400, Geoff Howard wrote:
Aha! That wiki example has a problem I just noticed -- you shouldn't return null here (I just corrected the wiki). Use the corrected version above - I'll explain below.
...
I'm not sure "return new Map()" will work in the revised Wiki example. Map is just an interface, so you can't actually return an instantiated object.
DOH! Sorry, typing between commercials of the football game. I was undecided between two alternatives and took halfway between. Use this:
return java.util.Collections.EMPTY_MAP;
On the other hand, I'm not sure if returning some random object (say, HashMap) is going to work. I'm going to give it a try, though, and see what happens.
Yes, that would work too. Well, not a random object but any instanceof Map obviously. As long as it's not null.
If I get this going, I'll try to put together an wikified example that uses the Cocoon 2.1 API.
That'd be great. Actually, I have had a written but not tested version of a MultiPartFileAction on my hard drive for months which was meant to be committed into CVS but I haven't had the time or interest to finish up. If you're motivated to test it etc., it's attached. I was just finishing converting an original which merely saved to disk to now use ModifiableSource which would provide automatic support for other Source implementations, such as webdav repositories, cvs, etc. as they become available.
Geoff
/*
============================================================================
The Apache Software License, Version 1.1
============================================================================
Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The end-user documentation included with the redistribution, if any, must
include the following acknowledgment: "This product includes software
developed by the Apache Software Foundation (http://www.apache.org/)."
Alternately, this acknowledgment may appear in the software itself, if
and wherever such third-party acknowledgments normally appear.
4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
used to endorse or promote products derived from this software without
prior written permission. For written permission, please contact
[EMAIL PROTECTED]
5. Products derived from this software may not be called "Apache", nor may
"Apache" appear in their name, without prior written permission of the
Apache Software Foundation.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This software consists of voluntary contributions made by many individuals
on behalf of the Apache Software Foundation and was originally created by
Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache
Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.cocoon.acting;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.servlet.multipart.Part;
import org.apache.cocoon.servlet.multipart.PartOnDisk;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.ModifiableSource;
import org.apache.excalibur.source.impl.FileSource;
/**
* Action to save (or move) uploaded file(s) in multipart requests to a
* configurable location. Works with either PartOnDisk or PartInMemory
* (see web.xml and javadocs for configuration and definition).
*
* Current implementation acts on all Part objects in the request
* and does not need/use the name of the html form element. An enhancement
* would be to define an optional parameter for the object key to act on
* (the html form element's name attribute), falling back to the existing
* behavior when the parameter is absent. This would a) allow multiple files
* in a single request to be handled individually, b) potentially provide a
* performance improvement where many request parameters are present.
*
* Declaration:
* In map:components/map:actions section, define the action:
* <code><map:action name="multipart"
src="org.apache.cocoon.acting.MultiPartFileAction"
logger="sitemap.acting.multipart"/></code>
*
* Usage:
* <pre>
* <map:match pattern"myuploadurl">
* <map:act type="multipart">
* <map:parameter name="upload-dir" value="dir/to/save/to"/>
* </map:act>
* ...
* </map:match>
* </pre>
*
* This action is originally based on code which appeared in the mail archives.
*
* TODO: configure - one, list params, or all
* TODO: custom max size?
* TODO: location in config and param?
* TODO: check that cleanup doesn't bomb if this moves them
*
*
* @author <a href="mailto:[EMAIL PROTECTED]">Geoff Howard</a>
* @version CVS $Id$
*/
public class MultiPartFileAction extends AbstractConfigurableAction implements
ThreadSafe {
public Map act(Redirector redirector, SourceResolver resolver, Map objectModel,
String source, Parameters parameters) throws Exception {
Request request = ObjectModelHelper.getRequest(objectModel);
Context ctx = ObjectModelHelper.getContext(objectModel);
Map results = Collections.EMPTY_MAP;
String uploadDir=(String)parameters.getParameter("upload-dir");
boolean debug = getLogger().isDebugEnabled();
if (debug) {
getLogger().debug("Using upload-dir: " + uploadDir);
}
Enumeration enum=request.getParameterNames();
while(enum.hasMoreElements()) {
String name=(String)enum.nextElement();
Object obj=request.get(name);
if (obj instanceof Part) {
String fileName=((Part)obj).getFileName();
//fileName = sanitizeFileName(fileName); // Should be handled by
MultipartParser
if (debug) {
getLogger().debug("Handling file: "+ fileName);
}
//String canonicalName = ctx.getRealPath(uploadDir);
Source outSource = resolver.resolveURI(uploadDir + fileName);
if (outSource instanceof ModifiableSource) {
if (debug) {
//getLogger().debug("Got Real Path: " + canonicalName);
getLogger().debug("Writing upload to source " +
outSource.getURI());
}
try {
saveUploadAs( (Part)obj , (ModifiableSource)outSource);
} catch (Exception e) {
getLogger().error("Error Saving File: " + fileName);
getLogger().error(e.getMessage());
return null;
}
}
} else if (debug && obj instanceof String) {
getLogger().debug("Skipping parameter: "+(String)obj);
}
}
return Collections.unmodifiableMap(results);
}
/**
* Saves any <code>Part</code> object (eg, <code>PartOnDisk</code>
* or <code>PartInMemory</code>) to an arbitrary WritableSource.
* Legitimacy of newFile is assumed.
*
* @param fileData the Part object
* @param source ModifiableSource
*
*/
private void saveUploadAs(Part fileData, ModifiableSource source) throws IOException
{
if (fileData instanceof PartOnDisk && source instanceof FileSource) {
((PartOnDisk)fileData).getFile().renameTo( ((FileSource)source).getFile() );
} else {
byte[] buf=new byte[4096];
OutputStream out = source.getOutputStream();
InputStream in = null;
try {
in = ((Part) fileData).getInputStream();
} catch (Exception e) {
getLogger().error("Could not get InputStream from FilePart: " +
fileData.getFileName());
}
int read=in.read(buf);
while(read>0) {
out.write(buf,0,read);
read=in.read(buf);
}
out.close();
}
}
/**
* Saves any <code>Part</code> object (eg, <code>PartOnDisk</code>
* or <code>PartInMemory</code>) to disk. Legitimacy of newFile is assumed.
*
* @param fileData the FilePart object
* @param newFile the new name/location
* @deprecated
*/
private void saveUploadAs(Part fileData, File newFile) throws IOException {
if (fileData instanceof PartOnDisk) {
((PartOnDisk)fileData).getFile().renameTo(newFile);
} else {
byte[] buf=new byte[4096];
FileOutputStream out=new FileOutputStream(newFile);
InputStream in = null;
try {
in = ((Part) fileData).getInputStream();
} catch (Exception e) {
getLogger().error("Could not get InputStream from FilePart: " +
fileData.getFileName());
}
int read=in.read(buf);
while(read>0) {
out.write(buf,0,read);
read=in.read(buf);
}
out.close();
}
}
}
MultiPartFileAction.class
Description: Binary data
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
