diff --git a/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.application.extension.api/src/main/java/io/entgra/device/mgt/core/apimgt/application/extension/api/util/APIUtil.java b/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.application.extension.api/src/main/java/io/entgra/device/mgt/core/apimgt/application/extension/api/util/APIUtil.java
index 3be91a559e..3c35514c40 100644
--- a/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.application.extension.api/src/main/java/io/entgra/device/mgt/core/apimgt/application/extension/api/util/APIUtil.java
+++ b/components/apimgt-extensions/io.entgra.device.mgt.core.apimgt.application.extension.api/src/main/java/io/entgra/device/mgt/core/apimgt/application/extension/api/util/APIUtil.java
@@ -51,6 +51,8 @@ public class APIUtil {
private static final String DEFAULT_ENTERPRISE_TAG= "androidforwork";
private static final String DEFAULT_ANALYTICS_MGT_TAG= "analytics_management";
+ private static final String DEFAULT_DEVICE_ORGANIZATION_MGT_TAG= "device_organization_management";
+
public static final String PERMISSION_PROPERTY_NAME = "name";
public static String getAuthenticatedUser() {
@@ -121,6 +123,7 @@ public class APIUtil {
allowedApisTags.add(DEFAULT_ANALYTICS_ARTIFACT_TAG);
allowedApisTags.add(DEFAULT_TRANSPORT_MGT_TAG);
allowedApisTags.add(DEFAULT_ANALYTICS_MGT_TAG);
+ allowedApisTags.add(DEFAULT_DEVICE_ORGANIZATION_MGT_TAG);
// In an environment only super tenant should be capable of calling this API tag
if (PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId() ==
MultitenantConstants.SUPER_TENANT_ID) {
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/pom.xml b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/pom.xml
new file mode 100644
index 0000000000..21fd9d2457
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/pom.xml
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+ device-mgt-extensions
+ io.entgra.device.mgt.core
+ 5.0.40-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api
+ war
+ Entgra IoT - API Device Organization Management API
+ This module extends the API manager's device organization management apis.
+ http://entgra.io
+
+
+
+
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+ maven-war-plugin
+
+ WEB-INF/lib/*cxf*.jar
+ api#device-org#v1.0
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+
+
+
+ jacoco-initialize
+
+ prepare-agent
+
+
+
+ jacoco-site
+ test
+
+ report
+
+
+ ${basedir}/target/coverage-reports/jacoco-unit.exec
+ ${basedir}/target/coverage-reports/site
+
+
+
+
+
+
+
+
+
+ deploy
+
+ compile
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 1.7
+
+
+ compile
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ client
+
+ test
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.2.1
+
+
+ test
+
+ java
+
+
+
+
+
+
+
+
+
+
+
+ org.testng
+ testng
+ test
+
+
+ org.springframework
+ spring-web
+ provided
+
+
+ org.apache.cxf
+ cxf-bundle
+ 3.0.0-milestone2
+ test
+
+
+ org.apache.cxf
+ cxf-bundle-jaxrs
+ provided
+
+
+ commons-httpclient.wso2
+ commons-httpclient
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.utils
+ provided
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.user.mgt
+ provided
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ jcl-over-slf4j
+
+
+
+
+ org.wso2.carbon
+ org.wso2.carbon.logging
+ provided
+
+
+ org.wso2.carbon.identity.inbound.auth.oauth2
+ org.wso2.carbon.identity.oauth.stub
+ provided
+
+
+ org.apache.axis2.wso2
+ axis2-client
+
+
+
+
+ org.json.wso2
+ json
+
+
+ commons-codec.wso2
+ commons-codec
+ provided
+
+
+ io.entgra.device.mgt.core
+ io.entgra.device.mgt.core.device.mgt.extensions.device.organization
+ ${io.entgra.device.mgt.core.version}
+ provided
+
+
+ com.google.code.gson
+ gson
+
+
+ io.swagger
+ swagger-annotations
+
+
+ io.swagger
+ swagger-core
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jaxb-annotations
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.wso2.orbit.com.fasterxml.jackson.core
+ jackson-core
+
+
+
+
+ io.swagger
+ swagger-jaxrs
+
+
+ com.fasterxml.jackson.module
+ jackson-module-jaxb-annotations
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.wso2.orbit.com.fasterxml.jackson.core
+ jackson-core
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ provided
+
+
+ io.entgra.device.mgt.core
+ io.entgra.device.mgt.core.apimgt.annotations
+ provided
+
+
+ org.wso2.orbit.com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ org.hibernate
+ hibernate-validator
+
+
+ javax.ws.rs
+ javax.ws.rs-api
+ provided
+
+
+ javax.ws.rs
+ jsr311-api
+ provided
+
+
+ org.wso2.carbon.commons
+ org.wso2.carbon.application.mgt.stub
+ provided
+
+
+ io.entgra.device.mgt.core
+ io.entgra.device.mgt.core.identity.jwt.client.extension
+ provided
+
+
+ org.wso2.carbon
+ org.wso2.carbon.registry.core
+ provided
+
+
+ org.wso2.carbon.registry
+ org.wso2.carbon.registry.resource
+ provided
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.user.store.count
+ ${carbon.identity.framework.version}
+ provided
+
+
+ org.powermock
+ powermock-module-testng
+ test
+
+
+ org.powermock
+ powermock-api-mockito
+ test
+
+
+ io.entgra.device.mgt.core
+ io.entgra.device.mgt.core.device.mgt.common
+ provided
+
+
+ io.entgra.device.mgt.core
+ io.entgra.device.mgt.core.device.mgt.extensions
+ provided
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.claim.metadata.mgt
+ ${carbon.identity.framework.version}
+ provided
+
+
+ io.entgra.device.mgt.core
+ io.entgra.device.mgt.core.device.mgt.core
+ provided
+
+
+
+
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/ApiOriginFilter.java b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/ApiOriginFilter.java
new file mode 100644
index 0000000000..4d16481e7f
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/ApiOriginFilter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018 - 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you 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 io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class ApiOriginFilter implements Filter {
+
+ 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);
+ }
+
+ public void destroy() {
+ //do nothing
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ //do nothing
+ }
+
+}
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/DeviceOrganizationMgtService.java b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/DeviceOrganizationMgtService.java
new file mode 100644
index 0000000000..cfc669c767
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/DeviceOrganizationMgtService.java
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2018 - 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you 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 io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api;
+
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.util.DeviceOrgConstants;
+import io.entgra.device.mgt.core.apimgt.annotations.Scope;
+import io.entgra.device.mgt.core.apimgt.annotations.Scopes;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.beans.ErrorResponse;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.dto.DeviceOrganization;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Extension;
+import io.swagger.annotations.ExtensionProperty;
+import io.swagger.annotations.Info;
+import io.swagger.annotations.ResponseHeader;
+import io.swagger.annotations.SwaggerDefinition;
+import io.swagger.annotations.Tag;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * This interface defines the RESTful web service endpoints for managing device organizations.
+ */
+
+@SwaggerDefinition(
+ info = @Info(
+ version = "1.0.0",
+ title = "",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = "name", value = "DeviceOrganizationManagement"),
+ @ExtensionProperty(name = "context", value = "/api/device-org/v1.0"),
+ })
+ }
+ ),
+ tags = {
+ @Tag(name = "device_organization_management", description = "Device organization " +
+ "management related REST-API. This can be used to manipulate device organization related details.")
+ }
+)
+
+@Api(value = "Device Organization Management", description = "This API carries all device organization management " +
+ "related operations.")
+@Path("/")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Scopes(scopes = {
+ @Scope(
+ name = "View Device Organization",
+ description = "View Device Organization",
+ key = "dm:device-org:view",
+ roles = {"Internal/devicemgt-user"},
+ permissions = {"/device-mgt/organization/view"}
+ ),
+ @Scope(
+ name = "Add Device Organization",
+ description = "Add Device Organization",
+ key = "dm:device-org:add",
+ roles = {"Internal/devicemgt-user"},
+ permissions = {"/device-mgt/organization/add"}
+ ),
+ @Scope(
+ name = "Modify Device Organization",
+ description = "Modify Device Organization",
+ key = "dm:device-org:modify",
+ roles = {"Internal/devicemgt-user"},
+ permissions = {"/device-mgt/organization/modify"}
+ ),
+ @Scope(
+ name = "Delete Device Organization",
+ description = "Delete Device Organization",
+ key = "dm:device-org:delete",
+ roles = {"Internal/devicemgt-user"},
+ permissions = {"/device-mgt/organization/delete"}
+ ),
+}
+)
+public interface DeviceOrganizationMgtService {
+
+ String SCOPE = DeviceOrgConstants.SCOPE;
+
+ /**
+ * Adds a new device organization.
+ *
+ * @param request The request containing the device organization information.
+ * @return A response indicating the success or failure of the operation.
+ */
+ @POST
+ @ApiOperation(
+ consumes = MediaType.APPLICATION_JSON,
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "POST",
+ value = "Add a new device Organization.",
+ notes = "This endpoint allows you to add a new device organization.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:add")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 201,
+ message = "OK. \n Successfully created the device organization.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response addDeviceOrganization(DeviceOrganization request);
+
+ /**
+ * Retrieves a list of child nodes of a given device node, up to a specified depth.
+ *
+ * @param deviceId The ID of the parent device node.
+ * @param maxDepth The maximum depth of child nodes to retrieve.
+ * @param includeDevice Indicates whether to include device information in the retrieved nodes.
+ * @return A response containing a list of child device nodes.
+ */
+ @GET
+ @Path("children")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Get Child Nodes of a Device Node",
+ notes = "This endpoint allows you to retrieve a list of child nodes of a given device node up to a specified depth.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the child devices.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response getChildrenOfDeviceNode(
+ @ApiParam(value = "The ID of the parent device node.", required = true)
+ @QueryParam("deviceId") int deviceId,
+ @ApiParam(value = "The maximum depth of child nodes to retrieve.", required = true)
+ @QueryParam("maxDepth") int maxDepth,
+ @ApiParam(value = "Indicates whether to include device information in the retrieved nodes.", required = true)
+ @QueryParam("includeDevice") boolean includeDevice
+ );
+
+
+ /**
+ * Retrieves a list of parent nodes of a given device node, up to a specified depth.
+ *
+ * @param deviceId The ID of the child device node.
+ * @param maxDepth The maximum depth of parent nodes to retrieve.
+ * @param includeDevice Indicates whether to include device information in the retrieved nodes.
+ * @return A response containing a list of parent device nodes.
+ */
+ @GET
+ @Path("parents")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Retrieve Parent Nodes of a Device Node",
+ notes = "Get a list of parent nodes of a specified child device node, up to a specified depth.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the parent devices.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response getParentsOfDeviceNode(
+ @ApiParam(value = "The ID of the child device node.", required = true)
+ @QueryParam("deviceId") int deviceId,
+ @ApiParam(value = "The maximum depth of parent nodes to retrieve.", required = true)
+ @QueryParam("maxDepth") int maxDepth,
+ @ApiParam(value = "Indicates whether to include device information in the retrieved nodes.", required = true)
+ @QueryParam("includeDevice") boolean includeDevice);
+
+
+ /**
+ * Retrieves a list of leaf device organizations.
+ *
+ * @return A response containing a list of leaf device organizations.
+ */
+ @GET
+ @Path("leafs")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Retrieve leaf Device Organizations",
+ notes = "Get a list of leaf device organizations.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the all devices.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response getDeviceOrganizationLeafs(
+ @ApiParam(
+ name = "offset",
+ value = "The starting pagination index for the complete list of qualified items",
+ required = false,
+ defaultValue = "0")
+ @DefaultValue("0") @QueryParam("offset")
+ int offset,
+ @ApiParam(
+ name = "limit",
+ value = "Provide how many policy details you require from the starting pagination index/offset.",
+ required = false,
+ defaultValue = "5")
+ @DefaultValue("20") @QueryParam("limit")
+ int limit);
+
+ /**
+ * Retrieves a list of root device organizations.
+ *
+ * @return A response containing a list of root device organizations.
+ */
+ @GET
+ @Path("roots")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Retrieve leaf Device Organizations",
+ notes = "Get a list of leaf device organizations.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the all devices.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response getDeviceOrganizationRoots(
+ @ApiParam(
+ name = "offset",
+ value = "The starting pagination index for the complete list of qualified items",
+ required = false,
+ defaultValue = "0")
+ @DefaultValue("0") @QueryParam("offset")
+ int offset,
+ @ApiParam(
+ name = "limit",
+ value = "Provide how many policy details you require from the starting pagination index/offset.",
+ required = false,
+ defaultValue = "5")
+ @DefaultValue("20") @QueryParam("limit")
+ int limit);
+
+ /**
+ * Retrieves a specific device organization by its organization ID.
+ *
+ * @param organizationId The organization ID of the device organization to retrieve.
+ * @return A response containing the device organization with the specified ID.
+ */
+ @GET
+ @Path("{organizationId}")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Retrieve Device Organization by ID",
+ notes = "Get a specific device organization by its ID.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully fetched the device organization by ID.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response getDeviceOrganizationById(@PathParam("organizationId") int organizationId);
+
+
+ /**
+ * Checks if a device organization with the specified device and parent device IDs already exists.
+ *
+ * @param deviceId The ID of the device.
+ * @param parentDeviceId The ID of the parent device.
+ * @return A response indicating whether the organization exists or not.
+ */
+ @GET
+ @Path("exists/{deviceId}/{parentDeviceId}")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Check Device Organization Existence",
+ notes = "Check if a device organization with the specified device and parent device IDs exists.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfull. The device organization exists.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response isDeviceOrganizationExist(
+ @ApiParam(name = "deviceId", value = "The ID of the child device.", required = true)
+ @PathParam("deviceId") int deviceId,
+ @ApiParam(name = "parentDeviceId", value = "The ID of the parent device.")
+ @PathParam("parentDeviceId") String parentDeviceId);
+
+
+ /**
+ * Retrieve a device organization by its unique key (deviceId and parentDeviceId).
+ *
+ * @param deviceId The ID of the device.
+ * @param parentDeviceId The ID of the parent device.
+ * @return A response containing the retrieved DeviceOrganization object, or null if not found.
+ */
+ @GET
+ @Path("organization/{deviceId}/{parentDeviceId}")
+ @ApiOperation(
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "GET",
+ value = "Get Device Organization by Unique Key",
+ notes = "Retrieve a device organization by its unique key, which is a combination of deviceId and parentDeviceId.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:view")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully retrieved organization details.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description =
+ "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }
+ ),
+ @ApiResponse(
+ code = 400,
+ message =
+ "Bad Request. \n"),
+ @ApiResponse(
+ code = 404,
+ message =
+ "Not Found. \n"),
+ @ApiResponse(
+ code = 406,
+ message = "Not Acceptable.\n The requested media type is not supported"),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n Server error occurred while fetching the " +
+ "list of supported device types.",
+ response = ErrorResponse.class)
+ })
+ Response getDeviceOrganizationByUniqueKey(
+ @ApiParam(name = "deviceId", value = "The ID of the child device.", required = true)
+ @PathParam("deviceId") int deviceId,
+ @ApiParam(name = "parentDeviceId", value = "The ID of the parent device.")
+ @PathParam("parentDeviceId") String parentDeviceId);
+
+ /**
+ * Updates a device organization.
+ *
+ * @param deviceOrganization The updated device organization.
+ * @return A response indicating the success or failure of the operation.
+ */
+ @PUT
+ @ApiOperation(
+ consumes = MediaType.APPLICATION_JSON,
+ produces = MediaType.APPLICATION_JSON,
+ httpMethod = "PUT",
+ value = "Update a Device Organization",
+ notes = "This endpoint allows you to update a device organization.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:modify")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully updated device organization.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description = "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }),
+ @ApiResponse(
+ code = 304,
+ message = "Not Modified. Empty body because the client already has the latest version" +
+ " of the requested resource.\n"),
+ @ApiResponse(
+ code = 400,
+ message = "Bad Request. \n Invalid request or validation error.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 404,
+ message = "Not Found. \n A deviceType with the specified device type was not found.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n " +
+ "Server error occurred while retrieving the device details.",
+ response = ErrorResponse.class)
+ })
+ Response updateDeviceOrganization(
+ @ApiParam(value = "The updated device organization.", required = true)
+ DeviceOrganization deviceOrganization);
+
+
+ /**
+ * Deletes a device organization by its organization ID.
+ *
+ * @param organizationId The organization ID of the device organization to delete.
+ * @return A response indicating the success or failure of the operation.
+ */
+ @DELETE
+ @Path("{organizationId}")
+ @ApiOperation(
+ httpMethod = "DELETE",
+ value = "Delete a Device Organization",
+ notes = "This endpoint allows you to delete a device organization by its organization ID.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:delete")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully deleted the device organization.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description = "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }),
+ @ApiResponse(
+ code = 304,
+ message = "Not Modified. Empty body because the client already has the latest version" +
+ " of the requested resource.\n"),
+ @ApiResponse(
+ code = 400,
+ message = "Bad Request. \n Invalid request or validation error.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 404,
+ message = "Not Found. \n A deviceType with the specified device type was not found.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n " +
+ "Server error occurred while retrieving the device details.",
+ response = ErrorResponse.class)
+ })
+ Response deleteDeviceOrganizationById(
+ @ApiParam(value = "The organization ID of the device organization to delete.", required = true)
+ @PathParam("organizationId") int organizationId);
+
+ /**
+ * Deletes records associated with a particular device ID from the device organization table.
+ * This method deletes records where the provided device ID matches either the deviceID column or
+ * parentDeviceID column in the device organization table.
+ *
+ * @param deviceId The ID of the device for which associations should be deleted.
+ * @return A response indicating the success or failure of the operation.
+ */
+ @DELETE
+ @Path("associations/{deviceId}")
+ @ApiOperation(
+ httpMethod = "DELETE",
+ value = "Delete Device Associations",
+ notes = "This endpoint allows you to delete records associated with a particular device ID from the device organization table.",
+ tags = "Device Organization Management",
+ extensions = {
+ @Extension(properties = {
+ @ExtensionProperty(name = SCOPE, value = "dm:device-org:delete")
+ })
+ }
+ )
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ code = 200,
+ message = "OK. \n Successfully deleted device organizations.",
+ responseHeaders = {
+ @ResponseHeader(
+ name = "Content-Type",
+ description = "The content type of the body"),
+ @ResponseHeader(
+ name = "ETag",
+ description = "Entity Tag of the response resource.\n" +
+ "Used by caches, or in conditional requests."),
+ @ResponseHeader(
+ name = "Last-Modified",
+ description = "Date and time the resource was last modified.\n" +
+ "Used by caches, or in conditional requests."),
+ }),
+ @ApiResponse(
+ code = 304,
+ message = "Not Modified. Empty body because the client already has the latest version" +
+ " of the requested resource.\n"),
+ @ApiResponse(
+ code = 400,
+ message = "Bad Request. \n Invalid request or validation error.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 404,
+ message = "Not Found. \n A deviceType with the specified device type was not found.",
+ response = ErrorResponse.class),
+ @ApiResponse(
+ code = 500,
+ message = "Internal Server Error. \n " +
+ "Server error occurred while retrieving the device details.",
+ response = ErrorResponse.class)
+ })
+ Response deleteDeviceAssociations(
+ @ApiParam(name = "deviceId", value = "The ID of the device for which associations should be deleted.", required = true)
+ @PathParam("deviceId") int deviceId);
+
+
+}
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/DeviceOrganizationMgtServiceImpl.java b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/DeviceOrganizationMgtServiceImpl.java
new file mode 100644
index 0000000000..9a4b2590be
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/DeviceOrganizationMgtServiceImpl.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2018 - 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you 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 io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api;
+
+import com.google.gson.Gson;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.beans.SuccessResponse;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.util.DeviceOrgAPIUtils;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.util.RequestValidationUtil;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.dto.DeviceNodeResult;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.dto.DeviceOrganization;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.dto.PaginationRequest;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.exception.DeviceOrganizationMgtPluginException;
+import io.entgra.device.mgt.core.device.mgt.extensions.device.organization.spi.DeviceOrganizationService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+@Path("/")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class DeviceOrganizationMgtServiceImpl implements DeviceOrganizationMgtService {
+
+ private static final Log log = LogFactory.getLog(DeviceOrganizationMgtServiceImpl.class);
+ private static final Gson gson = new Gson();
+
+ @POST
+ @Override
+ public Response addDeviceOrganization(DeviceOrganization deviceOrganizationRequest) {
+ if (deviceOrganizationRequest == null) {
+ String errorMessage = "The payload of the device organization is incorrect.";
+ log.error(errorMessage);
+ return Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).build();
+ }
+ try {
+ if (
+ deviceOrganizationRequest.getDeviceId() <= 0 ||
+ !(deviceOrganizationRequest.getParentDeviceId() == null ||
+ deviceOrganizationRequest.getParentDeviceId() >= 0)
+ ) {
+ String errorMessage = "The payload of the device organization is incorrect.";
+ return Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).build();
+ }
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ boolean resp = deviceOrganizationService.addDeviceOrganization(deviceOrganizationRequest);
+ SuccessResponse response = new SuccessResponse();
+ response.setSuccess(resp);
+ return Response.status(Response.Status.CREATED).entity(response).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "device organization failed to be created";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @GET
+ @Override
+ @Path("children")
+ public Response getChildrenOfDeviceNode(
+ @QueryParam("deviceId") int deviceId,
+ @QueryParam("maxDepth") int maxDepth,
+ @QueryParam("includeDevice") boolean includeDevice) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ DeviceNodeResult children = deviceOrganizationService.getChildrenOfDeviceNode(deviceId, maxDepth, includeDevice);
+ return Response.status(Response.Status.OK).entity(children).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "get Children of device node failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @GET
+ @Override
+ @Path("parents")
+ public Response getParentsOfDeviceNode(
+ @QueryParam("deviceId") int deviceId,
+ @QueryParam("maxDepth") int maxDepth,
+ @QueryParam("includeDevice") boolean includeDevice) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ DeviceNodeResult parents = deviceOrganizationService.getParentsOfDeviceNode(deviceId, maxDepth, includeDevice);
+ return Response.status(Response.Status.OK).entity(parents).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "get Parent of device node failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @GET
+ @Override
+ @Path("leafs")
+ public Response getDeviceOrganizationLeafs(
+ @DefaultValue("0") @QueryParam("offset") int offset,
+ @DefaultValue("20") @QueryParam("limit") int limit) {
+ RequestValidationUtil.validatePaginationParameters(offset, limit);
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ PaginationRequest request = new PaginationRequest(offset, limit);
+ List organizations = deviceOrganizationService.getDeviceOrganizationLeafs(request);
+ return Response.status(Response.Status.OK).entity(organizations).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "get leaf organizations failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @GET
+ @Path("roots")
+ @Override
+ public Response getDeviceOrganizationRoots(
+ @DefaultValue("0") @QueryParam("offset") int offset,
+ @DefaultValue("20") @QueryParam("limit") int limit) {
+ RequestValidationUtil.validatePaginationParameters(offset, limit);
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ PaginationRequest request = new PaginationRequest(offset, limit);
+ List organizations = deviceOrganizationService.getDeviceOrganizationRoots(request);
+ return Response.status(Response.Status.OK).entity(organizations).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "get root organizations failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @GET
+ @Override
+ @Path("{organizationId}")
+ public Response getDeviceOrganizationById(@PathParam("organizationId") int organizationId) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ DeviceOrganization organization = deviceOrganizationService.getDeviceOrganizationByID(organizationId);
+ return Response.status(Response.Status.OK).entity(organization).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "get organization by organization Id failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @GET
+ @Override
+ @Path("exists/{deviceId}/{parentDeviceId}")
+ public Response isDeviceOrganizationExist(
+ @PathParam("deviceId") int deviceId,
+ @PathParam("parentDeviceId") String parentDeviceId) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ boolean exists;
+ if (parentDeviceId.equals("null")) {
+ exists = deviceOrganizationService.isDeviceOrganizationExist(deviceId, null);
+ } else {
+ exists = deviceOrganizationService.isDeviceOrganizationExist(deviceId, Integer.valueOf(parentDeviceId));
+ }
+ SuccessResponse response = new SuccessResponse();
+ response.setSuccess(exists);
+ return Response.status(Response.Status.OK).entity(response).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "organization existence check for device Id and parent device Id failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ }
+
+
+ @GET
+ @Override
+ @Path("organization/{deviceId}/{parentDeviceId}")
+ public Response getDeviceOrganizationByUniqueKey(
+ @PathParam("deviceId") int deviceId,
+ @PathParam("parentDeviceId") String parentDeviceId) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ DeviceOrganization organization;
+ if (parentDeviceId.equals("null")) {
+ organization = deviceOrganizationService.getDeviceOrganizationByUniqueKey(deviceId, null);
+ } else {
+ organization = deviceOrganizationService.getDeviceOrganizationByUniqueKey(deviceId, Integer.valueOf(parentDeviceId));
+ }
+ return Response.status(Response.Status.OK).entity(organization).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "organization get for device Id and parent device Id failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @PUT
+ @Override
+ public Response updateDeviceOrganization(DeviceOrganization deviceOrganization) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ boolean resp = deviceOrganizationService.updateDeviceOrganization(deviceOrganization);
+ SuccessResponse response = new SuccessResponse();
+ response.setSuccess(resp);
+ return Response.status(Response.Status.OK).entity(response).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "update organization failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @DELETE
+ @Override
+ @Path("{organizationId}")
+ public Response deleteDeviceOrganizationById(@PathParam("organizationId") int organizationId) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ boolean resp = deviceOrganizationService.deleteDeviceOrganizationByID(organizationId);
+ SuccessResponse response = new SuccessResponse();
+ response.setSuccess(resp);
+ return Response.status(Response.Status.OK).entity(response).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "delete organization by organization Id failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+
+ @DELETE
+ @Override
+ @Path("associations/{deviceId}")
+ public Response deleteDeviceAssociations(@PathParam("deviceId") int deviceId) {
+ try {
+ DeviceOrganizationService deviceOrganizationService = DeviceOrgAPIUtils.getDeviceOrganizationService();
+ boolean resp = deviceOrganizationService.deleteDeviceAssociations(deviceId);
+ SuccessResponse response = new SuccessResponse();
+ response.setSuccess(resp);
+ return Response.status(Response.Status.OK).entity(response).build();
+ } catch (DeviceOrganizationMgtPluginException e) {
+ String errorMessage = "delete organizations associated with a device Id failed";
+ log.error(errorMessage);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();
+ }
+ }
+}
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/ErrorListItem.java b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/ErrorListItem.java
new file mode 100644
index 0000000000..9c0bbd8fad
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/ErrorListItem.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 - 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you 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 io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.beans;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+
+@ApiModel(description = "Error List Item")
+public class ErrorListItem {
+
+ @NotNull
+ private String code = null;
+ @NotNull
+ private String message = null;
+
+ @ApiModelProperty(required = true, value = "")
+ @JsonProperty("code")
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public ErrorListItem() {
+ }
+
+ public ErrorListItem(String code, String msg) {
+ this.code = code;
+ this.message = msg;
+ }
+
+
+ /**
+ * Description about individual errors occurred
+ */
+ @ApiModelProperty(required = true, value = "Description about individual errors occurred")
+ @JsonProperty("message")
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("errorItem {\n");
+
+ sb.append(" code: ").append(code).append("\n");
+ sb.append(" message: ").append(message).append("\n");
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+}
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/ErrorResponse.java b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/ErrorResponse.java
new file mode 100644
index 0000000000..c3769f5803
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/ErrorResponse.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2018 - 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you 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 io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.beans;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ApiModel(description = "Error Response")
+public class ErrorResponse {
+
+ private Long code = null;
+ private String message = null;
+ private String description = null;
+ private String moreInfo = null;
+ private List errorItems = new ArrayList<>();
+
+ private ErrorResponse() {
+ }
+
+ @JsonProperty(value = "code")
+ @ApiModelProperty(required = true, value = "")
+ public Long getCode() {
+ return code;
+ }
+
+ public void setCode(Long code) {
+ this.code = code;
+ }
+
+ @JsonProperty(value = "message")
+ @ApiModelProperty(required = true, value = "ErrorResponse message.")
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @JsonProperty(value = "description")
+ @ApiModelProperty(value = "A detail description about the error message.")
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @JsonProperty(value = "moreInfo")
+ @ApiModelProperty(value = "Preferably an url with more details about the error.")
+ public String getMoreInfo() {
+ return moreInfo;
+ }
+
+ public void setMoreInfo(String moreInfo) {
+ this.moreInfo = moreInfo;
+ }
+
+ public void addErrorListItem(ErrorListItem item) {
+ this.errorItems.add(item);
+ }
+
+ /**
+ * If there are more than one error list them out. \nFor example, list out validation errors by each field.
+ */
+ @JsonProperty(value = "errorItems")
+ @ApiModelProperty(value = "If there are more than one error list them out. \n" +
+ "For example, list out validation errors by each field.")
+ public List getErrorItems() {
+ return errorItems;
+ }
+
+ public void setErrorItems(List error) {
+ this.errorItems = error;
+ }
+
+ @Override
+ public String toString() {
+// StringBuilder sb = new StringBuilder();
+// sb.append("{");
+// boolean cont = false;
+// if (code != null) {
+// cont = true;
+// sb.append(" \"code\": ").append(code);
+// }
+// if (message != null) {
+// if (cont) {
+// sb.append(",");
+// }
+// cont = true;
+// sb.append(" \"message\": \"").append(message).append("\"");
+// }
+// if (description != null) {
+// if (cont) {
+// sb.append(",");
+// }
+// cont = true;
+// sb.append(" \"description\": ").append(description).append("\"");
+// }
+// if (moreInfo != null) {
+// if (cont) {
+// sb.append(",");
+// }
+// cont = true;
+// sb.append(" \"moreInfo\": \"").append(moreInfo).append("\"");
+// }
+// if (error != null && error.size() > 0) {
+// if (cont) {
+// sb.append(",");
+// }
+// sb.append(" \"errorItems\": ").append(error);
+// }
+// sb.append("}");
+// return sb.toString();
+ return null;
+ }
+
+ public static class ErrorResponseBuilder {
+
+ private Long code = null;
+ private String message = null;
+ private String description = null;
+ private String moreInfo = null;
+ private List error;
+
+
+ public ErrorResponseBuilder() {
+ this.error = new ArrayList<>();
+ }
+
+ public ErrorResponseBuilder setCode(long code) {
+ this.code = code;
+ return this;
+ }
+
+ public ErrorResponseBuilder setMessage(String message) {
+ this.message = message;
+ return this;
+ }
+
+ public ErrorResponseBuilder setDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
+ public ErrorResponseBuilder setMoreInfo(String moreInfo) {
+ this.moreInfo = moreInfo;
+ return this;
+ }
+
+ public ErrorResponseBuilder addErrorItem(String code, String msg) {
+ ErrorListItem item = new ErrorListItem();
+ item.setCode(code);
+ item.setMessage(msg);
+ this.error.add(item);
+ return this;
+ }
+
+ public ErrorResponse build() {
+ ErrorResponse errorResponse = new ErrorResponse();
+ errorResponse.setCode(code);
+ errorResponse.setMessage(message);
+ errorResponse.setErrorItems(error);
+ errorResponse.setDescription(description);
+ errorResponse.setMoreInfo(moreInfo);
+ return errorResponse;
+ }
+ }
+
+}
+
+
diff --git a/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/GsonMessageBodyHandler.java b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/GsonMessageBodyHandler.java
new file mode 100644
index 0000000000..cd0ee361e7
--- /dev/null
+++ b/components/device-mgt-extensions/io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api/src/main/java/io/entgra/device/mgt/core/device/mgt/extensions/device/organization/api/beans/GsonMessageBodyHandler.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018 - 2023, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
+ *
+ * Entgra (Pvt) Ltd. licenses this file to you 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 io.entgra.device.mgt.core.device.mgt.extensions.device.organization.api.beans;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+@Provider
+@Produces(APPLICATION_JSON)
+@Consumes(APPLICATION_JSON)
+public class GsonMessageBodyHandler implements MessageBodyWriter