All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.centurylink.mdw.service.data.WorkflowDataAccess Maven / Gradle / Ivy

/*
 * Copyright (C) 2017 CenturyLink, 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 for the specific language governing permissions and
 * limitations under the License.
 */
package com.centurylink.mdw.service.data;

import com.centurylink.mdw.cache.VariableTypeCache;
import com.centurylink.mdw.cache.asset.PackageCache;
import com.centurylink.mdw.common.service.Query;
import com.centurylink.mdw.constant.OwnerType;
import com.centurylink.mdw.dataaccess.DataAccessException;
import com.centurylink.mdw.dataaccess.DatabaseAccess;
import com.centurylink.mdw.dataaccess.DbAccess;
import com.centurylink.mdw.dataaccess.db.CommonDataAccess;
import com.centurylink.mdw.model.asset.AssetHeader;
import com.centurylink.mdw.model.asset.AssetVersionSpec;
import com.centurylink.mdw.model.variable.VariableInstance;
import com.centurylink.mdw.model.workflow.Package;
import com.centurylink.mdw.model.workflow.Process;
import com.centurylink.mdw.model.workflow.*;
import com.centurylink.mdw.service.data.process.ProcessCache;
import com.centurylink.mdw.util.DateHelper;
import com.centurylink.mdw.util.log.ActivityLog;
import com.centurylink.mdw.util.log.ActivityLogLine;
import com.centurylink.mdw.util.log.StandardLogger;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class WorkflowDataAccess extends CommonDataAccess {

    private static final String ACTIVITY_INSTANCE_COLS = "ai.activity_instance_id, ai.activity_id,"
            + " ai.start_dt, ai.end_dt, ai.compcode, ai.status_message, ai.status_cd,"
            + " pi.process_instance_id, pi.process_id, pi.master_request_id";

    public ProcessList getProcessInstances(Query query) throws DataAccessException {
        try {
            List procInsts = new ArrayList<>();
            db.openConnection();
            long count = -1;
            String where;
            if (query.getFind() != null) {
                try {
                    // numeric value means instance id or master request id
                    long findInstId = Long.parseLong(query.getFind());
                    where = "where (pi.process_instance_id like '" + findInstId
                            + "%' or pi.master_request_id like '" + query.getFind() + "%')\n";
                }
                catch (NumberFormatException ex) {
                    // otherwise master request id
                    where = "where pi.master_request_id like '" + query.getFind() + "%'\n";
                    String[] processIds = query.getArrayFilter("processIds");
                    if (processIds != null && processIds.length > 0) {
                        where += getProcessIdsClause(processIds);
                    }
                }
            }
            else {
                where = buildProcessWhere(query);
            }
            String countSql = "select count(process_instance_id) from PROCESS_INSTANCE pi\n" + where;
            ResultSet rs = db.runSelect(countSql);
            if (rs.next())
                count = rs.getLong(1);

            String orderBy = buildProcessOrderBy(query);
            StringBuilder sql = new StringBuilder();
            if (query.getMax() != Query.MAX_ALL)
              sql.append(db.pagingQueryPrefix());
            sql.append("select ").append(PROC_INST_COLS).append(" from PROCESS_INSTANCE pi\n").append(where).append(orderBy);
            if (query.getMax() != Query.MAX_ALL)
                sql.append(db.pagingQuerySuffix(query.getStart(), query.getMax()));
            rs = db.runSelect(sql.toString());
            while (rs.next())
                procInsts.add(buildProcessInstance(rs));

            ProcessList list = new ProcessList(ProcessList.PROCESS_INSTANCES, procInsts);
            list.setTotal(count);
            list.setRetrieveDate(DatabaseAccess.getDbDate());
            return list;
        }
        catch (SQLException ex) {
            throw new DataAccessException("Failed to retrieve Processes", ex);
        }
        finally {
            db.closeConnection();
        }
    }

    public long getProcessInstanceCount(Query query) throws DataAccessException {
        try {
            db.openConnection();
            long count = -1;
            String where = buildProcessWhere(query);
            String countSql = "select count(process_instance_id) from PROCESS_INSTANCE pi\n" + where;
            ResultSet rs = db.runSelect(countSql);
            if (rs.next())
                count = rs.getLong(1);
            return count;
        }
        catch (SQLException ex) {
            throw new DataAccessException("Failed to retrieve Processes", ex);
        }
        finally {
            db.closeConnection();
        }
    }

    protected String buildProcessWhere(Query query) throws DataAccessException {
        long instanceId = query.getLongFilter("instanceId");
        if (instanceId > 0)
            return "where pi.process_instance_id = " + instanceId + "\n"; // ignore other criteria

        StringBuilder sb = new StringBuilder();
        sb.append("where 1 = 1 ");

        // masterRequestId
        String masterRequestId = query.getFilter("masterRequestId");
        if (masterRequestId != null)
            sb.append(" and pi.master_request_id = '" + masterRequestId + "'\n");

        String owner = query.getFilter("owner");
        if (owner == null) {
            // default excludes embedded subprocs - unless searching for activityInstanceId
            if (!(query.getLongFilter("activityInstanceId") > 0L))
                sb.append(" and pi.owner != '").append(OwnerType.MAIN_PROCESS_INSTANCE).append("'\n");
            if ("true".equals(query.getFilter("master")))
                sb.append(" and pi.owner NOT IN ( '").append(OwnerType.PROCESS_INSTANCE).append("' , '").append(OwnerType.ERROR).append("' )\n");
        }
        else {
            sb.append(" and pi.owner = '").append(owner).append("'");
            String ownerId = query.getFilter("ownerId");
            if (ownerId != null)
                sb.append(" and pi.owner_id = ").append(ownerId).append("\n");
        }

        // processId
        String processId = query.getFilter("processId");
        if (processId != null) {
            sb.append(" and pi.process_id = ").append(processId).append("\n");
        }
        else {
            // processIds
            String[] processIds = query.getArrayFilter("processIds");
            if (processIds != null && processIds.length > 0) {
                sb.append(getProcessIdsClause(processIds));
            }
        }

        // secondaryOwnerId
        // for async subprocess invokers, secondary_owner is null so must match that case as well
        String secondaryOwner = query.getFilter("secondaryOwner");
        if (secondaryOwner != null) {
            sb.append(" and (pi.secondary_owner is null or pi.secondary_owner = '").append(secondaryOwner).append("')\n");
        }
        long secondaryOwnerId = query.getLongFilter("secondaryOwnerId");
        if (secondaryOwnerId > 0) {
            sb.append(" and (pi.secondary_owner_id is null or pi.secondary_owner_id = ");
            sb.append(secondaryOwnerId).append(")\n");
        }

        // activityInstanceId
        long activityInstanceId = query.getLongFilter("activityInstanceId");
        if (activityInstanceId > 0) {
            sb.append(" and pi.process_instance_id in (select process_instance_id from ACTIVITY_INSTANCE where activity_instance_id =");
            sb.append(activityInstanceId).append(")\n");
        }
        // status
        String status = query.getFilter("status");
        if (status != null && !status.equals("[Any]")) {
            if (status.equals(WorkStatus.STATUSNAME_ACTIVE)) {
                sb.append(" and pi.status_cd not in (")
                  .append(WorkStatus.STATUS_COMPLETED)
                  .append(",").append(WorkStatus.STATUS_FAILED)
                  .append(",").append(WorkStatus.STATUS_CANCELLED)
                  .append(",").append(WorkStatus.STATUS_PURGE)
                  .append(")\n");
            }
            else {
                sb.append(" and pi.status_cd = ").append(WorkStatuses.getCode(status)).append("\n");
            }
        }
        // startDate
        try {
            Date startDate = query.getDateFilter("startDate");
            if (startDate != null) {
                String start = getOracleDateFormat().format(startDate);
                if (db.isMySQL())
                    sb.append(" and pi.start_dt >= STR_TO_DATE('").append(start).append("','%d-%M-%Y')\n");
                else
                    sb.append(" and pi.start_dt >= '").append(start).append("'\n");
            }
        }
        catch (ParseException ex) {
            throw new DataAccessException(ex.getMessage(), ex);
        }
        // template
        String template = query.getFilter("template");
        if (template != null)
            sb.append(" and template = '" + template + "'");
        // values
        Map values = query.getMapFilter("values");
        if (values != null) {
            for (String varName : values.keySet()) {
                String varValue = values.get(varName);
                sb.append("\n and exists (select vi.variable_inst_id from VARIABLE_INSTANCE vi ");
                sb.append(" where vi.process_inst_id = pi.process_instance_id and vi.variable_name = '").append(varName).append("'");
                sb.append(" and vi.variable_value = '").append(varValue).append("')");
            }
        }
        return sb.toString();
    }

    protected String getProcessIdsClause(String[] processIds) {
        StringBuilder sb = new StringBuilder();
        if (processIds != null && processIds.length > 0) {
            sb.append(" and pi.process_id in (");
            for (int i = 0; i < processIds.length; i++) {
                sb.append(processIds[i]);
                if (i < processIds.length - 1)
                    sb.append(",");
            }
            sb.append(")\n");
        }
        return sb.toString();
    }

    protected String buildProcessOrderBy(Query query) {
        StringBuilder sb = new StringBuilder();
        sb.append(" order by process_instance_id");
        if (query.isDescending())
            sb.append(" desc");
        sb.append("\n");
        return sb.toString();
    }

    protected String buildActivityOrderBy(Query query) {
        StringBuilder sb = new StringBuilder();
        sb.append(" order by activity_instance_id");
        if (query.isDescending())
            sb.append(" desc");
        sb.append("\n");
        return sb.toString();
    }

    /**
     * Useful for inferring process name and version without definition.
     */
    public String getLatestProcessInstanceComments(Long processId) throws DataAccessException {
        StringBuilder query = new StringBuilder();
        query.append("select process_instance_id, comments from PROCESS_INSTANCE\n");
        query.append("where process_instance_id = (select max(process_instance_id) from PROCESS_INSTANCE ");
        query.append("where process_id = ? and comments is not null)");

        try {
            db.openConnection();
            ResultSet rs = db.runSelect(query.toString(), processId);
            if (rs.next())
                return rs.getString("comments");
            else
                return null;
        }
        catch (Exception ex) {
            throw new DataAccessException(-1, ex.getMessage(), ex);
        }
        finally {
            db.closeConnection();
        }
    }

    public void addActivityLog(Long processInstanceId, Long activityInstanceId, String level, String thread, String message)
            throws DataAccessException {
        String sql = "insert into ACTIVITY_LOG" +
                "\n (process_instance_id, activity_instance_id, log_level, thread, message)" +
                "\n values (?, ?, ?, ?, ?)";
        try {
            db.openConnection();
            Object[] args = new Object[5];
            args[0] = processInstanceId;
            args[1] = activityInstanceId;
            args[2] = level;
            args[3] = thread;
            args[4] = message;
            db.runUpdate(sql, args);
            db.commit();
        }
        catch (SQLException ex) {
            throw new DataAccessException("Failed to add activity log for " + activityInstanceId + ": " + message, ex);
        }
        finally {
            db.closeConnection();
        }
    }

    public ActivityLog getActivityLog(Long activityInstanceId) throws DataAccessException {
        String sql = "select * from ACTIVITY_LOG where activity_instance_id = ? order by CREATE_DT";
        try {
            db.openConnection();
            ResultSet rs = db.runSelect(sql, activityInstanceId);
            return buildActivityLog(rs);
        }
        catch (SQLException ex) {
            throw new DataAccessException("Failed to retrieve activity log: " + activityInstanceId, ex);
        }
        finally {
            db.closeConnection();
        }
    }

    public ActivityLog getProcessLog(Long processInstanceId, Long[] activityInstanceIds) throws DataAccessException {
        StringBuilder sql = new StringBuilder("select * from ACTIVITY_LOG\nwhere activity_instance_id in (");
        Object[] args = new Object[activityInstanceIds.length];
        for (int i = 0; i < activityInstanceIds.length; i++) {
            sql.append("?");
            if (i < activityInstanceIds.length - 1)
                sql.append(", ");
            args[i] = activityInstanceIds[i];
        }
        sql.append(")\n");
        sql.append("order by activity_instance_id desc, create_dt");
        try {
            db.openConnection();
            ResultSet rs = db.runSelect(sql.toString(), args);
            return buildActivityLog(rs);
        }
        catch (SQLException ex) {
            throw new DataAccessException("Failed to retrieve process log: " + processInstanceId, ex);
        }
        finally {
            db.closeConnection();
        }
    }

    public ActivityLog getProcessLog(Long processInstanceId, boolean withActivities) throws DataAccessException {
        String sql = "select * from ACTIVITY_LOG\nwhere process_instance_id = ?\n";
        if (!withActivities)
            sql += "and activity_instance_id is null\n";
        sql += "order by CREATE_DT";
        try {
            db.openConnection();
            ResultSet rs = db.runSelect(sql, processInstanceId);
            return buildActivityLog(rs);
        }
        catch (SQLException ex) {
            throw new DataAccessException("Failed to retrieve process log: " + processInstanceId, ex);
        }
        finally {
            db.closeConnection();
        }
    }

    /**
     * Returns null if now rows.
     */
    private ActivityLog buildActivityLog(ResultSet rs) throws SQLException {
        Long processInstanceId = null;
        List logLines = new ArrayList<>();
        while (rs.next()) {
            if (processInstanceId == null)
                processInstanceId = rs.getLong("PROCESS_INSTANCE_ID");
            Long actInstId = rs.getLong("ACTIVITY_INSTANCE_ID");
            Date when = rs.getTimestamp("CREATE_DT");
            String level = rs.getString("LOG_LEVEL");
            String thread = rs.getString("THREAD");
            String message = rs.getString("MESSAGE");
            if (message != null)
                message = message.replace("\r", "");
            logLines.add(new ActivityLogLine(actInstId, when.toInstant(), StandardLogger.LogLevel.valueOf(level), thread, message));
        }

        if (processInstanceId == null) {
            return null;
        }
        else {
            ActivityLog activityLog = new ActivityLog(processInstanceId);
            activityLog.setLogLines(logLines);
            ZonedDateTime serverTime = ZonedDateTime.now();
            activityLog.setServerZoneOffset(serverTime.getOffset().getTotalSeconds());
            long dbDiffSecs = DatabaseAccess.getDbTimeDiff() / 1000;
            activityLog.setDbZoneOffset(activityLog.getServerZoneOffset() + dbDiffSecs);
            return activityLog;
        }
    }

    public ActivityInstance getActivityInstance(Long instanceId) throws DataAccessException {
        Query query = new Query();
        query.setFilter("instanceId", instanceId);
        String sql = "select " + ACTIVITY_INSTANCE_COLS + " from ACTIVITY_INSTANCE ai, PROCESS_INSTANCE pi\n"
                + "where ai.process_instance_id = pi.process_instance_id and ai.activity_instance_id = ?";
        try (DbAccess dbAccess = new DbAccess()) {
            ResultSet rs = dbAccess.runSelect(sql, instanceId);
            if (rs.next())
                return buildActivityInstance(rs);
            else
                return null;
        } catch (SQLException | IOException ex) {
            throw new DataAccessException("Error retrieving activity instance: " + instanceId, ex);
        }
    }

    /**
     * Get latest activity instance for process instance and id.
     */
    public ActivityInstance getActivityInstance(Long processInstanceId, Long activityId) throws DataAccessException {

        String sql = "select ACTIVITY_INSTANCE_ID, STATUS_CD, START_DT, END_DT, STATUS_MESSAGE, ACTIVITY_ID, PROCESS_INSTANCE_ID"
                + " from ACTIVITY_INSTANCE where PROCESS_INSTANCE_ID = ? and ACTIVITY_ID = ? order by ACTIVITY_INSTANCE_ID desc";

        try (DbAccess dbAccess = new DbAccess()) {
            ResultSet rs = dbAccess.runSelect(sql, processInstanceId, activityId);
            if (rs.next()) {
                ActivityInstance activityInstance = new ActivityInstance();
                activityInstance.setId(rs.getLong("ACTIVITY_INSTANCE_ID"));
                activityInstance.setStatusCode(rs.getInt("STATUS_CD"));
                activityInstance.setStartDate(rs.getTimestamp("START_DT"));
                activityInstance.setEndDate(rs.getTimestamp("END_DT"));
                activityInstance.setMessage(rs.getString("STATUS_MESSAGE"));
                activityInstance.setActivityId(rs.getLong("ACTIVITY_ID"));
                activityInstance.setProcessInstanceId(rs.getLong("PROCESS_INSTANCE_ID"));
                return activityInstance;
            } else {
                return null;
            }
        }
        catch (SQLException ex) {
            throw new DataAccessException("Error retrieving milestone for pi=" + processInstanceId + ", a=" + activityId, ex);
        }
    }

    public ActivityList getActivityInstances(Query query) throws DataAccessException {
        try {
            List actInsts = new ArrayList<>();
            db.openConnection();
            long count = -1;
            String where = buildActivityWhere(query);
            String countSql = "select count(activity_instance_id) from ACTIVITY_INSTANCE ai, PROCESS_INSTANCE pi\n" + where;
            ResultSet rs = db.runSelect(countSql);
            if (rs.next())
                count = rs.getLong(1);

            String orderBy = buildActivityOrderBy(query);
            StringBuilder sql = new StringBuilder();
            if (query.getMax() != Query.MAX_ALL)
                sql.append(db.pagingQueryPrefix());
            sql.append("select " + ACTIVITY_INSTANCE_COLS + "\nfrom ACTIVITY_INSTANCE ai, PROCESS_INSTANCE pi\n");
            sql.append(where).append(orderBy);
            if (query.getMax() != Query.MAX_ALL)
                sql.append(db.pagingQuerySuffix(query.getStart(), query.getMax()));
            rs = db.runSelect(sql.toString());
            while (rs.next())
                actInsts.add(buildActivityInstance(rs));

            ActivityList list = new ActivityList(ActivityList.ACTIVITY_INSTANCES, actInsts);
            list.setTotal(count);
            list.setRetrieveDate(DatabaseAccess.getDbDate());
            return list;
        }
        catch (SQLException | IOException ex) {
            throw new DataAccessException("Failed to retrieve activities", ex);
        }
        finally {
            db.closeConnection();
        }
    }

    protected String buildActivityWhere(Query query) throws DataAccessException {
        long instanceId = query.getLongFilter("instanceId");
        if (instanceId > 0)
            return "where ai.activity_instance_id = " + instanceId + "\n"; // ignore other criteria

        StringBuilder sb = new StringBuilder();
        sb.append("where ai.process_instance_id = pi.process_instance_id");

        // masterRequestId
        String masterRequestId = query.getFilter("masterRequestId");
        if (masterRequestId != null)
            sb.append(" and pi.master_request_id = '" + masterRequestId + "'\n");

        // status
        String status = query.getFilter("status");
        if (status != null && !status.equals("[Any]")) {
            if (status.equals("[Stuck]")) {
                sb.append(" and ai.status_cd in (")
                        .append(WorkStatus.STATUS_IN_PROGRESS)
                        .append(",").append(WorkStatus.STATUS_FAILED)
                        .append(",").append(WorkStatus.STATUS_WAITING)
                        .append(")\n");
            }
            else {
                sb.append(" and ai.status_cd = ").append(WorkStatuses.getCode(status)).append("\n");
            }
        }
        // startDate
        try {
            Date startDate = query.getDateFilter("startDate");
            if (startDate != null) {
                String start = getOracleDateFormat().format(startDate);
                if (db.isMySQL())
                    sb.append(" and ai.start_dt >= STR_TO_DATE('").append(start).append("','%d-%M-%Y')\n");
                else
                    sb.append(" and ai.start_dt >= '").append(start).append("'\n");
            }
        }
        catch (ParseException ex) {
            throw new DataAccessException(ex.getMessage(), ex);
        }

        // activity => :A
        String activity = query.getFilter("activity");
        if (activity != null) {
            if (db.isOracle()) {
                sb.append(" and (pi.PROCESS_ID || ':A' || ai.ACTIVITY_ID) = '" + activity + "'");
            }
            else {
                sb.append(" and CONCAT(pi.PROCESS_ID, ':A', ai.ACTIVITY_ID) = '" + activity + "'");
            }
        }

        return sb.toString();
    }

    public ActivityInstance buildActivityInstance(ResultSet rs) throws SQLException, IOException {
        ActivityInstance ai = new ActivityInstance();
        ai.setId(rs.getLong("activity_instance_id"));
        ai.setActivityId(rs.getLong("activity_id"));
        ai.setDefinitionId("A" + ai.getActivityId());
        ai.setStartDate(rs.getTimestamp("start_dt"));
        ai.setEndDate(rs.getTimestamp("end_dt"));
        ai.setResult(rs.getString("compcode"));
        ai.setMessage(rs.getString("status_message"));
        ai.setStatusCode(rs.getInt("status_cd"));
        ai.setStatus(WorkStatuses.getName(ai.getStatusCode()));
        ai.setProcessInstanceId(rs.getLong("process_instance_id"));
        ai.setProcessId(rs.getLong("process_id"));
        ai.setMasterRequestId(rs.getString("master_request_id"));
        Process process = ProcessCache.getProcess(ai.getProcessId());
        if (process != null) {
            ai.setProcessName(process.getName());
            ai.setProcessVersion(process.getVersionString());
            Package pkg = PackageCache.getPackage(process.getPackageName());
            if (pkg != null)
                ai.setPackageName(pkg.getName());
        }
        return ai;
    }

    /**
     * For VCS-defined processes, relies on comment having been set.
     * Also sets status name from code.
     */
    protected void populateNameVersionStatus(ProcessInstance processInstance) throws DataAccessException {
        if (processInstance.getComment() != null) {
            AssetVersionSpec spec = AssetVersionSpec.parse(processInstance.getComment());
            processInstance.setProcessName(spec.getName());
            processInstance.setProcessVersion(spec.getVersion());
            String pkgNameVer = spec.getPackageName();
            if (pkgNameVer != null) {
                int spaceV = pkgNameVer.indexOf(" v");
                if (spaceV > 0 && pkgNameVer.length() > spaceV + 2)
                    processInstance.setPackageName(pkgNameVer.substring(0, spaceV));
                else
                    processInstance.setPackageName(spec.getPackageName());
            }

        }
        if (processInstance.getStatusCode() != null) {
            processInstance.setStatus(WorkStatuses.getName(processInstance.getStatusCode()));
        }
    }

    protected List getProcessInstancesForOwner(String ownerType, Long ownerId) throws SQLException, DataAccessException {
        List instanceList = null;
        String query = "select pi.PROCESS_INSTANCE_ID, pi.PROCESS_ID, pi.MASTER_REQUEST_ID," +
                " pi.STATUS_CD, pi.START_DT, pi.END_DT, pi.COMPCODE, pi.COMMENTS, pi.SECONDARY_OWNER, pi.SECONDARY_OWNER_ID" +
                " from PROCESS_INSTANCE pi" +
                " where pi.OWNER = '" + ownerType + "' and pi.OWNER_ID = ? order by pi.PROCESS_INSTANCE_ID";
        ResultSet rs = db.runSelect(query, ownerId);
        while (rs.next()) {
            if (instanceList == null)
                instanceList = new ArrayList<>();
            Long processId = rs.getLong("PROCESS_ID");
            String comment = rs.getString("COMMENTS");
            ProcessInstance pi = new ProcessInstance(processId, "");
            pi.setId(rs.getLong("PROCESS_INSTANCE_ID"));
            pi.setOwner(ownerType);
            pi.setOwnerId(ownerId);
            pi.setMasterRequestId(rs.getString("MASTER_REQUEST_ID"));
            pi.setStatusCode(rs.getInt("STATUS_CD"));
            pi.setStartDate(DateHelper.dateToString(rs.getTimestamp("START_DT")));
            pi.setEndDate(DateHelper.dateToString(rs.getTimestamp("END_DT")));
            pi.setCompletionCode(rs.getString("COMPCODE"));
            pi.setComment(comment);
            pi.setSecondaryOwner(rs.getString("SECONDARY_OWNER"));
            pi.setSecondaryOwnerId(rs.getLong("SECONDARY_OWNER_ID"));
            populateNameVersionStatus(pi);
            instanceList.add(pi);
        }

        return instanceList;
    }

    public ProcessInstance getProcessInstance(Long instanceId) throws DataAccessException {
        try {
            String q = "select PROCESS_INSTANCE_ID from PROCESS_INSTANCE where PROCESS_INSTANCE_ID=?";
            db.openConnection();
            ResultSet rs = db.runSelect(q, instanceId);
            if (!rs.next())
                return null;
            return getProcessInstanceAll(instanceId);
        } catch (SQLException ex) {
            throw new DataAccessException(0, "Failed to process instance: " + instanceId, ex);
        } finally {
            db.closeConnection();
        }
    }

    public ProcessInstance getProcessInstanceAll(Long procInstId)
            throws DataAccessException {
        try {
            db.openConnection();
            ProcessInstance procInstInfo = this.getProcessInstanceBase0(procInstId);
            List actInstList = new ArrayList();
            String query = "select ACTIVITY_INSTANCE_ID,STATUS_CD,START_DT,END_DT," +
                    "    STATUS_MESSAGE,ACTIVITY_ID,COMPCODE" +
                    " from ACTIVITY_INSTANCE where PROCESS_INSTANCE_ID=?" +
                    " order by ACTIVITY_INSTANCE_ID";
            ResultSet rs = db.runSelect(query, procInstId);
            ActivityInstance actInst;
            while (rs.next()) {
                actInst = new ActivityInstance();
                actInst.setId(new Long(rs.getLong(1)));
                actInst.setStatusCode(rs.getInt(2));
                actInst.setStartDate(rs.getTimestamp(3));
                actInst.setEndDate(rs.getTimestamp(4));
                actInst.setMessage(rs.getString(5));
                actInst.setActivityId(new Long(rs.getLong(6)));
                actInst.setCompletionCode(rs.getString(7));
                actInstList.add(actInst);
            }
            procInstInfo.setActivities(actInstList);
            List workTransInstanceList
                    = new ArrayList();
            query = "select WORK_TRANS_INST_ID,STATUS_CD,START_DT,END_DT,WORK_TRANS_ID" +
                    " from WORK_TRANSITION_INSTANCE" +
                    " where PROCESS_INST_ID=? order by WORK_TRANS_INST_ID";
            rs = db.runSelect(query, procInstId);
            TransitionInstance workTransInstance;
            while (rs.next()) {
                workTransInstance = new TransitionInstance();
                workTransInstance.setTransitionInstanceID(rs.getLong(1));
                workTransInstance.setProcessInstanceID(procInstId);
                workTransInstance.setStatusCode(rs.getInt(2));
                workTransInstance.setStartDate(DateHelper.dateToString(rs.getTimestamp(3)));
                workTransInstance.setEndDate(DateHelper.dateToString(rs.getTimestamp(4)));
                workTransInstance.setTransitionID(rs.getLong(5));
                workTransInstanceList.add(workTransInstance);
            }
            procInstInfo.setTransitions(workTransInstanceList);
            List variableDataList = new ArrayList();
            query = "select VARIABLE_INST_ID, VARIABLE_ID, VARIABLE_VALUE, VARIABLE_NAME, VARIABLE_TYPE_ID, VARIABLE_TYPE " +
                    "from VARIABLE_INSTANCE where PROCESS_INST_ID=? order by lower(VARIABLE_NAME)";
            rs = db.runSelect(query, procInstId);
            while (rs.next()) {
                VariableInstance variableInstance = new VariableInstance();
                variableInstance.setId(rs.getLong(1));
                variableInstance.setVariableId(rs.getLong(2));
                variableInstance.setStringValue(rs.getString(3));
                variableInstance.setName(rs.getString(4));
                String variableType = rs.getString(6);
                if (variableType == null || variableType.isEmpty())
                    variableType = VariableTypeCache.getVariableType(rs.getInt(5)).getName();
                variableInstance.setType(variableType);
                variableDataList.add(variableInstance);
            }
            procInstInfo.setVariables(variableDataList);
            return procInstInfo;
        } catch (Exception e) {
            throw new DataAccessException(0,"failed to load process instance runtime info", e);
        } finally {
            db.closeConnection();
        }
    }

    public ProcessInstance getProcessInstanceBase(Long procInstId) throws DataAccessException {
        try {
            db.openConnection();
            return getProcessInstanceBase0(procInstId);
        } catch (Exception e) {
            throw new DataAccessException(0, "failed to process instance", e);
        } finally {
            db.closeConnection();
        }
    }

    public ProcessList getProcessInstanceList(Map criteria, int pageIndex, int pageSize, String orderBy) throws DataAccessException {
        try {
            db.openConnection();

            // count query
            Long count;
            String query = buildCountQuery(criteria);
            ResultSet rs = db.runSelect(query);
            if (rs.next())
                count = new Long(rs.getLong(1));
            else
                count = new Long(-1);

            // instances query
            if (orderBy == null)
                orderBy = " ORDER BY PROCESS_INSTANCE_ID DESC\n";
            int startIndex = pageSize == Query.MAX_ALL ? Query.MAX_ALL : (pageIndex - 1) * pageSize;
            int endIndex = startIndex + pageSize;
            query = buildQuery(criteria, startIndex, endIndex, orderBy);

            rs = db.runSelect(query);
            List mdwProcessInstanceList = new ArrayList();
            while (rs.next()) {
                ProcessInstance pi = new ProcessInstance(rs.getLong(8), rs.getString(9));
                pi.setOwner(rs.getString(6));
                pi.setOwnerId(rs.getLong(7));
                pi.setMasterRequestId(rs.getString(2));
                pi.setStatusCode(rs.getInt(3));
                pi.setStartDate(DateHelper.dateToString(rs.getTimestamp(4)));
                pi.setId(rs.getLong(1));
                pi.setComment(rs.getString(10));
                pi.setEndDate(DateHelper.dateToString(rs.getTimestamp(5)));
                mdwProcessInstanceList.add(pi);
            }

            ProcessList processList = new ProcessList(ProcessList.PROCESS_INSTANCES, mdwProcessInstanceList);
            processList.setRetrieveDate(DatabaseAccess.getDbDate());
            processList.setCount(mdwProcessInstanceList.size());
            processList.setTotal(count);
            for (ProcessInstance process : processList.getItems())
                populateNameVersionStatus(process);
            return processList;
        } catch (Exception e) {
            throw new DataAccessException(0,"error to load child process instance list", e);
        } finally {
            db.closeConnection();
        }
    }

    public ProcessList getProcessInstanceList(Map criteria, Map variables, int pageIndex, int pageSize, String orderBy)
            throws DataAccessException {
        ProcessList procList = getProcessInstanceList(criteria, null, variables, pageIndex, pageSize, orderBy);
        for (ProcessInstance process : procList.getItems())
            populateNameVersionStatus(process);
        return procList;
    }

    public ProcessList getProcessInstanceList(
            Map criteria, List variableNames, Map variables,
            int pageIndex, int pageSize, String orderBy) throws DataAccessException {

        if ((variableNames == null || variableNames.isEmpty()) && (variables == null || variables.isEmpty()))
            return getProcessInstanceList(criteria, pageIndex, pageSize, orderBy);

        try {
            db.openConnection();

            String query = buildCountQuery(criteria, variables);
            ResultSet rs = db.runSelect(query);
            Long count;
            if (rs.next())
                count = new Long(rs.getLong(1));
            else
                count = new Long(-1);

            if (orderBy == null)
                orderBy = " ORDER BY PROCESS_INSTANCE_ID DESC\n";
            int startIndex = pageSize == Query.MAX_ALL ? Query.MAX_ALL : (pageIndex - 1) * pageSize;
            int endIndex = startIndex + pageSize;
            query = buildQuery(criteria, variableNames, variables, startIndex, endIndex, orderBy);

            rs = db.runSelect(query);
            List mdwProcessInstanceList = new ArrayList();
            while (rs.next()) {
                ProcessInstance pi = new ProcessInstance(rs.getLong(8), rs.getString(9));
                pi.setOwner(rs.getString(6));
                pi.setOwnerId(rs.getLong(7));
                pi.setMasterRequestId(rs.getString(2));
                pi.setStatusCode(rs.getInt(3));
                pi.setStartDate(DateHelper.dateToString(rs.getTimestamp(4)));
                pi.setId(rs.getLong(1));
                pi.setComment(rs.getString(10));
                pi.setEndDate(DateHelper.dateToString(rs.getTimestamp(5)));
                if (variableNames != null && variableNames.size() > 0) {
                    List vars = new ArrayList();
                    for (String varName : variableNames) {
                        String name = varName.startsWith("DATE:") ? varName.substring(5) : varName;
                        String varVal = rs.getString(name.toUpperCase());
                        VariableInstance varInstInfo = new VariableInstance();
                        varInstInfo.setName(name);
                        varInstInfo.setStringValue(varVal);
                        vars.add(varInstInfo);
                    }
                    pi.setVariables(vars);
                }
                mdwProcessInstanceList.add(pi);
            }
            ProcessList procList = new ProcessList(ProcessList.PROCESS_INSTANCES, mdwProcessInstanceList);
            procList.setRetrieveDate(DatabaseAccess.getDbDate());
            procList.setCount(mdwProcessInstanceList.size());
            procList.setTotal(count);
            return procList;
        }
        catch (Exception e) {
            throw new DataAccessException(-1, "Error loading process instance list", e);
        }
        finally {
            db.closeConnection();
        }
    }

    protected String buildCountQuery(Map criteria, Map variablesCriteria) {
        if (variablesCriteria == null || variablesCriteria.isEmpty())
            return buildCountQuery(criteria);

        StringBuffer sqlBuff = new StringBuffer();
        sqlBuff.append("select count(pi2.process_instance_id)\n");
        sqlBuff.append("from (\n");
        sqlBuff.append(" select pi.*\n");
        sqlBuff.append(buildVariablesClause(criteria, null, variablesCriteria));
        sqlBuff.append(") pi2");
        return sqlBuff.toString();
    }

    protected String buildQuery(Map criteria, List variables, Map variableCriteria, int startIndex, int endIndex, String orderBy) {
        StringBuffer sqlBuff = new StringBuffer();
        if (startIndex != Query.MAX_ALL)
            sqlBuff.append(db.pagingQueryPrefix());
        sqlBuff.append("select pis.process_instance_id, pis.master_request_id, pis.status_cd, pis.start_dt, pis.end_dt, ")
                .append("pis.owner, pis.owner_id, pis.process_id, '' as process_name, pis.comments");
        if (variables != null && variables.size() > 0) {
            for (String varName : variables)
                sqlBuff.append(", ").append(varName.startsWith("DATE:") ? varName.substring(5) : varName);
        }
        sqlBuff.append("\n    from (\n");
        sqlBuff.append("  select pi.* ");
        sqlBuff.append(buildVariablesSelect(variables));
        sqlBuff.append(buildVariablesClause(criteria, variables, variableCriteria));
        sqlBuff.append(") pis\n");
        if (orderBy != null)
            sqlBuff.append("\n").append(orderBy);
        if (startIndex != Query.MAX_ALL)
            sqlBuff.append(db.pagingQuerySuffix(startIndex, endIndex-startIndex));
        return sqlBuff.toString();
    }

    protected String buildVariablesClause(Map criteria, List variables, Map variableCriteria) {
        StringBuffer sqlBuff = new StringBuffer();
        sqlBuff.append(" from PROCESS_INSTANCE pi\n");
        sqlBuff.append(" where pi.process_id > 0\n"); // since common starts with AND
        buildQueryCommon(sqlBuff, criteria, null);
        if (variableCriteria != null) {
            for (String varName : variableCriteria.keySet()) {
                String varValue = variableCriteria.get(varName);
                boolean isDate = varName.startsWith("DATE:");
                String variableType = null;
                if (isDate) {
                    varName = varName.substring(5);
                    variableType = "java.util.Date";
                }

                sqlBuff.append("\n and exists (select vi.variable_inst_id from VARIABLE_INSTANCE vi")
                        .append(" where vi.process_inst_id = pi.process_instance_id")
                        .append(" and vi.variable_name = '" + varName + "'");

                if (isDate) {
                    sqlBuff.append(" and vi.VARIABLE_TYPE = '" + variableType + "'"); // date var type
                    if (db.isMySQL())
                        sqlBuff.append("\n and (select concat(substr(ivi.VARIABLE_VALUE, 5, 7), substr(ivi.VARIABLE_VALUE, 25))");
                    else
                        sqlBuff.append("\n and (select substr(ivi.VARIABLE_VALUE, 5, 7) || substr(ivi.VARIABLE_VALUE, 25)");
                    sqlBuff.append("\n     from VARIABLE_INSTANCE ivi  where ivi.variable_type = '" + variableType + "'");
                    sqlBuff.append("\n     and ivi.variable_inst_id = vi.variable_inst_id");
                    sqlBuff.append("\n     and ivi.variable_name = '" + varName + "') = '"+ varValue + "') ");
                }
                else {
                    if (varValue != null && ((varValue.trim().toLowerCase().startsWith("like ") && varValue.indexOf('%') >=0 )
                            || (varValue.trim().toLowerCase().startsWith("in ") && varValue.indexOf('(') >=0)))
                        sqlBuff.append(" and vi.VARIABLE_VALUE " + varValue + ") ");
                    else
                        sqlBuff.append(" and vi.VARIABLE_VALUE = '" + varValue + "') ");
                }
            }
        }
        return sqlBuff.toString();
    }

    protected String buildQuery(Map criteria, int startIndex, int endIndex, String orderBy) {
        StringBuffer sqlBuff = new StringBuffer();
        if (startIndex != Query.MAX_ALL)
            sqlBuff.append(db.pagingQueryPrefix());
        sqlBuff.append("SELECT ");
        if (startIndex != Query.MAX_ALL)
            sqlBuff.append("/*+ NO_USE_NL(pi r) */ ");
        sqlBuff.append("pi.PROCESS_INSTANCE_ID, pi.MASTER_REQUEST_ID, pi.STATUS_CD, pi.START_DT, ");
        sqlBuff.append("pi.END_DT, pi.OWNER, pi.OWNER_ID, pi.PROCESS_ID, '' as NAME, pi.COMMENTS\n");
        sqlBuff.append("FROM PROCESS_INSTANCE pi\n");
        sqlBuff.append("where 1=1 ");
        if (!OwnerType.MAIN_PROCESS_INSTANCE.equals(criteria.get("owner")))
            sqlBuff.append(" and pi.OWNER!='" + OwnerType.MAIN_PROCESS_INSTANCE +"' ");
        buildQueryCommon(sqlBuff, criteria, orderBy);
        if (startIndex != Query.MAX_ALL)
            sqlBuff.append(db.pagingQuerySuffix(startIndex, endIndex-startIndex));
        return sqlBuff.toString();
    }

    protected String buildProcessNameClause(String qualifiedName) {
        int slash = qualifiedName.indexOf('/');
        String pkg = qualifiedName.substring(0, slash);
        String proc = qualifiedName.substring(slash + 1);
        return " AND (pi.COMMENTS like '" + pkg + " v%/" + proc + " v%'"
                + " OR pi.COMMENTS like '" + pkg + "/" + proc + " v%')";

    }

    protected ProcessInstance getProcessInstanceBase0(Long processInstanceId) throws SQLException, DataAccessException {
        String query = "select PROCESS_ID, OWNER, OWNER_ID, MASTER_REQUEST_ID, " +
                "STATUS_CD, START_DT, END_DT, COMPCODE, COMMENTS, TEMPLATE, SECONDARY_OWNER, SECONDARY_OWNER_ID\n" +
                "from PROCESS_INSTANCE where PROCESS_INSTANCE_ID = ?";
        ResultSet rs = db.runSelect(query, processInstanceId);
        if (!rs.next())
            throw new SQLException("Cannot find process instance ID: " + processInstanceId);
        ProcessInstance pi = new ProcessInstance(rs.getLong("PROCESS_ID"), "");
        pi.setId(processInstanceId);
        pi.setOwner(rs.getString("OWNER"));
        pi.setOwnerId(rs.getLong("OWNER_ID"));
        pi.setMasterRequestId(rs.getString("MASTER_REQUEST_ID"));
        pi.setStatusCode(rs.getInt("STATUS_CD"));
        pi.setStartDate(DateHelper.dateToString(rs.getTimestamp("START_DT")));
        pi.setEndDate(DateHelper.dateToString(rs.getTimestamp("END_DT")));
        pi.setCompletionCode(rs.getString("COMPCODE"));
        pi.setComment(rs.getString("COMMENTS"));
        pi.setTemplate(rs.getString("TEMPLATE"));
        if (pi.getTemplate() != null) {
            AssetHeader templateHeader = new AssetHeader(pi.getTemplate());
            pi.setTemplate(templateHeader.getName());
            pi.setTemplatePackage(templateHeader.getPackageName());
            pi.setTemplateVersion(templateHeader.getVersion());
        }
        pi.setSecondaryOwner(rs.getString("SECONDARY_OWNER"));
        if (pi.getSecondaryOwner() != null)
            pi.setSecondaryOwnerId(rs.getLong("SECONDARY_OWNER_ID"));
        populateNameVersionStatus(pi);
        return pi;
    }

    public Linked getProcessInstanceCallHierarchy(Long processInstanceId) throws DataAccessException {
        try {
            db.openConnection();
            ProcessInstance startingInstance = getProcessInstanceBase0(processInstanceId);
            Linked startingLinked = new Linked<>(startingInstance);
            Linked top = startingLinked;
            // callers
            while (OwnerType.PROCESS_INSTANCE.equals(top.get().getOwner())) {
                ProcessInstance caller = getProcessInstanceBase0(top.get().getOwnerId());
                Linked callerLinked = new Linked<>(caller);
                top.setParent(callerLinked);
                callerLinked.getChildren().add(top);
                top = callerLinked;
            }
            // called
            addCalledHierarchy(startingLinked);
            return top;
        } catch (Exception ex) {
            throw new DataAccessException(-1, ex.getMessage(), ex);
        } finally {
            db.closeConnection();
        }
    }

    private void addCalledHierarchy(Linked caller) throws SQLException, DataAccessException {
        ProcessInstance callerProcInst = caller.get();
        List calledInsts = getProcessInstancesForOwner(OwnerType.PROCESS_INSTANCE, callerProcInst.getId());
        if (calledInsts != null) {
            for (ProcessInstance calledInst : calledInsts) {
                Linked child = new Linked<>(calledInst);
                child.setParent(caller);
                caller.getChildren().add(child);
                addCalledHierarchy(child);
            }
        }
    }

    protected String buildCountQuery(Map pMap) {
        StringBuffer sqlBuff = new StringBuffer();
        sqlBuff.append("SELECT count(pi.process_instance_id) ");
        sqlBuff.append("FROM PROCESS_INSTANCE pi ");
        sqlBuff.append("WHERE pi.PROCESS_ID is not null "); // just to allow next condition to have "and"
        buildQueryCommon(sqlBuff, pMap, null);
        return sqlBuff.toString();
    }

    public String buildVariablesSelect(List variables) {
        StringBuffer buff = new StringBuffer();
        if (variables != null && variables.size() > 0) {
            for (String varName : variables) {
                String name = varName.startsWith("DATE:") ? varName.substring(5) : varName;
                buff.append(",\n");
                buff.append("    (select vi.VARIABLE_VALUE from VARIABLE_INSTANCE vi "
                        + " where pi.PROCESS_INSTANCE_ID = vi.PROCESS_INST_ID "
                        + " and vi.variable_name = '" + name + "') " + name);
            }
        }
        return buff.toString();
    }

    protected void buildQueryCommon(StringBuffer sqlBuff, Map pMap, String orderBy) {

        String wildcardStr = "";
        if (pMap.containsKey("processName")) {
            sqlBuff.append(buildProcessNameClause(pMap.get("processName")));
        }
        if (pMap.containsKey("processId")){
            sqlBuff.append(" AND pi.PROCESS_ID = "+new Long((String)pMap.get("processId")));
        }
        if (pMap.containsKey("processIdList")){
            sqlBuff.append(" AND pi.PROCESS_ID in " + pMap.get("processIdList"));
        }
        if (pMap.containsKey("id")){
            sqlBuff.append(" AND pi.PROCESS_INSTANCE_ID = "+new Long((String)pMap.get("id")));
        }
        if (pMap.containsKey("ownerId")){
            sqlBuff.append(" AND pi.OWNER_ID = "+new Long((String)pMap.get("ownerId")));
        }
        if (pMap.containsKey("ownerIdList")){
            sqlBuff.append(" AND pi.OWNER_ID in " + pMap.get("ownerIdList"));
        }
        if (pMap.containsKey("owner")){
            String ownerType = pMap.get("owner");
            if (ownerType.startsWith("~")) sqlBuff.append(" AND pi.OWNER like '"+ownerType.substring(1)+"'");
            else sqlBuff.append(" AND pi.OWNER = '"+ownerType+"'");
        }
        if (pMap.containsKey("masterRequestId")){
            //AK..added on 05/12/2011..If wildcard provided and string length is >= 3, only then apply wildcard search in SQL query; else not
            wildcardStr = pMap.get("masterRequestId");
            if ( (wildcardStr.contains("%")) && (wildcardStr.length() >=3) )
            {
                sqlBuff.append(" AND pi.MASTER_REQUEST_ID LIKE '" + wildcardStr + "'");
            }
            else
            {
                sqlBuff.append(" AND pi.MASTER_REQUEST_ID = '" + wildcardStr + "'");
            }
        }
        if (pMap.containsKey("masterRequestIdIgnoreCase")){
            //AK..added on 05/12/2011..If wildcard provided and string length is >= 3, only then apply wildcard search in SQL query; else not
            wildcardStr = pMap.get("masterRequestIdIgnoreCase").toUpperCase();
            if ((wildcardStr.contains("%")) && (wildcardStr.length() >=3))
            {
                sqlBuff.append(" AND UPPER(pi.MASTER_REQUEST_ID) LIKE UPPER('" + wildcardStr + "')");
            }
            else
            {
                sqlBuff.append(" AND UPPER(pi.MASTER_REQUEST_ID) = UPPER('" + wildcardStr + "')");
            }
        }
        if (pMap.containsKey("statusCode")){
            sqlBuff.append(" AND pi.STATUS_CD = "+new Integer((String)pMap.get("statusCode")));
        }
        if (pMap.containsKey("statusCodeList") && !StringUtils.isBlank(pMap.get("statusCodeList"))){
            sqlBuff.append(" AND pi.STATUS_CD in (" + pMap.get("statusCodeList") + ")");
        }
        if (pMap.containsKey("startDatefrom")){
            if (db.isMySQL())
                sqlBuff.append(" AND pi.START_DT >= STR_TO_DATE('"+pMap.get("startDatefrom")+"','%d-%M-%Y')");
            else
                sqlBuff.append(" AND pi.START_DT >= '"+pMap.get("startDatefrom")+"'");
        }
        if (pMap.containsKey("startDateto")){
            if (db.isMySQL())
                sqlBuff.append(" AND pi.START_DT <= STR_TO_DATE('"+pMap.get("startDateto")+"','%d-%M-%Y')");
            else
                sqlBuff.append(" AND pi.START_DT <= '"+pMap.get("startDateto")+"'");
        }
        if (pMap.containsKey("endDatefrom")){
            if (db.isMySQL())
                sqlBuff.append(" AND pi.END_DT >= STR_TO_DATE('"+pMap.get("endDatefrom")+"','%d-%M-%Y')");
            else
                sqlBuff.append(" AND pi.END_DT >= '"+pMap.get("endDatefrom")+"'");
        }
        if (pMap.containsKey("endDateto")){
            if(db.isMySQL())
                sqlBuff.append(" AND pi.END_DT <= STR_TO_DATE('"+pMap.get("endDateto")+"','%d-%M-%Y')");
            else
                sqlBuff.append(" AND pi.END_DT <= '"+pMap.get("endDateto")+"'");
        }
        else if (pMap.containsKey("endDateTo")){
            // leave this criterion for backward compatibility, even though case is inconsistent
            sqlBuff.append(" AND pi.END_DT <= '"+pMap.get("endDateTo")+"'");
        }

        // new-style parameters
        if (pMap.containsKey("ids")) {
            sqlBuff.append(" AND pi.PROCESS_ID in (").append(pMap.get("ids")).append(")");
        }

        if (orderBy != null)
            sqlBuff.append("\n").append(orderBy);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy