Java tutorial
/******************************************************************************* * Copyright [2015] [Onboard team of SERC, Peking University] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package com.onboard.service.websocket.impl; import java.io.IOException; import java.nio.CharBuffer; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.Set; import javax.annotation.PostConstruct; import org.apache.catalina.websocket.MessageInbound; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectWriter; import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.onboard.domain.model.Activity; import com.onboard.domain.model.Notification; import com.onboard.domain.model.User; import com.onboard.service.websocket.WebSocketService; @Service("webSocketServiceBean") public class WebSocketServiceImpl implements WebSocketService { public static final Logger logger = LoggerFactory.getLogger(WebSocketServiceImpl.class); private Multimap<String, MessageInbound> userPagesMap; @PostConstruct public void init() { userPagesMap = ArrayListMultimap.create(); } @Override public void registerClient(String user, MessageInbound inbound) { logger.info("New page registered at" + new Date().toString()); userPagesMap.put(user, inbound); logger.info("Size of " + user + ":" + userPagesMap.get(user).size()); } @Override public void unregisterClient(String user, MessageInbound inbound) { logger.info("A page unregistered at " + new Date().toString()); userPagesMap.remove(user, inbound); logger.info("Size of " + user + ":" + userPagesMap.get(user).size()); } @Override public void sendToPage(MessageInbound inbound, String message) throws IOException { inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message)); logger.info("message sent to client:" + message); } /** * ?map?json * * @param actionMap * @return */ private String getJson(Object activity) { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL); ObjectWriter ow = objectMapper.writer().withDefaultPrettyPrinter(); String message = ""; try { message = ow.writeValueAsString(activity); } catch (IOException e) { logger.info("activity to json failure"); } return message; } @Override /** * code be strictly written like below(about synchronization), following guava's official guide. */ public void broadcastOne(String user, Activity activity) { logger.info(getJson(activity)); String message = getJson(activity); broadcastOne(user, message); } @Override public void broadcastOne(String user, Notification notification) { String message = getJson(notification); broadcastOne(user, message); } @Override public void broadcastAll(Activity activity) { Set<String> keySet = userPagesMap.keySet(); for (String user : keySet) { broadcastOne(user, activity); } } @Override public void broadcastOne(String user, String message) { Multimap<String, MessageInbound> syncMap = Multimaps.synchronizedMultimap(userPagesMap); Collection<MessageInbound> mis = syncMap.get(user); synchronized (syncMap) { if (mis != null) { Iterator<MessageInbound> it = mis.iterator(); while (it.hasNext()) { MessageInbound inbound = it.next(); try { sendToPage(inbound, message); } catch (IOException e) { // userPagesMap.remove(user, inbound); logger.info("The WebSocket connection has been closed: " + inbound.toString()); } } } } } @Override public void broadcastOne(User user, Object object) { broadcastOne(user.getEmail(), getJson(object)); } }