Java tutorial
/* * Copyright (C) 2015 Orange * * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.orange.ngsi.server; import com.orange.ngsi.ProtocolRegistry; import com.orange.ngsi.exception.MismatchIdException; import com.orange.ngsi.exception.MissingRequestParameterException; import com.orange.ngsi.model.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; /** * Controller for the NGSI 9/10 convenient REST requests * Deviation from standard: * - no support for attributeDomains requests * - only NGSI 10 REST requests are supported */ public class NgsiRestBaseController { private static Logger logger = LoggerFactory.getLogger(NgsiRestBaseController.class); @Autowired private NgsiValidation ngsiValidation; @Autowired private ProtocolRegistry protocolRegistry; /* Context Entities */ @RequestMapping(method = RequestMethod.POST, value = { "/contextEntities/{entityID}", "/contextEntities/{entityID}/attributes" }, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<AppendContextElementResponse> appendContextElement(@PathVariable String entityID, @RequestBody AppendContextElement appendContextElement, HttpServletRequest httpServletRequest) throws Exception { ngsiValidation.checkAppendContextElement(appendContextElement); registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(appendContextElement(entityID, appendContextElement), HttpStatus.OK); } @RequestMapping(method = RequestMethod.PUT, value = { "/contextEntities/{entityID}", "/contextEntities/{entityID}/attributes" }, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<UpdateContextElementResponse> updateContextEntity(@PathVariable String entityID, @RequestBody UpdateContextElement updateContextElement, HttpServletRequest httpServletRequest) throws Exception { ngsiValidation.checkUpdateContextElement(updateContextElement); registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(updateContextElement(entityID, updateContextElement), HttpStatus.OK); } @RequestMapping(method = RequestMethod.GET, value = { "/contextEntities/{entityID}", "/contextEntities/{entityID}/attributes" }) final public ResponseEntity<ContextElementResponse> getContextEntity(@PathVariable String entityID, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(getContextElement(entityID), HttpStatus.OK); } @RequestMapping(method = RequestMethod.DELETE, value = { "/contextEntities/{entityID}", "/contextEntities/{entityID}/attributes" }) final public ResponseEntity<StatusCode> deleteContextEntity(@PathVariable String entityID, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(deleteContextElement(entityID), HttpStatus.OK); } /* Context Attributes */ @RequestMapping(method = RequestMethod.POST, value = "/contextEntities/{entityID}/attributes/{attributeName}", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<StatusCode> appendContextAttributeValue(@PathVariable String entityID, @PathVariable String attributeName, @RequestBody UpdateContextAttribute updateContextAttribute, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); ngsiValidation.checkUpdateContextAttribute(entityID, attributeName, null, updateContextAttribute); return new ResponseEntity<>(appendContextAttribute(entityID, attributeName, updateContextAttribute), HttpStatus.OK); } @RequestMapping(method = RequestMethod.PUT, value = "/contextEntities/{entityID}/attributes/{attributeName}", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<StatusCode> updateContextAttribute(@PathVariable String entityID, @PathVariable String attributeName, @RequestBody UpdateContextAttribute updateContextAttribute, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); ngsiValidation.checkUpdateContextAttribute(entityID, attributeName, null, updateContextAttribute); return new ResponseEntity<>(updateContextAttribute(entityID, attributeName, updateContextAttribute), HttpStatus.OK); } @RequestMapping(method = RequestMethod.GET, value = "/contextEntities/{entityID}/attributes/{attributeName}") final public ResponseEntity<ContextAttributeResponse> getContextAttribute(@PathVariable String entityID, @PathVariable String attributeName, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(getContextAttribute(entityID, attributeName), HttpStatus.OK); } @RequestMapping(method = RequestMethod.DELETE, value = "/contextEntities/{entityID}/attributes/{attributeName}") final public ResponseEntity<StatusCode> deleteContextAttribute(@PathVariable String entityID, @PathVariable String attributeName, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(deleteContextAttribute(entityID, attributeName), HttpStatus.OK); } /* Context Attributes Value instances */ @RequestMapping(method = RequestMethod.PUT, value = "/contextEntities/{entityID}/attributes/{attributeName}/{valueID}", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<StatusCode> updateContextAttributeValue(@PathVariable String entityID, @PathVariable String attributeName, @PathVariable String valueID, @RequestBody UpdateContextAttribute updateContextAttribute, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); ngsiValidation.checkUpdateContextAttribute(entityID, attributeName, valueID, updateContextAttribute); return new ResponseEntity<>( updateContextAttributeValue(entityID, attributeName, valueID, updateContextAttribute), HttpStatus.OK); } @RequestMapping(method = RequestMethod.GET, value = "/contextEntities/{entityID}/attributes/{attributeName}/{valueID}") final public ResponseEntity<ContextAttributeResponse> getContextAttributeValue(@PathVariable String entityID, @PathVariable String attributeName, @PathVariable String valueID, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(getContextAttributeValue(entityID, attributeName, valueID), HttpStatus.OK); } @RequestMapping(method = RequestMethod.DELETE, value = "/contextEntities/{entityID}/attributes/{attributeName}/{valueID}") final public ResponseEntity<StatusCode> deleteContextAttributeValue(@PathVariable String entityID, @PathVariable String attributeName, @PathVariable String valueID, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(deleteContextAttributeValue(entityID, attributeName, valueID), HttpStatus.OK); } /* Entity types */ @RequestMapping(method = RequestMethod.GET, value = { "/contextEntityTypes/{typeName}", "/contextEntityTypes/{typeName}/attributes" }) final public ResponseEntity<QueryContextResponse> getContextEntityTypes(@PathVariable String typeName, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(getContextEntitiesType(typeName), HttpStatus.OK); } @RequestMapping(method = RequestMethod.GET, value = "/contextEntityTypes/{typeName}/attributes/{attributeName}") final public ResponseEntity<QueryContextResponse> getContextEntityTypes(@PathVariable String typeName, @PathVariable String attributeName, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(getContextEntitiesType(typeName, attributeName), HttpStatus.OK); } /* Subscriptions */ @RequestMapping(method = RequestMethod.POST, value = "/contextSubscriptions", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<SubscribeContextResponse> createSubscription( @RequestBody SubscribeContext subscribeContext, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); ngsiValidation.checkSubscribeContext(subscribeContext); return new ResponseEntity<>(createSubscription(subscribeContext), HttpStatus.OK); } @RequestMapping(method = RequestMethod.PUT, value = "/contextSubscriptions/{subscriptionID}", consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) final public ResponseEntity<UpdateContextSubscriptionResponse> updateSubscription( @PathVariable String subscriptionID, @RequestBody UpdateContextSubscription updateContextSubscription, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); ngsiValidation.checkUpdateSubscription(subscriptionID, updateContextSubscription); return new ResponseEntity<>(updateSubscription(updateContextSubscription), HttpStatus.OK); } @RequestMapping(method = RequestMethod.DELETE, value = "/contextSubscriptions/{subscriptionID}") final public ResponseEntity<UnsubscribeContextResponse> deleteSubscription(@PathVariable String subscriptionID, HttpServletRequest httpServletRequest) throws Exception { registerIntoDispatcher(httpServletRequest); return new ResponseEntity<>(deleteSubscription(subscriptionID), HttpStatus.OK); } /* * Exception handling */ @ExceptionHandler({ MissingRequestParameterException.class }) public ResponseEntity<Object> missingParameter(HttpServletRequest req, MissingRequestParameterException missingException) { logger.error("Missing parameter: {}", missingException.getParameterName()); StatusCode statusCode = new StatusCode(CodeEnum.CODE_471, missingException.getParameterName(), missingException.getParameterType()); return errorResponse(req.getRequestURI(), statusCode); } @ExceptionHandler({ HttpMessageNotReadableException.class }) public ResponseEntity<Object> messageNotReadableExceptionHandler(HttpServletRequest req, HttpMessageNotReadableException exception) { logger.error("Message not readable: {}", exception.toString()); return errorResponse(req.getRequestURI(), new StatusCode(CodeEnum.CODE_400)); } @ExceptionHandler({ UnsupportedOperationException.class }) public ResponseEntity<Object> unsupportedOperation(HttpServletRequest req, UnsupportedOperationException exception) { logger.error("Unsupported operation: {}", exception.toString()); return errorResponse(req.getRequestURI(), new StatusCode(CodeEnum.CODE_403)); } @ExceptionHandler({ MismatchIdException.class }) public ResponseEntity<Object> mismatchIdException(HttpServletRequest req, MismatchIdException exception) { logger.error("Mismatch id: {}", exception.toString()); return errorResponse(req.getRequestURI(), new StatusCode(CodeEnum.CODE_472, exception.getParameterId())); } @ExceptionHandler({ Exception.class }) public ResponseEntity<Object> exceptionHandler(HttpServletRequest req, Exception exception) { logger.error("Exception handler: {}", exception); return errorResponse(req.getRequestURI(), new StatusCode(CodeEnum.CODE_500)); } /* * Methods overridden by child classes to handle the NGSI v1 convenient REST requests */ protected AppendContextElementResponse appendContextElement(String entityID, AppendContextElement appendContextElement) throws Exception { throw new UnsupportedOperationException("appendContextElement"); } protected UpdateContextElementResponse updateContextElement(String entityID, UpdateContextElement updateContextElement) throws Exception { throw new UnsupportedOperationException("updateContextElement"); } protected ContextElementResponse getContextElement(String entityID) throws Exception { throw new UnsupportedOperationException("getContextElement"); } protected StatusCode deleteContextElement(String entityID) throws Exception { throw new UnsupportedOperationException("deleteContextElement"); } protected StatusCode appendContextAttribute(String entityID, String attributeName, UpdateContextAttribute updateContextAttribute) throws Exception { throw new UnsupportedOperationException("appendContextAttribute"); } protected StatusCode updateContextAttribute(final String entityID, String attributeName, UpdateContextAttribute updateContextElementRequest) throws Exception { throw new UnsupportedOperationException("updateContextAttribute"); } protected ContextAttributeResponse getContextAttribute(String entityID, String attributeName) throws Exception { throw new UnsupportedOperationException("getContextAttribute"); } protected StatusCode deleteContextAttribute(String entityID, String attributeName) throws Exception { throw new UnsupportedOperationException("deleteContextAttribute"); } protected StatusCode updateContextAttributeValue(final String entityID, String attributeName, String valueID, UpdateContextAttribute updateContextElementRequest) throws Exception { throw new UnsupportedOperationException("updateContextAttributeValue"); } protected ContextAttributeResponse getContextAttributeValue(String entityID, String attributeName, String valueID) throws Exception { throw new UnsupportedOperationException("getContextAttributeValue"); } protected StatusCode deleteContextAttributeValue(String entityID, String attributeName, String valueID) throws Exception { throw new UnsupportedOperationException("deleteContextAttributeValue"); } protected QueryContextResponse getContextEntitiesType(String typeName) throws Exception { throw new UnsupportedOperationException("getContextEntitiesType"); } protected QueryContextResponse getContextEntitiesType(String typeName, String attributeName) throws Exception { throw new UnsupportedOperationException("getContextEntitiesType"); } protected SubscribeContextResponse createSubscription(final SubscribeContext subscribeContext) throws Exception { throw new UnsupportedOperationException("createSubscription"); } protected UpdateContextSubscriptionResponse updateSubscription( UpdateContextSubscription updateContextSubscription) throws Exception { throw new UnsupportedOperationException("updateSubscription"); } protected UnsubscribeContextResponse deleteSubscription(String subscriptionID) throws Exception { throw new UnsupportedOperationException("deleteSubscription"); } /* * Other methods for use by child classes. */ /** * Response for request error. NGSI requests require custom responses with 200 OK HTTP response code. */ protected ResponseEntity<Object> errorResponse(String path, StatusCode statusCode) { return new ResponseEntity<Object>(statusCode, HttpStatus.OK); } /** * Register the host to protocolRegistry if it supports JSON * @param httpServletRequest the request */ private void registerIntoDispatcher(HttpServletRequest httpServletRequest) { String uri = httpServletRequest.getRequestURI(); // Use Accept or fallback to Content-Type if not defined String accept = httpServletRequest.getHeader("Accept"); if (accept == null) { accept = httpServletRequest.getHeader("Content-Type"); } if (accept != null && accept.contains(MediaType.APPLICATION_XML_VALUE)) { protocolRegistry.registerHost(uri); } } }