fix concurrent accesss issue with remote session

revert-dabc3590
warunalakshitha 7 years ago
parent f0faba1b34
commit 82f6736bce

@ -23,7 +23,7 @@
<parent> <parent>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId> <groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>remote-session-extension</artifactId> <artifactId>remote-session-extension</artifactId>
<version>4.0.54-SNAPSHOT</version> <version>4.0.66-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

@ -20,11 +20,9 @@ package org.wso2.carbon.device.mgt.extensions.remote.session.endpoint;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.extensions.remote.session.constants.RemoteSessionConstants;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionInvalidException;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.HttpSessionConfigurator; import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.HttpSessionConfigurator;
import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.ServiceHolder; import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.ServiceHolder;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import javax.websocket.CloseReason; import javax.websocket.CloseReason;
import javax.websocket.OnClose; import javax.websocket.OnClose;
@ -43,6 +41,7 @@ import java.io.IOException;
public class ClientSessionSubscriptionEndpoint extends SubscriptionEndpoint { public class ClientSessionSubscriptionEndpoint extends SubscriptionEndpoint {
private static final Log log = LogFactory.getLog(ClientSessionSubscriptionEndpoint.class); private static final Log log = LogFactory.getLog(ClientSessionSubscriptionEndpoint.class);
/** /**
* Web socket onOpen - When client sends a message * Web socket onOpen - When client sends a message
* *
@ -51,15 +50,10 @@ public class ClientSessionSubscriptionEndpoint extends SubscriptionEndpoint {
@OnOpen @OnOpen
public void onOpen(Session session, @PathParam("deviceType") String deviceType, @PathParam("deviceId") String public void onOpen(Session session, @PathParam("deviceType") String deviceType, @PathParam("deviceId") String
deviceId) { deviceId) {
System.out.print("**************Open***************");
if (log.isDebugEnabled()) {
log.debug("WebSocket opened, for RemoteSession id: " + session.getId());
}
try { try {
ServiceHolder.getInstance().getRemoteSessionManagementService().initializeSession(session, deviceType, deviceId); ServiceHolder.getInstance().getRemoteSessionManagementService().initializeSession(session, deviceType,
System.out.print("**************Opened***************"); deviceId);
} catch (RemoteSessionInvalidException e) { } catch (RemoteSessionManagementException e) {
System.out.print(e.getMessage());
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.error("Error occurred while initializing session ", e); log.error("Error occurred while initializing session ", e);
} }
@ -68,20 +62,7 @@ public class ClientSessionSubscriptionEndpoint extends SubscriptionEndpoint {
} catch (IOException ex) { } catch (IOException ex) {
log.error("Failed to disconnect the client.", ex); log.error("Failed to disconnect the client.", ex);
} }
} catch (RemoteSessionManagementException e) {
System.out.print(e.getMessage());
if (log.isDebugEnabled()) {
log.error("Error occurred while initializing session ", e);
}
try {
session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "Error occurred while adding operation"));
} catch (IOException ex) {
if (log.isDebugEnabled()) {
log.error("Failed to disconnect the client.", ex);
}
}
} }
} }
/** /**
@ -92,7 +73,7 @@ public class ClientSessionSubscriptionEndpoint extends SubscriptionEndpoint {
*/ */
@OnMessage @OnMessage
public void onMessage(Session session, String message, @PathParam("deviceType") String deviceType, @PathParam public void onMessage(Session session, String message, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) throws RemoteSessionManagementException { ("deviceId") String deviceId) {
super.onMessage(session, message, deviceType, deviceId); super.onMessage(session, message, deviceType, deviceId);
} }
@ -104,7 +85,7 @@ public class ClientSessionSubscriptionEndpoint extends SubscriptionEndpoint {
*/ */
@OnMessage @OnMessage
public void onMessage(Session session, byte[] message, @PathParam("deviceType") String deviceType, @PathParam public void onMessage(Session session, byte[] message, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) throws RemoteSessionManagementException { ("deviceId") String deviceId) {
super.onMessage(session, message, deviceType, deviceId); super.onMessage(session, message, deviceType, deviceId);
} }

@ -20,11 +20,9 @@ package org.wso2.carbon.device.mgt.extensions.remote.session.endpoint;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.extensions.remote.session.constants.RemoteSessionConstants;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionInvalidException;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.HttpSessionConfigurator; import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.HttpSessionConfigurator;
import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.ServiceHolder; import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.ServiceHolder;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import javax.websocket.CloseReason; import javax.websocket.CloseReason;
import javax.websocket.OnClose; import javax.websocket.OnClose;
@ -43,6 +41,7 @@ import java.io.IOException;
public class DeviceSessionSubscriptionEndpoint extends SubscriptionEndpoint { public class DeviceSessionSubscriptionEndpoint extends SubscriptionEndpoint {
private static final Log log = LogFactory.getLog(DeviceSessionSubscriptionEndpoint.class); private static final Log log = LogFactory.getLog(DeviceSessionSubscriptionEndpoint.class);
/** /**
* Web socket onOpen - When client sends a message * Web socket onOpen - When client sends a message
* *
@ -51,16 +50,10 @@ public class DeviceSessionSubscriptionEndpoint extends SubscriptionEndpoint {
@OnOpen @OnOpen
public void onOpen(Session session, @PathParam("deviceType") String deviceType, @PathParam("deviceId") String public void onOpen(Session session, @PathParam("deviceType") String deviceType, @PathParam("deviceId") String
deviceId, @PathParam("operationId") String operationId) { deviceId, @PathParam("operationId") String operationId) {
System.out.print("**************Open***************"+operationId);
if (log.isDebugEnabled()) {
log.debug("WebSocket opened, for RemoteSession id: " + session.getId());
}
try { try {
ServiceHolder.getInstance().getRemoteSessionManagementService().initializeSession(session, deviceType, ServiceHolder.getInstance().getRemoteSessionManagementService().initializeSession(session, deviceType,
deviceId, operationId); deviceId, operationId);
System.out.print("**************Opened***************"); } catch (RemoteSessionManagementException e) {
} catch (RemoteSessionInvalidException e) {
System.out.print(e.getMessage());
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.error("Error occurred while initializing session ", e); log.error("Error occurred while initializing session ", e);
} }
@ -69,20 +62,7 @@ public class DeviceSessionSubscriptionEndpoint extends SubscriptionEndpoint {
} catch (IOException ex) { } catch (IOException ex) {
log.error("Failed to disconnect the client.", ex); log.error("Failed to disconnect the client.", ex);
} }
} catch (RemoteSessionManagementException e) {
System.out.print(e.getMessage());
if (log.isDebugEnabled()) {
log.error("Error occurred while initializing session ", e);
}
try {
session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "Error occurred while adding operation"));
} catch (IOException ex) {
if (log.isDebugEnabled()) {
log.error("Failed to disconnect the client.", ex);
}
}
} }
} }
/** /**
@ -93,7 +73,7 @@ public class DeviceSessionSubscriptionEndpoint extends SubscriptionEndpoint {
*/ */
@OnMessage @OnMessage
public void onMessage(Session session, String message, @PathParam("deviceType") String deviceType, @PathParam public void onMessage(Session session, String message, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) throws RemoteSessionManagementException { ("deviceId") String deviceId) {
super.onMessage(session, message, deviceType, deviceId); super.onMessage(session, message, deviceType, deviceId);
} }
@ -105,7 +85,7 @@ public class DeviceSessionSubscriptionEndpoint extends SubscriptionEndpoint {
*/ */
@OnMessage @OnMessage
public void onMessage(Session session, byte[] message, @PathParam("deviceType") String deviceType, @PathParam public void onMessage(Session session, byte[] message, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) throws RemoteSessionManagementException { ("deviceId") String deviceId) {
super.onMessage(session, message, deviceType, deviceId); super.onMessage(session, message, deviceType, deviceId);
} }

@ -20,9 +20,8 @@ package org.wso2.carbon.device.mgt.extensions.remote.session.endpoint;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionInvalidException;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.ServiceHolder; import org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.utils.ServiceHolder;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import javax.websocket.CloseReason; import javax.websocket.CloseReason;
import javax.websocket.Session; import javax.websocket.Session;
@ -43,15 +42,14 @@ public class SubscriptionEndpoint {
* @param message - Status code for web-socket close. * @param message - Status code for web-socket close.
*/ */
public void onMessage(Session session, String message, @PathParam("deviceType") String deviceType, @PathParam public void onMessage(Session session, String message, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) throws RemoteSessionManagementException { ("deviceId") String deviceId) {
System.out.print("______________" + session.getId());
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Received message from client for RemoteSession id: " + session.getId() + " device type: " + log.debug("Received message from client for RemoteSession id: " + session.getId() + " device type: " +
deviceType + " device id: " + deviceId); deviceType + " device id: " + deviceId);
} }
try { try {
ServiceHolder.getInstance().getRemoteSessionManagementService().sendMessageToPeer(session, message); ServiceHolder.getInstance().getRemoteSessionManagementService().sendMessageToPeer(session, message);
} catch (RemoteSessionInvalidException e) { } catch (RemoteSessionManagementException e) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.error("Error occurred while send message to peer session ", e); log.error("Error occurred while send message to peer session ", e);
} }
@ -72,15 +70,14 @@ public class SubscriptionEndpoint {
* @param message - Message which needs to send to peer * @param message - Message which needs to send to peer
*/ */
public void onMessage(Session session, byte[] message, @PathParam("deviceType") String deviceType, @PathParam public void onMessage(Session session, byte[] message, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) throws RemoteSessionManagementException { ("deviceId") String deviceId) {
System.out.print("______________" + session.getId());
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Received message from client for RemoteSession id: " + session.getId() + " device type: " + log.debug("Received message from client for RemoteSession id: " + session.getId() + " device type: " +
deviceType + " device id: " + deviceId); deviceType + " device id: " + deviceId);
} }
try { try {
ServiceHolder.getInstance().getRemoteSessionManagementService().sendMessageToPeer(session, message); ServiceHolder.getInstance().getRemoteSessionManagementService().sendMessageToPeer(session, message);
} catch (RemoteSessionInvalidException e) { } catch (RemoteSessionManagementException e) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.error("Error occurred while send message to peer session ", e); log.error("Error occurred while send message to peer session ", e);
} }
@ -102,17 +99,14 @@ public class SubscriptionEndpoint {
*/ */
public void onClose(Session session, CloseReason reason, @PathParam("deviceType") String deviceType, @PathParam public void onClose(Session session, CloseReason reason, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) { ("deviceId") String deviceId) {
ServiceHolder.getInstance().getRemoteSessionManagementService().endSession(session, "Remote session closed");
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Closing a WebSocket due to " + reason.getReasonPhrase() + ", for session ID:" + session.getId log.debug("websocket closed due to " + reason.getReasonPhrase() + ", for session ID:" + session.getId
() + ", for request URI - " + session.getRequestURI() + " device type: " + deviceType + " device id: " + deviceId); () + ", for request URI - " + session.getRequestURI() + " device type: " + deviceType + " device " +
} "id: " + deviceId);
try {
ServiceHolder.getInstance().getRemoteSessionManagementService().endSession(session);
} catch (IOException ex) {
if (log.isDebugEnabled()) {
log.error("Failed to disconnect the client.", ex);
}
} }
} }
/** /**
@ -123,12 +117,20 @@ public class SubscriptionEndpoint {
*/ */
public void onError(Session session, Throwable throwable, @PathParam("deviceType") String deviceType, @PathParam public void onError(Session session, Throwable throwable, @PathParam("deviceType") String deviceType, @PathParam
("deviceId") String deviceId) { ("deviceId") String deviceId) {
log.error(
"Error occurred in session ID: " + session.getId() + " device type: " + deviceType + " device id: " + if (throwable instanceof IOException) {
deviceId + ", for request URI - " + session.getRequestURI() + if (log.isDebugEnabled()) {
log.error("Error occurred in session ID: " + session.getId() + " device type: " + deviceType +
"device id: " + deviceId + ", for request URI - " + session.getRequestURI() +
", " + throwable.getMessage(), throwable); ", " + throwable.getMessage(), throwable);
}
} else {
log.error("Error occurred in session ID: " + session.getId() + " device type: " + deviceType + " device " +
"id: " + deviceId + ", for request URI - " + session.getRequestURI() + ", " + throwable.getMessage
(), throwable);
}
try { try {
ServiceHolder.getInstance().getRemoteSessionManagementService().endSession(session); ServiceHolder.getInstance().getRemoteSessionManagementService().endSession(session, "Remote session closed");
if (session.isOpen()) { if (session.isOpen()) {
session.close(new CloseReason(CloseReason.CloseCodes.PROTOCOL_ERROR, "Unexpected Error Occurred")); session.close(new CloseReason(CloseReason.CloseCodes.PROTOCOL_ERROR, "Unexpected Error Occurred"));
} }

@ -20,6 +20,9 @@
package org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.constants; package org.wso2.carbon.device.mgt.extensions.remote.session.endpoint.constants;
/**
* This holds the constants related to remote session web socket endpoint
*/
public class Constants { public class Constants {
public static final String HTTP_HEADERS = "HttpHeaders"; public static final String HTTP_HEADERS = "HttpHeaders";
} }

@ -1,6 +1,6 @@
/* /*
* *
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* WSO2 Inc. licenses this file to you under the Apache License, * WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except * Version 2.0 (the "License"); you may not use this file except

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
~ Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. ~ Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
~ ~
~ WSO2 Inc. licenses this file to you under the Apache License, ~ WSO2 Inc. licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except ~ Version 2.0 (the "License"); you may not use this file except
@ -22,7 +22,7 @@
<parent> <parent>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId> <groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>remote-session-extension</artifactId> <artifactId>remote-session-extension</artifactId>
<version>4.0.54-SNAPSHOT</version> <version>4.0.66-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

@ -17,7 +17,6 @@
*/ */
package org.wso2.carbon.device.mgt.extensions.remote.session; package org.wso2.carbon.device.mgt.extensions.remote.session;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionInvalidException;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException; import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import javax.websocket.Session; import javax.websocket.Session;
@ -34,11 +33,10 @@ public interface RemoteSessionManagementService {
* @param session Web socket RemoteSession * @param session Web socket RemoteSession
* @param deviceType Device Type * @param deviceType Device Type
* @param deviceId Device Id * @param deviceId Device Id
* @throws RemoteSessionInvalidException throws when session cannot be made due to invalid data * @throws RemoteSessionManagementException throws when session has errors with accessing device resources
* @throws RemoteSessionManagementException throws when session has error with accessing device resources
*/ */
public void initializeSession(Session session, String deviceType, String deviceId) throws public void initializeSession(Session session, String deviceType, String deviceId) throws
RemoteSessionInvalidException, RemoteSessionManagementException; RemoteSessionManagementException;
/** /**
* Initialize session based on web socket request . This method use by the device to connect * Initialize session based on web socket request . This method use by the device to connect
@ -47,39 +45,34 @@ public interface RemoteSessionManagementService {
* @param deviceType Device Type * @param deviceType Device Type
* @param deviceId Device Id * @param deviceId Device Id
* @param operationId Operation Id that device needs to connec * @param operationId Operation Id that device needs to connec
* @throws RemoteSessionInvalidException throws when session cannot be made due to invalid data * @throws RemoteSessionManagementException throws when session has errors with accessing device resources
* @throws RemoteSessionManagementException throws when session has error with accessing device resources
*/ */
public void initializeSession(Session session, String deviceType, String deviceId, String operationId) throws public void initializeSession(Session session, String deviceType, String deviceId, String operationId) throws
RemoteSessionInvalidException, RemoteSessionManagementException; RemoteSessionManagementException;
/** /**
* Send message to connected remote device or client * Send string message to connected remote device or client
* *
* @param session Web socket RemoteSession * @param session Web socket RemoteSession
* @param message Message needs to send to peer connection client * @param message Message needs to send to peer connection client
* @throws RemoteSessionInvalidException
* @throws RemoteSessionManagementException * @throws RemoteSessionManagementException
*/ */
public void sendMessageToPeer(Session session, String message) throws public void sendMessageToPeer(Session session, String message) throws RemoteSessionManagementException;
RemoteSessionInvalidException, RemoteSessionManagementException;
/** /**
* Send message to connected remote device or client * Send byte message to connected remote device or client
* *
* @param session Web socket RemoteSession * @param session Web socket RemoteSession
* @param message Message needs to send to peer connection * @param message Message needs to send to peer connection
* @throws RemoteSessionInvalidException
* @throws RemoteSessionManagementException * @throws RemoteSessionManagementException
*/ */
public void sendMessageToPeer(Session session, byte[] message) throws public void sendMessageToPeer(Session session, byte[] message) throws RemoteSessionManagementException;
RemoteSessionInvalidException, RemoteSessionManagementException;
/** /**
* Close the session * Close the session
* *
* @param session Web socket RemoteSession * @param session Web socket RemoteSession
*/ */
public void endSession(Session session) throws IOException; public void endSession(Session session,String closeReason);
} }

@ -33,10 +33,7 @@ import org.wso2.carbon.device.mgt.core.operation.mgt.ConfigOperation;
import org.wso2.carbon.device.mgt.extensions.remote.session.authentication.AuthenticationInfo; import org.wso2.carbon.device.mgt.extensions.remote.session.authentication.AuthenticationInfo;
import org.wso2.carbon.device.mgt.extensions.remote.session.authentication.OAuthAuthenticator; import org.wso2.carbon.device.mgt.extensions.remote.session.authentication.OAuthAuthenticator;
import org.wso2.carbon.device.mgt.extensions.remote.session.constants.RemoteSessionConstants; import org.wso2.carbon.device.mgt.extensions.remote.session.constants.RemoteSessionConstants;
import org.wso2.carbon.device.mgt.extensions.remote.session.dto.ClientSession; import org.wso2.carbon.device.mgt.extensions.remote.session.dto.RemoteSession;
import org.wso2.carbon.device.mgt.extensions.remote.session.dto.DeviceSession;
import org.wso2.carbon.device.mgt.extensions.remote.session.dto.common.RemoteSession;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionInvalidException;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException; import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import org.wso2.carbon.device.mgt.extensions.remote.session.internal.RemoteSessionManagementDataHolder; import org.wso2.carbon.device.mgt.extensions.remote.session.internal.RemoteSessionManagementDataHolder;
@ -53,21 +50,19 @@ import java.util.Map;
public class RemoteSessionManagementServiceImpl implements RemoteSessionManagementService { public class RemoteSessionManagementServiceImpl implements RemoteSessionManagementService {
private static final Log log = LogFactory.getLog(RemoteSessionManagementServiceImpl.class); private static final Log log = LogFactory.getLog(RemoteSessionManagementServiceImpl.class);
private static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
private static final int MAX_BUFFER_SIZE = 640 * 1024;
@Override @Override
public void initializeSession(Session session, String deviceType, String deviceId, String operationId) throws public void initializeSession(Session session, String deviceType, String deviceId, String operationId) throws
RemoteSessionInvalidException, RemoteSessionManagementException { RemoteSessionManagementException {
// Check whether required configurations are enabled
if (!RemoteSessionManagementDataHolder.getInstance().isEnabled()) { if (!RemoteSessionManagementDataHolder.getInstance().isEnabled()) {
throw new RemoteSessionManagementException("Remote session feature is disabled."); throw new RemoteSessionManagementException("Remote session feature is disabled.");
} else if (RemoteSessionManagementDataHolder.getInstance().getServerUrl() == null) { } else if (RemoteSessionManagementDataHolder.getInstance().getServerUrl() == null) {
throw new RemoteSessionManagementException("Server url haven't been configured."); throw new RemoteSessionManagementException("Server url has not been configured.");
} }
// Read Query Parameters for obtain the token
Map<String, List<String>> sessionQueryParam = new HashedMap(); Map<String, List<String>> sessionQueryParam = new HashedMap();
List<String> sessionQueryParamList = new LinkedList<>(); List<String> sessionQueryParamList = new LinkedList<>();
sessionQueryParamList.add(session.getQueryString()); sessionQueryParamList.add(session.getQueryString());
@ -78,64 +73,61 @@ public class RemoteSessionManagementServiceImpl implements RemoteSessionManageme
AuthenticationInfo authenticationInfo = oAuthAuthenticator.isAuthenticated(sessionQueryParam); AuthenticationInfo authenticationInfo = oAuthAuthenticator.isAuthenticated(sessionQueryParam);
if (authenticationInfo != null && authenticationInfo.isAuthenticated()) { if (authenticationInfo != null && authenticationInfo.isAuthenticated()) {
try { try {
PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(authenticationInfo.getTenantDomain() PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(authenticationInfo
.getTenantDomain()
, true); , true);
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(authenticationInfo.getUsername()); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(authenticationInfo.getUsername());
if (deviceId != null && !deviceId.isEmpty() && deviceType != null && !deviceType.isEmpty()) { if (deviceId != null && !deviceId.isEmpty() && deviceType != null && !deviceType.isEmpty()) {
DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
deviceIdentifier.setId(deviceId); deviceIdentifier.setId(deviceId);
deviceIdentifier.setType(deviceType); deviceIdentifier.setType(deviceType);
// Check authorization for user
// Check authorization of user for given device
boolean userAuthorized = RemoteSessionManagementDataHolder.getInstance() boolean userAuthorized = RemoteSessionManagementDataHolder.getInstance()
.getDeviceAccessAuthorizationService() .getDeviceAccessAuthorizationService()
.isUserAuthorized(deviceIdentifier, authenticationInfo.getUsername()); .isUserAuthorized(deviceIdentifier, authenticationInfo.getUsername());
if (userAuthorized) { if (userAuthorized) {
log.info("Operation ID: " + operationId);
// set common settings for session // set common settings for session
session.setMaxBinaryMessageBufferSize(MAX_BUFFER_SIZE); session.setMaxBinaryMessageBufferSize(RemoteSessionConstants.MAX_BUFFER_SIZE);
session.setMaxTextMessageBufferSize(MAX_BUFFER_SIZE); session.setMaxTextMessageBufferSize(RemoteSessionConstants.MAX_BUFFER_SIZE);
session.setMaxIdleTimeout(RemoteSessionManagementDataHolder.getInstance().getMaxIdleTimeout()); session.setMaxIdleTimeout(RemoteSessionManagementDataHolder.getInstance().getMaxIdleTimeout());
// if session initiated using operatiod id means request came from device // if session initiated using operation id means request came from device
if (operationId != null) { if (operationId != null) {
Session pendingSession = RemoteSessionManagementDataHolder.getInstance() RemoteSession activeSession = RemoteSessionManagementDataHolder.getInstance()
.getDeviceRequestMap().get((authenticationInfo.getTenantDomain() + "/" + deviceType .getActiveDeviceClientSessionMap().get((authenticationInfo.getTenantDomain() + "/" +
+ "/" + deviceId)); deviceType + "/" + deviceId));
if (activeSession != null) {
if (pendingSession != null) {
RemoteSession clientRemote = RemoteSessionManagementDataHolder.getInstance() RemoteSession clientRemote = RemoteSessionManagementDataHolder.getInstance()
.getSessionMap().get(pendingSession.getId()); .getSessionMap().get(activeSession.getMySession().getId());
if (clientRemote != null) { if (clientRemote != null) {
if (clientRemote.getOperationId().equals(operationId)) { if (clientRemote.getOperationId().equals(operationId)) {
RemoteSession deviceRemote = new DeviceSession(session, authenticationInfo RemoteSession deviceRemote = new RemoteSession(session, authenticationInfo
.getTenantDomain(), deviceType, deviceId, operationId); .getTenantDomain(), deviceType, deviceId);
deviceRemote.setOperationId(operationId);
deviceRemote.setPeerSession(clientRemote); deviceRemote.setPeerSession(clientRemote);
clientRemote.setPeerSession(deviceRemote); clientRemote.setPeerSession(deviceRemote);
RemoteSessionManagementDataHolder.getInstance().getSessionMap().put(session RemoteSessionManagementDataHolder.getInstance().getSessionMap().put(session
.getId(), deviceRemote); .getId(), deviceRemote);
RemoteSessionManagementDataHolder.getInstance().getDeviceRequestMap().remove(
(authenticationInfo.getTenantDomain() + "/" + deviceType + "/" + deviceId));
// Send Remote connect response // Send Remote connect response
JSONObject message = new JSONObject(); JSONObject message = new JSONObject();
message.put("code", RemoteSessionConstants.REMOTE_CONNECT); message.put(RemoteSessionConstants.REMOTE_CONNECT_CODE, RemoteSessionConstants
message.put("operation_response", "connected"); .REMOTE_CONNECT);
deviceRemote.sendMessageToPeer(message.toString()); deviceRemote.sendMessageToPeer(message.toString());
log.info("Device session opened for session id: " + session.getId() +
" device Type : " + deviceType + " , " + "deviceId : " + deviceId);
} else { } else {
throw new RemoteSessionManagementException("Device and Operation information does" + throw new RemoteSessionManagementException("Device and Operation information " +
" not matched with client information for operation id: " + operationId + "does not matched with client information for operation id: " +
" device Type : " + deviceType + " , " + "deviceId : " + operationId + " device Type : " + deviceType + " , " + "deviceId : " +
deviceId); deviceId);
} }
} else { } else {
throw new RemoteSessionManagementException("Device session is inactive for operation " + throw new RemoteSessionManagementException("Device session is inactive for " +
"id: " + operationId + " device Type : " + deviceType + " , " + "deviceId : " + "operation id: " + operationId + " device Type : " + deviceType + " , " +
deviceId); "deviceId : " + deviceId);
} }
@ -144,19 +136,34 @@ public class RemoteSessionManagementServiceImpl implements RemoteSessionManageme
"id: " + operationId + " device Type : " + deviceType + " , " + "deviceId : " + "id: " + operationId + " device Type : " + deviceType + " , " + "deviceId : " +
deviceId); deviceId);
} }
} else { } else {
RemoteSession clientRemote = new RemoteSession(session, authenticationInfo
.getTenantDomain(), deviceType, deviceId);
// Create new remote control operation to start the session // Create new remote control operation to start the session
Session pendingSession = RemoteSessionManagementDataHolder.getInstance().getDeviceRequestMap().get( RemoteSession activeSession = RemoteSessionManagementDataHolder.getInstance()
(authenticationInfo.getTenantDomain() + "/" + deviceType + "/" + deviceId)); .getActiveDeviceClientSessionMap().putIfAbsent((authenticationInfo
if (pendingSession != null && pendingSession.isOpen()) { .getTenantDomain() + "/" + deviceType + "/" + deviceId),
throw new RemoteSessionManagementException("Another client session waiting on device to connect."); clientRemote);
if (activeSession != null && activeSession.getMySession().isOpen() && activeSession
.getPeerSession() == null) {
throw new RemoteSessionManagementException("Another client session waiting on device " +
"to connect.");
} else { } else {
Session lastSession = RemoteSessionManagementDataHolder.getInstance().getDeviceRequestMap().putIfAbsent( // if there is pending session exists but already closed, then we need to remove it.
(authenticationInfo.getTenantDomain() + "/" + deviceType + "/" + deviceId), if (activeSession != null) {
session); endSession(activeSession.getMySession(), "Remote session closed due to new session" +
" request");
// Use put if absent for adding session to waiting list since we need to overcome
// multithreaded session requests.
activeSession = RemoteSessionManagementDataHolder.getInstance()
.getActiveDeviceClientSessionMap().putIfAbsent((authenticationInfo
.getTenantDomain() + "/" + deviceType + "/" +
deviceId), clientRemote);
}
if (lastSession == null) { // If another client tried to start session same time then active session will be
// exist. So we are adding session request only no parallel sessions added to map
if (activeSession == null) {
// Create operation if session initiated by client // Create operation if session initiated by client
Operation operation = new ConfigOperation(); Operation operation = new ConfigOperation();
@ -164,55 +171,58 @@ public class RemoteSessionManagementServiceImpl implements RemoteSessionManageme
operation.setEnabled(true); operation.setEnabled(true);
operation.setControl(Operation.Control.NO_REPEAT); operation.setControl(Operation.Control.NO_REPEAT);
JSONObject payload = new JSONObject(); JSONObject payload = new JSONObject();
payload.put("serverUrl", RemoteSessionManagementDataHolder.getInstance().getServerUrl()); payload.put("serverUrl", RemoteSessionManagementDataHolder.getInstance()
.getServerUrl());
operation.setPayLoad(payload.toString()); operation.setPayLoad(payload.toString());
String date = new SimpleDateFormat(DATE_FORMAT_NOW).format(new Date()); String date = new SimpleDateFormat(RemoteSessionConstants.DATE_FORMAT_NOW).format
(new Date());
operation.setCreatedTimeStamp(date); operation.setCreatedTimeStamp(date);
List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>(); List<DeviceIdentifier> deviceIdentifiers = new ArrayList<>();
deviceIdentifiers.add(new DeviceIdentifier(deviceId, deviceType)); deviceIdentifiers.add(new DeviceIdentifier(deviceId, deviceType));
Activity activity = RemoteSessionManagementDataHolder.getInstance() Activity activity = RemoteSessionManagementDataHolder.getInstance()
.getDeviceManagementProviderService().addOperation(deviceType, operation, .getDeviceManagementProviderService().addOperation(deviceType, operation,
deviceIdentifiers); deviceIdentifiers);
log.info("Activity id: " + activity.getActivityId()); clientRemote.setOperationId(activity.getActivityId()
.replace(DeviceManagementConstants.OperationAttributes.ACTIVITY, ""));
RemoteSessionManagementDataHolder.getInstance().getSessionMap().put(session.getId
(), clientRemote);
log.info("Client remote session opened for session id: " + session.getId() +
" device Type : " + deviceType + " , " + "deviceId : " + deviceId);
RemoteSession clientRemote = new ClientSession(session, authenticationInfo } else {
.getTenantDomain(), deviceType, deviceId, activity.getActivityId().replace(DeviceManagementConstants throw new RemoteSessionManagementException("Another client session waiting on " +
.OperationAttributes.ACTIVITY, "")); "device to connect.");
RemoteSessionManagementDataHolder.getInstance().getSessionMap().put(session.getId(), clientRemote);
} }
} }
} }
log.info("Current session count: " + RemoteSessionManagementDataHolder log.info("Current remote sessions count: " + RemoteSessionManagementDataHolder.getInstance()
.getInstance().getSessionMap().size()); .getSessionMap().size());
} else { } else {
throw new RemoteSessionInvalidException("Missing device Id or type ", new CloseReason throw new RemoteSessionManagementException("Missing device Id or type ");
(CloseReason.CloseCodes.CANNOT_ACCEPT, "Missing device Id or device type "));
} }
} else { } else {
throw new RemoteSessionInvalidException("Unauthorized Access for the device Type : " + deviceType throw new RemoteSessionManagementException("Unauthorized Access for the device Type : " + deviceType
+ " , deviceId : " + deviceId, new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, + " , deviceId : " + deviceId);
"Unauthorized Access"));
} }
} catch (OperationManagementException | InvalidDeviceException e) { } catch (OperationManagementException | InvalidDeviceException e) {
throw new RemoteSessionManagementException("Error occurred while adding initial operation for the device Type : " + throw new RemoteSessionManagementException("Error occurred while adding initial operation for the " +
deviceType + " , deviceId : " + deviceId, e); "device Type : " + deviceType + " , deviceId : " + deviceId);
} catch (DeviceAccessAuthorizationException e) { } catch (DeviceAccessAuthorizationException e) {
throw new RemoteSessionManagementException("Error occurred while device access authorization for the device Type : " + throw new RemoteSessionManagementException("Error occurred while device access authorization for the " +
deviceType + " , " + "deviceId : " + deviceId, e); "device Type : " + deviceType + " , " + "deviceId : " + deviceId);
} finally { } finally {
PrivilegedCarbonContext.endTenantFlow(); PrivilegedCarbonContext.endTenantFlow();
} }
} else { } else {
throw new RemoteSessionInvalidException("Invalid token", new CloseReason(CloseReason.CloseCodes throw new RemoteSessionManagementException("Invalid token");
.CANNOT_ACCEPT, "Invalid token"));
} }
} }
@Override @Override
public void initializeSession(Session session, String deviceType, String deviceId) throws RemoteSessionInvalidException, RemoteSessionManagementException { public void initializeSession(Session session, String deviceType, String deviceId) throws
RemoteSessionManagementException {
initializeSession(session, deviceType, deviceId, null); initializeSession(session, deviceType, deviceId, null);
} }
@ -221,22 +231,18 @@ public class RemoteSessionManagementServiceImpl implements RemoteSessionManageme
* *
* @param session Web socket RemoteSession * @param session Web socket RemoteSession
* @param message String message needs to send to peer connection * @param message String message needs to send to peer connection
* @throws RemoteSessionInvalidException throws when session cannot be made due to invalid data * @throws RemoteSessionManagementException throws when session cannot be made due to invalid data
* @throws RemoteSessionManagementException throws when session has error with accessing device resources * @throws RemoteSessionManagementException throws when session has error with accessing device resources
*/ */
@Override @Override
public void sendMessageToPeer(Session session, String message) throws RemoteSessionManagementException, public void sendMessageToPeer(Session session, String message) throws RemoteSessionManagementException {
RemoteSessionInvalidException {
JSONObject jsonObject = new JSONObject(message); JSONObject jsonObject = new JSONObject(message);
RemoteSession remoteSession = RemoteSessionManagementDataHolder.getInstance().getSessionMap().get(session.getId()); RemoteSession remoteSession = RemoteSessionManagementDataHolder.getInstance().getSessionMap().get(session
.getId());
if (remoteSession != null) { if (remoteSession != null) {
if (remoteSession instanceof ClientSession) {
jsonObject.put("id", remoteSession.getOperationId());
}
remoteSession.sendMessageToPeer(jsonObject.toString()); remoteSession.sendMessageToPeer(jsonObject.toString());
} else { } else {
throw new RemoteSessionInvalidException("Remote Session cannot be found ", new CloseReason(CloseReason throw new RemoteSessionManagementException("Remote Session cannot be found ");
.CloseCodes.CANNOT_ACCEPT, "Invalid RemoteSession"));
} }
} }
@ -246,48 +252,68 @@ public class RemoteSessionManagementServiceImpl implements RemoteSessionManageme
* *
* @param session Web socket RemoteSession * @param session Web socket RemoteSession
* @param message Byte message needs to send to peer connection * @param message Byte message needs to send to peer connection
* @throws RemoteSessionInvalidException throws when session cannot be made due to invalid data * @throws RemoteSessionManagementException throws when session cannot be made due to invalid data
* @throws RemoteSessionManagementException throws when session has error with accessing device resources * @throws RemoteSessionManagementException throws when session has error with accessing device resources
*/ */
@Override @Override
public void sendMessageToPeer(Session session, byte[] message) throws RemoteSessionInvalidException, public void sendMessageToPeer(Session session, byte[] message) throws RemoteSessionManagementException {
RemoteSessionManagementException {
RemoteSession remoteSession = RemoteSessionManagementDataHolder.getInstance().getSessionMap().get(session.getId()); RemoteSession remoteSession = RemoteSessionManagementDataHolder.getInstance().getSessionMap().get(session
.getId());
if (remoteSession != null) { if (remoteSession != null) {
remoteSession.sendMessageToPeer(message); remoteSession.sendMessageToPeer(message);
} else { } else {
throw new RemoteSessionInvalidException("Remote Session cannot be found ", new CloseReason(CloseReason throw new RemoteSessionManagementException("Remote Session cannot be found ");
.CloseCodes.CANNOT_ACCEPT, "Invalid RemoteSession"));
} }
} }
/** /**
* Closing the session and cleanup the resources * Closing the session and cleanup the resources
* *
* @param session Web socket RemoteSession * @param session Web socket Remote Session
*/ */
@Override @Override
public void endSession(Session session) throws IOException { public void endSession(Session session, String closeReason) {
log.info("Closing session: "+session.getId()+" due to:"+ closeReason);
RemoteSession remoteSession = RemoteSessionManagementDataHolder.getInstance().getSessionMap().remove(session.getId()); RemoteSession remoteSession = RemoteSessionManagementDataHolder.getInstance().getSessionMap().remove(session
.getId());
if (remoteSession != null) { if (remoteSession != null) {
String operationId = remoteSession.getOperationId(); String operationId = remoteSession.getOperationId();
Session peerSession = remoteSession.getPeerSession().getMySession(); if (remoteSession.getPeerSession() != null) {
if (peerSession != null) { Session peerSession = remoteSession.getPeerSession().getMySession();
RemoteSessionManagementDataHolder.getInstance().getSessionMap().remove(peerSession.getId()); if (peerSession != null) {
if (peerSession.isOpen()) { RemoteSessionManagementDataHolder.getInstance().getSessionMap().remove(peerSession.getId());
peerSession.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, "Remote session closed")); if (peerSession.isOpen()) {
try {
peerSession.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, closeReason));
} catch (IOException ex) {
if (log.isDebugEnabled()) {
log.error("Failed to disconnect the client.", ex);
}
}
}
}
}
if (remoteSession.getMySession() != null) {
Session mySession = remoteSession.getMySession();
if (mySession.isOpen()) {
try {
mySession.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, closeReason));
} catch (IOException ex) {
if (log.isDebugEnabled()) {
log.error("Failed to disconnect the client.", ex);
}
}
} }
} }
if (operationId != null) { if (operationId != null) {
Session lastSession = RemoteSessionManagementDataHolder.getInstance().getDeviceRequestMap().get( String deviceIdentifier = remoteSession.getTenantDomain() + "/" + remoteSession
(remoteSession.getTenantDomain() + "/" + remoteSession.getDeviceType() + "/" + remoteSession .getDeviceType() + "/" + remoteSession.getDeviceId();
.getDeviceId())); RemoteSession lastSession = RemoteSessionManagementDataHolder.getInstance()
if (lastSession != null && lastSession.getId().equals(session.getId())) { .getActiveDeviceClientSessionMap().get(deviceIdentifier);
RemoteSessionManagementDataHolder.getInstance().getDeviceRequestMap().remove( if (lastSession != null && lastSession.getMySession().getId().equals(session.getId())) {
(remoteSession.getTenantDomain() + "/" + remoteSession.getDeviceType() + "/" + remoteSession RemoteSessionManagementDataHolder.getInstance().getActiveDeviceClientSessionMap().remove
.getDeviceId())); (deviceIdentifier);
} }
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* WSO2 Inc. licenses this file to you under the Apache License, * WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except * Version 2.0 (the "License"); you may not use this file except
@ -54,7 +54,6 @@ public class OAuthTokenValidatorStubFactory extends BasePoolableObjectFactory {
private HttpClient httpClient; private HttpClient httpClient;
Map<String, String> tokenValidationProperties; Map<String, String> tokenValidationProperties;
public OAuthTokenValidatorStubFactory(Map<String, String> globalProperties) { public OAuthTokenValidatorStubFactory(Map<String, String> globalProperties) {
this.tokenValidationProperties = globalProperties; this.tokenValidationProperties = globalProperties;
this.httpClient = createHttpClient(); this.httpClient = createHttpClient();

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* WSO2 Inc. licenses this file to you under the Apache License, * WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except * Version 2.0 (the "License"); you may not use this file except

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* WSO2 Inc. licenses this file to you under the Apache License, * WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except * Version 2.0 (the "License"); you may not use this file except
@ -19,7 +19,7 @@
package org.wso2.carbon.device.mgt.extensions.remote.session.constants; package org.wso2.carbon.device.mgt.extensions.remote.session.constants;
/** /**
* This holds the constants related to this feature * This holds the constants related to remote session
*/ */
public class RemoteSessionConstants { public class RemoteSessionConstants {
@ -28,14 +28,18 @@ public class RemoteSessionConstants {
public static final String TOKEN_VALIDATION_CONTEX = "/services/OAuth2TokenValidationService"; public static final String TOKEN_VALIDATION_CONTEX = "/services/OAuth2TokenValidationService";
public static final String USERNAME = "username"; public static final String USERNAME = "username";
public static final String PASSWORD = "password"; public static final String PASSWORD = "password";
public static final String REMOTE_CONNECT = "REMOTE_CONNECT"; public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
public static final String THROTTLE_OUT = "THROTTLE_OUT"; public static final int MAX_BUFFER_SIZE = 640 * 1024;
public static final String QUERY_STRING = "queryString"; public static final String QUERY_STRING = "queryString";
public static final String MAXIMUM_TOTAL_HTTP_CONNECTION = "maximumTotalHttpConnection"; public static final String MAXIMUM_TOTAL_HTTP_CONNECTION = "maximumTotalHttpConnection";
public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST = "maximumHttpConnectionPerHost"; public static final String MAXIMUM_HTTP_CONNECTION_PER_HOST = "maximumHttpConnectionPerHost";
public static final String DEFAULT_MAXIMUM_HTTP_CONNECTION_PER_HOST = "2"; public static final String DEFAULT_MAXIMUM_HTTP_CONNECTION_PER_HOST = "2";
public static final String DEFAULT_MAXIMUM_TOTAL_HTTP_CONNECTIONS = "100"; public static final String DEFAULT_MAXIMUM_TOTAL_HTTP_CONNECTIONS = "100";
// Initial remote connection operation related Constants
public static final String REMOTE_CONNECT = "REMOTE_CONNECT";
public static final String REMOTE_CONNECT_CODE = "code";
private RemoteSessionConstants() { private RemoteSessionConstants() {
} }

@ -15,41 +15,44 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.wso2.carbon.device.mgt.extensions.remote.session.dto.common; package org.wso2.carbon.device.mgt.extensions.remote.session.dto;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionInvalidException;
import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException; import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSessionManagementException;
import org.wso2.carbon.device.mgt.extensions.remote.session.internal.RemoteSessionManagementDataHolder;
import javax.websocket.CloseReason;
import javax.websocket.Session; import javax.websocket.Session;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
* {@link RemoteSession} will represent remote websocket session * {@link RemoteSession} will represent remote websocket session
* This class implements the behaviours of sending message to the session in multithreaded environment. * This class implements the behaviours of sending message to the session in multithreaded context.
*/ */
public class RemoteSession { public class RemoteSession {
private static final Log log = LogFactory.getLog(RemoteSession.class); private static final Log log = LogFactory.getLog(RemoteSession.class);
private String tenantDomain, operationId, deviceType, deviceId; private String tenantDomain, operationId, deviceType, deviceId;
private long lastMessageTimeStamp = System.currentTimeMillis(); private long lastMessageTimeStamp = System.currentTimeMillis();
;
private RemoteSession peerSession; private RemoteSession peerSession;
private Session mySession; private Session mySession;
private final Object writeLockObject = new Object(); private final Object writeLockObject = new Object();
private int maxMessagesPerSecond;
private int messageAllowance;
private double messageRatePerSecond;
protected RemoteSession(Session session, String tenantDomain, String deviceType, String deviceId) { public RemoteSession(Session session, String tenantDomain, String deviceType, String deviceId) {
this.mySession = session; this.mySession = session;
this.deviceType = deviceType; this.deviceType = deviceType;
this.deviceId = deviceId; this.deviceId = deviceId;
this.tenantDomain = tenantDomain; this.tenantDomain = tenantDomain;
maxMessagesPerSecond = RemoteSessionManagementDataHolder.getInstance().getMaxMessagesPerSecond();
messageAllowance = maxMessagesPerSecond;
messageRatePerSecond = (double) maxMessagesPerSecond / 1000;
} }
private void sendMessage(Object message) throws RemoteSessionInvalidException, RemoteSessionManagementException { private void sendMessage(Object message) throws RemoteSessionManagementException {
if (message != null) { if (message != null) {
boolean isMessageCountExceed = false; boolean isMessageCountExceed = false;
if (mySession != null && mySession.isOpen()) { if (mySession != null && mySession.isOpen()) {
@ -71,38 +74,41 @@ public class RemoteSession {
} }
} }
} else { } else {
throw new RemoteSessionInvalidException("Peer Session already closed ", new CloseReason throw new RemoteSessionManagementException("Peer Session already closed ");
(CloseReason.CloseCodes.CANNOT_ACCEPT, "Peer Session already closed "));
} }
} else { } else {
throw new RemoteSessionManagementException("Message is empty"); throw new RemoteSessionManagementException("Message is empty");
} }
} }
public void sendMessageToPeer(Object message) throws RemoteSessionInvalidException, public void sendMessageToPeer(Object message) throws RemoteSessionManagementException {
RemoteSessionManagementException {
peerSession.sendMessage(message); peerSession.sendMessage(message);
} }
/** /**
* Use for limit the messages for given time * Use for limit the messages for given time
* *
* @return message rate applied * @return message rate applied
*/ */
public boolean applyRateLimit(){ private boolean applyRateLimit() {
return false; long currentTime = System.currentTimeMillis();
messageAllowance += (currentTime - lastMessageTimeStamp) * messageRatePerSecond;
if (messageAllowance > maxMessagesPerSecond) {
messageAllowance = maxMessagesPerSecond;
}
if (messageAllowance >= 1) {
lastMessageTimeStamp = currentTime;
messageAllowance -= 1;
return false;
} else {
return true;
}
} }
public Session getMySession() { public Session getMySession() {
return mySession; return mySession;
} }
public void setMySession(Session mySession) {
this.mySession = mySession;
}
public RemoteSession getPeerSession() { public RemoteSession getPeerSession() {
return peerSession; return peerSession;
} }
@ -115,10 +121,6 @@ public class RemoteSession {
return tenantDomain; return tenantDomain;
} }
public void setTenantDomain(String tenantDomain) {
this.tenantDomain = tenantDomain;
}
public String getOperationId() { public String getOperationId() {
return operationId; return operationId;
} }
@ -131,23 +133,7 @@ public class RemoteSession {
return deviceType; return deviceType;
} }
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public long getLastMessageTimeStamp() {
return lastMessageTimeStamp;
}
public void setLastMessageTimeStamp(long lastMessageTimeStamp) {
this.lastMessageTimeStamp = lastMessageTimeStamp;
}
} }

@ -18,28 +18,23 @@
package org.wso2.carbon.device.mgt.extensions.remote.session.exception; package org.wso2.carbon.device.mgt.extensions.remote.session.exception;
import javax.websocket.CloseReason;
/** /**
* This Exception will be thrown, when there any interference with Remote RemoteSession. * This Exception will be thrown, when there any management issues with Remote Session.
*/ */
public class RemoteSessionManagementException extends Exception { public class RemoteSessionManagementException extends Exception {
public RemoteSessionManagementException(String msg, Exception nestedEx) { CloseReason closeReason;
super(msg, nestedEx);
}
public RemoteSessionManagementException(String message, Throwable cause) {
super(message, cause);
}
public RemoteSessionManagementException(String msg) { public RemoteSessionManagementException(String msg) {
super(msg); super(msg);
this.closeReason = new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, msg);
} }
public RemoteSessionManagementException() { public CloseReason getCloseReason() {
super(); return closeReason;
} }
public RemoteSessionManagementException(Throwable cause) {
super(cause);
}
} }

@ -21,12 +21,15 @@ package org.wso2.carbon.device.mgt.extensions.remote.session.internal;
import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService; import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService;
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
import org.wso2.carbon.device.mgt.extensions.remote.session.authentication.OAuthAuthenticator; import org.wso2.carbon.device.mgt.extensions.remote.session.authentication.OAuthAuthenticator;
import org.wso2.carbon.device.mgt.extensions.remote.session.dto.common.RemoteSession; import org.wso2.carbon.device.mgt.extensions.remote.session.dto.RemoteSession;
import javax.websocket.Session;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/**
* Class {@link RemoteSessionManagementDataHolder} will hold the configurations and in memory storage strictures to
* manage remote sessions.
*/
public class RemoteSessionManagementDataHolder { public class RemoteSessionManagementDataHolder {
private static RemoteSessionManagementDataHolder thisInstance = new RemoteSessionManagementDataHolder(); private static RemoteSessionManagementDataHolder thisInstance = new RemoteSessionManagementDataHolder();
@ -35,9 +38,9 @@ public class RemoteSessionManagementDataHolder {
private boolean isEnabled; private boolean isEnabled;
private String serverUrl; private String serverUrl;
private long maxIdleTimeout; private long maxIdleTimeout;
private int messagesPerSession; private int maxMessagesPerSecond;
private OAuthAuthenticator oAuthAuthenticator; private OAuthAuthenticator oAuthAuthenticator;
private Map<String, Session> deviceRequestMap = new ConcurrentHashMap<String, Session>(); private Map<String, RemoteSession> activeDeviceClientSessionMap = new ConcurrentHashMap<String, RemoteSession>();
private Map<String, RemoteSession> sessionMap = new ConcurrentHashMap<String, RemoteSession>(); private Map<String, RemoteSession> sessionMap = new ConcurrentHashMap<String, RemoteSession>();
public static RemoteSessionManagementDataHolder getInstance() { public static RemoteSessionManagementDataHolder getInstance() {
@ -72,16 +75,8 @@ public class RemoteSessionManagementDataHolder {
return sessionMap; return sessionMap;
} }
public void setSessionMap(Map<String, RemoteSession> sessionMap) { public Map<String, RemoteSession> getActiveDeviceClientSessionMap() {
this.sessionMap = sessionMap; return activeDeviceClientSessionMap;
}
public Map<String, Session> getDeviceRequestMap() {
return deviceRequestMap;
}
public void setDeviceRequestMap(Map<String, Session> deviceRequestMap) {
this.deviceRequestMap = deviceRequestMap;
} }
public boolean isEnabled() { public boolean isEnabled() {
@ -100,12 +95,12 @@ public class RemoteSessionManagementDataHolder {
this.serverUrl = serverUrl; this.serverUrl = serverUrl;
} }
public int getMessagesPerSession() { public int getMaxMessagesPerSecond() {
return messagesPerSession; return maxMessagesPerSecond;
} }
public void setMessagesPerSession(int messagesPerSession) { public void setMaxMessagesPerSecond(int maxMessagesPerSecond) {
this.messagesPerSession = messagesPerSession; this.maxMessagesPerSecond = maxMessagesPerSecond;
} }
public long getMaxIdleTimeout() { public long getMaxIdleTimeout() {

@ -54,10 +54,10 @@ public class RemoteSessionManagementServiceComponent {
try { try {
BundleContext bundleContext = componentContext.getBundleContext(); BundleContext bundleContext = componentContext.getBundleContext();
bundleContext.registerService(ServerStartupObserver.class.getName(), new RemoteSessionManagerStartupListener(), bundleContext.registerService(ServerStartupObserver.class.getName(), new
null); RemoteSessionManagerStartupListener(), null);
bundleContext.registerService(RemoteSessionManagementService.class.getName(), new RemoteSessionManagementServiceImpl(), bundleContext.registerService(RemoteSessionManagementService.class.getName(), new
null); RemoteSessionManagementServiceImpl(), null);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Remote Session device access service implementation bundle has been successfully " + log.debug("Remote Session device access service implementation bundle has been successfully " +
"initialized"); "initialized");
@ -73,18 +73,23 @@ public class RemoteSessionManagementServiceComponent {
} }
protected void setDeviceManagementProviderService(DeviceManagementProviderService deviceManagementProviderService) { protected void setDeviceManagementProviderService(DeviceManagementProviderService deviceManagementProviderService) {
RemoteSessionManagementDataHolder.getInstance().setDeviceManagementProviderService(deviceManagementProviderService); RemoteSessionManagementDataHolder.getInstance()
.setDeviceManagementProviderService(deviceManagementProviderService);
} }
protected void unsetDeviceManagementProviderService(DeviceManagementProviderService deviceManagementProviderService) { protected void unsetDeviceManagementProviderService(DeviceManagementProviderService
deviceManagementProviderService) {
RemoteSessionManagementDataHolder.getInstance().setDeviceManagementProviderService(null); RemoteSessionManagementDataHolder.getInstance().setDeviceManagementProviderService(null);
} }
protected void setDeviceAccessAuthorizationService(DeviceAccessAuthorizationService deviceAccessAuthorizationService) { protected void setDeviceAccessAuthorizationService(DeviceAccessAuthorizationService
RemoteSessionManagementDataHolder.getInstance().setDeviceAccessAuthorizationService(deviceAccessAuthorizationService); deviceAccessAuthorizationService) {
RemoteSessionManagementDataHolder.getInstance()
.setDeviceAccessAuthorizationService(deviceAccessAuthorizationService);
} }
protected void unsetDeviceAccessAuthorizationService(DeviceAccessAuthorizationService deviceAccessAuthorizationService) { protected void unsetDeviceAccessAuthorizationService(DeviceAccessAuthorizationService
deviceAccessAuthorizationService) {
RemoteSessionManagementDataHolder.getInstance().setDeviceManagementProviderService(null); RemoteSessionManagementDataHolder.getInstance().setDeviceManagementProviderService(null);
} }

@ -62,10 +62,14 @@ public class RemoteSessionManagerStartupListener implements ServerStartupObserve
Map<String, String> configProperties = new HashMap<>(); Map<String, String> configProperties = new HashMap<>();
// Set max idle timeout in milliseconds // Set max idle timeout in milliseconds
RemoteSessionManagementDataHolder.getInstance().setMaxIdleTimeout(rsConfig.getSessionIdleTimeOut()*60000); RemoteSessionManagementDataHolder.getInstance().setMaxIdleTimeout((long) rsConfig.getSessionIdleTimeOut() *
60000);
// Set max messages per second. // Set max messages per second.
RemoteSessionManagementDataHolder.getInstance().setMessagesPerSession(rsConfig.getMaxMessagesPerSession()); if (rsConfig.getMaxMessagesPerSession() > 0) {
RemoteSessionManagementDataHolder.getInstance().setMaxMessagesPerSecond(rsConfig
.getMaxMessagesPerSession());
}
// Token validation related configuration // Token validation related configuration
configProperties.put(RemoteSessionConstants.TOKEN_VALIDATION_ENDPOINT_URL, kmConfig.getServerUrl()); configProperties.put(RemoteSessionConstants.TOKEN_VALIDATION_ENDPOINT_URL, kmConfig.getServerUrl());
configProperties.put(RemoteSessionConstants.USERNAME, kmConfig.getAdminUsername()); configProperties.put(RemoteSessionConstants.USERNAME, kmConfig.getAdminUsername());

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
* *
* WSO2 Inc. licenses this file to you under the Apache License, * WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except * Version 2.0 (the "License"); you may not use this file except
@ -23,9 +23,17 @@ import org.wso2.carbon.device.mgt.extensions.remote.session.exception.RemoteSess
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/**
* Class for reading web socket url parameters
*/
public class PropertyUtils { public class PropertyUtils {
//This method is only used if the mb features are within DAS. /**
* Replace URL with placeholders with properties
* @param urlWithPlaceholders URL
* @return replaced url
* @throws RemoteSessionManagementException
*/
public static String replaceProperty(String urlWithPlaceholders) throws RemoteSessionManagementException { public static String replaceProperty(String urlWithPlaceholders) throws RemoteSessionManagementException {
String regex = "\\$\\{(.*?)\\}"; String regex = "\\$\\{(.*?)\\}";
Pattern pattern = Pattern.compile(regex); Pattern pattern = Pattern.compile(regex);

@ -22,7 +22,7 @@
<parent> <parent>
<groupId>org.wso2.carbon.devicemgt-plugins</groupId> <groupId>org.wso2.carbon.devicemgt-plugins</groupId>
<artifactId>extensions</artifactId> <artifactId>extensions</artifactId>
<version>4.0.54-SNAPSHOT</version> <version>4.0.66-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

Loading…
Cancel
Save