/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.agp.multipart2;
import com.esri.gpt.framework.http.ContentProvider;
import com.esri.gpt.framework.http.HttpClientRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
/**
* Provides content for a multi-part HTTP request (outbound).
*/
public class MultipartProvider extends ContentProvider {
/** class variables ========================================================= */
/** The Logger. */
private static Logger LOGGER = Logger.getLogger(MultipartProvider.class.getName());
/** instance variables ====================================================== */
private String boundary = "387F8C2A-CFAB-443C-863B-B180E79B05F4";
private List<MPart> parts = new ArrayList<MPart>();
/** constructors ============================================================ */
/** Default constructor. */
public MultipartProvider() {}
/** properties ============================================================== */
/**
* Gets the boundary string.
* @return the boundary
*/
public String getBoundary() {
return this.boundary;
}
/**
* Sets the boundary string.
* @param boundary the boundary
*/
public void setBoundary(String boundary) {
this.boundary = boundary;
}
/**
* Gets the content type.
* @return the content type
*/
@Override
public String getContentType() {
return "multipart/form-data; boundary="+this.boundary;
}
/**
* Gets the parts.
* @return the parts
*/
public List<MPart> getParts() {
return this.parts;
}
/** methods ================================================================= */
/**
* Adds a part.
* @param part the part
*/
public void add(MPart part) {
this.getParts().add(part);
}
/**
* Adds a part.
* @param name the part name
* @param data the data value
* @throws IOException if an exception occurs
*/
public void add(String name, String data) throws IOException {
this.add(new MPart(name,data));
}
/**
* Adds a part.
* @param name the name
* @param data the data
* @param contentType the content type
* @throws IOException if an exception occurs
*/
public void add(String name, String data, String contentType)
throws IOException {
this.add(new MPart(name,data,contentType));
}
/**
* Adds a part.
* @param name the name
* @param data the data
* @param filename the file name
* @param contentType the content type
* @param charset the character set
* @throws IOException if an exception occurs
*/
public void add(String name, byte[] data, String filename,
String contentType, String charset) throws IOException {
this.add(new MPart(name,data,filename,contentType,charset));
}
/**
* Adds a part.
* @param name the name
* @param file the file
* @param filename the file name
* @param contentType the content type
* @param charset the character set
* @param deleteAfterUpload if true then delete the file after uploading
* @throws IOException if an exception occurs
*/
public void add(String name, final File file, String filename,
String contentType, String charset, final boolean deleteAfterUpload)
throws IOException {
this.add(new MPart(name,null,filename,contentType,charset) {
@Override
protected long dataLength() throws IOException {
if (file != null) return file.length();
return 0;
}
@Override
public boolean isRepeatable() {
return !deleteAfterUpload;
}
@Override
protected void sendData(OutputStream out) throws IOException {
if (this.dataLength() > 0) {
InputStream in = null;
try {
in = new FileInputStream(file);
this.streamData(in,out);
} finally {
try {if (in != null) in.close();}
catch (Exception ef) {ef.printStackTrace(System.err);}
if (deleteAfterUpload) {
try {
boolean deleted = file.delete();
if (!deleted) {
LOGGER.warning("Unable to delete file: "+file.getAbsolutePath());
}
} catch (SecurityException ex) {
LOGGER.warning("Unable to delete file: "+file.getAbsolutePath());
}
}
}
}
}
});
}
/**
* Gets the US-ASCII bytes for a value
* @param value the value
* @return the bytes
* @throws UnsupportedEncodingException if the encoding is unsupported
*/
protected byte[] getAsciiBytes(String value) throws UnsupportedEncodingException {
return value.getBytes("US-ASCII");
}
/**
* Gets the request body content length.
* @return the request content length (in bytes, -1 if unknown);
*/
@Override
public long getContentLength() {
try {
long nTotal = 0;
for (MPart part: this.getParts()) {
part.setBoundary(this.getBoundary());
long n = part.partLength();
if (n < 0) {
return -1;
}
nTotal += n;
}
nTotal += this.getAsciiBytes("--").length;
nTotal += this.getAsciiBytes(this.getBoundary()).length;
nTotal += this.getAsciiBytes("--").length;
nTotal += this.getAsciiBytes("\r\n").length;
//System.err.println("mpctl===== "+nTotal);
return nTotal;
} catch (Exception e) {
e.printStackTrace(System.err);
return 0;
}
}
/**
* True if all the parts can be written to the output stream more than once.
* @return true if repeatable
*/
@Override
public boolean isRepeatable() {
for (MPart part: this.getParts()) {
if (!part.isRepeatable()) {
return false;
}
}
return true;
}
/**
* Writes the content of the HTTP request body to an output stream.
* @param request the HTTP request that is executing
* @param destination the output stream to which data will be written
* @throws IOException if an exception occurs
*/
@Override
public void writeRequest(HttpClientRequest request, OutputStream destination)
throws IOException {
try {
for (MPart part: this.getParts()) {
part.setBoundary(this.getBoundary());
part.send(destination);
}
destination.write(this.getAsciiBytes("--"));
destination.write(this.getAsciiBytes(this.getBoundary()));
destination.write(this.getAsciiBytes("--"));
destination.write(this.getAsciiBytes("\r\n"));
} catch (IOException ioe) {
throw ioe;
} catch (Exception e) {
throw new IOException(e);
}
}
}