/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.rioproject.tools.ui.browser; import com.sun.jini.admin.DestroyAdmin; import com.sun.jini.config.Config; import com.sun.jini.logging.Levels; import com.sun.jini.proxy.BasicProxyTrustVerifier; import net.jini.admin.JoinAdmin; import net.jini.config.ConfigurationException; import net.jini.core.discovery.LookupLocator; import net.jini.core.entry.Entry; import net.jini.core.event.EventRegistration; import net.jini.core.event.RemoteEvent; import net.jini.core.event.RemoteEventListener; import net.jini.core.lease.Lease; import net.jini.core.lookup.*; import net.jini.export.Exporter; import net.jini.jeri.BasicILFactory; import net.jini.jeri.BasicJeriExporter; import net.jini.jeri.tcp.TcpServerEndpoint; import net.jini.lookup.DiscoveryAdmin; import net.jini.lookup.entry.UIDescriptor; import net.jini.security.TrustVerifier; import net.jini.security.proxytrust.ServerProxyTrust; import javax.swing.*; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.*; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.rmi.server.ExportException; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; /** * ServiceEditor is a gui-based utility to add/modify * attributes, groups and lookup locators. * And also supports some well known admin interfaces. * (DestroyAdmin, DiscoveryAdmin) * <p/> * <p/> * current issues<br> * <ul> * <li> can't operate(add/remove/modify) array elements in an entry. * <li> does not support EntryBean. * <li> field modification is not based on EditableTree * </ul> */ class ServiceEditor extends JPanel { private static final Logger logger = Browser.logger; private Browser browser; private ServiceItem item; private ServiceRegistrar registrar; protected Object admin; private ServiceTemplate stmpl; private NotifyReceiver receiver; private Lease elease = null; private long eventID = 0; private long seqNo = Long.MAX_VALUE; private AttributeTreePanel attrPanel; private static JDialog dialog; private final static int MINIMUM_WINDOW_WIDTH = 320; private ServiceEditor(final ServiceItem item, final Object admin, final ServiceRegistrar registrar, final Browser browser) { super(new BorderLayout()); this.item = item; this.admin = admin; this.registrar = registrar; this.browser = browser; // init main components attrPanel = new AttributeTreePanel(); // setup notify try { stmpl = new ServiceTemplate(item.serviceID, new Class[]{item.service.getClass()}, new Entry[]{}); receiver = new NotifyReceiver(); setupNotify(); } catch (Throwable t) { logger.log(Level.INFO, "event registration failed", t); cancelNotify(); } dialog.addWindowListener(browser.wrap(new WindowAdapter() { public void windowClosing(WindowEvent e) { cleanup(); } })); // add menu and attr panel add(new JoinMenuBar(), BorderLayout.NORTH); add(attrPanel, BorderLayout.CENTER); validate(); // center in parent frame Rectangle bounds = browser.getBounds(); Dimension dialogSize = getPreferredSize(); int xpos = bounds.x + (bounds.width - dialogSize.width) / 2; int ypos = bounds.y + (bounds.height - dialogSize.height) / 2; setLocation((xpos < 0) ? 0 : xpos, (ypos < 0) ? 0 : ypos); } static JDialog getDialog(ServiceItem item, Object admin, ServiceRegistrar registrar, Browser browser) { dialog = new JDialog(browser, "ServiceItem Editor", true); ServiceEditor serviceEditor = new ServiceEditor(item, admin, registrar, browser); dialog.getContentPane().add(serviceEditor); dialog.pack(); dialog.setSize(((dialog.getSize().width < MINIMUM_WINDOW_WIDTH) ? MINIMUM_WINDOW_WIDTH : dialog.getSize().width), dialog.getSize().height); dialog.setModal(false); dialog.setLocationRelativeTo(browser); return (dialog); } void cleanup() { // cancel lease cancelNotify(); // release resources and close all child frames receiver.unexport(); dialog.dispose(); } protected void cancelNotify() { if (elease != null) { try { browser.getLeaseManager().cancel(elease); } catch (Throwable t) { logger.log(Levels.HANDLED, "event cancellation failed", t); } elease = null; seqNo = Long.MAX_VALUE; } } protected void setupNotify() { if (registrar != null) { try { EventRegistration reg = registrar.notify(stmpl, ServiceRegistrar.TRANSITION_MATCH_NOMATCH | ServiceRegistrar.TRANSITION_NOMATCH_MATCH | ServiceRegistrar.TRANSITION_MATCH_MATCH, receiver.proxy, null, Lease.ANY); elease = (Lease) browser.getLeasePreparer().prepareProxy(reg.getLease()); browser.getLeaseManager().renewUntil(elease, Lease.ANY, new Browser.LeaseNotify()); eventID = reg.getID(); seqNo = reg.getSequenceNumber(); } catch (Throwable t) { logger.log(Level.INFO, "event registration failed", t); } } } private class NotifyReceiver implements RemoteEventListener, ServerProxyTrust { private final Exporter exporter; final RemoteEventListener proxy; public NotifyReceiver() throws ConfigurationException, ExportException { exporter = (Exporter) Config.getNonNullEntry(browser.getConfiguration(), Browser.BROWSER, "listenerExporter", Exporter.class, new BasicJeriExporter(TcpServerEndpoint.getInstance(0), new BasicILFactory(), false, false)); proxy = (RemoteEventListener) exporter.export(this); } public void notify(final RemoteEvent ev) { SwingUtilities.invokeLater(browser.wrap(new Runnable() { public void run() { if (eventID == ev.getID() && seqNo < ev.getSequenceNumber()) { seqNo = ev.getSequenceNumber(); attrPanel.receiveNotify(((ServiceEvent) ev).getTransition()); } } })); } public TrustVerifier getProxyVerifier() { return new BasicProxyTrustVerifier(proxy); } void unexport() { exporter.unexport(true); } } class JoinMenuBar extends JMenuBar { public JoinMenuBar() { JMenuItem mitem; // "File" Menu JMenu fileMenu = add(new JMenu("File")); mitem = fileMenu.add(new JMenuItem("Show Info")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { Class[] infs = Browser.getInterfaces(item.service.getClass()); String[] msg = new String[3 + infs.length]; msg[0] = "ServiceID: " + item.serviceID; msg[1] = "Service Instance: " + item.service.getClass().getName(); if (infs.length == 1) msg[2] = "Implemented Interface:"; else msg[2] = "Implemented Interfaces:"; for (int i = 0; i < infs.length; i++) msg[3 + i] = " " + infs[i].getName(); JOptionPane.showMessageDialog(ServiceEditor.this, msg, "ServiceItem Information", JOptionPane.INFORMATION_MESSAGE); } })); mitem = fileMenu.add(new JMenuItem("Refresh")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { attrPanel.refreshPanel(); } })); mitem = fileMenu.add(new JMenuItem("Close")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { cleanup(); } })); // "Edit" Menu JMenu editMenu = add(new JMenu("Edit")); mitem = editMenu.add(new JMenuItem("Add Attribute...")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { attrPanel.addAttr(); } })); if (!(admin instanceof JoinAdmin)) mitem.setEnabled(false); mitem = editMenu.add(new JMenuItem("Remove Attribute")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { attrPanel.removeAttr(); } })); if (!(admin instanceof JoinAdmin)) mitem.setEnabled(false); // "Admin" Menu JMenu adminMenu = add(new JMenu("Admin")); // Group (JoinAdmin) mitem = adminMenu.add(new JMenuItem("Joining groups...")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { new GroupLister("Joining Groups").showFrame(); } })); if (!(admin instanceof JoinAdmin)) mitem.setEnabled(false); // Locator (JoinAdmin) mitem = adminMenu.add(new JMenuItem("Joining locators...")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { new LocatorLister("Joining Locators").showFrame(); } })); if (!(admin instanceof JoinAdmin)) mitem.setEnabled(false); // separator adminMenu.addSeparator(); // Group (DiscoveryAdmin) mitem = adminMenu.add(new JMenuItem("Member groups...")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { new MemberGroupLister("Member Groups").showFrame(); } })); if (!(admin instanceof DiscoveryAdmin)) mitem.setEnabled(false); // Unicast port (DiscoveryAdmin) mitem = adminMenu.add(new JMenuItem("Unicast port...")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { try { String[] msg = {"Current port is " + ((DiscoveryAdmin) admin).getUnicastPort(), "Input a new value"}; String result = JOptionPane.showInputDialog(ServiceEditor.this, msg, "Unicast Port", JOptionPane.QUESTION_MESSAGE); if (result == null) return; try { int port = Integer.parseInt(result); ((DiscoveryAdmin) admin).setUnicastPort(port); } catch (NumberFormatException e) { JOptionPane.showMessageDialog(ServiceEditor.this, result + " is not acceptable.", "Error", JOptionPane.ERROR_MESSAGE); } catch (Throwable t) { logger.log(Level.INFO, "setting unicast port failed", t); JOptionPane.showMessageDialog(ServiceEditor.this, t.getMessage(), t.getClass().getName(), JOptionPane.ERROR_MESSAGE); } } catch (Throwable t) { logger.log(Level.INFO, "getting unicast port failed", t); JOptionPane.showMessageDialog(ServiceEditor.this, t.getMessage(), t.getClass().getName(), JOptionPane.ERROR_MESSAGE); } } })); if (!(admin instanceof DiscoveryAdmin)) mitem.setEnabled(false); // separator adminMenu.addSeparator(); // DestroyAdmin mitem = adminMenu.add(new JMenuItem("Destroy")); mitem.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { if (JOptionPane.showConfirmDialog(ServiceEditor.this, "Are you sure to destroy this service?", "Query", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) try { ((DestroyAdmin) admin).destroy(); cleanup(); } catch (Throwable t) { logger.log(Level.INFO, "service destroy failed", t); JOptionPane.showMessageDialog(ServiceEditor.this, t.getMessage(), t.getClass().getName(), JOptionPane.ERROR_MESSAGE); } } })); if (!(admin instanceof DestroyAdmin)) mitem.setEnabled(false); } } class AttributeTreePanel extends EntryTreePanel { public AttributeTreePanel() { super(admin instanceof JoinAdmin); if (admin instanceof JoinAdmin) { tree.addMouseListener(browser.wrap(new DoubleClicker(this))); } tree.addMouseListener(browser.wrap(new MouseReceiver(item, uiDescriptorPopup()))); refreshPanel(); } protected Entry[] getEntryArray() { if (admin instanceof JoinAdmin) { try { item.attributeSets = ((JoinAdmin) admin).getLookupAttributes(); } catch (Throwable t) { logger.log(Level.INFO, "obtaining attributes failed", t); } } else { try { ServiceMatches matches = registrar.lookup(stmpl, 1); if (matches.totalMatches != 1) Browser.logger.log(Level.INFO, "unexpected lookup matches: {0}", matches.totalMatches); else item.attributeSets = matches.items[0].attributeSets; } catch (Throwable t) { Browser.logger.log(Level.INFO, "lookup failed", t); } } return item.attributeSets; } protected void receiveNotify(int transition) { if (browser.isAutoConfirm()) { if (transition == ServiceRegistrar.TRANSITION_MATCH_NOMATCH) cleanup(); else refreshPanel(); return; } String[] msg = (transition == ServiceRegistrar.TRANSITION_MATCH_NOMATCH) ? new String[]{ "Service has been removed from lookup service.", "Do you want to close the service editor window ?"} : new String[]{ "Attributes have been modified by another client or the service itself.", "Do you want to refresh the attributes ?"}; int result = JOptionPane.showConfirmDialog(AttributeTreePanel.this, msg, "Query", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { if (transition == ServiceRegistrar.TRANSITION_MATCH_NOMATCH) cleanup(); else refreshPanel(); } } public void editField(ObjectNode node) { String result = JOptionPane.showInputDialog(this, "Input a new value", "Modify a field", JOptionPane.QUESTION_MESSAGE); if (result != null) { // Save current value as template Entry template = cloneEntry((Entry) node.getEntryTop()); Object oldVal; if (result.length() == 0) { oldVal = node.setValue(null); } else { oldVal = node.setValue(result); } // modifyAttribute try { node.setObjectRecursive(); Entry attr = (Entry) node.getEntryTop(); //Entry template = (Entry) generateTemplate(attr); // cancel notify while adding an attribute cancelNotify(); ((JoinAdmin) admin).modifyLookupAttributes(new Entry[]{template}, new Entry[]{attr}); setupNotify(); // Redraw node value model.nodeChanged(node); } catch (Throwable t) { logger.log(Level.INFO, "attribute modification failed", t); // recover tree node try { node.setValue(oldVal); node.setObjectRecursive(); } catch (Throwable tt) { logger.log(Levels.HANDLED, "node reset failed", tt); } model.nodeChanged(node); //model.nodeStructureChanged(node); // show dialog JOptionPane.showMessageDialog(AttributeTreePanel.this, t.getMessage(), t.getClass().getName(), JOptionPane.ERROR_MESSAGE); } } } public void addAttr() { String result = JOptionPane.showInputDialog(this, "Input an entry class name", "Add an attribute", JOptionPane.QUESTION_MESSAGE); if (!(result == null || result.length() == 0)) { try { Class clazz = Class.forName(result); Object attr = clazz.newInstance(); if (!(attr instanceof Entry)) { JOptionPane.showMessageDialog(AttributeTreePanel.this, "Does not implement Entry interface", "Unacceptable Class", JOptionPane.WARNING_MESSAGE); } else if (attr instanceof net.jini.lookup.entry.ServiceControlled) { JOptionPane.showMessageDialog(AttributeTreePanel.this, "Implements ServiceControlled interface", "Unacceptable Class", JOptionPane.WARNING_MESSAGE); } else { // cancel notify while adding an attribute cancelNotify(); ((JoinAdmin) admin).addLookupAttributes( new Entry[]{(Entry) attr}); // add node of this attribute ObjectNode node = new ObjectNode(attr, true); root.add(node); recursiveObjectTree(node); // setupNotify(); // refresh view model.nodesWereInserted(root, new int[]{model.getIndexOfChild(root, node)}); } } catch (ClassNotFoundException e) { JOptionPane.showMessageDialog(AttributeTreePanel.this, e.getMessage(), "Class Not Found", JOptionPane.WARNING_MESSAGE); } catch (Throwable t) { logger.log(Level.INFO, "adding attribute failed", t); JOptionPane.showMessageDialog(AttributeTreePanel.this, t.getMessage(), t.getClass().getName(), JOptionPane.WARNING_MESSAGE); } } } public void removeAttr() { ObjectNode node = (ObjectNode) tree.getLastSelectedPathComponent(); if (node == null) { JOptionPane.showMessageDialog(AttributeTreePanel.this, "Select an attribute folder to remove.", "Warning", JOptionPane.WARNING_MESSAGE); return; } else if (!node.isControllable()) { JOptionPane.showMessageDialog(AttributeTreePanel.this, "This attribute is under service provider's control.", "Warning", JOptionPane.WARNING_MESSAGE); return; } else if (!node.isEntryTop()) { JOptionPane.showMessageDialog(AttributeTreePanel.this, "Select a top of attribute folder.", "Warning", JOptionPane.WARNING_MESSAGE); return; } Entry target = (Entry) node.getObject(); int result = JOptionPane.showConfirmDialog(AttributeTreePanel.this, new String[]{"Remove attribute:", target.toString()}, "Query", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { // Remote Attribute try { // cancel notify while adding an attribute cancelNotify(); ((JoinAdmin) admin).modifyLookupAttributes( new Entry[]{target}, new Entry[]{null}); // setupNotify(); int index = root.getIndex(node); root.remove(node); model.nodesWereRemoved(root, new int[]{index}, new Object[]{node}); } catch (Throwable t) { logger.log(Level.INFO, "attribute removal failed", t); JOptionPane.showMessageDialog(AttributeTreePanel.this, t.getMessage(), t.getClass().getName(), JOptionPane.ERROR_MESSAGE); } } } private Entry cloneEntry(final Entry attr) { try { Class realClass = attr.getClass(); Entry template = (Entry) realClass.newInstance(); Field[] f = realClass.getFields(); for (Field field : f) { if (!usableField(field)) continue; field.set(template, field.get(attr)); } return template; } catch (Throwable t) { logger.log(Level.INFO, "duplicating entry failed", t); } return null; } // from EntryRep private boolean usableField(final Field field) { Class desc = field.getDeclaringClass(); if (desc.isPrimitive()) { throw new IllegalArgumentException("primitive types not allowed in an Entry"); } // skip anything that isn't a public per-object mutable field int mods = field.getModifiers(); return (0 == (mods & (Modifier.TRANSIENT | Modifier.STATIC | Modifier.FINAL))); } class DoubleClicker extends MouseAdapter { AttributeTreePanel parent; public DoubleClicker(final AttributeTreePanel parent) { this.parent = parent; } public void mouseClicked(final MouseEvent ev) { if (ev.getClickCount() >= 2) { JTree tree = (JTree) ev.getSource(); TreePath path = tree.getPathForLocation(ev.getX(), ev.getY()); if (path == null) return; ObjectNode node = (ObjectNode) path.getLastPathComponent(); if (node.isLeaf()) { if (!node.isControllable()) { JOptionPane.showMessageDialog(AttributeTreePanel.this, "This attribute is under service provider's control.", "Warning", JOptionPane.WARNING_MESSAGE); } else if (node.isEditable() && ((ObjectNode) node.getParent()).isEntryTop()) { parent.editField(node); } else { JOptionPane.showMessageDialog(AttributeTreePanel.this, "This field is not editable.", "Warning", JOptionPane.WARNING_MESSAGE); } } tree.scrollPathToVisible(path); } } } } abstract class ListerFrame extends JFrame { private JList listBox; private JScrollPane scrollPane; protected DefaultListModel model = new DefaultListModel(); private DefaultListModel dummyModel = new DefaultListModel(); // to keep away from Swing's bug private JButton addButton; private JButton removeButton; private JButton closeButton; public ListerFrame(final String title) { super(title); getContentPane().setLayout(new BorderLayout()); // create the initial list listBox = new JList(model); listBox.setFixedCellHeight(20); scrollPane = new JScrollPane(listBox); getContentPane().add(scrollPane, "Center"); //resetListModel(); // Create the controls JPanel buttonPanel = new JPanel(); addButton = new JButton("Add"); addButton.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { String result = JOptionPane.showInputDialog(ListerFrame.this, getAddMessage()); if (result != null) { StringTokenizer st = new StringTokenizer(result); String[] tokens = new String[st.countTokens()]; for (int i = 0; i < tokens.length; i++) tokens[i] = st.nextToken().trim(); addItems(tokens); resetListModel(); scrollPane.validate(); } } })); buttonPanel.add(addButton); removeButton = new JButton("Remove"); removeButton.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { Object[] selected = listBox.getSelectedValues(); if (selected == null || selected.length == 0) { // no items are selected JOptionPane.showMessageDialog(ListerFrame.this, "No items are selected", "Warning", JOptionPane.WARNING_MESSAGE); return; } int result = JOptionPane.showConfirmDialog(ListerFrame.this, getRemoveMessage(selected), "Query", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { removeItems(selected); resetListModel(); scrollPane.validate(); } } })); buttonPanel.add(removeButton); closeButton = new JButton("Close"); closeButton.addActionListener(browser.wrap(new ActionListener() { public void actionPerformed(ActionEvent ev) { setVisible(false); } })); buttonPanel.add(closeButton); getContentPane().add(buttonPanel, "South"); pack(); } public void showFrame() { // init list data resetListModel(); setLocationRelativeTo(browser); setVisible(true); } private void resetListModel() { //listBox.setModel(null); listBox.setModel(dummyModel); // to keep away from NullException (Swing's bug) model.removeAllElements(); initListModel(); listBox.setModel(model); listBox.clearSelection(); listBox.ensureIndexIsVisible(0); listBox.repaint(); listBox.revalidate(); } protected abstract void initListModel(); protected abstract String getAddMessage(); protected abstract String getRemoveMessage(Object[] items); protected abstract void addItems(String[] items); protected abstract void removeItems(Object[] items); } class GroupLister extends ListerFrame { public GroupLister(final String title) { super(title); } protected void initListModel() { if (!(admin instanceof JoinAdmin)) { return; } try { String[] groups = ((JoinAdmin) admin).getLookupGroups(); for (String group : groups) { model.addElement(new GroupItem(group)); } } catch (Throwable t) { logger.log(Level.INFO, "obtaining groups failed", t); } } protected String getAddMessage() { return "Enter adding group(s)"; } protected String getRemoveMessage(final Object[] items) { StringBuffer msg = new StringBuffer(); if (items.length > 1) msg.append("Remove these groups : "); else msg.append("Remove a group : "); for (int i = 0; i < items.length; i++) { if (i != 0) msg.append(", "); msg.append((items[i]).toString()); } return msg.toString(); } protected void addItems(final String[] items) { // check "public" String[] grps = new String[items.length]; for (int i = 0; i < items.length; i++) grps[i] = new GroupItem(items[i]).group; try { ((JoinAdmin) admin).addLookupGroups(grps); } catch (Throwable t) { logger.log(Level.INFO, "adding groups failed", t); } } protected void removeItems(final Object[] items) { String[] grps = new String[items.length]; for (int i = 0; i < items.length; i++) grps[i] = ((GroupItem) items[i]).group; try { ((JoinAdmin) admin).removeLookupGroups(grps); } catch (Throwable t) { logger.log(Level.INFO, "removing groups failed", t); } } } class MemberGroupLister extends ListerFrame { public MemberGroupLister(final String title) { super(title); } protected void initListModel() { try { String[] groups = ((DiscoveryAdmin) admin).getMemberGroups(); for (String group : groups) { model.addElement(new GroupItem(group)); } } catch (Throwable t) { logger.log(Level.INFO, "obtaining groups failed", t); } } protected String getAddMessage() { return "Enter adding group(s)"; } protected String getRemoveMessage(final Object[] items) { StringBuilder msg = new StringBuilder(); if (items.length > 1) msg.append("Remove these groups : "); else msg.append("Remove a group : "); for (int i = 0; i < items.length; i++) { if (i != 0) msg.append(", "); msg.append((items[i]).toString()); } return msg.toString(); } protected void addItems(final String[] items) { // check "public" String[] grps = new String[items.length]; for (int i = 0; i < items.length; i++) grps[i] = new GroupItem(items[i]).group; try { ((DiscoveryAdmin) admin).addMemberGroups(grps); } catch (Throwable t) { logger.log(Level.INFO, "adding groups failed", t); } } protected void removeItems(final Object[] items) { String[] grps = new String[items.length]; for (int i = 0; i < items.length; i++) grps[i] = ((GroupItem) items[i]).group; try { ((DiscoveryAdmin) admin).removeMemberGroups(grps); } catch (Throwable t) { logger.log(Level.INFO, "removing groups failed", t); } } } class GroupItem { public String group; public GroupItem(final String group) { if (group.equals("public")) this.group = ""; else this.group = group; } public String toString() { if ("".equals(group)) return "public"; else return group; } } class LocatorLister extends ListerFrame { public LocatorLister(final String title) { super(title); } protected void initListModel() { if (!(admin instanceof JoinAdmin)) { return; } try { LookupLocator[] locators = ((JoinAdmin) admin).getLookupLocators(); for (LookupLocator locator : locators) { model.addElement(locator); } } catch (Throwable t) { logger.log(Level.INFO, "obtaining locators failed", t); } } protected String getAddMessage() { return "Enter a new locator's URL"; } protected String getRemoveMessage(final Object[] items) { StringBuilder msg = new StringBuilder(); if (items.length > 1) msg.append("Remove these locators : "); else msg.append("Remove a locator : "); for (int i = 0; i < items.length; i++) { if (i != 0) msg.append(", "); msg.append(items[i].toString()); } return msg.toString(); } protected void addItems(final String[] items) { LookupLocator[] locs = new LookupLocator[items.length]; for (int i = 0; i < items.length; i++) { try { locs[i] = new LookupLocator(items[i]); } catch (MalformedURLException e) { JOptionPane.showMessageDialog(LocatorLister.this, "\"" + items[i] + "\": " + e.getMessage(), "Bad Locator", JOptionPane.WARNING_MESSAGE); return; } } try { ((JoinAdmin) admin).addLookupLocators(locs); } catch (Throwable t) { logger.log(Level.INFO, "adding locators failed", t); } } protected void removeItems(final Object[] items) { LookupLocator[] locs = new LookupLocator[items.length]; for (int i = 0; i < items.length; i++) locs[i] = (LookupLocator) items[i]; try { ((JoinAdmin) admin).removeLookupLocators(locs); } catch (Throwable t) { logger.log(Level.INFO, "removing locators failed", t); } } } // provides support for ServiceUI public class UIDescriptorPopup extends JPopupMenu implements ActionListener, PopupMenuListener { protected transient JMenuItem showUIItem; protected transient ServiceItem serviceItem; public UIDescriptorPopup() { super(); showUIItem = new JMenuItem("Show UI"); showUIItem.addActionListener(this); showUIItem.setActionCommand("showUI"); add(showUIItem); addPopupMenuListener(this); setOpaque(true); setLightWeightPopupEnabled(true); } public void actionPerformed(final ActionEvent anEvent) { UIDescriptor uiDescriptor = getSelectedUIDescriptor(); if (uiDescriptor == null) { return; } ServiceUIHelper.handle(uiDescriptor, serviceItem, dialog); } public void popupMenuWillBecomeVisible(final PopupMenuEvent ev) { } public void popupMenuWillBecomeInvisible(final PopupMenuEvent ev) { } public void popupMenuCanceled(final PopupMenuEvent ev) { } public void setServiceItem(final ServiceItem anItem) { serviceItem = anItem; } } class MouseReceiver extends MouseAdapter { private ServiceEditor.UIDescriptorPopup popup; private ServiceItem serviceItem; public MouseReceiver(final ServiceItem aServiceItem, final ServiceEditor.UIDescriptorPopup popup) { this.popup = popup; serviceItem = aServiceItem; } public void mouseReleased(final MouseEvent ev) { higlightSelection(ev); if (!ev.isPopupTrigger()) { return; } UIDescriptor selectedDescriptor = getSelectedUIDescriptor(); if (selectedDescriptor == null) { return; } if (!"javax.swing".equals(selectedDescriptor.toolkit)) { return; } popup.setServiceItem(serviceItem); popup.show(ev.getComponent(), ev.getX(), ev.getY()); } public void mousePressed(final MouseEvent ev) { higlightSelection(ev); if (!ev.isPopupTrigger()) { return; } UIDescriptor selectedDescriptor = getSelectedUIDescriptor(); if (selectedDescriptor == null) { return; } if (!"javax.swing".equals(selectedDescriptor.toolkit)) { return; } popup.setServiceItem(serviceItem); popup.show(ev.getComponent(), ev.getX(), ev.getY()); } } private UIDescriptor getSelectedUIDescriptor() { ObjectNode selectedNode = (ObjectNode) attrPanel.tree.getLastSelectedPathComponent(); if (selectedNode == null) { return null; } Object selectedObject = selectedNode.getObject(); try { return (UIDescriptor) selectedObject; } catch (ClassCastException e) { return null; } } private void higlightSelection(final MouseEvent event) { attrPanel.tree.setSelectionPath(attrPanel.tree.getPathForLocation(event.getX(), event.getY())); } private ServiceEditor.UIDescriptorPopup uiDescriptorPopup() { return new ServiceEditor.UIDescriptorPopup(); } }