source: src/main/java/geniusweb/profilesserver/websocket/ProfilesListSocket.java@ 5

Last change on this file since 5 was 5, checked in by bart, 5 years ago

Fixed performance issue with some computers

File size: 4.7 KB
Line 
1package geniusweb.profilesserver.websocket;
2
3import java.io.IOException;
4import java.lang.management.ManagementFactory;
5import java.net.InetAddress;
6import java.net.URI;
7import java.net.URISyntaxException;
8import java.net.UnknownHostException;
9import java.util.HashMap;
10import java.util.List;
11import java.util.Map;
12import java.util.Set;
13import java.util.logging.Level;
14import java.util.stream.Collectors;
15
16import javax.management.MBeanServer;
17import javax.management.MalformedObjectNameException;
18import javax.management.ObjectName;
19import javax.management.Query;
20import javax.websocket.OnClose;
21import javax.websocket.OnError;
22import javax.websocket.OnOpen;
23import javax.websocket.Session;
24import javax.websocket.server.ServerEndpoint;
25
26import com.fasterxml.jackson.databind.ObjectMapper;
27
28import geniusweb.profilesserver.ProfilesFactory;
29import geniusweb.profilesserver.events.ChangeEvent;
30import tudelft.utilities.listener.Listener;
31import tudelft.utilities.logging.ReportToLogger;
32import tudelft.utilities.logging.Reporter;
33
34/**
35 * Returns a websocket that communicates the list of currently available domains
36 * and profiles. Every time something changes, a new list of domains and
37 * profiles is sent. For each new websocket the server will create one of this
38 * but they all share one {@link ProfilesFactory}.
39 */
40@ServerEndpoint("/websocket/liststream")
41public class ProfilesListSocket {
42
43 private final Reporter log;
44 /** following both final but set in {@link #start(Session)} */
45 private Session session;
46 private Listener<ChangeEvent> changeListener;
47 private static transient String hostport = ""; // cache
48
49 public ProfilesListSocket() {
50 this(new ReportToLogger("profilesserver"));
51 }
52
53 public ProfilesListSocket(ReportToLogger reportToLogger) {
54 this.log = reportToLogger;
55 }
56
57 @OnOpen
58 public void start(Session session) throws IOException {
59 this.session = session;
60 log.log(Level.INFO, "New connection " + session.getRequestURI());
61
62 sendupdatedProfiles();
63 changeListener = new Listener<ChangeEvent>() {
64
65 @Override
66 public void notifyChange(ChangeEvent data) {
67 try {
68 sendupdatedProfiles();
69 } catch (IOException e) {
70 e.printStackTrace();
71 }
72 }
73 };
74 Profiles.factory.addListener(changeListener);
75 }
76
77 /**
78 * Send the latest profiles to the client.
79 *
80 * @throws IOException
81 */
82 private void sendupdatedProfiles() throws IOException {
83 log.log(Level.FINER, "sending updated profiles");
84 session.getBasicRemote().sendText(
85 new ObjectMapper().writeValueAsString(getDomainsProfiles()));
86 }
87
88 /**
89 * @return list of domain and profile URIs, as a hashmap.
90 */
91 private Map<URI, List<URI>> getDomainsProfiles() {
92 Map<URI, List<URI>> allprofiles = new HashMap<>();
93 for (String domain : Profiles.factory.getDomains()) {
94 List<URI> profiles = Profiles.factory.getProfiles(domain).stream()
95 .map(profile -> makeURI(domain, profile.getName()))
96 .collect(Collectors.toList());
97 allprofiles.put(makeURI(domain, null), profiles);
98 }
99 return allprofiles;
100 }
101
102 /**
103 * @param domain the domain name.
104 * @param profile the profile name. If null, a ref to the the domain (no
105 * profile) is needed
106 * @return a URI where to get the given profile/domain.
107 */
108 private URI makeURI(String domain, String profile) {
109 try {
110 return new URI("ws://" + getIpAddressAndPort() + "/"
111 + getServerName() + "/websocket/get/" + domain
112 + (profile != null ? "/" + profile : ""));
113 } catch (MalformedObjectNameException | UnknownHostException
114 | URISyntaxException e) {
115 log.log(Level.SEVERE, "Failed to create profile URI", e);
116 return null;
117 }
118 }
119
120 /**
121 *
122 * @return name of our service, eg "profilesserver"
123 */
124 private String getServerName() {
125 // typically something like /profilesserver/websocket/liststream
126 // profilesserver is the name we're looking for
127 return session.getRequestURI().getPath().split("/")[1]; // drop leading
128 // '/'
129 }
130
131 private String getIpAddressAndPort()
132 throws UnknownHostException, MalformedObjectNameException {
133 synchronized (hostport) {
134 if (hostport.isEmpty()) {
135 MBeanServer beanServer = ManagementFactory
136 .getPlatformMBeanServer();
137
138 Set<ObjectName> objectNames = beanServer.queryNames(
139 new ObjectName("*:type=Connector,*"),
140 Query.match(Query.attr("protocol"),
141 Query.value("HTTP/1.1")));
142
143 String host = InetAddress.getLocalHost().getHostAddress();
144 String port = objectNames.iterator().next()
145 .getKeyProperty("port");
146
147 hostport = host + ":" + port;
148 }
149 return hostport;
150 }
151
152 }
153
154 @OnClose
155 public void end() throws IOException {
156 Profiles.factory.removeListener(changeListener);
157 }
158
159 @OnError
160 public void onError(Throwable t) throws Throwable {
161 t.printStackTrace();
162 }
163
164}
Note: See TracBrowser for help on using the repository browser.