Java 某些服务器生成的事件无法通过WebSocket在生产中传递到客户端
底线: 某些服务器生成的事件不会通过WebSocket在生产中传递到客户端。但是,websocket连接建立得很好 案例研究: 我打开谷歌浏览器并连接到我们的服务器。打开devtools。在WS选项卡下,我看到连接建立得很好,但当服务器需要更新页面上的某些内容时,我没有收到任何帧。我等待了一段时间,有时(只是有时)我会收到一些延迟很大的事件。然而,这在当地起到了预期的作用 问题: 是否有人见过类似的websocket行为,并对如何消除本次调查中的变量提出了建议 基础设施: 服务器:LinuxTomcat 两台服务器处理: 1.来自设备的流量(通过TCP/IP与服务器通信) 2.来自用户的流量 用户和设备是多对多关系。如果用户连接到未连接设备的服务器。此服务器查看其他服务器并处理信息交换 服务器前面有一个防火墙 代码: WebSocketServerEndpoint.javaJava 某些服务器生成的事件无法通过WebSocket在生产中传递到客户端,java,amazon-web-services,java-websocket,maven-tomcat-plugin,Java,Amazon Web Services,Java Websocket,Maven Tomcat Plugin,底线: 某些服务器生成的事件不会通过WebSocket在生产中传递到客户端。但是,websocket连接建立得很好 案例研究: 我打开谷歌浏览器并连接到我们的服务器。打开devtools。在WS选项卡下,我看到连接建立得很好,但当服务器需要更新页面上的某些内容时,我没有收到任何帧。我等待了一段时间,有时(只是有时)我会收到一些延迟很大的事件。然而,这在当地起到了预期的作用 问题: 是否有人见过类似的websocket行为,并对如何消除本次调查中的变量提出了建议 基础设施: 服务器:LinuxTo
@ServerEndpoint("/actions")
public class WebSocketServerEndpoint {
static private final org.slf4j.Logger logger = LoggerFactory.getLogger(WebSocketServerEndpoint.class);
@OnOpen
public void open(Session session) {
WebSocketSessionHandler.addSession(session);
}
@OnClose
public void close(Session session) {
WebSocketSessionHandler.removeSession(session);
}
@OnError
public void onError(Throwable error) {
//Logger.getLogger(WebSocketServerEndpoint.class.getName()).log(Level.SEVERE, null, error);
}
@OnMessage
public void handleMessage(String message, Session session) {
try (JsonReader reader = Json.createReader(new StringReader(message))) {
JsonObject jsonMessage = reader.readObject();
Long userId = null;
Long tenantId = null;
switch (WebSocketActions.valueOf(jsonMessage.getString("action"))){
case SaveUserId:
userId = getUserId(jsonMessage);
tenantId = getTenantId(jsonMessage);
Long userIdKey = WebSocketSessionHandler.saveUserId(userId, session);
Long tenantUserKey = WebSocketSessionHandler.saveTenantUser(tenantId, userId);
WebSocketSessionHandler.updateUserSessionKeys(session, tenantUserKey, userIdKey); // Needed for Making Weak Maps Keep Their Keys if Session is Currently Active
}
} catch (Exception e) {
logger.error(e.toString());
}
}
private Long getUserId(JsonObject jsonMessage) {
Long userId = null;
try {
userId = Long.parseLong(((Integer) jsonMessage.getInt("userId")).toString());
return userId;
} catch (Exception e) {
logger.error(e.getMessage());
return userId;
}
}
private Long getTenantId(JsonObject jsonMessage) {
Long tenantId = null;
try {
tenantId = Long.parseLong(((Integer) jsonMessage.getInt("tenantId")).toString());
return tenantId;
} catch (Exception e) {
logger.error(e.getMessage());
return tenantId;
}
}
}
@Singleton
public class WebSocketService {
private static final Logger logger = LoggerFactory.getLogger(WebSocketService.class);
public enum WebSocketEvents{
OnConnection,
OnActivity,
OnAccesspointStatus,
OnClosedStatus,
OnConnectedStatus,
OnAlert,
OnSessionExpired
}
public enum WebSocketActions{
SaveUserId
}
@WebPost("/lookupWebSocketSessions")
public WebResponse lookupWebSocketSessions(@JsonArrayParam("userIds") List<Integer> userIds, @WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketSessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
@WebPost("/lookupWebSocketHistorySessions")
public WebResponse lookupWebSocketHistorySessions(@JsonArrayParam("userIds") List<Integer> userIds, @WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketHistorySessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
// Kick Out a User if Their Session is no Longer Valid
public void sendLogout(User user) {
try {
Long userId = user.getId();
List<Long> userIds = new ArrayList<>();
userIds.add(userId);
JSONObject result = new JSONObject();
result.put("userId", userId);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnSessionExpired, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
logger.error("Couldn't Logout User");
}
}
// Send History after Processing Data
// Returns "0" if success, "-1" otherwise
public int sendHistory(Activity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersSubscribedToActivity(activity.getTenantId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
//logger.error("Couldn't Send History");
return -1;
}
}
// SendAlertUpdate after Processing Data
public void sendAlertUpdate(Alert alert) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(alert.getAccesspointId());
JSONObject result = JSONObject.fromObject(alert);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnAlert, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Aleart");
}
}
// Send Connected Status after Processing Data
public void sendConnectedStatus(Long accesspointId, Boolean isConnected) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointId);
JSONObject result = new JSONObject();
result.put("accesspointId", accesspointId);
result.put("isConnected", isConnected);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnConnectedStatus, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Connected Status");
}
}
public int sendHistory(CredentialActivity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersUnderTenantByAccesspointId(activity.getAccesspointId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
return -1;
}
}
public Boolean isUserSessionAvailable(Long id) {
return WebSocketSessionHandler.isUserSessionAvailable(id);
}
public void lookOnOtherServers(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLs();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public void lookOnOtherServersHistory(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLsHistory();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public int sendClosedStatus(AccesspointStatus accesspointStatus){
try {
JSONObject accesspointStatusJSON = new JSONObject();
accesspointStatusJSON.put("accesspointId", accesspointStatus.getAccesspointId());
accesspointStatusJSON.put("openStatus", accesspointStatus.getOpenStatus());
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointStatus.getAccesspointId());
lookOnOtherServers(userIds, accesspointStatusJSON);
return 0;
} catch (Exception e) {
return -1;
}
}
public List<Long> getUsersSubscribedToActivity(Long tenantId) {
List<Long> userList = WebSocketSessionHandler.getUsersForTenant(tenantId);
return userList;
}
private List<Long> getUsersUnderTenantByAccesspointId(Long accesspointId) {
List<Long> userList = new ArrayList<>();
User user = userDao.getBackgroundUserByAccesspoint(accesspointId);
List<Record> recordList = tenantDao.getTenantsByUser(user, user.getId());
for (Record record : recordList) {
Long tenantId = (Long) record.get("id");
userList.addAll(getUsersSubscribedToActivity(tenantId));
}
return userList;
}
public void postJSONDataToUrl(String url, List<Long> userId, JSON data) throws AppException {
List<NameValuePair> parameters;
HttpResponse httpResponse;
HttpClientService.SimpleHttpClient simpleHttpClient = httpClientService.createHttpClient(url);
try {
parameters = httpClientService.convertJSONObjectToNameValuePair(userId, data);
} catch (Exception e) {
throw new AppException("Couldn't Convert Input Parameters");
}
try {
httpResponse = simpleHttpClient.sendHTTPPost(parameters);
} catch (Exception e) {
throw new AppException("Couldn't Get Data from the Server");
}
if (httpResponse == null) {
throw new AppException("Couldn't Send to Another Server");
} else {
//logger.error(httpResponse.getStatusLine().toString());
}
}
}
public class WebSocketSessionHandler {
// Apparently required to instantiate the dialogue,
// ideally it would be better to just create session map where sessions are mapped to userId,
// however, userId will be send only after the session is created.
// TODO: Investigate Instantiation of WebSocket Session Further
// WeakHashMap is Used for Automatic Memory Management (So That Removal of Keys That are no Longer Used Can be Automatically Performed)
// NOTE: However, it Requires Certain Precautions to Make Sure Their Keys Don't Expire Unexpectedly, Look for the Commented Code Below
private static final Map<Long, Set<Session>> sessionMap = new WeakHashMap<>();
private static final Map<Long, Set<Long>> tenantUserMap = new WeakHashMap<>();
public WebSocketSessionHandler() {}
public static List<Long> getUsersForTenant(Long tenantId) {
List<Long> userIds = new ArrayList<>();
Set<Long> userIdsSet = tenantUserMap.get(tenantId);
if (userIdsSet != null) {
for (Long userId : userIdsSet){
userIds.add(userId);
}
}
return userIds;
}
public static Boolean isUserSessionAvailable(Long id){
Set<Session> userSessions = sessionMap.get(id);
if (userSessions == null || userSessions.size() == 0) {
return false;
} else {
return true;
}
}
// addSession() should add "session" to "sessions" set
// returns: "0" if success and "-1" otherwise
public static int addSession(Session session) {
int output;
try {
final long ONE_DAY = 86400000;
session.setMaxIdleTimeout(ONE_DAY);
sessions.put(session, new ArrayList<>());
return sendToSession(session, createMessage(WebSocketEvents.OnConnection, "Successfully Connected"));
} catch (Exception e) {
logger.error("Couldn't Add Session");
return -1;
}
}
// removeSession() should remove "session" from "sessions" set
// Scenarios:
// sessions is null?
// returns: "0" if success and "-1" otherwise
public static int removeSession( Session session) {
try {
closeSessionProperly(session);
if (sessions.remove(session) != null) {
return 0;
} else {
return -1;
}
} catch (Exception e) {
logger.error("Couldn't Remove Session");
return -1;
}
}
private static void closeSessionProperly(Session session) {
try {
session.close();
} catch (IOException ex) {
}
}
public static Long getKeyFromMap(Map map, Long key){ // Needed for Weak Maps
Set<Long> keySet = map.keySet();
for (Long keyReference : keySet) {
if (keyReference == key) {
return keyReference;
}
}
return key; // If Not Found Return the Value Passed in
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveUserId(Long userId, Session session){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
userId = getKeyFromMap(sessionMap, userId); // Required for Weak Maps to Work Correctly
Set<Session> sessionsForUser = sessionMap.get(userId);
if (sessionsForUser == null) {
sessionsForUser = new HashSet<>();
}
sessionsForUser.add(session);
sessionMap.put(userId, sessionsForUser);
return userId;
} catch (Exception e) {
logger.error("Couldn't Save User Id");
return null;
}
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveTenantUser(Long tenantId, Long userId){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
tenantId = getKeyFromMap(tenantUserMap, tenantId); // Required for Weak Maps to Work Correctly
Set<Long> users = tenantUserMap.get(tenantId);
if (users == null) {
users = new HashSet<>();
}
users.add(userId);
tenantUserMap.put(tenantId, users);
return tenantId;
} catch (Exception e) {
logger.error("Couldn't Save Tenant User");
return null;
}
}
public static void updateUserSessionKeys(Session session, Long tenantId, Long userId) {
try {
List<Long> userSessionKeys = sessions.get(session);
userSessionKeys.add(0, tenantId);
userSessionKeys.add(1, userId);
} catch (Exception e) {
logger.error("Couldn't Update User Session Keys");
}
}
// removeUserId() should remove an { userId -> session } entry in sessionMap
// returns: "0" if success and "-1" otherwise
public static int removeUserId( Long userId) {
try {
sessionMap.remove(userId);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendAccesspointStatus() should compose JSON message and pass it to sendToUser()
// returns: "0" if success and "-1" otherwise
public static int sendClosedStatus(Long userId, JSONObject accesspointStatus) {
try {
JSONObject accesspointStatusEventMessage = (JSONObject) createMessage(WebSocketEvents.OnClosedStatus, accesspointStatus);
sendToUser(userId, accesspointStatusEventMessage);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendToUser() sends message to session that is mapped to userId
// returns: "0" if success and "-1" otherwise
public static int sendToUser( Long userId, JSON message) {
if (sessionMap.containsKey(userId)) {
Set<Session> sessionsForUser = sessionMap.get(userId);
for (Session session : sessionsForUser) {
if (!session.isOpen()) {
sessions.remove(session);
continue;
}
sendToSession(session, message);
}
return 0;
} else {
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, JSON message){
try {
try {
Long tenantId = sessions.get(session).get(0);
((JSONObject) message).put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(message.toString());
return 0;
} catch (IOException e) {
try {
session.close();
} catch (IOException ex) {
}
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, String message){
try {
JSONObject newMessage = JSONObject.fromObject(message);
try {
Long tenantId = sessions.get(session).get(0);
newMessage.put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(newMessage.toString());
return 0;
} catch (IOException e) {
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
}
WebSocketService.java
@ServerEndpoint("/actions")
public class WebSocketServerEndpoint {
static private final org.slf4j.Logger logger = LoggerFactory.getLogger(WebSocketServerEndpoint.class);
@OnOpen
public void open(Session session) {
WebSocketSessionHandler.addSession(session);
}
@OnClose
public void close(Session session) {
WebSocketSessionHandler.removeSession(session);
}
@OnError
public void onError(Throwable error) {
//Logger.getLogger(WebSocketServerEndpoint.class.getName()).log(Level.SEVERE, null, error);
}
@OnMessage
public void handleMessage(String message, Session session) {
try (JsonReader reader = Json.createReader(new StringReader(message))) {
JsonObject jsonMessage = reader.readObject();
Long userId = null;
Long tenantId = null;
switch (WebSocketActions.valueOf(jsonMessage.getString("action"))){
case SaveUserId:
userId = getUserId(jsonMessage);
tenantId = getTenantId(jsonMessage);
Long userIdKey = WebSocketSessionHandler.saveUserId(userId, session);
Long tenantUserKey = WebSocketSessionHandler.saveTenantUser(tenantId, userId);
WebSocketSessionHandler.updateUserSessionKeys(session, tenantUserKey, userIdKey); // Needed for Making Weak Maps Keep Their Keys if Session is Currently Active
}
} catch (Exception e) {
logger.error(e.toString());
}
}
private Long getUserId(JsonObject jsonMessage) {
Long userId = null;
try {
userId = Long.parseLong(((Integer) jsonMessage.getInt("userId")).toString());
return userId;
} catch (Exception e) {
logger.error(e.getMessage());
return userId;
}
}
private Long getTenantId(JsonObject jsonMessage) {
Long tenantId = null;
try {
tenantId = Long.parseLong(((Integer) jsonMessage.getInt("tenantId")).toString());
return tenantId;
} catch (Exception e) {
logger.error(e.getMessage());
return tenantId;
}
}
}
@Singleton
public class WebSocketService {
private static final Logger logger = LoggerFactory.getLogger(WebSocketService.class);
public enum WebSocketEvents{
OnConnection,
OnActivity,
OnAccesspointStatus,
OnClosedStatus,
OnConnectedStatus,
OnAlert,
OnSessionExpired
}
public enum WebSocketActions{
SaveUserId
}
@WebPost("/lookupWebSocketSessions")
public WebResponse lookupWebSocketSessions(@JsonArrayParam("userIds") List<Integer> userIds, @WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketSessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
@WebPost("/lookupWebSocketHistorySessions")
public WebResponse lookupWebSocketHistorySessions(@JsonArrayParam("userIds") List<Integer> userIds, @WebParam("message") String message){
try {
for (Integer userIdInt : userIds) {
Long userId = Long.parseLong(userIdInt.toString());
if (WebSocketHistorySessionHandler.sendToUser(userId, message) == 0) {
} else {
//logger.debug("Couldn't Send to User");
}
}
} catch (ClassCastException e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
} catch (Exception e) {
//logger.error(e.getMessage());
return webResponseBuilder.fail(e);
}
return webResponseBuilder.success(message);
}
// Kick Out a User if Their Session is no Longer Valid
public void sendLogout(User user) {
try {
Long userId = user.getId();
List<Long> userIds = new ArrayList<>();
userIds.add(userId);
JSONObject result = new JSONObject();
result.put("userId", userId);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnSessionExpired, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
logger.error("Couldn't Logout User");
}
}
// Send History after Processing Data
// Returns "0" if success, "-1" otherwise
public int sendHistory(Activity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersSubscribedToActivity(activity.getTenantId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
//logger.error("Couldn't Send History");
return -1;
}
}
// SendAlertUpdate after Processing Data
public void sendAlertUpdate(Alert alert) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(alert.getAccesspointId());
JSONObject result = JSONObject.fromObject(alert);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnAlert, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Aleart");
}
}
// Send Connected Status after Processing Data
public void sendConnectedStatus(Long accesspointId, Boolean isConnected) {
try {
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointId);
JSONObject result = new JSONObject();
result.put("accesspointId", accesspointId);
result.put("isConnected", isConnected);
JSON message = WebSocketSessionHandler.createMessage(WebSocketEvents.OnConnectedStatus, result);
lookOnOtherServers(userIds, message);
} catch (Exception e) {
//logger.error("Couldn't Send Connected Status");
}
}
public int sendHistory(CredentialActivity activity) {
try {
TimezoneService.TimeZoneConfig timeZoneConfig = timezoneService.getTimezoneConfigsByAp(null, activity.getAccesspointId());
JSONObject result = (JSONObject) JSONSerializer.toJSON(activity);
String timezoneId = timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
result.put("timezoneString", timezoneId);
result.put(
"profileId",
userDao.getUserProfileId(activity.getUserId())
);
JSON message = WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity, result);
List<Long> userIds = getUsersUnderTenantByAccesspointId(activity.getAccesspointId());
lookOnOtherServersHistory(userIds, message);
return 0;
} catch (Exception e) {
return -1;
}
}
public Boolean isUserSessionAvailable(Long id) {
return WebSocketSessionHandler.isUserSessionAvailable(id);
}
public void lookOnOtherServers(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLs();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public void lookOnOtherServersHistory(List<Long> userId, JSON data){
List<String> urls = awsService.getServerURLsHistory();
for (String url : urls) {
postJSONDataToUrl(url, userId, data);
}
}
public int sendClosedStatus(AccesspointStatus accesspointStatus){
try {
JSONObject accesspointStatusJSON = new JSONObject();
accesspointStatusJSON.put("accesspointId", accesspointStatus.getAccesspointId());
accesspointStatusJSON.put("openStatus", accesspointStatus.getOpenStatus());
List<Long> userIds = getUsersUnderTenantByAccesspointId(accesspointStatus.getAccesspointId());
lookOnOtherServers(userIds, accesspointStatusJSON);
return 0;
} catch (Exception e) {
return -1;
}
}
public List<Long> getUsersSubscribedToActivity(Long tenantId) {
List<Long> userList = WebSocketSessionHandler.getUsersForTenant(tenantId);
return userList;
}
private List<Long> getUsersUnderTenantByAccesspointId(Long accesspointId) {
List<Long> userList = new ArrayList<>();
User user = userDao.getBackgroundUserByAccesspoint(accesspointId);
List<Record> recordList = tenantDao.getTenantsByUser(user, user.getId());
for (Record record : recordList) {
Long tenantId = (Long) record.get("id");
userList.addAll(getUsersSubscribedToActivity(tenantId));
}
return userList;
}
public void postJSONDataToUrl(String url, List<Long> userId, JSON data) throws AppException {
List<NameValuePair> parameters;
HttpResponse httpResponse;
HttpClientService.SimpleHttpClient simpleHttpClient = httpClientService.createHttpClient(url);
try {
parameters = httpClientService.convertJSONObjectToNameValuePair(userId, data);
} catch (Exception e) {
throw new AppException("Couldn't Convert Input Parameters");
}
try {
httpResponse = simpleHttpClient.sendHTTPPost(parameters);
} catch (Exception e) {
throw new AppException("Couldn't Get Data from the Server");
}
if (httpResponse == null) {
throw new AppException("Couldn't Send to Another Server");
} else {
//logger.error(httpResponse.getStatusLine().toString());
}
}
}
public class WebSocketSessionHandler {
// Apparently required to instantiate the dialogue,
// ideally it would be better to just create session map where sessions are mapped to userId,
// however, userId will be send only after the session is created.
// TODO: Investigate Instantiation of WebSocket Session Further
// WeakHashMap is Used for Automatic Memory Management (So That Removal of Keys That are no Longer Used Can be Automatically Performed)
// NOTE: However, it Requires Certain Precautions to Make Sure Their Keys Don't Expire Unexpectedly, Look for the Commented Code Below
private static final Map<Long, Set<Session>> sessionMap = new WeakHashMap<>();
private static final Map<Long, Set<Long>> tenantUserMap = new WeakHashMap<>();
public WebSocketSessionHandler() {}
public static List<Long> getUsersForTenant(Long tenantId) {
List<Long> userIds = new ArrayList<>();
Set<Long> userIdsSet = tenantUserMap.get(tenantId);
if (userIdsSet != null) {
for (Long userId : userIdsSet){
userIds.add(userId);
}
}
return userIds;
}
public static Boolean isUserSessionAvailable(Long id){
Set<Session> userSessions = sessionMap.get(id);
if (userSessions == null || userSessions.size() == 0) {
return false;
} else {
return true;
}
}
// addSession() should add "session" to "sessions" set
// returns: "0" if success and "-1" otherwise
public static int addSession(Session session) {
int output;
try {
final long ONE_DAY = 86400000;
session.setMaxIdleTimeout(ONE_DAY);
sessions.put(session, new ArrayList<>());
return sendToSession(session, createMessage(WebSocketEvents.OnConnection, "Successfully Connected"));
} catch (Exception e) {
logger.error("Couldn't Add Session");
return -1;
}
}
// removeSession() should remove "session" from "sessions" set
// Scenarios:
// sessions is null?
// returns: "0" if success and "-1" otherwise
public static int removeSession( Session session) {
try {
closeSessionProperly(session);
if (sessions.remove(session) != null) {
return 0;
} else {
return -1;
}
} catch (Exception e) {
logger.error("Couldn't Remove Session");
return -1;
}
}
private static void closeSessionProperly(Session session) {
try {
session.close();
} catch (IOException ex) {
}
}
public static Long getKeyFromMap(Map map, Long key){ // Needed for Weak Maps
Set<Long> keySet = map.keySet();
for (Long keyReference : keySet) {
if (keyReference == key) {
return keyReference;
}
}
return key; // If Not Found Return the Value Passed in
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveUserId(Long userId, Session session){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
userId = getKeyFromMap(sessionMap, userId); // Required for Weak Maps to Work Correctly
Set<Session> sessionsForUser = sessionMap.get(userId);
if (sessionsForUser == null) {
sessionsForUser = new HashSet<>();
}
sessionsForUser.add(session);
sessionMap.put(userId, sessionsForUser);
return userId;
} catch (Exception e) {
logger.error("Couldn't Save User Id");
return null;
}
}
// saveUserId() should create an { userId -> session } entry in sessionMap
public static Long saveTenantUser(Long tenantId, Long userId){
// Test Scenarios:
// Can userId be null or wrong?
// Can session be null or wrong?
try {
tenantId = getKeyFromMap(tenantUserMap, tenantId); // Required for Weak Maps to Work Correctly
Set<Long> users = tenantUserMap.get(tenantId);
if (users == null) {
users = new HashSet<>();
}
users.add(userId);
tenantUserMap.put(tenantId, users);
return tenantId;
} catch (Exception e) {
logger.error("Couldn't Save Tenant User");
return null;
}
}
public static void updateUserSessionKeys(Session session, Long tenantId, Long userId) {
try {
List<Long> userSessionKeys = sessions.get(session);
userSessionKeys.add(0, tenantId);
userSessionKeys.add(1, userId);
} catch (Exception e) {
logger.error("Couldn't Update User Session Keys");
}
}
// removeUserId() should remove an { userId -> session } entry in sessionMap
// returns: "0" if success and "-1" otherwise
public static int removeUserId( Long userId) {
try {
sessionMap.remove(userId);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendAccesspointStatus() should compose JSON message and pass it to sendToUser()
// returns: "0" if success and "-1" otherwise
public static int sendClosedStatus(Long userId, JSONObject accesspointStatus) {
try {
JSONObject accesspointStatusEventMessage = (JSONObject) createMessage(WebSocketEvents.OnClosedStatus, accesspointStatus);
sendToUser(userId, accesspointStatusEventMessage);
return 0;
} catch (Exception e) {
return -1;
}
}
// sendToUser() sends message to session that is mapped to userId
// returns: "0" if success and "-1" otherwise
public static int sendToUser( Long userId, JSON message) {
if (sessionMap.containsKey(userId)) {
Set<Session> sessionsForUser = sessionMap.get(userId);
for (Session session : sessionsForUser) {
if (!session.isOpen()) {
sessions.remove(session);
continue;
}
sendToSession(session, message);
}
return 0;
} else {
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, JSON message){
try {
try {
Long tenantId = sessions.get(session).get(0);
((JSONObject) message).put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(message.toString());
return 0;
} catch (IOException e) {
try {
session.close();
} catch (IOException ex) {
}
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
// sendToSession() sends string message to session
// returns: "0" if success and "-1" otherwise
private static int sendToSession( Session session, String message){
try {
JSONObject newMessage = JSONObject.fromObject(message);
try {
Long tenantId = sessions.get(session).get(0);
newMessage.put("tenantId", tenantId);
} catch (Exception e) {
logger.error("No tenantId Found");
}
session.getBasicRemote().sendText(newMessage.toString());
return 0;
} catch (IOException e) {
closeSessionProperly(session);
sessions.remove(session);
return -1;
}
}
}
@Singleton
公共类WebSocketService{
私有静态最终记录器Logger=LoggerFactory.getLogger(WebSocketService.class);
公共枚举WebSocketEvents{
连接,
积极性,
OnAccesspointStatus,
一旦关闭状态,
未连接状态,
奥纳勒特,
会话已过期
}
公共枚举WebSocketActions{
SaveUserId
}
@WebPost(“/lookupWebSocketSessions”)
公共WebResponse lookupWebSocketSessions(@JsonArrayParam(“userIds”)列出userid,@WebParam(“message”)字符串消息){
试一试{
for(整数useridit:userIds){
Long userId=Long.parseLong(useridit.toString());
if(WebSocketSessionHandler.sendToUser(用户ID,消息)==0){
}否则{
//debug(“无法发送给用户”);
}
}
}catch(ClassCastException e){
//logger.error(例如getMessage());
返回webResponseBuilder.fail(e);
}捕获(例外e){
//logger.error(例如getMessage());
返回webResponseBuilder.fail(e);
}
返回webResponseBuilder.success(消息);
}
@WebPost(“/lookupWebSocketHistorySessions”)
公共WebResponse lookupWebSocketHistorySessions(@JsonArrayParam(“userIds”)列出userIds,@WebParam(“message”)字符串消息){
试一试{
for(整数useridit:userIds){
Long userId=Long.parseLong(useridit.toString());
if(WebSocketHistorySessionHandler.sendToUser(userId,message)==0){
}否则{
//debug(“无法发送给用户”);
}
}
}catch(ClassCastException e){
//logger.error(例如getMessage());
返回webResponseBuilder.fail(e);
}捕获(例外e){
//logger.error(例如getMessage());
返回webResponseBuilder.fail(e);
}
返回webResponseBuilder.success(消息);
}
//如果用户的会话不再有效,则将其踢出
公共无效发送注销(用户){
试一试{
Long userId=user.getId();
List userid=new ArrayList();
添加(userId);
JSONObject结果=新建JSONObject();
结果.put(“userId”,userId);
JSON message=WebSocketSessionHandler.createMessage(WebSocketEvents.OnSessionExpired,结果);
查找其他服务器(用户标识、消息);
}捕获(例外e){
logger.error(“无法注销用户”);
}
}
//处理数据后发送历史记录
//如果成功则返回“0”,否则返回-1
公共int发送历史记录(活动){
试一试{
TimezoneService.TimeZoneConfig TimeZoneConfig=TimezoneService.getTimezoneConfigsByAp(null,activity.getAccesspointId());
JSONObject结果=(JSONObject)JSONSerializer.toJSON(活动);
字符串timezoneId=timezoneService.convertTimezoneConfigToTimezoneId(timeZoneConfig);
结果。put(“时区限制”,时区ID);
结果(
“profileId”,
userDao.getUserProfileId(activity.getUserId())
);
JSON message=WebSocketHistorySessionHandler.createMessage(WebSocketEvents.OnActivity,result);
List userid=getusersssubscribedtoactivity(activity.getTenantId());
lookOnOtherServersHistory(用户标识、消息);
返回0;
}捕获(例外e){
//logger.error(“无法发送历史记录”);
返回-1;
}
}
//SendAlertUpdate处理数据后更新
公共无效sendAlertUpdate(警报){
试一试{
List userid=getUsersUnderTenantByAccesspointId(alert.getAccesspointId());
JSONObject结果=JSONObject.fromObject(警报);
JSON message=WebSocketSessionHandler.createMessage(WebSocketEvents.OnAlert,结果);
查找其他服务器(用户标识、消息);
}捕获(例外e){
//logger.error(“无法发送Aleart”);
}