datai/docs/reference-code/force-wsc-57.0.0/com/sforce/async/BulkConnection.java

713 lines
32 KiB
Java

package com.sforce.async;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;
import com.sforce.ws.MessageHandler;
import com.sforce.ws.MessageHandlerWithHeaders;
import com.sforce.ws.bind.CalendarCodec;
import com.sforce.ws.bind.TypeMapper;
import com.sforce.ws.parser.PullParserException;
import com.sforce.ws.parser.XmlInputStream;
import com.sforce.ws.parser.XmlOutputStream;
import com.sforce.ws.transport.Transport;
import com.sforce.ws.util.FileUtil;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.xml.namespace.QName;
public class BulkConnection {
public static final String NAMESPACE = "http://www.force.com/2009/06/asyncapi/dataload";
public static final String SESSION_ID = "X-SFDC-Session";
public static final String XML_CONTENT_TYPE = "application/xml";
public static final String CSV_CONTENT_TYPE = "text/csv";
public static final String JSON_CONTENT_TYPE = "application/json";
public static final String ZIP_XML_CONTENT_TYPE = "zip/xml";
public static final String ZIP_CSV_CONTENT_TYPE = "zip/csv";
public static final String ZIP_JSON_CONTENT_TYPE = "zip/json";
public static final QName JOB_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "jobInfo");
public static final QName BATCH_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "batchInfo");
public static final QName BATCH_LIST_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "batchInfoList");
public static final QName ERROR_QNAME = new QName("http://www.force.com/2009/06/asyncapi/dataload", "error");
private ConnectorConfig config;
private HashMap<String, String> headers = new HashMap<>();
public static final TypeMapper typeMapper = new TypeMapper(null, null, false);
private static final JsonFactory factory = new JsonFactory((ObjectCodec)new ObjectMapper());
public BulkConnection(ConnectorConfig config) throws AsyncApiException {
if (config == null)
throw new AsyncApiException("config can not be null", AsyncExceptionCode.ClientInputError);
if (config.getRestEndpoint() == null)
throw new AsyncApiException("rest endpoint cannot be null",
AsyncExceptionCode.ClientInputError);
this.config = config;
if (config.getSessionId() == null)
throw new AsyncApiException("session ID not found",
AsyncExceptionCode.ClientInputError);
}
public JobInfo createJob(String object, String operation) throws AsyncApiException {
JobInfo job = new JobInfo();
job.setObject(object);
job.setOperation(OperationEnum.valueOf(operation));
return createJob(job);
}
public JobInfo createJob(JobInfo job) throws AsyncApiException {
String endpoint = getRestEndpoint();
endpoint = String.valueOf(endpoint) + "job/";
return createOrUpdateJob(job, endpoint);
}
public JobInfo createJob(JobInfo job, ContentType contentType) throws AsyncApiException {
String endpoint = getRestEndpoint();
endpoint = String.valueOf(endpoint) + "job/";
return createOrUpdateJob(job, endpoint, contentType);
}
private JobInfo createOrUpdateJob(JobInfo job, String endpoint) throws AsyncApiException {
return createOrUpdateJob(job, endpoint, (job.getContentType() == null) ? ContentType.XML :
job.getContentType());
}
private JobInfo createOrUpdateJob(JobInfo job, String endpoint, ContentType contentType) throws AsyncApiException {
try {
Transport transport = this.config.createTransport();
if (contentType == ContentType.ZIP_JSON || contentType == ContentType.JSON) {
OutputStream out = transport.connect(endpoint, getHeaders("application/json"));
serializeToJson(out, job);
out.close();
} else {
OutputStream out = transport.connect(endpoint, getHeaders("application/xml"));
XmlOutputStream xout = new AsyncXmlOutputStream(out, true);
job.write(JOB_QNAME, xout, typeMapper);
xout.close();
}
InputStream in = transport.getContent();
if (transport.isSuccessful()) {
if (contentType == ContentType.ZIP_JSON || contentType == ContentType.JSON)
return deserializeJsonToObject(in, JobInfo.class);
XmlInputStream xin = new XmlInputStream();
xin.setInput(in, "UTF-8");
JobInfo result = new JobInfo();
result.load(xin, typeMapper);
return result;
}
parseAndThrowException(in, contentType);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to create job ", AsyncExceptionCode.ClientInputError, e);
} catch (IOException e) {
throw new AsyncApiException("Failed to create job ", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create job ", AsyncExceptionCode.ClientInputError, e);
}
return null;
}
static void parseAndThrowException(InputStream in, ContentType type) throws AsyncApiException {
try {
AsyncApiException exception;
if (type == ContentType.XML || type == ContentType.ZIP_XML || type == ContentType.CSV || type == ContentType.ZIP_CSV) {
exception = new AsyncApiException();
XmlInputStream xin = new XmlInputStream();
xin.setInput(in, "UTF-8");
exception.load(xin, typeMapper);
} else if (type == ContentType.JSON || type == ContentType.ZIP_JSON) {
JsonParser parser = factory.createJsonParser(in);
exception = (AsyncApiException)parser.readValueAs(AsyncApiException.class);
} else {
throw new AsyncApiException("Server error returned in unknown format", AsyncExceptionCode.ClientInputError);
}
throw exception;
} catch (PullParserException e) {
AsyncApiException exception;
throw new AsyncApiException("Failed to parse exception ", AsyncExceptionCode.ClientInputError, exception);
} catch (IOException e) {
throw new AsyncApiException("Failed to parse exception", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to parse exception ", AsyncExceptionCode.ClientInputError, e);
}
}
public void addHeader(String headerName, String headerValue) {
this.headers.put(headerName, headerValue);
}
private String getRestEndpoint() {
String endpoint = this.config.getRestEndpoint();
endpoint = endpoint.endsWith("/") ? endpoint : (String.valueOf(endpoint) + "/");
return endpoint;
}
public BatchInfo createBatchFromStream(JobInfo jobInfo, InputStream input) throws AsyncApiException {
return createBatchFromStreamImpl(jobInfo, input, false);
}
public BatchInfo createBatchFromZipStream(JobInfo jobInfo, InputStream zipInput) throws AsyncApiException {
return createBatchFromStreamImpl(jobInfo, zipInput, true);
}
private BatchInfo createBatchFromStreamImpl(JobInfo jobInfo, InputStream input, boolean isZip) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
Transport transport = this.config.createTransport();
endpoint = String.valueOf(endpoint) + "job/" + jobInfo.getId() + "/batch";
String contentType = getContentTypeString(jobInfo.getContentType(), isZip);
HashMap<String, String> httpHeaders = getHeaders(contentType);
boolean allowZipToBeGzipped = false;
OutputStream out = transport.connect(endpoint, httpHeaders, !(!allowZipToBeGzipped && isZip));
FileUtil.copy(input, out);
InputStream result = transport.getContent();
if (!transport.isSuccessful())
parseAndThrowException(result, jobInfo.getContentType());
if (jobInfo.getContentType() == ContentType.JSON || jobInfo.getContentType() == ContentType.ZIP_JSON)
return deserializeJsonToObject(result, BatchInfo.class);
return BatchRequest.loadBatchInfo(result);
} catch (IOException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
}
}
public BatchInfo createBatchFromDir(JobInfo job, InputStream batchContent, File attachmentDir) throws AsyncApiException {
List<File> files = FileUtil.listFilesRecursive(attachmentDir, false);
Map<String, File> fileMap = new HashMap<>(files.size());
String rootPath = String.valueOf(attachmentDir.getAbsolutePath()) + File.separator;
for (File f : files) {
String name = f.getAbsolutePath().replace(rootPath, "");
fileMap.put(name, f);
}
return createBatchWithFileAttachments(job, batchContent, fileMap);
}
public BatchInfo createBatchWithFileAttachments(JobInfo jobInfo, InputStream batchContent, File rootDirectory, String... files) throws AsyncApiException {
Map<String, File> fileMap = new HashMap<>(files.length);
byte b;
int i;
String[] arrayOfString;
for (i = (arrayOfString = files).length, b = 0; b < i; ) {
String fileName = arrayOfString[b];
File f = new File(rootDirectory, fileName);
fileMap.put(fileName, f);
b++;
}
return createBatchWithFileAttachments(jobInfo, batchContent, fileMap);
}
public BatchInfo createBatchWithFileAttachments(JobInfo jobInfo, InputStream batchContent, Map<String, File> attachedFiles) throws AsyncApiException {
Map<String, InputStream> inputStreamMap = new HashMap<>(attachedFiles.size());
for (Map.Entry<String, File> entry : attachedFiles.entrySet()) {
File file = entry.getValue();
try {
inputStreamMap.put(entry.getKey(), new FileInputStream(file));
} catch (IOException e) {
throw new AsyncApiException("Failed to create batch. Could not read file : " + file,
AsyncExceptionCode.ClientInputError, e);
}
}
return createBatchWithInputStreamAttachments(jobInfo, batchContent, inputStreamMap);
}
public BatchInfo createBatchWithInputStreamAttachments(JobInfo jobInfo, InputStream batchContent, Map<String, InputStream> attachments) throws AsyncApiException {
if (batchContent != null && attachments.get("request.txt") != null)
throw new AsyncApiException("Request content cannot be included as both input stream and attachment",
AsyncExceptionCode.ClientInputError);
try {
String endpoint = getRestEndpoint();
endpoint = String.valueOf(endpoint) + "job/" + jobInfo.getId() + "/batch";
Transport transport = this.config.createTransport();
ZipOutputStream zipOut = new ZipOutputStream(transport.connect(endpoint, getHeaders(getContentTypeString(
jobInfo.getContentType(), true)), false));
try {
if (batchContent != null) {
zipOut.putNextEntry(new ZipEntry("request.txt"));
FileUtil.copy(batchContent, zipOut, false);
}
for (Map.Entry<String, InputStream> entry : attachments.entrySet()) {
zipOut.putNextEntry(new ZipEntry(entry.getKey()));
FileUtil.copy(entry.getValue(), zipOut, false);
}
} finally {
zipOut.close();
}
InputStream result = transport.getContent();
if (jobInfo.getContentType() == ContentType.JSON || jobInfo.getContentType() == ContentType.ZIP_JSON)
return deserializeJsonToObject(result, BatchInfo.class);
return BatchRequest.loadBatchInfo(result);
} catch (IOException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
}
}
public BatchInfo createBatchFromForeignCsvStream(JobInfo jobInfo, InputStream input, String charSet) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
Transport transport = this.config.createTransport();
endpoint = String.valueOf(endpoint) + "job/" + jobInfo.getId() + "/batch";
String contentType = getContentTypeString(ContentType.CSV, false);
if (charSet != null)
contentType = String.valueOf(contentType) + ";charset=" + charSet;
HashMap<String, String> httpHeaders = getHeaders(contentType);
boolean allowZipToBeGzipped = false;
OutputStream out = transport.connect(endpoint, httpHeaders, false);
FileUtil.copy(input, out);
InputStream result = transport.getContent();
if (!transport.isSuccessful())
parseAndThrowException(result, jobInfo.getContentType());
return BatchRequest.loadBatchInfo(result);
} catch (IOException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
}
}
public void createTransformationSpecFromStream(JobInfo jobInfo, InputStream input) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
Transport transport = this.config.createTransport();
endpoint = String.valueOf(endpoint) + "job/" + jobInfo.getId() + "/spec";
String contentType = getContentTypeString(ContentType.CSV, false);
HashMap<String, String> httpHeaders = getHeaders(contentType);
boolean allowZipToBeGzipped = false;
OutputStream out = transport.connect(endpoint, httpHeaders, false);
FileUtil.copy(input, out);
InputStream result = transport.getContent();
if (!transport.isSuccessful())
parseAndThrowException(result, jobInfo.getContentType());
} catch (IOException e) {
throw new AsyncApiException("Failed to create transformation specification", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create transformation specification", AsyncExceptionCode.ClientInputError, e);
}
}
private String getContentTypeString(ContentType contentType, boolean isZip) throws AsyncApiException {
ContentType ct = (contentType == null) ? ContentType.XML : contentType;
if (isZip) {
switch (ct) {
case ZIP_CSV:
return "zip/csv";
case ZIP_XML:
return "zip/xml";
case ZIP_JSON:
return "zip/json";
}
throw new AsyncApiException("Invalid zip content type: " + contentType,
AsyncExceptionCode.ClientInputError);
}
switch (ct) {
case XML:
return "application/xml";
case null:
return "text/csv";
case JSON:
return "application/json";
}
throw new AsyncApiException("Not expecting zip content type: " + contentType,
AsyncExceptionCode.ClientInputError);
}
private HashMap<String, String> getHeaders(String contentType) {
HashMap<String, String> newMap = new HashMap<>();
for (Map.Entry<String, String> entry : this.headers.entrySet())
newMap.put(entry.getKey(), entry.getValue());
newMap.put("Content-Type", contentType);
newMap.put("X-SFDC-Session", this.config.getSessionId());
return newMap;
}
public BatchRequest createBatch(JobInfo job) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
Transport transport = this.config.createTransport();
endpoint = String.valueOf(endpoint) + "job/" + job.getId() + "/batch";
ContentType ct = job.getContentType();
if (ct != null && ct != ContentType.XML && ct != ContentType.JSON)
throw new AsyncApiException(
"This method can only be used with xml or JSON content type", AsyncExceptionCode.ClientInputError);
String jobContentType = "";
if (ct == null) {
jobContentType = "application/xml";
} else {
OutputStream out;
switch (ct) {
case JSON:
jobContentType = "application/json";
out = transport.connect(endpoint, getHeaders(jobContentType));
return new BatchRequest(transport, out);
}
jobContentType = "application/xml";
}
OutputStream outputStream = transport.connect(endpoint, getHeaders(jobContentType));
return new BatchRequest(transport, outputStream);
} catch (IOException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException x) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, x);
}
}
public CsvBatchRequest createCsvBatch(JobInfo job) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
Transport transport = this.config.createTransport();
endpoint = String.valueOf(endpoint) + "job/" + job.getId() + "/batch";
ContentType ct = job.getContentType();
if (ct != null && ct != ContentType.CSV)
throw new AsyncApiException(
"This method can only be used with csv content type", AsyncExceptionCode.ClientInputError);
OutputStream out = transport.connect(endpoint, getHeaders("text/csv"));
return new CsvBatchRequest(transport, out);
} catch (IOException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create batch", AsyncExceptionCode.ClientInputError, e);
}
}
public TransformationSpecRequest createTransformationSpec(JobInfo job) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
Transport transport = this.config.createTransport();
endpoint = String.valueOf(endpoint) + "job/" + job.getId() + "/spec";
ContentType ct = job.getContentType();
if (ct != null && ct != ContentType.CSV)
throw new AsyncApiException(
"This method can only be used with csv content type", AsyncExceptionCode.ClientInputError);
boolean allowZipToBeGzipped = false;
OutputStream out = transport.connect(endpoint, getHeaders("text/csv"), false);
return new TransformationSpecRequest(transport, out);
} catch (IOException e) {
throw new AsyncApiException("Failed to create transformation spec", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to create transformation spec", AsyncExceptionCode.ClientInputError, e);
}
}
public BatchInfoList getBatchInfoList(String jobId) throws AsyncApiException {
return getBatchInfoList(jobId, ContentType.XML);
}
public BatchInfoList getBatchInfoList(String jobId, ContentType contentType) throws AsyncApiException {
try {
String endpoint = String.valueOf(getRestEndpoint()) + "job/" + jobId + "/batch/";
URL url = new URL(endpoint);
InputStream stream = doHttpGet(url);
if (contentType == ContentType.JSON || contentType == ContentType.ZIP_JSON)
return deserializeJsonToObject(stream, BatchInfoList.class);
XmlInputStream xin = new XmlInputStream();
xin.setInput(stream, "UTF-8");
BatchInfoList result = new BatchInfoList();
result.load(xin, typeMapper);
return result;
} catch (IOException e) {
throw new AsyncApiException("Failed to get batch info list ", AsyncExceptionCode.ClientInputError, e);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to get batch info list ", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to get batch info list ", AsyncExceptionCode.ClientInputError, e);
}
}
public BatchInfo getBatchInfo(String jobId, String batchId) throws AsyncApiException {
return getBatchInfo(jobId, batchId, ContentType.XML);
}
public BatchInfo getBatchInfo(String jobId, String batchId, ContentType contentType) throws AsyncApiException {
try {
String endpoint = String.valueOf(getRestEndpoint()) + "job/" + jobId + "/batch/" + batchId;
URL url = new URL(endpoint);
InputStream stream = doHttpGet(url);
if (contentType == ContentType.JSON || contentType == ContentType.ZIP_JSON)
return deserializeJsonToObject(stream, BatchInfo.class);
XmlInputStream xin = new XmlInputStream();
xin.setInput(stream, "UTF-8");
BatchInfo result = new BatchInfo();
result.load(xin, typeMapper);
return result;
} catch (IOException e) {
throw new AsyncApiException("Failed to parse batch info ", AsyncExceptionCode.ClientInputError, e);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to parse batch info ", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to parse batch info ", AsyncExceptionCode.ClientInputError, e);
}
}
public BatchResult getBatchResult(String jobId, String batchId) throws AsyncApiException {
return getBatchResult(jobId, batchId, ContentType.XML);
}
public BatchResult getBatchResult(String jobId, String batchId, ContentType contentType) throws AsyncApiException {
try {
InputStream stream = doHttpGet(buildBatchResultURL(jobId, batchId));
if (contentType == ContentType.JSON || contentType == ContentType.ZIP_JSON) {
BatchResult batchResult = new BatchResult();
Result[] results = deserializeJsonToObject(stream, (Class)Result[].class);
batchResult.setResult(results);
return batchResult;
}
XmlInputStream xin = new XmlInputStream();
xin.setInput(stream, "UTF-8");
BatchResult result = new BatchResult();
result.load(xin, typeMapper);
return result;
} catch (PullParserException e) {
throw new AsyncApiException("Failed to parse result ", AsyncExceptionCode.ClientInputError, e);
} catch (IOException e) {
throw new AsyncApiException("Failed to get result ", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to get result ", AsyncExceptionCode.ClientInputError, e);
}
}
public InputStream getBatchResultStream(String jobId, String batchId) throws AsyncApiException {
try {
String endpoint = String.valueOf(getRestEndpoint()) + "job/" + jobId + "/batch/" + batchId + "/result";
URL url = new URL(endpoint);
return doHttpGet(url);
} catch (IOException e) {
throw new AsyncApiException("Failed to get result ", AsyncExceptionCode.ClientInputError, e);
}
}
public URL buildBatchResultURL(String jobId, String batchId) throws AsyncApiException {
try {
return new URL(String.valueOf(getRestEndpoint()) + "job/" + jobId + "/batch/" + batchId + "/result");
} catch (MalformedURLException e) {
throw new AsyncApiException("Failed to construct URL for getting batch results: " + e.getMessage(),
AsyncExceptionCode.ClientInputError, e);
}
}
public InputStream getBatchRequestInputStream(String jobId, String batchId) throws AsyncApiException {
try {
String endpoint = String.valueOf(getRestEndpoint()) + "job/" + jobId + "/batch/" + batchId + "/request";
URL url = new URL(endpoint);
return doHttpGet(url);
} catch (IOException e) {
throw new AsyncApiException("Failed to get request ", AsyncExceptionCode.ClientInputError, e);
}
}
public QueryResultList getQueryResultList(String jobId, String batchId) throws AsyncApiException {
return getQueryResultList(jobId, batchId, ContentType.XML);
}
public QueryResultList getQueryResultList(String jobId, String batchId, ContentType contentType) throws AsyncApiException {
InputStream stream = getBatchResultStream(jobId, batchId);
try {
if (contentType == ContentType.JSON || contentType == ContentType.ZIP_JSON) {
String[] results = deserializeJsonToObject(stream, (Class)String[].class);
QueryResultList list = new QueryResultList();
list.setResult(results);
return list;
}
XmlInputStream xin = new XmlInputStream();
xin.setInput(stream, "UTF-8");
QueryResultList result = new QueryResultList();
result.load(xin, typeMapper);
return result;
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to parse query result list ", AsyncExceptionCode.ClientInputError, e);
} catch (PullParserException e) {
throw new AsyncApiException("Failed to parse query result list ", AsyncExceptionCode.ClientInputError, e);
} catch (IOException e) {
throw new AsyncApiException("Failed to parse query result list ", AsyncExceptionCode.ClientInputError, e);
}
}
public InputStream getQueryResultStream(String jobId, String batchId, String resultId) throws AsyncApiException {
try {
return doHttpGet(buildQueryResultURL(jobId, batchId, resultId));
} catch (IOException e) {
throw new AsyncApiException("Failed to get result ", AsyncExceptionCode.ClientInputError, e);
}
}
public URL buildQueryResultURL(String jobId, String batchId, String resultId) throws AsyncApiException {
try {
return new URL(String.valueOf(getRestEndpoint()) + "job/" + jobId + "/batch/" + batchId + "/result" + "/" + resultId);
} catch (MalformedURLException e) {
throw new AsyncApiException("Failed to construct URL for getting query result: " + e.getMessage(),
AsyncExceptionCode.ClientInputError, e);
}
}
private InputStream doHttpGet(URL url) throws IOException, AsyncApiException {
InputStream in;
HttpURLConnection connection = this.config.createConnection(url, null);
SSLContext sslContext = this.config.getSslContext();
if (sslContext != null && connection instanceof HttpsURLConnection)
((HttpsURLConnection)connection).setSSLSocketFactory(sslContext.getSocketFactory());
connection.setRequestProperty("X-SFDC-Session", this.config.getSessionId());
boolean success = true;
try {
in = connection.getInputStream();
} catch (IOException e) {
success = false;
in = connection.getErrorStream();
}
String encoding = connection.getHeaderField("Content-Encoding");
if ("gzip".equals(encoding))
in = new GZIPInputStream(in);
if (this.config.isTraceMessage() || this.config.hasMessageHandlers()) {
byte[] bytes = FileUtil.toBytes(in);
in = new ByteArrayInputStream(bytes);
if (this.config.hasMessageHandlers()) {
Iterator<MessageHandler> it = this.config.getMessagerHandlers();
while (it.hasNext()) {
MessageHandler handler = it.next();
if (handler instanceof MessageHandlerWithHeaders) {
((MessageHandlerWithHeaders)handler).handleRequest(url, new byte[0], null);
((MessageHandlerWithHeaders)handler).handleResponse(url, bytes, connection.getHeaderFields());
continue;
}
handler.handleRequest(url, new byte[0]);
handler.handleResponse(url, bytes);
}
}
if (this.config.isTraceMessage()) {
this.config.getTraceStream().println(url.toExternalForm());
Map<String, List<String>> headers = connection.getHeaderFields();
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
StringBuffer sb = new StringBuffer();
List<String> values = entry.getValue();
if (values != null)
for (String v : values)
sb.append(v);
this.config.getTraceStream().println(String.valueOf(entry.getKey()) + ": " + sb.toString());
}
this.config.teeInputStream(bytes);
}
}
if (!success) {
ContentType type = null;
String contentTypeHeader = connection.getContentType();
if (contentTypeHeader != null)
if (contentTypeHeader.contains("application/xml")) {
type = ContentType.XML;
} else if (contentTypeHeader.contains("application/json")) {
type = ContentType.JSON;
}
parseAndThrowException(in, type);
}
return in;
}
public JobInfo getJobStatus(String jobId) throws AsyncApiException {
return getJobStatus(jobId, ContentType.XML);
}
public JobInfo getJobStatus(String jobId, ContentType contentType) throws AsyncApiException {
try {
String endpoint = getRestEndpoint();
endpoint = String.valueOf(endpoint) + "job/" + jobId;
URL url = new URL(endpoint);
InputStream in = doHttpGet(url);
if (contentType == ContentType.JSON || contentType == ContentType.ZIP_JSON)
return deserializeJsonToObject(in, JobInfo.class);
JobInfo result = new JobInfo();
XmlInputStream xin = new XmlInputStream();
xin.setInput(in, "UTF-8");
result.load(xin, typeMapper);
return result;
} catch (PullParserException e) {
throw new AsyncApiException("Failed to get job status ", AsyncExceptionCode.ClientInputError, e);
} catch (IOException e) {
throw new AsyncApiException("Failed to get job status ", AsyncExceptionCode.ClientInputError, e);
} catch (ConnectionException e) {
throw new AsyncApiException("Failed to get job status ", AsyncExceptionCode.ClientInputError, e);
}
}
static void serializeToJson(OutputStream out, Object value) throws IOException {
JsonGenerator generator = factory.createJsonGenerator(out);
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(CalendarCodec.getDateFormat());
mapper.writeValue(generator, value);
}
static <T> T deserializeJsonToObject(InputStream in, Class<T> tmpClass) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.setTimeZone(TimeZone.getTimeZone("GMT"));
return (T)mapper.readValue(in, tmpClass);
}
public JobInfo abortJob(String jobId) throws AsyncApiException {
JobInfo job = new JobInfo();
job.setId(jobId);
job.setState(JobStateEnum.Aborted);
return updateJob(job);
}
public JobInfo closeJob(String jobId) throws AsyncApiException {
JobInfo job = new JobInfo();
job.setId(jobId);
job.setState(JobStateEnum.Closed);
return updateJob(job);
}
public JobInfo updateJob(JobInfo job) throws AsyncApiException {
return updateJob(job, ContentType.XML);
}
public JobInfo updateJob(JobInfo job, ContentType contentType) throws AsyncApiException {
String endpoint = getRestEndpoint();
endpoint = String.valueOf(endpoint) + "job/" + job.getId();
return createOrUpdateJob(job, endpoint, contentType);
}
public ConnectorConfig getConfig() {
return this.config;
}
}