/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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 org.apache.camel.component.salesforce.internal.processor; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.apache.camel.AsyncCallback; import org.apache.camel.CamelException; import org.apache.camel.Exchange; import org.apache.camel.InvalidPayloadException; import org.apache.camel.Message; import org.apache.camel.StreamCache; import org.apache.camel.component.salesforce.SalesforceEndpoint; import org.apache.camel.component.salesforce.SalesforceEndpointConfig; import org.apache.camel.component.salesforce.api.SalesforceException; import org.apache.camel.component.salesforce.api.dto.bulk.BatchInfo; import org.apache.camel.component.salesforce.api.dto.bulk.ContentType; import org.apache.camel.component.salesforce.api.dto.bulk.JobInfo; import org.apache.camel.component.salesforce.internal.client.BulkApiClient; import org.apache.camel.component.salesforce.internal.client.DefaultBulkApiClient; import org.apache.camel.converter.stream.StreamCacheConverter; import org.apache.camel.util.ServiceHelper; import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.BATCH_ID; import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.CONTENT_TYPE; import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.JOB_ID; import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.RESULT_ID; import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_QUERY; public class BulkApiProcessor extends AbstractSalesforceProcessor { private BulkApiClient bulkClient; public BulkApiProcessor(SalesforceEndpoint endpoint) throws SalesforceException { super(endpoint); this.bulkClient = new DefaultBulkApiClient( (String) endpointConfigMap.get(SalesforceEndpointConfig.API_VERSION), session, httpClient); } @Override public boolean process(final Exchange exchange, final AsyncCallback callback) { boolean done = false; try { switch (operationName) { case CREATE_JOB: processCreateJob(exchange, callback); break; case GET_JOB: processGetJob(exchange, callback); break; case CLOSE_JOB: processCloseJob(exchange, callback); break; case ABORT_JOB: processAbortJob(exchange, callback); break; case CREATE_BATCH: processCreateBatch(exchange, callback); break; case GET_BATCH: processGetBatch(exchange, callback); break; case GET_ALL_BATCHES: processGetAllBatches(exchange, callback); break; case GET_REQUEST: processGetRequest(exchange, callback); break; case GET_RESULTS: processGetResults(exchange, callback); break; case CREATE_BATCH_QUERY: processCreateBatchQuery(exchange, callback); break; case GET_QUERY_RESULT_IDS: processGetQueryResultIds(exchange, callback); break; case GET_QUERY_RESULT: processGetQueryResult(exchange, callback); break; default: throw new SalesforceException("Unknown operation name: " + operationName.value(), null); } } catch (SalesforceException e) { exchange.setException(new SalesforceException( String.format("Error processing %s: [%s] \"%s\"", operationName.value(), e.getStatusCode(), e.getMessage()), e)); callback.done(true); done = true; } catch (InvalidPayloadException e) { exchange.setException(new SalesforceException( String.format("Unexpected Error processing %s: \"%s\"", operationName.value(), e.getMessage()), e)); callback.done(true); done = true; } catch (RuntimeException e) { exchange.setException(new SalesforceException( String.format("Unexpected Error processing %s: \"%s\"", operationName.value(), e.getMessage()), e)); callback.done(true); done = true; } // continue routing asynchronously if false return done; } private void processCreateJob(final Exchange exchange, final AsyncCallback callback) throws InvalidPayloadException { JobInfo jobBody = exchange.getIn().getMandatoryBody(JobInfo.class); bulkClient.createJob(jobBody, new BulkApiClient.JobInfoResponseCallback() { @Override public void onResponse(JobInfo jobInfo, SalesforceException ex) { processResponse(exchange, jobInfo, ex, callback); } }); } private void processGetJob(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { JobInfo jobBody; jobBody = exchange.getIn().getBody(JobInfo.class); String jobId; if (jobBody != null) { jobId = jobBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getJob(jobId, new BulkApiClient.JobInfoResponseCallback() { @Override public void onResponse(JobInfo jobInfo, SalesforceException ex) { processResponse(exchange, jobInfo, ex, callback); } }); } private void processCloseJob(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { JobInfo jobBody; String jobId; jobBody = exchange.getIn().getBody(JobInfo.class); if (jobBody != null) { jobId = jobBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.closeJob(jobId, new BulkApiClient.JobInfoResponseCallback() { @Override public void onResponse(JobInfo jobInfo, SalesforceException ex) { processResponse(exchange, jobInfo, ex, callback); } }); } private void processAbortJob(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { JobInfo jobBody; String jobId; jobBody = exchange.getIn().getBody(JobInfo.class); if (jobBody != null) { jobId = jobBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.abortJob(jobId, new BulkApiClient.JobInfoResponseCallback() { @Override public void onResponse(JobInfo jobInfo, SalesforceException ex) { processResponse(exchange, jobInfo, ex, callback); } }); } private void processCreateBatch(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { String jobId; // since request is in the body, use headers or endpoint params ContentType contentType = ContentType.fromValue( getParameter(CONTENT_TYPE, exchange, IGNORE_BODY, NOT_OPTIONAL)); jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); InputStream request; try { request = exchange.getIn().getMandatoryBody(InputStream.class); } catch (CamelException e) { String msg = "Error preparing batch request: " + e.getMessage(); throw new SalesforceException(msg, e); } bulkClient.createBatch(request, jobId, contentType, new BulkApiClient.BatchInfoResponseCallback() { @Override public void onResponse(BatchInfo batchInfo, SalesforceException ex) { processResponse(exchange, batchInfo, ex, callback); } }); } private void processGetBatch(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { String jobId; BatchInfo batchBody = exchange.getIn().getBody(BatchInfo.class); String batchId; if (batchBody != null) { jobId = batchBody.getJobId(); batchId = batchBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getBatch(jobId, batchId, new BulkApiClient.BatchInfoResponseCallback() { @Override public void onResponse(BatchInfo batchInfo, SalesforceException ex) { processResponse(exchange, batchInfo, ex, callback); } }); } private void processGetAllBatches(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { JobInfo jobBody; String jobId; jobBody = exchange.getIn().getBody(JobInfo.class); if (jobBody != null) { jobId = jobBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getAllBatches(jobId, new BulkApiClient.BatchInfoListResponseCallback() { @Override public void onResponse(List<BatchInfo> batchInfoList, SalesforceException ex) { processResponse(exchange, batchInfoList, ex, callback); } }); } private void processGetRequest(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { String jobId; BatchInfo batchBody; String batchId; batchBody = exchange.getIn().getBody(BatchInfo.class); if (batchBody != null) { jobId = batchBody.getJobId(); batchId = batchBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getRequest(jobId, batchId, new BulkApiClient.StreamResponseCallback() { @Override public void onResponse(InputStream inputStream, SalesforceException ex) { // read the request stream into a StreamCache temp file // ensures the connection is read StreamCache body = null; if (inputStream != null) { try { body = StreamCacheConverter.convertToStreamCache(inputStream, exchange); } catch (IOException e) { String msg = "Error retrieving batch request: " + e.getMessage(); ex = new SalesforceException(msg, e); } finally { // close the input stream to release the Http connection try { inputStream.close(); } catch (IOException ignore) { } } } processResponse(exchange, body, ex, callback); } }); } private void processGetResults(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { String jobId; BatchInfo batchBody; String batchId; batchBody = exchange.getIn().getBody(BatchInfo.class); if (batchBody != null) { jobId = batchBody.getJobId(); batchId = batchBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getResults(jobId, batchId, new BulkApiClient.StreamResponseCallback() { @Override public void onResponse(InputStream inputStream, SalesforceException ex) { // read the result stream into a StreamCache temp file // ensures the connection is read StreamCache body = null; if (inputStream != null) { try { body = StreamCacheConverter.convertToStreamCache(inputStream, exchange); } catch (IOException e) { String msg = "Error retrieving batch results: " + e.getMessage(); ex = new SalesforceException(msg, e); } finally { // close the input stream to release the Http connection try { inputStream.close(); } catch (IOException ignore) { } } } processResponse(exchange, body, ex, callback); } }); } private void processCreateBatchQuery(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { JobInfo jobBody; String jobId; ContentType contentType; jobBody = exchange.getIn().getBody(JobInfo.class); String soqlQuery; if (jobBody != null) { jobId = jobBody.getId(); contentType = jobBody.getContentType(); // use SOQL query from header or endpoint config soqlQuery = getParameter(SOBJECT_QUERY, exchange, IGNORE_BODY, NOT_OPTIONAL); } else { jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); contentType = ContentType.fromValue( getParameter(CONTENT_TYPE, exchange, IGNORE_BODY, NOT_OPTIONAL)); // reuse SOBJECT_QUERY property soqlQuery = getParameter(SOBJECT_QUERY, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.createBatchQuery(jobId, soqlQuery, contentType, new BulkApiClient.BatchInfoResponseCallback() { @Override public void onResponse(BatchInfo batchInfo, SalesforceException ex) { processResponse(exchange, batchInfo, ex, callback); } }); } private void processGetQueryResultIds(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { String jobId; BatchInfo batchBody; String batchId; batchBody = exchange.getIn().getBody(BatchInfo.class); if (batchBody != null) { jobId = batchBody.getJobId(); batchId = batchBody.getId(); } else { jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); batchId = getParameter(BATCH_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getQueryResultIds(jobId, batchId, new BulkApiClient.QueryResultIdsCallback() { @Override public void onResponse(List<String> ids, SalesforceException ex) { processResponse(exchange, ids, ex, callback); } }); } private void processGetQueryResult(final Exchange exchange, final AsyncCallback callback) throws SalesforceException { String jobId; BatchInfo batchBody; String batchId; batchBody = exchange.getIn().getBody(BatchInfo.class); String resultId; if (batchBody != null) { jobId = batchBody.getJobId(); batchId = batchBody.getId(); resultId = getParameter(RESULT_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); } else { jobId = getParameter(JOB_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); batchId = getParameter(BATCH_ID, exchange, IGNORE_BODY, NOT_OPTIONAL); resultId = getParameter(RESULT_ID, exchange, USE_BODY, NOT_OPTIONAL); } bulkClient.getQueryResult(jobId, batchId, resultId, new BulkApiClient.StreamResponseCallback() { @Override public void onResponse(InputStream inputStream, SalesforceException ex) { StreamCache body = null; if (inputStream != null) { // read the result stream into a StreamCache temp file // ensures the connection is read try { body = StreamCacheConverter.convertToStreamCache(inputStream, exchange); } catch (IOException e) { String msg = "Error retrieving query result: " + e.getMessage(); ex = new SalesforceException(msg, e); } finally { // close the input stream to release the Http connection try { inputStream.close(); } catch (IOException e) { // ignore } } } processResponse(exchange, body, ex, callback); } }); } private void processResponse(Exchange exchange, Object body, SalesforceException ex, AsyncCallback callback) { final Message out = exchange.getOut(); if (ex != null) { exchange.setException(ex); } else { out.setBody(body); } // copy headers and attachments out.getHeaders().putAll(exchange.getIn().getHeaders()); out.getAttachmentObjects().putAll(exchange.getIn().getAttachmentObjects()); // signal exchange completion callback.done(false); } @Override public void start() throws Exception { ServiceHelper.startService(bulkClient); } @Override public void stop() throws Exception { // stop the client ServiceHelper.stopService(bulkClient); } }