001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.multipart.commons;
018:
019: import java.io.ByteArrayInputStream;
020: import java.io.File;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.Serializable;
024:
025: import org.apache.commons.fileupload.FileItem;
026: import org.apache.commons.fileupload.FileUploadException;
027: import org.apache.commons.fileupload.disk.DiskFileItem;
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import org.springframework.web.multipart.MultipartFile;
032:
033: /**
034: * MultipartFile implementation for Jakarta Commons FileUpload.
035: *
036: * <p><b>NOTE:</b> As of Spring 2.0, this class requires Commons FileUpload 1.1
037: * or higher. The implementation does not use any deprecated FileUpload 1.0 API
038: * anymore, to be compatible with future Commons FileUpload releases.
039: *
040: * @author Trevor D. Cook
041: * @author Juergen Hoeller
042: * @since 29.09.2003
043: * @see CommonsMultipartResolver
044: */
045: public class CommonsMultipartFile implements MultipartFile,
046: Serializable {
047:
048: protected static final Log logger = LogFactory
049: .getLog(CommonsMultipartFile.class);
050:
051: private final FileItem fileItem;
052:
053: private final long size;
054:
055: /**
056: * Create an instance wrapping the given FileItem.
057: * @param fileItem the FileItem to wrap
058: */
059: public CommonsMultipartFile(FileItem fileItem) {
060: this .fileItem = fileItem;
061: this .size = this .fileItem.getSize();
062: }
063:
064: /**
065: * Return the underlying <code>org.apache.commons.fileupload.FileItem</code>
066: * instance. There is hardly any need to access this.
067: */
068: public final FileItem getFileItem() {
069: return this .fileItem;
070: }
071:
072: public String getName() {
073: return this .fileItem.getFieldName();
074: }
075:
076: public String getOriginalFilename() {
077: String filename = this .fileItem.getName();
078: if (filename == null) {
079: // Should never happen.
080: return "";
081: }
082: // check for Unix-style path
083: int pos = filename.lastIndexOf("/");
084: if (pos == -1) {
085: // check for Windows-style path
086: pos = filename.lastIndexOf("\\");
087: }
088: if (pos != -1) {
089: // any sort of path separator found
090: return filename.substring(pos + 1);
091: } else {
092: // plain name
093: return filename;
094: }
095: }
096:
097: public String getContentType() {
098: return this .fileItem.getContentType();
099: }
100:
101: public boolean isEmpty() {
102: return (this .size == 0);
103: }
104:
105: public long getSize() {
106: return this .size;
107: }
108:
109: public byte[] getBytes() {
110: if (!isAvailable()) {
111: throw new IllegalStateException(
112: "File has been moved - cannot be read again");
113: }
114: byte[] bytes = this .fileItem.get();
115: return (bytes != null ? bytes : new byte[0]);
116: }
117:
118: public InputStream getInputStream() throws IOException {
119: if (!isAvailable()) {
120: throw new IllegalStateException(
121: "File has been moved - cannot be read again");
122: }
123: InputStream inputStream = this .fileItem.getInputStream();
124: return (inputStream != null ? inputStream
125: : new ByteArrayInputStream(new byte[0]));
126: }
127:
128: public void transferTo(File dest) throws IOException,
129: IllegalStateException {
130: if (!isAvailable()) {
131: throw new IllegalStateException(
132: "File has already been moved - cannot be transferred again");
133: }
134:
135: if (dest.exists() && !dest.delete()) {
136: throw new IOException("Destination file ["
137: + dest.getAbsolutePath()
138: + "] already exists and could not be deleted");
139: }
140:
141: try {
142: this .fileItem.write(dest);
143: if (logger.isDebugEnabled()) {
144: String action = "transferred";
145: if (!this .fileItem.isInMemory()) {
146: action = isAvailable() ? "copied" : "moved";
147: }
148: logger.debug("Multipart file '" + getName()
149: + "' with original filename ["
150: + getOriginalFilename() + "], stored "
151: + getStorageDescription() + ": " + action
152: + " to [" + dest.getAbsolutePath() + "]");
153: }
154: } catch (FileUploadException ex) {
155: throw new IllegalStateException(ex.getMessage());
156: } catch (IOException ex) {
157: throw ex;
158: } catch (Exception ex) {
159: logger.error("Could not transfer to file", ex);
160: throw new IOException("Could not transfer to file: "
161: + ex.getMessage());
162: }
163: }
164:
165: /**
166: * Determine whether the multipart content is still available.
167: * If a temporary file has been moved, the content is no longer available.
168: */
169: protected boolean isAvailable() {
170: // If in memory, it's available.
171: if (this .fileItem.isInMemory()) {
172: return true;
173: }
174: // Check actual existence of temporary file.
175: if (this .fileItem instanceof DiskFileItem) {
176: return ((DiskFileItem) this .fileItem).getStoreLocation()
177: .exists();
178: }
179: // Check whether current file size is different than original one.
180: return (this .fileItem.getSize() == this .size);
181: }
182:
183: /**
184: * Return a description for the storage location of the multipart content.
185: * Tries to be as specific as possible: mentions the file location in case
186: * of a temporary file.
187: */
188: public String getStorageDescription() {
189: if (this .fileItem.isInMemory()) {
190: return "in memory";
191: } else if (this .fileItem instanceof DiskFileItem) {
192: return "at ["
193: + ((DiskFileItem) this .fileItem).getStoreLocation()
194: .getAbsolutePath() + "]";
195: } else {
196: return "on disk";
197: }
198: }
199:
200: }
|