You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ch...@apache.org on 2011/05/31 16:00:53 UTC

svn commit: r1129681 - in /activemq/activemq-apollo/trunk: apollo-web/pom.xml apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala apollo-website/src/documentation/management-api.md pom.xml

Author: chirino
Date: Tue May 31 14:00:53 2011
New Revision: 1129681

URL: http://svn.apache.org/viewvc?rev=1129681&view=rev
Log:
Fixes https://issues.apache.org/jira/browse/APLO-27
We now support a paged/tabular interface to accessing the management interface.

Modified:
    activemq/activemq-apollo/trunk/apollo-web/pom.xml
    activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala
    activemq/activemq-apollo/trunk/apollo-website/src/documentation/management-api.md
    activemq/activemq-apollo/trunk/pom.xml

Modified: activemq/activemq-apollo/trunk/apollo-web/pom.xml
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/pom.xml?rev=1129681&r1=1129680&r2=1129681&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-web/pom.xml (original)
+++ activemq/activemq-apollo/trunk/apollo-web/pom.xml Tue May 31 14:00:53 2011
@@ -90,7 +90,19 @@
       <scope>provided</scope>
       <optional>true</optional>
     </dependency>
-    
+
+    <dependency>
+      <groupId>net.sf.josql</groupId>
+      <artifactId>josql</artifactId>
+      <version>${josql-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>net.sf.josql</groupId>
+      <artifactId>gentlyweb-utils</artifactId>
+      <version>${josql-version}</version>
+    </dependency>
+
+
     <!-- Scala Support -->
     <dependency>
       <groupId>org.scala-lang</groupId>

Modified: activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala?rev=1129681&r1=1129680&r2=1129681&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala (original)
+++ activemq/activemq-apollo/trunk/apollo-web/src/main/scala/org/apache/activemq/apollo/web/resources/BrokerResource.scala Tue May 31 14:00:53 2011
@@ -16,18 +16,22 @@
  */
 package org.apache.activemq.apollo.web.resources;
 
-import javax.ws.rs._
-import core.Response
-import Response.Status._
 import org.apache.activemq.apollo.dto._
 import java.{lang => jl}
 import org.fusesource.hawtdispatch._
 import org.apache.activemq.apollo.broker._
 import scala.collection.Iterable
-import org.apache.activemq.apollo.util.{Failure, Success, Dispatched, Result}
 import scala.Some
 import security.{SecurityContext, Authorizer}
 import org.apache.activemq.apollo.util.path.PathParser
+import org.apache.activemq.apollo.web.resources.Resource._
+import org.josql.Query
+import org.apache.activemq.apollo.util._
+import collection.mutable.ListBuffer
+import javax.ws.rs._
+import core.Response
+import Response.Status._
+import org.josql.expressions.SelectItemExpression
 
 /**
  * <p>
@@ -222,6 +226,45 @@ case class BrokerResource() extends Reso
     link
   }
 
+  def narrow[T](kind:Class[T], x:Iterable[Result[T, Throwable]], f:java.util.List[String], q:String, p:java.lang.Integer, ps:java.lang.Integer) = {
+    import collection.JavaConversions._
+    try {
+      var records = x.toSeq.flatMap(_.success_option)
+
+      val page_size = if( ps !=null ) ps.intValue() else 100
+      val page = if( p !=null ) p.intValue() else 0
+
+      val query = new Query
+      val fields = if (f.isEmpty) "*" else f.toList.mkString(",")
+      val where_clause = if (q != null) q else "1=1"
+
+      query.parse("SELECT " + fields + " FROM " + kind.getName + " WHERE "+ where_clause+" LIMIT "+((page_size*page)+1)+", "+page_size)
+      val headers = if (f.isEmpty) seqAsJavaList(List("*")) else f
+
+      val list = query.execute(records).getResults
+
+      Success(seqAsJavaList( headers :: list.toList) )
+    } catch {
+      case e:Throwable => Failure(e)
+    }
+  }
+
+  @GET @Path("virtual-hosts/{id}/topics")
+  @Produces(Array("application/json"))
+  def topics(@PathParam("id") id : String, @QueryParam("f") f:java.util.List[String],
+            @QueryParam("q") q:String, @QueryParam("p") p:java.lang.Integer, @QueryParam("ps") ps:java.lang.Integer ):java.util.List[_] = {
+    with_virtual_host(id) { host =>
+      val router: LocalRouter = host
+      val records = Future.all {
+        router.topic_domain.destination_by_id.values.map { value  =>
+          status(value)
+        }
+      }
+      val rc:FutureResult[java.util.List[_]] = records.map(narrow(classOf[TopicStatusDTO], _, f, q, p, ps))
+      rc
+    }
+  }
+
   @GET @Path("virtual-hosts/{id}/topics/{name:.*}")
   def topic(@PathParam("id") id : String, @PathParam("name") name : String):TopicStatusDTO = {
     with_virtual_host(id) { host =>
@@ -231,6 +274,23 @@ case class BrokerResource() extends Reso
     }
   }
 
+  @GET @Path("virtual-hosts/{id}/queues")
+  @Produces(Array("application/json"))
+  def queues(@PathParam("id") id : String, @QueryParam("f") f:java.util.List[String],
+            @QueryParam("q") q:String, @QueryParam("p") p:java.lang.Integer, @QueryParam("ps") ps:java.lang.Integer ):java.util.List[_] = {
+    with_virtual_host(id) { host =>
+      val router: LocalRouter = host
+      val values: Iterable[Queue] = router.queue_domain.destination_by_id.values
+
+      val records = sync_all(values) { value =>
+        status(value, false)
+      }
+
+      val rc:FutureResult[java.util.List[_]] = records.map(narrow(classOf[QueueStatusDTO], _, f, q, p, ps))
+      rc
+    }
+  }
+
   @GET @Path("virtual-hosts/{id}/queues/{name:.*}")
   def queue(@PathParam("id") id : String, @PathParam("name") name : String, @QueryParam("entries") entries:Boolean ):QueueStatusDTO = {
     with_virtual_host(id) { host =>
@@ -240,6 +300,22 @@ case class BrokerResource() extends Reso
     }
   }
 
+  @GET @Path("virtual-hosts/{id}/dsubs")
+  @Produces(Array("application/json"))
+  def durable_subscriptions(@PathParam("id") id : String, @QueryParam("f") f:java.util.List[String],
+            @QueryParam("q") q:String, @QueryParam("p") p:java.lang.Integer, @QueryParam("ps") ps:java.lang.Integer ):java.util.List[_] = {
+    with_virtual_host(id) { host =>
+      val router: LocalRouter = host
+      val values: Iterable[Queue] = router.topic_domain.durable_subscriptions_by_id.values
+
+      val records = sync_all(values) { value =>
+        status(value, false)
+      }
+
+      val rc:FutureResult[java.util.List[_]] = records.map(narrow(classOf[QueueStatusDTO], _, f, q, p, ps))
+      rc
+    }
+  }
   @GET @Path("virtual-hosts/{id}/dsubs/{name:.*}")
   def durable_subscription(@PathParam("id") id : String, @PathParam("name") name : String, @QueryParam("entries") entries:Boolean):QueueStatusDTO = {
     with_virtual_host(id) { host =>
@@ -377,27 +453,30 @@ case class BrokerResource() extends Reso
     }
   }
 
-
   @GET @Path("connections")
-  def connections:LongIdListDTO = {
+  @Produces(Array("application/json"))
+  def connections(@QueryParam("f") f:java.util.List[String], @QueryParam("q") q:String,
+                  @QueryParam("p") p:java.lang.Integer, @QueryParam("ps") ps:java.lang.Integer ):java.util.List[_] = {
+
     with_broker { broker =>
       monitoring(broker) {
-        val rc = new LongIdListDTO
 
+        val values = ListBuffer[BrokerConnection]()
         broker.connectors.foreach { connector=>
-          connector.connections.foreach { case (id,connection) =>
-            // TODO: may need to sync /w connection's dispatch queue
-            rc.items.add(new LongIdLabeledDTO(id, connection.transport.getRemoteAddress ))
-          }
+          values ++= connector.connections.values
+        }
+        val records = sync_all(values) { value =>
+          value.get_connection_status
         }
 
+        val rc:FutureResult[java.util.List[_]] = records.map(narrow(classOf[ConnectionStatusDTO], _, f, q, p, ps))
         rc
       }
     }
   }
 
   @GET @Path("connections/{id}")
-  def connections(@PathParam("id") id : Long):ConnectionStatusDTO = {
+  def connection(@PathParam("id") id : Long):ConnectionStatusDTO = {
     with_connection(id){ connection=>
       monitoring(connection.connector.broker) {
         connection.get_connection_status

Modified: activemq/activemq-apollo/trunk/apollo-website/src/documentation/management-api.md
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/apollo-website/src/documentation/management-api.md?rev=1129681&r1=1129680&r2=1129681&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/apollo-website/src/documentation/management-api.md (original)
+++ activemq/activemq-apollo/trunk/apollo-website/src/documentation/management-api.md Tue May 31 14:00:53 2011
@@ -39,6 +39,92 @@ Example:
 
     $ curl -u "admin:password" http://localhost:61680/broker.json
 
+### Working with Tabular Results
+
+Many of the resource routes provided by the broker implement
+a selectable paged tabular interface.  A good example of such
+a resource route is the connections list.  It's route is:
+
+    /broker/connections
+
+Example:
+
+    $ curl -u "admin:password" \
+    'http://localhost:61680/broker/connections.json'
+    [
+      [
+        "*"
+      ],
+      {
+        "id":"4",
+        "state":"STARTED",
+        "state_since":1306848325102,
+        "read_counter":103,
+        "write_counter":239110628,
+        "transport":"tcp",
+        "protocol":"stomp",
+        "remote_address":"/127.0.0.1:61775",
+        "protocol_version":"1.0",
+        "user":"admin",
+        "waiting_on":"client request",
+        "subscription_count":1
+      },
+      {
+        "id":"5",
+        "state":"STARTED",
+        "state_since":1306848325102,
+        "read_counter":227739229,
+        "write_counter":113,
+        "transport":"tcp",
+        "protocol":"stomp",
+        "remote_address":"/127.0.0.1:61776",
+        "protocol_version":"1.0",
+        "user":"admin",
+        "waiting_on":"blocked sending to: org.apache.activemq.apollo.broker.Queue$$anon$1@13765e9b",
+        "subscription_count":0
+      }
+    ]
+
+The results are an array of records with the first record acting as a header
+records describing the fields selected. The `*` field means all the record's
+fields were selected. To narrow down the selected fields you can add
+multiple `f` query parameters to pick the fields you want to retrieve.
+
+Example:
+    $ curl -u "admin:password" \
+    'http://localhost:61680/broker/connections.json?f=id&f=read_counter'
+    [
+      [
+        "id",
+        "read_counter"
+      ],
+      [
+        "7",
+        110733109
+      ],
+      [
+        "6",
+        103
+      ]
+    ]
+
+If you want to narrow down the records which get selected, you can set a `q`
+query parameter to SQL 92 style where clause which uses the record's fields
+to filter down the selected records.
+
+For example to only view local connection, you would want to use a where
+clause like `remote_address LIKE "/127.0.0.01:%"` which to execute with
+`curl` you would run:
+
+    curl -u "admin:password" \
+    'http://localhost:61680/broker/connections.json?q=remote_address%20LIKE%20"/127.0.0.1:%"'
+
+The records are paged. The default page size is 100, so only the first 100
+records will be displayed. If you want to view subsequent results, you must
+set the `p` query parameter to the page you wish to access. You can change
+the page size by setting the `ps` query parameter.
+
+
 ### Broker Management
 
 The route for managing the broker is:
@@ -107,7 +193,11 @@ Results in a [Connector Status](./api/ap
 
 ### Connection Management
 
-The route for managing a connection is:
+The route for getting a tabular list of connections is:
+
+    /broker/connections
+
+The route for managing a single connection is:
 
     /broker/connections/:id
 
@@ -226,6 +316,10 @@ Results in a [Store Status](./api/apollo
 
 #### Queue Management
 
+The route for getting a tabular list of queues is:
+
+    /broker/virtual-hosts/:name/queues
+
 The route for managing a virtual host's Queue is:
 
     /broker/virtual-hosts/:name/queues/:qid
@@ -295,6 +389,10 @@ Results in a [Queue Status](./api/apollo
 
 #### Topic Management
 
+The route for getting a tabular list of queues is:
+
+    /broker/virtual-hosts/:name/topics
+
 The route for managing a virtual host's Topic is:
 
     /broker/virtual-hosts/:name/topics/:tid
@@ -337,6 +435,28 @@ Results in a [Topic Status](./api/apollo
 }
 {pygmentize}
 
+
+#### Durable Subscription Management
+
+The route for getting a tabular list of durable subscriptions is:
+
+    /broker/virtual-hosts/:name/dsubs
+
+The route for managing a virtual host's durable subscription is:
+
+    /broker/virtual-hosts/:name/dsubs/:sub
+
+Where `:name` is the id of a virtual host configured in the broker and `:sub` is the id
+of the durable subscription.
+
+Example:
+
+    $ curl -u "admin:password" \
+    http://localhost:61680/broker/virtual-hosts/localhost/dsubs/mysub.json
+
+Results in a [Queue Status](./api/apollo-dto/org/apache/activemq/apollo/dto/QueueStatusDTO.html):
+
+
 ### Getting the Broker's Configuration
 
 To get current runtime configuration of the broker GET:

Modified: activemq/activemq-apollo/trunk/pom.xml
URL: http://svn.apache.org/viewvc/activemq/activemq-apollo/trunk/pom.xml?rev=1129681&r1=1129680&r2=1129681&view=diff
==============================================================================
--- activemq/activemq-apollo/trunk/pom.xml (original)
+++ activemq/activemq-apollo/trunk/pom.xml Tue May 31 14:00:53 2011
@@ -122,6 +122,7 @@
     
     <cascal-version>1.3-SNAPSHOT</cascal-version>
     <hawtdb-version>1.6-SNAPSHOT</hawtdb-version>
+    <josql-version>1.5</josql-version>
     
     <!-- osgi stuff -->
     <osgi-version>4.2.0</osgi-version>
@@ -739,7 +740,15 @@
           <snapshots><enabled>true</enabled></snapshots>
           <releases><enabled>false</enabled></releases>
         </repository>
-    
+
+        <!-- for net.sf.josql dependency not yet in central -->
+        <repository>
+          <id>com.fusesource.m2</id>
+          <url>http://repo.fusesource.com/nexus/content/groups/public/</url>
+          <releases><enabled>true</enabled></releases>
+          <snapshots><enabled>false</enabled></snapshots>
+        </repository>
+
       </repositories>
 
       <pluginRepositories>