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

ru.taskurotta.service.ora.storage.OraProcessService Maven / Gradle / Ivy

package ru.taskurotta.service.ora.storage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.taskurotta.exception.ServiceCriticalException;
import ru.taskurotta.service.common.ResultSetCursor;
import ru.taskurotta.service.console.model.GenericPage;
import ru.taskurotta.service.console.model.Process;
import ru.taskurotta.service.console.retriever.ProcessInfoRetriever;
import ru.taskurotta.service.console.retriever.command.ProcessSearchCommand;
import ru.taskurotta.service.ora.tools.PagedQueryBuilder;
import ru.taskurotta.service.storage.ProcessService;
import ru.taskurotta.transport.model.TaskContainer;
import ru.taskurotta.transport.model.serialization.JsonSerializer;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * User: moroz
 * Date: 25.04.13
 */
public class OraProcessService implements ProcessService, ProcessInfoRetriever {

    private DataSource dataSource;

    private final static Logger logger = LoggerFactory.getLogger(OraProcessService.class);

    private JsonSerializer taskSerializer = new JsonSerializer<>(TaskContainer.class);

    protected static final String SQL_GET_PROCESS_CNT_BY_STATE =
            "SELECT COUNT(PROCESS_ID) AS cnt FROM PROCESS WHERE STATE = ? ";
    protected static final String SQL_FIND_INCOMPLETE_PROCESSES =
            "SELECT process_id FROM process WHERE state = ? AND start_time < ?";


    public OraProcessService(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public void finishProcess(UUID processId, String returnValue) {
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("UPDATE PROCESS SET end_time = ?, state = ?, return_value= ? WHERE process_id = ?")
        ) {
            ps.setLong(1, (new Date()).getTime());
            ps.setInt(2, Process.FINISH);
            ps.setString(3, returnValue);
            ps.setString(4, processId.toString());
            ps.executeUpdate();
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        }
    }

    @Override
    public void deleteProcess(UUID processId) {
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("DELETE FROM PROCESS WHERE process_id = ?")
        ) {
            ps.setString(1, processId.toString());
            ps.executeUpdate();
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        }
    }

    @Override
    public void startProcess(TaskContainer task) {

        logger.debug("Starting process with TaskContainer [{}]", task);

        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("INSERT INTO PROCESS (process_id, start_task_id, custom_id, start_time, state, start_json, actor_id) VALUES (?, ?, ?, ?, ?, ?, ?)")
        ) {
            ps.setString(1, task.getProcessId().toString());
            ps.setString(2, task.getTaskId().toString());
            ps.setString(3, ((task.getOptions() != null) && (task.getOptions().getTaskConfigContainer() != null)) ?
                    task.getOptions().getTaskConfigContainer().getCustomId() : null);
            ps.setLong(4, (new Date()).getTime());
            ps.setInt(5, Process.START);
            ps.setString(6, (String) taskSerializer.serialize(task));
            ps.setString(7, task.getActorId());
            ps.executeUpdate();
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        }
    }

    @Override
    public Process getProcess(UUID processUUID) {
        Process result = null;
        ResultSet rs = null;
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("SELECT PROCESS_ID, START_TASK_ID, CUSTOM_ID, START_TIME, END_TIME, STATE, RETURN_VALUE, START_JSON FROM PROCESS WHERE PROCESS_ID = ?")
        ) {
            ps.setString(1, processUUID.toString());
            rs = ps.executeQuery();
            while (rs.next()) {
                result = createProcessFromResultSet(rs);
            }
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        } finally {
            closeResultSet(rs);
        }
        return result;
    }

    @Override
    public TaskContainer getStartTask(UUID processId) {
        TaskContainer result = null;
        ResultSet rs = null;
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("SELECT start_json FROM PROCESS WHERE PROCESS_ID = ?")
        ) {
            ps.setString(1, processId.toString());
            rs = ps.executeQuery();
            while (rs.next()) {
                result = taskSerializer.deserialize(rs.getString("start_json"));
            }
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        } finally {
            closeResultSet(rs);
        }
        return result;
    }

    @Override
    public void markProcessAsBroken(UUID processId) {
        setProcessState(processId, Process.BROKEN);
    }

    @Override
    public void markProcessAsStarted(UUID processId) {
        setProcessState(processId, Process.START);
    }

    private void setProcessState(UUID processId, int state) {
        logger.trace("Try to mark process [{}] state as ([{}])", processId, state);

        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement("UPDATE PROCESS set STATE = ? WHERE PROCESS_ID = ?")) {

            ps.setInt(1, state);
            ps.setString(2, processId.toString());
            ps.executeUpdate();
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        }

        logger.debug("Process [{}] state marked as ([{}])", processId, state);
    }

    @Override
    public GenericPage listProcesses(int pageNumber, int pageSize, int status, String typeFilter) {
        List result = new ArrayList<>();
        long totalCount = 0;
        ResultSet rs = null;
        String query = "SELECT PROCESS_ID, START_TASK_ID, CUSTOM_ID, START_TIME, END_TIME, STATE, RETURN_VALUE, START_JSON FROM PROCESS ";
        if (status >= 0 || typeFilter!=null) {
            StringBuilder sb = new StringBuilder("WHERE");
            if (status >= 0) {
                sb.append(" STATE = ? ");
            }
            if (typeFilter != null) {
                sb.append(" ACTOR_ID LIKE ? ");
            }
            query+= sb.toString();
        }
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement(PagedQueryBuilder.createPagesQuery(query))
        ) {
            int argIndex = 1;
            if (status >= 0) {
                ps.setInt(argIndex++, status);
            }
            if (typeFilter != null) {
                ps.setString(argIndex++, typeFilter + "%");
            }
            int startIndex = (pageNumber - 1) * pageSize + 1;
            int endIndex = startIndex + pageSize - 1;
            ps.setInt(argIndex++, endIndex);
            ps.setInt(argIndex++, startIndex);

            rs = ps.executeQuery();
            while (rs.next()) {
                result.add(createProcessFromResultSet(rs));
                totalCount = rs.getLong("cnt");
            }
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        } finally {
            closeResultSet(rs);
        }

        logger.debug("Process list got by params: pageNum[{}], pageSize[{}], status[{}] is [{}]", pageNumber, pageSize, status, result);

        return new GenericPage<>(result, pageNumber, pageSize, totalCount);
    }

    private static void closeResultSet(ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new ServiceCriticalException("Error on closing ResultSet", e);
            }
        }
    }

    @Override
    public List findProcesses(ProcessSearchCommand command) {
        List result = new ArrayList<>();
        if(command!=null && !command.isEmpty()) {
            String query = getSearchSql(command);
            ResultSet rs = null;
            try (Connection connection = dataSource.getConnection();
                 PreparedStatement ps = connection.prepareStatement(query)
            ) {
                rs = ps.executeQuery();
                while (rs.next()) {
                    result.add(createProcessFromResultSet(rs));
                }
            } catch (SQLException ex) {
                logger.error("DataBase exception on query [" + query + "]: " + ex.getMessage(), ex);
                throw new ServiceCriticalException("Database error", ex);
            } finally {
                closeResultSet(rs);
            }
        }
        return result;
    }

    @Override
    public int getFinishedCount(String customId) {
        int result = 0;
        String sql = customId!=null? SQL_GET_PROCESS_CNT_BY_STATE + "AND CUSTOM_ID = ? ": SQL_GET_PROCESS_CNT_BY_STATE;
        try (Connection connection = dataSource.getConnection();
             PreparedStatement ps = connection.prepareStatement(sql)) {

            ps.setInt(1, Process.FINISH);
            if (customId != null) {
                ps.setString(2, customId);
            }
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                result = rs.getInt("cnt");
            }
        } catch (SQLException ex) {
            logger.error("DataBase exception: " + ex.getMessage(), ex);
            throw new ServiceCriticalException("Database error", ex);
        }
        return result;
    }

    private String getSearchSql(ProcessSearchCommand command) {
        StringBuilder sb = new StringBuilder("SELECT PROCESS_ID, START_TASK_ID, CUSTOM_ID, START_TIME, END_TIME, STATE, START_JSON, RETURN_VALUE FROM PROCESS WHERE ");
        boolean requireAndCdtn = false;
        if(command.getProcessId()!=null && command.getProcessId().trim().length()>0) {
            sb.append("PROCESS_ID LIKE '").append(command.getProcessId()).append("%'");
            requireAndCdtn = true;
        }
        if(command.getCustomId()!=null && command.getCustomId().trim().length()>0) {
            if(requireAndCdtn) {
                sb.append(" AND ");
            }
            sb.append("CUSTOM_ID LIKE '").append(command.getCustomId()).append("%'");
        }

        sb.append(" AND ROWNUM <= 200");

        return sb.toString();
    }

    private Process createProcessFromResultSet(ResultSet resultSet) throws SQLException {
        Process process = new Process();

        process.setProcessId(UUID.fromString(resultSet.getString("process_id")));
        process.setStartTaskId(UUID.fromString(resultSet.getString("start_task_id")));
        process.setCustomId(resultSet.getString("custom_id"));
        process.setStartTime(resultSet.getLong("start_time"));
        process.setEndTime(resultSet.getLong("end_time"));
        process.setState(resultSet.getInt("state"));
        process.setReturnValue(resultSet.getString("return_value"));
        process.setStartTask(taskSerializer.deserialize(resultSet.getString("start_json")));

        return process;
    }

    @Override
    public ResultSetCursor findProcesses(long recoveryTime, int limit) {
        final Collection result = new ArrayList<>();
        try (Connection connection = dataSource.getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(getSql(limit))) {

            preparedStatement.setInt(1, Process.START);
            preparedStatement.setLong(2, recoveryTime);
            if (limit>0) {
                preparedStatement.setInt(3, limit);
            }

            ResultSet resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                UUID processId = UUID.fromString(resultSet.getString("process_id"));
                result.add(processId);
            }

        } catch (Throwable e) {
            logger.error("Cannot find incomplete before time["+ recoveryTime +"]processes limit["+limit+"] due to database error", e);
            throw new ServiceCriticalException("Incomplete processes search before time["+ recoveryTime +"] failed", e);
        }
        return new ResultSetCursor() {
            @Override
            public void close() throws IOException {

            }

            @Override
            public Collection getNext() {
                return result;
            }
        };
    }

    private String getSql(int limit) {
        return limit>0? SQL_FIND_INCOMPLETE_PROCESSES + " AND ROWNUM < ? ": SQL_FIND_INCOMPLETE_PROCESSES;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy