Search in sources :

Example 1 with Handle

use of org.apache.qpid.qmf2.common.Handle in project qpid by apache.

the class QpidServer method doPost.

/**
 * Called by the Web Server to allow a Server to handle a POST request.
 * <pre>
 * POST: &lt;host&gt;:&lt;port&gt;/qpid/connection/&lt;name&gt;/object/&lt;ObjectId&gt;
 *      HTTP body: {"_method_name":&lt;method&gt;,"_arguments":&lt;inArgs&gt;}
 *      &lt;method&gt;: A string containing the QMF2 method name e.g. "getLogLevel", "setLogLevel", "create", "delete".
 *      &lt;inArgs&gt;: A JSON string containing the method arguments e.g. {"level":"debug+:Broker"} for setLogLevel.
 *      HTTP response: A JSON string containing the response e.g. {"level":"notice+"} for getLogLevel (may be empty).
 *
 *      This method invokes the QMF2 method &lt;method&gt; with arguments &lt;inArgs&gt; on the object &lt;ObjectId&gt;
 * </pre>
 * @param tx the HttpTransaction containing the request from the client and used to send the response.
 */
@SuppressWarnings("unchecked")
public void doPost(final HttpTransaction tx) throws IOException {
    String path = tx.getRequestURI();
    if (path.startsWith("/qpid/connection/")) {
        path = path.substring(17);
        String user = tx.getPrincipal();
        String connectionName = path;
        int i = path.indexOf("/");
        if (// Can use > rather than >= as we've already tested for "/qpid/connection/" above.
        i > 0) {
            connectionName = user + "." + path.substring(0, i);
            path = path.substring(i + 1);
            // Find the Connection with the name extracted from the URI.
            ConnectionProxy connection = _connections.get(connectionName);
            if (connection == null) {
                _log.info("QpidServer.doPost path: {} Connection not found.", tx.getRequestURI());
                tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
            } else if (!connection.isConnected()) {
                tx.sendResponse(HTTP_INTERNAL_ERROR, "text/plain", "500 Broker Disconnected.");
            } else {
                // If we get this far we should have found a Qpid Connection so retrieve the QMF2 Console Object.
                Console console = connection.getConsole();
                if (path.startsWith("object/")) {
                    path = path.substring(7);
                    // The ObjectId has been passed in the URI create an ObjectId and retrieve the Agent Name.
                    ObjectId oid = new ObjectId(path);
                    String agentName = oid.getAgentName();
                    // The qpidd ManagementAgent doesn't populate AgentName, if it's empty assume it's the broker.
                    agentName = agentName.equals("") ? "broker" : agentName;
                    // Find the Agent we got the QmfData from.
                    Agent agent = console.getAgent(agentName);
                    if (agent == null) {
                        _log.info("QpidServer.doPost path: {} Agent: {} not found.", tx.getRequestURI(), agentName);
                        tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
                    } else {
                        // If we get this far we can create the Object and invoke the method.
                        // We can create a QmfConsoleData with nothing but an ObjectId and the agent.
                        QmfConsoleData object = new QmfConsoleData(Collections.EMPTY_MAP, agent);
                        object.setObjectId(oid);
                        String request = tx.getRequestString();
                        _log.info("QpidServer.doPost path: {} body: {}", tx.getRequestURI(), request);
                        // System.out.println(request);
                        String method = "";
                        try {
                            Map<String, Object> reqMap = JSON.toMap(request);
                            method = (String) reqMap.get("_method_name");
                            Object arguments = reqMap.get("_arguments");
                            Map args = (arguments instanceof Map) ? (Map) arguments : null;
                            // System.out.println("method: " + method + ", args: " + args);
                            // Parse the args if present into a QmfData (needed by invokeMethod).
                            QmfData inArgs = (args == null) ? new QmfData() : new QmfData(args);
                            // Invoke the specified method on the QmfConsoleData we've created.
                            MethodResult results = null;
                            _log.info("invokeMethod: {}", request);
                            results = object.invokeMethod(method, inArgs);
                            tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(results));
                        } catch (QmfException qmfe) {
                            _log.info("QpidServer.doPost() caught Exception {}", qmfe.getMessage());
                            tx.sendResponse(HTTP_INTERNAL_ERROR, "text/plain", "invokeMethod(" + method + ") -> " + qmfe.getMessage());
                        } catch (Exception e) {
                            _log.info("QpidServer.doPost() caught Exception {}", e.getMessage());
                            tx.sendResponse(HTTP_INTERNAL_ERROR, "text/plain", "500 " + e.getMessage());
                        }
                    }
                } else {
                    tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
                }
            }
        } else {
            tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
        }
    } else {
        tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
    }
}
Also used : Agent(org.apache.qpid.qmf2.console.Agent) QmfData(org.apache.qpid.qmf2.common.QmfData) ObjectId(org.apache.qpid.qmf2.common.ObjectId) QmfException(org.apache.qpid.qmf2.common.QmfException) IOException(java.io.IOException) Console(org.apache.qpid.qmf2.console.Console) QmfConsoleData(org.apache.qpid.qmf2.console.QmfConsoleData) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Map(java.util.Map) MethodResult(org.apache.qpid.qmf2.console.MethodResult) QmfException(org.apache.qpid.qmf2.common.QmfException)

Example 2 with Handle

use of org.apache.qpid.qmf2.common.Handle in project qpid by apache.

the class QpidServer method doGet.

/**
 * Called by the Web Server to allow a Server to handle a GET request.
 * The HTTP GET URL structure for the REST API is specified above in the overall class documentation.
 *
 * @param tx the HttpTransaction containing the request from the client and used to send the response.
 */
public void doGet(final HttpTransaction tx) throws IOException {
    String path = tx.getRequestURI();
    if (path.startsWith("/qpid/connection/")) {
        path = path.substring(17);
        // Using the principal lets different users use the default connection.
        String user = tx.getPrincipal();
        if (path.length() == 0) {
            // handle "/qpid/connection/" request with unspecified connection (returns list of available connections).
            tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(_connections.getAll(user)));
        } else {
            // if path.length() > 0 we're dealing with a specified Connection so extract the name and look it up.
            String connectionName = path;
            int i = path.indexOf("/");
            if (// Can use > rather than >= as we've already tested for "/qpid/connection/" above.
            i > 0) {
                connectionName = path.substring(0, i);
                path = path.substring(i + 1);
            } else {
                path = "";
            }
            connectionName = user + "." + connectionName;
            // attempts to connect to a broker specified in the QpidRestAPI config (or default 0.0.0.0:5672).
            if (connectionName.equals(user + ".default")) {
                ConnectionProxy defaultConnection = _connections.get(connectionName);
                if (defaultConnection == null) {
                    defaultConnection = _connections.create(connectionName, _defaultBroker, "", false);
                    // Wait a maximum of 1000ms for the underlying Qpid Connection to become available. If we
                    // don't do this the first call using the default will return 404 Not Found.
                    defaultConnection.waitForConnection(1000);
                }
            }
            // Find the Connection with the name extracted from the URI.
            ConnectionProxy connection = _connections.get(connectionName);
            if (connection == null) {
                tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
            } else if (!connection.isConnected()) {
                tx.sendResponse(HTTP_INTERNAL_ERROR, "text/plain", "500 Broker Disconnected.");
            } else {
                if (path.length() == 0) {
                    // handle request for information about a specified Console
                    tx.sendResponse(HTTP_OK, "application/json", connection.toString());
                } else {
                    // In this block we are dealing with resources associated with a specified connectionName.
                    // path describes the resources specifically related to "/qpid/connection/<connectionName>"
                    Console console = connection.getConsole();
                    if (path.startsWith("console/objects/")) {
                        // Get information about specified objects.
                        path = path.substring(16);
                        sendGetObjectsResponse(tx, console, path);
                    } else if (path.startsWith("console/objects") && path.length() == 15) {
                        // If objects is unspecified treat as a synonym for classes.
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getClasses()));
                    } else if (path.startsWith("console/address/")) {
                        // Get the Console AMQP Address
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getAddress()));
                    } else if (path.startsWith("console/address") && path.length() == 15) {
                        // Get the Console AMQP Address
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getAddress()));
                    } else if (path.startsWith("console/workItemCount/")) {
                        // Returns the count of pending WorkItems that can be retrieved.
                        tx.sendResponse(HTTP_OK, "text/plain", "" + console.getWorkitemCount());
                    } else if (path.startsWith("console/workItemCount") && path.length() == 21) {
                        // Returns the count of pending WorkItems that can be retrieved.
                        tx.sendResponse(HTTP_OK, "text/plain", "" + console.getWorkitemCount());
                    } else if (path.startsWith("console/nextWorkItem/")) {
                        // Obtains the next pending work item, or null if none available.
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getNextWorkitem()));
                    } else if (path.startsWith("console/nextWorkItem") && path.length() == 20) {
                        // Obtains the next pending work item, or null if none available.
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getNextWorkitem()));
                    } else if (path.startsWith("console/agents") && path.length() == 14) {
                        // Get information about all available Agents.
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getAgents()));
                    } else if (path.startsWith("console/agent/")) {
                        // Get information about a specified Agent.
                        Agent agent = console.getAgent(path.substring(14));
                        if (agent == null) {
                            tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
                        } else {
                            tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(agent));
                        }
                    } else if (path.startsWith("console/agent") && path.length() == 13) {
                        // If agent is unspecified treat as a synonym for agents.
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getAgents()));
                    } else if (path.startsWith("console/classes/")) {
                        // Get information about the classes for a specified Agent
                        // Get Agent name
                        path = path.substring(16);
                        // TODO handle getClasses() for specified Agent
                        tx.sendResponse(HTTP_NOT_IMPLEMENTED, "text/plain", "501 getClasses() for specified Agent not yet implemented.");
                    } else if (path.startsWith("console/classes") && path.length() == 15) {
                        // Get information about all the classes for all Agents
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getClasses()));
                    } else if (path.startsWith("console/packages/")) {
                        // Get information about the packages for a specified Agent
                        // Get Agent name
                        path = path.substring(17);
                        // TODO handle getPackages() for specified Agent.
                        tx.sendResponse(HTTP_NOT_IMPLEMENTED, "text/plain", "501 getPackages() for specified Agent not yet implemented.");
                    } else if (path.startsWith("object/")) {
                        /**
                         * This is the REST implementation of getObjects(oid) it is also the equivalent of
                         * the QmfConsoleData refresh() method where an object can update its state.
                         * N.B. that the ManagementAgent on the broker appears not to set the timestamp properties
                         * in the response to this call, which means that they get set to current time in the
                         * QmfConsoleData, this is OK for _update_ts but not for _create_ts and _delete_ts
                         * users of this call should be aware of that in their own code.
                         */
                        path = path.substring(7);
                        // The ObjectId has been passed in the URI, create a real ObjectId
                        ObjectId oid = new ObjectId(path);
                        List<QmfConsoleData> objects = console.getObjects(oid);
                        if (objects.size() == 0) {
                            tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
                        } else {
                            // Not that in a departure from the QMF2 API this returns the QmfConsoleData object
                            // rather than a list of size one. Perhaps the APIs should be completely consistent
                            // but this response seems more convenient.
                            tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(objects.get(0)));
                        }
                    } else if (path.startsWith("console/packages") && path.length() == 16) {
                        // Get information about all the packages for all Agents
                        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(console.getPackages()));
                    } else {
                        tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
                    }
                }
            }
        }
    } else if (path.startsWith("/qpid/connection")) {
        // handle "/qpid/connection" request with unspecified connection (returns list of available connections).
        // Using the principal lets different users use the default connection.
        String user = tx.getPrincipal();
        tx.sendResponse(HTTP_OK, "application/json", JSON.fromObject(_connections.getAll(user)));
    } else {
        tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
    }
}
Also used : Agent(org.apache.qpid.qmf2.console.Agent) ObjectId(org.apache.qpid.qmf2.common.ObjectId) Console(org.apache.qpid.qmf2.console.Console) List(java.util.List)

Example 3 with Handle

use of org.apache.qpid.qmf2.common.Handle in project qpid by apache.

the class QpidServer method doPut.

/**
 * <pre>
 * PUT: &lt;host&gt;:&lt;port&gt;/qpid/connection/&lt;name&gt;
 *      HTTP body: {"url":&lt;url&gt;,"connectionOptions":&lt;connectionOptions&gt;[,"disableEvents":true;]}
 *      &lt;url&gt;: A string containing an AMQP connection URL as used in the qpid::messaging API.
 *      &lt;connectionOptions&gt;: A JSON string containing connectionOptions in the form specified in the
 *      qpid::messaging API.
 * </pre>
 * Called by the Web Server to allow a Server to handle a PUT request.
 * This method creates a Qpid Connection Object with the name &lt;name&gt; using the specified url and options.
 * <p>
 * The optional disableEvents property is used to start up a QMF Connection which can only
 * do synchronous calls such as getObjects() and can't receive Agent updates or QMF2 Events.
 * <p>
 * N.B. It is possible for the Qpid broker to be unavailable when this method is called so it is actually a
 * ConnectionProxy that is created. This method waits for up to 1000ms for the underlying Qpid Connection to
 * become available and then returns. Clients should be aware that this method successfully returning only
 * implies that the ConnectionProxy is in place and the underlying Qpid Connection may not be available.
 * If the broker is down the ConnectionProxy will periodically attempt to reconnect, but whilst it is down
 * the REST API will return a 500 Broker Disconnected response to any PUT or POST call.
 *
 * @param tx the HttpTransaction containing the request from the client and used to send the response.
 */
@SuppressWarnings("unchecked")
public void doPut(final HttpTransaction tx) throws IOException {
    String path = tx.getRequestURI();
    if (path.startsWith("/qpid/connection/")) {
        path = path.substring(17);
        String user = tx.getPrincipal();
        String request = tx.getRequestString();
        _log.info("QpidServer.doPut path: {} body: {}", tx.getRequestURI(), request);
        String name = user + "." + path;
        try {
            // The PUT request is a JSON string containing a url String property and a connectionOptions
            // property which is itself a JSON String.
            Map<String, String> reqMap = JSON.toMap(request);
            String url = reqMap.get("url");
            url = url.equals("") ? _defaultBroker : url;
            // Extract the connectionOptions property and check its type is a MAP
            Object options = reqMap.get("connectionOptions");
            Map optionsMap = (options instanceof Map) ? (Map) options : null;
            // Turn the connectionOptions Map back into a JSON String. Note that we can't just get
            // connectionOptions as a String from reqMap as it is sent as JSON and the JSON.toMap()
            // call on the POST request will fully parse it.
            String connectionOptions = JSON.fromObject(optionsMap);
            boolean disableEvents = false;
            String disableEventsString = reqMap.get("disableEvents");
            if (disableEventsString != null) {
                disableEvents = disableEventsString.equalsIgnoreCase("true");
            }
            ConnectionProxy proxy = _connections.create(name, url, connectionOptions, disableEvents);
            // Wait a maximum of 1000ms for the underlying Qpid Connection to become available then return.
            proxy.waitForConnection(1000);
            tx.sendResponse(HTTP_CREATED, "text/plain", "201 Created.");
        } catch (Exception e) {
            _log.info("QpidServer.doPut() caught Exception {}", e.getMessage());
            tx.sendResponse(HTTP_INTERNAL_ERROR, "text/plain", "500 " + e.getMessage());
        }
    } else {
        tx.sendResponse(HTTP_NOT_FOUND, "text/plain", "404 Not Found.");
    }
}
Also used : ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Map(java.util.Map) QmfException(org.apache.qpid.qmf2.common.QmfException) IOException(java.io.IOException)

Example 4 with Handle

use of org.apache.qpid.qmf2.common.Handle in project qpid by apache.

the class JSON method fromWorkItem.

/**
 * Serialise a WorkItem Object to JSON.
 * @param data the WorkItem that we wish to serialise to JSON.
 * @return the JSON String encoding.
 */
public static final String fromWorkItem(final WorkItem data) {
    // TODO There are a couple of WorkItem types that won't serialise correctly - SubscriptionIndicationWorkItem
    // and MethodCallWorkItem. Their params require a custom serialiser - though they probably won't be used
    // from a REST API so they've been parked for now.
    String type = "\"_type\":\"" + data.getType() + "\",";
    Handle handle = data.getHandle();
    String handleString = handle == null ? "" : "\"_handle\":\"" + handle.getCorrelationId() + "\",";
    String params = "\"_params\":" + fromObject(data.getParams());
    return "{" + type + handleString + params + "}";
}
Also used : Handle(org.apache.qpid.qmf2.common.Handle)

Example 5 with Handle

use of org.apache.qpid.qmf2.common.Handle in project qpid by apache.

the class QmfManagementAgent method onEvent.

// ******************************* QmfEventListener implementation method *******************************
/**
 * Callback method triggered when the underlying QMF2 Agent has WorkItems available for processing.
 * The purpose of this method is mainly to handle the METHOD_CALL WorkItem and demultiplex &amp; delegate
 * to the invokeMethod() call on the relevant concrete QmfAgentData Object.
 * @param wi the WorkItem that has been passed by the QMF2 Agent to be processed here (mainly METHOD_CALL).
 */
@Override
public void onEvent(final WorkItem wi) {
    if (wi.getType() == METHOD_CALL) {
        MethodCallWorkItem item = (MethodCallWorkItem) wi;
        MethodCallParams methodCallParams = item.getMethodCallParams();
        String methodName = methodCallParams.getName();
        ObjectId objectId = methodCallParams.getObjectId();
        // Look up QmfAgentData by ObjectId from the Agent's internal Object store.
        QmfAgentData object = _agent.getObject(objectId);
        if (object == null) {
            _agent.raiseException(item.getHandle(), "No object found with ID=" + objectId);
        } else {
            // other classes yet.
            if (object instanceof org.apache.qpid.server.qmf2.agentdata.Broker) {
                org.apache.qpid.server.qmf2.agentdata.Broker broker = (org.apache.qpid.server.qmf2.agentdata.Broker) object;
                broker.invokeMethod(_agent, item.getHandle(), methodName, methodCallParams.getArgs());
            } else if (object instanceof org.apache.qpid.server.qmf2.agentdata.Queue) {
                org.apache.qpid.server.qmf2.agentdata.Queue queue = (org.apache.qpid.server.qmf2.agentdata.Queue) object;
                queue.invokeMethod(_agent, item.getHandle(), methodName, methodCallParams.getArgs());
            } else {
                _agent.raiseException(item.getHandle(), "Unknown Method " + methodName + " on " + object.getClass().getSimpleName());
            }
        }
    }
}
Also used : MethodCallWorkItem(org.apache.qpid.qmf2.agent.MethodCallWorkItem) Broker(org.apache.qpid.server.model.Broker) ObjectId(org.apache.qpid.qmf2.common.ObjectId) MethodCallParams(org.apache.qpid.qmf2.agent.MethodCallParams) QmfAgentData(org.apache.qpid.qmf2.agent.QmfAgentData) Queue(org.apache.qpid.server.model.Queue)

Aggregations

JMSException (javax.jms.JMSException)9 Map (java.util.Map)7 MapMessage (javax.jms.MapMessage)7 QmfData (org.apache.qpid.qmf2.common.QmfData)7 QmfException (org.apache.qpid.qmf2.common.QmfException)7 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)6 Handle (org.apache.qpid.qmf2.common.Handle)6 ObjectId (org.apache.qpid.qmf2.common.ObjectId)6 HashMap (java.util.HashMap)5 Message (javax.jms.Message)5 AMQPMessage (org.apache.qpid.qmf2.common.AMQPMessage)5 SchemaClassId (org.apache.qpid.qmf2.common.SchemaClassId)5 ArrayList (java.util.ArrayList)3 List (java.util.List)3 Destination (javax.jms.Destination)3 QmfAgentData (org.apache.qpid.qmf2.agent.QmfAgentData)3 QmfQuery (org.apache.qpid.qmf2.common.QmfQuery)3 IOException (java.io.IOException)2 AddressParser (org.apache.qpid.messaging.util.AddressParser)2 MethodCallParams (org.apache.qpid.qmf2.agent.MethodCallParams)2