com.globalsight.everest.workflowmanager.WfStatePostThread.java Source code

Java tutorial

Introduction

Here is the source code for com.globalsight.everest.workflowmanager.WfStatePostThread.java

Source

/**
 *  Copyright 2009 Welocalize, 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.globalsight.everest.workflowmanager;

import java.io.IOException;
import java.util.Vector;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BestMatchSpecFactory;
import org.apache.http.impl.cookie.BrowserCompatSpec;
import org.apache.http.impl.cookie.BrowserCompatSpecFactory;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.json.JSONObject;

import com.globalsight.everest.foundation.L10nProfile;
import com.globalsight.everest.servlet.util.ServerProxy;
import com.globalsight.everest.taskmanager.Task;
import com.globalsight.everest.workflow.WorkflowArrowInstance;
import com.globalsight.everest.workflow.WorkflowConstants;
import com.globalsight.everest.workflow.WorkflowTaskInstance;
import com.globalsight.persistence.hibernate.HibernateUtil;
import com.globalsight.util.mail.MailerConstants;

public class WfStatePostThread implements Runnable {
    static private final Logger s_logger = Logger.getLogger(WfStatePostThread.class);

    private CloseableHttpClient httpClient = null;

    private Task task;
    private String destinationArrow;
    private boolean isDispatch;

    public WfStatePostThread(Task task, String destinationArrow, boolean isDispatch) {
        super();
        this.task = task;
        this.destinationArrow = destinationArrow;
        this.isDispatch = isDispatch;
    }

    @Override
    public void run() {
        wfStatePost(task, destinationArrow, isDispatch);
    }

    private synchronized void wfStatePost(Task p_task, String p_destinationArrow, boolean isDispatch) {
        long taskId = p_task.getId();
        try {
            s_logger.info("Begin to post workflow state transition info for task: " + taskId);

            JSONObject jsonObj = getNotifyMessage(p_task, destinationArrow, isDispatch);
            s_logger.info("workflow transition post info: " + jsonObj);
            L10nProfile l10nProfile = ServerProxy.getJobHandler().getL10nProfileByJobId(p_task.getJobId());
            long wfStatePostId = l10nProfile.getWfStatePostId();
            WorkflowStatePosts wfStatePost = ServerProxy.getProjectHandler().getWfStatePostProfile(wfStatePostId);

            doPost(wfStatePost, jsonObj);
        } catch (Exception e) {
            s_logger.error("wfStatePost error:", e);
        } finally {
            shutdownHttpClient();
            HibernateUtil.closeSession();
            s_logger.info("End to post workflow state transition info for task: " + taskId);
        }
    }

    @SuppressWarnings("unchecked")
    private JSONObject getNotifyMessage(Task p_task, String p_destinationArrow, boolean isDispatch)
            throws Exception {
        String toArrowName = p_destinationArrow;
        JSONObject jsonObj = new JSONObject();
        long jobId = p_task.getJobId();
        if (isDispatch) {
            jsonObj.put("prevActivity", "start");
            WorkflowTaskInstance firstTask = ServerProxy.getWorkflowServer()
                    .getWorkflowTaskInstance(p_task.getWorkflow().getId(), p_task.getId());
            jsonObj.put("currActivity", firstTask.getActivityDisplayName());
            Vector<WorkflowArrowInstance> arrows3 = firstTask.getIncomingArrows();
            for (WorkflowArrowInstance arrow3 : arrows3) {
                WorkflowTaskInstance srcNode = (WorkflowTaskInstance) arrow3.getSourceNode();
                if (srcNode.getType() == WorkflowConstants.START) {
                    toArrowName = arrow3.getName();
                }
            }
        } else {
            WorkflowTaskInstance nextTask = ServerProxy.getWorkflowServer().nextNodeInstances(p_task,
                    p_destinationArrow, null);
            if (nextTask != null) {
                jsonObj.put("currActivity", nextTask.getActivityDisplayName());
            } else {
                jsonObj.put("currActivity", "exit");
            }
            if (StringUtils.isEmpty(p_destinationArrow)) {
                if (nextTask != null) {
                    Vector<WorkflowArrowInstance> arrows = nextTask.getIncomingArrows();
                    if (arrows != null && arrows.size() == 1) {
                        toArrowName = arrows.get(0).getName();
                    } else {
                        for (WorkflowArrowInstance arrow : arrows) {
                            toArrowName = determineIncomingArrow(arrow, p_task.getId());
                            if (toArrowName != null)
                                break;
                        }
                    }
                } else {
                    WorkflowTaskInstance currentTask = ServerProxy.getWorkflowServer()
                            .getWorkflowTaskInstance(p_task.getWorkflow().getId(), p_task.getId());
                    Vector<WorkflowArrowInstance> arrows2 = currentTask.getOutgoingArrows();
                    for (WorkflowArrowInstance arrow2 : arrows2) {
                        toArrowName = determineOutgoingArrow(arrow2);
                        if (toArrowName != null)
                            break;
                    }
                }
            }
            jsonObj.put("prevActivity", p_task.getTaskDisplayName());
        }
        jsonObj.put("arrowText", toArrowName);
        jsonObj.put("jobId", jobId);
        jsonObj.put("jobName", p_task.getJobName());
        jsonObj.put("workflowId", p_task.getWorkflow().getIdAsLong());
        jsonObj.put("sourceLocale", p_task.getSourceLocale().toString());
        jsonObj.put("targetLocale", p_task.getTargetLocale().toString());

        return jsonObj;
    }

    @SuppressWarnings("unchecked")
    private String determineIncomingArrow(WorkflowArrowInstance arrow, long p_originalTaskId) {
        String toArrowName = null;
        WorkflowTaskInstance srcNode = (WorkflowTaskInstance) arrow.getSourceNode();
        if (srcNode.getType() == WorkflowConstants.ACTIVITY && srcNode.getTaskId() == p_originalTaskId) {
            toArrowName = arrow.getName();
        } else if (srcNode.getType() == WorkflowConstants.CONDITION) {
            Vector<WorkflowArrowInstance> arrows = srcNode.getIncomingArrows();
            for (WorkflowArrowInstance arrow2 : arrows) {
                WorkflowTaskInstance srcNode2 = (WorkflowTaskInstance) arrow2.getSourceNode();
                if (srcNode2.getType() == WorkflowConstants.ACTIVITY && srcNode2.getTaskId() == p_originalTaskId) {
                    toArrowName = arrow.getName();
                    break;
                }
            }
        }

        return toArrowName;
    }

    @SuppressWarnings("unchecked")
    private String determineOutgoingArrow(WorkflowArrowInstance arrow) {
        String toArrowName = null;
        WorkflowTaskInstance trgNode = (WorkflowTaskInstance) arrow.getTargetNode();
        if (trgNode.getType() == WorkflowConstants.STOP) {
            toArrowName = arrow.getName();
        } else if (trgNode.getType() == WorkflowConstants.CONDITION) {
            Vector<WorkflowArrowInstance> arrows = trgNode.getOutgoingArrows();
            for (WorkflowArrowInstance arrow2 : arrows) {
                WorkflowTaskInstance trgNode2 = (WorkflowTaskInstance) arrow2.getTargetNode();
                if (trgNode2.getType() == WorkflowConstants.STOP) {
                    toArrowName = arrow2.getName();
                    break;
                }
            }
        }

        return toArrowName;
    }

    private void doPost(WorkflowStatePosts wfStatePost, JSONObject message) {
        int num = wfStatePost.getRetryNumber();
        CloseableHttpClient httpClient = getHttpClient();
        for (int i = 0; i < num; i++) {
            try {
                String listenerUrl = wfStatePost.getListenerURL();
                String secretKey = wfStatePost.getSecretKey();
                HttpPost httpPost = new HttpPost(listenerUrl);
                httpPost.setHeader(HttpHeaders.AUTHORIZATION, secretKey);
                RequestConfig config = RequestConfig.custom()
                        .setConnectionRequestTimeout(wfStatePost.getTimeoutPeriod() * 1000)
                        .setConnectTimeout(wfStatePost.getTimeoutPeriod() * 1000)
                        .setSocketTimeout(wfStatePost.getTimeoutPeriod() * 1000).build();
                httpPost.setConfig(config);
                StringEntity reqEntity = new StringEntity(message.toString());
                reqEntity.setContentEncoding("UTF-8");
                reqEntity.setContentType("application/json");
                httpPost.setEntity(reqEntity);
                HttpResponse response = null;
                try {
                    response = httpClient.execute(httpPost);
                } catch (Exception e) {
                    s_logger.error("Post workflow transition info error:", e);
                } finally {
                    if (response != null) {
                        EntityUtils.consumeQuietly(response.getEntity());
                    }
                }
                if (response != null) {
                    int statusCode = response.getStatusLine().getStatusCode();
                    if (statusCode == 204) {
                        break;
                    } else {
                        logPostFailureInfo(statusCode);
                        if (StringUtils.isNotEmpty(wfStatePost.getNotifyEmail()) && (i == num)) {
                            String recipient = wfStatePost.getNotifyEmail();
                            long companyId = wfStatePost.getCompanyId();
                            String[] messageArguments = { wfStatePost.getName(), wfStatePost.getListenerURL(),
                                    message.toString() };
                            ServerProxy.getMailer().sendMailFromAdmin(recipient, messageArguments,
                                    MailerConstants.WORKFLOW_STATE_POST_FAILURE_SUBJECT,
                                    MailerConstants.WORKFLOW_STATE_POST_FAILURE_MESSAGE, String.valueOf(companyId));
                        }
                    }
                }
            } catch (Exception e) {
                s_logger.error(e);
            }
        }
    }

    CookieSpecProvider easySpecProvider = new CookieSpecProvider() {
        public CookieSpec create(HttpContext context) {
            return new BrowserCompatSpec() {
                @Override
                public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException {
                    // Oh, I am easy
                }
            };
        }
    };

    Registry<CookieSpecProvider> reg = RegistryBuilder.<CookieSpecProvider>create()
            .register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
            .register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory())
            .register("mySpec", easySpecProvider).build();

    RequestConfig requestConfig = RequestConfig.custom().setCookieSpec("mySpec").build();

    private CloseableHttpClient getHttpClient() {
        if (httpClient == null) {
            httpClient = HttpClients.custom().setDefaultCookieSpecRegistry(reg)
                    .setDefaultRequestConfig(requestConfig).build();
        }

        return httpClient;
    }

    private void shutdownHttpClient() {
        if (httpClient == null)
            return;

        try {
            httpClient.close();
        } catch (IOException e) {
            s_logger.error("Fail to close httpclient", e);
        }
    }

    private static void logPostFailureInfo(int statusCode) {
        s_logger.warn("Fail to post workflow transition info, status code is: " + statusCode);
        if (statusCode == 400) {
            s_logger.warn("Workflow state post failure: The request payload data failed validation!");
        } else if (statusCode == 401) {
            s_logger.warn("Workflow state post failure: Not authorized. The secret value is incorrect!");
        } else if (statusCode == 405) {
            s_logger.warn("Workflow state post failure: The request did not use the POST method!");
        } else if (statusCode == 500) {
            s_logger.warn("Workflow state post failure: Database error!");
        }
    }
}