1 package jalview.ws.jws2;
3 import jalview.bin.Cache;
4 import jalview.gui.AlignFrame;
5 import jalview.gui.Desktop;
6 import jalview.gui.JvSwingUtils;
7 import jalview.util.MessageManager;
8 import jalview.ws.api.ServiceWithParameters;
10 import java.awt.Color;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Hashtable;
18 import java.util.List;
20 import javax.swing.JMenu;
21 import javax.swing.JMenuItem;
23 public class PreferredServiceRegistry
26 private static PreferredServiceRegistry us = new PreferredServiceRegistry();
28 public static PreferredServiceRegistry getRegistry()
32 us = new PreferredServiceRegistry();
37 List<ServiceWithParameters> ourServices = new ArrayList<>();
40 * forget about any known services
42 public void clearServices()
47 public void populateWSMenuEntry(List<ServiceWithParameters> services,
48 PreferredServiceChangeListener changeListener, JMenu menu,
49 final AlignFrame alignFrame, String typeFilter)
52 * eventually, JWS2 services will appear under the same align/etc submenus.
53 * for moment we keep them separate.
55 ourServices.addAll(services);
58 List<ServiceWithParameters> oneshotServices = new ArrayList<>();
59 List<ServiceWithParameters> interactiveServices = new ArrayList<>();
60 Map<String, ServiceWithParameters> preferredHosts = new HashMap<>();
61 Map<String, List<ServiceWithParameters>> alternates = new HashMap<>();
63 for (var service : services)
65 if (service.isInteractiveUpdate())
66 interactiveServices.add(service);
68 oneshotServices.add(service);
70 for (var service : interactiveServices)
72 if (!preferredHosts.containsKey(service.getName()))
74 var preferred = getPreferredServiceFor(alignFrame, service.getName());
75 preferredHosts.put(service.getName(), (preferred != null) ? preferred : service);
77 var ph = alternates.getOrDefault(service.getName(), new ArrayList<>());
78 if (!preferredHosts.containsValue(service))
81 alternates.putIfAbsent(service.getName(), ph);
85 // create GUI element for classic services
86 addEnumeratedServices(menu, alignFrame, oneshotServices);
87 // and the instantaneous services
88 for (final ServiceWithParameters service : preferredHosts.values())
90 atpoint = JvSwingUtils.findOrCreateMenu(menu,
91 service.getServiceType());
92 if (atpoint.getItemCount() > 1)
94 // previous service of this type already present
95 atpoint.addSeparator();
98 atpoint.add(hitm = new JMenuItem(service.getHostURL()));
99 hitm.setForeground(Color.blue);
100 hitm.addActionListener(e -> Desktop.showUrl(service.getHostURL()));
101 hitm.setToolTipText(JvSwingUtils.wrapTooltip(false,
102 MessageManager.getString("label.open_jabaws_web_page")));
104 service.attachWSMenuEntry(atpoint, alignFrame);
105 if (alternates.containsKey(service.getName()))
107 atpoint.add(hitm = new JMenu(
108 MessageManager.getString("label.switch_server")));
109 hitm.setToolTipText(JvSwingUtils.wrapTooltip(false,
110 MessageManager.getString("label.choose_jabaws_server")));
111 for (final ServiceWithParameters sv : alternates
112 .get(service.getName()))
115 hitm.add(itm = new JMenuItem(sv.getHostURL()));
116 itm.setForeground(Color.blue);
117 itm.addActionListener(e -> {
118 setPreferredServiceFor(alignFrame, sv.getName(), sv.getServiceType(), sv);
119 changeListener.preferredServiceChanged(sv);
127 * add services using the Java 2.5/2.6/2.7 system which optionally creates
128 * submenus to index by host and service program type
130 private void addEnumeratedServices(final JMenu jws2al,
131 final AlignFrame alignFrame,
132 List<ServiceWithParameters> enumerableServices)
134 boolean byhost = Cache.getDefault("WSMENU_BYHOST", false),
135 bytype = Cache.getDefault("WSMENU_BYTYPE", false);
137 * eventually, JWS2 services will appear under the same align/etc submenus.
138 * for moment we keep them separate.
142 List<String> hostLabels = new ArrayList<>();
143 Hashtable<String, String> lasthostFor = new Hashtable<>();
144 Hashtable<String, ArrayList<ServiceWithParameters>> hosts = new Hashtable<>();
145 ArrayList<String> hostlist = new ArrayList<>();
146 for (ServiceWithParameters service : enumerableServices)
148 ArrayList<ServiceWithParameters> hostservices = hosts
149 .get(service.getHostURL());
150 if (hostservices == null)
152 hosts.put(service.getHostURL(), hostservices = new ArrayList<>());
153 hostlist.add(service.getHostURL());
155 hostservices.add(service);
157 // now add hosts in order of the given array
158 for (String host : hostlist)
160 ServiceWithParameters orderedsvcs[] = hosts.get(host)
161 .toArray(new ServiceWithParameters[1]);
162 String sortbytype[] = new String[orderedsvcs.length];
163 for (int i = 0; i < sortbytype.length; i++)
165 sortbytype[i] = orderedsvcs[i].getName();
167 jalview.util.QuickSort.sort(sortbytype, orderedsvcs);
168 for (final ServiceWithParameters service : orderedsvcs)
170 atpoint = JvSwingUtils.findOrCreateMenu(jws2al,
171 service.getAction());
172 String type = service.getName();
175 atpoint = JvSwingUtils.findOrCreateMenu(atpoint, host);
176 if (atpoint.getToolTipText() == null)
178 atpoint.setToolTipText(MessageManager
179 .formatMessage("label.services_at", new String[]
185 atpoint = JvSwingUtils.findOrCreateMenu(atpoint, type);
186 if (atpoint.getToolTipText() == null)
188 atpoint.setToolTipText(service.getActionText());
191 if (!byhost && !hostLabels.contains(
192 host + service.getName() + service.getActionText()))
193 // !hostLabels.contains(host + (bytype ?
194 // service.serviceType+service.getActionText() : "")))
196 // add a marker indicating where this service is hosted
197 // relies on services from the same host being listed in a
201 if (hostLabels.contains(host))
203 atpoint.addSeparator();
207 hostLabels.add(host);
209 if (lasthostFor.get(service.getAction()) == null
210 || !lasthostFor.get(service.getAction()).equals(host))
212 atpoint.add(hitm = new JMenuItem(host));
213 hitm.setForeground(Color.blue);
214 hitm.addActionListener(new ActionListener()
218 public void actionPerformed(ActionEvent e)
220 Desktop.showUrl(service.getHostURL());
224 JvSwingUtils.wrapTooltip(true, MessageManager
225 .getString("label.open_jabaws_web_page")));
226 lasthostFor.put(service.getAction(), host);
229 .add(host + service.getName() + service.getActionText());
232 service.attachWSMenuEntry(atpoint, alignFrame);
238 * pick the user's preferred service based on a set of URLs (jaba server
239 * locations) and service URIs (specifying version and service interface
243 * @return null or best match for given uri/ls.
245 public ServiceWithParameters getPreferredServiceFor(String[] serviceURLs)
247 HashSet<String> urls = new HashSet<>();
248 urls.addAll(Arrays.asList(serviceURLs));
249 ServiceWithParameters match = null;
251 if (ourServices != null)
253 for (ServiceWithParameters svc : ourServices)
255 // TODO getNameURI Should return a versioned URI for the service, but
256 // doesn't as of 2.11
257 if (urls.contains(svc.getNameURI()))
261 // for moment we always pick service from server ordered first in
262 // user's preferences
265 if (urls.contains(svc.getUri()))
267 // stop and return - we've matched type URI and URI for service
277 Map<String, Map<String, String>> preferredServiceMap = new HashMap<>();
280 * get current preferred endpoint of the given Jabaws service, or global
284 * null or a specific alignFrame
286 * ServiceWithParameters.getName() for service
287 * @return null if no service of this type is available, the preferred service
288 * for the serviceType and af if specified and if defined.
290 public ServiceWithParameters getPreferredServiceFor(AlignFrame af,
293 String serviceurl = null;
294 synchronized (preferredServiceMap)
296 String afid = (af == null) ? "" : af.getViewport().getSequenceSetId();
297 Map<String, String> prefmap = preferredServiceMap.get(afid);
298 if (afid.length() > 0 && prefmap == null)
300 // recover global setting, if any
301 prefmap = preferredServiceMap.get("");
305 serviceurl = prefmap.get(serviceName);
309 ServiceWithParameters response = null;
310 for (ServiceWithParameters svc : ourServices)
312 if (svc.getName().equals(serviceName))
314 if (serviceurl == null || serviceurl.equals(svc.getHostURL()))
324 public void setPreferredServiceFor(AlignFrame af, String serviceName,
325 String serviceAction, ServiceWithParameters selectedServer)
327 // TODO: pull out and generalise for the selectedServer's attributes
328 String afid = (af == null) ? "" : af.getViewport().getSequenceSetId();
329 if (preferredServiceMap == null)
331 preferredServiceMap = new HashMap<>();
333 Map<String, String> prefmap = preferredServiceMap.get(afid);
336 prefmap = new HashMap<>();
337 preferredServiceMap.put(afid, prefmap);
339 prefmap.put(serviceName, selectedServer.getHostURL());
340 prefmap.put(serviceAction, selectedServer.getHostURL());
343 public void setPreferredServiceFor(String serviceType,
344 String serviceAction, ServiceWithParameters selectedServer)
346 setPreferredServiceFor(null, serviceType, serviceAction,
350 public boolean contains(ServiceWithParameters service)
352 return ourServices.contains(service);