Added few fixes after testing and added default UI for device type management

4.x.x
ayyoob 8 years ago
parent 6004ee7264
commit dd1c2e4338

@ -257,7 +257,7 @@ public interface DeviceEventManagementService {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the event defintion.",
response = EventAttributeList.class,
response = DeviceTypeEvent.class,
responseHeaders = {
@ResponseHeader(
name = "Content-Type",

@ -33,6 +33,7 @@ import org.wso2.carbon.apimgt.annotations.api.Scope;
import org.wso2.carbon.apimgt.annotations.api.Scopes;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeList;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
@ -81,6 +82,57 @@ import javax.ws.rs.core.Response;
)
public interface DeviceTypeManagementAdminService {
@GET
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Getting the Supported Device Type with Meta Definition",
notes = "Get the list of device types supported by WSO2 IoT.",
tags = "Device Type Management",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:device-type")
})
}
)
@ApiResponses(
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully fetched the list of supported device types.",
response = DeviceTypeList.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 = 304,
message =
"Not Modified. \n Empty body because the client already has the latest version " +
"of the requested resource.\n"),
@ApiResponse(
code = 406,
message = "Not Acceptable.\n The requested media type is not supported"),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while fetching the " +
"list of supported device types.",
response = ErrorResponse.class)
}
)
Response getDeviceTypes();
@POST
@ApiOperation(
produces = MediaType.APPLICATION_JSON,

@ -40,16 +40,17 @@ import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceEventManagementService
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.event.publisher.stub.EventPublisherAdminServiceCallbackHandler;
import org.wso2.carbon.event.publisher.stub.EventPublisherAdminServiceStub;
import org.wso2.carbon.event.receiver.stub.types.EventMappingPropertyDto;
import org.wso2.carbon.event.receiver.stub.EventReceiverAdminServiceCallbackHandler;
import org.wso2.carbon.event.receiver.stub.EventReceiverAdminServiceStub;
import org.wso2.carbon.event.receiver.stub.types.BasicInputAdapterPropertyDto;
import org.wso2.carbon.event.receiver.stub.types.EventReceiverConfigurationDto;
import org.wso2.carbon.event.stream.stub.EventStreamAdminServiceStub;
import org.wso2.carbon.event.stream.stub.types.EventStreamAttributeDto;
import org.wso2.carbon.event.stream.stub.types.EventStreamDefinitionDto;
import org.wso2.carbon.identity.jwt.client.extension.JWTClient;
import org.wso2.carbon.identity.jwt.client.extension.exception.JWTClientException;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.analytics.datasource.commons.Record;
import org.wso2.carbon.analytics.datasource.commons.exception.AnalyticsException;
import javax.net.ssl.KeyManagerFactory;
@ -107,6 +108,8 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
private static final String DEFAULT_STREAM_VERSION = "1.0.0";
private static final String DEFAULT_EVENT_STORE_NAME = "EVENT_STORE";
private static final String DEFAULT_WEBSOCKET_PUBLISHER_ADAPTER_TYPE = "secured-websocket";
private static final String OAUTH_MQTT_ADAPTER_TYPE = "oauth-mqtt";
private static final String OAUTH_HTTP_ADAPTER_TYPE = "oauth-http";
private static KeyStore keyStore;
private static KeyStore trustStore;
@ -140,6 +143,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
public Response getDeviceTypeEventDefinition(@PathParam("type") String deviceType) {
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
EventStreamAdminServiceStub eventStreamAdminServiceStub = null;
EventReceiverAdminServiceStub eventReceiverAdminServiceStub = null;
try {
if (deviceType == null ||
!DeviceMgtAPIUtils.getDeviceManagementService().getAvailableDeviceTypes().contains(deviceType)) {
@ -162,7 +166,18 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
, AttributeType.valueOf(eventStreamAttributeDto.getAttributeType().toUpperCase())));
}
eventAttributeList.setList(attributes);
return Response.ok().entity(eventAttributeList).build();
DeviceTypeEvent deviceTypeEvent = new DeviceTypeEvent();
deviceTypeEvent.setEventAttributeList(eventAttributeList);
deviceTypeEvent.setTransportType(TransportType.HTTP);
eventReceiverAdminServiceStub = getEventReceiverAdminServiceStub();
EventReceiverConfigurationDto eventReceiverConfigurationDto = eventReceiverAdminServiceStub
.getActiveEventReceiverConfiguration(getReceiverName(deviceType, tenantDomain));
String eventAdapterType = eventReceiverConfigurationDto.getFromAdapterConfigurationDto()
.getEventAdapterType();
if (OAUTH_MQTT_ADAPTER_TYPE.equals(eventAdapterType)) {
deviceTypeEvent.setTransportType(TransportType.MQTT);
}
return Response.ok().entity(deviceTypeEvent).build();
} catch (AxisFault e) {
log.error("failed to retrieve event definitions for tenantDomain:" + tenantDomain, e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
@ -180,6 +195,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} finally {
cleanup(eventStreamAdminServiceStub);
cleanup(eventReceiverAdminServiceStub);
}
}
@ -293,8 +309,8 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
tenantBasedEventReceiverAdminServiceStub = getEventReceiverAdminServiceStub();
tenantBasedEventStreamAdminServiceStub = getEventStreamAdminServiceStub();
eventStreamAdminServiceStub.removeEventStreamDefinition(streamName, DEFAULT_STREAM_VERSION);
eventReceiverAdminServiceStub.startundeployInactiveEventReceiverConfiguration(eventReceiverName
tenantBasedEventStreamAdminServiceStub.removeEventStreamDefinition(streamName, DEFAULT_STREAM_VERSION);
tenantBasedEventReceiverAdminServiceStub.startundeployInactiveEventReceiverConfiguration(eventReceiverName
, eventReceiverAdminServiceCallbackHandler);
}
@ -323,6 +339,8 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
cleanup(eventReceiverAdminServiceStub);
cleanup(eventReceiverAdminServiceStub);
cleanup(eventStreamAdminServiceStub);
cleanup(tenantBasedEventReceiverAdminServiceStub);
cleanup(tenantBasedEventStreamAdminServiceStub);
}
}
@ -373,7 +391,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
throws RemoteException, UserStoreException, JWTClientException {
EventReceiverAdminServiceStub receiverAdminServiceStub = getEventReceiverAdminServiceStub();
try {
String adapterType = "oauth-mqtt";
String adapterType = OAUTH_MQTT_ADAPTER_TYPE;
BasicInputAdapterPropertyDto basicInputAdapterPropertyDtos[];
if (transportType == TransportType.MQTT) {
basicInputAdapterPropertyDtos = new BasicInputAdapterPropertyDto[4];
@ -383,7 +401,7 @@ public class DeviceEventManagementServiceImpl implements DeviceEventManagementSe
basicInputAdapterPropertyDtos[2] = getBasicInputAdapterPropertyDto("cleanSession", "true");
basicInputAdapterPropertyDtos[3] = getBasicInputAdapterPropertyDto("clientId", generateUUID());
} else {
adapterType = "oauth-http";
adapterType = OAUTH_HTTP_ADAPTER_TYPE;
basicInputAdapterPropertyDtos = new BasicInputAdapterPropertyDto[1];
basicInputAdapterPropertyDtos[0] = getBasicInputAdapterPropertyDto("contentValidator", "iot-mqtt");
}

@ -23,16 +23,21 @@ import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
import org.wso2.carbon.device.mgt.extensions.device.type.template.HTTPDeviceTypeManagerService;
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeList;
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.DeviceTypeManagementAdminService;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
@Path("/admin/device-types")
@Produces(MediaType.APPLICATION_JSON)
@ -41,10 +46,24 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen
private static final Log log = LogFactory.getLog(DeviceTypeManagementAdminServiceImpl.class);
@GET
@Override
public Response getDeviceTypes() {
try {
List<DeviceType> deviceTypes = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceTypes();
return Response.status(Response.Status.OK).entity(deviceTypes).build();
} catch (DeviceManagementException e) {
String msg = "Error occurred while fetching the list of device types.";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
@Override
@POST
public Response addDeviceType(DeviceType deviceType) {
if (deviceType != null) {
if (deviceType != null && deviceType.getDeviceTypeMetaDefinition() != null) {
try {
if (DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(deviceType.getName()) != null) {
String msg = "Device type already available, " + deviceType.getName();
@ -67,7 +86,7 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen
@Override
@PUT
public Response updateDeviceType(DeviceType deviceType) {
if (deviceType != null) {
if (deviceType != null && deviceType.getDeviceTypeMetaDefinition() != null) {
try {
if (DeviceMgtAPIUtils.getDeviceManagementService().getDeviceType(deviceType.getName()) == null) {
String msg = "Device type does not exist, " + deviceType.getName();

@ -18,6 +18,15 @@ public class DeviceTypeMetaDefinition {
private OperationMonitoringTaskConfig taskConfig;
private InitialOperationConfig initialOperationConfig;
private License license;
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<String> getProperties() {
return properties;

@ -22,7 +22,8 @@ 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.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceTypeServiceIdentifier;
import org.wso2.carbon.device.mgt.core.dto.DeviceManagementServiceHolder;
import org.wso2.carbon.device.mgt.core.dto.DeviceTypeServiceIdentifier;
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
import org.wso2.carbon.device.mgt.common.ProvisioningConfig;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager;
@ -50,8 +51,7 @@ import java.util.Map;
public class DeviceManagementPluginRepository implements DeviceManagerStartupListener {
private Map<DeviceTypeServiceIdentifier, DeviceManagementService> providers;
private Map<DeviceTypeServiceIdentifier, Long> dynamicProviderTimestamp;
private Map<DeviceTypeServiceIdentifier, DeviceManagementServiceHolder> providers;
private boolean isInited;
private static final Log log = LogFactory.getLog(DeviceManagementPluginRepository.class);
private OperationManagerRepository operationManagerRepository;
@ -59,8 +59,7 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
public DeviceManagementPluginRepository() {
this.operationManagerRepository = new OperationManagerRepository();
providers = Collections.synchronizedMap(new HashMap<DeviceTypeServiceIdentifier, DeviceManagementService>());
dynamicProviderTimestamp = Collections.synchronizedMap(new HashMap<DeviceTypeServiceIdentifier, Long>());
providers = Collections.synchronizedMap(new HashMap<DeviceTypeServiceIdentifier, DeviceManagementServiceHolder>());
DeviceManagementServiceComponent.registerStartupListener(this);
}
@ -81,15 +80,23 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
provider.init();
DeviceTypeMetaDefinition deviceTypeDefinition = null;
if (provider instanceof DeviceTypeDefinitionProvider) {
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(
provider.getType());
DeviceManagementServiceHolder existingProvider = providers.get(deviceTypeIdentifier);
deviceTypeDefinition = ((DeviceTypeDefinitionProvider) provider).getDeviceTypeMeta();
if (existingProvider != null && !(existingProvider.getDeviceManagementService()
instanceof DeviceTypeDefinitionProvider)) {
throw new DeviceManagementException("Definition of device type " + provider.getType()
+ " is already available through sharing.");
}
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(
provider.getType().toLowerCase(), tenantId);
DeviceManagementService existingProvider = providers.get(deviceTypeIdentifier);
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(provider.getType(), tenantId);
existingProvider = providers.get(deviceTypeIdentifier);
if (existingProvider != null) {
removeDeviceManagementProvider(provider);
}
}
DeviceManagerUtil.registerDeviceType(deviceType, tenantId, isSharedWithAllTenants, deviceTypeDefinition);
DeviceManagementDataHolder.getInstance().setRequireDeviceAuthorization(deviceType,
provider.getDeviceManager()
@ -101,15 +108,13 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
throw new DeviceManagementException("Error occurred while adding device management provider '" +
deviceType + "'", e);
}
DeviceManagementServiceHolder deviceManagementServiceHolder = new DeviceManagementServiceHolder(provider);
if (isSharedWithAllTenants) {
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceType);
providers.put(deviceTypeIdentifier, provider);
providers.put(deviceTypeIdentifier, deviceManagementServiceHolder);
} else {
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceType, tenantId);
providers.put(deviceTypeIdentifier, provider);
if (provider instanceof DeviceTypeDefinitionProvider) {
dynamicProviderTimestamp.put(deviceTypeIdentifier, System.currentTimeMillis());
}
providers.put(deviceTypeIdentifier, deviceManagementServiceHolder);
}
}
}
@ -126,9 +131,6 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
int providerTenantId = DeviceManagerUtil.getTenantId(provisioningConfig.getProviderTenantDomain());
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceTypeName, providerTenantId);
providers.remove(deviceTypeIdentifier);
if (provider instanceof DeviceTypeDefinitionProvider) {
dynamicProviderTimestamp.remove(deviceTypeIdentifier);
}
}
unregisterPushNotificationStrategy(deviceTypeIdentifier);
unregisterMonitoringTask(provider);
@ -148,30 +150,39 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
public DeviceManagementService getDeviceManagementService(String type, int tenantId) {
//Priority need to be given to the tenant before public.
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(type.toLowerCase(), tenantId);
DeviceManagementService provider = providers.get(deviceTypeIdentifier);
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(type, tenantId);
DeviceManagementServiceHolder provider = providers.get(deviceTypeIdentifier);
if (provider == null) {
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(type.toLowerCase());
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(type);
provider = providers.get(deviceTypeIdentifier);
if (provider == null) {
try {
DeviceType deviceType = DeviceManagerUtil.getDeviceType(type,tenantId);
DeviceType deviceType = DeviceManagerUtil.getDeviceType(type, tenantId);
if (deviceType == null) {
return null;
}
DeviceTypeMetaDefinition deviceTypeMetaDefinition = deviceType.getDeviceTypeMetaDefinition();
if (deviceTypeMetaDefinition != null) {
HTTPDeviceTypeManagerService deviceTypeManagerService = new HTTPDeviceTypeManagerService
(type, deviceTypeMetaDefinition);
addDeviceManagementProvider(deviceTypeManagerService);
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(type, tenantId);
provider = providers.get(deviceTypeIdentifier);
}
} catch (DeviceManagementException e) {
log.error("Failing to retrieve the device type service for " + type, e);
return null;
}
}
if (provider == null) {
log.error("Device Type Definition not found for " + type);
return null;
}
} else {
// retrieves per tenant device type management service
if (provider instanceof DeviceTypeDefinitionProvider) {
if (provider.getDeviceManagementService() instanceof DeviceTypeDefinitionProvider) {
//handle updates.
long updatedTimestamp = dynamicProviderTimestamp.get(deviceTypeIdentifier);
long updatedTimestamp = provider.getTimestamp();
if (System.currentTimeMillis() - updatedTimestamp > DEFAULT_UPDATE_TIMESTAMP) {
try {
DeviceType deviceType = DeviceManagerUtil.getDeviceType(type,tenantId);
@ -179,7 +190,8 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
if (deviceTypeMetaDefinition != null) {
Gson gson = new Gson();
String dbStoredDefinition = gson.toJson(deviceTypeMetaDefinition);
deviceTypeMetaDefinition = ((DeviceTypeDefinitionProvider) provider).getDeviceTypeMeta();
deviceTypeMetaDefinition = ((DeviceTypeDefinitionProvider)
provider.getDeviceManagementService()).getDeviceTypeMeta();
String cachedDefinition = gson.toJson(deviceTypeMetaDefinition);
if (!cachedDefinition.equals(dbStoredDefinition)) {
HTTPDeviceTypeManagerService deviceTypeManagerService = new HTTPDeviceTypeManagerService
@ -196,14 +208,14 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
}
}
}
return provider;
return provider.getDeviceManagementService();
}
public Map<DeviceTypeServiceIdentifier, DeviceManagementService> getAllDeviceManagementServices(int tenantId) {
Map<DeviceTypeServiceIdentifier, DeviceManagementService> tenantProviders = new HashMap<>();
for (DeviceTypeServiceIdentifier identifier : providers.keySet()) {
if (identifier.getTenantId() == tenantId || identifier.isSharedWithAllTenant()) {
tenantProviders.put(identifier, providers.get(identifier));
tenantProviders.put(identifier, providers.get(identifier).getDeviceManagementService());
}
}
return tenantProviders;
@ -289,10 +301,10 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
public OperationManager getOperationManager(String deviceType, int tenantId) {
//Priority need to be given to the tenant before public.
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceType.toLowerCase(), tenantId);
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceType, tenantId);
OperationManager operationManager = operationManagerRepository.getOperationManager(deviceTypeIdentifier);
if (operationManager == null) {
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceType.toLowerCase());
deviceTypeIdentifier = new DeviceTypeServiceIdentifier(deviceType);
operationManager = operationManagerRepository.getOperationManager(deviceTypeIdentifier);
}
return operationManager;
@ -302,10 +314,11 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
public void notifyObserver() {
String deviceTypeName;
synchronized (providers) {
for (DeviceManagementService provider : providers.values()) {
for (DeviceManagementServiceHolder deviceManagementServiceHolder : providers.values()) {
DeviceManagementService provider= deviceManagementServiceHolder.getDeviceManagementService();
try {
provider.init();
deviceTypeName = provider.getType().toLowerCase();
deviceTypeName = provider.getType();
ProvisioningConfig provisioningConfig = provider.getProvisioningConfig();
int tenantId = DeviceManagerUtil.getTenantId(provisioningConfig.getProviderTenantDomain());
DeviceTypeMetaDefinition deviceTypeDefinition = null;
@ -313,8 +326,8 @@ public class DeviceManagementPluginRepository implements DeviceManagerStartupLis
deviceTypeDefinition = ((DeviceTypeDefinitionProvider) provider).getDeviceTypeMeta();
DeviceTypeServiceIdentifier deviceTypeIdentifier = new DeviceTypeServiceIdentifier(
provider.getType().toLowerCase(), tenantId);
DeviceManagementService existingProvider = providers.get(deviceTypeIdentifier);
provider.getType(), tenantId);
DeviceManagementServiceHolder existingProvider = providers.get(deviceTypeIdentifier);
if (existingProvider == null) {
removeDeviceManagementProvider(provider);
}

@ -0,0 +1,47 @@
/*
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.dto;
import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService;
/**
* This holds the information of the registered device management service against the device type
* definition loaded timestamp. This is used to handle device type update scenario.
*/
public class DeviceManagementServiceHolder {
private DeviceManagementService deviceManagementService;
private long timestamp;
public DeviceManagementServiceHolder(DeviceManagementService deviceManagementService) {
this.deviceManagementService = deviceManagementService;
this.timestamp = System.currentTimeMillis();
}
public DeviceManagementService getDeviceManagementService() {
return deviceManagementService;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}

@ -15,7 +15,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.wso2.carbon.device.mgt.common;
package org.wso2.carbon.device.mgt.core.dto;
import java.io.Serializable;

@ -18,7 +18,7 @@
*/
package org.wso2.carbon.device.mgt.core.operation.mgt;
import org.wso2.carbon.device.mgt.common.DeviceTypeServiceIdentifier;
import org.wso2.carbon.device.mgt.core.dto.DeviceTypeServiceIdentifier;
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager;
import java.util.Map;

@ -343,4 +343,10 @@ public interface DeviceManagementProviderService {
* @throws DeviceManagementException
*/
DeviceType getDeviceType(String deviceType) throws DeviceManagementException;
/**
* This retrieves the device type info for the given type
* @throws DeviceManagementException
*/
List<DeviceType> getDeviceTypes() throws DeviceManagementException;
}

@ -28,7 +28,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.common.DeviceManager;
import org.wso2.carbon.device.mgt.common.DeviceNotFoundException;
import org.wso2.carbon.device.mgt.common.DeviceTypeServiceIdentifier;
import org.wso2.carbon.device.mgt.core.dto.DeviceTypeServiceIdentifier;
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
import org.wso2.carbon.device.mgt.common.FeatureManager;
import org.wso2.carbon.device.mgt.common.InitialOperationConfig;
@ -2174,7 +2174,6 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
@Override
public DeviceType getDeviceType(String deviceType) throws DeviceManagementException {
HashMap<Integer, Device> deviceHashMap;
try {
DeviceManagementDAOFactory.openConnection();
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
@ -2187,4 +2186,20 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
DeviceManagementDAOFactory.closeConnection();
}
}
@Override
public List<DeviceType> getDeviceTypes() throws DeviceManagementException {
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
try {
DeviceManagementDAOFactory.openConnection();
return deviceTypeDAO.getDeviceTypes(tenantId);
} catch (DeviceManagementDAOException e) {
throw new DeviceManagementException("Error occurred while obtaining the device types for tenant "
+ tenantId, e);
} catch (SQLException e) {
throw new DeviceManagementException("Error occurred while opening a connection to the data source", e);
} finally {
DeviceManagementDAOFactory.closeConnection();
}
}
}

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS DM_DEVICE_TYPE (
ID INT AUTO_INCREMENT NOT NULL,
NAME VARCHAR(300) NULL DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(2000) NULL DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(20000) NULL DEFAULT NULL,
LAST_UPDATED_TIMESTAMP TIMESTAMP NOT NULL,
PROVIDER_TENANT_ID INTEGER DEFAULT 0,
SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE,

@ -72,7 +72,8 @@ public class DeviceTypeManagerService implements DeviceManagementService {
this.setOperationMonitoringConfig(deviceTypeConfiguration);
this.initialOperationConfig = new InitialOperationConfig();
this.setInitialOperationConfig(deviceTypeConfiguration);
if (deviceTypeConfiguration.getPolicyMonitoring() != null ) {
if (deviceTypeConfiguration.getPolicyMonitoring() != null
&& deviceTypeConfiguration.getPolicyMonitoring().isEnabled()) {
this.policyMonitoringManager = new DefaultPolicyMonitoringManager();
}
}

@ -81,6 +81,7 @@ public class HTTPDeviceTypeManagerService extends DeviceTypeManagerService imple
for (Feature feature : deviceTypeMetaDefinition.getFeatures()) {
org.wso2.carbon.device.mgt.extensions.device.type.template.config.Feature configFeature = new org
.wso2.carbon.device.mgt.extensions.device.type.template.config.Feature();
if (feature.getCode() != null && feature.getName() != null) {
configFeature.setCode(feature.getCode());
configFeature.setDescription(feature.getDescription());
configFeature.setName(feature.getName());
@ -93,6 +94,7 @@ public class HTTPDeviceTypeManagerService extends DeviceTypeManagerService imple
}
featureList.add(configFeature);
}
}
features.addFeatures(featureList);
deviceTypeConfiguration.setFeatures(features);
}
@ -117,7 +119,8 @@ public class HTTPDeviceTypeManagerService extends DeviceTypeManagerService imple
if (pushNotificationConfig != null) {
PushNotificationProvider pushNotificationProvider = new PushNotificationProvider();
pushNotificationProvider.setType(pushNotificationConfig.getType());
pushNotificationProvider.setScheduled(pushNotificationConfig.isScheduled());
//default schedule value will be true.
pushNotificationProvider.setScheduled(true);
if (pushNotificationConfig.getProperties() != null &&
pushNotificationConfig.getProperties().size() > 0) {
ConfigProperties configProperties = new ConfigProperties();

@ -178,7 +178,8 @@
"perm:admin",
"perm:devicetype:deployment",
"perm:device-types:events",
"perm:device-types:events:view"
"perm:device-types:events:view",
"perm:admin:device-type"
],
"isOAuthEnabled": true,
"backendRestEndpoints": {

@ -268,6 +268,34 @@ deviceModule = function () {
}
};
publicMethods.getDeviceTypeCount = function () {
var carbonUser = session.get(constants.USER_SESSION_KEY);
if (carbonUser) {
var userModule = require("/app/modules/business-controllers/user.js")["userModule"];
var uiPermissions = userModule.getUIPermissions();
var url;
if (uiPermissions.LIST_OWN_DEVICES) {
url = devicemgtProps["httpsURL"] +
devicemgtProps["backendRestEndpoints"]["deviceMgt"] + "/device-types";
} else {
log.error("Access denied for user: " + carbonUser.username);
return -1;
}
return serviceInvokers.XMLHttp.get(
url, function (responsePayload) {
return parse(responsePayload["responseText"])["count"];
},
function (responsePayload) {
log.error(responsePayload["responseText"]);
return -1;
}
);
} else {
log.error("User object was not found in the session");
throw constants["ERRORS"]["USER_NOT_FOUND"];
}
};
publicMethods.getDeviceTypes = function () {
var url = devicemgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"] + "/device-types";
var response = privateMethods.callBackend(url, constants["HTTP_GET"]);

@ -191,6 +191,40 @@
</div>
</div>
</div>
{{#if permissions.IS_ADMIN}}
<div class="col-md-3 wr-stats-board">
<div class="wr-stats-board-tile">
<div class="tile-name">Device Types</div>
<div>
<div class="tile-icon"><i class="fw fw-devices"></i></div>
<div class="tile-stats">
<span id="device-types-count">{{deviceTypeCount}}</span>
<span class="tile-stats-free">
<!--suppress HtmlUnknownTarget -->
{{#if deviceTypeCount}}
<a href="{{@app.context}}/device-types">
<span class="fw-stack">
<i class="fw fw-circle-outline fw-stack-2x"></i>
<i class="fw fw-view fw-stack-1x"></i>
</span>
View
</a>
{{/if}}
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-type/add">
<span class="fw-stack">
<i class="fw fw-circle-outline fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Add
</a>
</span>
</div>
</div>
</div>
</div>
{{/if}}
{{else}}
<h1 class="page-sub-title">
Permitted None

@ -44,6 +44,7 @@ function onRequest(context) {
viewModel.groupCount = groupModule.getGroupCount();
viewModel.userCount = userModule.getUsersCount();
viewModel.policyCount = policyModule.getPoliciesCount();
viewModel.deviceTypeCount = deviceModule.getDeviceTypeCount();
viewModel.isCloud = devicemgtProps.isCloud;
if (devicemgtProps.isCloud) {
viewModel.roleCount = userModule.getFilteredRoles("devicemgt").content.count;

@ -0,0 +1,226 @@
{{!
Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
WSO2 Inc. 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.
}}
{{unit "cdmf.unit.ui.title" pageTitle="Device Type Management"}}
{{#zone "topCss"}}
{{css "css/devicetype.css"}}
{{/zone}}
{{#zone "breadcrumbs"}}
<li>
<a href="{{@app.context}}/">
<i class="icon fw fw-home"></i>
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-types">
Device Types
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-type/add">
Add
</a>
</li>
{{/zone}}
{{#zone "content"}}
{{#if canManage}}
<!-- content/body -->
<div class="row">
<div class="col-md-12">
<!-- content -->
<div id="devicetype-create-form" class="container col-centered wr-content">
<div class="wr-form">
<p class="page-sub-title">Create Device Type</p>
<hr/>
<div class="row">
<div class="col-lg-8">
<div class="wr-steps">
<div class="col-md-6 col-xs-6">
<div class="itm-wiz itm-wiz-current" data-step="policy-platform">
<div class="wiz-no">1</div>
<div class="wiz-lbl hidden-xs"><span>Create A Device Type</span></div>
</div>
</div>
<div class="col-md-6 col-xs-6">
<div class="itm-wiz" data-step="policy-profile">
<div class="wiz-no">2</div>
<div class="wiz-lbl hidden-xs"><span>Create Device Event</span></div>
</div>
</div>
<br class="c-both"/>
</div>
<br/><br/>
<hr/>
<div id="devicetype-create-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<label class="wr-input-label">
Device Type Name *
</label>
<br>
<input aria-describedby="basic-addon1" type="text" id="deviceTypeName"
data-error-msg="invalid device type name" class="form-control"/>
<label class="wr-input-label">
Device Type Description *
</label>
<br>
<textarea aria-describedby="basic-addon1" type="text" id="deviceTypeDescription"
data-error-msg="invalid device type description"
class="form-control" rows="3" cols="70"></textarea>
<label class="wr-input-label">Push Notification Transport</label>
<div class="wr-input-control">
<!--suppress HtmlFormInputWithoutLabel -->
<select id="pushNotification" class="form-control select">
<option>NONE</option>
<option>MQTT</option>
<option>FCM</option>
<option>APNS</option>
</select>
</div>
<label class="wr-input-label">
Features
</label>
<br>
<div class="form-group feature_field_wrapper">
<div class="dontfloat" name="deviceFeature">
<div class="col-xs-3">
<input type="text" class="form-control" id="feature-name" placeholder="name"/>
</div>
<div class="col-xs-4">
<input type="text" class="form-control" id="feature-code" placeholder="code"/>
</div>
<div class="col-xs-4">
<textarea aria-describedby="basic-addon1" type="text" id="feature-description"
placeholder="description"
data-error-msg="invalid feature description"
class="form-control" rows="1" cols="30"></textarea>
</div>
<button type="button" class="btn btn-default add_feature_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<br>
<label class="wr-input-label">
Device Attributes
</label>
<br>
<div class="form-group attribute_field_wrapper">
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="attribute[]" />
</div>
<button type="button" class="btn btn-default add_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="hidden-div">
<div id="add-attribute-field" name="add-attribute-field">
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="attribute[]" />
</div>
<button type="button" class="btn btn-default remove_button"><i class="fa fa-minus"></i></button>
</div>
</div>
</div>
<label class="wr-input-label">
Initial Operation(Feature Code, Trigger operation when device enrolls)
</label>
<br>
<div class="form-group operation_field_wrapper">
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="operation[]" />
</div>
<button type="button" class="btn btn-default add_operation_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="hidden-div">
<div id="add-operation-field" name="add-operation-field">
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="operation[]" />
</div>
<button type="button" class="btn btn-default remove_operation_button"><i class="fa fa-minus"></i></button>
</div>
</div>
</div>
<label class="wr-input-label">Claimable</label>
<input aria-describedby="basic-addon1" type="checkbox" id="deviceClaimable"/>
</br>
<label class="wr-input-label">Policy Monitoring</label>
<input aria-describedby="basic-addon1" type="checkbox" id="policyMonitoring"/>
</br>
<span class="roleNameError hidden glyphicon glyphicon-remove form-control-feedback"></span>
<label class="error roleNameEmpty hidden" for="summary">
Device Type Name is required, should be in minimum 3 characters long and not include any
whitespaces or "@" character or "/" character.
</label>
</div>
</div>
<br>
<button id="add-devicetype-btn" class="wr-btn">Add Device Type</button>
</div>
</div>
<div id="devicetype-created-msg" class="container col-centered wr-content hidden">
<div class="wr-form">
<p class="page-sub-title">Devicetype was added successfully.</p>
<b>"View Device Type List"</b> to complete the process and go back to the devie type list.
<hr/>
<button class="wr-btn" onclick="window.location.href='{{@app.context}}/device-types'">
View Device Type List
</button>
</div>
</div>
<!-- /content -->
<div id="app-context" data-app-context="{{@app.context}}" class="hidden"></div>
</div>
</div>
<!-- /content/body -->
{{else}}
<h1 class="page-sub-title">
Permission Denied
</h1>
<br>
You not authorized to create device type.
<br>
{{/if}}
{{/zone}}
{{#zone "bottomJs"}}
{{js "js/bottomJs.js"}}
{{/zone}}

@ -0,0 +1,29 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
function onRequest(context) {
var userModule = require("/app/modules/business-controllers/user.js")["userModule"];
var deviceMgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var displayData = {};
if (userModule.isAuthorized("/permission/admin/device-mgt/admin/device-type")) {
displayData.canManage = true;
}
return displayData;
}

@ -0,0 +1,240 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
/**
* Checks if provided input is valid against RegEx input.
*
* @param regExp Regular expression
* @param inputString Input string to check
* @returns {boolean} Returns true if input matches RegEx
*/
function inputIsValid(regExp, inputString) {
regExp = new RegExp(regExp);
return regExp.test(inputString);
}
var validateInline = {};
var clearInline = {};
var apiBasePath = "/api/device-mgt/v1.0";
var enableInlineError = function (inputField, errorMsg, errorSign) {
var fieldIdentifier = "#" + inputField;
var errorMsgIdentifier = "#" + inputField + " ." + errorMsg;
var errorSignIdentifier = "#" + inputField + " ." + errorSign;
if (inputField) {
$(fieldIdentifier).addClass(" has-error has-feedback");
}
if (errorMsg) {
$(errorMsgIdentifier).removeClass(" hidden");
}
if (errorSign) {
$(errorSignIdentifier).removeClass(" hidden");
}
};
var disableInlineError = function (inputField, errorMsg, errorSign) {
var fieldIdentifier = "#" + inputField;
var errorMsgIdentifier = "#" + inputField + " ." + errorMsg;
var errorSignIdentifier = "#" + inputField + " ." + errorSign;
if (inputField) {
$(fieldIdentifier).removeClass(" has-error has-feedback");
}
if (errorMsg) {
$(errorMsgIdentifier).addClass(" hidden");
}
if (errorSign) {
$(errorSignIdentifier).addClass(" hidden");
}
};
function formatRepo(user) {
if (user.loading) {
return user.text
}
if (!user.username) {
return;
}
var markup = '<div class="clearfix">' +
'<div class="col-sm-8">' +
'<div class="clearfix">' +
'<div class="col-sm-4">' + user.username + '</div>';
if (user.name || user.name != undefined) {
markup += '<div class="col-sm-8"> ( ' + user.name + ' )</div>';
}
markup += '</div></div></div>';
return markup;
}
function formatRepoSelection(user) {
return user.username || user.text;
}
$(document).ready(function () {
var appContext = $("#app-context").data("app-context");
var maxField = 100; //Input fields increment limitation
var addButton = $('.add_button'); //Add button selector
var wrapper = $('.attribute_field_wrapper'); //Input field wrapper
var fieldHTML = $('#add-attribute-field').html(); //New input field html
$(addButton).click(function(){ //Once add button is clicked
$(wrapper).append(fieldHTML); // Add field html
});
$(wrapper).on('click', '.remove_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove();
});
var addOperationButton = $('.add_operation_button'); //Add button selector
var operationWrapper = $('.operation_field_wrapper'); //Input field wrapper
var operationFieldHTML = $('#add-operation-field').html(); //New input field html
$(addOperationButton).click(function(){ //Once add button is clicked
$(operationWrapper).append(operationFieldHTML); // Add field html
});
$(operationWrapper).on('click', '.remove_operation_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove();
});
var addFeatureButton = $('.add_feature_button'); //Add button selector
var featureWrapper = $('.feature_field_wrapper'); //Input field wrapper
$(addFeatureButton).click(function(){ //Once add button is clicked
var featureFieldHtml = ' <div class="dontfloat" name ="deviceFeature"> <div class="col-xs-3"> <input type="text"' +
' class="form-control" id="feature-name" placeholder="name"/> </div> <div class="col-xs-4"> ' +
'<input type="text" class="form-control" id="feature-code" placeholder="code"/> </div> ' +
'<div class="col-xs-4"> <textarea aria-describedby="basic-addon1" type="text" ' +
'id="feature-description" placeholder="description"data-error-msg="invalid ' +
'feature description"class="form-control" rows="1" cols="30"></textarea> </div> ' +
'<button type="button" class="btn btn-default remove_feature_button"><i class="fa fa-minus"></i></button> </div>'
$(featureWrapper).append(featureFieldHtml); // Add field html
});
$(featureWrapper).on('click', '.remove_feature_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove(); //Remove field html
});
/**
* Following click function would execute
* when a user clicks on "Add Device type" button.
*/
$("button#add-devicetype-btn").click(function () {
var errorMsgWrapper = "#devicetype-create-error-msg";
var errorMsg = "#devicetype-create-error-msg span";
var deviceType = {};
var deviceTypeName = $("#deviceTypeName").val();
var deviceTypeDescription = $("#deviceTypeDescription").val();
if (!deviceTypeName || deviceTypeName.trim() == "" ) {
$(errorMsg).text("Device Type Name Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
return;
}
if (!deviceTypeDescription || deviceTypeDescription.trim() == "" ) {
$(errorMsg).text("Device Type Description Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
return
}
deviceType.name = deviceTypeName.trim();
deviceType.deviceTypeMetaDefinition = {}
deviceType.deviceTypeMetaDefinition.description = deviceTypeDescription.trim();
var pushNotification = $("#pushNotification").val();
if (pushNotification != "NONE") {
deviceType.deviceTypeMetaDefinition.pushNotificationConfig = {};
deviceType.deviceTypeMetaDefinition.pushNotificationConfig.scheduled = true;
deviceType.deviceTypeMetaDefinition.pushNotificationConfig.type = pushNotification;
}
var propertyValues = [];
$('input[name^="attribute"]').each(function() {
var propertyValue = $(this).val();
if (propertyValue.trim() != "") {
propertyValues.push(propertyValue.trim());
}
});
deviceType.deviceTypeMetaDefinition.properties = propertyValues;
var operationValues = [];
$('input[name^="operation"]').each(function() {
var operationValue = $(this).val();
if (operationValue.trim() != "") {
operationValues.push(operationValue.trim());
}
});
if (operationValues.length > 0) {
deviceType.deviceTypeMetaDefinition.initialOperationConfig = {};
deviceType.deviceTypeMetaDefinition.initialOperationConfig.operations = operationValues;
}
deviceType.deviceTypeMetaDefinition.policyMonitoringEnabled = $("#policyMonitoring").is(":checked");
deviceType.deviceTypeMetaDefinition.claimable = $("#deviceClaimable").is(":checked");;
var features = [];
$('div[name^="deviceFeature"]').each(function() {
var featureName = $(this).find("#feature-name").val();
var featureCode = $(this).find("#feature-code").val();
if (featureName && featureName.trim() != "" && featureCode && featureCode.trim() != "") {
var feature = {};
feature.name = featureName.trim();
feature.code = featureCode.trim();
feature.description = $("#feature-description").val();
features.push(feature);
}
});
deviceType.deviceTypeMetaDefinition.features = features;
var addRoleAPI = apiBasePath + "/admin/device-types";
invokerUtil.post(
addRoleAPI,
deviceType,
function (data, textStatus, jqXHR) {
if (jqXHR.status == 200) {
window.location.href = appContext + "/device-type/edit-event?type=" +
encodeURIComponent(deviceTypeName);
}
},
function (jqXHR) {
if (jqXHR.status == 500) {
$(errorMsg).text("Unexpected error.");
$(errorMsgWrapper).removeClass("hidden");
}
if (jqXHR.status == 409) {
$(errorMsg).text("Device type already exists");
$(errorMsgWrapper).removeClass("hidden");
}
}
);
});
});

@ -0,0 +1,273 @@
{{!
Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
WSO2 Inc. 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.
}}
{{unit "cdmf.unit.ui.title" pageTitle="Device Type Management"}}
{{#zone "topCss"}}
{{css "css/devicetype.css"}}
{{/zone}}
{{#zone "breadcrumbs"}}
<li>
<a href="{{@app.context}}/">
<i class="icon fw fw-home"></i>
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-types">
Device Types
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-type/edit?type={{name}}">
Edit
</a>
</li>
{{/zone}}
{{#zone "content"}}
{{#if canManage}}
<!-- content/body -->
<div class="row">
<div class="col-md-12">
<!-- content -->
<div id="devicetype-create-form" class="container col-centered wr-content">
<div class="wr-form">
<p class="page-sub-title">{{name}}</p>
<hr/>
<div class="row">
<div class="col-lg-8">
<div id="devicetype-create-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<br>
<input aria-describedby="basic-addon1" type="text" id="deviceTypeName"
data-error-msg="invalid device type name" class="form-control hidden-input" value="{{name}}"/>
<label class="wr-input-label">
Device Type Description *
</label>
<br>
<textarea aria-describedby="basic-addon1" type="text" id="deviceTypeDescription"
data-error-msg="invalid device type description"
class="form-control" rows="3" cols="70">{{type.deviceTypeMetaDefinition.description}}</textarea>
<label class="wr-input-label">Push Notification Transport</label>
<div class="wr-input-control">
<!--suppress HtmlFormInputWithoutLabel -->
<select id="pushNotification" class="form-control select">
{{#if type.deviceTypeMetaDefinition.pushNotificationConfig}}
<option>NONE</option>
{{#if_eq type.deviceTypeMetaDefinition.pushNotificationConfig.type "MQTT"}}
<option selected>MQTT</option>
<option>FCM</option>
<option>APNS</option>
{{/if_eq}}
{{#if_eq type.deviceTypeMetaDefinition.pushNotificationConfig.type "FCM"}}
<option>MQTT</option>
<option selected>FCM</option>
<option>APNS</option>
{{/if_eq}}
{{#if_eq type.deviceTypeMetaDefinition.pushNotificationConfig.type "APNS"}}
<option>MQTT</option>
<option>FCM</option>
<option selected>APNS</option>
{{/if_eq}}
{{else}}
<option selected>NONE</option>
<option>MQTT</option>
<option>FCM</option>
<option>APNS</option>
{{/if}}
</select>
</div>
<label class="wr-input-label">
Features
</label>
<br>
<div class="form-group feature_field_wrapper">
{{#if type.deviceTypeMetaDefinition.features}}
{{#each type.deviceTypeMetaDefinition.features}}
<div class="dontfloat" name ="deviceFeature">
<div class="col-xs-3">
<input type="text" class="form-control" id="feature-name" placeholder="name" value="{{this.name}}"/>
</div>
<div class="col-xs-4">
<input type="text" class="form-control" id="feature-code" placeholder="code" value="{{this.code}}"/>
</div>
<div class="col-xs-4">
<textarea aria-describedby="basic-addon1" type="text" id="feature-description"
placeholder="description"data-error-msg="invalid feature description"class="form-control" rows="1" cols="30">
{{this.description}}
</textarea>
</div>
<button type="button" class="btn btn-default remove_feature_button"><i class="fa fa-minus"></i></button>
</div>
{{/each}}
{{/if}}
<div class="dontfloat" name="deviceFeature">
<div class="col-xs-3">
<input type="text" class="form-control" id="feature-name" placeholder="name"/>
</div>
<div class="col-xs-4">
<input type="text" class="form-control" id="feature-code" placeholder="code"/>
</div>
<div class="col-xs-4">
<textarea aria-describedby="basic-addon1" type="text" id="feature-description"
placeholder="description"
data-error-msg="invalid feature description"
class="form-control" rows="1" cols="30"></textarea>
</div>
<button type="button" class="btn btn-default add_feature_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<br>
<label class="wr-input-label">
Device Attributes
</label>
<br>
<div class="form-group attribute_field_wrapper">
{{#if type.deviceTypeMetaDefinition.properties}}
{{#each type.deviceTypeMetaDefinition.properties}}
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="attribute[]" value="{{this}}" />
</div>
<button type="button" class="btn btn-default remove_button"><i class="fa fa-minus"></i></button>
</div>
{{/each}}
{{/if}}
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="attribute[]" />
</div>
<button type="button" class="btn btn-default add_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="hidden-div">
<div id="add-attribute-field" name="add-attribute-field">
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="attribute[]" />
</div>
<button type="button" class="btn btn-default remove_button"><i class="fa fa-minus"></i></button>
</div>
</div>
</div>
<label class="wr-input-label">
Initial Operation(Feature Code, Trigger operation when device enrolls)
</label>
<br>
<div class="form-group operation_field_wrapper">
{{#if type.deviceTypeMetaDefinition.initialOperationConfig}}
{{#each type.deviceTypeMetaDefinition.initialOperationConfig.operations}}
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="operation[]" value="{{this}}"/>
</div>
<button type="button" class="btn btn-default remove_operation_button"><i class="fa fa-minus"></i></button>
</div>
{{/each}}
{{/if}}
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="operation[]" />
</div>
<button type="button" class="btn btn-default add_operation_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="hidden-div">
<div id="add-operation-field" name="add-operation-field">
<div class="dontfloat">
<div class="col-xs-3">
<input type="text" class="form-control" name="operation[]" />
</div>
<button type="button" class="btn btn-default remove_operation_button"><i class="fa fa-minus"></i></button>
</div>
</div>
</div>
<label class="wr-input-label">Claimable</label>
<input aria-describedby="basic-addon1" type="checkbox" id="deviceClaimable"
{{#if type.deviceTypeMetaDefinition.claimable}}
checked
{{/if}}/>
</br>
<label class="wr-input-label">Policy Monitoring</label>
<input aria-describedby="basic-addon1" type="checkbox" id="policyMonitoring"
{{#if type.deviceTypeMetaDefinition.policyMonitoringEnabled}}
checked
{{/if}}/>
</br>
<span class="roleNameError hidden glyphicon glyphicon-remove form-control-feedback"></span>
<label class="error roleNameEmpty hidden" for="summary">
Device Type Name is required, should be in minimum 3 characters long and not include any
whitespaces or "@" character or "/" character.
</label>
</div>
</div>
<br>
<button id="add-devicetype-btn" class="wr-btn">Update</button>
<div id="devicetype-create-success-msg" class="alert hidden" role="alert">
<i class="icon fw fw-success"></i><span></span>
</div>
</div>
</div>
<div id="devicetype-created-msg" class="container col-centered wr-content hidden">
<div class="wr-form">
<p class="page-sub-title">Devicetype was added successfully.</p>
<b>"View Device Type List"</b> to complete the process and go back to the devie type list.
<hr/>
<button class="wr-btn" onclick="window.location.href='{{@app.context}}/device-types'">
View Device Type List
</button>
</div>
</div>
<!-- /content -->
<div id="app-context" data-app-context="{{@app.context}}" class="hidden"></div>
</div>
</div>
<!-- /content/body -->
{{else}}
<h1 class="page-sub-title">
Permission Denied
</h1>
<br>
You not authorized to edit device type.
<br>
{{/if}}
{{/zone}}
{{#zone "bottomJs"}}
{{js "js/bottomJs.js"}}
{{/zone}}

@ -0,0 +1,52 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
function onRequest(context) {
var userModule = require("/app/modules/business-controllers/user.js")["userModule"];
var deviceMgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var displayData = {};
if (userModule.isAuthorized("/permission/admin/device-mgt/admin/device-type")) {
displayData.canManage = true;
}
context.handlebars.registerHelper('if_eq', function(a, b, opts) {
if(a == b) // Or === depending on your needs
return opts.fn(this);
else
return opts.inverse(this);
});
var deviceType = request.getParameter("type");
var serviceInvokers = require("/app/modules/oauth/token-protected-service-invokers.js")["invokers"];
var restAPIEndpoint = deviceMgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"]
+ "/device-types/all/" + deviceType;
displayData.name = deviceType;
serviceInvokers.XMLHttp.get(
restAPIEndpoint,
function (restAPIResponse) {
if (restAPIResponse["status"] == 200 && restAPIResponse["responseText"]) {
var typeData = parse(restAPIResponse["responseText"]);
displayData.type = typeData;
}
}
);
return displayData;
}

@ -0,0 +1,243 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
/**
* Checks if provided input is valid against RegEx input.
*
* @param regExp Regular expression
* @param inputString Input string to check
* @returns {boolean} Returns true if input matches RegEx
*/
function inputIsValid(regExp, inputString) {
regExp = new RegExp(regExp);
return regExp.test(inputString);
}
var validateInline = {};
var clearInline = {};
var apiBasePath = "/api/device-mgt/v1.0";
var domain = $("#domain").val();
var enableInlineError = function (inputField, errorMsg, errorSign) {
var fieldIdentifier = "#" + inputField;
var errorMsgIdentifier = "#" + inputField + " ." + errorMsg;
var errorSignIdentifier = "#" + inputField + " ." + errorSign;
if (inputField) {
$(fieldIdentifier).addClass(" has-error has-feedback");
}
if (errorMsg) {
$(errorMsgIdentifier).removeClass(" hidden");
}
if (errorSign) {
$(errorSignIdentifier).removeClass(" hidden");
}
};
var disableInlineError = function (inputField, errorMsg, errorSign) {
var fieldIdentifier = "#" + inputField;
var errorMsgIdentifier = "#" + inputField + " ." + errorMsg;
var errorSignIdentifier = "#" + inputField + " ." + errorSign;
if (inputField) {
$(fieldIdentifier).removeClass(" has-error has-feedback");
}
if (errorMsg) {
$(errorMsgIdentifier).addClass(" hidden");
}
if (errorSign) {
$(errorSignIdentifier).addClass(" hidden");
}
};
function formatRepo(user) {
if (user.loading) {
return user.text
}
if (!user.username) {
return;
}
var markup = '<div class="clearfix">' +
'<div class="col-sm-8">' +
'<div class="clearfix">' +
'<div class="col-sm-4">' + user.username + '</div>';
if (user.name || user.name != undefined) {
markup += '<div class="col-sm-8"> ( ' + user.name + ' )</div>';
}
markup += '</div></div></div>';
return markup;
}
function formatRepoSelection(user) {
return user.username || user.text;
}
$(document).ready(function () {
var appContext = $("#app-context").data("app-context");
var addButton = $('.add_button'); //Add button selector
var wrapper = $('.attribute_field_wrapper'); //Input field wrapper
var fieldHTML = $('#add-attribute-field').html(); //New input field html
$(addButton).click(function(){ //Once add button is clicked
$(wrapper).append(fieldHTML); // Add field html
});
$(wrapper).on('click', '.remove_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove(); //Remove field html
});
var addOperationButton = $('.add_operation_button'); //Add button selector
var operationWrapper = $('.operation_field_wrapper'); //Input field wrapper
var operationFieldHTML = $('#add-operation-field').html(); //New input field html
$(addOperationButton).click(function(){ //Once add button is clicked
$(operationWrapper).append(operationFieldHTML); // Add field html
});
$(operationWrapper).on('click', '.remove_operation_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove();
});
var addFeatureButton = $('.add_feature_button'); //Add button selector
var featureWrapper = $('.feature_field_wrapper'); //Input field wrapper
$(addFeatureButton).click(function(){ //Once add button is clicked
var featureFieldHtml = ' <div class="dontfloat" name ="deviceFeature"> <div class="col-xs-3"> <input type="text"' +
' class="form-control" id="feature-name" placeholder="name"/> </div> <div class="col-xs-4"> ' +
'<input type="text" class="form-control" id="feature-code" placeholder="code"/> </div> ' +
'<div class="col-xs-4"> <textarea aria-describedby="basic-addon1" type="text" ' +
'id="feature-description" placeholder="description"data-error-msg="invalid ' +
'feature description"class="form-control" rows="1" cols="30"></textarea> </div> ' +
'<button type="button" class="btn btn-default remove_feature_button"><i class="fa fa-minus"></i></button> </div>'
$(featureWrapper).append(featureFieldHtml); // Add field html
});
$(featureWrapper).on('click', '.remove_feature_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove(); //Remove field html
op--; //Decrement field counter
});
/**
* Following click function would execute
* when a user clicks on "Add Device type" button.
*/
$("button#add-devicetype-btn").click(function () {
var errorMsgWrapper = "#devicetype-create-error-msg";
var errorMsg = "#devicetype-create-error-msg span";
var successMsgWrapper = "#devicetype-create-success-msg";
var successMsg = "#devicetype-create-success-msg span";
var deviceType = {};
var deviceTypeName = $("#deviceTypeName").val();
var deviceTypeDescription = $("#deviceTypeDescription").val();
if (!deviceTypeName || deviceTypeName.trim() == "" ) {
$(errorMsg).text("Device Type Name Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
return;
}
if (!deviceTypeDescription || deviceTypeDescription.trim() == "" ) {
$(errorMsg).text("Device Type Description Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
return
}
deviceType.name = deviceTypeName.trim();
deviceType.deviceTypeMetaDefinition = {}
deviceType.deviceTypeMetaDefinition.description = deviceTypeDescription.trim();
var pushNotification = $("#pushNotification").val();
if (pushNotification != "NONE") {
deviceType.deviceTypeMetaDefinition.pushNotificationConfig = {};
deviceType.deviceTypeMetaDefinition.pushNotificationConfig.scheduled = true;
deviceType.deviceTypeMetaDefinition.pushNotificationConfig.type = pushNotification;
}
var propertyValues = [];
$('input[name^="attribute"]').each(function() {
var propertyValue = $(this).val();
if (propertyValue.trim() != "") {
propertyValues.push(propertyValue.trim());
}
});
deviceType.deviceTypeMetaDefinition.properties = propertyValues;
var operationValues = [];
$('input[name^="operation"]').each(function() {
var operationValue = $(this).val();
if (operationValue.trim() != "") {
operationValues.push(operationValue.trim());
}
});
if (operationValues.length > 0) {
deviceType.deviceTypeMetaDefinition.initialOperationConfig = {};
deviceType.deviceTypeMetaDefinition.initialOperationConfig.operations = operationValues;
}
deviceType.deviceTypeMetaDefinition.policyMonitoringEnabled = $("#policyMonitoring").is(":checked");
deviceType.deviceTypeMetaDefinition.claimable = $("#deviceClaimable").is(":checked");;
var features = [];
$('div[name^="deviceFeature"]').each(function() {
var featureName = $(this).find("#feature-name").val();
var featureCode = $(this).find("#feature-code").val();
if (featureName && featureName.trim() != "" && featureCode && featureCode.trim() != "") {
var feature = {};
feature.name = featureName.trim();
feature.code = featureCode.trim();
feature.description = $("#feature-description").val();
features.push(feature);
}
});
deviceType.deviceTypeMetaDefinition.features = features;
var addRoleAPI = apiBasePath + "/admin/device-types";
invokerUtil.put(
addRoleAPI,
deviceType,
function (data, textStatus, jqXHR) {
if (jqXHR.status == 200) {
$(successMsg).text("Device type updated.");
$(successMsgWrapper).removeClass("hidden");
}
},
function (jqXHR) {
if (jqXHR.status == 500) {
$(errorMsg).text("Unexpected error.");
$(errorMsgWrapper).removeClass("hidden");
}
if (jqXHR.status == 409) {
$(errorMsg).text("Device type already exists");
$(errorMsgWrapper).removeClass("hidden");
}
}
);
});
});

@ -0,0 +1,160 @@
{{!
Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
WSO2 Inc. 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.
}}
{{unit "cdmf.unit.ui.title" pageTitle="Device Type Management"}}
{{#zone "topCss"}}
{{css "css/devicetype.css"}}
{{/zone}}
{{#zone "breadcrumbs"}}
<li>
<a href="{{@app.context}}/">
<i class="icon fw fw-home"></i>
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-types">
Device Types
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-type/edit-event?type={{name}}">
Event
</a>
</li>
{{/zone}}
{{#zone "content"}}
{{#if canManage}}
<!-- content/body -->
<div class="row">
<div class="col-md-12">
<!-- content -->
<div id="devicetype-create-form" class="container col-centered wr-content">
<div class="wr-form">
<p class="page-sub-title">{{name}}</p>
<hr/>
<div class="row">
<div class="col-lg-8">
<div id="devicetype-create-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<br>
<input aria-describedby="basic-addon1" type="text" id="deviceTypeName"
data-error-msg="invalid device type name" class="form-control hidden-input" value="{{name}}"/>
<label class="wr-input-label">Transport</label>
<div class="wr-input-control">
<!--suppress HtmlFormInputWithoutLabel -->
<select id="transport" class="form-control select">
{{#if event}}
<option {{selected event.transport "MQTT"}}>MQTT</option>
<option {{selected event.transport "HTTP"}}>HTTP</option>
{{else}}
<option>MQTT</option>
<option>HTTP</option>
{{/if}}
</select>
</div>
<label class="wr-input-label">
Event Attributes
</label>
<br>
<div class="form-group event_field_wrapper">
{{#if event.eventAttributes}}
{{#each event.eventAttributes.attributes}}
<div class="dontfloat" name="deviceEvent">
<div class="col-xs-3">
<input type="text" class="form-control" id="event-name" placeholder="name" value="{{this.name}}"/>
</div>
<div class="col-xs-4">
<select class="form-control select" id="event-type">
<option {{selected this.type "STRING"}}>STRING</option>
<option {{selected this.type "LONG"}}>LONG</option>
<option {{selected this.type "BOOL"}}>BOOL</option>
<option {{selected this.type "INT"}}>INT</option>
<option {{selected this.type "FLOAT"}}>FLOAT</option>
<option {{selected this.type "DOUBLE"}}>DOUBLE</option>
</select>
</div>
<button type="button" class="btn btn-default remove_event_button"><i class="fa fa-minus"></i></button>
</div>
{{/each}}
{{/if}}
<div class="dontfloat" name="deviceEvent">
<div class="col-xs-3">
<input type="text" class="form-control" id="event-name" placeholder="name"/>
</div>
<div class="col-xs-4">
<select class="form-control select" id="event-type">
<option>STRING</option>
<option>LONG</option>
<option>BOOL</option>
<option>INT</option>
<option>FLOAT</option>
<option>DOUBLE</option>
</select>
</div>
<button type="button" class="btn btn-default add_event_button"><i class="fa fa-plus"></i></button>
</div>
</div>
<br>
{{#if event}}
<button id="add-event-btn" class="wr-btn">Update</button>
{{else}}
<button id="add-event-btn" class="wr-btn">Add</button>
{{/if}}
<div id="devicetype-create-success-msg" class="alert hidden" role="alert">
<i class="icon fw fw-success"></i><span></span>
</div>
</div>
</div>
<div id="devicetype-created-msg" class="container col-centered wr-content hidden">
<div class="wr-form">
<p class="page-sub-title">Device Type Event was added successfully.</p>
<b>"View Device Type List"</b> to complete the process and go back to the devie type list.
<hr/>
<button class="wr-btn" onclick="window.location.href='{{@app.context}}/device-types'">
View Device Type List
</button>
</div>
</div>
<!-- /content -->
<div id="app-context" data-app-context="{{@app.context}}" class="hidden"></div>
</div>
</div>
<!-- /content/body -->
{{else}}
<h1 class="page-sub-title">
Permission Denied
</h1>
<br>
You not authorized to edit device type.
<br>
{{/if}}
{{/zone}}
{{#zone "bottomJs"}}
{{js "js/bottomJs.js"}}
{{/zone}}

@ -0,0 +1,51 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
function onRequest(context) {
var userModule = require("/app/modules/business-controllers/user.js")["userModule"];
var deviceMgtProps = require("/app/modules/conf-reader/main.js")["conf"];
var displayData = {};
if (userModule.isAuthorized("/permission/admin/device-mgt/admin/device-type")) {
displayData.canManage = true;
}
context.handlebars.registerHelper('selected', function(a, b, opts) {
if(a == b) // Or === depending on your needs
return "selected";
else
return "";
});
var deviceType = request.getParameter("type");
var serviceInvokers = require("/app/modules/oauth/token-protected-service-invokers.js")["invokers"];
var restAPIEndpoint = deviceMgtProps["httpsURL"] + devicemgtProps["backendRestEndpoints"]["deviceMgt"]
+ "/events/" + deviceType;
displayData.name = deviceType;
serviceInvokers.XMLHttp.get(
restAPIEndpoint,
function (restAPIResponse) {
if (restAPIResponse["status"] == 200 && restAPIResponse["responseText"]) {
var typeData = parse(restAPIResponse["responseText"]);
displayData.event = typeData;
}
}
);
return displayData;
}

@ -0,0 +1,182 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
/**
* Checks if provided input is valid against RegEx input.
*
* @param regExp Regular expression
* @param inputString Input string to check
* @returns {boolean} Returns true if input matches RegEx
*/
function inputIsValid(regExp, inputString) {
regExp = new RegExp(regExp);
return regExp.test(inputString);
}
var validateInline = {};
var clearInline = {};
var apiBasePath = "/api/device-mgt/v1.0";
var domain = $("#domain").val();
var enableInlineError = function (inputField, errorMsg, errorSign) {
var fieldIdentifier = "#" + inputField;
var errorMsgIdentifier = "#" + inputField + " ." + errorMsg;
var errorSignIdentifier = "#" + inputField + " ." + errorSign;
if (inputField) {
$(fieldIdentifier).addClass(" has-error has-feedback");
}
if (errorMsg) {
$(errorMsgIdentifier).removeClass(" hidden");
}
if (errorSign) {
$(errorSignIdentifier).removeClass(" hidden");
}
};
var disableInlineError = function (inputField, errorMsg, errorSign) {
var fieldIdentifier = "#" + inputField;
var errorMsgIdentifier = "#" + inputField + " ." + errorMsg;
var errorSignIdentifier = "#" + inputField + " ." + errorSign;
if (inputField) {
$(fieldIdentifier).removeClass(" has-error has-feedback");
}
if (errorMsg) {
$(errorMsgIdentifier).addClass(" hidden");
}
if (errorSign) {
$(errorSignIdentifier).addClass(" hidden");
}
};
function formatRepo(user) {
if (user.loading) {
return user.text
}
if (!user.username) {
return;
}
var markup = '<div class="clearfix">' +
'<div class="col-sm-8">' +
'<div class="clearfix">' +
'<div class="col-sm-4">' + user.username + '</div>';
if (user.name || user.name != undefined) {
markup += '<div class="col-sm-8"> ( ' + user.name + ' )</div>';
}
markup += '</div></div></div>';
return markup;
}
function formatRepoSelection(user) {
return user.username || user.text;
}
$(document).ready(function () {
var appContext = $("#app-context").data("app-context");
var addEventButton = $('.add_event_button'); //Add button selector
var eventWrapper = $('.event_field_wrapper'); //Input field wrapper
$(addEventButton).click(function(){ //Once add button is clicked
var eventFieldHtml = ' <div class="dontfloat" name="deviceEvent"> ' +
'<div class="col-xs-3"> <input type="text" class="form-control" id="event-name" placeholder="name"/> ' +
'</div> <div class="col-xs-4"> <select class="form-control select" id="event-type"> ' +
'<option>STRING</option> <option>LONG</option> <option>BOOL</option> <option>INT</option> <option>FLOAT</option> ' +
'<option>DOUBLE</option> </select> </div> ' +
'<button type="button" class="btn btn-default remove_event_button"><i class="fa fa-minus"></i></button> </div>'
$(eventWrapper).append(eventFieldHtml); // Add field html
});
$(eventWrapper).on('click', '.remove_event_button', function(e){ //Once remove button is clicked
e.preventDefault();
$(this).parent('div').remove();
});
/**
* Following click function would execute
* when a user clicks on "Add Device type" button.
*/
$("button#add-event-btn").click(function () {
var errorMsgWrapper = "#devicetype-create-error-msg";
var errorMsg = "#devicetype-create-error-msg span";
var successMsgWrapper = "#devicetype-create-success-msg";
var successMsg = "#devicetype-create-success-msg span";
var deviceTypeEvent = {};
var deviceTypeName = $("#deviceTypeName").val();
var deviceTypeDescription = $("#deviceTypeDescription").val();
if (!deviceTypeName || deviceTypeName.trim() == "" ) {
$(errorMsg).text("Device Type Name Cannot be empty.");
$(errorMsgWrapper).removeClass("hidden");
return;
}
deviceTypeEvent.eventAttributes = {};
deviceTypeEvent.transport = $("#transport").val();
var attributes = [];
$('div[name^="deviceEvent"]').each(function() {
var eventName = $(this).find("#event-name").val();
var eventType = $(this).find("#event-type").val();
if (eventName && eventName.trim() != "" && eventType && eventType.trim() != "" && eventName != "deviceId") {
var attribute = {};
attribute.name = eventName.trim();
attribute.type = eventType.trim();
attributes.push(attribute);
}
});
deviceTypeEvent.eventAttributes.attributes = attributes;
var addEventsAPI = apiBasePath + "/events/" + deviceTypeName;
invokerUtil.post(
addEventsAPI,
deviceTypeEvent,
function (data, textStatus, jqXHR) {
if (jqXHR.status == 200) {
$(successMsg).text("Device Event Definition added.");
$(successMsgWrapper).removeClass("hidden");
}
},
function (jqXHR) {
if (jqXHR.status == 500) {
$(errorMsg).text("Unexpected error.");
$(errorMsgWrapper).removeClass("hidden");
}
if (jqXHR.status == 409) {
$(errorMsg).text("Device type already exists");
$(errorMsgWrapper).removeClass("hidden");
}
}
);
});
});

@ -0,0 +1,110 @@
{{!
Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
WSO2 Inc. 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.
}}
{{unit "cdmf.unit.ui.title" pageTitle="Device Type Management"}}
{{unit "cdmf.unit.data-tables-extended"}}
{{unit "cdmf.unit.ui.modal"}}
{{#zone "breadcrumbs"}}
<li>
<a href="{{@app.context}}/">
<i class="icon fw fw-home"></i>
</a>
</li>
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-types">
Device Types
</a>
</li>
{{/zone}}
{{#zone "navbarActions"}}
{{#unless isCloud}}
<li>
<!--suppress HtmlUnknownTarget -->
<a href="{{@app.context}}/device-type/add" class="cu-btn">
<span class="icon fw-stack">
<i class="fw fw-add fw-stack-1x"></i>
<i class="fw fw-circle-outline fw-stack-2x"></i>
</span>
Create Device Type
</a>
</li>
{{/unless}}
{{/zone}}
{{#zone "content"}}
{{#if hasDeviceTypes}}
<div id="loading-content" class="col-centered">
<input type="hidden" id="can-edit" value="true"/>
<i class="fw fw-settings fw-spin fw-2x"></i>
Loading device types . . .
<br>
</div>
<div id="devicetype-table">
<table class="table table-striped table-hover list-table display responsive nowrap data-table grid-view"
id="devicetype-grid">
<thead>
<tr class="sort-row">
<th>By Device Type Name</th>
</tr>
<tr class="bulk-action-row">
<th colspan="3"></th>
</tr>
</thead>
<tbody id="ast-container" data-app-context="{{@app.context}}/"></tbody>
</table>
</div>
<div id="content-filter-types" style="display: none">
<div class="sort-title">Sort By</div>
<div class="sort-options">
<!--suppress HtmlUnknownTag -->
<th>By Device Type name</th>
</div>
</div>
{{else}}
<div id="user-created-msg" class="container col-centered wr-content">
<div class="wr-form">
<p class="page-sub-title">You Haven't created device types yet.</p>
<br>Please click <b>"Create a Device Type"</b>, if you wish to create a device type.
<hr/>
<a href="{{@app.context}}/device-type/add" class="cu-btn-inner">
<span class="fw-stack">
<i class="fw fw-circle-outline fw-stack-2x"></i>
<i class="fw fw-add fw-stack-1x"></i>
</span>
Create Device Type
</a>
</div>
</div>
{{/if}}
{{/zone}}
{{#zone "bottomJs"}}
<!--suppress HtmlUnknownTarget -->
<script id="devicetype-listing" data-current-user="{{@user.username}}"
src="{{@page.publicUri}}/templates/devicetype-listing.hbs" type="text/x-handlebars-template"></script>
{{js "js/devicetype-listing.js"}}
{{/zone}}

@ -0,0 +1,36 @@
/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
function onRequest(context) {
var deviceModule = require("/app/modules/business-controllers/device.js")["deviceModule"];
var deviceMgtProps = require("/app/modules/conf-reader/main.js")["conf"];
context["permissions"] = userModule.getUIPermissions();
if (userModule.isAuthorized("/permission/admin/device-mgt/admin/device-type")) {
context["editPermitted"] = true;
}
var deviceTypeCount = deviceModule.getDeviceTypeCount();
if (deviceTypeCount > 0) {
context["hasDeviceTypes"] = true;
} else {
context["hasDeviceTypes"] = false;
}
return context;
}

@ -0,0 +1,206 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
var loadDeviceTypeBasedActionURL = function (action, deviceTypeName) {
href = $("#ast-container").data("app-context") + "device-type/" + action + "?type=" + encodeURIComponent(deviceTypeName);
$(location).attr('href', href);
};
$(function () {
var sortableElem = '.wr-sortable';
$(sortableElem).sortable({
beforeStop: function () {
$(this).sortable('toArray');
}
});
$(sortableElem).disableSelection();
});
var apiBasePath = "/api/device-mgt/v1.0";
var modalPopup = ".modal";
var modalPopupContainer = modalPopup + " .modal-content";
var modalPopupContent = modalPopup + " .modal-content";
var body = "body";
var isInit = true;
var isCloud = false;
/**
*
* Fires the res_text when ever a data table redraw occurs making
* the font icons change the size to respective screen resolution.
*
*/
$(document).on('draw.dt', function () {
$(".icon .text").res_text(0.2);
});
/*
* set popup maximum height function.
*/
function setPopupMaxHeight() {
$(modalPopupContent).css('max-height', ($(body).height() - ($(body).height() / 100 * 30)));
$(modalPopupContainer).css('margin-top', (-($(modalPopupContainer).height() / 2)));
}
/*
* show popup function.
*/
function showPopup() {
$(modalPopup).modal('show');
//setPopupMaxHeight();
}
/*
* hide popup function.
*/
function hidePopup() {
$(modalPopupContent).html('');
$(modalPopup).modal('hide');
$('body').removeClass('modal-open').css('padding-right', '0px');
$('.modal-backdrop').remove();
}
/**
* Following function would execute
* when a user clicks on the list item
* initial mode and with out select mode.
*/
function InitiateViewOption() {
// $(location).attr('href', $(this).data("url"));
}
function htmlspecialchars(text) {
return jQuery('<div/>').text(text).html();
}
function loadDeviceTypes() {
var loadingContent = $("#loading-content");
loadingContent.show();
var dataFilter = function (data) {
data = JSON.parse(data);
var objects = [];
$(data).each(function (index) {
objects.push(
{
name: htmlspecialchars(data[index].name),
DT_RowId: "devicetype-" + htmlspecialchars(data[index].name),
metaDefinition: (data[index].deviceTypeMetaDefinition ? true : false)
}
)
});
var json = {
"recordsTotal": data.length,
"recordsFiltered": data.length,
"data": objects
};
return JSON.stringify(json);
};
//noinspection JSUnusedLocalSymbols
var fnCreatedRow = function (nRow, aData, iDataIndex) {
$(nRow).attr('data-type', 'selectable');
};
//noinspection JSUnusedLocalSymbols
var columns = [
{
class: "remove-padding icon-only content-fill",
data: null,
defaultContent: "<div class='thumbnail icon'>" +
"<i class='square-element text fw fw-devices' style='font-size: 74px;'></i>" +
"</div>"
},
{
class: "",
data: "name",
render: function (name, type, row, meta) {
return '<h4>' + name.replace("devicemgt", ""); + '</h4>';
}
},
{
class: "text-right content-fill text-left-on-grid-view no-wrap",
data: null,
render: function (data, type, row, meta) {
var isCloud = false;
if ($('#is-cloud').length > 0) {
isCloud = true;
}
var innerhtml = '';
if (data.metaDefinition) {
var editLink = '<a onclick="javascript:loadDeviceTypeBasedActionURL(\'edit\', \'' + data.name + '\')" ' +
'data-devicetype="' + data.name + '" ' +
'data-click-event="edit-form" ' +
'class="btn padding-reduce-on-grid-view edit-devicetype-link">' +
'<span class="fw-stack">' +
'<i class="fw fw-circle-outline fw-stack-2x"></i>' +
'<i class="fw fw-devices fw-stack-1x"></i>' +
'<span class="fw-stack fw-move-right fw-move-bottom">' +
'<i class="fw fw-circle fw-stack-2x fw-stroke fw-inverse"></i>' +
'<i class="fw fw-circle fw-stack-2x"></i><i class="fw fw-edit fw-stack-1x fw-inverse"></i>' +
'</span>' +
'</span>' +
'<span class="hidden-xs hidden-on-grid-view">Edit</span>' +
'</a>';
var editEventLink = '<a onclick="javascript:loadDeviceTypeBasedActionURL(\'edit-event\', \'' + data.name + '\')" ' +
'data-devicetype="' + data.name + '" ' +
'data-click-event="edit-form" ' +
'class="btn padding-reduce-on-grid-view edit-event-link">' +
'<span class="fw-stack">' +
'<i class="fw fw-circle-outline fw-stack-2x"></i>' +
'<i class="fw fw-document fw-stack-1x"></i>' +
'<span class="fw-stack fw-move-right fw-move-bottom">' +
'<i class="fw fw-circle fw-stack-2x fw-stroke fw-inverse"></i>' +
'<i class="fw fw-circle fw-stack-2x"></i><i class="fw fw-edit fw-stack-1x fw-inverse"></i>' +
'</span>' +
'</span>' +
'<span class="hidden-xs hidden-on-grid-view">Edit Event</span>' +
'</a>';
innerhtml = editLink + editEventLink;
}
return innerhtml;
}
}
];
var options = {
"placeholder": "Search By Device Type Name",
"searchKey": "filter"
};
var settings = {
"sorting": false
};
var deviceTypeApiUrl = '/api/device-mgt/v1.0/admin/device-types';
$('#devicetype-grid').datatables_extended_serverside_paging(settings, deviceTypeApiUrl, dataFilter, columns, fnCreatedRow, null, options);
loadingContent.hide();
}
$(document).ready(function () {
loadDeviceTypes();
});

@ -0,0 +1,44 @@
{{#each deviceTypes}}
<tr data-type="selectable" id="devicetype-{{deviceTypeName}}">
<td class="remove-padding icon-only content-fill">
<div class="thumbnail icon">
<i class="square-element text fw fw-user"></i>
</div>
</td>
<td class="remove-padding-top">{{deviceTypeName}}</td>
<td class="text-right content-fill text-left-on-grid-view no-wrap">
{{#if canEdit}}
<a onclick="javascript:loadDeviceTypeBasedActionURL('edit', '{{deviceTypeName}}')" data-devicetype="{{deviceTypeName}}"
data-click-event="edit-form"
class="btn padding-reduce-on-grid-view edit-devicetype-link" title="Edit Device Type">
<span class="fw-stack fw-lg">
<i class="fw fw-circle-outline fw-stack-2x"></i>
<i class="fw fw-user fw-stack-1x"></i>
<span class="fw-stack fw-move-right fw-move-bottom">
<i class="fw fw-circle fw-stack-2x fw-stroke fw-inverse"></i>
<i class="fw fw-circle fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x fw-inverse"></i>
</span>
</span>
<span class="hidden-xs hidden-on-grid-view">Edit</span>
</a>
<a onclick="javascript:loadDeviceTypeBasedActionURL('edit-event', '{{deviceTypeName}}')"
data-devicetype="{{deviceTypeName}}"
data-click-event="edit-form" class="btn padding-reduce-on-grid-view edit-permission-link"
title="Edit Device Event">
<span class="fw-stack fw-lg">
<i class="fw fw-circle-outline fw-stack-2x"></i>
<i class="fw fw-security-policy fw-stack-1x"></i>
<span class="fw-stack fw-move-right fw-move-bottom">
<i class="fw fw-circle fw-stack-2x fw-stroke fw-inverse"></i>
<i class="fw fw-circle fw-stack-2x"></i>
<i class="fw fw-edit fw-stack-1x fw-inverse"></i>
</span>
</span>
<span class="hidden-xs hidden-on-grid-view">Edit Event</span>
</a>
{{/if}}
</td>
</tr>
{{/each}}

@ -30,7 +30,14 @@
</a>
</li>
{{/if}}
{{#if permissions.IS_ADMIN}}
<li>
<a href="{{@app.context}}/device-types">
<i class="fw fw-devices"></i>
Device Type Management
</a>
</li>
{{/if}}
{{#unless isCloud}}
{{#if permissions.VIEW_DASHBOARD}}
<li>

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS DM_DEVICE_TYPE (
ID INT AUTO_INCREMENT NOT NULL,
NAME VARCHAR(300) NULL DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(2000) NULL DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(20000) NULL DEFAULT NULL,
LAST_UPDATED_TIMESTAMP TIMESTAMP NOT NULL,
PROVIDER_TENANT_ID INTEGER DEFAULT 0,
SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE,

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS DM_DEVICE_TYPE (
ID INT AUTO_INCREMENT NOT NULL,
NAME VARCHAR(300) NULL DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(2000) NULL DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(20000) NULL DEFAULT NULL,
LAST_UPDATED_TIMESTAMP TIMESTAMP NOT NULL,
PROVIDER_TENANT_ID INTEGER DEFAULT 0,
SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE,

@ -2,7 +2,7 @@ IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[D
CREATE TABLE DM_DEVICE_TYPE (
ID INTEGER IDENTITY(1,1) NOT NULL,
NAME VARCHAR(300) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(2000) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(20000) DEFAULT NULL,
LAST_UPDATED_TIMESTAMP DATETIME2 NOT NULL,
PROVIDER_TENANT_ID INTEGER NULL,
SHARED_WITH_ALL_TENANTS BIT NOT NULL DEFAULT 0,

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS DM_DEVICE_TYPE (
ID INTEGER AUTO_INCREMENT NOT NULL,
NAME VARCHAR(300) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(2000) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(20000) DEFAULT NULL,
LAST_UPDATED_TIMESTAMP TIMESTAMP NOT NULL,
PROVIDER_TENANT_ID INTEGER DEFAULT 0,
SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE,

@ -1,7 +1,7 @@
CREATE TABLE DM_DEVICE_TYPE (
ID NUMBER(10) NOT NULL,
NAME VARCHAR2(300) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR2(2000) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR2(20000) DEFAULT NULL,
LAST_UPDATED_TIMESTAMP TIMESTAMP NOT NULL,
PROVIDER_TENANT_ID INTEGER DEFAULT 0,
SHARED_WITH_ALL_TENANTS NUMBER(1) DEFAULT 0 NOT NULL,

@ -1,7 +1,7 @@
CREATE TABLE IF NOT EXISTS DM_DEVICE_TYPE (
ID BIGSERIAL PRIMARY KEY,
NAME VARCHAR(300) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(2000) DEFAULT NULL,
DEVICE_TYPE_META VARCHAR(20000) DEFAULT NULL,
LAST_UPDATED_TIMESTAMP TIMESTAMP NOT NULL,
PROVIDER_TENANT_ID INTEGER DEFAULT 0,
SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE,

Loading…
Cancel
Save