modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
| 40 ++-
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
| 84 +++++++-
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
| 12 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/MetricAggregate.java
| 4
modules/integration-tests/rest-api/README.md
| 13 +
modules/integration-tests/rest-api/pom.xml
| 56 +++++
modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java
| 78 +++++++
modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
| 104 ++++++++++
8 files changed, 372 insertions(+), 19 deletions(-)
New commits:
commit f74b119c57c4fe7721127b2faa9a5b0b046a8811
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Dec 7 12:04:02 2011 +0100
Initial set of integration tests for the REST api.
diff --git a/modules/integration-tests/rest-api/README.md
b/modules/integration-tests/rest-api/README.md
new file mode 100644
index 0000000..b5551be
--- /dev/null
+++ b/modules/integration-tests/rest-api/README.md
@@ -0,0 +1,13 @@
+# REST-API Integration tests
+
+These require a running server with at least one platform as resource id 10001 in
inventory.
+Also required are two accounts
+
+* rhqadmin with password rhqadmin in the superuser role
+* user with password name23 as a restricted user
+
+The server to connect to can be given on the command line via
`-Drest.server=<server>` as in
+
+ `mvn -Pdev -Drest.server=pintsize test`
+
+If no server is given, localhost is assumed.
\ No newline at end of file
diff --git a/modules/integration-tests/rest-api/pom.xml
b/modules/integration-tests/rest-api/pom.xml
new file mode 100644
index 0000000..4a2c4a6
--- /dev/null
+++ b/modules/integration-tests/rest-api/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-integration-tests</artifactId>
+ <version>4.3.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>rest-api-tests</artifactId>
+
+ <name>RHQ REST API tests</name>
+
+ <properties>
+ <surefire-plugin.version>2.10</surefire-plugin.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire-plugin.version}</version>
+ <dependencies>
+ <dependency>
+ <!-- explicitly choose the junit4.7+ provider -->
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-junit47</artifactId>
+ <version>${surefire-plugin.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.restfuse</groupId>
+ <artifactId>com.eclipsesource.restfuse</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git
a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java
b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java
new file mode 100644
index 0000000..b59bd11
--- /dev/null
+++
b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/GetStatusTest.java
@@ -0,0 +1,78 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.modules.integrationTests.restApi;
+
+
+import com.eclipsesource.restfuse.AuthenticationType;
+import com.eclipsesource.restfuse.Destination;
+import com.eclipsesource.restfuse.HttpJUnitRunner;
+import com.eclipsesource.restfuse.Method;
+import com.eclipsesource.restfuse.Response;
+import com.eclipsesource.restfuse.annotation.Authentication;
+import com.eclipsesource.restfuse.annotation.Context;
+import com.eclipsesource.restfuse.annotation.HttpTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test the status part of the API
+ */
+(a)RunWith(HttpJUnitRunner.class)
+public class GetStatusTest {
+
+
+
+ @Rule
+ public Destination destination = new Destination("http://" +
System.getProperty("rest.server","localhost") +
":7080/rest/1");
+
+ @Context
+ private Response response;
+
+
+ @Test
+ @HttpTest( method = Method.GET, path = "/status" )
+ public void testAuthRequired() {
+ com.eclipsesource.restfuse.Assert.assertUnauthorized(response);
+ }
+
+
+ @Test
+ @HttpTest( method = Method.GET, path = "/status" ,authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin",
password = "rhqadmin")
+ )
+ public void testAuthRhqadmin() {
+ com.eclipsesource.restfuse.Assert.assertOk(response);
+ }
+
+ @Test
+ @HttpTest( method = Method.GET, path = "/status" ,authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "user",
password = "name23")
+ )
+ public void testAuthRestricted() {
+ com.eclipsesource.restfuse.Assert.assertForbidden(response);
+ }
+
+
+}
diff --git
a/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
new file mode 100644
index 0000000..88cfaaf
--- /dev/null
+++
b/modules/integration-tests/rest-api/src/test/java/org/rhq/modules/integrationTests/restApi/ResourcesTest.java
@@ -0,0 +1,104 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.modules.integrationTests.restApi;
+
+import com.eclipsesource.restfuse.AuthenticationType;
+import com.eclipsesource.restfuse.Destination;
+import com.eclipsesource.restfuse.HttpJUnitRunner;
+import com.eclipsesource.restfuse.Method;
+import com.eclipsesource.restfuse.Response;
+import com.eclipsesource.restfuse.annotation.Authentication;
+import com.eclipsesource.restfuse.annotation.Context;
+import com.eclipsesource.restfuse.annotation.Header;
+import com.eclipsesource.restfuse.annotation.HttpTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * Test the resources part
+ * @author Heiko W. Rupp
+ */
+(a)RunWith(HttpJUnitRunner.class)
+public class ResourcesTest {
+
+ @Rule
+ public Destination destination = new Destination("http://" +
System.getProperty("rest.server","localhost") +
":7080/rest/1");
+
+ @Context
+ private Response response;
+
+
+ @HttpTest( method = Method.GET, path = "/resource/platforms" )
+ public void testAuthRequired() {
+ com.eclipsesource.restfuse.Assert.assertUnauthorized(response);
+ }
+
+ @HttpTest( method = Method.GET, path =
"/resource/platforms",authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin",
password = "rhqadmin")
+ )
+ public void testPlatformsPresent() {
+ com.eclipsesource.restfuse.Assert.assertOk(response);
+ assertTrue(response.hasBody());
+ }
+
+ @HttpTest( method = Method.GET, path = "/resource/10001",authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin",
password = "rhqadmin"),
+ headers = {@Header(name = "Accept",value
="application/json")}
+ )
+ public void testGetPlatformJson() {
+ com.eclipsesource.restfuse.Assert.assertOk(response);
+ assertTrue(response.hasBody());
+ }
+
+ @HttpTest( method = Method.GET, path = "/resource/10001",authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin",
password = "rhqadmin"),
+ headers = {@Header(name = "Accept",value
="application/xml")}
+ )
+ public void testGetPlatformXml() {
+ com.eclipsesource.restfuse.Assert.assertOk(response);
+ assertTrue(response.hasBody());
+ }
+
+ @HttpTest( method = Method.GET, path =
"/resource/10001/schedules",authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin",
password = "rhqadmin"),
+ headers = {@Header(name = "Accept",value
="application/json")}
+ )
+ public void testGetPlatformSchedules() {
+ com.eclipsesource.restfuse.Assert.assertOk(response);
+ assertTrue(response.hasBody());
+ }
+
+ @HttpTest( method = Method.GET, path =
"/resource/10001/children",authentications =
+ @Authentication(type = AuthenticationType.BASIC, user = "rhqadmin",
password = "rhqadmin"),
+ headers = {@Header(name = "Accept",value
="application/json")}
+ )
+ public void testGetPlatformChildren() {
+ com.eclipsesource.restfuse.Assert.assertOk(response);
+ assertTrue(response.hasBody());
+ }
+
+}
commit 56eab8fd42ea5c3cfece191a71fef81fd8bf9c54
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Dec 7 12:03:28 2011 +0100
Improve Exception mapping
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
index d951767..58ccf30 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/CustomExceptionMapper.java
@@ -18,11 +18,11 @@
*/
package org.rhq.enterprise.server.rest;
-import javax.ejb.EJBException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
+import org.rhq.enterprise.server.authz.PermissionException;
import org.rhq.enterprise.server.resource.ResourceNotFoundException;
/**
@@ -30,31 +30,39 @@ import org.rhq.enterprise.server.resource.ResourceNotFoundException;
* @author Heiko W. Rupp
*/
@Provider
-public class CustomExceptionMapper implements ExceptionMapper<EJBException> {
+public class CustomExceptionMapper implements ExceptionMapper<Exception> {
@Override
- public Response toResponse(EJBException e) {
+ public Response toResponse(Exception e) {
Throwable cause = e.getCause();
+ Response.ResponseBuilder builder;
if (cause !=null) {
+ Response.Status status;
if (cause instanceof StuffNotFoundException)
- return Response.status(Response.Status.NOT_FOUND)
- .entity(cause.getMessage())
- .build();
+ status =Response.Status.NOT_FOUND;
else if (cause instanceof ResourceNotFoundException)
- return Response.status(Response.Status.NOT_FOUND)
- .entity(cause.getMessage())
- .build();
+ status = Response.Status.NOT_FOUND;
else if (cause instanceof ParameterMissingException)
- return Response.status(Response.Status.NOT_ACCEPTABLE)
- .entity(cause.getMessage())
- .build();
+ status = Response.Status.NOT_ACCEPTABLE;
+ else if (cause instanceof PermissionException)
+ status = Response.Status.FORBIDDEN;
else
- return Response.status(Response.Status.SERVICE_UNAVAILABLE)
- .entity(cause.getMessage())
- .build();
+ status = Response.Status.SERVICE_UNAVAILABLE;
+
+ builder = Response.status(status);
+ builder.entity(cause.getMessage());
+ }
+ else {
+ if (e instanceof PermissionException) {
+ builder = Response.status(Response.Status.FORBIDDEN);
+ } else {
+ builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ if (e.getMessage()!=null)
+ builder.entity(e.getMessage());
}
- throw e;
+ return builder.build();
}
}
commit 8c1ab57450bc314e7a469ff968d4c24a806905ef
Author: Heiko W. Rupp <hwr(a)redhat.com>
Date: Wed Dec 7 09:30:45 2011 +0100
Allow to obtain metrics for multiple schedules at once.
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
index 8be8070..5934dbe 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerBean.java
@@ -26,9 +26,14 @@ import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.EntityTag;
+import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
@@ -38,6 +43,7 @@ import javax.ws.rs.core.UriInfo;
import org.jboss.cache.Fqn;
+import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.MeasurementSchedule;
@@ -73,7 +79,7 @@ public class MetricHandlerBean extends AbstractRestBean implements
MetricHandle
@Context Request request,
@Context HttpHeaders headers) {
- if (dataPoints<0)
+ if (dataPoints<=0)
throw new IllegalArgumentException("dataPoints must be >0 ");
if (startTime==0) {
@@ -103,11 +109,14 @@ public class MetricHandlerBean extends AbstractRestBean implements
MetricHandle
List<List<MeasurementDataNumericHighLowComposite>> listList =
dataManager.findDataForResource(caller,
schedule.getResource().getId(), new int[]{definitionId}, startTime,
endTime, dataPoints);
+/*
long minTime=Long.MAX_VALUE;
long maxTime=0;
+*/
if (!listList.isEmpty()) {
List<MeasurementDataNumericHighLowComposite> list = listList.get(0);
+/*
for (MeasurementDataNumericHighLowComposite c : list) {
long timestamp = c.getTimestamp();
if (!Double.isNaN(c.getValue()) || !hideEmpty) {
@@ -123,6 +132,9 @@ public class MetricHandlerBean extends AbstractRestBean implements
MetricHandle
}
res.setMaxTimeStamp(maxTime);
res.setMinTimeStamp(minTime);
+*/
+ res = fill(list,scheduleId,hideEmpty);
+ }
CacheControl cc = new CacheControl();
int maxAge = (int) (schedule.getInterval() / 1000L)/2; // millis ; half of
schedule interval
@@ -144,6 +156,76 @@ public class MetricHandlerBean extends AbstractRestBean implements
MetricHandle
return builder.build();
}
+ private MetricAggregate fill(List<MeasurementDataNumericHighLowComposite>
list,int scheduleId , boolean hideEmpty) {
+ long minTime=Long.MAX_VALUE;
+ long maxTime=0;
+ MetricAggregate res = new MetricAggregate();
+ res.setScheduleId(scheduleId);
+
+ for (MeasurementDataNumericHighLowComposite c : list) {
+ long timestamp = c.getTimestamp();
+ if (!Double.isNaN(c.getValue()) || !hideEmpty) {
+ MetricAggregate.DataPoint dp = new
MetricAggregate.DataPoint(timestamp,c.getValue(),c.getHighValue(),c.getLowValue());
+ res.addDataPoint(dp);
+ }
+ if (timestamp <minTime)
+ minTime= timestamp;
+ if (timestamp >maxTime)
+ maxTime= timestamp;
+ }
+ res.setNumDataPoints(list.size());
+ res.setMaxTimeStamp(maxTime);
+ res.setMinTimeStamp(minTime);
+
+ return res;
+ }
+
+ @Override
+ @GET
+ @Path("data")
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML,
MediaType.TEXT_HTML})
+ public Response getMetricDataMulti(@QueryParam("sid") String schedules,
@QueryParam("startTime") long startTime,
+ @QueryParam("endTime") long endTime,
@QueryParam("dataPoints") int dataPoints,
+ @QueryParam("hideEmpty") boolean
hideEmpty, @Context Request request,
+ @Context HttpHeaders headers) {
+
+ if (startTime==0) {
+ endTime = System.currentTimeMillis();
+ startTime = endTime - EIGHT_HOURS;
+ }
+
+ String[] tmp = schedules.split(",");
+ Integer[] scheduleIds = new Integer[tmp.length];
+ try {
+ for (int i = 0; i < tmp.length ; i++)
+ scheduleIds[i] = Integer.parseInt(tmp[i]);
+ }
+ catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Bad input: " +
nfe.getMessage());
+ }
+
+ List<MetricAggregate> resList = new
ArrayList<MetricAggregate>(scheduleIds.length);
+ for (Integer scheduleId : scheduleIds) {
+ MeasurementSchedule sched =
scheduleManager.getScheduleById(caller,scheduleId);
+ if (sched==null)
+ throw new StuffNotFoundException("Schedule with id " +
scheduleId);
+ int definitionId = sched.getDefinition().getId();
+ List<List<MeasurementDataNumericHighLowComposite>> listList =
+ dataManager.findDataForContext(caller,
EntityContext.forResource(sched.getResource().getId()),definitionId,startTime,endTime,dataPoints);
+ if (!listList.isEmpty()) {
+ List<MeasurementDataNumericHighLowComposite> list =
listList.get(0);
+ MetricAggregate ma = fill(list,scheduleId,hideEmpty);
+ resList.add(ma);
+ }
+ else
+ throw new StuffNotFoundException("Metrics for schedule " +
scheduleId);
+ }
+
+ GenericEntity<List<MetricAggregate>> metAgg = new
GenericEntity<List<MetricAggregate>>(resList) {};
+
+ return Response.ok(metAgg).build();
+
+ }
/**
* Return a metric schedule with the respective status codes for cache validation
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
index 44844ae..7e908ad 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/MetricHandlerLocal.java
@@ -18,7 +18,6 @@
*/
package org.rhq.enterprise.server.rest;
-import java.io.InputStream;
import java.util.List;
import javax.ejb.Local;
@@ -60,6 +59,17 @@ public interface MetricHandlerLocal {
@Context Request request,
@Context HttpHeaders headers);
+ @GET
+ @Path("data")
+
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML,MediaType.TEXT_HTML})
+ Response getMetricDataMulti(@QueryParam("sid") String scheduleIds,
+ @QueryParam("startTime") long startTime,
+ @QueryParam("endTime") long endTime,
+ @QueryParam("dataPoints") int dataPoints,
+ @QueryParam("hideEmpty") boolean hideEmpty,
+ @Context Request request,
+ @Context HttpHeaders headers);
+
@GET
@Path("data/resource/{resourceId}")
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/MetricAggregate.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/MetricAggregate.java
index d6af76e..16b6d40 100644
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/MetricAggregate.java
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/rest/domain/MetricAggregate.java
@@ -41,15 +41,17 @@ public class MetricAggregate {
long maxTimeStamp;
public MetricAggregate() {
+ dataPoints = new ArrayList<DataPoint>();
}
public MetricAggregate(Integer scheduleId, double min, double avg, double max) {
+ this();
this.scheduleId = scheduleId;
this.min = min;
this.avg = avg;
this.max = max;
- dataPoints = new ArrayList<DataPoint>();
+
}
@XmlElement