com.wavemaker.runtime.server.ServiceResponse.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.runtime.server.ServiceResponse.java

Source

/*
 *  Copyright (C) 2012-2013 CloudJee, Inc. All rights reserved.
 *
 *  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.wavemaker.runtime.server;

import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.wavemaker.common.WMRuntimeException;
import com.wavemaker.common.WMUnfinishedProcException;
import com.wavemaker.common.util.Tuple;
import com.wavemaker.json.JSONObject;
import com.wavemaker.runtime.RuntimeAccess;

public class ServiceResponse {

    private final Log log = LogFactory.getLog(ServiceResponse.class);

    private static final String INITIAL_REQUEST = "wm-initial-request";

    private static final String POLLING_REQUEST = "wm-polling-request";

    private static final String JSON_RESPONSE_STATUS = "wm-json-response-status";

    private final Map<String, Tuple.Two<Long, JSONObject>> serviceResponseTable = new Hashtable<String, Tuple.Two<Long, JSONObject>>();

    private final Map<String, Thread> threads = new Hashtable<String, Thread>();

    private RuntimeAccess runtimeAccess;

    private int connectionTimeout;

    public ServiceResponse() {
    }

    public Object invokeMethod(Method method, Object serviceObject, Object[] args) throws Exception {
        Object ret;
        this.threads.put(this.getRequestId(), Thread.currentThread());
        if (!isPollingRequest()) {
            //ret = addResponse(System.currentTimeMillis(), method.invoke(serviceObject, args));
            ret = addResponse(System.currentTimeMillis(), ServerUtils.invokeMethod(serviceObject, method, args));
        } else {
            ret = getResponseFromService();
        }

        return ret;
    }

    public synchronized Object addResponse(long startTime, Object obj) {
        String requestId = this.getRequestId();
        log.debug("ServiceResponse: addResponse: " + requestId + "  ***");
        if (System.currentTimeMillis() - this.runtimeAccess.getStartTime() > (this.connectionTimeout - 3) * 1000) {
            this.cleanup();
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("status", "done");
            jsonObj.put("result", obj);
            Tuple.Two<Long, JSONObject> t = new Tuple.Two<Long, JSONObject>(System.currentTimeMillis(), jsonObj);
            log.debug("ServiceResponse: addResponse: putting: " + requestId + " status: " + jsonObj.get("status")
                    + "  +++");
            this.serviceResponseTable.put(requestId, t);
        } else {
            this.threads.remove(requestId);
        }

        return obj;
    }

    private void cleanup() {
        for (Map.Entry<String, Thread> entry : this.threads.entrySet()) {
            String requestId = entry.getKey();
            Thread thread = entry.getValue();
            if (!thread.isAlive()) {
                Tuple.Two<Long, JSONObject> t = this.serviceResponseTable.get(requestId);
                if (t != null) {
                    long time = t.v1;
                    if (System.currentTimeMillis() - time > (this.connectionTimeout - 3) * 1000 * 2) {
                        log.debug("ServiceResponse: Cleanup: Remvoving: " + requestId + " " + thread.getId()
                                + " ---");
                        this.serviceResponseTable.remove(requestId);
                        this.threads.remove(requestId);
                    }
                }
            }
        }
    }

    public synchronized void addError(Object obj) {
        JSONObject resp = new JSONObject();
        resp.put("status", "error");
        resp.put("result", obj);
        Tuple.Two<Long, JSONObject> t = new Tuple.Two<Long, JSONObject>(System.currentTimeMillis(), resp);
        log.debug("ServiceResponse: addError: putting" + this.getRequestId() + "  +++");
        this.serviceResponseTable.put(this.getRequestId(), t);
    }

    public Object getResponseFromService() {

        JSONObject result = this.getResponseBeforeTimeout();
        String status = (String) result.get("status");
        if (status.equals("processing")) {
            Thread originalThread = this.getRequestThread();
            if (originalThread == null || !originalThread.isAlive()) {
                result = this.getResponseTryOnce();
                status = (String) result.get("status");
                if (status.equals("processing")) {
                    if (originalThread == null) {
                        throw new WMRuntimeException("Error: The original request thread is lost");
                    } else {
                        throw new WMRuntimeException("Error: The original request thread has been terminated");
                    }
                }
            }
        }

        if (status.equals("error")) {
            throw new WMRuntimeException((Exception) result.get("result"));
        }

        setJsonResponseStatus((String) result.get("status"));
        return result.get("result");
    }

    private void setJsonResponseStatus(String status) {
        this.runtimeAccess.getResponse().setHeader(JSON_RESPONSE_STATUS, status);
    }

    public JSONObject getResponseBeforeTimeout() {
        int time = 0;
        JSONObject result;

        while (time < this.connectionTimeout - 3) {
            try {
                result = getResponse();
                return result;
            } catch (WMUnfinishedProcException ex1) {
                try {
                    Thread.sleep(2000);
                    time = time + 2;
                } catch (InterruptedException ex2) {
                    throw new WMRuntimeException(ex2);
                }
            }
        }

        result = new JSONObject();
        result.put("status", "processing");
        result.put("requestId", this.getRequestId());
        return result;
    }

    private JSONObject getResponseTryOnce() {
        JSONObject result;
        try {
            result = getResponse();
        } catch (WMUnfinishedProcException ex1) {
            result = new JSONObject();
            result.put("status", "processing");
            result.put("requestId", this.getRequestId());
        }
        return result;
    }

    public synchronized JSONObject getResponse() {
        String requestId = this.getRequestId();
        log.debug("ServiceResponse: getResponse: " + this.getRequestId() + " ***");
        if (this.serviceResponseTable.containsKey(requestId)) {
            Tuple.Two<Long, JSONObject> t = this.serviceResponseTable.get(requestId);
            JSONObject rtn = t.v2;
            log.debug("ServiceResponse: getResponse: Remvoving: " + requestId + " ---");
            this.serviceResponseTable.remove(requestId);
            this.threads.remove(requestId);
            return rtn;
        } else {
            throw new WMUnfinishedProcException("still processing");
        }
    }

    public synchronized void addRequestThread(String requestId, Thread thread) {
        this.threads.put(requestId, thread);
    }

    public synchronized Thread getRequestThread() {
        return this.threads.get(this.getRequestId());
    }

    public boolean isPollingRequest() {
        return this.runtimeAccess.getRequest().getHeader(POLLING_REQUEST) != null;
    }

    public String getRequestId() {
        String reqId;
        reqId = this.runtimeAccess.getRequest().getHeader(POLLING_REQUEST);
        if (reqId == null) {
            reqId = this.runtimeAccess.getRequest().getHeader(INITIAL_REQUEST);
        }
        if (reqId == null) {
            throw new WMRuntimeException(
                    "Invalid Long Polling Request: Service requests to this server require the header "
                            + POLLING_REQUEST + " or " + INITIAL_REQUEST + ". Timeout for this server is: "
                            + getConnectionTimeout());

        }

        return reqId;
    }

    public RuntimeAccess getRuntimeAccess() {
        return this.runtimeAccess;
    }

    public void setRuntimeAccess(RuntimeAccess runtimeAccess) {
        this.runtimeAccess = runtimeAccess;
    }

    public void setConnectionTimeout(int connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    public int getConnectionTimeout() {
        return this.connectionTimeout;
    }
}