/** * 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.util.EnumSet; import java.util.Optional; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; import org.apache.camel.InvalidPayloadException; import org.apache.camel.Message; 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.composite.ReferenceId; import org.apache.camel.component.salesforce.api.dto.composite.SObjectBatch; import org.apache.camel.component.salesforce.api.dto.composite.SObjectBatchResponse; import org.apache.camel.component.salesforce.api.dto.composite.SObjectTree; import org.apache.camel.component.salesforce.api.dto.composite.SObjectTreeResponse; import org.apache.camel.component.salesforce.internal.PayloadFormat; import org.apache.camel.component.salesforce.internal.client.CompositeApiClient; import org.apache.camel.component.salesforce.internal.client.DefaultCompositeApiClient; import org.apache.camel.util.ServiceHelper; public final class CompositeApiProcessor extends AbstractSalesforceProcessor { @FunctionalInterface interface ResponseHandler<T> { void handleResponse(Exchange exchange, Optional<T> body, SalesforceException exception, AsyncCallback callback); } private final CompositeApiClient compositeClient; private final PayloadFormat format; public CompositeApiProcessor(final SalesforceEndpoint endpoint) throws SalesforceException { super(endpoint); final SalesforceEndpointConfig configuration = endpoint.getConfiguration(); final String apiVersion = configuration.getApiVersion(); format = configuration.getFormat(); if (!EnumSet.of(PayloadFormat.JSON, PayloadFormat.XML).contains(format)) { throw new SalesforceException("Unsupported format: " + format, 0); } compositeClient = new DefaultCompositeApiClient(configuration, format, apiVersion, session, httpClient); } @Override public boolean process(final Exchange exchange, final AsyncCallback callback) { try { switch (operationName) { case COMPOSITE_TREE: return processInternal(SObjectTree.class, exchange, compositeClient::submitCompositeTree, this::processCompositeTreeResponse, callback); case COMPOSITE_BATCH: return processInternal(SObjectBatch.class, exchange, compositeClient::submitCompositeBatch, this::processCompositeBatchResponse, callback); default: throw new SalesforceException("Unknown operation name: " + operationName.value(), null); } } catch (final SalesforceException e) { return processException(exchange, callback, e); } catch (final RuntimeException e) { final SalesforceException exception = new SalesforceException( String.format("Unexpected Error processing %s: \"%s\"", operationName.value(), e.getMessage()), e); return processException(exchange, callback, exception); } } @Override public void start() throws Exception { ServiceHelper.startService(compositeClient); } @Override public void stop() throws Exception { ServiceHelper.stopService(compositeClient); } void processCompositeBatchResponse(final Exchange exchange, final Optional<SObjectBatchResponse> responseBody, final SalesforceException exception, final AsyncCallback callback) { try { if (!responseBody.isPresent()) { exchange.setException(exception); } else { final Message in = exchange.getIn(); final Message out = exchange.getOut(); final SObjectBatchResponse response = responseBody.get(); out.copyFromWithNewBody(in, response); } } finally { // notify callback that exchange is done callback.done(false); } } void processCompositeTreeResponse(final Exchange exchange, final Optional<SObjectTreeResponse> responseBody, final SalesforceException exception, final AsyncCallback callback) { try { if (!responseBody.isPresent()) { exchange.setException(exception); } else { final Message in = exchange.getIn(); final Message out = exchange.getOut(); final SObjectTree tree = in.getBody(SObjectTree.class); final SObjectTreeResponse response = responseBody.get(); final boolean hasErrors = response.hasErrors(); for (final ReferenceId referenceId : response.getResults()) { tree.setIdFor(referenceId.getReferenceId(), referenceId.getId()); if (hasErrors) { tree.setErrorFor(referenceId.getReferenceId(), referenceId.getErrors()); } } if (hasErrors) { final SalesforceException withErrors = new SalesforceException(response.getAllErrors(), exception.getStatusCode(), exception); exchange.setException(withErrors); } out.copyFromWithNewBody(in, tree); } } finally { // notify callback that exchange is done callback.done(false); } } boolean processException(final Exchange exchange, final AsyncCallback callback, final Exception e) { exchange.setException(e); callback.done(true); return true; } <T, R> boolean processInternal(final Class<T> bodyType, final Exchange exchange, final CompositeApiClient.Operation<T, R> clientOperation, final ResponseHandler<R> responseHandler, final AsyncCallback callback) throws SalesforceException { final T body; final Message in = exchange.getIn(); try { body = in.getMandatoryBody(bodyType); } catch (final InvalidPayloadException e) { throw new SalesforceException(e); } clientOperation.submit(body, (response, exception) -> responseHandler.handleResponse(exchange, response, exception, callback)); return false; } }