Implement Device Tagging Feature

release-version-support
Lasantha Dharmakeerthi 3 months ago
commit fa4d466798

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018 - 2024, 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.api.jaxrs.beans;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "TagInfo", description = "Tag details including parameters associated with tags " +
"wrapped here.")
public class TagInfo {
@ApiModelProperty(name = "name", value = "The name of the tag.", required = true)
private String name;
@ApiModelProperty(name = "description", value = "Describes the behavior of the tag.",
required = false)
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018 - 2024, 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.api.jaxrs.beans;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "TagInfoList")
public class TagInfoList extends BasePaginatedResult {
private List<String> tags;
@ApiModelProperty(value = "Returns the list of tags that match the offset and limit parameter values "
+ "that were specified.")
@JsonProperty("tags")
public List<String> getList() {
return tags;
}
public void setList(List<String> tags) {
this.tags = tags;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{\n");
sb.append(" count: ").append(getCount()).append(",\n");
sb.append(" tags: [").append(tags).append("\n");
sb.append("]}\n");
return sb.toString();
}
}

@ -0,0 +1,62 @@
/*
* Copyright (c) 2018 - 2024, 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.api.jaxrs.beans;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "TagMappingInfo", description = "Tag mapping details including parameters associated with " +
"device mapping wrapped here.")
public class TagMappingInfo {
@ApiModelProperty(name = "deviceIdentifiers", value = "Defines the device identifiers.", required = true)
private List<String> deviceIdentifiers;
@ApiModelProperty(name = "deviceType", value = "Defines the device type.", required = true)
private String deviceType;
@ApiModelProperty(name = "tags", value = "Defines the tags.", required = true)
private List<String> tags;
public List<String> getDeviceIdentifiers() {
return deviceIdentifiers;
}
public void setDeviceIdentifiers(List<String> deviceIdentifiers) {
this.deviceIdentifiers = deviceIdentifiers;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
}

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018 - 2024, 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.api.jaxrs.beans;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
@ApiModel(value = "TagMappingInfoList")
public class TagMappingInfoList extends BasePaginatedResult {
private List<String> tagMappings;
@ApiModelProperty(value = "Returns the list of tag mappings that match the offset and "
+ "limit parameter values that were specified.")
@JsonProperty("tagMappings")
public List<String> getList() {
return tagMappings;
}
public void setList(List<String> tagMappings) {
this.tagMappings = tagMappings;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{\n");
sb.append(" count: ").append(getCount()).append(",\n");
sb.append(" tagMappings: [").append(tagMappings).append("\n");
sb.append("]}\n");
return sb.toString();
}
}

@ -64,9 +64,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
/**
* Device related REST-API. This can be used to manipulated device related details.
@ -339,6 +337,12 @@ public interface DeviceManagementService {
required = false)
@QueryParam("requireDeviceInfo")
boolean requireDeviceInfo,
@ApiParam(
name = "tag",
value = "Describes the tags associated with the enrolment",
required = false)
@QueryParam("tag")
List<String> tags,
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.",

@ -0,0 +1,404 @@
/*
* Copyright (c) 2018 - 2024, 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.api.jaxrs.service.api;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.TagInfo;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.TagInfoList;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.TagMappingInfo;
import io.swagger.annotations.*;
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.api.jaxrs.util.Constants;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
@SwaggerDefinition(
info = @Info(
version = "1.0.0",
title = "",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = "name", value = "TagManagement"),
@ExtensionProperty(name = "context", value = "/api/device-mgt/v1.0/tags"),
})
}
),
tags = {
@Tag(name = "device_management")
}
)
@Scopes(
scopes = {
@Scope(
name = "Getting the List of Tags",
description = "Getting the List of Tags",
key = "tm:tags:view",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/view"}
),
@Scope(
name = "Adding a new tag",
description = "Adding a new tag",
key = "tm:tags:create",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/create"}
),
@Scope(
name = "Updating a tag",
description = "Updating a tag",
key = "tm:tags:update",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/update"}
),
@Scope(
name = "Delete a tag",
description = "Delete a tag",
key = "tm:tags:delete",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/delete"}
),
@Scope(
name = "Adding a device tag mapping",
description = "Adding a device-tag mapping",
key = "tm:tags:mapping:create",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/mapping/create"}
),
@Scope(
name = "Deleting a device tag mapping",
description = "Deleting a device-tag mapping",
key = "tm:tags:mapping:delete",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/mapping/delete"}
),
@Scope(
name = "Getting the list of device tag mappings",
description = "Getting the list of device-tag mappings",
key = "tm:tags:mapping:view",
roles = {"Internal/devicemgt-user"},
permissions = {"/device-mgt/tags/mapping/view"}
)
}
)
@Path("/tags")
@Api(value = "Tag Management", description = "Tag management related operations can be found here.")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface TagManagementService {
@GET
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Getting the List of Tags",
notes = "This endpoint is used to retrieve all tags",
tags = "Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:view")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the list of tags.",
response = TagInfoList.class,
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 has been modified the last time.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 304,
message = "Not Modified. \n Empty body because the client already has the latest version of the requested resource."),
@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 list of roles.",
response = ErrorResponse.class)
})
Response getTags();
@POST
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Adding a Tag",
notes = "This endpoint is used to add new tags",
tags = "Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:create")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "Created. \n Successfully created the tag.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The URL to the newly added tag."),
@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 has been modified the last time.\n" +
"Used by caches, or in conditional requests.")}),
@ApiResponse(
code = 303,
message = "See Other. \n The source can be retrieved from the URL specified in the location header.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The Source URL of the document.")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 415,
message = "Unsupported media type. \n The format of the requested entity was not supported.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while adding a new tag.",
response = ErrorResponse.class)
})
Response addTag(
@ApiParam(
name = "tag",
value = "The properties required to add a new tag.",
required = true) List<TagInfo> tags);
@PUT
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "PUT",
value = "Updating a Tag",
notes = "This endpoint is used to update a specific tag",
tags = "Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:update")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully updated the tag.",
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 404,
message = "Not Found. \n The specified tag does not exist.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while updating the tag.",
response = ErrorResponse.class)
})
Response updateTag(
@ApiParam(
name = "tagId",
value = "The ID of the tag to be updated.",
required = false) @QueryParam("tagId") Integer tagId,
@ApiParam(
name = "tagName",
value = "The name of the tag to be updated.",
required = false) @QueryParam("tagName") String tagName,
@ApiParam(
name = "tagInfo",
value = "The properties required to update the tag.",
required = true) TagInfo tagInfo);
@DELETE
@Path("/{tagId}")
@ApiOperation(
httpMethod = "DELETE",
value = "Deleting a Tag",
notes = "This endpoint is used to delete a specific tag",
tags = "Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:delete")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 204,
message = "No Content. \n Successfully deleted the tag."),
@ApiResponse(
code = 404,
message = "Not Found. \n The specified tag does not exist.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while deleting the tag.",
response = ErrorResponse.class)
})
Response deleteTag(
@ApiParam(
name = "tagId",
value = "The ID of the tag to be deleted.",
required = true) @PathParam("tagId") int tagId);
@GET
@Path("/{tagId}")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Getting a Tag by ID",
notes = "This endpoint is used to retrieve tag by id",
tags = "Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:view")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the tag.",
response = Tag.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")}),
@ApiResponse(
code = 404,
message = "Not Found. \n The specified tag does not exist.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while fetching the tag.",
response = ErrorResponse.class)
})
Response getTagById(
@ApiParam(
name = "tagId",
value = "The ID of the tag to be fetched.",
required = true) @PathParam("tagId") int tagId);
@POST
@Path("/mapping")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Adding a Device-Tag Mapping",
notes = "This endpoint is used to map devices with tags",
tags = "Device-Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:mapping:create")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "Created. \n Successfully created the device-tag mapping.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The URL to the newly added device-tag mapping."),
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while adding the device-tag mapping.",
response = ErrorResponse.class)
})
Response addDeviceTagMapping(
@ApiParam(
name = "deviceTagInfo",
value = "The properties required to add a new device-tag mapping.",
required = true) TagMappingInfo tagMappingInfo);
@DELETE
@Path("/mapping")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "DELETE",
value = "Deleting a Device-Tag Mapping",
notes = "This endpoint is used to remove tag mappings from devices",
tags = "Device-Tag Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "tm:tags:mapping:delete")
})
}
)
@ApiResponses(value = {
@ApiResponse(
code = 204,
message = "No Content. \n Successfully deleted the device-tag mapping."),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while deleting the device-tag mapping.",
response = ErrorResponse.class)
})
Response deleteDeviceTagMapping(
@ApiParam(
name = "deviceTagInfo",
value = "The properties required to add a new device-tag mapping.",
required = true) TagMappingInfo tagMappingInfo);
}

@ -151,6 +151,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
@QueryParam("since") String since,
@HeaderParam("If-Modified-Since") String ifModifiedSince,
@QueryParam("requireDeviceInfo") boolean requireDeviceInfo,
@QueryParam("tag") List<String> tags,
@QueryParam("offset") int offset,
@QueryParam("limit") int limit) {
try {
@ -226,6 +227,10 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
return Response.status(Response.Status.OK).entity(devices).build();
}
if (tags != null && !tags.isEmpty()) {
request.setTags(tags);
}
// this is the user who initiates the request
String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername();
if (groupId != 0) {

@ -0,0 +1,218 @@
/*
* Copyright (c) 2018 - 2024, 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.api.jaxrs.service.impl;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.ErrorResponse;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.TagInfo;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.TagMappingInfo;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.api.TagManagementService;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util.RequestValidationUtil;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.util.DeviceMgtAPIUtils;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.BadRequestException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.TagManagementException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.TagNotFoundException;
import io.entgra.device.mgt.core.device.mgt.extensions.logger.spi.EntgraLogger;
import io.entgra.device.mgt.core.notification.logger.impl.EntgraRoleMgtLoggerImpl;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;
@Path("/tags")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class TagManagementServiceImpl implements TagManagementService {
private static final EntgraLogger log = new EntgraRoleMgtLoggerImpl(TagManagementServiceImpl.class);
@GET
@Override
public Response getTags() {
try {
List<Tag> tags = DeviceMgtAPIUtils.getTagManagementService().getAllTags();
return Response.status(Response.Status.OK).entity(tags).build();
} catch (TagManagementException e) {
String msg = "Error occurred while getting tags.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
@POST
@Override
public Response addTag(List<TagInfo> tagInfoList) {
RequestValidationUtil.validateTagListDetails(tagInfoList);
try {
List<Tag> tags = new ArrayList<>();
for (TagInfo tagInfo : tagInfoList) {
Tag tag = new Tag(tagInfo.getName(), tagInfo.getDescription());
tags.add(tag);
}
DeviceMgtAPIUtils.getTagManagementService().addTags(tags);
return Response.status(Response.Status.CREATED).entity(tagInfoList).build();
} catch (TagManagementException e) {
String msg = "Error occurred while adding tags." ;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity
(new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (BadRequestException e) {
String msg = "Error occurred while adding tags. Please check the request" ;
if(log.isDebugEnabled()) {
log.debug(msg, e);
}
return Response.status(Response.Status.BAD_REQUEST).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
}
}
@PUT
@Override
public Response updateTag(@QueryParam("tagId") Integer tagId, @QueryParam("tagName") String tagName, TagInfo tagInfo) {
RequestValidationUtil.validateTagDetails(tagId, tagName, tagInfo);
try {
Tag tag;
if (tagId != null) {
tag = DeviceMgtAPIUtils.getTagManagementService().getTagById(tagId);
} else {
tag = DeviceMgtAPIUtils.getTagManagementService().getTagByName(tagName);
}
if (tag == null) {
String msg = (tagId != null) ? "Tag with ID " + tagId + " is not found."
: "Tag with name " + tagName + " is not found.";
log.error(msg);
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorResponse.ErrorResponseBuilder().
setMessage(msg).build()).build();
}
tag.setName(tagInfo.getName());
tag.setDescription(tagInfo.getDescription());
DeviceMgtAPIUtils.getTagManagementService().updateTag(tag);
return Response.status(Response.Status.OK).entity(tag).build();
} catch (TagManagementException e) {
String msg = (tagId != null) ? "Error occurred while updating tag with ID " + tagId + "."
: "Error occurred while updating tag with name " + tagName + ".";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (TagNotFoundException e) {
String msg = (tagId != null) ? "Tag with ID " + tagId + " is not found."
: "Tag with name " + tagName + " is not found.";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorResponse.ErrorResponseBuilder().
setMessage(msg).build()).build();
} catch (BadRequestException e) {
String msg = (tagId != null) ? "Error occurred while updating tag with ID " + tagId
: "Error occurred while updating tag with name " + tagName;
if(log.isDebugEnabled()) {
log.debug(msg, e);
}
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorResponse.ErrorResponseBuilder().
setMessage(e.getMessage()).build()).build();
}
}
@DELETE
@Path("/{tagId}")
@Override
public Response deleteTag(@PathParam("tagId") int tagId) {
try {
DeviceMgtAPIUtils.getTagManagementService().deleteTag(tagId);
return Response.status(Response.Status.NO_CONTENT).build();
} catch (TagManagementException e) {
String msg = "Error occurred while deleting tag with ID " + tagId + ".";
log.error(msg, e);
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorResponse.ErrorResponseBuilder().
setMessage(msg).build()).build();
} catch (TagNotFoundException e) {
String msg = "Tag with ID " + tagId + " is not found.";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorResponse.ErrorResponseBuilder().
setMessage(e.getMessage()).build()).build();
}
}
@GET
@Path("/{tagId}")
@Override
public Response getTagById(@PathParam("tagId") int tagId) {
try {
Tag tag = DeviceMgtAPIUtils.getTagManagementService().getTagById(tagId);
return Response.status(Response.Status.OK).entity(tag).build();
} catch (TagManagementException e) {
String msg = "Error occurred while getting tag with ID " + tagId + ".";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (TagNotFoundException e) {
String msg = "Tag with ID " + tagId + " is not found.";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
}
}
@POST
@Path("/mapping")
public Response addDeviceTagMapping(TagMappingInfo tagMappingInfo) {
RequestValidationUtil.validateTagMappingDetails(tagMappingInfo);
try {
DeviceMgtAPIUtils.getTagManagementService().addDeviceTagMapping(tagMappingInfo.getDeviceIdentifiers(),
tagMappingInfo.getDeviceType(), tagMappingInfo.getTags());
return Response.status(Response.Status.CREATED).entity(tagMappingInfo).build();
} catch (TagManagementException e) {
String msg = "Error occurred while adding device-tag mapping.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (BadRequestException e) {
String msg = "Error occurred while adding tag mappings.";
if(log.isDebugEnabled()) {
log.debug(msg, e);
}
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
}
}
@DELETE
@Path("/mapping")
public Response deleteDeviceTagMapping(TagMappingInfo tagMappingInfo) {
RequestValidationUtil.validateTagMappingDetails(tagMappingInfo);
try {
DeviceMgtAPIUtils.getTagManagementService().deleteDeviceTagMapping(tagMappingInfo.getDeviceIdentifiers(),
tagMappingInfo.getDeviceType(), tagMappingInfo.getTags());
return Response.status(Response.Status.NO_CONTENT).entity(tagMappingInfo).build();
} catch (TagManagementException e) {
String msg = "Error occurred while deleting tag mappings.";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (BadRequestException e) {
String msg = "Error occurred while deleting tag mappings.";
if(log.isDebugEnabled()) {
log.debug(msg, e);
}
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorResponse.
ErrorResponseBuilder().setMessage(e.getMessage()).build()).build();
}
}
}

@ -19,6 +19,7 @@ package io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.util;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import io.entgra.device.mgt.core.device.mgt.api.jaxrs.beans.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -492,6 +493,70 @@ public class RequestValidationUtil {
}
}
/**
* Validates the provided tag details to ensure that either a valid tagId or a non-empty tagName is provided,
* and that the tagInfo is not null. Throws InputValidationException if any of these conditions are not met.
*
* @param tagId the ID of the tag (must be greater than 0)
* @param tagName the name of the tag (must be non-empty if tagId is not provided)
* @param tagInfo the TagInfo object to validate (must not be null)
* @throws InputValidationException if neither a valid tagId nor a tagName is provided, or if tagInfo is null
*/
public static void validateTagDetails(Integer tagId, String tagName, TagInfo tagInfo) {
if ((tagId == null || tagId <= 0) && StringUtils.isBlank(tagName)) {
String msg = "Either valid tagId or tagName must be provided.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(msg).build());
}
if (tagInfo == null) {
String msg = "Provided request body is empty.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage("Request body is "
+ "empty").build());
}
}
/**
* Validates the provided list of TagInfo objects to ensure that it is not null.
* Throws InputValidationException if the list is null.
*
* @param tagInfo the list of TagInfo objects to validate (must not be null)
* @throws InputValidationException if the list is null
*/
public static void validateTagListDetails(List<TagInfo> tagInfo) {
if (tagInfo == null) {
String msg = "Provided request body is empty.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage("Request body is "
+ "empty").build());
}
}
/**
* Validates the provided TagMappingInfo object to ensure it is not null and contains valid
* device identifiers, device type, and tags. Throws InputValidationException if validation fails.
*
* @param tagMappingInfo the TagMappingInfo object to validate
* @throws InputValidationException if the tagMappingInfo or its required fields are invalid
*/
public static void validateTagMappingDetails(TagMappingInfo tagMappingInfo) {
if (tagMappingInfo == null) {
String msg = "Provided request body is empty.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(400L).setMessage("Request body is empty").build());
} else if (tagMappingInfo.getDeviceIdentifiers() == null || tagMappingInfo.getDeviceType() == null
|| tagMappingInfo.getTags() == null) {
String msg = "Invalid tag mapping request body.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(400L).setMessage("Invalid tag mapping request body").build());
}
}
public static void validateScopes(List<Scope> scopes) {
if (scopes == null || scopes.isEmpty()) {
throw new InputValidationException(

@ -24,6 +24,7 @@ import io.entgra.device.mgt.core.application.mgt.common.services.SubscriptionMan
import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuthorizationService;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.permission.mgt.PermissionManagerServiceImpl;
import io.entgra.device.mgt.core.device.mgt.core.service.TagManagementProviderService;
import io.entgra.device.mgt.core.tenant.mgt.common.spi.TenantManagerAdminService;
import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
@ -65,7 +66,6 @@ import io.entgra.device.mgt.core.device.mgt.common.operation.mgt.Operation;
import io.entgra.device.mgt.core.device.mgt.common.report.mgt.ReportManagementService;
import io.entgra.device.mgt.core.device.mgt.common.spi.DeviceTypeGeneratorService;
import io.entgra.device.mgt.core.device.mgt.common.spi.OTPManagementService;
import io.entgra.device.mgt.core.device.mgt.common.spi.TraccarManagementService;
import io.entgra.device.mgt.core.device.mgt.core.app.mgt.ApplicationManagementProviderService;
import io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.DeviceInformationManager;
import io.entgra.device.mgt.core.device.mgt.core.dto.DeviceTypeVersion;
@ -165,6 +165,7 @@ public class DeviceMgtAPIUtils {
private static volatile APIPublisherService apiPublisher;
private static volatile TenantManagerAdminService tenantManagerAdminService;
private static volatile TagManagementProviderService tagManagementService;
static {
String keyStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Password");
@ -505,6 +506,28 @@ public class DeviceMgtAPIUtils {
return policyManagementService;
}
/**
* Initializing and accessing method for TagManagementService.
*
* @return TagManagementService instance
* @throws IllegalStateException if TagManagementService cannot be initialized
*/
public static TagManagementProviderService getTagManagementService() {
if (tagManagementService == null) {
synchronized (DeviceMgtAPIUtils.class) {
if (tagManagementService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
tagManagementService = (TagManagementProviderService) ctx.getOSGiService(
TagManagementProviderService.class, null);
if (tagManagementService == null) {
throw new IllegalStateException("Tag Management service not initialized.");
}
}
}
}
return tagManagementService;
}
public static PlatformConfigurationManagementService getPlatformConfigurationManagementService() {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
PlatformConfigurationManagementService tenantConfigurationManagementService =

@ -51,6 +51,7 @@
<ref bean="metadataService"/>
<ref bean="whitelabelService"/>
<ref bean="deviceStatusFilterService"/>
<ref bean="tagManagementService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jsonProvider"/>
@ -103,6 +104,7 @@
<bean id="metadataService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.MetadataServiceImpl"/>
<bean id="whitelabelService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.WhiteLabelServiceImpl"/>
<bean id="deviceStatusFilterService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.DeviceStatusFilterServiceImpl"/>
<bean id="tagManagementService" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.service.impl.TagManagementServiceImpl"/>
<!--<bean id="errorHandler" class="io.entgra.device.mgt.core.device.mgt.api.jaxrs.common.ErrorHandler"/>-->
<cxf:bus>

@ -158,7 +158,7 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
}
@ -178,22 +178,22 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null,null, DEFAULT_STATUS_LIST, 1, 0, null, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, null, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, true,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
}
@ -307,7 +307,7 @@ public class DeviceManagementServiceImplTest {
Mockito.when(deviceAccessAuthorizationService.isDeviceAdminUser()).thenReturn(true);
deviceManagementService.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null,
DEFAULT_ROLE, DEFAULT_OWNERSHIP, null,null, DEFAULT_STATUS_LIST, 1,
0, null, null, false, 10, 5);
0, null, null, false, null, 10, 5);
}
@Test(description = "Testing get devices when user is the device admin")
@ -326,11 +326,11 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP
, null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false, 10, 5);
, null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false, null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, null, DEFAULT_USERNAME, DEFAULT_ROLE, DEFAULT_OWNERSHIP
, null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false, 10, 5);
, null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false, null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
}
@ -353,7 +353,7 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, "newuser", null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 0, 0, null, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode());
Mockito.reset(this.deviceAccessAuthorizationService);
}
@ -375,17 +375,17 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 0, 0, null, ifModifiedSince, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 0, 0, null, ifModifiedSince, true,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 0, 0, null, "ErrorModifiedSince",
false, 10, 5);
false, null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
}
@ -406,17 +406,17 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null,DEFAULT_STATUS_LIST, 0, 0, since, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null,DEFAULT_STATUS_LIST, 0, 0, since, null, true,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null,DEFAULT_STATUS_LIST, 0, 0, "ErrorSince", null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode());
}
@ -439,7 +439,7 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false,
10, 5);
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
Mockito.reset(this.deviceManagementProviderService);
}
@ -461,8 +461,8 @@ public class DeviceManagementServiceImplTest {
Response response = this.deviceManagementService
.getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP,
null, null, DEFAULT_STATUS_LIST, 1, 0, null, null, false,
10, 5);
null, null, DEFAULT_STATUS_LIST, 1, 0,null, null, false,
null, 10, 5);
Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
Mockito.reset(this.deviceAccessAuthorizationService);
}

@ -21,7 +21,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;
@ApiModel(value = "EnrolmentInfo", description = "This class carries all information related to a devices enrollment" +
" status.")
@ -61,6 +61,9 @@ public class EnrolmentInfo implements Serializable {
@ApiModelProperty(name = "owner", value = "The device owner's name.", required = true )
private String owner;
@ApiModelProperty(name = "tags", value = "Tags associated with enrolment.", required = false )
private List<String> tags;
public EnrolmentInfo() {
}
@ -134,6 +137,14 @@ public class EnrolmentInfo implements Serializable {
this.owner = owner;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof EnrolmentInfo) {

@ -52,6 +52,7 @@ public class PaginationRequest {
private Map<String, String> customProperty = new HashMap<>();
private Map<String, Object> property = new HashMap<>();
private List<String> statusList = new ArrayList<>();
private List<String> tags = new ArrayList<>();
private OperationLogFilters operationLogFilters = new OperationLogFilters();
private List<SortColumn> sortColumn = new ArrayList<>();
private int deviceTypeId;
@ -199,6 +200,14 @@ public class PaginationRequest {
public List<SortColumn> getSortColumn() { return sortColumn; }
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
/**
* Convert SortColumns field parameter and splitting string into columnName and sortType
*

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018 - 2024, 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.common.tag.mgt;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* DTO of DeviceTag object which is used to manage Device Tags.
*/
@ApiModel(value = "DeviceTag", description = "This is used to manage device tags.")
public class DeviceTag {
@ApiModelProperty(name = "enrolmentId", value = "Defines the device id.", required = true)
private int enrolmentId;
@ApiModelProperty(name = "tagId", value = "Defines the tag id.", required = true)
private int tagId;
public int getEnrolmentId() {
return enrolmentId;
}
public void setEnrolmentId(int enrolmentId) {
this.enrolmentId = enrolmentId;
}
public int getTagId() {
return tagId;
}
public void setTagId(int tagId) {
this.tagId = tagId;
}
}

@ -0,0 +1,85 @@
/*
* Copyright (c) 2018 - 2024, 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.common.tag.mgt;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* DTO of Tag object which is used to manage Tags in devices.
*/
@ApiModel(value = "Tag", description = "This is used to manage tags in devices.")
public class Tag {
@ApiModelProperty(name = "id", value = "Defines the tag ID.", required = false)
private int id;
@ApiModelProperty(name = "name", value = "Defines the tag name.", required = true)
private String name;
@ApiModelProperty(name = "description", value = "Defines the tag description.", required = false)
private String description;
public Tag(String name, String description) {
this.name = name;
this.description = description;
}
public Tag() {}
public Tag(int id, String name, String description) {
this.id = id;
this.name = name;
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "tag {" +
" id= " + id +
", name= '" + name + '\'' +
", description= '" + description + '\'' +
'}';
}
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2018 - 2024, 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.common.tag.mgt;
/**
* Custom exception class to be used in TagManagement related functionalities.
*/
public class TagManagementException extends Exception {
private static final long serialVersionUID = -8933146283800122660L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public TagManagementException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public TagManagementException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public TagManagementException(String msg) {
super(msg);
setErrorMessage(msg);
}
public TagManagementException() {
super();
}
public TagManagementException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,73 @@
/*
* Copyright (c) 2018 - 2024, 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.common.tag.mgt;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
/**
* DTO of TagMapping object which is used to manage Device Tags.
*/
@ApiModel(value = "TagMappingDTO", description = "This is used to manage device tags.")
public class TagMappingDTO {
@ApiModelProperty(name = "deviceIdentifiers", value = "Defines the device identifiers.", required = true)
private List<String> deviceIdentifiers;
@ApiModelProperty(name = "deviceType", value = "Defines the device type.", required = true)
private String deviceType;
@ApiModelProperty(name = "tags", value = "Defines the tag.", required = true)
private List<String> tags;
public TagMappingDTO() {}
public TagMappingDTO(List<String> deviceIdentifiers, String deviceType, List<String> tags) {
this.deviceIdentifiers = deviceIdentifiers;
this.deviceType = deviceType;
this.tags = tags;
}
public List<String> getDeviceIdentifiers() {
return deviceIdentifiers;
}
public void setDeviceIdentifiers(List<String> deviceIdentifiers) {
this.deviceIdentifiers = deviceIdentifiers;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2018 - 2024, 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.common.tag.mgt;
/**
* Custom exception class to be used in TagManagement related functionalities.
*/
public class TagNotFoundException extends Exception {
private static final long serialVersionUID = -8933146283800122660L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public TagNotFoundException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public TagNotFoundException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public TagNotFoundException(String msg) {
super(msg);
setErrorMessage(msg);
}
public TagNotFoundException() {
super();
}
public TagNotFoundException(Throwable cause) {
super(cause);
}
}

@ -171,6 +171,22 @@ public class DeviceManagementDAOFactory {
throw new IllegalStateException("Database engine has not initialized properly.");
}
public static TagDAO getTagDAO() {
if (databaseEngine != null) {
switch (databaseEngine) {
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_POSTGRESQL:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_ORACLE:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MSSQL:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_H2:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MYSQL:
return new TagDAOImpl();
default:
throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
}
}
throw new IllegalStateException("Database engine has not initialized properly.");
}
public static DeviceStatusDAO getDeviceStatusDAO() {
return new DeviceStatusDAOImpl();
}

@ -0,0 +1,130 @@
/*
* Copyright (c) 2018 - 2024, 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.core.dao;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.DeviceTag;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import java.util.List;
/**
* This interface represents the key operations associated with persisting tag related information.
*/
public interface TagDAO {
/**
* Add a new tag.
*
* @param tags to be added.
* @param tenantId of the tag.
* @throws TagManagementDAOException
*/
void addTags(List<Tag> tags, int tenantId) throws TagManagementDAOException;
/**
* Update an existing tag.
*
* @param tag to be updated.
* @param tenantId of the tag.
* @throws TagManagementDAOException
*/
void updateTag(Tag tag, int tenantId) throws TagManagementDAOException;
/**
* Delete an existing tag.
*
* @param tagId of the tag.
* @param tenantId of the tag.
* @throws TagManagementDAOException
*/
void deleteTag(int tagId, int tenantId) throws TagManagementDAOException;
/**
* Get a tag by id.
*
* @param tagId of the tag.
* @param tenantId of the tag.
* @return Tag object.
* @throws TagManagementDAOException
*/
Tag getTagById(int tagId, int tenantId) throws TagManagementDAOException;
/**
* Method to retrieve a tag by its name.
*
* @param tagName - Name of the tag to be retrieved.
* @param tenantId - Tenant ID.
* @return Tag object retrieved from the database.
* @throws TagManagementDAOException if something goes wrong while retrieving the Tag.
*/
Tag getTagByName(String tagName, int tenantId) throws TagManagementDAOException;
/**
* Get all tags for a tenant.
*
* @param tenantId of the tag.
* @return List of all tags.
* @throws TagManagementDAOException
*/
List<Tag> getTags(int tenantId) throws TagManagementDAOException;
/**
* Add a device tag mapping.
*
* @param deviceIdentifiers of the mapping.
* @param deviceType of the mapping.
* @param tagNames of the mapping.
* @param tenantId of the mapping.
* @throws TagManagementDAOException
*/
void addDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tagNames, int tenantId)
throws TagManagementDAOException;
/**
* Delete a device tag mapping.
*
* @param deviceIdentifiers of the mapping.
* @param deviceType of the mapping.
* @param tagNames of the mapping.
* @param tenantId of the mapping.
* @throws TagManagementDAOException
*/
void deleteDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tagNames, int tenantId)
throws TagManagementDAOException;
/**
* Get all device tags for a device.
*
* @param deviceId of the device.
* @param tenantId of the mapping.
* @return List of device tags.
* @throws TagManagementDAOException
*/
List<DeviceTag> getTagsForDevice(int deviceId, int tenantId) throws TagManagementDAOException;
/**
* Get all devices for a tag.
*
* @param tagId of the tag.
* @param tenantId of the mapping.
* @return List of device tags.
* @throws TagManagementDAOException
*/
List<DeviceTag> getDevicesForTag(int tagId, int tenantId) throws TagManagementDAOException;
}

@ -0,0 +1,87 @@
/*
* Copyright (c) 2018 - 2024, 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.core.dao;
/**
* Custom exception class for tag management data access related exceptions.
*/
public class TagManagementDAOException extends Exception {
private static final long serialVersionUID = 2021891706072918864L;
private String message;
private boolean uniqueConstraintViolation;
/**
* Constructs a new exception with the specified detail message and nested exception.
*
* @param message error message
* @param nestedException exception
*/
public TagManagementDAOException(String message, Exception nestedException) {
super(message, nestedException);
setErrorMessage(message);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message.
* @param cause the cause of this exception.
*/
public TagManagementDAOException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message.
*/
public TagManagementDAOException(String message) {
super(message);
setErrorMessage(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause of this exception.
*/
public TagManagementDAOException(Throwable cause) {
super(cause);
}
public TagManagementDAOException(String message, Throwable cause, boolean uniqueConstraintViolation) {
super(message, cause);
setErrorMessage(message);
this.uniqueConstraintViolation = uniqueConstraintViolation;
}
public String getMessage() {
return message;
}
public void setErrorMessage(String errorMessage) {
this.message = errorMessage;
}
public boolean isUniqueConstraintViolation() {
return uniqueConstraintViolation;
}
}

@ -1030,6 +1030,8 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
boolean isStatusProvided = false;
Date since = request.getSince();
boolean isSinceProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
Connection conn = getConnection();
@ -1084,6 +1086,15 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
sql += buildStatusQuery(statusList);
isStatusProvided = true;
}
if (tagList != null && !tagList.isEmpty()) {
sql += " AND e.ID IN ( " +
"SELECT dtm.ENROLMENT_ID " +
"FROM DM_DEVICE_TAG_MAPPING dtm " +
"JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY dtm.ENROLMENT_ID HAVING COUNT(DISTINCT t.NAME) = ? )";
isTagsProvided = true;
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIdx = 1;
@ -1112,6 +1123,12 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
stmt.setString(paramIdx++, status);
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
@ -1300,6 +1317,8 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
boolean isStatusProvided = false;
Date since = request.getSince();
boolean isSinceProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
Connection conn = getConnection();
@ -1342,6 +1361,15 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
sql += buildStatusQuery(statusList);
isStatusProvided = true;
}
if (tagList != null && !tagList.isEmpty()) {
sql += " AND e.ID IN ( " +
"SELECT dtm.ENROLMENT_ID " +
"FROM DM_DEVICE_TAG_MAPPING dtm " +
"JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY dtm.ENROLMENT_ID HAVING COUNT(DISTINCT t.NAME) = ? )";
isTagsProvided = true;
}
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIdx = 1;
@ -1368,6 +1396,12 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
stmt.setString(paramIdx++, status);
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
@ -2942,6 +2976,11 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
return joiner.toString();
}
protected String buildTagQuery(List<String> tagList)
throws DeviceManagementDAOException {
return String.join(", ", Collections.nCopies(tagList.size(), "?"));
}
public int getFunctioningDevicesInSystem() throws DeviceManagementDAOException {
Connection conn;
PreparedStatement stmt = null;

@ -0,0 +1,382 @@
/*
* Copyright (c) 2018 - 2024, 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.core.dao.impl;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.DeviceTag;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import io.entgra.device.mgt.core.device.mgt.core.dao.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static io.entgra.device.mgt.core.device.mgt.core.dao.util.TagManagementDAOUtil.loadDeviceTagMapping;
import static io.entgra.device.mgt.core.device.mgt.core.dao.util.TagManagementDAOUtil.loadTag;
import static io.entgra.device.mgt.core.device.mgt.core.dao.util.TagManagementDAOUtil.cleanupResources;
public class TagDAOImpl implements TagDAO {
private static final Log log = LogFactory.getLog(TagDAOImpl.class);
protected Connection getConnection() throws SQLException {
return DeviceManagementDAOFactory.getConnection();
}
@Override
public void addTags(List<Tag> tags, int tenantId) throws TagManagementDAOException {
String query = "INSERT INTO DM_TAG (NAME, DESCRIPTION, TENANT_ID) " +
"SELECT ?, ?, ? " +
"WHERE NOT EXISTS ( " +
" SELECT 1 FROM DM_TAG " +
" WHERE NAME = ? AND TENANT_ID = ? " +
")";
Connection connection;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
for (Tag tag : tags) {
preparedStatement.setString(1, tag.getName());
preparedStatement.setString(2, tag.getDescription());
preparedStatement.setInt(3, tenantId);
preparedStatement.setString(4, tag.getName());
preparedStatement.setInt(5, tenantId);
preparedStatement.addBatch();
}
int[] updateCounts = preparedStatement.executeBatch();
for (int count : updateCounts) {
if (count == PreparedStatement.EXECUTE_FAILED) {
String msg = "Error occurred while adding tags, adding some tags failed.";
log.error(msg);
throw new TagManagementDAOException(msg);
}
}
} catch (SQLException e) {
String msg = "Error occurred while adding tags.";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, null);
}
}
@Override
public void updateTag(Tag tag, int tenantId) throws TagManagementDAOException {
String query = "UPDATE DM_TAG SET NAME = ?, DESCRIPTION = ? WHERE ID = ? AND TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, tag.getName());
preparedStatement.setString(2, tag.getDescription());
preparedStatement.setInt(3, tag.getId());
preparedStatement.setInt(4, tenantId);
preparedStatement.executeUpdate();
} catch (SQLException e) {
String msg = "Error occurred while updating tag.";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, null);
}
}
@Override
public void deleteTag(int tagId, int tenantId) throws TagManagementDAOException {
String query = "DELETE FROM DM_TAG WHERE ID = ? AND TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, tagId);
preparedStatement.setInt(2, tenantId);
preparedStatement.executeUpdate();
} catch (SQLException e) {
String msg = "Error occurred while deleting tag.";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, null);
}
}
@Override
public Tag getTagById(int tagId, int tenantId) throws TagManagementDAOException {
String query = "SELECT * FROM DM_TAG WHERE ID = ? AND TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Tag tag = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, tagId);
preparedStatement.setInt(2, tenantId);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
tag = loadTag(resultSet);
}
} catch (SQLException e) {
String msg = "Error occurred while getting a specific tag." + tagId;
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, resultSet);
}
return tag;
}
@Override
public Tag getTagByName(String tagName, int tenantId) throws TagManagementDAOException {
String query = "SELECT * FROM DM_TAG WHERE NAME = ? AND TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Tag tag = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, tagName);
preparedStatement.setInt(2, tenantId);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
tag = loadTag(resultSet);
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving tag with name: " + tagName;
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, resultSet);
}
return tag;
}
@Override
public List<Tag> getTags(int tenantId) throws TagManagementDAOException {
String query = "SELECT * FROM DM_TAG WHERE TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<Tag> tags = new ArrayList<>();
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, tenantId);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Tag tag = loadTag(resultSet);
tags.add(tag);
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving tags";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, resultSet);
}
return tags;
}
@Override
public void addDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tagNames, int tenantId) throws TagManagementDAOException {
String deviceIdentifiersPlaceholders = String.join(", ", Collections.nCopies(deviceIdentifiers.size(), "?"));
String tagNamesPlaceholders = String.join(", ", Collections.nCopies(tagNames.size(), "?"));
String query = String.format(
"INSERT INTO DM_DEVICE_TAG_MAPPING (ENROLMENT_ID, TAG_ID, TENANT_ID) " +
"SELECT e.ID, t.ID, ? " +
"FROM DM_ENROLMENT e " +
"JOIN DM_DEVICE d ON d.ID = e.DEVICE_ID " +
"JOIN DM_TAG t ON t.NAME IN (%s) " +
"WHERE d.DEVICE_IDENTIFICATION IN (%s) " +
"AND e.DEVICE_TYPE = ? " +
"AND e.STATUS != 'REMOVED' " +
"AND e.TENANT_ID = ? " +
"AND t.TENANT_ID = ? " +
"AND NOT EXISTS ( " +
" SELECT 1 " +
" FROM DM_DEVICE_TAG_MAPPING m " +
" WHERE m.ENROLMENT_ID = e.ID " +
" AND m.TAG_ID = t.ID " +
" AND m.TENANT_ID = ? " +
")",
tagNamesPlaceholders,
deviceIdentifiersPlaceholders
);
Connection connection;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
int paramIndex = 1;
preparedStatement.setInt(paramIndex++, tenantId);
for (String tagName : tagNames) {
preparedStatement.setString(paramIndex++, tagName);
}
for (String deviceIdentifier : deviceIdentifiers) {
preparedStatement.setString(paramIndex++, deviceIdentifier);
}
preparedStatement.setString(paramIndex++, deviceType);
preparedStatement.setInt(paramIndex++, tenantId);
preparedStatement.setInt(paramIndex++, tenantId);
preparedStatement.setInt(paramIndex, tenantId);
preparedStatement.executeUpdate();
} catch (SQLIntegrityConstraintViolationException e) {
String msg = "Tag is already mapped to this device";
log.error(msg, e);
throw new TagManagementDAOException(msg, e, true);
} catch (SQLException e) {
String msg = "Error occurred while adding device tag mapping";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, null);
}
}
@Override
public void deleteDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tagNames, int tenantId) throws TagManagementDAOException {
String deviceIdentifiersPlaceholders = String.join(", ", Collections.nCopies(deviceIdentifiers.size(), "?"));
String tagNamesPlaceholders = String.join(", ", Collections.nCopies(tagNames.size(), "?"));
String query = String.format(
"DELETE FROM DM_DEVICE_TAG_MAPPING " +
"WHERE ENROLMENT_ID IN ( " +
" SELECT e.ID " +
" FROM DM_ENROLMENT e " +
" JOIN DM_DEVICE d ON d.ID = e.DEVICE_ID " +
" WHERE d.DEVICE_IDENTIFICATION IN (%s) " +
" AND e.DEVICE_TYPE = ? " +
" AND e.TENANT_ID = ? " +
" AND e.STATUS != 'REMOVED' " +
") " +
"AND TAG_ID IN ( " +
" SELECT t.ID " +
" FROM DM_TAG t " +
" WHERE t.NAME IN (%s) " +
" AND t.TENANT_ID = ? " +
")",
deviceIdentifiersPlaceholders,
tagNamesPlaceholders
);
Connection connection;
PreparedStatement preparedStatement = null;
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
int paramIndex = 1;
for (String deviceIdentifier : deviceIdentifiers) {
preparedStatement.setString(paramIndex++, deviceIdentifier);
}
preparedStatement.setString(paramIndex++, deviceType);
preparedStatement.setInt(paramIndex++, tenantId);
for (String tagName : tagNames) {
preparedStatement.setString(paramIndex++, tagName);
}
preparedStatement.setInt(paramIndex, tenantId);
preparedStatement.executeUpdate();
} catch (SQLException e) {
String msg = "Error occurred while deleting device tag mapping";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, null);
}
}
@Override
public List<DeviceTag> getTagsForDevice(int deviceId, int tenantId) throws TagManagementDAOException {
String query = "SELECT * FROM DM_DEVICE_TAG_MAPPING WHERE DEVICE_ID = ? AND TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<DeviceTag> deviceTags = new ArrayList<>();
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, deviceId);
preparedStatement.setInt(2, tenantId);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
DeviceTag deviceTag = loadDeviceTagMapping(resultSet);
deviceTags.add(deviceTag);
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving device tags";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, resultSet);
}
return deviceTags;
}
@Override
public List<DeviceTag> getDevicesForTag(int tagId, int tenantId) throws TagManagementDAOException {
String query = "SELECT * FROM DM_DEVICE_TAG_MAPPING WHERE TAG_ID = ? AND TENANT_ID = ?";
Connection connection;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<DeviceTag> deviceTags = new ArrayList<>();
try {
connection = getConnection();
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, tagId);
preparedStatement.setInt(2, tenantId);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
DeviceTag deviceTag = loadDeviceTagMapping(resultSet);
deviceTags.add(deviceTag);
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving devices for tag";
log.error(msg, e);
throw new TagManagementDAOException(msg, e);
} finally {
cleanupResources(preparedStatement, resultSet);
}
return deviceTags;
}
}

@ -71,6 +71,8 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
Connection conn = getConnection();
@ -86,7 +88,10 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
"e.IS_TRANSFERRED, " +
"e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, " +
"e.ID AS ENROLMENT_ID " +
"e.ID AS ENROLMENT_ID, " +
"( SELECT GROUP_CONCAT(t.NAME ORDER BY t.NAME SEPARATOR ', ') " +
"FROM DM_DEVICE_TAG_MAPPING dtm JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE dtm.ENROLMENT_ID = e.ID ) AS TAGS " +
"FROM DM_ENROLMENT e, " +
"(SELECT d.ID, " +
"d.DESCRIPTION, " +
@ -162,7 +167,21 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
sql += buildStatusQuery(statusList);
isStatusProvided = true;
}
sql = sql + " LIMIT ? OFFSET ?";
sql += " AND e.ID IN (" +
"SELECT e.ID " +
"FROM DM_ENROLMENT e " +
"LEFT JOIN DM_DEVICE_TAG_MAPPING dtm ON e.ID = dtm.ENROLMENT_ID " +
"LEFT JOIN DM_TAG t ON dtm.TAG_ID = t.ID ";
if (tagList != null && !tagList.isEmpty()) {
sql += " WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY e.ID HAVING COUNT(DISTINCT t.NAME) = ? ";
isTagsProvided = true;
} else {
sql += " GROUP BY e.ID ";
}
sql += ") ";
sql += " LIMIT ? OFFSET ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
int paramIdx = 1;
@ -198,13 +217,19 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
stmt.setString(paramIdx++, status);
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
stmt.setInt(paramIdx++, request.getRowCount());
stmt.setInt(paramIdx, request.getStartIndex());
try (ResultSet rs = stmt.executeQuery()) {
devices = new ArrayList<>();
while (rs.next()) {
Device device = DeviceManagementDAOUtil.loadDevice(rs);
Device device = DeviceManagementDAOUtil.loadDevice(rs, true);
devices.add(device);
}
return devices;
@ -667,6 +692,8 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
Connection conn = getConnection();
@ -682,7 +709,10 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
"e.IS_TRANSFERRED, " +
"e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, " +
"e.ID AS ENROLMENT_ID " +
"e.ID AS ENROLMENT_ID, " +
"( SELECT GROUP_CONCAT(t.NAME ORDER BY t.NAME SEPARATOR ', ') " +
"FROM DM_DEVICE_TAG_MAPPING dtm JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE dtm.ENROLMENT_ID = e.ID ) AS TAGS " +
"FROM DM_ENROLMENT e, " +
"(SELECT gd.DEVICE_ID, " +
"gd.DESCRIPTION, " +
@ -739,7 +769,7 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
//Filter Group with serial number or any Custom Property in DM_DEVICE_INFO
if (serial != null || !request.getCustomProperty().isEmpty()) {
if (serial != null) {
sql += "AND EXISTS (" +
sql += " AND EXISTS (" +
"SELECT VALUE_FIELD " +
"FROM DM_DEVICE_INFO di " +
"WHERE di.DEVICE_ID = d1.DEVICE_ID " +
@ -749,7 +779,7 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
}
if (!request.getCustomProperty().isEmpty()) {
for (Map.Entry<String, String> entry : request.getCustomProperty().entrySet()) {
sql += "AND EXISTS (" +
sql += " AND EXISTS (" +
"SELECT VALUE_FIELD " +
"FROM DM_DEVICE_INFO di2 " +
"WHERE di2.DEVICE_ID = d1.DEVICE_ID " +
@ -758,6 +788,18 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
}
}
}
if (tagList != null && !tagList.isEmpty()) {
sql += " AND e.ID IN (" +
"SELECT e.ID " +
"FROM DM_ENROLMENT e " +
"LEFT JOIN DM_DEVICE_TAG_MAPPING dtm ON e.ID = dtm.ENROLMENT_ID " +
"LEFT JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY e.ID HAVING COUNT(DISTINCT t.NAME) = ? ) ";
isTagsProvided = true;
} else {
sql += " GROUP BY e.ID ";
}
sql = sql + " LIMIT ? OFFSET ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -795,13 +837,19 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
stmt.setInt(paramIdx++, request.getRowCount());
stmt.setInt(paramIdx, request.getStartIndex());
try (ResultSet rs = stmt.executeQuery()) {
devices = new ArrayList<>();
while (rs.next()) {
Device device = DeviceManagementDAOUtil.loadDevice(rs);
Device device = DeviceManagementDAOUtil.loadDevice(rs, true);
devices.add(device);
}
return devices;

@ -68,6 +68,8 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
conn = getConnection();
@ -82,7 +84,10 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
"e.IS_TRANSFERRED, " +
"e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, " +
"e.ID AS ENROLMENT_ID " +
"e.ID AS ENROLMENT_ID, " +
"(SELECT STRING_AGG(t.NAME, ', ') FROM DM_DEVICE_TAG_MAPPING dtm " +
"JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE dtm.ENROLMENT_ID = e.ID) AS TAGS " +
"FROM DM_ENROLMENT e, " +
"(SELECT d.ID, " +
"d.DESCRIPTION, " +
@ -155,6 +160,13 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
sql += buildStatusQuery(statusList);
isStatusProvided = true;
}
if (tagList != null && !tagList.isEmpty()) {
sql += " AND e.ID IN (SELECT e.ID FROM DM_ENROLMENT e " +
"LEFT JOIN DM_DEVICE_TAG_MAPPING dtm ON e.ID = dtm.ENROLMENT_ID " +
"LEFT JOIN DM_TAG t ON dtm.TAG_ID = t.ID WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY e.ID HAVING COUNT(DISTINCT t.NAME) = ? ) ";
isTagsProvided = true;
}
sql = sql + " LIMIT ? OFFSET ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -188,6 +200,12 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
stmt.setString(paramIdx++, status);
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
stmt.setInt(paramIdx++, request.getRowCount());
stmt.setInt(paramIdx, request.getStartIndex());
@ -466,6 +484,8 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
conn = getConnection();
@ -480,7 +500,10 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
"e.IS_TRANSFERRED, " +
"e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, " +
"e.ID AS ENROLMENT_ID " +
"e.ID AS ENROLMENT_ID, " +
"(SELECT STRING_AGG(t.NAME, ', ') FROM DM_DEVICE_TAG_MAPPING dtm " +
"JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE dtm.ENROLMENT_ID = e.ID) AS TAGS " +
"FROM DM_ENROLMENT e, " +
"(SELECT gd.DEVICE_ID, " +
"gd.DESCRIPTION, " +
@ -555,6 +578,18 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
}
}
}
if (tagList != null && !tagList.isEmpty()) {
sql += " AND e.ID IN (" +
"SELECT e.ID " +
"FROM DM_ENROLMENT e " +
"LEFT JOIN DM_DEVICE_TAG_MAPPING dtm ON e.ID = dtm.ENROLMENT_ID " +
"LEFT JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY e.ID HAVING COUNT(DISTINCT t.NAME) = ? ) ";
isTagsProvided = true;
} else {
sql += " GROUP BY e.ID ";
}
sql = sql + " LIMIT ? OFFSET ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -592,13 +627,19 @@ public class PostgreSQLDeviceDAOImpl extends GenericDeviceDAOImpl {
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
stmt.setInt(paramIdx++, request.getRowCount());
stmt.setInt(paramIdx, request.getStartIndex());
try (ResultSet rs = stmt.executeQuery()) {
devices = new ArrayList<>();
while (rs.next()) {
Device device = DeviceManagementDAOUtil.loadDevice(rs);
Device device = DeviceManagementDAOUtil.loadDevice(rs, true);
devices.add(device);
}
return devices;

@ -69,6 +69,8 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
conn = getConnection();
@ -83,7 +85,10 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
"e.IS_TRANSFERRED, " +
"e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, " +
"e.ID AS ENROLMENT_ID " +
"e.ID AS ENROLMENT_ID, " +
"(SELECT STRING_AGG(t.NAME, ', ') FROM DM_DEVICE_TAG_MAPPING dtm " +
"JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE dtm.ENROLMENT_ID = e.ID) AS TAGS " +
"FROM DM_ENROLMENT e, " +
"(SELECT d.ID, " +
"d.DESCRIPTION, " +
@ -161,6 +166,13 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
sql += buildStatusQuery(statusList);
isStatusProvided = true;
}
if (tagList!= null && !tagList.isEmpty()) {
sql += " AND e.ID IN (SELECT e.ID FROM DM_ENROLMENT e " +
"LEFT JOIN DM_DEVICE_TAG_MAPPING dtm ON e.ID = dtm.ENROLMENT_ID " +
"LEFT JOIN DM_TAG t ON dtm.TAG_ID = t.ID WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY e.ID HAVING COUNT(DISTINCT t.NAME) = ? ) ";
isTagsProvided = true;
}
sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -197,13 +209,19 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
stmt.setString(paramIdx++, status);
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
stmt.setInt(paramIdx++, request.getStartIndex());
stmt.setInt(paramIdx, request.getRowCount());
try (ResultSet rs = stmt.executeQuery()) {
devices = new ArrayList<>();
while (rs.next()) {
Device device = DeviceManagementDAOUtil.loadDevice(rs);
Device device = DeviceManagementDAOUtil.loadDevice(rs, true);
devices.add(device);
}
return devices;
@ -485,6 +503,8 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
boolean isSinceProvided = false;
String serial = request.getSerialNumber();
boolean isSerialProvided = false;
List<String> tagList = request.getTags();
boolean isTagsProvided = false;
try {
conn = getConnection();
@ -499,7 +519,10 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
"e.IS_TRANSFERRED, " +
"e.DATE_OF_LAST_UPDATE, " +
"e.DATE_OF_ENROLMENT, " +
"e.ID AS ENROLMENT_ID " +
"e.ID AS ENROLMENT_ID, " +
"(SELECT STRING_AGG(t.NAME, ', ') FROM DM_DEVICE_TAG_MAPPING dtm " +
"JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE dtm.ENROLMENT_ID = e.ID) AS TAGS " +
"FROM DM_ENROLMENT e, " +
"(SELECT gd.DEVICE_ID, " +
"gd.DESCRIPTION, " +
@ -574,6 +597,18 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
}
}
}
if (tagList != null && !tagList.isEmpty()) {
sql += " AND e.ID IN (" +
"SELECT e.ID FROM DM_ENROLMENT e " +
"LEFT JOIN DM_DEVICE_TAG_MAPPING dtm ON e.ID = dtm.ENROLMENT_ID " +
"LEFT JOIN DM_TAG t ON dtm.TAG_ID = t.ID " +
"WHERE t.NAME IN (" + buildTagQuery(tagList);
sql += ") GROUP BY e.ID HAVING COUNT(DISTINCT t.NAME) = ?)";
isTagsProvided = true;
} else {
sql += " GROUP BY e.ID ";
}
sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
@ -611,13 +646,19 @@ public class SQLServerDeviceDAOImpl extends GenericDeviceDAOImpl {
stmt.setString(paramIdx++, "%" + entry.getValue() + "%");
}
}
if (isTagsProvided) {
for (String tag : tagList) {
stmt.setString(paramIdx++, tag);
}
stmt.setInt(paramIdx++, tagList.size());
}
stmt.setInt(paramIdx++, request.getStartIndex());
stmt.setInt(paramIdx, request.getRowCount());
try (ResultSet rs = stmt.executeQuery()) {
devices = new ArrayList<>();
while (rs.next()) {
Device device = DeviceManagementDAOUtil.loadDevice(rs);
Device device = DeviceManagementDAOUtil.loadDevice(rs, true);
devices.add(device);
}
return devices;

@ -26,16 +26,13 @@ import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.el.lang.ELSupport;
import org.wso2.carbon.context.CarbonContext;
import io.entgra.device.mgt.core.device.mgt.common.Device;
import io.entgra.device.mgt.core.device.mgt.common.DeviceBilling;
import io.entgra.device.mgt.core.device.mgt.common.DeviceIdentifier;
import io.entgra.device.mgt.core.device.mgt.common.EnrolmentInfo;
import io.entgra.device.mgt.core.device.mgt.common.device.details.DeviceInfo;
import io.entgra.device.mgt.core.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
import io.entgra.device.mgt.core.device.mgt.common.device.details.DeviceMonitoringData;
import io.entgra.device.mgt.core.device.mgt.common.type.mgt.DeviceStatus;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOException;
import io.entgra.device.mgt.core.device.mgt.core.dto.DeviceType;
import io.entgra.device.mgt.core.device.mgt.core.internal.DeviceManagementDataHolder;
@ -143,6 +140,10 @@ public final class DeviceManagementDAOUtil {
}*/
public static EnrolmentInfo loadEnrolment(ResultSet rs) throws SQLException {
return loadEnrolment(rs, false);
}
public static EnrolmentInfo loadEnrolment(ResultSet rs, boolean isTagsProvided) throws SQLException {
EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
enrolmentInfo.setId(rs.getInt("ENROLMENT_ID"));
enrolmentInfo.setOwner(rs.getString("OWNER"));
@ -151,6 +152,16 @@ public final class DeviceManagementDAOUtil {
enrolmentInfo.setDateOfEnrolment(rs.getTimestamp("DATE_OF_ENROLMENT").getTime());
enrolmentInfo.setDateOfLastUpdate(rs.getTimestamp("DATE_OF_LAST_UPDATE").getTime());
enrolmentInfo.setStatus(EnrolmentInfo.Status.valueOf(rs.getString("STATUS")));
if (isTagsProvided) {
List<String> tags = new ArrayList<>();
String tagColumn = rs.getString("TAGS");
if (tagColumn != null) {
for (String tag : tagColumn.split(",")) {
tags.add(tag.trim());
}
}
enrolmentInfo.setTags(tags);
}
return enrolmentInfo;
}
@ -224,6 +235,10 @@ public final class DeviceManagementDAOUtil {
}
public static Device loadDevice(ResultSet rs) throws SQLException {
return loadDevice(rs, false);
}
public static Device loadDevice(ResultSet rs, boolean isTagsProvided) throws SQLException {
Device device = new Device();
device.setId(rs.getInt("DEVICE_ID"));
device.setName(rs.getString("DEVICE_NAME"));
@ -231,7 +246,7 @@ public final class DeviceManagementDAOUtil {
device.setType(rs.getString("DEVICE_TYPE"));
device.setDeviceIdentifier(rs.getString("DEVICE_IDENTIFICATION"));
device.setLastUpdatedTimeStamp(rs.getTimestamp("LAST_UPDATED_TIMESTAMP").getTime());
device.setEnrolmentInfo(loadEnrolment(rs));
device.setEnrolmentInfo(loadEnrolment(rs, isTagsProvided));
return device;
}

@ -0,0 +1,98 @@
/*
* Copyright (c) 2018 - 2024, 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.core.dao.util;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.DeviceTag;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
/**
* This class represents utilities required to work with tag management data
*/
public final class TagManagementDAOUtil {
private static final Log log = LogFactory.getLog(TagManagementDAOUtil.class);
/**
* Cleanup resources used to transaction
*
* @param stmt Prepared statement used
* @param rs Obtained results set
*/
public static void cleanupResources(PreparedStatement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.warn("Error occurred while closing result set", e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.warn("Error occurred while closing prepared statement", e);
}
}
}
/**
* Lookup datasource using name and jndi properties
*
* @param dataSourceName Name of datasource to lookup
* @param jndiProperties Hash table of JNDI Properties
* @return datasource looked
*/
public static DataSource lookupDataSource(String dataSourceName,
final Hashtable<Object, Object> jndiProperties) {
try {
if (jndiProperties == null || jndiProperties.isEmpty()) {
return (DataSource) InitialContext.doLookup(dataSourceName);
}
final InitialContext context = new InitialContext(jndiProperties);
return (DataSource) context.lookup(dataSourceName);
} catch (Exception e) {
throw new RuntimeException("Error in looking up data source: " + e.getMessage(), e);
}
}
public static Tag loadTag(ResultSet resultSet) throws SQLException {
Tag tag = new Tag();
tag.setId(resultSet.getInt("ID"));
tag.setName(resultSet.getString("NAME"));
tag.setDescription(resultSet.getString("DESCRIPTION"));
return tag;
}
public static DeviceTag loadDeviceTagMapping(ResultSet resultSet) throws SQLException {
DeviceTag deviceTag = new DeviceTag();
deviceTag.setEnrolmentId(resultSet.getInt("ENROLMENT_ID"));
deviceTag.setTagId(resultSet.getInt("TAG_ID"));
return deviceTag;
}
}

@ -21,6 +21,8 @@ import io.entgra.device.mgt.core.device.mgt.common.authorization.GroupAccessAuth
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.authorization.GroupAccessAuthorizationServiceImpl;
import io.entgra.device.mgt.core.device.mgt.core.metadata.mgt.DeviceStatusManagementServiceImpl;
import io.entgra.device.mgt.core.device.mgt.core.service.TagManagementProviderService;
import io.entgra.device.mgt.core.device.mgt.core.service.TagManagementProviderServiceImpl;
import io.entgra.device.mgt.core.server.bootup.heartbeat.beacon.service.HeartBeatManagementService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -349,6 +351,10 @@ public class DeviceManagementServiceComponent {
ReportManagementService reportManagementService = new ReportManagementServiceImpl();
bundleContext.registerService(ReportManagementService.class.getName(), reportManagementService, null);
/* Registering Tag Management Service */
TagManagementProviderService tagManagementProviderService = new TagManagementProviderServiceImpl();
bundleContext.registerService(TagManagementProviderService.class.getName(), tagManagementProviderService, null);
/* Registering DeviceAccessAuthorization Service */
DeviceAccessAuthorizationService deviceAccessAuthorizationService = new DeviceAccessAuthorizationServiceImpl();
DeviceManagementDataHolder.getInstance().setDeviceAccessAuthorizationService(deviceAccessAuthorizationService);

@ -22,7 +22,15 @@ import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.ConflictException;
import io.entgra.device.mgt.core.device.mgt.common.metadata.mgt.DeviceStatusManagementService;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceTypeDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.EnrollmentDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.ApplicationDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceStatusDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOFactory;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOException;
import io.entgra.device.mgt.core.device.mgt.core.dao.TenantDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.TagDAO;
import io.entgra.device.mgt.core.device.mgt.core.dto.DeviceDetailsDTO;
import io.entgra.device.mgt.core.device.mgt.core.dto.OwnerWithDeviceDTO;
import io.entgra.device.mgt.core.device.mgt.core.dto.OperationDTO;
@ -119,13 +127,6 @@ import io.entgra.device.mgt.core.device.mgt.core.cache.impl.DeviceCacheManagerIm
import io.entgra.device.mgt.core.device.mgt.core.common.Constants;
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceConfigurationManager;
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceManagementConfig;
import io.entgra.device.mgt.core.device.mgt.core.dao.ApplicationDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOException;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceManagementDAOFactory;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceStatusDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.DeviceTypeDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.EnrollmentDAO;
import io.entgra.device.mgt.core.device.mgt.core.operation.mgt.dao.OperationDAO;
import io.entgra.device.mgt.core.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import io.entgra.device.mgt.core.device.mgt.core.device.details.mgt.DeviceDetailsMgtException;
@ -185,6 +186,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
private MetadataDAO metadataDAO;
private final DeviceStatusDAO deviceStatusDAO;
private final TenantDAO tenantDao;
private final TagDAO tagDAO;
int count = 0;
public DeviceManagementProviderServiceImpl() {
@ -197,6 +199,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
this.metadataDAO = MetadataManagementDAOFactory.getMetadataDAO();
this.deviceStatusDAO = DeviceManagementDAOFactory.getDeviceStatusDAO();
this.tenantDao = DeviceManagementDAOFactory.getTenantDAO();
this.tagDAO = DeviceManagementDAOFactory.getTagDAO();
/* Registering a listener to retrieve events when some device management service plugin is installed after
* the component is done getting initialized */

@ -0,0 +1,103 @@
/*
* Copyright (c) 2018 - 2024, 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.core.service;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.BadRequestException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.*;
import java.util.List;
/**
* Defines the contract of TagManagementService.
*/
public interface TagManagementProviderService {
/**
* Method to add a tag to the database.
*
* @param tag - Tag to be added to the database.
* @throws TagManagementException if something goes wrong while adding the Tag.
*/
void addTags(List<Tag> tag) throws TagManagementException, BadRequestException;
/**
* Method to fetch all tags.
*
* @return List of all Tags.
* @throws TagManagementException if something goes wrong while fetching the Tags.
*/
List<Tag> getAllTags() throws TagManagementException;
/**
* Method to update a tag in the database.
*
* @param tag - Tag to be updated in the database.
* @throws TagManagementException if something goes wrong while updating the Tag.
*/
void updateTag(Tag tag) throws TagManagementException, TagNotFoundException, BadRequestException;
/**
* Method to delete a tag from the database.
*
* @param tagId - ID of the tag to be deleted.
* @throws TagManagementException if something goes wrong while deleting the Tag.
*/
void deleteTag(int tagId) throws TagManagementException, TagNotFoundException;
/**
* Method to retrieve a tag by its ID.
*
* @param tagId - ID of the tag to be retrieved.
* @return Tag object retrieved from the database.
* @throws TagManagementException if something goes wrong while retrieving the Tag.
*/
Tag getTagById(int tagId) throws TagManagementException, TagNotFoundException;
/**
* Method to retrieve a tag by its name.
*
* @param tagName - Name of the tag to be retrieved.
* @return Tag object retrieved from the database.
* @throws TagManagementException if something goes wrong while retrieving the Tag.
* @throws TagNotFoundException if the Tag with the given name is not found.
*/
Tag getTagByName(String tagName) throws TagManagementException, TagNotFoundException, BadRequestException;
/**
* Method to add a device-tag mapping.
*
* @param deviceIdentifiers - List of device ids to map.
* @param deviceType - Device Type of that specific devices.
* @param tags - List of tags you want to attach.
* @throws TagManagementException if something goes wrong while adding the device-tag mapping.
*/
void addDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tags)
throws TagManagementException, BadRequestException;
/**
* Method to delete a device-tag mapping.
*
* @param deviceIdentifiers - List of device ids to map.
* @param deviceType - Device Type of that specific devices.
* @param tags - List of tags you want to attach.
* @throws TagManagementException if something goes wrong while deleting the device-tag mapping.
*/
void deleteDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tags)
throws TagManagementException, BadRequestException;
}

@ -0,0 +1,284 @@
/*
* Copyright (c) 2018 - 2024, 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.core.service;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.BadRequestException;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.TransactionManagementException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.*;
import io.entgra.device.mgt.core.device.mgt.core.dao.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.CarbonContext;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class TagManagementProviderServiceImpl implements TagManagementProviderService {
private static final Log log = LogFactory.getLog(TagManagementProviderServiceImpl.class);
private final TagDAO tagDAO;
public TagManagementProviderServiceImpl() {
this.tagDAO = DeviceManagementDAOFactory.getTagDAO();
}
@Override
public void addTags(List<Tag> tags) throws TagManagementException, BadRequestException {
if (tags == null || tags.isEmpty()) {
String msg = "Received incomplete data for tags";
log.error(msg);
throw new BadRequestException(msg);
}
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
for (Tag tag : tags) {
if (tag.getName() == null) {
String msg = "Tag name cannot be null";
log.error(msg);
throw new BadRequestException(msg);
}
}
if (log.isDebugEnabled()) {
log.debug("Starting creating Tags.");
}
tagDAO.addTags(tags, tenantId);
DeviceManagementDAOFactory.commitTransaction();
} catch (TransactionManagementException e) {
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while adding tags to database.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} catch (Exception e) {
String msg = "Error occurred in creating tags.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public List<Tag> getAllTags() throws TagManagementException {
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
List<Tag> tags = tagDAO.getTags(tenantId);
DeviceManagementDAOFactory.commitTransaction();
return tags;
} catch (TransactionManagementException e) {
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while retrieving tags.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} catch (Exception e) {
String msg = "Error occurred in retrieving tags.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public Tag getTagById(int tagId) throws TagManagementException, TagNotFoundException {
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
Tag tag = tagDAO.getTagById(tagId, tenantId);
DeviceManagementDAOFactory.commitTransaction();
if (tag == null) {
String msg = "Tag with ID " + tagId + " not found.";
throw new TagNotFoundException(msg);
}
return tag;
} catch (TransactionManagementException | TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while retrieving the tag with ID: " + tagId;
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public Tag getTagByName(String tagName) throws TagManagementException, TagNotFoundException, BadRequestException {
if (tagName == null || tagName.trim().isEmpty()) {
String msg = "Tag name cannot be null or empty.";
log.error(msg);
throw new BadRequestException(msg);
}
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
Tag tag = tagDAO.getTagByName(tagName, tenantId);
DeviceManagementDAOFactory.commitTransaction();
if (tag == null) {
String msg = "Tag with name " + tagName + " not found.";
throw new TagNotFoundException(msg);
}
return tag;
} catch (TransactionManagementException | TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while retrieving the tag with name: " + tagName;
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public void updateTag(Tag tag) throws TagManagementException, TagNotFoundException, BadRequestException {
if (tag == null || tag.getName() == null) {
String msg = "Received incomplete data for tag update";
log.error(msg);
throw new BadRequestException(msg);
}
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
Tag existingTag = tagDAO.getTagById(tag.getId(), tenantId);
if (existingTag == null) {
String msg = "Tag with ID: " + tag.getId() + " does not exist.";
log.error(msg);
throw new TagNotFoundException(msg);
}
Tag tagWithName = tagDAO.getTagByName(tag.getName(), tenantId);
if (tagWithName != null && tagWithName.getId() != tag.getId()) {
String msg = "Tag with name: " + tag.getName() + " already exists.";
log.error(msg);
throw new BadRequestException(msg);
}
tagDAO.updateTag(tag, tenantId);
DeviceManagementDAOFactory.commitTransaction();
} catch (TagManagementDAOException | TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while updating the tag with ID: " + tag.getId();
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public void deleteTag(int tagId) throws TagManagementException, TagNotFoundException {
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
Tag existingTag = tagDAO.getTagById(tagId, tenantId);
if (existingTag == null) {
String msg = "Tag with ID: " + tagId + " does not exist.";
log.error(msg);
throw new TagNotFoundException(msg);
}
tagDAO.deleteTag(tagId, tenantId);
DeviceManagementDAOFactory.commitTransaction();
} catch (TagManagementDAOException | TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting the tag with ID: " + tagId;
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public void addDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tags)
throws TagManagementException, BadRequestException {
if (deviceIdentifiers == null || deviceType == null || tags == null) {
String msg = "Received incomplete data for device tag mapping.";
log.error(msg);
throw new BadRequestException(msg);
}
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
TagMappingDTO tagMappingDto = new TagMappingDTO(deviceIdentifiers, deviceType, tags);
List<Tag> tagList = new ArrayList<>();
for (String tagName : tagMappingDto.getTags()) {
Tag tag = new Tag();
tag.setName(tagName);
tagList.add(tag);
}
tagDAO.addTags(tagList, tenantId);
tagDAO.addDeviceTagMapping(tagMappingDto.getDeviceIdentifiers(), tagMappingDto.getDeviceType(),
tagMappingDto.getTags(), tenantId);
DeviceManagementDAOFactory.commitTransaction();
} catch (TagManagementDAOException e) {
if (e.isUniqueConstraintViolation()) {
String msg = "Tag is already mapped to this device.";
log.info(msg, e);
throw new BadRequestException(msg);
} else {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while adding device tag mapping.";
log.error(msg, e);
throw new TagManagementException(msg, e);
}
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while adding device tag mapping.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public void deleteDeviceTagMapping(List<String> deviceIdentifiers, String deviceType, List<String> tags) throws TagManagementException, BadRequestException {
if (deviceIdentifiers == null || deviceType == null || tags == null) {
String msg = "Received incomplete data for device tag mapping.";
log.error(msg);
throw new BadRequestException(msg);
}
try {
DeviceManagementDAOFactory.beginTransaction();
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
TagMappingDTO tagMappingDto = new TagMappingDTO(deviceIdentifiers, deviceType, tags);
tagDAO.deleteDeviceTagMapping(tagMappingDto.getDeviceIdentifiers(), tagMappingDto.getDeviceType(),
tagMappingDto.getTags(), tenantId);
DeviceManagementDAOFactory.commitTransaction();
} catch (TagManagementDAOException | TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting device tag mappings.";
log.error(msg, e);
throw new TagManagementException(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
}

@ -17,6 +17,7 @@
*/
package io.entgra.device.mgt.core.device.mgt.core;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import io.entgra.device.mgt.core.device.mgt.common.DeviceIdentifier;
@ -100,6 +101,45 @@ public class TestUtils {
return group;
}
public static Tag getTag1() {
return new Tag(1,"tag1", "This is tag1");
}
public static Tag getTag2() {
return new Tag( 2, "tag2", "This is tag2");
}
public static Tag getTag1Dao() {
return new Tag("tag1", "This is tag1");
}
public static Tag getTag2Dao() {
return new Tag( "tag2", "This is tag2");
}
public static Tag getTag3() {
return new Tag("tag3", "This is tag3");
}
public static List<Tag> createTagList1() {
List<Tag> tagList = new ArrayList<>();
tagList.add(new Tag(null, "This is tag1"));
return tagList;
}
public static List<Tag> createTagList2() {
List<Tag> tagList = new ArrayList<>();
tagList.add(getTag1());
tagList.add(getTag2());
return tagList;
}
public static List<Tag> createTagList3() {
List<Tag> tagList = new ArrayList<>();
tagList.add(getTag1Dao());
tagList.add(getTag2Dao());
return tagList;
}
public static GroupPaginationRequest createPaginationRequest(){
GroupPaginationRequest request = new GroupPaginationRequest(0, 5);

@ -27,6 +27,7 @@ import io.entgra.device.mgt.core.device.mgt.common.device.details.DeviceData;
import io.entgra.device.mgt.core.device.mgt.common.device.details.DeviceInfo;
import io.entgra.device.mgt.core.device.mgt.common.group.mgt.DeviceGroup;
import io.entgra.device.mgt.core.device.mgt.common.notification.mgt.Notification;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import io.entgra.device.mgt.core.device.mgt.core.dto.DeviceType;
import java.util.ArrayList;
@ -34,11 +35,14 @@ import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Calendar;
import java.util.Arrays;
public class TestDataHolder {
public final static String TEST_DEVICE_TYPE = "TEST-DEVICE-TYPE";
public final static Integer SUPER_TENANT_ID = -1234;
public final static Integer ALTERNATE_TENANT_ID = 1234;
public final static Integer ALTERNATE_TENANT_ID_1 = 1235;
public final static String SUPER_TENANT_DOMAIN = "carbon.super";
public final static String initialDeviceIdentifier = "12345";
public final static String initialDeviceName = "TEST-DEVICE";
@ -46,6 +50,7 @@ public class TestDataHolder {
public static final String OPERATION_CONFIG = "TEST-OPERATION-";
public static Device initialTestDevice;
public static DeviceType initialTestDeviceType;
public static List<String> TAGS = Arrays.asList("tag1", "tag2", "tag3");
public static Date getTimeBefore(int minutes) {
Calendar calendar = Calendar.getInstance();
@ -56,7 +61,7 @@ public class TestDataHolder {
public static Device generateDummyDeviceData(String deviceType) {
Device device = new Device();
device.setEnrolmentInfo(generateEnrollmentInfo(new Date().getTime(), new Date().getTime(), OWNER, EnrolmentInfo
.OwnerShip.BYOD, EnrolmentInfo.Status.ACTIVE));
.OwnerShip.BYOD, EnrolmentInfo.Status.ACTIVE, TAGS));
device.setDescription("Test Description");
device.setDeviceIdentifier(initialDeviceIdentifier);
device.setType(deviceType);
@ -65,16 +70,26 @@ public class TestDataHolder {
public static EnrolmentInfo generateEnrollmentInfo(long dateOfEnrollment, long dateOfLastUpdate,
String owner, EnrolmentInfo.OwnerShip ownership,
EnrolmentInfo.Status status) {
EnrolmentInfo.Status status, List<String> tags) {
EnrolmentInfo enrolmentInfo = new EnrolmentInfo();
enrolmentInfo.setDateOfEnrolment(dateOfEnrollment);
enrolmentInfo.setDateOfLastUpdate(dateOfLastUpdate);
enrolmentInfo.setOwner(owner);
enrolmentInfo.setOwnership(ownership);
enrolmentInfo.setStatus(status);
enrolmentInfo.setTags(tags);
return enrolmentInfo;
}
public static List<Tag> getTagList() {
List<Tag> tagList = new ArrayList<>();
for (int i = 1; i <= 3; i++) {
Tag tag = new Tag("tag" + i, "This is tag" + i);
tagList.add(tag);
}
return tagList;
}
public static DeviceInfo generateDummyDeviceInfo() {
DeviceInfo deviceInfo = new DeviceInfo();
deviceInfo.setDeviceModel("DUMMY_MODEL");
@ -141,8 +156,12 @@ public class TestDataHolder {
public static Device generateDummyDeviceData(DeviceIdentifier deviceIdentifier) {
Device device = new Device();
List<String> tags = new ArrayList<>();
tags.add("tag1");
tags.add("tag2");
tags.add("tag3");
device.setEnrolmentInfo(generateEnrollmentInfo(new Date().getTime(), new Date().getTime(), OWNER, EnrolmentInfo
.OwnerShip.BYOD, EnrolmentInfo.Status.ACTIVE));
.OwnerShip.BYOD, EnrolmentInfo.Status.ACTIVE, tags));
device.setDescription("Test Description");
device.setDeviceIdentifier(deviceIdentifier.getId());
device.setType(deviceIdentifier.getType());

@ -47,6 +47,7 @@ import java.util.List;
public class DevicePersistTests extends BaseDeviceManagementTest {
DeviceDAO deviceDAO;
TagDAO tagDAO;
DeviceTypeDAO deviceTypeDAO;
private static final Log log = LogFactory.getLog(DevicePersistTests.class);
@ -56,6 +57,7 @@ public class DevicePersistTests extends BaseDeviceManagementTest {
public void init() throws Exception {
initDataSource();
deviceDAO = DeviceManagementDAOFactory.getDeviceDAO();
tagDAO = DeviceManagementDAOFactory.getTagDAO();
deviceTypeDAO = DeviceManagementDAOFactory.getDeviceTypeDAO();
}
@ -103,6 +105,8 @@ public class DevicePersistTests extends BaseDeviceManagementTest {
int deviceId = deviceDAO.addDevice(TestDataHolder.initialTestDeviceType.getId(), device, tenantId);
device.setId(deviceId);
deviceDAO.addEnrollment(device, tenantId);
tagDAO.addTags(TestDataHolder.getTagList(), tenantId);
tagDAO.addDeviceTagMapping(Collections.singletonList(device.getDeviceIdentifier()), TestDataHolder.TEST_DEVICE_TYPE, TestDataHolder.TAGS, tenantId);
DeviceManagementDAOFactory.commitTransaction();
TestDataHolder.initialTestDevice = device;
} catch (DeviceManagementDAOException e) {
@ -115,6 +119,10 @@ public class DevicePersistTests extends BaseDeviceManagementTest {
String msg = "Error occurred while initiating transaction";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TagManagementDAOException e) {
String msg = "Error occurred while adding tag mappings";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
@ -508,6 +516,223 @@ public class DevicePersistTests extends BaseDeviceManagementTest {
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithTag() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(Collections.singletonList("tag1"));
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.getDevices(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithTags() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(TestDataHolder.TAGS);
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.getDevices(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithNonExistingTags() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(Collections.singletonList("tag10"));
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.getDevices(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(0, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithTagAndStatus() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setStatusList(Collections.singletonList(Status.ACTIVE.name()));
pr.setTags(Collections.singletonList("tag1"));
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.getDevices(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithTagsAndStatus() throws DeviceManagementDAOException, TransactionManagementException {
List<String> tags = new ArrayList<>() ;
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setStatusList(Collections.singletonList(Status.ACTIVE.name()));
pr.setTags(tags);
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.getDevices(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDeviceCountWithTag() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(Collections.singletonList("tag1"));
DeviceManagementDAOFactory.beginTransaction();
int result = deviceDAO.getDeviceCount(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, result, "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDeviceCountWithTags() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(TestDataHolder.TAGS);
DeviceManagementDAOFactory.beginTransaction();
int result = deviceDAO.getDeviceCount(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, result, "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDeviceCountWithTagAndStatus() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setStatusList(Collections.singletonList(Status.ACTIVE.name()));
pr.setTags(Collections.singletonList("tag1"));
DeviceManagementDAOFactory.beginTransaction();
int result = deviceDAO.getDeviceCount(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, result, "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDeviceCountWithTagsAndStatus() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setStatusList(Collections.singletonList(Status.ACTIVE.name()));
pr.setTags(TestDataHolder.TAGS);
DeviceManagementDAOFactory.beginTransaction();
int result = deviceDAO.getDeviceCount(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(1, result, "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithTagAndGroupId() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(Collections.singletonList("tag1"));
pr.setGroupId(1);
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.searchDevicesInGroup(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(0, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDevicesWithTagsAndGroupId() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(TestDataHolder.TAGS);
pr.setGroupId(1);
DeviceManagementDAOFactory.beginTransaction();
List<Device> results = deviceDAO.searchDevicesInGroup(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(0, results.size(), "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDeviceCountWithTagAndGroupId() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(Collections.singletonList("tag1"));
pr.setGroupId(1);
DeviceManagementDAOFactory.beginTransaction();
int result = deviceDAO.getCountOfDevicesInGroup(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(0, result, "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getDeviceCountWithTagsAndGroupId() throws DeviceManagementDAOException, TransactionManagementException {
try {
PaginationRequest pr = new PaginationRequest(0, 10);
pr.setTags(TestDataHolder.TAGS);
pr.setGroupId(1);
DeviceManagementDAOFactory.beginTransaction();
int result = deviceDAO.getCountOfDevicesInGroup(pr, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(0, result, "No device returned");
DeviceManagementDAOFactory.commitTransaction();
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementDAOException("Error occurred while retrieving the device" + e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "testAddDeviceTest")
public void getCountOfDevicesInGroup() throws DeviceManagementDAOException, TransactionManagementException {
PaginationRequest pr = new PaginationRequest(0, 10);

@ -0,0 +1,216 @@
/*
* Copyright (c) 2018 - 2024, 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.core.dao;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.TransactionManagementException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import io.entgra.device.mgt.core.device.mgt.core.TestUtils;
import io.entgra.device.mgt.core.device.mgt.core.common.BaseDeviceManagementTest;
import io.entgra.device.mgt.core.device.mgt.core.common.TestDataHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.List;
public class TagPersistTests extends BaseDeviceManagementTest {
private TagDAO tagDAO;
private static final Log log = LogFactory.getLog(TagPersistTests.class);
@BeforeClass
@Override
public void init() throws Exception {
initDataSource();
tagDAO = DeviceManagementDAOFactory.getTagDAO();
}
@Test
public void addTag() {
try {
DeviceManagementDAOFactory.beginTransaction();
tagDAO.addTags(TestUtils.createTagList3(), TestDataHolder.ALTERNATE_TENANT_ID);
log.debug("Tags added to the database");
Tag tag = tagDAO.getTagByName("tag1", TestDataHolder.ALTERNATE_TENANT_ID);
DeviceManagementDAOFactory.commitTransaction();
Assert.assertNotNull(tag, "Tag should be added and retrieved.");
Assert.assertEquals(tag.getName(), "tag1", "Tag name mismatch.");
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while adding tag list type.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "addTag")
public void updateTag() {
try {
DeviceManagementDAOFactory.beginTransaction();
String updatedDescription = "Updated Description";
Tag tag = tagDAO.getTagByName("tag1", TestDataHolder.ALTERNATE_TENANT_ID);
Tag tagToUpdate = new Tag(tag.getId(), tag.getName(), updatedDescription);
tagDAO.updateTag(tagToUpdate, TestDataHolder.ALTERNATE_TENANT_ID);
log.debug("Tag updated in the database");
tag = tagDAO.getTagByName("tag1", TestDataHolder.ALTERNATE_TENANT_ID);
DeviceManagementDAOFactory.commitTransaction();
Assert.assertEquals(tag.getDescription(), updatedDescription, "Tag description mismatch.");
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while updating tag.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "updateTag")
public void deleteTag() {
try {
DeviceManagementDAOFactory.beginTransaction();
tagDAO.deleteTag(1, TestDataHolder.ALTERNATE_TENANT_ID);
log.debug("Tag deleted from the database");
Tag deletedTag = tagDAO.getTagById(1, TestDataHolder.ALTERNATE_TENANT_ID);
DeviceManagementDAOFactory.commitTransaction();
Assert.assertNull(deletedTag, "Tag should be deleted.");
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting tag.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = {"deleteTag"})
public void getTags() {
try {
DeviceManagementDAOFactory.beginTransaction();
List<Tag> tags = tagDAO.getTags(TestDataHolder.ALTERNATE_TENANT_ID);
DeviceManagementDAOFactory.commitTransaction();
log.debug("Tags retrieved successfully.");
Assert.assertEquals(tags.size(), 2);
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while retrieving tags.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = {"getTags"})
public void getTagByName() {
try {
String tagName = "tag2";
DeviceManagementDAOFactory.beginTransaction();
Tag tag = tagDAO.getTagByName(tagName, TestDataHolder.ALTERNATE_TENANT_ID);
DeviceManagementDAOFactory.commitTransaction();
log.debug("Tag " + tagName + " retrieved successfully.");
Assert.assertEquals(tag.getName(), "tag2");
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while retrieving tag by Id.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "getTagByName")
public void addTagsForAlternateTenant() {
try {
DeviceManagementDAOFactory.beginTransaction();
//Here, adding a same tag name for a separate tenant is tested.
tagDAO.addTags(TestUtils.createTagList3(), TestDataHolder.ALTERNATE_TENANT_ID_1);
log.debug("Tags added for a alternate tenant");
List<Tag> tagList = tagDAO.getTags(TestDataHolder.ALTERNATE_TENANT_ID_1);
DeviceManagementDAOFactory.commitTransaction();
Assert.assertEquals(tagList.size(), 2, "Tag count mismatch.");
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while adding tags for a different tenant.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = "addTagsForAlternateTenant")
public void getTagsOfAlternateTenant() {
try {
DeviceManagementDAOFactory.beginTransaction();
List<Tag> tagList = tagDAO.getTags(TestDataHolder.ALTERNATE_TENANT_ID_1);
log.debug("Tags retrieved for a alternate tenant " + TestDataHolder.ALTERNATE_TENANT_ID_1);
DeviceManagementDAOFactory.commitTransaction();
Assert.assertEquals(tagList.size(), 2, "Tag count mismatch.");
} catch (TagManagementDAOException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while adding tags for a different tenant.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
DeviceManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while initiating transaction.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
}

@ -0,0 +1,192 @@
/*
* Copyright (c) 2018 - 2024, 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.core.service;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.BadRequestException;
import io.entgra.device.mgt.core.device.mgt.common.exceptions.DeviceManagementException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.Tag;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.TagManagementException;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.TagMappingDTO;
import io.entgra.device.mgt.core.device.mgt.common.tag.mgt.TagNotFoundException;
import io.entgra.device.mgt.core.device.mgt.core.TestUtils;
import io.entgra.device.mgt.core.device.mgt.core.common.BaseDeviceManagementTest;
import io.entgra.device.mgt.core.device.mgt.core.config.DeviceConfigurationManager;
import io.entgra.device.mgt.core.device.mgt.core.internal.DeviceManagementDataHolder;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.wso2.carbon.registry.core.jdbc.realm.InMemoryRealmService;
import org.wso2.carbon.user.core.service.RealmService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TagManagementProviderServiceTest extends BaseDeviceManagementTest {
private TagManagementProviderService tagManagementProviderService;
public static final String DEVICE_ID_1 = "100001";
public static final String DEVICE_ID_2 = "100002";
private static final String DEVICE_TYPE = "RANDOM_DEVICE_TYPE";
@BeforeClass
@Override
public void init() throws Exception {
tagManagementProviderService = new TagManagementProviderServiceImpl();
RealmService realmService = new InMemoryRealmService();
DeviceManagementDataHolder.getInstance().setRealmService(realmService);
realmService.getTenantManager().getSuperTenantDomain();
DeviceConfigurationManager.getInstance().initConfig();
}
@Test(expectedExceptions = {TagManagementException.class, BadRequestException.class})
public void createTagsNull() throws TagManagementException, BadRequestException {
tagManagementProviderService.addTags(null);
}
@Test(expectedExceptions = {TagManagementException.class, BadRequestException.class}, dependsOnMethods = "createTagsNull")
public void createTagsNameNullError() throws TagManagementException, BadRequestException {
tagManagementProviderService.addTags(TestUtils.createTagList1());
}
@Test(dependsOnMethods = "createTagsNameNullError")
public void createTags() throws TagManagementException, BadRequestException {
tagManagementProviderService.addTags(TestUtils.createTagList2());
}
@Test(expectedExceptions = {TagNotFoundException.class, BadRequestException.class, TagManagementException.class})
public void updateTagsNotFound() throws TagNotFoundException, TagManagementException, BadRequestException {
String updateDescString = "This tag is updated";
tagManagementProviderService.updateTag(new Tag(10,"tag10", updateDescString));
}
@Test(dependsOnMethods = "updateTagsNotFound")
public void updateTags() throws TagNotFoundException, TagManagementException, BadRequestException {
String updateDescString = "This tag is updated";
tagManagementProviderService.updateTag(new Tag(1,"tag1", updateDescString));
Tag tag = tagManagementProviderService.getTagById(1);
Assert.assertEquals(tag.getDescription(), updateDescString);
}
@Test(dependsOnMethods = "updateTags", expectedExceptions = {TagNotFoundException.class})
public void getTagNotFoundById() throws TagManagementException, TagNotFoundException {
tagManagementProviderService.getTagById(10);
}
@Test(dependsOnMethods = "getTagNotFoundById", expectedExceptions = {BadRequestException.class})
public void getTagNotFoundByNameNull() throws TagManagementException, TagNotFoundException, BadRequestException {
tagManagementProviderService.getTagByName(null);
}
@Test(dependsOnMethods = "getTagNotFoundByNameNull", expectedExceptions = {TagNotFoundException.class})
public void getTagNotFoundByName() throws TagManagementException, TagNotFoundException, BadRequestException {
tagManagementProviderService.getTagByName("tag10");
}
@Test(dependsOnMethods = "getTagNotFoundByName")
public void getTagById() throws TagManagementException, TagNotFoundException {
Tag tag = tagManagementProviderService.getTagById(2);
Assert.assertEquals(tag.getName(), TestUtils.getTag2().getName());
}
@Test(dependsOnMethods = "getTagById")
public void getTagByName() throws TagManagementException, TagNotFoundException, BadRequestException {
Tag tag = tagManagementProviderService.getTagByName("tag2");
Assert.assertEquals(tag.getName(), TestUtils.getTag2().getName());
}
@Test(dependsOnMethods = "getTagByName")
public void getTags() throws TagManagementException {
List<Tag> tags = tagManagementProviderService.getAllTags();
Assert.assertEquals(tags.size(), 3);
}
@Test(expectedExceptions = {TagNotFoundException.class}, dependsOnMethods = "getTags")
public void deleteTagNotExists() throws TagManagementException, TagNotFoundException {
tagManagementProviderService.deleteTag(10);
}
@Test(dependsOnMethods = "deleteTagNotExists")
public void deleteTag() throws TagManagementException, TagNotFoundException {
tagManagementProviderService.deleteTag(1);
List<Tag> tags = tagManagementProviderService.getAllTags();
Assert.assertEquals(tags.size(), 2);
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "deleteTag")
public void createTagMappingsNull() throws TagManagementException, BadRequestException {
tagManagementProviderService.addDeviceTagMapping(null, null, null);
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "createTagMappingsNull")
public void createTagsMappingsNullDeviceIdentifiers() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.addDeviceTagMapping(null, DEVICE_TYPE,
new ArrayList<>(Arrays.asList("tag1", "tag2")));
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "createTagsMappingsNullDeviceIdentifiers")
public void createTagsMappingsNullDeviceType() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.addDeviceTagMapping(new ArrayList<>(Arrays.asList(DEVICE_ID_1, DEVICE_ID_2)),
null, new ArrayList<>(Arrays.asList("tag1", "tag2")));
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "createTagsMappingsNullDeviceType")
public void createTagsMappingsNullTags() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.addDeviceTagMapping(new ArrayList<>(Arrays.asList(DEVICE_ID_1, DEVICE_ID_2)),
DEVICE_TYPE, null);
}
@Test(dependsOnMethods = "createTagsMappingsNullTags")
public void createTagsMappings() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.addDeviceTagMapping(new ArrayList<>(Arrays.asList(DEVICE_ID_1, DEVICE_ID_2)),
DEVICE_TYPE, new ArrayList<>(Arrays.asList("tag1", "tag2")));
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "createTagsMappings")
public void deleteTagMappingsNull() throws TagManagementException, BadRequestException {
tagManagementProviderService.deleteDeviceTagMapping(null, null, null);
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "deleteTagMappingsNull")
public void deleteTagsMappingsNullDeviceIdentifiers() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.deleteDeviceTagMapping(null, DEVICE_TYPE,
new ArrayList<>(Arrays.asList("tag1", "tag2")));
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "deleteTagsMappingsNullDeviceIdentifiers")
public void deleteTagsMappingsNullDeviceType() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.deleteDeviceTagMapping(new ArrayList<>(Arrays.asList(DEVICE_ID_1, DEVICE_ID_2)),
null, new ArrayList<>(Arrays.asList("tag1", "tag2")));
}
@Test(expectedExceptions = {BadRequestException.class}, dependsOnMethods = "deleteTagsMappingsNullDeviceType")
public void deleteTagsMappingsNullTags() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.deleteDeviceTagMapping(new ArrayList<>(Arrays.asList(DEVICE_ID_1, DEVICE_ID_2)),
DEVICE_TYPE, null);
}
@Test(dependsOnMethods = "deleteTagsMappingsNullTags")
public void deleteTagsMappings() throws TagManagementException, DeviceManagementException {
tagManagementProviderService.deleteDeviceTagMapping(new ArrayList<>(Arrays.asList(DEVICE_ID_1, DEVICE_ID_2)),
DEVICE_TYPE, new ArrayList<>(Arrays.asList("tag1", "tag2")));
}
}

@ -33,6 +33,7 @@
<class name="io.entgra.device.mgt.core.device.mgt.core.app.mgt.AppManagementConfigurationManagerTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.search.DeviceDetails"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.GroupPersistTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.TagPersistTests"/>
</classes>
</test>

@ -33,6 +33,7 @@
<class name="io.entgra.device.mgt.core.device.mgt.core.app.mgt.AppManagementConfigurationManagerTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.search.DeviceDetails"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.GroupPersistTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.TagPersistTests"/>
</classes>
</test>

@ -33,6 +33,7 @@
<class name="io.entgra.device.mgt.core.device.mgt.core.app.mgt.AppManagementConfigurationManagerTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.search.DeviceDetails"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.GroupPersistTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.TagPersistTests"/>
</classes>
</test>

@ -33,6 +33,7 @@
<class name="io.entgra.device.mgt.core.device.mgt.core.app.mgt.AppManagementConfigurationManagerTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.search.DeviceDetails"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.GroupPersistTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.TagPersistTests"/>
</classes>
</test>

@ -685,3 +685,25 @@ CREATE TABLE IF NOT EXISTS DM_METADATA (
CONSTRAINT METADATA_KEY_TENANT_ID UNIQUE (METADATA_KEY, TENANT_ID)
);
-- END OF METADATA TABLE --
-- DM_TAG TABLE --
CREATE TABLE IF NOT EXISTS DM_TAG (
ID BIGINT AUTO_INCREMENT,
NAME VARCHAR(255) NOT NULL,
DESCRIPTION VARCHAR(255) NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
CONSTRAINT DM_TAG_NAME_TENANT_UNIQUE UNIQUE (NAME, TENANT_ID)
);
-- END OF DM_TAG TABLE --
-- DM_DEVICE_TAG_MAPPING TABLE --
CREATE TABLE IF NOT EXISTS DM_DEVICE_TAG_MAPPING (
ENROLMENT_ID BIGINT NOT NULL,
TAG_ID BIGINT NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (ENROLMENT_ID, TAG_ID, TENANT_ID),
FOREIGN KEY (ENROLMENT_ID) REFERENCES DM_ENROLMENT(ID),
FOREIGN KEY (TAG_ID) REFERENCES DM_TAG(ID) ON DELETE CASCADE
);
-- END OF DM_DEVICE_TAG_MAPPING TABLE --

@ -33,6 +33,7 @@
<class name="io.entgra.device.mgt.core.device.mgt.core.app.mgt.AppManagementConfigurationManagerTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.search.DeviceDetails"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.GroupPersistTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.TagPersistTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.EnrolmentPersistenceTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.dao.DeviceStatusPersistenceTests"/>
</classes>
@ -43,6 +44,7 @@
<class name="io.entgra.device.mgt.core.device.mgt.core.service.DeviceManagementProviderServiceTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.app.mgt.ApplicationManagementProviderServiceTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.service.GroupManagementProviderServiceTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.service.TagManagementProviderServiceTest"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.operation.OperationManagementTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.operation.OperationManagementNoDBSchemaTests"/>
<class name="io.entgra.device.mgt.core.device.mgt.core.operation.OperationManagementNegativeDBOperationTest"/>

@ -875,3 +875,24 @@ CREATE TABLE IF NOT EXISTS DM_CEA_POLICIES (
-- END OF DM_CEA_POLICIES TABLE --
-- DM_TAG TABLE --
CREATE TABLE IF NOT EXISTS DM_TAG (
ID BIGINT AUTO_INCREMENT,
NAME VARCHAR(255) NOT NULL,
DESCRIPTION VARCHAR(255) NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (ID),
CONSTRAINT DM_TAG_NAME_TENANT_UNIQUE UNIQUE (NAME, TENANT_ID)
);
-- END OF DM_TAG TABLE --
-- DM_DEVICE_TAG_MAPPING TABLE --
CREATE TABLE IF NOT EXISTS DM_DEVICE_TAG_MAPPING (
ENROLMENT_ID BIGINT NOT NULL,
TAG_ID BIGINT NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (ENROLMENT_ID, TAG_ID, TENANT_ID),
FOREIGN KEY (ENROLMENT_ID) REFERENCES DM_ENROLMENT(ID),
FOREIGN KEY (TAG_ID) REFERENCES DM_TAG(ID) ON DELETE CASCADE
);
-- END OF DM_DEVICE_TAG_MAPPING TABLE --

@ -951,3 +951,25 @@ BEGIN
END;
-- END OF DM_CEA_POLICIES TABLE --
-- DM_TAG TABLE --
CREATE TABLE IF NOT EXISTS DM_TAG (
ID BIGINT IDENTITY(1,1) PRIMARY KEY,
NAME NVARCHAR(255) NOT NULL,
DESCRIPTION NVARCHAR(255) NULL,
TENANT_ID INT NOT NULL,
CONSTRAINT DM_TAG_NAME_TENANT_UNIQUE UNIQUE (NAME, TENANT_ID)
);
-- END OF DM_TAG TABLE --
-- DM_DEVICE_TAG_MAPPING TABLE --
CREATE TABLE IF NOT EXISTS DM_DEVICE_TAG_MAPPING (
ENROLMENT_ID BIGINT NOT NULL,
TAG_ID BIGINT NOT NULL,
TENANT_ID INT NOT NULL,
PRIMARY KEY (ENROLMENT_ID, TAG_ID, TENANT_ID),
FOREIGN KEY (ENROLMENT_ID) REFERENCES DM_ENROLMENT(ID),
FOREIGN KEY (TAG_ID) REFERENCES DM_TAG(ID) ON DELETE CASCADE
);
-- END OF DM_DEVICE_TAG_MAPPING TABLE --

@ -950,3 +950,25 @@ CREATE TABLE IF NOT EXISTS DM_CEA_POLICIES (
);
-- END OF DM_CEA_POLICIES TABLE --
-- DM_TAG TABLE --
CREATE TABLE IF NOT EXISTS DM_TAG (
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(255) NOT NULL,
DESCRIPTION VARCHAR(255) NULL,
TENANT_ID INT NOT NULL,
CONSTRAINT DM_TAG_NAME_TENANT_UNIQUE UNIQUE (NAME, TENANT_ID)
);
-- END OF DM_TAG TABLE --
-- DM_DEVICE_TAG_MAPPING TABLE --
CREATE TABLE IF NOT EXISTS DM_DEVICE_TAG_MAPPING (
ENROLMENT_ID BIGINT NOT NULL,
TAG_ID BIGINT NOT NULL,
TENANT_ID INT NOT NULL,
PRIMARY KEY (ENROLMENT_ID, TAG_ID, TENANT_ID),
FOREIGN KEY (ENROLMENT_ID) REFERENCES DM_ENROLMENT(ID),
FOREIGN KEY (TAG_ID) REFERENCES DM_TAG(ID) ON DELETE CASCADE
);
-- END OF DM_DEVICE_TAG_MAPPING TABLE --

@ -1255,3 +1255,25 @@ END;
/
-- END OF DM_CEA_POLICIES TABLE --
-- DM_TAG TABLE --
CREATE TABLE DM_TAG (
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
NAME VARCHAR2(255) NOT NULL,
DESCRIPTION VARCHAR2(255) NULL,
TENANT_ID NUMBER(10) NOT NULL,
CONSTRAINT DM_TAG_NAME_TENANT_UNIQUE UNIQUE (NAME, TENANT_ID)
);
-- END OF DM_TAG TABLE --
-- DM_DEVICE_TAG_MAPPING TABLE --
CREATE TABLE DM_DEVICE_TAG_MAPPING (
ENROLMENT_ID NUMBER(19) NOT NULL,
TAG_ID NUMBER(19) NOT NULL,
TENANT_ID NUMBER(10) NOT NULL,
PRIMARY KEY (ENROLMENT_ID, TAG_ID, TENANT_ID),
FOREIGN KEY (ENROLMENT_ID) REFERENCES DM_ENROLMENT(ID),
FOREIGN KEY (TAG_ID) REFERENCES DM_TAG(ID) ON DELETE CASCADE
);
-- END OF DM_DEVICE_TAG_MAPPING TABLE --

@ -881,3 +881,25 @@ CREATE TABLE IF NOT EXISTS DM_CEA_POLICIES (
);
-- END OF DM_CEA_POLICIES TABLE --
-- DM_TAG TABLE --
CREATE TABLE IF NOT EXISTS DM_TAG (
ID BIGSERIAL PRIMARY KEY,
NAME VARCHAR(255) NOT NULL,
DESCRIPTION VARCHAR(255) NULL,
TENANT_ID INTEGER NOT NULL,
CONSTRAINT DM_TAG_NAME_TENANT_UNIQUE UNIQUE (NAME, TENANT_ID)
);
-- END OF DM_TAG TABLE --
-- DM_DEVICE_TAG_MAPPING TABLE --
CREATE TABLE IF NOT EXISTS DM_DEVICE_TAG_MAPPING (
ENROLMENT_ID BIGINT NOT NULL,
TAG_ID BIGINT NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (ENROLMENT_ID, TAG_ID, TENANT_ID),
FOREIGN KEY (ENROLMENT_ID) REFERENCES DM_ENROLMENT(ID),
FOREIGN KEY (TAG_ID) REFERENCES DM_TAG(ID) ON DELETE CASCADE
);
-- END OF DM_DEVICE_TAG_MAPPING TABLE --

Loading…
Cancel
Save