Merge branch 'feature-metadata' into 'master'

Metadata repository

Closes product-iots#525

See merge request entgra/carbon-device-mgt!505
vpp
Dharmakeerthi Lasantha 5 years ago
commit 361820b345

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.jaxrs.beans;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import java.util.List;
@ApiModel(value = "metadataList")
public class MetadataList extends BasePaginatedResult {
private List<Metadata> metadataList;
@JsonProperty("metadataList")
@ApiModelProperty("metadataList")
public List<Metadata> getMetadataList() {
return metadataList;
}
public void setMetadataList(List<Metadata> metadataList) {
this.metadataList = metadataList;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(" count: ").append(getCount()).append(",");
sb.append(" metadataList: [").append(metadataList).append("");
sb.append("]}");
return sb.toString();
}
}

@ -0,0 +1,357 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.jaxrs.service.api;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.Extension;
import io.swagger.annotations.ExtensionProperty;
import io.swagger.annotations.Info;
import io.swagger.annotations.ResponseHeader;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.Tag;
import org.apache.axis2.transport.http.HTTPConstants;
import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.beans.MetadataList;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* Metadata related REST-API implementation.
*/
@SwaggerDefinition(
info = @Info(
version = "1.0.0",
title = "Metadata Service",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = "name", value = "DeviceMetadataManagement"),
@ExtensionProperty(name = "context", value = "/api/device-mgt/v1.0/metadata"),
})
}
),
tags = {
@Tag(name = "device_management")
}
)
@Scopes(
scopes = {
@Scope(
name = "View metadata records",
description = "View metadata records",
key = "perm:metadata:view",
permissions = {"/device-mgt/metadata/view"}
),
@Scope(
name = "Create a metadata record",
description = "Create a metadata record",
key = "perm:metadata:create",
permissions = {"/device-mgt/metadata/create"}
),
@Scope(
name = "Update a metadata record",
description = "Updating a specified metadata record",
key = "perm:metadata:update",
permissions = {"/device-mgt/metadata/update"}
),
@Scope(
name = "Delete a metadata record",
description = "Delete a specified metadata record",
key = "perm:metadata:remove",
permissions = {"/device-mgt/metadata/remove"}
)
}
)
@Api(value = "Device Metadata Management")
@Path("/metadata")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public interface MetadataService {
@GET
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_GET,
value = "Get all metadata entries",
notes = "Provides a list of metadata entries, which are stored as key-value pairs.",
tags = "Device Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:metadata:view")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the list of metadata entries.",
response = MetadataList.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 was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@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 fetching the metadata entry list.",
response = ErrorResponse.class)
})
Response getAllMetadataEntries(
@ApiParam(
name = "offset",
value = "The starting pagination index for the complete list of qualified items.")
@QueryParam("offset")
int offset,
@ApiParam(
name = "limit",
value = "Provide how many metadata entries you require from the starting pagination index/offset.",
defaultValue = "5")
@QueryParam("limit")
int limit);
@GET
@Path("/{metaKey}")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_GET,
value = "Get metadata by metaKey",
notes = "Retrieve a metadata entry by providing a metaKey value",
tags = "Device Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:metadata:view")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the requested metadata entry.",
response = Metadata.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 was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 404,
message = "Not Found. \n The requested metadata entry is not found.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while fetching the metadata entry.",
response = ErrorResponse.class)
})
Response getMetadataEntry(
@ApiParam(
name = "metaKey",
value = "Key of the metadata",
required = true)
@PathParam("metaKey") String metaKey);
@POST
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_PUT,
value = "Create metadata entry",
notes = "Create a entry in metadata repository",
tags = "Device Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:metadata:create")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully created the metadata entry.",
response = Metadata.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 was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 409,
message = "Conflict. \n The provided metadataKey is already exist.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while creating the metadata entry.",
response = ErrorResponse.class)
})
Response createMetadataEntry(
Metadata metadata
);
@PUT
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_PUT,
value = "Update metadata entry",
notes = "Update metadata entry by the provided metaKey of the Metadata object, if the metaKey is not " +
"already exist a new entry will be inserted.",
tags = "Device Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:metadata:update")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully updated the provided metadata entry.",
response = Metadata.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 was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@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 updating the metadata entry.",
response = ErrorResponse.class)
})
Response updateMetadataEntry(
Metadata metadata
);
@DELETE
@Path("/{metaKey}")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = HTTPConstants.HEADER_DELETE,
value = "Delete metadata entry",
notes = "Delete metadata entry by providing a metaKey value",
tags = "Device Metadata Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:metadata:remove")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully deleted the requested metadata entry.",
response = Metadata.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 was last modified.\n" +
"Used by caches, or in conditional requests."),
}),
@ApiResponse(
code = 404,
message = "Not Found. \n The requested metadata entry to be deleted is not found.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. " +
"\n Server error occurred while deleting the metadata entry.",
response = ErrorResponse.class)
})
Response deleteMetadataEntry(
@ApiParam(
name = "metaKey",
value = "Key of the metadata",
required = true)
@PathParam("metaKey") String metaKey
);
}

@ -0,0 +1,154 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.jaxrs.service.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataKeyAlreadyExistsException;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataKeyNotFoundException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataManagementException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.MetadataManagementService;
import org.wso2.carbon.device.mgt.jaxrs.beans.MetadataList;
import org.wso2.carbon.device.mgt.jaxrs.service.api.MetadataService;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* This is the service class for metadata management.
*/
@Path("/metadata")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class MetadataServiceImpl implements MetadataService {
private static final Log log = LogFactory.getLog(MetadataServiceImpl.class);
@GET
@Override
public Response getAllMetadataEntries(
@QueryParam("offset") int offset,
@DefaultValue("5")
@QueryParam("limit") int limit) {
RequestValidationUtil.validatePaginationParameters(offset, limit);
PaginationRequest request = new PaginationRequest(offset, limit);
MetadataList metadataList = new MetadataList();
try {
MetadataManagementService metadataManagementService = DeviceMgtAPIUtils.getMetadataManagementService();
PaginationResult result = metadataManagementService.retrieveAllMetadata(request);
metadataList.setCount(result.getRecordsTotal());
metadataList.setMetadataList((List<Metadata>) result.getData());
return Response.status(Response.Status.OK).entity(metadataList).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while retrieving metadata list for given parameters [offset:" +
offset + ", limit:" + limit + " ]";
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@GET
@Override
@Path("/{metaKey}")
public Response getMetadataEntry(
@PathParam("metaKey") String metaKey) {
Metadata metadata;
try {
metadata = DeviceMgtAPIUtils.getMetadataManagementService().retrieveMetadata(metaKey);
return Response.status(Response.Status.OK).entity(metadata).build();
} catch (MetadataKeyNotFoundException e) {
String msg = "Metadata entry metaKey:" + metaKey + " is not found.";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while getting the metadata entry for metaKey:" + metaKey;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@POST
@Override
public Response createMetadataEntry(Metadata metadata) {
RequestValidationUtil.validateMetadata(metadata);
try {
Metadata createdMetadata = DeviceMgtAPIUtils.getMetadataManagementService().createMetadata(metadata);
return Response.status(Response.Status.CREATED).entity(createdMetadata).build();
} catch (MetadataKeyAlreadyExistsException e) {
String msg = "Metadata entry metaKey:" + metadata.getMetaKey() + " is already exist.";
log.error(msg, e);
return Response.status(Response.Status.CONFLICT).entity(msg).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while creating the metadata entry for metaKey:" + metadata.getMetaKey();
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@PUT
@Override
public Response updateMetadataEntry(Metadata metadata) {
RequestValidationUtil.validateMetadata(metadata);
try {
Metadata updatedMetadata = DeviceMgtAPIUtils.getMetadataManagementService().updateMetadata(metadata);
return Response.status(Response.Status.OK).entity(updatedMetadata).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while updating the metadata entry for metaKey:" + metadata.getMetaKey();
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
@DELETE
@Override
@Path("/{metaKey}")
public Response deleteMetadataEntry(
@PathParam("metaKey") String metaKey) {
try {
DeviceMgtAPIUtils.getMetadataManagementService().deleteMetadata(metaKey);
return Response.status(Response.Status.OK).entity("Metadata entry is deleted successfully.").build();
} catch (MetadataKeyNotFoundException e) {
String msg = "Metadata entry metaKey:" + metaKey + " is not found.";
log.error(msg, e);
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
} catch (MetadataManagementException e) {
String msg = "Error occurred while deleting the metadata entry for metaKey:" + metaKey;
log.error(msg, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
}
}
}

@ -25,6 +25,7 @@ import org.apache.http.HttpStatus;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.common.notification.mgt.Notification; import org.wso2.carbon.device.mgt.common.notification.mgt.Notification;
import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationWrapper;
@ -36,11 +37,12 @@ import org.wso2.carbon.device.mgt.jaxrs.beans.RoleInfo;
import org.wso2.carbon.device.mgt.jaxrs.beans.Scope; import org.wso2.carbon.device.mgt.jaxrs.beans.Scope;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants; import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtUtil;
import org.wso2.carbon.policy.mgt.common.PolicyPayloadValidator; import org.wso2.carbon.policy.mgt.common.PolicyPayloadValidator;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
public class RequestValidationUtil { public class RequestValidationUtil {
@ -474,6 +476,49 @@ public class RequestValidationUtil {
} }
} }
/**
* Validate if the metaData and metaKey values are non empty & in proper format.
*
* @param metadata a Metadata instance, which contains user submitted values
*/
public static void validateMetadata(Metadata metadata) {
if (StringUtils.isEmpty(metadata.getMetaKey())) {
String msg = "Request parameter metaKey should be non empty.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
String regex = "^[a-zA-Z0-9_.]*$";
if (!metadata.getMetaKey().matches(regex)) {
String msg = "Request parameter metaKey should only contain period, " +
"underscore and alphanumeric characters.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if (metadata.getMetaValue() == null) {
String msg = "Request parameter metaValue should be non empty.";
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder()
.setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
if (metadata.getDataType() != null) {
for (Metadata.DataType dataType : Metadata.DataType.values()) {
if (dataType.name().equals(metadata.getDataType().name())) {
return;
}
}
}
String msg = "Request parameter dataType should only contain one of following:" +
Arrays.asList(Metadata.DataType.values());
log.error(msg);
throw new InputValidationException(
new ErrorResponse.ErrorResponseBuilder().setCode(HttpStatus.SC_BAD_REQUEST).setMessage(msg).build());
}
public static boolean isNonFilterRequest(String username, String firstName, String lastName, String emailAddress) { public static boolean isNonFilterRequest(String username, String firstName, String lastName, String emailAddress) {
return StringUtils.isEmpty(username) && StringUtils.isEmpty(firstName) && StringUtils.isEmpty(lastName) return StringUtils.isEmpty(username) && StringUtils.isEmpty(firstName) && StringUtils.isEmpty(lastName)
&& StringUtils.isEmpty(emailAddress); && StringUtils.isEmpty(emailAddress);

@ -46,6 +46,7 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration;
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService;
import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService; import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService;
import org.wso2.carbon.device.mgt.common.metadata.mgt.MetadataManagementService;
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService;
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService; import org.wso2.carbon.device.mgt.common.permission.mgt.PermissionManagerService;
@ -139,6 +140,7 @@ public class DeviceMgtAPIUtils {
private static char[] keyStorePassword; private static char[] keyStorePassword;
private static IntegrationClientService integrationClientService; private static IntegrationClientService integrationClientService;
private static MetadataManagementService metadataManagementService;
static { static {
String keyStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Password"); String keyStorePassword = ServerConfiguration.getInstance().getFirstProperty("Security.KeyStore.Password");
@ -435,6 +437,28 @@ public class DeviceMgtAPIUtils {
return notificationManagementService; return notificationManagementService;
} }
/**
* Initializing and accessing method for MetadataManagementService.
*
* @return MetadataManagementService instance
* @throws IllegalStateException if metadataManagementService cannot be initialized
*/
public static MetadataManagementService getMetadataManagementService() {
if (metadataManagementService == null) {
synchronized (DeviceMgtAPIUtils.class) {
if (metadataManagementService == null) {
PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext();
metadataManagementService = (MetadataManagementService) ctx.getOSGiService(
MetadataManagementService.class, null);
if (metadataManagementService == null) {
throw new IllegalStateException("Metadata Management service not initialized.");
}
}
}
}
return metadataManagementService;
}
/** /**
* Method for initializing ReportManagementService * Method for initializing ReportManagementService
* @return ReportManagementServie Instance * @return ReportManagementServie Instance

@ -48,6 +48,7 @@
<ref bean="deviceAgentService"/> <ref bean="deviceAgentService"/>
<ref bean="swaggerResource"/> <ref bean="swaggerResource"/>
<ref bean="analyticsArtifactsManagementService"/> <ref bean="analyticsArtifactsManagementService"/>
<ref bean="metadataService"/>
</jaxrs:serviceBeans> </jaxrs:serviceBeans>
<jaxrs:providers> <jaxrs:providers>
<ref bean="jsonProvider"/> <ref bean="jsonProvider"/>
@ -97,6 +98,7 @@
<bean id="deviceAgentService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.DeviceAgentServiceImpl"/> <bean id="deviceAgentService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.DeviceAgentServiceImpl"/>
<bean id="jsonProvider" class="org.wso2.carbon.device.mgt.jaxrs.common.GsonMessageBodyHandler"/> <bean id="jsonProvider" class="org.wso2.carbon.device.mgt.jaxrs.common.GsonMessageBodyHandler"/>
<bean id="analyticsArtifactsManagementService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.AnalyticsArtifactsManagementServiceImpl"/> <bean id="analyticsArtifactsManagementService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.AnalyticsArtifactsManagementServiceImpl"/>
<bean id="metadataService" class="org.wso2.carbon.device.mgt.jaxrs.service.impl.MetadataServiceImpl"/>
<!--<bean id="errorHandler" class="org.wso2.carbon.device.mgt.jaxrs.common.ErrorHandler"/>--> <!--<bean id="errorHandler" class="org.wso2.carbon.device.mgt.jaxrs.common.ErrorHandler"/>-->
<cxf:bus> <cxf:bus>

@ -0,0 +1,60 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.common.exceptions;
/**
* Custom exception class to be used in MetadataMgmt related functionalities.
*/
public class MetadataKeyAlreadyExistsException extends Exception {
private static final long serialVersionUID = -1814347544027733436L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public MetadataKeyAlreadyExistsException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public MetadataKeyAlreadyExistsException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public MetadataKeyAlreadyExistsException(String msg) {
super(msg);
setErrorMessage(msg);
}
public MetadataKeyAlreadyExistsException() {
super();
}
public MetadataKeyAlreadyExistsException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.common.exceptions;
/**
* Custom exception class to be used in MetadataMgmt related functionalities.
*/
public class MetadataKeyNotFoundException extends Exception {
private static final long serialVersionUID = 5260831982626354815L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public MetadataKeyNotFoundException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public MetadataKeyNotFoundException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public MetadataKeyNotFoundException(String msg) {
super(msg);
setErrorMessage(msg);
}
public MetadataKeyNotFoundException() {
super();
}
public MetadataKeyNotFoundException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.common.exceptions;
/**
* Custom exception class to be used in MetadataMgmt related functionalities.
*/
public class MetadataManagementException extends Exception {
private static final long serialVersionUID = -8933146283800122661L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public MetadataManagementException(String msg, Exception nestedEx) {
super(msg, nestedEx);
setErrorMessage(msg);
}
public MetadataManagementException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
public MetadataManagementException(String msg) {
super(msg);
setErrorMessage(msg);
}
public MetadataManagementException() {
super();
}
public MetadataManagementException(Throwable cause) {
super(cause);
}
}

@ -0,0 +1,83 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.common.metadata.mgt;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* DTO of Metadata object which is used to communicate Operation metadata to MDM core.
*/
@ApiModel(value = "Metadata", description = "This is used to communicate Operation metadata to MDM.")
public class Metadata {
/**
* Data types available in metadata repository.
*/
public enum DataType {
INT, STRING
}
@JsonProperty(value = "dataType")
@ApiModelProperty(name = "dataType", value = "Defines the data type related to the metadata", required = true)
private DataType dataType = DataType.STRING;
@JsonProperty(value = "metaKey", required = true)
@ApiModelProperty(name = "metaKey", value = "Defines the device Name related to the metadata.")
private String metaKey;
@JsonProperty(value = "metaValue", required = true)
@ApiModelProperty(name = "metaValue", value = "Provides the message you want to send to the user.", required = true)
private String metaValue;
public DataType getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = DataType.valueOf(dataType);
}
public String getMetaKey() {
return metaKey;
}
public void setMetaKey(String metaKey) {
this.metaKey = metaKey;
}
public String getMetaValue() {
return metaValue;
}
public void setMetaValue(String metaValue) {
this.metaValue = metaValue;
}
@Override
public String toString() {
return "metadata {" +
", type=" + dataType + '\'' +
", metaKey='" + metaKey + '\'' +
", metaValue='" + metaValue + '\'' +
'}';
}
}

@ -0,0 +1,92 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.common.metadata.mgt;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataKeyAlreadyExistsException;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataKeyNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataManagementException;
import java.util.List;
/**
* Defines the contract of MetadataManagementService.
*/
public interface MetadataManagementService {
/**
* Persist the provided Metadata entry.
*
* @param metadata the Metadata entry to be persisted
* @return the Metadata entry along with the updated Metadata.id
* @throws MetadataManagementException If a data source related exception occurred
* @throws MetadataKeyAlreadyExistsException If the provided Metadata.metaKey already exist
*/
Metadata createMetadata(Metadata metadata) throws MetadataManagementException, MetadataKeyAlreadyExistsException;
/**
* Get the specified Metadata entry.
*
* @param metaKey a string to be search against the Metadata.metaKey
* @return the Metadata entry for specified Metadata.metaKey
* @throws MetadataManagementException If a data source related exception occurred
* @throws MetadataKeyNotFoundException If the provided Metadata.metaKey not found
*/
Metadata retrieveMetadata(String metaKey) throws MetadataManagementException, MetadataKeyNotFoundException;
/**
* Get all Metadata entries.
*
* @return a list of Metadata entries
* @throws MetadataManagementException If a data source related exception occurred
*/
List<Metadata> retrieveAllMetadata() throws MetadataManagementException;
/**
* Get a paginated list of Metadata entries.
*
* @param request {@link PaginationRequest} obtained from the user
* @return {@link PaginationResult} enriched with metadata entries
* @throws MetadataManagementException If a data source related exception occurred
*/
PaginationResult retrieveAllMetadata(PaginationRequest request) throws MetadataManagementException;
/**
* Update the provided Metadata entry.
* a new entry will be created if the provided Metadata.metaKey is not exist
*
* @param metadata the Metadata entry to be updated/created
* @return the updated/created Metadata entry
* @throws MetadataManagementException If a data source related exception occurred
*/
Metadata updateMetadata(Metadata metadata) throws MetadataManagementException;
/**
* Delete the specified Metadata entry.
*
* @param metaKey the key value of the Metadata entry to be deleted
* @return true if the Metadata entry is deleted successfully,
* false otherwise.
* @throws MetadataManagementException If a data source related exception occurred
* @throws MetadataKeyNotFoundException If the provided Metadata.metaKey not found
*/
boolean deleteMetadata(String metaKey) throws MetadataManagementException, MetadataKeyNotFoundException;
}

@ -33,6 +33,7 @@ public class PaginationConfiguration {
private int notificationListPageSize; private int notificationListPageSize;
private int activityListPageSize; private int activityListPageSize;
private int topicListPageSize; private int topicListPageSize;
private int metadataListPageSize;
public int getDeviceListPageSize() { public int getDeviceListPageSize() {
return deviceListPageSize; return deviceListPageSize;
@ -80,7 +81,7 @@ public class PaginationConfiguration {
} }
public int getTopicListPageSize() { public int getTopicListPageSize() {
return deviceListPageSize; return topicListPageSize;
} }
@XmlElement(name = "TopicListPageSize", required = true) @XmlElement(name = "TopicListPageSize", required = true)
@ -88,5 +89,13 @@ public class PaginationConfiguration {
this.topicListPageSize = topicListPageSize; this.topicListPageSize = topicListPageSize;
} }
public int getMetadataListPageSize() {
return metadataListPageSize;
}
@XmlElement(name = "MetadataListPageSize", required = true)
public void setMetadataListPageSize(int metadataListPageSize) {
this.metadataListPageSize = metadataListPageSize;
}
} }

@ -27,6 +27,7 @@ import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorization
import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfigurationManagementService;
import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService; import org.wso2.carbon.device.mgt.common.geo.service.GeoLocationProviderService;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.MetadataManagementService;
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementService;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager;
@ -49,6 +50,8 @@ import org.wso2.carbon.device.mgt.core.dao.GroupManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager; import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager;
import org.wso2.carbon.device.mgt.core.device.details.mgt.impl.DeviceInformationManagerImpl; import org.wso2.carbon.device.mgt.core.device.details.mgt.impl.DeviceInformationManagerImpl;
import org.wso2.carbon.device.mgt.core.geo.service.GeoLocationProviderServiceImpl; import org.wso2.carbon.device.mgt.core.geo.service.GeoLocationProviderServiceImpl;
import org.wso2.carbon.device.mgt.core.metadata.mgt.MetadataManagementServiceImpl;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.notification.mgt.NotificationManagementServiceImpl; import org.wso2.carbon.device.mgt.core.notification.mgt.NotificationManagementServiceImpl;
import org.wso2.carbon.device.mgt.core.notification.mgt.dao.NotificationManagementDAOFactory; import org.wso2.carbon.device.mgt.core.notification.mgt.dao.NotificationManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.operation.mgt.OperationManagerImpl; import org.wso2.carbon.device.mgt.core.operation.mgt.OperationManagerImpl;
@ -172,6 +175,7 @@ public class DeviceManagementServiceComponent {
GroupManagementDAOFactory.init(dsConfig); GroupManagementDAOFactory.init(dsConfig);
NotificationManagementDAOFactory.init(dsConfig); NotificationManagementDAOFactory.init(dsConfig);
OperationManagementDAOFactory.init(dsConfig); OperationManagementDAOFactory.init(dsConfig);
MetadataManagementDAOFactory.init(dsConfig);
/*Initialize the device cache*/ /*Initialize the device cache*/
DeviceManagerUtil.initializeDeviceCache(); DeviceManagerUtil.initializeDeviceCache();
@ -317,6 +321,10 @@ public class DeviceManagementServiceComponent {
GeoLocationProviderService geoService = new GeoLocationProviderServiceImpl(); GeoLocationProviderService geoService = new GeoLocationProviderServiceImpl();
bundleContext.registerService(GeoLocationProviderService.class.getName(), geoService, null); bundleContext.registerService(GeoLocationProviderService.class.getName(), geoService, null);
/* Registering Metadata Service */
MetadataManagementService metadataManagementService = new MetadataManagementServiceImpl();
bundleContext.registerService(MetadataManagementService.class.getName(), metadataManagementService, null);
/* Registering App Management service */ /* Registering App Management service */
try { try {
AppManagementConfigurationManager.getInstance().initConfig(); AppManagementConfigurationManager.getInstance().initConfig();

@ -0,0 +1,239 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.PaginationResult;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataKeyAlreadyExistsException;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataKeyNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.common.metadata.mgt.MetadataManagementService;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataDAO;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOException;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import java.sql.SQLException;
import java.util.List;
/**
* This class implements the MetadataManagementService.
*/
public class MetadataManagementServiceImpl implements MetadataManagementService {
private static final Log log = LogFactory.getLog(MetadataManagementServiceImpl.class);
private MetadataDAO metadataDAO;
public MetadataManagementServiceImpl() {
this.metadataDAO = MetadataManagementDAOFactory.getMetadataDAO();
}
@Override
public Metadata createMetadata(Metadata metadata)
throws MetadataManagementException, MetadataKeyAlreadyExistsException {
if (log.isDebugEnabled()) {
log.debug("Creating Metadata : [" + metadata.toString() + "]");
}
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
try {
MetadataManagementDAOFactory.beginTransaction();
if (metadataDAO.isExist(tenantId, metadata.getMetaKey())) {
String msg = "Specified metaKey is already exist. {metaKey:" + metadata.getMetaKey() + "}";
log.error(msg);
throw new MetadataKeyAlreadyExistsException(msg);
}
metadataDAO.addMetadata(tenantId, metadata);
MetadataManagementDAOFactory.commitTransaction();
if (log.isDebugEnabled()) {
log.debug("Metadata entry created successfully. " + metadata.toString());
}
return metadata;
} catch (MetadataManagementDAOException e) {
MetadataManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while creating the metadata entry. " + metadata.toString();
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException("Error occurred while creating metadata record", e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public Metadata retrieveMetadata(String metaKey) throws MetadataManagementException, MetadataKeyNotFoundException {
if (log.isDebugEnabled()) {
log.debug("Retrieving Metadata for metaKey:" + metaKey);
}
try {
MetadataManagementDAOFactory.openConnection();
Metadata metadata = metadataDAO.getMetadata(
PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true), metaKey);
if (metadata == null) {
String msg = "Specified Metadata entry has not found. {metaKey:" + metaKey + "}";
log.error(msg);
throw new MetadataKeyNotFoundException(msg);
}
return metadata;
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving the metadata entry for metaKey:" + metaKey;
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public List<Metadata> retrieveAllMetadata() throws MetadataManagementException {
if (log.isDebugEnabled()) {
log.debug("Retrieving all Metadata entries");
}
try {
MetadataManagementDAOFactory.openConnection();
PaginationRequest request = new PaginationRequest(0, -1);
return metadataDAO.getAllMetadata(request,
PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true));
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving all metadata entries";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public PaginationResult retrieveAllMetadata(PaginationRequest request) throws MetadataManagementException {
if (log.isDebugEnabled()) {
log.debug("Retrieving Metadata entries for given PaginationRequest [rowCount:" +
request.getRowCount() + ", startIndex:" + request.getStartIndex() + "]");
}
PaginationResult paginationResult = new PaginationResult();
request = DeviceManagerUtil.validateMetadataListPageSize(request);
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
try {
MetadataManagementDAOFactory.openConnection();
List<Metadata> metadata = metadataDAO.getAllMetadata(request, tenantId);
int count = metadataDAO.getMetadataCount(tenantId);
paginationResult.setData(metadata);
paginationResult.setRecordsFiltered(count);
paginationResult.setRecordsTotal(count);
return paginationResult;
} catch (MetadataManagementDAOException e) {
String msg = "Error occurred while retrieving metadata entries for given PaginationRequest [rowCount:" +
request.getRowCount() + ", startIndex:" + request.getStartIndex() + "]";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public Metadata updateMetadata(Metadata metadata) throws MetadataManagementException {
if (log.isDebugEnabled()) {
log.debug("Updating Metadata : [" + metadata.toString() + "]");
}
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true);
try {
MetadataManagementDAOFactory.beginTransaction();
if (metadataDAO.isExist(tenantId, metadata.getMetaKey())) {
metadataDAO.updateMetadata(tenantId, metadata);
if (log.isDebugEnabled()) {
log.debug("A Metadata entry has updated successfully. " + metadata.toString());
}
} else {
metadataDAO.addMetadata(tenantId, metadata);
if (log.isDebugEnabled()) {
log.debug("Metadata entry has inserted successfully, due to the absence of provided metaKey " +
metadata.toString());
}
}
MetadataManagementDAOFactory.commitTransaction();
return metadata;
} catch (MetadataManagementDAOException e) {
MetadataManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while updating metadata entry. " + metadata.toString();
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
@Override
public boolean deleteMetadata(String key) throws MetadataManagementException, MetadataKeyNotFoundException {
if (log.isDebugEnabled()) {
log.debug("Deleting metadata entry. {metaKey:" + key + "}");
}
try {
MetadataManagementDAOFactory.beginTransaction();
boolean status = metadataDAO.deleteMetadata(
PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true), key);
MetadataManagementDAOFactory.commitTransaction();
if (status) {
if (log.isDebugEnabled()) {
log.debug("Metadata entry has deleted successfully. {metaKey:" + key + "}");
}
return true;
} else {
String msg = "Specified Metadata entry has not found. {metaKey:" + key + "}";
log.error(msg);
throw new MetadataKeyNotFoundException(msg);
}
} catch (MetadataManagementDAOException e) {
MetadataManagementDAOFactory.rollbackTransaction();
String msg = "Error occurred while deleting metadata entry. {metaKey:" + key + "}";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source";
log.error(msg, e);
throw new MetadataManagementException(msg, e);
} finally {
MetadataManagementDAOFactory.closeConnection();
}
}
}

@ -0,0 +1,103 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import java.util.List;
/**
* This class defines the methods to be implemented by MetadataDAO layer.
*/
public interface MetadataDAO {
/**
* Insert metadata entry to datasource.
*
* @param tenantId Tenant Id
* @param metadata Metadata object.
* @return a number, auto-generated assigned to Metadata.id
* @throws MetadataManagementDAOException might occur while executing database queries
*/
int addMetadata(int tenantId, Metadata metadata) throws MetadataManagementDAOException;
/**
* Select a Metadata entry by the provided metaKey.
*
* @param tenantId Tenant Id
* @param metaKey a string to be search against the Metadata.metaKey
* @return the Metadata entry for specified Metadata.metaKey
* @throws MetadataManagementDAOException might occur while executing database queries
*/
Metadata getMetadata(int tenantId, String metaKey) throws MetadataManagementDAOException;
/**
* Check if the specified Metadata entry exists.
*
* @param tenantId Tenant Id
* @param metaKey the key value of the Metadata entry to be checked
* @return true if the Metadata entry is exist,
* false otherwise.
* @throws MetadataManagementDAOException might occur while executing database queries
*/
boolean isExist(int tenantId, String metaKey) throws MetadataManagementDAOException;
/**
* Update the specified Metadata entry.
*
* @param tenantId Tenant Id
* @param metadata Metadata object.
* @return true if the Metadata entry is updated successfully,
* false otherwise.
* @throws MetadataManagementDAOException might occur while executing database queries
*/
boolean updateMetadata(int tenantId, Metadata metadata) throws MetadataManagementDAOException;
/**
* Delete specified Metadata entry.
*
* @param tenantId Tenant Id
* @param metaKey the key value of the Metadata entry to be deleted
* @return true if the Metadata entry is deleted successfully,
* false otherwise.
* @throws MetadataManagementDAOException might occur while executing database queries
*/
boolean deleteMetadata(int tenantId, String metaKey) throws MetadataManagementDAOException;
/**
* Select Metadata entries based on PaginationRequest.
*
* @param request {@link PaginationRequest}
* @param tenantId Tenant Id
* @return a list of Metadata entries
* @throws MetadataManagementDAOException might occur while executing database queries
*/
List<Metadata> getAllMetadata(PaginationRequest request, int tenantId) throws MetadataManagementDAOException;
/**
* Count number of Metadata entries.
*
* @param tenantId Tenant Id
* @return Metadata entry count of given tenant
* @throws MetadataManagementDAOException might occur while executing database queries
*/
int getMetadataCount(int tenantId) throws MetadataManagementDAOException;
}

@ -0,0 +1,78 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao;
/**
* Custom exception class for data access related exceptions.
*/
public class MetadataManagementDAOException extends Exception {
private String message;
private static final long serialVersionUID = 2021891706072918865L;
/**
* Constructs a new exception with the specified detail message and nested exception.
*
* @param message error message
* @param nestedException exception
*/
public MetadataManagementDAOException(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 MetadataManagementDAOException(String message, Throwable cause) {
super(message, cause);
setErrorMessage(message);
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message.
*/
public MetadataManagementDAOException(String message) {
super(message);
setErrorMessage(message);
}
/**
* Constructs a new exception with the specified and cause.
*
* @param cause the cause of this exception.
*/
public MetadataManagementDAOException(Throwable cause) {
super(cause);
}
public String getMessage() {
return message;
}
public void setErrorMessage(String errorMessage) {
this.message = errorMessage;
}
}

@ -0,0 +1,201 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.DeviceManagementConstants;
import org.wso2.carbon.device.mgt.common.exceptions.IllegalTransactionStateException;
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.UnsupportedDatabaseEngineException;
import org.wso2.carbon.device.mgt.core.config.datasource.DataSourceConfig;
import org.wso2.carbon.device.mgt.core.config.datasource.JNDILookupDefinition;
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl.GenericMetadataDAOImpl;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl.OracleMetadataDAOImpl;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl.SQLServerMetadataDAOImpl;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.List;
import javax.sql.DataSource;
/**
* DAO factory class to be used in MetadataManagement related functionalities.
*/
public class MetadataManagementDAOFactory {
private static DataSource dataSource;
private static String databaseEngine;
private static final Log log = LogFactory.getLog(MetadataManagementDAOFactory.class);
private static ThreadLocal<Connection> currentConnection = new ThreadLocal<>();
public static MetadataDAO getMetadataDAO() {
if (databaseEngine != null) {
switch (databaseEngine) {
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_ORACLE:
return new OracleMetadataDAOImpl();
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MSSQL:
return new SQLServerMetadataDAOImpl();
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_POSTGRESQL:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_H2:
case DeviceManagementConstants.DataBaseTypes.DB_TYPE_MYSQL:
return new GenericMetadataDAOImpl();
default:
throw new UnsupportedDatabaseEngineException("Unsupported database engine : " + databaseEngine);
}
}
throw new IllegalStateException("Database engine has not initialized properly.");
}
public static void init(DataSourceConfig config) {
dataSource = resolveDataSource(config);
try {
databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
} catch (SQLException e) {
log.error("Error occurred while retrieving config.datasource connection", e);
}
}
public static void init(DataSource dtSource) {
dataSource = dtSource;
try {
databaseEngine = dataSource.getConnection().getMetaData().getDatabaseProductName();
} catch (SQLException e) {
log.error("Error occurred while retrieving config.datasource connection", e);
}
}
public static void beginTransaction() throws TransactionManagementException {
Connection conn = currentConnection.get();
if (conn != null) {
throw new IllegalTransactionStateException("A transaction is already active within the context of " +
"this particular thread. Therefore, calling 'beginTransaction/openConnection' while another " +
"transaction is already active is a sign of improper transaction handling");
}
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
currentConnection.set(conn);
} catch (SQLException e) {
throw new TransactionManagementException("Error occurred while retrieving config.datasource connection", e);
}
}
public static void openConnection() throws SQLException {
Connection conn = currentConnection.get();
if (conn != null) {
throw new IllegalTransactionStateException("A transaction is already active within the context of " +
"this particular thread. Therefore, calling 'beginTransaction/openConnection' while another " +
"transaction is already active is a sign of improper transaction handling");
}
conn = dataSource.getConnection();
currentConnection.set(conn);
}
public static Connection getConnection() throws IllegalTransactionStateException {
Connection conn = currentConnection.get();
if (conn == null) {
throw new IllegalTransactionStateException("No connection is associated with the current transaction. " +
"This might have ideally been caused by not properly initiating the transaction via " +
"'beginTransaction'/'openConnection' methods");
}
return conn;
}
public static void commitTransaction() {
Connection conn = currentConnection.get();
if (conn == null) {
throw new IllegalTransactionStateException("No connection is associated with the current transaction. " +
"This might have ideally been caused by not properly initiating the transaction via " +
"'beginTransaction'/'openConnection' methods");
}
try {
conn.commit();
} catch (SQLException e) {
log.error("Error occurred while committing the transaction", e);
}
}
public static void rollbackTransaction() {
Connection conn = currentConnection.get();
if (conn == null) {
throw new IllegalTransactionStateException("No connection is associated with the current transaction. " +
"This might have ideally been caused by not properly initiating the transaction via " +
"'beginTransaction'/'openConnection' methods");
}
try {
conn.rollback();
} catch (SQLException e) {
log.warn("Error occurred while roll-backing the transaction", e);
}
}
public static void closeConnection() {
Connection conn = currentConnection.get();
if (conn == null) {
throw new IllegalTransactionStateException("No connection is associated with the current transaction. " +
"This might have ideally been caused by not properly initiating the transaction via " +
"'beginTransaction'/'openConnection' methods");
}
try {
conn.close();
} catch (SQLException e) {
log.warn("Error occurred while close the connection");
}
currentConnection.remove();
}
/**
* Resolve data source from the data source definition.
*
* @param config data source configuration
* @return data source resolved from the data source definition
*/
private static DataSource resolveDataSource(DataSourceConfig config) {
DataSource dataSource = null;
if (config == null) {
throw new RuntimeException(
"Device Management Repository data source configuration " + "is null and " +
"thus, is not initialized");
}
JNDILookupDefinition jndiConfig = config.getJndiLookupDefinition();
if (jndiConfig != null) {
if (log.isDebugEnabled()) {
log.debug("Initializing Device Management Repository data source using the JNDI " +
"Lookup Definition");
}
List<JNDILookupDefinition.JNDIProperty> jndiPropertyList =
jndiConfig.getJndiProperties();
if (jndiPropertyList != null) {
Hashtable<Object, Object> jndiProperties = new Hashtable<>();
for (JNDILookupDefinition.JNDIProperty prop : jndiPropertyList) {
jndiProperties.put(prop.getName(), prop.getValue());
}
dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), jndiProperties);
} else {
dataSource = DeviceManagementDAOUtil.lookupDataSource(jndiConfig.getJndiName(), null);
}
}
return dataSource;
}
}

@ -0,0 +1,179 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataDAO;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOException;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.util.MetadataDAOUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* Implementation of MetadataDAO which includes the methods to do CRUD operations on metadata.
*/
public abstract class AbstractMetadataDAOImpl implements MetadataDAO {
private static final Log log = LogFactory.getLog(AbstractMetadataDAOImpl.class);
@Override
public int addMetadata(int tenantId, Metadata metadata) throws MetadataManagementDAOException {
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String sql = "INSERT INTO DM_METADATA (DATA_TYPE, METADATA_KEY, METADATA_VALUE, TENANT_ID) " +
"VALUES (?, ?, ?, ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
stmt.setString(1, metadata.getDataType().toString());
stmt.setString(2, metadata.getMetaKey());
stmt.setString(3, metadata.getMetaValue());
stmt.setInt(4, tenantId);
stmt.executeUpdate();
try (ResultSet rs = stmt.getGeneratedKeys()) {
rs.next();
return rs.getInt(1);
}
}
} catch (SQLException e) {
String msg = "Error occurred while adding the " + "Metadata for metadataKey : " + metadata.getMetaKey();
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
}
@Override
public Metadata getMetadata(int tenantId, String metaKey) throws MetadataManagementDAOException {
Metadata metadata = null;
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String sql = "SELECT DATA_TYPE, METADATA_KEY, METADATA_VALUE " +
"FROM DM_METADATA " +
"WHERE TENANT_ID = ? " +
"AND METADATA_KEY = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
stmt.setString(2, metaKey);
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
metadata = MetadataDAOUtil.getMetadata(rs);
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving data for metadataKey : " + metaKey;
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return metadata;
}
@Override
public boolean updateMetadata(int tenantId, Metadata metadata) throws MetadataManagementDAOException {
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String sql = "UPDATE DM_METADATA " +
"SET DATA_TYPE = ?, METADATA_VALUE = ? " +
"WHERE METADATA_KEY = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, metadata.getDataType().toString());
stmt.setString(2, metadata.getMetaValue());
stmt.setString(3, metadata.getMetaKey());
stmt.setInt(4, tenantId);
int rows = stmt.executeUpdate();
return rows == 1;
}
} catch (SQLException e) {
String msg = "Error occurred while updating data of metadataKey:" + metadata.getMetaKey();
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
}
@Override
public boolean deleteMetadata(int tenantId, String key) throws MetadataManagementDAOException {
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String query = "DELETE FROM DM_METADATA WHERE METADATA_KEY = ? AND TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setString(1, key);
stmt.setInt(2, tenantId);
int rows = stmt.executeUpdate();
return rows == 1;
}
} catch (SQLException e) {
String msg = "Error occurred while deleting metadata for specified metadataKey:" + key;
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
}
@Override
public int getMetadataCount(int tenantId) throws MetadataManagementDAOException {
int metadataCount = 0;
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String sql =
"SELECT COUNT(*) AS METADATA_COUNT FROM DM_METADATA WHERE TENANT_ID = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
metadataCount = rs.getInt("METADATA_COUNT");
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while counting metadata";
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return metadataCount;
}
@Override
public boolean isExist(int tenantId, String metaKey) throws MetadataManagementDAOException {
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String sql = "SELECT COUNT(*) AS COUNT FROM DM_METADATA " +
"WHERE TENANT_ID = ? " +
"AND METADATA_KEY = ?";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
stmt.setString(2, metaKey);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return rs.getInt(1) != 0;
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while checking the existence of Metadata entry for metadataKey:" + metaKey;
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return false;
}
}

@ -0,0 +1,101 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOException;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.util.MetadataDAOUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* This class holds the generic implementation of MetadataDAO which can be used to support ANSI db syntax.
*/
public class GenericMetadataDAOImpl extends AbstractMetadataDAOImpl {
private static final Log log = LogFactory.getLog(GenericMetadataDAOImpl.class);
@Override
public List<Metadata> getAllMetadata(PaginationRequest request, int tenantId)
throws MetadataManagementDAOException {
List<Metadata> metadata;
String sql = "SELECT DATA_TYPE, METADATA_KEY, METADATA_VALUE " +
"FROM DM_METADATA " +
"WHERE TENANT_ID = ? " +
"ORDER BY METADATA_KEY";
if (request.getRowCount() != -1) {
sql = sql + " LIMIT ? OFFSET ?";
}
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
if (request.getRowCount() != -1) {
stmt.setInt(2, request.getRowCount());
stmt.setInt(3, request.getStartIndex());
}
try (ResultSet rs = stmt.executeQuery()) {
metadata = new ArrayList<>();
while (rs.next()) {
metadata.add(MetadataDAOUtil.getMetadata(rs));
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving all metadata";
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return metadata;
}
@Override
public boolean isExist(int tenantId, String metaKey) throws MetadataManagementDAOException {
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
String sql = "SELECT EXISTS (SELECT METADATA_KEY FROM DM_METADATA " +
"WHERE TENANT_ID = ? " +
"AND METADATA_KEY = ?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
stmt.setString(2, metaKey);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return rs.getInt(1) == 1;
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while checking the existence of Metadata entry for metadataKey:" + metaKey;
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return false;
}
}

@ -0,0 +1,77 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOException;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.util.MetadataDAOUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* This class holds the Oracle implementation of MetadataDAO which can be used to support Oracle db syntax.
*/
public class OracleMetadataDAOImpl extends AbstractMetadataDAOImpl {
private static final Log log = LogFactory.getLog(OracleMetadataDAOImpl.class);
@Override
public List<Metadata> getAllMetadata(PaginationRequest request, int tenantId)
throws MetadataManagementDAOException {
List<Metadata> metadata;
String sql = "SELECT DATA_TYPE, METADATA_KEY, METADATA_VALUE " +
"FROM DM_METADATA " +
"WHERE TENANT_ID = ? " +
"ORDER BY METADATA_KEY";
if (request.getRowCount() != -1) {
sql = sql + " OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
}
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
if (request.getRowCount() != -1) {
stmt.setInt(2, request.getStartIndex());
stmt.setInt(3, request.getRowCount());
}
try (ResultSet rs = stmt.executeQuery()) {
metadata = new ArrayList<>();
while (rs.next()) {
metadata.add(MetadataDAOUtil.getMetadata(rs));
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving all metadata";
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return metadata;
}
}

@ -0,0 +1,77 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.PaginationRequest;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOException;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.MetadataManagementDAOFactory;
import org.wso2.carbon.device.mgt.core.metadata.mgt.dao.util.MetadataDAOUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* This class holds the implementation of MetadataDAO which can be used to support SQLServer db syntax.
*/
public class SQLServerMetadataDAOImpl extends AbstractMetadataDAOImpl {
private static final Log log = LogFactory.getLog(SQLServerMetadataDAOImpl.class);
@Override
public List<Metadata> getAllMetadata(PaginationRequest request, int tenantId)
throws MetadataManagementDAOException {
List<Metadata> metadata;
String sql = "SELECT DATA_TYPE, METADATA_KEY, METADATA_VALUE " +
"FROM DM_METADATA " +
"WHERE TENANT_ID = ? " +
"ORDER BY METADATA_KEY";
if (request.getRowCount() != -1) {
sql = sql + " OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
}
try {
Connection conn = MetadataManagementDAOFactory.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, tenantId);
if (request.getRowCount() != -1) {
stmt.setInt(2, request.getStartIndex());
stmt.setInt(3, request.getRowCount());
}
try (ResultSet rs = stmt.executeQuery()) {
metadata = new ArrayList<>();
while (rs.next()) {
metadata.add(MetadataDAOUtil.getMetadata(rs));
}
}
}
} catch (SQLException e) {
String msg = "Error occurred while retrieving all metadata";
log.error(msg, e);
throw new MetadataManagementDAOException(msg, e);
}
return metadata;
}
}

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020, 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 org.wso2.carbon.device.mgt.core.metadata.mgt.dao.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.metadata.mgt.Metadata;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* This class includes the utility methods required by MetadataMgmt functionalities.
*/
public class MetadataDAOUtil {
private static final Log log = LogFactory.getLog(MetadataDAOUtil.class);
/**
* Populates {@link Metadata} object with the result obtained from the database.
*
* @param rs {@link ResultSet} obtained from the database
* @return {@link Metadata} object populated with the data
* @throws SQLException If unable to populate {@link Metadata} object with the data
*/
public static Metadata getMetadata(ResultSet rs) throws SQLException {
Metadata metadata = new Metadata();
metadata.setMetaKey(rs.getString("METADATA_KEY"));
metadata.setMetaValue(rs.getString("METADATA_VALUE"));
metadata.setDataType(rs.getString("DATA_TYPE"));
return metadata;
}
}

@ -53,6 +53,7 @@ import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException; import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException;
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
import org.wso2.carbon.device.mgt.common.exceptions.MetadataManagementException;
import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException; import org.wso2.carbon.device.mgt.common.notification.mgt.NotificationManagementException;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
import org.wso2.carbon.device.mgt.common.type.mgt.DeviceTypeMetaDefinition; import org.wso2.carbon.device.mgt.common.type.mgt.DeviceTypeMetaDefinition;
@ -452,6 +453,30 @@ public final class DeviceManagerUtil {
return limit; return limit;
} }
/**
* Validate Metadata pagination request.
*
* @param paginationRequest {@link PaginationRequest} obtained from the user
* @return {@link PaginationRequest} object validated/enriched
* @throws MetadataManagementException if device management configuration has not initialized
*/
public static PaginationRequest validateMetadataListPageSize(PaginationRequest paginationRequest) throws
MetadataManagementException {
if (paginationRequest.getRowCount() == 0) {
DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance().
getDeviceManagementConfig();
if (deviceManagementConfig != null) {
paginationRequest.setRowCount(deviceManagementConfig.getPaginationConfiguration().
getMetadataListPageSize());
} else {
String msg = "Device-Mgt configuration has not initialized. Please check the cdm-config.xml file.";
log.error(msg);
throw new MetadataManagementException(msg);
}
}
return paginationRequest;
}
public static boolean isPublishLocationResponseEnabled() throws DeviceManagementException { public static boolean isPublishLocationResponseEnabled() throws DeviceManagementException {
DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance(). DeviceManagementConfig deviceManagementConfig = DeviceConfigurationManager.getInstance().
getDeviceManagementConfig(); getDeviceManagementConfig();

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -71,6 +71,7 @@
<ActivityListPageSize>20</ActivityListPageSize> <ActivityListPageSize>20</ActivityListPageSize>
<OperationListPageSize>20</OperationListPageSize> <OperationListPageSize>20</OperationListPageSize>
<TopicListPageSize>20</TopicListPageSize> <TopicListPageSize>20</TopicListPageSize>
<MetadataListPageSize>20</MetadataListPageSize>
</PaginationConfiguration> </PaginationConfiguration>
<!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node <!--This specifies whether to enable the DeviceStatus Task in this node. In clustered setup only master node
should have to run this task.--> should have to run this task.-->

@ -556,6 +556,18 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_TYPE_PLATFORM (
) )
); );
-- METADATA TABLE --
CREATE TABLE IF NOT EXISTS DM_METADATA (
METADATA_ID INT AUTO_INCREMENT NOT NULL,
DATA_TYPE VARCHAR(16) NOT NULL,
METADATA_KEY VARCHAR(128) NOT NULL,
METADATA_VALUE VARCHAR(512) NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (METADATA_ID),
CONSTRAINT METADATA_KEY_TENANT_ID UNIQUE (METADATA_KEY, TENANT_ID)
);
-- END OF METADATA TABLE --
-- DASHBOARD RELATED VIEWS -- -- DASHBOARD RELATED VIEWS --
CREATE VIEW POLICY_COMPLIANCE_INFO AS CREATE VIEW POLICY_COMPLIANCE_INFO AS
SELECT SELECT

@ -595,6 +595,19 @@ CREATE TABLE DM_DEVICE_TYPE_PLATFORM(
) )
); );
-- METADATA TABLE --
IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[DM_METADATA]') AND TYPE IN (N'U'))
CREATE TABLE DM_METADATA (
METADATA_ID INTEGER IDENTITY(1,1) NOT NULL,
DATA_TYPE VARCHAR(16) NOT NULL,
METADATA_KEY VARCHAR(128) NOT NULL,
METADATA_VALUE VARCHAR(512) NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (METADATA_ID),
CONSTRAINT METADATA_KEY_TENANT_ID UNIQUE(METADATA_KEY, TENANT_ID)
);
-- END OF METADATA TABLE --
-- DASHBOARD RELATED VIEWS -- -- DASHBOARD RELATED VIEWS --
IF NOT EXISTS (SELECT * FROM SYS.VIEWS WHERE NAME = 'POLICY_COMPLIANCE_INFO') IF NOT EXISTS (SELECT * FROM SYS.VIEWS WHERE NAME = 'POLICY_COMPLIANCE_INFO')

@ -614,6 +614,17 @@ CREATE TABLE IF NOT EXISTS `DM_DEVICE_TYPE_PLATFORM` (
) )
ENGINE = InnoDB; ENGINE = InnoDB;
-- METADATA TABLE --
CREATE TABLE IF NOT EXISTS DM_METADATA (
METADATA_ID INTEGER NOT NULL AUTO_INCREMENT,
DATA_TYPE VARCHAR(16) NOT NULL,
METADATA_KEY VARCHAR(128) NOT NULL,
METADATA_VALUE VARCHAR(512) NOT NULL,
TENANT_ID INTEGER NOT NULL,
PRIMARY KEY (METADATA_ID),
UNIQUE KEY METADATA_KEY_TENANT_ID (METADATA_KEY,TENANT_ID)
) ENGINE=InnoDB;
-- END OF METADATA TABLE --
-- DASHBOARD RELATED VIEWS -- -- DASHBOARD RELATED VIEWS --

@ -945,6 +945,32 @@ BEGIN
END; END;
/ /
-- METADATA TABLE --
CREATE TABLE DM_METADATA (
METADATA_ID NUMBER(10) NOT NULL,
DATA_TYPE VARCHAR2(16) NOT NULL,
METADATA_KEY VARCHAR2(128) NOT NULL,
METADATA_VALUE VARCHAR2(512) NOT NULL,
TENANT_ID INTEGER NOT NULL,
CONSTRAINT PK_DM_METADATA PRIMARY KEY (METADATA_ID),
CONSTRAINT METADATA_KEY_TENANT_ID UNIQUE (METADATA_KEY, TENANT_ID)
)
/
-- Generate ID using sequence and trigger
CREATE SEQUENCE DM_METADATA_id_seq START WITH 1 INCREMENT BY 1 NOCACHE
/
CREATE OR REPLACE TRIGGER DM_METADATA_id_seq_tr
BEFORE INSERT
ON DM_METADATA
REFERENCING NEW AS NEW
FOR EACH ROW
WHEN (NEW.METADATA_ID IS NULL)
BEGIN
SELECT DM_METADATA_id_seq.NEXTVAL INTO :NEW.METADATA_ID FROM DUAL;
END;
/
-- END OF METADATA TABLE --
-- DASHBOARD RELATED VIEWS -- -- DASHBOARD RELATED VIEWS --
CREATE VIEW POLICY_COMPLIANCE_INFO AS CREATE VIEW POLICY_COMPLIANCE_INFO AS

@ -605,6 +605,17 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL (
CREATE INDEX FK_DM_DEVICE_DETAILS_DEVICE_idx ON DM_DEVICE_DETAIL (DEVICE_ID ASC); CREATE INDEX FK_DM_DEVICE_DETAILS_DEVICE_idx ON DM_DEVICE_DETAIL (DEVICE_ID ASC);
CREATE INDEX FK_DM_ENROLMENT_DEVICE_DETAILS_idx ON DM_DEVICE_DETAIL (ENROLMENT_ID ASC); CREATE INDEX FK_DM_ENROLMENT_DEVICE_DETAILS_idx ON DM_DEVICE_DETAIL (ENROLMENT_ID ASC);
-- METADATA TABLE --
CREATE TABLE IF NOT EXISTS DM_METADATA (
METADATA_ID BIGSERIAL PRIMARY KEY,
DATA_TYPE VARCHAR(16) NOT NULL,
METADATA_KEY VARCHAR(128) NOT NULL,
METADATA_VALUE VARCHAR(512) NOT NULL,
TENANT_ID INTEGER NOT NULL,
CONSTRAINT METADATA_KEY_TENANT_ID UNIQUE(METADATA_KEY, TENANT_ID)
);
-- END OF METADATA TABLE --
-- DASHBOARD RELATED VIEWS -- -- DASHBOARD RELATED VIEWS --
CREATE VIEW DEVICE_INFO_VIEW AS CREATE VIEW DEVICE_INFO_VIEW AS

Loading…
Cancel
Save