org.eclipse.flux.client.RequestResponseHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.flux.client.RequestResponseHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2014 Pivotal Software, Inc. and others.
 * All rights reserved. This program and the accompanying materials are made 
 * available under the terms of the Eclipse Public License v1.0 
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
 *
 * Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.flux.client;

import org.eclipse.flux.client.util.Assert;
import org.eclipse.flux.client.util.Console;
import org.eclipse.flux.client.util.ExceptionUtil;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * A Abstract MessageHandler that provides some help in implementing a typical
 * request -> response pattern. I.e. a handler that is accepting 'request' messages
 * and sends a single response back as a result.
 * <p>
 * Subclasses must override either createResponse or fillResponse, whichever is
 * more convenient.
 * 
 * @author Kris De Volder
 */
public abstract class RequestResponseHandler extends MessageHandler {

    private MessageConnector flux;
    private String responseType;

    private static final Console console = Console.get(RequestResponseHandler.class.getName());

    public RequestResponseHandler(MessageConnector flux, String type) {
        super(type);
        this.flux = flux;
        this.responseType = type.replaceAll("Request$", "Response");
        Assert.assertTrue(responseType.endsWith("Response"));
    }

    public final void handle(String type, JSONObject req) {
        try {
            JSONObject res;
            try {
                res = createResponse(type, req);
            } catch (Throwable e) {
                console.log(e);
                flux.send(responseType, errorResponse(req, e));
                return;
            }
            //We only get here if no exception was caught:
            flux.send(responseType, res);
        } catch (Exception e) {
            //This happens only if we had a problem sending the response
            console.log(e);
        }
    }

    protected JSONObject createResponse(String type, JSONObject req) throws Exception {
        JSONObject res = copy(req);
        return fillResponse(type, req, res);
    }

    protected JSONObject copy(JSONObject req) {
        try {
            JSONObject res = new JSONObject(req);
            for (String name : JSONObject.getNames(req)) {
                res.put(name, req.get(name));
            }
            return res;
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Subclasses can implement this to fill in a response for the given request object.
     * <p>
     * If the method throws an exception it will be caugth and turned into an error response
     * automatically.
     * <p>
     * If the method returns null, the request is silently ignored.
     * <p>
     * If the method returns a JSONObject this is sent as the response to the flux message bus.
     * <p>
     * For convenience a copy of the request object is passed in as as the 'res' parameter. 
     * Implementers can add additional properties, modify the res object at will 
     * or create a brand new object from scratch. However, when creating object from scratch
     * is is better to override 'createResponse' directly to avoid it creating a useless 
     * copy of the req object.
     */
    protected JSONObject fillResponse(String type, JSONObject req, JSONObject res) throws Exception {
        return res;
    }

    protected JSONObject errorResponse(JSONObject req, Throwable e) {
        try {
            JSONObject res = copy(req);
            res.put("error", ExceptionUtil.getMessage(e));
            res.put("errorDetails", ExceptionUtil.stackTrace(e));
            return res;
        } catch (JSONException shouldNotHappen) {
            throw new RuntimeException(shouldNotHappen);
        }
    }

}