diff --git a/src/main/java/edu/kit/scc/CdmiRestController.java b/src/main/java/edu/kit/scc/CdmiRestController.java index f43da78..5fc769a 100644 --- a/src/main/java/edu/kit/scc/CdmiRestController.java +++ b/src/main/java/edu/kit/scc/CdmiRestController.java @@ -22,7 +22,6 @@ import org.snia.cdmiserver.dao.CdmiObjectDao; import org.snia.cdmiserver.dao.ContainerDao; import org.snia.cdmiserver.dao.DataObjectDao; -import org.snia.cdmiserver.exception.BadRequestException; import org.snia.cdmiserver.model.Capability; import org.snia.cdmiserver.model.CdmiObject; import org.snia.cdmiserver.model.Container; @@ -44,10 +43,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.HandlerMapping; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Enumeration; -import java.util.Iterator; import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -143,11 +139,21 @@ public ResponseEntity getCapabilities( (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); log.debug("Requested capabilities path {}", path); + String query = request.getQueryString(); + log.debug("Requested capabilities query {}", query); + Capability capability = capabilityDao.findByPath(path); if (capability != null) { - return new ResponseEntity(capability.toJson().toString(), responseHeaders, - HttpStatus.OK); + JSONObject capabilityJson = capability.toJson(); + + if (query != null) { + return new ResponseEntity(filterQueryFields(capabilityJson, query).toString(), + responseHeaders, HttpStatus.OK); + } else { + return new ResponseEntity(capabilityJson.toString(), responseHeaders, + HttpStatus.OK); + } } return new ResponseEntity("Capabilities not found", responseHeaders, @@ -362,83 +368,6 @@ public ResponseEntity deleteCdmiObject( return new ResponseEntity("Not found", responseHeaders, HttpStatus.NOT_FOUND); } - @SuppressWarnings("unused") - private String[] parseFields(HttpServletRequest request) { - Enumeration attributes = request.getParameterNames(); - String[] requestedFields = null; - while (attributes.hasMoreElements()) { - String attributeName = attributes.nextElement(); - requestedFields = attributeName.split(";"); - } - return requestedFields; - } - - @SuppressWarnings("unused") - private JSONObject getRequestedJson(JSONObject object, String[] requestedFields) { - JSONObject requestedJson = new JSONObject(); - try { - for (int i = 0; i < requestedFields.length; i++) { - String field = requestedFields[i]; - if (!field.contains(":")) { - requestedJson.put(field, object.get(field)); - } else { - String[] fieldsplit = field.split(":"); - if (object.get(fieldsplit[0]) instanceof JSONObject) { - JSONObject fieldObject = new JSONObject(); - String prefix = fieldsplit[1]; - String fieldname = fieldsplit[0]; - if (requestedJson.has(fieldname)) { - fieldObject = requestedJson.getJSONObject(fieldname); - } - Iterator keys = object.getJSONObject(fieldname).keys(); - while (keys.hasNext()) { - String key = (String) keys.next(); - if (key.startsWith(prefix)) { - fieldObject.put(key, object.getJSONObject(fieldname).get(key)); - } - } - if (fieldObject.length() != 0) { - requestedJson.put(fieldname, fieldObject); - } - } else if (field.startsWith("children:")) { - String range = field.split("children:")[1]; - String[] rangeSplit = range.split("-"); - List requestedChildren = new ArrayList(); - JSONArray children = object.getJSONArray("children"); - int startIndex = Integer.valueOf(rangeSplit[0]); - if (rangeSplit.length > 1) { - int endIndex = Integer.valueOf(rangeSplit[1]); - for (int j = startIndex; j <= endIndex; j++) { - requestedChildren.add(children.getString(j)); - } - } else { - requestedChildren.add(children.getString(startIndex)); - } - requestedJson.put("children", requestedChildren); - } else if (field.startsWith("value:")) { - String range = field.split("value:")[1]; - String[] rangeSplit = range.split("-"); - requestedJson.put("value", - new String(Arrays.copyOfRange(object.getString("value").getBytes(), - Integer.valueOf(rangeSplit[0].trim()), Integer.valueOf(rangeSplit[1].trim())))); - } else { - throw new BadRequestException("Bad prefix"); - } - - } - } - if (requestedJson.has("childrenrange") && requestedJson.has("children")) { - requestedJson.put("childrenrange", - "0-" + String.valueOf(requestedJson.getJSONArray("children").length() - 1)); - } - } catch (JSONException e) { - throw new BadRequestException("bad field"); - } catch (IndexOutOfBoundsException | NumberFormatException e) { - throw new BadRequestException("bad range"); - } - return requestedJson; - } - /** * Verifies the authorization according to the authorization header. * @@ -480,4 +409,58 @@ public boolean verifyAuthorization(String authorizationHeader) { return false; } + /** + * Filters the requested JSON object according to the query parameters. + * + * @param json the requested {@link JSONObject} + * @param query the given query parameters + * @return the filtered {@link JSONObject} + */ + public JSONObject filterQueryFields(JSONObject json, String query) { + String[] queryFields = query.split(";"); + List queryList = Arrays.asList(queryFields); + + JSONArray names = json.names(); + JSONArray children = json.optJSONArray("children"); + + for (int i = 0; i < names.length(); i++) { + String name = names.getString(i); + if (!queryList.contains(name)) { + json.remove(name); + } + } + + if (children != null) { + for (String queryField : queryList) { + if (queryField.contains("children:")) { + String[] childrenRange = queryField.split(":"); + String range = childrenRange[1]; + String[] rangeValues = range.split("-"); + + JSONArray returnChildren = new JSONArray(); + int rangeStart = Integer.valueOf(rangeValues[0]); + + if (rangeValues.length > 1) { + int rangeStop = Integer.valueOf(rangeValues[1]); + for (int i = rangeStart; i <= rangeStop; i++) { + try { + returnChildren.put(children.get(i)); + } catch (JSONException ex) { + log.warn("Requested range out of bounds, {}", i); + } + } + } else { + try { + returnChildren.put(children.get(rangeStart)); + } catch (JSONException ex) { + log.warn("Requested range out of bounds, {}", rangeStart); + } + } + json.put("children", returnChildren); + break; + } + } + } + return json; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1737eea..08ea26c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,7 +5,7 @@ spring.profiles.active=filesystem # LOGGING logging.level.edu.kit.scc=DEBUG logging.level.org.snia.cdmiserver=TRACE -logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n +logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %clr(%5p) %c{1}:%L - %m%n # SERVER server.port: 8080 diff --git a/src/test/java/edu/kit/scc/cdmi/rest/FilterJsonTest.java b/src/test/java/edu/kit/scc/cdmi/rest/FilterJsonTest.java new file mode 100644 index 0000000..24c5adf --- /dev/null +++ b/src/test/java/edu/kit/scc/cdmi/rest/FilterJsonTest.java @@ -0,0 +1,240 @@ +/* + * Copyright 2016 Karlsruhe Institute of Technology (KIT) + * + * 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 + */ + +package edu.kit.scc.cdmi.rest; + +import static org.junit.Assert.assertTrue; + +import edu.kit.scc.CdmiRestController; +import edu.kit.scc.CdmiServerApplication; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.snia.cdmiserver.model.Capability; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = CdmiServerApplication.class) +public class FilterJsonTest { + + private static final Logger log = LoggerFactory.getLogger(FilterJsonTest.class); + + @Autowired + private CdmiRestController controller; + + @Test + public void testQueryNoParamter() { + String query = ""; + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.length() == 0); + } + + @Test + public void testQueryOneParameter() { + String query = "objectID"; + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("objectID")); + } + + @Test + public void testQueryMultipleParameter() { + String query = "objectID;metadata;objectName"; + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("objectID")); + assertTrue(filteredJson.has("metadata")); + assertTrue(filteredJson.has("objectName")); + } + + @Test + public void testQueryOneWrongParameter() { + String query = "objectId"; + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.length() == 0); + } + + @Test + public void testQueryMixedWrongParameter() { + String query = "objectID;invalid"; + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("objectID")); + } + + @Test + public void testQueryChildren() { + String query = "children"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("children")); + } + + @Test + public void testQueryMixedChildren() { + String query = "children;objectID"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("objectID")); + assertTrue(filteredJson.has("children")); + } + + @Test + public void testQueryChildrenRange() { + String query = "children:0-1"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("children")); + assertTrue(filteredJson.getJSONArray("children").length() == 2); + + JSONArray returnChildren = filteredJson.getJSONArray("children"); + assertTrue(returnChildren.get(0).equals("child1")); + assertTrue(returnChildren.get(1).equals("child2")); + } + + @Test + public void testQueryOneChildren() { + String query = "children:1"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("children")); + assertTrue(filteredJson.getJSONArray("children").length() == 1); + + JSONArray returnChildren = filteredJson.getJSONArray("children"); + assertTrue(returnChildren.get(0).equals("child2")); + } + + @Test + public void testQueryMixedChildrenRange() { + String query = "objectID;children:0-1"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("children")); + assertTrue(filteredJson.has("objectID")); + assertTrue(filteredJson.getJSONArray("children").length() == 2); + + JSONArray returnChildren = filteredJson.getJSONArray("children"); + assertTrue(returnChildren.get(0).equals("child1")); + assertTrue(returnChildren.get(1).equals("child2")); + } + + @Test + public void testQueryChildrenOneOutOfRange() { + String query = "objectID;children:3"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + // assertTrue(!filteredJson.has("children")); + assertTrue(filteredJson.has("objectID")); + } + + @Test + public void testQueryChildrenOutOfRange() { + String query = "objectID;children:0-3"; + JSONArray children = new JSONArray(); + children.put("child1"); + children.put("child2"); + + Capability capability = new Capability("newProfile", "/cdmi_capabilities", "parentId"); + capability.setChildren(children); + + log.debug("Test filter JSON with {}", capability.toJson().toString()); + JSONObject filteredJson = controller.filterQueryFields(capability.toJson(), query); + log.debug("Filtered JSON {}", filteredJson.toString()); + + assertTrue(filteredJson.has("children")); + assertTrue(filteredJson.has("objectID")); + assertTrue(filteredJson.getJSONArray("children").length() == 2); + + JSONArray returnChildren = filteredJson.getJSONArray("children"); + assertTrue(returnChildren.get(0).equals("child1")); + assertTrue(returnChildren.get(1).equals("child2")); + } +} diff --git a/src/test/java/edu/kit/scc/cdmi/rest/RestTestSuite.java b/src/test/java/edu/kit/scc/cdmi/rest/RestTestSuite.java index a24d746..34c9279 100644 --- a/src/test/java/edu/kit/scc/cdmi/rest/RestTestSuite.java +++ b/src/test/java/edu/kit/scc/cdmi/rest/RestTestSuite.java @@ -24,8 +24,8 @@ import java.util.Properties; @RunWith(Suite.class) -@Suite.SuiteClasses({AuthorizationTest.class, CapabilitiesTest.class, CdmiObjectTest.class, - ContainerTest.class, DataObjectTest.class, DomainTest.class}) +@Suite.SuiteClasses({AuthorizationTest.class, FilterJsonTest.class, CapabilitiesTest.class, + CdmiObjectTest.class, ContainerTest.class, DataObjectTest.class, DomainTest.class}) public class RestTestSuite { @AfterClass