/* 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.client; import com.esri.gpt.agp.multipart2.MPart; import com.esri.gpt.framework.http.ContentHandler; import com.esri.gpt.framework.http.HttpClientRequest; import com.esri.gpt.framework.http.ResponseInfo; import com.esri.gpt.framework.http.StringProvider; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.logging.Logger; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HeaderElement; import org.apache.commons.httpclient.NameValuePair; /** * A part within a multi-part HTTP request that streams source data * (e.g. item data, item thumbnail, ...) to a destination. */ public class AgpDPart extends MPart { /** class variables ========================================================= */ /** The Logger. */ private static Logger LOGGER = Logger.getLogger(AgpDPart.class.getName()); /** instance variables ====================================================== */ private AgpConnection sourceConnection; private String sourceFileName; private AgpItem sourceItem; private long sourceLength = -1; private String sourceUrl; private String step = null; /** constructors ============================================================ */ /** * Constructor. * @param sourceConnection the connection to the portal containing the source item * @param sourceItem the source item * @param sourceUrl the URL for the source item * @param name the part/property name * @param sourceFileName the part/property file name * @param sourceLength the length of the part data */ public AgpDPart(AgpConnection sourceConnection, AgpItem sourceItem, String sourceUrl, String name, String sourceFileName, long sourceLength) { super(name,null,sourceFileName,"application/octet-stream",null); //this.setTransferEncoding("binary"); this.setTransferEncoding(null); this.sourceConnection = sourceConnection; this.sourceItem = sourceItem; this.sourceUrl = sourceUrl; this.sourceFileName = sourceFileName; this.sourceLength = sourceLength; if (this.sourceItem == null) {} } /** * The length of the part data in bytes (-1 if unknown). * @return the data length * @throws IOException if an exception occurs */ @Override protected long dataLength() throws IOException { return this.sourceLength; } /** * Execute the write. * @param out the output stream * @throws Exception if an exception occurs */ private void execSend(final OutputStream destinationStream) throws Exception { AgpConnection srcCon = this.sourceConnection; String sUrl = this.sourceUrl; String rqType = "application/x-www-form-urlencoded"; StringBuilder rqParams = new StringBuilder(); srcCon.appendToken(rqParams); AgpProperties hdr = srcCon.makeRequestHeaderProperties(); AgpClient client = srcCon.ensureClient(); StringProvider provider = new StringProvider(rqParams.toString(),rqType); this.step = "connectingToSource"; try { client.executeRequest(sUrl,hdr,provider, new ContentHandler() { @Override public boolean onBeforeReadResponse(HttpClientRequest request) { AgpDPart oThis = AgpDPart.this; ResponseInfo info = request.getResponseInfo(); Header h; String s; s = "responseContentLength "+info.getContentLength(); AgpDPart.LOGGER.finest("onBeforeReadResponse "+s); h = info.getResponseHeader("Content-Type"); if (h != null) { HeaderElement elements[] = h.getElements(); // Expect only one header element to be there, no more, no less if (elements.length == 1) { String sContentType = elements[0].getName(); String sCharset = null; NameValuePair nvp = elements[0].getParameterByName("charset"); if (nvp != null) { sCharset = nvp.getValue(); } oThis.setContentType(sContentType); oThis.setCharset(sCharset); s = "contentType="+sContentType+" charset="+sCharset; AgpDPart.LOGGER.finest("onBeforeReadResponse "+s); } } h = info.getResponseHeader("Content-Disposition"); if (h != null) { HeaderElement elements[] = h.getElements(); for (HeaderElement element: elements) { NameValuePair[] params = element.getParameters(); for (NameValuePair param: params) { s = "Content-Disposition param "+param.getName()+"="+param.getValue(); AgpDPart.LOGGER.finest("onBeforeReadResponse "+s); if (param.getName().equals("filename")) { String sValue = param.getValue(); if (sValue != null) { oThis.sourceFileName = sValue; oThis.setFileName(sValue); s = "found Content-Disposition filename "+oThis.sourceFileName; AgpDPart.LOGGER.finest("onBeforeReadResponse "+s); } } else if (param.getName().equals("size")) { String sValue = param.getValue(); if (sValue != null) { long nSize = -2; try { nSize = Long.valueOf(param.getValue()); oThis.sourceLength = nSize; s = "found Content-Disposition size "+nSize; AgpDPart.LOGGER.finest("onBeforeReadResponse "+s); } catch (NumberFormatException nfe) { nSize = -2; } } } } } } return true; } @Override public void readResponse(HttpClientRequest request, InputStream responseStream) throws IOException { AgpDPart.LOGGER.finest("readResponse, streaming data..."); AgpDPart oThis = AgpDPart.this; oThis.step = "streamingToDestination"; oThis.sendStart(destinationStream); oThis.sendDispositionHeader(destinationStream); oThis.sendContentTypeHeader(destinationStream); oThis.sendTransferEncodingHeader(destinationStream); oThis.sendEndOfHeader(destinationStream); long nTotal = oThis.streamData(responseStream,destinationStream); AgpDPart.LOGGER.finest("readResponse, bytes transferred="+nTotal); oThis.sendEnd(destinationStream); } } ); } catch (IOException e) { boolean bThrow = true; if (this.step.equals("connectingToSource")) { String s = this.getName(); if ((s != null) && s.equals("metadata")) { s = e.toString(); // this is what happens when there is no metadata // 1.6.02 HTTP Request failed: HTTP/1.1 500 Internal Server Error // AGOL 4/13/2012 HTTP Request failed: HTTP/1.1 400 Bad Request if (s.contains("HTTP Request failed")) { AgpDPart.LOGGER.finest("No metadata found "+s); bThrow = false; } } } else { throw e; } if (bThrow) throw e; } } /** * Write the part to the stream. * @param out the output stream * @throws IOException if an exception occurs */ @Override public void send(OutputStream out) throws IOException { try { execSend(out); } catch (IOException ioe) { ioe.printStackTrace(); throw ioe; } catch (Exception e) { e.printStackTrace(); throw new IOException(e); } } }