All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.orange.ngsi.server.NgsiRestBaseController Maven / Gradle / Ivy

There is a newer version: 0.1.3
Show newest version
/*
 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 deleteSubscription(
            @PathVariable String subscriptionID,
            HttpServletRequest httpServletRequest) throws Exception {
        registerIntoDispatcher(httpServletRequest);
        return new ResponseEntity<>(deleteSubscription(subscriptionID), HttpStatus.OK);
    }

    /*
     * Exception handling
     */

    @ExceptionHandler({MissingRequestParameterException.class})
    public ResponseEntity 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 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 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 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 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 errorResponse(String path, StatusCode statusCode) {
        return new ResponseEntity(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_JSON_VALUE)) {
            protocolRegistry.registerHost(uri, true);
        }
    }
}