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

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

Fix for IssueValue hashcode.

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