Commit f7f438e0 authored by Eduardo Santos's avatar Eduardo Santos
Browse files

Implemented and tested TMF702 API

parent 5655f069
Loading
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -289,6 +289,13 @@
			<artifactId>junit-platform-runner</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-inline</artifactId>
			<version>4.0.0</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
+29 −0
Original line number Diff line number Diff line
/*-
 * ========================LICENSE_START=================================
 * org.etsi.osl.tmf.api
 * %%
 * Copyright (C) 2024 openslice.io
 * %%
 * 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.
 * =========================LICENSE_END==================================
 */

package org.etsi.osl.tmf.ram702.api;

public class ApiException extends Exception{
    private int code;
    public ApiException (int code, String msg) {
        super(msg);
        this.code = code;
    }
}
+50 −0
Original line number Diff line number Diff line
/*-
 * ========================LICENSE_START=================================
 * org.etsi.osl.tmf.api
 * %%
 * Copyright (C) 2024 openslice.io
 * %%
 * 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.
 * =========================LICENSE_END==================================
 */

package org.etsi.osl.tmf.ram702.api;

import java.io.IOException;

import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;

public class ApiOriginFilter implements jakarta.servlet.Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        res.addHeader("Access-Control-Allow-Headers", "Content-Type");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
}
+88 −0
Original line number Diff line number Diff line
/*-
 * ========================LICENSE_START=================================
 * org.etsi.osl.tmf.api
 * %%
 * Copyright (C) 2024 openslice.io
 * %%
 * 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.
 * =========================LICENSE_END==================================
 */

package org.etsi.osl.tmf.ram702.api;

import jakarta.xml.bind.annotation.XmlTransient;

@jakarta.xml.bind.annotation.XmlRootElement
public class ApiResponseMessage {
    public static final int ERROR = 1;
    public static final int WARNING = 2;
    public static final int INFO = 3;
    public static final int OK = 4;
    public static final int TOO_BUSY = 5;

    int code;
    String type;
    String message;

    public ApiResponseMessage(){}

    public ApiResponseMessage(int code, String message){
        this.code = code;
        switch(code){
        case ERROR:
            setType("error");
            break;
        case WARNING:
            setType("warning");
            break;
        case INFO:
            setType("info");
            break;
        case OK:
            setType("ok");
            break;
        case TOO_BUSY:
            setType("too busy");
            break;
        default:
            setType("unknown");
            break;
        }
        this.message = message;
    }

    @XmlTransient
    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
+317 −0
Original line number Diff line number Diff line
/*-
 * ========================LICENSE_START=================================
 * org.etsi.osl.tmf.api
 * %%
 * Copyright (C) 2024 openslice.io
 * %%
 * 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.
 * =========================LICENSE_END==================================
 */

package org.etsi.osl.tmf.ram702.api;

import java.io.IOException;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.etsi.osl.tmf.ri639.model.Resource;
import org.etsi.osl.tmf.ri639.model.ResourceCreate;
import org.etsi.osl.tmf.ri639.model.ResourceUpdate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;

import org.etsi.osl.tmf.ram702.utils.JSONResponseUtils;

@Tag(name = "resource", description = "The resource Activation API")
public interface ResourceActivationApi {

    Logger log = LoggerFactory.getLogger(ResourceActivationApi.class);

    default Optional<ObjectMapper> getObjectMapper() {
        return Optional.empty();
    }

    default Optional<HttpServletRequest> getRequest() {
        return Optional.empty();
    }

    default Optional<String> getAcceptHeader() {
        return getRequest().map(r -> r.getHeader("Accept"));
    }

    @Operation(
        summary = "Creates a Resource",
        operationId = "createResource",
        description = "This operation creates a Resource entity.",
        tags = {"resource"}
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "400", description = "Created"),
        @ApiResponse(responseCode = "400", description = "Bad Request"),
        @ApiResponse(responseCode = "401", description = "Unauthorized"),
        @ApiResponse(responseCode = "403", description = "Forbidden"),
        @ApiResponse(responseCode = "405", description = "Method Not allowed"),
        @ApiResponse(responseCode = "409", description = "Conflict"),
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
    })
    @RequestMapping(
        value = "/resource",
        produces = {"application/json;charset=utf-8"},
        consumes = {"application/json;charset=utf-8"},
        method = RequestMethod.POST
    )
    default ResponseEntity<Resource> createResource(
        Principal principal,
        @Parameter(description = "The Resource to be created", required = true)
        @Valid @RequestBody ResourceCreate body
    ) {
        if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
            if (getAcceptHeader().get().contains("application/json")) {
                try {
                    return new ResponseEntity<>(
                        getObjectMapper().get().readValue(
                            JSONResponseUtils.RESOURCE_JSON_RESPONSE, Resource.class
                        ),
                        HttpStatus.NOT_IMPLEMENTED
                    );
                } catch (IOException e) {
                    log.error(
                        "Couldn't serialize response for content type application/json", e
                    );
                    return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
                }
            }
        } else {
            log.warn(
                "ObjectMapper or HttpServletRequest not configured in default ResourceActivationApi interface so no example is generated"
            );
        }
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }

    @Operation(
        summary = "Deletes a Resource",
        operationId = "deleteResource",
        description = "This operation deletes a Resource entity.",
        tags = {"resource"}
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "204", description = "Deleted"),
        @ApiResponse(responseCode = "400", description = "Bad Request"),
        @ApiResponse(responseCode = "401", description = "Unauthorized"),
        @ApiResponse(responseCode = "403", description = "Forbidden"),
        @ApiResponse(responseCode = "404", description = "Not Found"),
        @ApiResponse(responseCode = "405", description = "Method Not allowed"),
        @ApiResponse(responseCode = "409", description = "Conflict"),
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
    })
    @RequestMapping(
        value = "/resource/{id}",
        produces = {"application/json;charset=utf-8"},
        method = RequestMethod.DELETE
    )
    default ResponseEntity<Void> deleteResource(
        @Parameter(description = "Identifier of the Resource", required = true)
        @PathVariable("id") String id
    ) {
        if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
            // Implementation goes here
        } else {
            log.warn(
                "ObjectMapper or HttpServletRequest not configured in default ResourceActivationApi interface so no example is generated"
            );
        }
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }

    @Operation(
        summary = "List or find Resource objects",
        operationId = "listResource",
        description = "This operation lists or finds Resource entities.",
        tags = {"resource"}
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Success"),
        @ApiResponse(responseCode = "400", description = "Bad Request"),
        @ApiResponse(responseCode = "401", description = "Unauthorized"),
        @ApiResponse(responseCode = "403", description = "Forbidden"),
        @ApiResponse(responseCode = "404", description = "Not Found"),
        @ApiResponse(responseCode = "405", description = "Method Not allowed"),
        @ApiResponse(responseCode = "409", description = "Conflict"),
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
    })
    @RequestMapping(
        value = "/resource",
        produces = {"application/json;charset=utf-8"},
        method = RequestMethod.GET
    )
    default ResponseEntity<List<Resource>> listResource(
        Principal principal,
        @Parameter(description = "Comma-separated properties to be provided in response")
        @Valid @RequestParam(value = "fields", required = false) String fields,
        @Parameter(description = "Requested index for start of resources to be provided in response")
        @Valid @RequestParam(value = "offset", required = false) Integer offset,
        @Parameter(description = "Requested number of resources to be provided in response")
        @Valid @RequestParam(value = "limit", required = false) Integer limit,
        @Parameter(hidden = true) @Valid @RequestParam Map<String, String> allParams
    ) {
        if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
            if (getAcceptHeader().get().contains("application/json")) {
                try {
                    return new ResponseEntity<>(
                        getObjectMapper().get().readValue(
                            JSONResponseUtils.RESOURCE_LIST_JSON_RESPONSE,
                            new TypeReference<List<Resource>>() {}
                        ),
                        HttpStatus.NOT_IMPLEMENTED
                    );
                } catch (IOException e) {
                    log.error(
                        "Couldn't serialize response for content type application/json", e
                    );
                    return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
                }
            }
        } else {
            log.warn(
                "ObjectMapper or HttpServletRequest not configured in default ResourceActivationApi interface so no example is generated"
            );
        }
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }

    @Operation(
        summary = "Updates partially a Resource",
        operationId = "patchResource",
        description = "This operation updates partially a Resource entity.",
        tags = {"resource"}
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Updated"),
        @ApiResponse(responseCode = "400", description = "Bad Request"),
        @ApiResponse(responseCode = "401", description = "Unauthorized"),
        @ApiResponse(responseCode = "403", description = "Forbidden"),
        @ApiResponse(responseCode = "404", description = "Not Found"),
        @ApiResponse(responseCode = "405", description = "Method Not allowed"),
        @ApiResponse(responseCode = "409", description = "Conflict"),
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
    })
    @RequestMapping(
        value = "/resource/{id}",
        produces = {"application/json;charset=utf-8"},
        consumes = {"application/json;charset=utf-8"},
        method = RequestMethod.PATCH
    )
    default ResponseEntity<Resource> patchResource(
        Principal principal,
        @Parameter(description = "The Resource to be updated", required = true)
        @Valid @RequestBody ResourceUpdate body,
        @Parameter(description = "Identifier of the Resource", required = true)
        @PathVariable("id") String id
    ) {
        if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
            if (getAcceptHeader().get().contains("application/json")) {
                try {
                    return new ResponseEntity<>(
                        getObjectMapper().get().readValue(
                            JSONResponseUtils.RESOURCE_JSON_RESPONSE, Resource.class
                        ),
                        HttpStatus.NOT_IMPLEMENTED
                    );
                } catch (IOException e) {
                    log.error(
                        "Couldn't serialize response for content type application/json", e
                    );
                    return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
                }
            }
        } else {
            log.warn(
                "ObjectMapper or HttpServletRequest not configured in default ResourceActivationApi interface so no example is generated"
            );
        }
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }

    @Operation(
        summary = "Retrieves a Resource by ID",
        operationId = "retrieveResource",
        description = "This operation retrieves a Resource entity. Attribute selection is enabled for all first-level attributes.",
        tags = {"resource"}
    )
    @ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "Success"),
        @ApiResponse(responseCode = "400", description = "Bad Request"),
        @ApiResponse(responseCode = "401", description = "Unauthorized"),
        @ApiResponse(responseCode = "403", description = "Forbidden"),
        @ApiResponse(responseCode = "404", description = "Not Found"),
        @ApiResponse(responseCode = "405", description = "Method Not allowed"),
        @ApiResponse(responseCode = "409", description = "Conflict"),
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
    })
    @RequestMapping(
        value = "/resource/{id}",
        produces = {"application/json;charset=utf-8"},
        method = RequestMethod.GET
    )
    default ResponseEntity<Resource> retrieveResource(
        Principal principal,
        @Parameter(description = "Identifier of the Resource", required = true)
        @PathVariable("id") String id,
        @Parameter(description = "Comma-separated properties to provide in response")
        @Valid @RequestParam(value = "fields", required = false) String fields
    ) {
        if (getObjectMapper().isPresent() && getAcceptHeader().isPresent()) {
            if (getAcceptHeader().get().contains("application/json")) {
                try {
                    return new ResponseEntity<>(
                        getObjectMapper().get().readValue(
                            JSONResponseUtils.RESOURCE_JSON_RESPONSE, Resource.class
                        ),
                        HttpStatus.NOT_IMPLEMENTED
                    );
                } catch (IOException e) {
                    log.error(
                        "Couldn't serialize response for content type application/json", e
                    );
                    return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
                }
            }
        } else {
            log.warn(
                "ObjectMapper or HttpServletRequest not configured in default ResourceActivationApi interface so no example is generated"
            );
        }
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }
}
Loading