nl.paston.bonita.importfile.Main.java Source code

Java tutorial

Introduction

Here is the source code for nl.paston.bonita.importfile.Main.java

Source

/*
 * Copyright (C) 2015 Paston Solutions BV
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package nl.paston.bonita.importfile;

import java.io.Console;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.lang.reflect.UndeclaredThrowableException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.bonitasoft.engine.api.ApiAccessType;
import org.bonitasoft.engine.api.LoginAPI;
import org.bonitasoft.engine.api.ProcessAPI;
import org.bonitasoft.engine.api.TenantAPIAccessor;
import org.bonitasoft.engine.bpm.contract.ContractViolationException;
import org.bonitasoft.engine.bpm.process.ProcessActivationException;
import org.bonitasoft.engine.bpm.process.ProcessDefinitionNotFoundException;
import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfo;
import org.bonitasoft.engine.bpm.process.ProcessDeploymentInfoSearchDescriptor;
import org.bonitasoft.engine.bpm.process.ProcessExecutionException;
import org.bonitasoft.engine.exception.BonitaHomeNotSetException;
import org.bonitasoft.engine.exception.SearchException;
import org.bonitasoft.engine.exception.ServerAPIException;
import org.bonitasoft.engine.exception.UnknownAPITypeException;
import org.bonitasoft.engine.platform.LoginException;
import org.bonitasoft.engine.search.Order;
import org.bonitasoft.engine.search.SearchOptions;
import org.bonitasoft.engine.search.SearchOptionsBuilder;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.engine.util.APITypeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.SimpleLogger;

/**
 *
 * @author <a href="mailto:martijnburger@paston.nl">Martijn Burger</a>
 */
public class Main {

    private static Logger log;

    private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("bonita-importfile");

    private static final int NUMBER_OF_PROCESSES = 20;

    private static final String DEFAULT_URL = BUNDLE.getString("default.url");
    private static final String DEFAULT_APPLICATION = "bonita";
    private static final String DEFAULT_USER = "walter.bates";

    protected static enum Cmd {
        SERVER_URL("serverUrl"), APPLICATION_NAME("applicationName"), USERNAME("username"), PASSWORD(
                "password"), PROCESS_NAME("processName"), PROCESS_VERSION("processVersion"), INPUT_VARIABLE(
                        "inputVariable"), CSV_FILE("csvFile"), HELP("help"), TALKATIVE("talkative"), QUIET("quiet");

        private final String name;

        Cmd(String name) {
            this.name = name;
        }

        protected String getName() {
            return name;
        }

    }

    public static void main(String[] args) {
        // Parse the commandline arguments.
        CommandLine cmd = parseArguments(args);
        log.info("Starting bonita-importfile. For help information add -h.");

        // Get input paramters for Login API
        String serverUrl = getConsoleInput("Bonita server URL", DEFAULT_URL, cmd, Cmd.SERVER_URL.getName());

        String applicationName = getConsoleInput("Bonita application name", DEFAULT_APPLICATION, cmd,
                Cmd.APPLICATION_NAME.getName());

        // Connect to Bonita server and create the Login API.
        LoginAPI loginAPI = getLoginAPI(serverUrl, applicationName);

        // Get login parameters for APISession
        String userName = getConsoleInput("Bonita user name", DEFAULT_USER, cmd, Cmd.USERNAME.getName());

        char[] password = cmd.hasOption(Cmd.PASSWORD.getName())
                ? cmd.getOptionValue(Cmd.PASSWORD.getName()).toCharArray()
                : System.console().readPassword("Bonita password: ");

        // Create an APISession and a ProcessAPI.
        APISession apiSession = getAPISession(loginAPI, userName, password);
        ProcessAPI processAPI = getProcessAPI(apiSession);

        // Get a list of processes and let the user choose the process.
        List<ProcessDeploymentInfo> processList = getProcessList(processAPI);

        ProcessDeploymentInfo processDeploymentInfo = getProcess(processList, cmd);

        // Read records from file;
        Reader in = getReader(cmd);
        Iterable<CSVRecord> records = getCSVRecords(in);

        // Parse and push records to Bonita.
        Iterator<CSVRecord> iterator = records.iterator();
        CSVRecord fullHeader = getFullHeader(iterator);
        for (CSVRecord record : records) {
            Map<String, Serializable> map = parseRecord(record, fullHeader);
            pushRecordToBonita(processAPI, processDeploymentInfo, map);
        }
        log.info("Finished bonita-importfile succesfully.");
    }

    protected static Map<String, Serializable> parseRecord(CSVRecord record, CSVRecord fullHeader) {
        if (record == null) {
            log.warn("Record is null.");
            return null;
        }
        log.info("Parsing record number: " + (record.getRecordNumber() - 1));
        log.debug(" with content: " + record.toString());
        final Map<String, Serializable> map = new HashMap<>();
        for (int i = 0; i < record.size(); i++) {
            String headerFieldType = getHeaderFieldType(fullHeader.get(i));
            Object recordField = getRecordField(headerFieldType, record.get(i));
            if (recordField != null) {
                String headerField = getHeaderField(fullHeader.get(i));
                String[] headerFieldParts = headerField.split("\\.");
                Map<String, Serializable> targetMap = map;
                for (int j = 0; j < headerFieldParts.length - 1; j++) {
                    try {
                        targetMap = (Map<String, Serializable>) targetMap.computeIfAbsent(headerFieldParts[j],
                                x -> new HashMap<>());
                    } catch (ClassCastException ex) {
                        log.debug("Problem parsing: " + headerFieldParts[j]);
                    }
                }
                String currentHeaderField = headerFieldParts[headerFieldParts.length - 1];
                Matcher listMatcher = Pattern.compile("\\[(.*)\\]").matcher(currentHeaderField);
                if (listMatcher.find()) {
                    String parametersString = listMatcher.group(1);
                    Matcher chfNameMatcher = Pattern.compile("(.*)\\[").matcher(currentHeaderField);
                    if (chfNameMatcher.find()) {
                        String chfName = chfNameMatcher.group(1);
                        String[] parameters = parametersString.split("&");
                        List<Serializable> list = (List<Serializable>) targetMap.computeIfAbsent(chfName,
                                x -> new ArrayList<>());
                        if (parametersString.isEmpty()) {
                            list.add((Serializable) recordField);
                        } else {
                            Map<String, Serializable> subMap = new HashMap<>();
                            for (String parameter : parameters) {
                                String[] parameterKeys = parameter.split("=");
                                if (parameterKeys.length == 2) {
                                    subMap.put(parameterKeys[0], parameterKeys[1]);
                                } else if (parameterKeys.length == 1) {
                                    subMap.put(parameterKeys[0], (Serializable) recordField);
                                } else {
                                    log.error("Wrong number of parameters for: " + currentHeaderField);
                                    System.exit(1);
                                }
                            }
                            list.add((Serializable) subMap);
                        }
                    }
                } else {
                    targetMap.put(currentHeaderField, (Serializable) recordField);
                }
            } else {
                log.warn("Skipped value for record item: " + record.get(i));
            }
        }
        return map;
    }

    protected static void pushRecordToBonita(ProcessAPI processAPI, ProcessDeploymentInfo info,
            Map<String, Serializable> map) {
        if (map == null) {
            log.warn("map is null.");
            return;
        }
        log.info("Pushing record to Bonita server.");
        log.debug(map.toString());
        try {
            processAPI.startProcessWithInputs(info.getProcessId(), map);
            log.debug("Succesfully pushed record.");
        } catch (ProcessDefinitionNotFoundException | ProcessActivationException | ProcessExecutionException
                | ContractViolationException ex) {
            log.error("Cannot push data to bonita. Reason: " + ex.getMessage());
            System.exit(1);
        }
    }

    protected static Object getRecordField(String headerType, String stringValue) {
        if (headerType == null) {
            log.warn("Cannot parse an based on an empty headertype.");
            return null;
        }
        switch (headerType) {
        case "BOOLEAN":
            String trueValue = BUNDLE.getString("excel.true");
            if (stringValue.equals(trueValue)) {
                return true;
            }
            String falseValue = BUNDLE.getString("excel.false");
            if (stringValue.equals(falseValue)) {
                return false;
            }
            log.warn("This is not a boolean (" + trueValue + "," + falseValue + "): " + stringValue);
            return null;
        case "DATE":
            try {
                DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
                return df.parse(stringValue);
            } catch (ParseException ex) {
                log.warn("This is not a date: " + stringValue);
                return null;
            }
        case "DOUBLE":
            try {
                return Double.parseDouble(stringValue);
            } catch (NumberFormatException ex) {
                log.warn("This is not a double: " + stringValue);
                return null;
            }
        case "FLOAT":
            try {
                return Float.parseFloat(stringValue);
            } catch (NumberFormatException ex) {
                log.warn("This is not a float: " + stringValue);
                return null;
            }
        case "INTEGER":
            try {
                return Integer.parseInt(stringValue);
            } catch (NumberFormatException ex) {
                log.warn("This is not an integer: " + stringValue);
                return null;
            }
        case "LONG":
            try {
                return Long.parseLong(stringValue);
            } catch (NumberFormatException ex) {
                log.warn("This is not a long: " + stringValue);
                return null;
            }
        case "STRING":
        case "TEXT":
            return stringValue;
        default:
            log.warn("Type not recognized from header: " + headerType);
            return null;
        }
    }

    protected static CSVRecord getFullHeader(Iterator<CSVRecord> iterator) {
        if (iterator == null) {
            log.warn("iterator is null.");
            return null;
        }
        if (iterator.hasNext()) {
            return iterator.next();
        } else {
            log.error("File is empty. Not parsing any records.");
            System.exit(1);
        }
        return null;
    }

    protected static Iterable<CSVRecord> getCSVRecords(Reader in) {
        if (in == null) {
            log.warn("in is null.");
            return null;
        }
        try {
            return CSVFormat.EXCEL.parse(in);
        } catch (IOException ex) {
            log.error("File cannot be parsed as csv.");
            System.exit(1);
        }
        return null;
    }

    protected static Reader getReader(CommandLine cmd) {
        log.debug("Reading CSV file.");
        while (cmd != null) {
            String fileName = cmd.hasOption(Cmd.CSV_FILE.getName()) ? cmd.getOptionValue(Cmd.CSV_FILE.getName())
                    : System.console().readLine("Name of the CSV File to read: ");
            String userDir = System.getProperty("user.dir");
            File file = new File(userDir + File.separatorChar + fileName);
            try {
                InputStream is = new FileInputStream(file);
                log.info("Succesfully read CSV file.");
                return new InputStreamReader(is);
            } catch (FileNotFoundException ex) {
                log.error("File cannot be found: " + file.getAbsolutePath());
                System.exit(1);
            }
        }
        return null;
    }

    protected static ProcessDeploymentInfo getProcess(List<ProcessDeploymentInfo> processList, CommandLine cmd) {
        if (cmd != null && cmd.hasOption(Cmd.PROCESS_NAME.getName())
                && cmd.hasOption(Cmd.PROCESS_VERSION.getName())) {
            for (ProcessDeploymentInfo process : processList) {
                if (process.getName().equals(cmd.getOptionValue(Cmd.PROCESS_NAME.getName()))
                        && process.getVersion().equals(cmd.getOptionValue(Cmd.PROCESS_VERSION.getName()))) {
                    return process;
                }
            }
        }
        if (processList != null) {
            for (int i = 0; i < processList.size(); i++) {
                System.out.println(
                        i + 1 + ". " + processList.get(i).getName() + " (" + processList.get(i).getVersion() + ")");
            }
            int processId = 0;
            do {
                processId = tryParse(getConsoleInput("Select process", Integer.toString(processId + 1))) - 1;
            } while (processId < 0 || processId >= processList.size());
            return processList.get(processId);
        }
        return null;
    }

    protected static List<ProcessDeploymentInfo> getProcessList(ProcessAPI processAPI) {
        log.debug("Retrieving process list.");
        SearchOptions searchOptions = new SearchOptionsBuilder(0, NUMBER_OF_PROCESSES)
                .sort(ProcessDeploymentInfoSearchDescriptor.DEPLOYMENT_DATE, Order.DESC).done();
        try {
            List<ProcessDeploymentInfo> deploymentInfoResults = null;
            if (processAPI != null) {
                deploymentInfoResults = processAPI.searchProcessDeploymentInfos(searchOptions).getResult();
            }
            log.debug("Successfully retrieved process list.");
            return deploymentInfoResults;
        } catch (SearchException ex) {
            log.error("Search process throws an exception.");
            log.error(ex.getMessage());
            System.exit(1);
        }
        return null;
    }

    protected static ProcessAPI getProcessAPI(APISession apiSession) {
        log.debug("Connecting to ProcessAPI.");
        try {
            ProcessAPI processAPI = TenantAPIAccessor.getProcessAPI(apiSession);
            log.info("Succesfully connected to ProcessAPI.");
            return processAPI;
        } catch (BonitaHomeNotSetException | ServerAPIException | UnknownAPITypeException ex) {
            log.error("Error creating the Process API.");
            System.exit(1);
        }
        return null;
    }

    protected static APISession getAPISession(LoginAPI loginAPI, String userName, char[] password) {
        log.info("Logging into server.");
        if (loginAPI == null) {
            log.warn("loginAPI is null.");
            return null;
        }
        log.debug("Logging into the bonita server.");
        try {
            APISession apiSession = loginAPI.login(userName, new String(password));
            log.info("Succesfully logged into server.");
            return apiSession;
        } catch (LoginException ex) {
            log.error("Cannot loging with credentials.");
            log.debug("Stacktrace", ex);
            System.exit(1);
        } catch (UndeclaredThrowableException ex) {
            log.error("Cannot connect to the server.");
            log.debug("Stacktrace", ex);
            System.exit(1);
        }
        return null;
    }

    protected static LoginAPI getLoginAPI(String serverUrl, String applicationName) {
        log.debug("Creating LoginAPI.");
        Map<String, String> settings = new HashMap<>();
        settings.put("server.url", serverUrl);
        settings.put("application.name", applicationName);
        APITypeManager.setAPITypeAndParams(ApiAccessType.HTTP, settings);
        try {
            LoginAPI loginAPI = TenantAPIAccessor.getLoginAPI();
            log.debug("Succesfully created LoginAPI.");
            return loginAPI;
        } catch (BonitaHomeNotSetException | ServerAPIException | UnknownAPITypeException ex) {
            log.error("Error creating the Login API");
            log.debug("Stacktrace", ex);
            System.exit(1);
        }
        return null;
    }

    protected static String getConsoleInput(String displayText, String defaultValue) {
        return getConsoleInput(displayText, defaultValue, null, null);
    }

    protected static String getConsoleInput(String displayText, String defaultValue, CommandLine cmd,
            String optionName) {
        if (cmd != null && cmd.hasOption(optionName)) {
            return cmd.getOptionValue(optionName);
        } else {
            Console console = System.console();
            String consoleInput = null;
            if (console != null) {
                consoleInput = console.readLine(displayText + " (" + defaultValue + "): ");

                if (!consoleInput.trim().isEmpty()) {
                    return consoleInput.trim();
                } else {
                    return defaultValue;
                }
            }
        }
        return defaultValue;
    }

    protected static int tryParse(Object obj) {
        Integer retVal;
        try {
            retVal = Integer.parseInt((String) obj);
        } catch (NumberFormatException nfe) {
            retVal = 0;
        }
        return retVal;
    }

    protected static String getHeaderField(String fullHeaderValue) {
        if (fullHeaderValue != null && !fullHeaderValue.isEmpty()) {
            Matcher matcher = Pattern.compile("(.*?)[\\s\\(]").matcher(fullHeaderValue);
            matcher.find();
            String header = matcher.group(1);
            if (!header.isEmpty()) {
                return header;
            } else {
                log.warn("No header value found in: " + fullHeaderValue);
                return null;
            }
        } else {
            log.warn("No or empty header received.");
            return null;
        }
    }

    protected static String getHeaderFieldType(String fullHeaderValue) {
        if (fullHeaderValue != null && !fullHeaderValue.isEmpty()) {
            Matcher matcher = Pattern.compile("\\((.*?)\\)").matcher(fullHeaderValue);
            matcher.find();
            String headerType = matcher.group(1).toUpperCase().trim();
            if (!headerType.isEmpty()) {
                return headerType;
            } else {
                log.warn("No header type found in: " + fullHeaderValue);
                return null;
            }
        } else {
            log.warn("No or empty header received.");
            return null;
        }
    }

    protected static CommandLine parseArguments(String[] args) {
        Options options = new Options();

        Option serverUrl = new Option("s", Cmd.SERVER_URL.getName(), true, "URL of the Bonita BPM Server.");
        options.addOption(serverUrl);

        Option applicationName = new Option("a", Cmd.APPLICATION_NAME.getName(), true,
                "Name of the Bonita BPM application.");
        options.addOption(applicationName);

        Option username = new Option("u", Cmd.USERNAME.getName(), true, "Username of the Bonita BPM user.");
        options.addOption(username);

        Option password = new Option("p", Cmd.PASSWORD.getName(), true, "Password of the Bonita BPM user.");
        options.addOption(password);

        Option processName = new Option("n", Cmd.PROCESS_NAME.getName(), true, "Name of the Bonita BPM Process");
        options.addOption(processName);

        Option procesVersion = new Option("v", Cmd.PROCESS_VERSION.getName(), true,
                "Version of the Bonita BPM Process");
        options.addOption(procesVersion);

        Option csvFilename = new Option("c", Cmd.CSV_FILE.getName(), true, "Filename of the CSV file.");
        options.addOption(csvFilename);

        Option help = new Option("h", Cmd.HELP.getName(), false, "Display help information.");
        options.addOption(help);

        Option talkative = new Option("t", Cmd.TALKATIVE.getName(), false, "Show talkative logging.");
        options.addOption(talkative);

        Option quiet = new Option("q", Cmd.QUIET.getName(), false, "No logging infomation in shown.");
        options.addOption(quiet);

        CommandLineParser parser = new DefaultParser();
        CommandLine commandLine = null;
        try {
            commandLine = parser.parse(options, args);
        } catch (org.apache.commons.cli.ParseException ex) {
            log.error(ex.getMessage());
        }
        if (commandLine != null && !commandLine.hasOption(Cmd.HELP.getName())) {
            if (commandLine.hasOption(Cmd.TALKATIVE.getName())) {
                System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE");
            }
            if (commandLine.hasOption(Cmd.QUIET.getName())) {
                System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "ERROR");
            }
            log = LoggerFactory.getLogger(Main.class);
            return commandLine;
        } else {
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp("bonita-importfile", options);
            System.exit(1);
        }

        return null;
    }

}