// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed 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.google.api.ads.adwords.axis.utils.v201607.batchjob;
import com.google.api.ads.adwords.axis.utils.AxisDeserializer;
import com.google.api.ads.adwords.axis.v201607.cm.ApiError;
import com.google.api.ads.adwords.axis.v201607.cm.BatchJob;
import com.google.api.ads.adwords.axis.v201607.cm.BatchJobOpsServiceSoapBindingStub;
import com.google.api.ads.adwords.axis.v201607.cm.Operand;
import com.google.api.ads.adwords.axis.v201607.cm.Operation;
import com.google.api.ads.adwords.lib.utils.BatchJobException;
import com.google.api.ads.adwords.lib.utils.BatchJobHelperInterface;
import com.google.api.ads.adwords.lib.utils.BatchJobUploadResponse;
import com.google.api.ads.adwords.lib.utils.BatchJobUploadStatus;
import com.google.api.ads.adwords.lib.utils.BatchJobUploader;
import com.google.api.ads.adwords.lib.utils.logging.BatchJobLogger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import java.net.URI;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;
import org.apache.axis.client.Call;
import org.apache.axis.encoding.TypeMapping;
/** Utility for uploading operations and downloading results for a {@link BatchJob}. */
class BatchJobHelperImpl
implements BatchJobHelperInterface<
Operation, Operand, ApiError, MutateResult, BatchJobMutateResponse> {
private final BatchJobUploader uploader;
private final BatchJobLogger batchJobLogger;
private final QName resultQName;
@Inject
BatchJobHelperImpl(BatchJobUploader uploader, BatchJobLogger batchJobLogger) {
this.uploader = uploader;
this.batchJobLogger = batchJobLogger;
resultQName = new QName("https://adwords.google.com/api/adwords/cm/v201607", "MutateResult");
}
@Override
public BatchJobUploadResponse uploadBatchJobOperations(Iterable<Operation> operations,
String uploadUrl) throws BatchJobException {
// All uploads must go through the incremental upload workflow.
return uploadIncrementalBatchJobOperations(
operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl)));
}
@Override
public BatchJobUploadResponse uploadIncrementalBatchJobOperations(
Iterable<? extends Operation> operations, boolean isLastRequest,
BatchJobUploadStatus batchJobUploadStatus) throws BatchJobException {
BatchJobMutateRequest request = new BatchJobMutateRequest();
request.addOperations(operations);
return uploader.uploadIncrementalBatchJobOperations(
request, isLastRequest, batchJobUploadStatus);
}
@Override
public BatchJobMutateResponse downloadBatchJobMutateResponse(String downloadUrl)
throws BatchJobException {
AxisDeserializer deserializer = new AxisDeserializer();
/*
* Deserialize using the generated cm.MutateResult class instead of the batchjob.MutateResult
* class. The MutateResult and ErrorList types in the batchjob package have properties defined
* in the BatchJobMutateResultInterface and BatchJobErrorListInterface interfaces, respectively.
* On some Hotspot JVMs, if java.beans.Introspector (used by Axis) encounters a property
* defined via an implemented interface, it will return a PropertyDescriptor where
* getPropertType() returns the interface class instead of the type declared in the
* implementing class (e.g., BatchJobErrorListInterface instead of ErrorList). This causes
* problems during Axis deserialization because Axis relies on the presence of a static
* getTypeDesc method on each property it encounters.
*/
List<com.google.api.ads.adwords.axis.v201607.cm.MutateResult> cmMutateResults;
try {
cmMutateResults =
deserializer.deserializeBatchJobMutateResults(
new URL(downloadUrl),
getServiceTypeMappings(),
com.google.api.ads.adwords.axis.v201607.cm.MutateResult.class,
resultQName);
} catch (Exception e) {
batchJobLogger.logDownload(downloadUrl, null, e);
throw new BatchJobException(
"Failed to download batch job mutate response from URL: " + downloadUrl, e);
}
// Translate the cm.MutateResults into batchjob.MutateResults.
BatchJobMutateResponse response = new BatchJobMutateResponse();
List<MutateResult> mutateResults = Lists.newArrayList();
for (com.google.api.ads.adwords.axis.v201607.cm.MutateResult cmMutateResult : cmMutateResults) {
MutateResult mutateResult = new MutateResult();
mutateResult.setIndex(cmMutateResult.getIndex());
mutateResult.setOperand(cmMutateResult.getResult());
if (cmMutateResult.getErrorList() != null) {
mutateResult.setErrorList(new ErrorList());
if (cmMutateResult.getErrorList().getErrors() != null) {
mutateResult.getErrorList().setErrors(cmMutateResult.getErrorList().getErrors());
}
}
mutateResults.add(mutateResult);
}
response.setMutateResults(mutateResults.toArray(new MutateResult[mutateResults.size()]));
batchJobLogger.logDownload(downloadUrl, response, null);
return response;
}
/**
* Returns all of the service type mappings required to serialize/deserialize Axis objects.
*/
static List<TypeMapping> getServiceTypeMappings() {
// Build the list of type mappings based on BatchJobOpsService for this version of the API.
ImmutableList.Builder<TypeMapping> mappings = ImmutableList.builder();
try {
mappings.add(
new BatchJobOpsServiceSoapBindingStub() {
@Override
public Call _createCall() throws ServiceException {
try {
return super.createCall();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}._createCall().getTypeMapping());
} catch (Exception e) {
throw new RuntimeException("Failed to initialize service type mappings", e);
}
return mappings.build();
}
}