/**
* Copyright 2015 Anaplan Inc.
*
* 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.md file for the specific language governing permissions and
* limitations under the License.
*/
package com.anaplan.connector.utils;
import com.anaplan.client.AnaplanAPIException;
import com.anaplan.client.Import;
import com.anaplan.client.Model;
import com.anaplan.client.ServerFile;
import com.anaplan.client.Task;
import com.anaplan.client.TaskResult;
import com.anaplan.client.TaskStatus;
import com.anaplan.connector.MulesoftAnaplanResponse;
import com.anaplan.connector.connection.AnaplanConnection;
import com.anaplan.connector.exceptions.AnaplanOperationException;
import com.google.gson.JsonSyntaxException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Iterator;
/**
* Used to import CSV data into Anaplan lists or modules.
*
* @author spondonsaha
*/
public class AnaplanImportOperation extends BaseAnaplanOperation{
private static Logger logger = LogManager.getLogger(
AnaplanImportOperation.class.getName());
public AnaplanImportOperation(AnaplanConnection apiConn) {
super(apiConn);
}
/**
* Core method to run the Import operation. Expects data as a string-ified
* CSV, parses the data based on provided column-separator and delimiter,
* creates an import action based on Model provided, writes the provided
* data to the action object, executes the action on the server and
* monitor's the status until the import completes successfully and responds
* the status (failed/succeeded) via an AnaplanResponse object.
*
* @param data Import CSV data
* @param model Model object to which to import to
* @param importId Import action ID
* @param delimiter Escape character for cell values.
* @throws AnaplanAPIException Thrown when Anaplan API operation fails or
* error is encountered when writing to
* cell data writer.
*/
private static MulesoftAnaplanResponse runImportCsv(String data,
Model model,
String importId,
String columnSeparator,
String delimiter)
throws AnaplanOperationException {
// 1. Write the provided CSV data to the data-writer.
Import imp;
try {
imp = model.getImport(importId);
} catch (AnaplanAPIException e) {
throw new AnaplanOperationException("Error fetching Import action:", e);
}
if (imp == null) {
throw new AnaplanOperationException(MessageFormat.format("Invalid " +
"import ID provided: {0}", importId));
}
ServerFile serverFile;
try {
serverFile = model.getServerFile(imp.getSourceFileId());
if (serverFile == null) {
throw new AnaplanOperationException("Could not fetch server-file!");
}
// set the column-separator and delimiter for the input
serverFile.setSeparator(columnSeparator);
serverFile.setDelimiter(delimiter);
// upload the data file as a stream
OutputStream uploadStream = serverFile.getUploadStream();
Iterator<String> iterator = AnaplanUtil.stringChunkReader(data);
byte[] dataChunk;
while (iterator.hasNext()) {
dataChunk = iterator.next().getBytes("UTF-8");
uploadStream.write(dataChunk);
}
uploadStream.close();
} catch (AnaplanAPIException | IOException e) {
throw new AnaplanOperationException("Error encountered while " +
"importing data: ", e);
}
// 2. Create the task that will import the data to the server.
Task task;
TaskStatus status;
try {
task = imp.createTask();
status = AnaplanUtil.runServerTask(task);
} catch (AnaplanAPIException e) {
throw new AnaplanOperationException("Error running Import action:", e);
}
// 3. Get task status details and fetch the row counts
String taskDetailsMsg = collectTaskLogs(status);
setRunStatusDetails(taskDetailsMsg);
logger.info(getRunStatusDetails());
// 3. Determine execution status and create response.
final TaskResult taskResult = status.getResult();
if (taskResult.isFailureDumpAvailable()) {
logger.info(UserMessages.getMessage("failureDump"));
final ServerFile failDump = taskResult.getFailureDump();
return MulesoftAnaplanResponse.importWithFailureDump(
UserMessages.getMessage("importBadData", importId),
failDump);
} else {
logger.info(UserMessages.getMessage("noFailureDump"));
if (taskResult.isSuccessful()) {
return MulesoftAnaplanResponse.importSuccess(getRunStatusDetails(),
serverFile);
} else {
return MulesoftAnaplanResponse.importFailure(getRunStatusDetails(),
null);
}
}
}
/**
* Imports a model using the provided workspace-ID, model-ID and Import-ID.
*
* @param workspaceId Anaplan Workspace ID
* @param modelId Anaplan Model ID
* @param importId Anaplan Import ID
* @throws AnaplanOperationException Internal operation exception thrown to
* capture any IOException, JsonSyntaxException or AnaplanAPIException.
*/
public String runImport(String data,
String workspaceId,
String modelId,
String importId,
String columnSeparator,
String delimiter) throws AnaplanOperationException {
logger.info("<< Starting import >>");
logger.info("Workspace-ID: {}", workspaceId);
logger.info("Model-ID: {}", modelId);
logger.info("Import-ID: {}", importId);
// validate workspace-ID and model-ID are valid, else throw exception
validateInput(workspaceId, modelId);
MulesoftAnaplanResponse anaplanResponse;
String importResponse = "";
try {
logger.info("Starting import: {}", importId);
anaplanResponse = runImportCsv(data, model, importId, columnSeparator,
delimiter);
importResponse = createResponse(anaplanResponse);
logger.info("Import complete: Status: {}, Response message: {}",
anaplanResponse.getStatus(), importResponse);
} catch (JsonSyntaxException e) {
MulesoftAnaplanResponse.responseEpicFail(apiConn, e, null);
} finally {
apiConn.closeConnection();
}
return importResponse;
}
}