org.apromore.service.pql.impl.PQLServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apromore.service.pql.impl.PQLServiceImpl.java

Source

/*
 * Copyright  2009-2016 The Apromore Initiative.
 *
 * This file is part of "Apromore".
 *
 * "Apromore" is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * "Apromore" 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 */

package org.apromore.service.pql.impl;

// Java 2 Standard
import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

// Java 2 Enterprise
import javax.inject.Inject;

// Third party
import org.apache.commons.io.IOUtils;
import org.pql.api.IPQLAPI;
import org.pql.core.PQLTask;
import org.pql.index.IndexStatus;
import org.pql.query.PQLQueryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

// First party
import org.apromore.dao.ProcessModelVersionRepository;
import org.apromore.dao.model.Process;
import org.apromore.dao.model.ProcessBranch;
import org.apromore.dao.model.ProcessModelVersion;
import org.apromore.exception.ExportFormatException;
import org.apromore.helper.Version;
import org.apromore.model.Detail;
import org.apromore.model.ExportFormatResultType;
import org.apromore.model.SummariesType;
import org.apromore.model.ProcessSummaryType;
import org.apromore.model.VersionSummaryType;
import org.apromore.plugin.DefaultPlugin;
import org.apromore.plugin.process.ProcessPlugin;
import org.apromore.plugin.property.RequestParameterType;
import org.apromore.service.pql.ExternalId;
import org.apromore.service.pql.PQLService;
import org.apromore.service.ProcessService;

/**
 * Created by corno on 22/07/2014.
 */
@Service
public class PQLServiceImpl extends DefaultPlugin implements PQLService, ProcessPlugin {

    private static final Logger LOGGER = LoggerFactory.getLogger(PQLServiceImpl.class);
    private final String PNML_NATIVE_TYPE = "PNML 1.3.2";

    @Inject
    private ProcessService processService;
    @Inject
    private ProcessModelVersionRepository processModelVersionRepository;
    @Inject
    private PqlBeanImpl pqlBean;

    private final List<ExternalId> queue = Collections.synchronizedList(new ArrayList<ExternalId>());

    /**
     * Store the text of a PNML model into the PQL database.
     *
     * This is a relatively quick, synchronous operation.  The model is not indexed immediately, but
     * becomes available for eventual (asynchronous) indexing by the PQL "bot" process.
     *
     * @param exportResult  a PNML model obtained from the {@link ProcessService#exportProcess} method
     * @param procId
     * @param version
     * @param branchName
     * @throws IOException  if the native PNML serialization couldn't be obtained from the <var>exportResult</var>
     * @throws SQLException  if the model couldn't be store into the PQL database
     */
    private void storeModel(ExportFormatResultType exportResult, Integer procId, Version version, String branchName)
            throws IOException, SQLException {

        byte[] bytes = IOUtils.toByteArray(exportResult.getNative().getInputStream());
        ExternalId externalId = new ExternalId(procId, branchName, version);
        int internalId = pqlBean.getApi().storeModel(bytes, externalId.toString());

        LOGGER.info("SOUNDNESS: " + pqlBean.getApi().checkModel(internalId));
    }

    /** @inheritDoc */
    @Override
    public SummariesType query(String pql) throws QueryException {

        PQLQueryResult pqlQueryResult;
        try {
            pqlQueryResult = pqlBean.getApi().query(pql);

            // If the pql wasn't well-formed, throw the parse errors
            if (pqlQueryResult.getNumberOfParseErrors() != 0) {
                throw new QueryParsingException(pqlQueryResult.getParseErrorMessages());
            }
            assert pqlQueryResult.getNumberOfParseErrors() == 0;

            // Compose process summaries for the query results
            SummariesType processSummaries = new SummariesType();
            for (String result : pqlQueryResult.getSearchResults()) {
                ExternalId id = new ExternalId(result);

                ProcessModelVersion pmv = processModelVersionRepository.getProcessModelVersion(id.getProcessId(),
                        id.getBranch(), id.getVersion().toString());
                ProcessBranch pb = pmv.getProcessBranch();
                Process p = pb.getProcess();

                VersionSummaryType versionSummary = new VersionSummaryType();
                versionSummary.setVersionNumber(pmv.getVersionNumber());

                ProcessSummaryType processSummary = new ProcessSummaryType();
                processSummary.setName(p.getName());
                processSummary.setId(p.getId());
                processSummary.setOriginalNativeType("BPMN 2.0");
                processSummary.setDomain(p.getDomain());
                processSummary.setRanking(p.getRanking());
                processSummary.setLastVersion(pmv.getVersionNumber());
                processSummary.setOwner(p.getUser().getUsername());
                processSummary.getVersionSummaries().add(versionSummary);

                processSummaries.getSummary().add(processSummary);
            }
            return processSummaries;

        } catch (QueryParsingException e) {
            throw e;

        } catch (Exception e) {
            throw new QueryException("Unable to execute PQL query: " + pql, e);
        }
    }

    public List<String> runAPQLQuery(String queryPQL, List<String> IDs, String userID) {
        //Set<String> idNets=new HashSet<>();
        List<String> results = Collections.emptyList();
        IPQLAPI api = pqlBean.getApi();
        LOGGER.error("-----------PQLAPI: " + api);
        LOGGER.error("----------- query: " + queryPQL);
        LOGGER.error("-----------   IDs: " + IDs);
        LOGGER.error("-----------  user: " + userID);
        try {
            PQLQueryResult pqlQueryResult = api.query(queryPQL, new HashSet<>(IDs));
            if (pqlQueryResult.getNumberOfParseErrors() != 0) {
                results = pqlQueryResult.getParseErrorMessages();
            } else {//risultati
                LOGGER.error("-----------IDS PQLServiceImpl" + IDs);
                map = pqlQueryResult.getTaskMap();
                LinkedList<PQLTask> tasks = new LinkedList<>(map.values());
                /*
                                idNets=new HashSet<>(IDs);
                                idNets=api.checkLastQuery(idNets);
                                results.addAll(idNets);
                */
                results = new LinkedList<>(pqlQueryResult.getSearchResults());
                LOGGER.error("-----------QUERYAPQL ESATTA " + results);
            }
        } catch (Exception e) {
            LOGGER.error("-----------ERRORRE: " + e.toString());
            for (StackTraceElement ste : e.getStackTrace())
                LOGGER.info("ERRORE6: " + ste.getClassName() + " " + ste.getMethodName() + " " + ste.getLineNumber()
                        + " " + ste.getFileName());
        }
        return results;
    }

    private Map<PQLTask, PQLTask> map = new HashMap<>();

    public List<Detail> getDetails() {
        List<Detail> details = new LinkedList<>();
        Detail detail;
        for (PQLTask task : map.keySet()) {
            PQLTask taskTwo = map.get(task);

            detail = new Detail();
            detail.setLabelOne(task.getLabel());
            detail.setSimilarityLabelOne("" + task.getSimilarity());
            if (taskTwo.getSimilarLabels() != null) {
                detail.getDetail().addAll(taskTwo.getSimilarLabels());
            }
            details.add(detail);
        }
        return details;
    }

    /**
     * @param id  a process ID in the Apromore database (the "external ID" from PQL's point of view)
     * @return the indexing status of the identified process in the PQL index
     */
    @Override
    public IndexStatus getIndexStatus(ExternalId id) throws SQLException {
        IPQLAPI api = pqlBean.getApi();
        int internalId = api.getInternalID(id.toString());
        return api.getIndexStatus(internalId);
    }

    // Implementation of the ProcessPlugin interface

    /** {@inheritDoc} */
    public void bindToProcessService() {
        LOGGER.info("Binding to process service " + processService);
        IPQLAPI api = pqlBean.getApi();
        for (ProcessModelVersion pmv : processModelVersionRepository.findAll()) {
            int processId = pmv.getProcessBranch().getProcess().getId();
            String branch = pmv.getProcessBranch().getBranchName();
            Version version = new Version(pmv.getVersionNumber());
            ExternalId externalId = new ExternalId(processId, branch, version);

            try {
                int internalId = api.getInternalID(externalId.toString());
                IndexStatus status = (internalId == 0) ? IndexStatus.UNINDEXED : api.getIndexStatus(internalId);

                // If the external ID doesn't occur in the PQL index, queue it to be asynchronously indexed
                switch (status) {
                case UNINDEXED:
                    LOGGER.info("PQL index needs to be initialized for process with external ID " + externalId);
                    queue.add(externalId);
                    break;
                case INDEXING:
                    LOGGER.info("PQL index " + internalId + " already being indexed for process with external ID "
                            + externalId);
                    break;
                case INDEXED:
                    LOGGER.info("PQL index " + internalId + " already present for process with external ID "
                            + externalId);
                    break;
                case CANNOTINDEX:
                    LOGGER.info("PQL index " + internalId
                            + " couldn't previously be indexed for process with external ID " + externalId);
                    break;
                default:
                    LOGGER.warn("PQL index " + internalId + " for process with external ID " + externalId
                            + " has unknown status " + status);
                }
            } catch (SQLException e) {
                LOGGER.error("Unable to look up process with external ID " + externalId + " in the PQL index", e);
            }
        }
        LOGGER.info("Bound to process service " + processService);
    }

    /** {@inheritDoc} */
    public void unbindFromProcessService() {
        LOGGER.info("Unbound from process service " + processService);
    }

    /** {@inheritDoc} */
    public void processChanged(int processId, String branch, Version version) throws ProcessChangedException {
        ExternalId externalId = new ExternalId(processId, branch, version);
        LOGGER.info("PQL index needs to be updated for process with external ID " + externalId
                + " in process service " + processService);
        queue.add(externalId);
    }

    // Asynchronous indexing

    @Scheduled(cron = "*/${pql.defaultBotSleepTime} * * * * ?")
    public void indexQueuedProcesses() {
        //LOGGER.info("Indexing queued processes");
        try {
            while (!queue.isEmpty()) {
                ExternalId externalId = queue.remove(0);
                indexProcess(externalId);
            }
        } catch (IndexOutOfBoundsException e) {
            // if there wasn't a 0th element of the queue, we're done
        }
        //LOGGER.info("Indexing queue empty");
    }

    private void indexProcess(ExternalId externalId) {
        //LOGGER.info("Indexing queued process " + externalId);
        IPQLAPI api = pqlBean.getApi();
        try {
            Set<RequestParameterType<?>> requestProperties = new HashSet<>();
            requestProperties.add(new RequestParameterType<>("isCpfTaskPnmlTransition", true));
            requestProperties.add(new RequestParameterType<>("isCpfTaskPnmlTrans", false));

            ExportFormatResultType exportResult = processService.exportProcess("dummy process name",
                    externalId.getProcessId(), externalId.getBranch(), externalId.getVersion(), PNML_NATIVE_TYPE,
                    null, false, requestProperties);

            byte[] bytes = IOUtils.toByteArray(exportResult.getNative().getInputStream());
            int internalId = api.storeModel(bytes, externalId.toString());
            LOGGER.info("Stored " + (api.checkModel(internalId) ? "sound" : "unsound") + " process " + externalId
                    + " for PQL indexing as id " + internalId);

        } catch (ExportFormatException | IOException | SQLException e) {
            LOGGER.warn("Unable to index " + externalId + " for PQL indexing", e);

            // This is USUALLY because the model has been deleted.  In other cases, it's still relatively safe to just delete the associated index.
            try {
                LOGGER.info("Removing model with external ID " + externalId + " from PQL index");
                int internalId = api.getInternalID(externalId.toString());
                if (!api.deleteModel(internalId)) {
                    LOGGER.error("Failed to remove model with external ID " + externalId + " from PQL index");
                } else {
                    LOGGER.error("Removed model with external ID " + externalId + " and internal ID " + internalId
                            + " from PQL index");
                }

            } catch (SQLException e2) {
                LOGGER.error("Exception while removing model " + externalId + " from PQL index", e2);
            }
        }
    }
}