Package org.rioproject.tools.ui.browser

Source Code of org.rioproject.tools.ui.browser.Browser$Handler

/*
* 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.Administrable;
import net.jini.admin.JoinAdmin;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import net.jini.config.EmptyConfiguration;
import net.jini.config.NoSuchEntryException;
import net.jini.core.constraint.MethodConstraints;
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.discovery.*;
import net.jini.export.Exporter;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.jeri.tcp.TcpServerEndpoint;
import net.jini.lease.LeaseListener;
import net.jini.lease.LeaseRenewalEvent;
import net.jini.lease.LeaseRenewalManager;
import net.jini.lookup.DiscoveryAdmin;
import net.jini.lookup.entry.UIDescriptor;
import net.jini.security.*;
import net.jini.security.proxytrust.ServerProxyTrust;
import org.rioproject.tools.ui.serviceui.AdminFrame;
import org.rioproject.ui.Util;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.lang.reflect.*;
import java.net.MalformedURLException;
import java.rmi.server.ExportException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.*;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
* This is not great user interface design. It was a quick-and-dirty hack
* and an experiment in on-the-fly menu construction, and it's still
* here because we've never had time to do anything better.
*/

/**
* Example service browser. See the package documentation for details.
*/
public class Browser extends JFrame {
    static final String BROWSER = Browser.class.getPackage().getName();
    static final Logger logger = Logger.getLogger(BROWSER);

    private SecurityContext ctx;
    private ClassLoader ccl;
    private Configuration config;
    private DiscoveryGroupManagement disco;
    private ServiceRegistrar lookup = null;
    private Object eventSource = null;
    private long eventID = 0;
    private long seqNo = Long.MAX_VALUE;
    private ServiceTemplate tmpl;
    private Listener listen;
    private Lease elease = null;
    private ProxyPreparer leasePreparer;
    private ProxyPreparer servicePreparer;
    private ProxyPreparer adminPreparer;
    private MethodConstraints locatorConstraints;
    private LeaseRenewalManager leaseMgr;
    private LeaseListener lnotify;
    private List<String> ignoreInterfaces;
    private JTextArea text;
    private JMenu registrars;
    private JCheckBoxMenuItem esuper;
    private JCheckBoxMenuItem ssuper;
    private JCheckBoxMenuItem sclass;
    private boolean isAdmin;
    private volatile boolean autoConfirm;
    private JList list;
    private DefaultListModel listModel;
    private DefaultListModel dummyModel = new DefaultListModel();
    private JScrollPane listScrollPane;
    private JSplitPane splitPane;

    /**
     * Creates an instance of the {@code Browser}.
     *
     * @param config the configuration, or <code>null</code>
     * @param parent, the frame that launched this utility
     */
    public Browser(Configuration config, JFrame parent) throws ConfigurationException, IOException {
        if (config == null)
            config = EmptyConfiguration.INSTANCE;
        init(config);
        if(parent!=null)
            this.setLocationRelativeTo(parent);
    }

    LeaseRenewalManager getLeaseManager() {
        return leaseMgr;
    }

    Configuration getConfiguration() {
        return config;
    }

    ProxyPreparer getLeasePreparer() {
        return leasePreparer;
    }

    private void init(Configuration config) throws ConfigurationException, IOException {
        this.config = config;
        ctx = Security.getContext();
        ccl = Thread.currentThread().getContextClassLoader();
        leaseMgr = (LeaseRenewalManager) Config.getNonNullEntry(config,
                                                                BROWSER,
                                                                "leaseManager",
                                                                LeaseRenewalManager.class,
                                                                new LeaseRenewalManager(config));
        isAdmin = (Boolean) config.getEntry(BROWSER, "folderView", boolean.class, Boolean.TRUE);
        leasePreparer = (ProxyPreparer) Config.getNonNullEntry(config,
                                                               BROWSER,
                                                               "leasePreparer",
                                                               ProxyPreparer.class,
                                                               new BasicProxyPreparer());
        servicePreparer = (ProxyPreparer)Config.getNonNullEntry(config,
                                                                BROWSER,
                                                                "servicePreparer",
                                                                ProxyPreparer.class,
                                                                new BasicProxyPreparer());
        adminPreparer = (ProxyPreparer) Config.getNonNullEntry(config,
                                                               BROWSER,
                                                               "adminPreparer",
                                                               ProxyPreparer.class,
                                                               new BasicProxyPreparer());
        locatorConstraints = (MethodConstraints)config.getEntry(BROWSER,
                                                                "locatorConstraints",
                                                                MethodConstraints.class,
                                                                null);
        ignoreInterfaces = Arrays.asList((String[])Config.getNonNullEntry(config, BROWSER,
                                                                          "uninterestingInterfaces",
                                                                          String[].class,
                                                                          new String[]{"java.io.Serializable",
                                                                                       "java.rmi.Remote",
                                                                                       "net.jini.admin.Administrable",
                                                                                       "net.jini.core.constraint.RemoteMethodControl",
                                                                                       "net.jini.id.ReferentUuid",
                                                                                       "net.jini.security.proxytrust.TrustEquivalence"}));
        autoConfirm = (Boolean) config.getEntry(BROWSER, "autoConfirm", boolean.class, Boolean.FALSE);
        listen = new Listener();
        try {
            DiscoveryManagement disco = (DiscoveryManagement)Config.getNonNullEntry(config,
                                                                                    BROWSER,
                                                                                    "discoveryManager",
                                                                                    DiscoveryManagement.class);
            if (!(disco instanceof DiscoveryGroupManagement)) {
                throw new ConfigurationException("discoveryManager does not support DiscoveryGroupManagement");
            } else if (!(disco instanceof DiscoveryLocatorManagement)) {
                throw new ConfigurationException("discoveryManager does not support DiscoveryLocatorManagement");
            }
            this.disco = (DiscoveryGroupManagement) disco;
            String[] groups = this.disco.getGroups();
            if (groups == null || groups.length > 0) {
                throw new ConfigurationException("discoveryManager cannot have initial groups");
            }
            if (((DiscoveryLocatorManagement) disco).getLocators().length > 0) {
                throw new ConfigurationException("discoveryManager cannot have initial locators");
            }
        } catch (NoSuchEntryException e) {
            disco = new LookupDiscoveryManager(new String[0], new LookupLocator[0], null, config);
        }
        disco.setGroups((String[]) config.getEntry(BROWSER,
                                                   "initialLookupGroups",
                                                   String[].class,
                                                   null));
        ((DiscoveryLocatorManagement) disco).setLocators((LookupLocator[])Config.getNonNullEntry(config,
                                                                                                 BROWSER,
                                                                                                 "initialLookupLocators",
                                                                                                 LookupLocator[].class,
                                                                                                 new LookupLocator[0]));
        tmpl = new ServiceTemplate(null, new Class[0], new Entry[0]);
        setTitle("Service Browser");
        JMenuBar bar = new JMenuBar();
        JMenu file = new JMenu("File");
        JMenuItem allfind = new JMenuItem("Find All");
        allfind.addActionListener(wrap(new AllFind()));
        file.add(allfind);
        JMenuItem pubfind = new JMenuItem("Find Public");
        pubfind.addActionListener(wrap(new PubFind()));
        file.add(pubfind);
        JMenuItem multifind = new JMenuItem("Find By Group...");
        multifind.addActionListener(wrap(new MultiFind()));
        file.add(multifind);
        JMenuItem unifind = new JMenuItem("Find By Address...");
        unifind.addActionListener(wrap(new UniFind()));
        file.add(unifind);
        if (!isAdmin) {
            JMenuItem show = new JMenuItem("Show Matches");
            show.addActionListener(wrap(new Show()));
            file.add(show);
        }
        JMenuItem reset = new JMenuItem("Reset");
        reset.addActionListener(wrap(new Reset()));
        file.add(reset);
        JMenuItem exit = new JMenuItem("Exit");
        exit.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                terminate();
            }
        });
        file.add(exit);
        bar.add(file);
        addWindowListener(new WindowAdapter() {
            @Override public void windowClosing(WindowEvent e) {
                terminate();
            }
        });
        registrars = new JMenu("Registrar");
        addNone(registrars);
        bar.add(registrars);
        JMenu options = new JMenu("Options");
        esuper = new JCheckBoxMenuItem("Attribute supertypes", false);
        options.add(esuper);
        ssuper = new JCheckBoxMenuItem("Service supertypes", false);
        options.add(ssuper);
        sclass = new JCheckBoxMenuItem("Service classes", false);
        options.add(sclass);
        bar.add(options);
        JMenu services = new JMenu("Services");
        services.addMenuListener(wrap(new Services(services)));
        bar.add(services);
        JMenu attrs = new JMenu("Attributes");
        attrs.addMenuListener(wrap(new Entries(attrs)));
        bar.add(attrs);
        setJMenuBar(bar);

        getContentPane().setLayout(new BorderLayout());
        int textRows = 8;
        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true);
        if (isAdmin) {
            textRows = 4;
            JPanel bpanel = new JPanel();
            bpanel.setLayout(new BorderLayout());

            TitledBorder border = BorderFactory.createTitledBorder("Matching Services");
            border.setTitlePosition(TitledBorder.TOP);
            border.setTitleJustification(TitledBorder.LEFT);
            bpanel.setBorder(border);

            listModel = new DefaultListModel();
            list = new JList(listModel);
            list.setFixedCellHeight(20);
            list.setCellRenderer((ListCellRenderer)
                                     wrap(new ServiceItemRenderer(), ListCellRenderer.class));
            list.addMouseListener(wrap(new MouseReceiver(new ServiceListPopup())));
            listScrollPane = new JScrollPane(list);
            bpanel.add(listScrollPane, BorderLayout.CENTER);
            splitPane.setBottomComponent(bpanel);
        }
        text = new JTextArea(genText(false), textRows, 40);
        text.setEditable(false);
        JScrollPane scroll = new JScrollPane(text);
        splitPane.setTopComponent(scroll);
        getContentPane().add(splitPane, BorderLayout.CENTER);

        validate();
        SwingUtilities.invokeLater(wrap(new Runnable() {
            public void run() {
                pack();
                setSize(new Dimension(490, 450));
                setVisible(true);
                splitPane.setDividerLocation(65);
            }
        }));
        LookupListener adder = new LookupListener();
        lnotify = new LeaseNotify();
        ((DiscoveryManagement) disco).addDiscoveryListener(adder);
    }

    private void terminate() {
        Browser.this.dispose();
        cancelLease();
        listen.unexport();
    }

    private static String typeName(Class type) {
        String name = type.getName();
        int i = name.lastIndexOf('.');
        if (i >= 0)
            name = name.substring(i + 1);
        return name;
    }

    private void setText(boolean match) {
        text.setText(genText(match));
    }

    private String genText(boolean match) {
        StringBuffer buf = new StringBuffer();
        if (tmpl.serviceTypes.length > 0) {
            for (int i = 0; i < tmpl.serviceTypes.length; i++) {
                buf.append(tmpl.serviceTypes[i].getName());
                buf.append("\n");
            }
        }
        if (tmpl.attributeSetTemplates.length > 0)
            genEntries(buf, tmpl.attributeSetTemplates, false);
        genMatches(buf, match);
        return buf.toString();
    }

    private void genEntries(StringBuffer buf, Entry[] entries, boolean showNulls) {
        for (Entry entry : entries) {
            if (entry == null) {
                buf.append("null\n");
                continue;
            }
            buf.append(typeName(entry.getClass()));
            buf.append(": ");
            try {
                Field[] fields = entry.getClass().getFields();
                for (Field field : fields) {
                    if (!valid(field))
                        continue;
                    Object val = field.get(entry);
                    if (val != null || showNulls) {
                        buf.append(field.getName());
                        buf.append("=");
                        buf.append(val);
                        buf.append(" ");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            buf.append("\n");
        }
    }

    private static boolean valid(Field f) {
        return (f.getModifiers() & (Modifier.STATIC | Modifier.FINAL)) == 0;
    }

    private void genMatches(StringBuffer buf, boolean match) {
        if (isAdmin) {
            list.setModel(dummyModel);    // to keep away from Swing's bug

            listModel.removeAllElements();
            list.clearSelection();
            list.ensureIndexIsVisible(0);
            list.repaint();
            list.revalidate();
            listScrollPane.validate();
        }
        if (lookup == null) {
            String[] groups = disco.getGroups();
            if (groups == null) {
                buf.append("Groups: <all>\n");
            } else if (groups.length > 0) {
                buf.append("Groups:");
                for (String group : groups) {
                    if (group.length() == 0)
                        group = "public";
                    buf.append(" ");
                    buf.append(group);
                }
                buf.append("\n");
            }
            LookupLocator[] locators =
                ((DiscoveryLocatorManagement) disco).getLocators();
            if (locators.length > 0) {
                buf.append("Addresses:");
                for (LookupLocator locator : locators) {
                    buf.append(" ");
                    buf.append(locator.getHost());
                    if (locator.getPort() != Constants.discoveryPort) {
                        buf.append(":");
                        buf.append(locator.getPort());
                    }
                }
                buf.append("\n");
            }
            if (!(registrars.getMenuComponent(0) instanceof
                      JRadioButtonMenuItem)) {
                buf.append("No registrars to select");
                return;
            }
            int n = registrars.getMenuComponentCount();
            if (n == 1) {
                buf.append("1 registrar, not selected");
            } else {
                buf.append(n);
                buf.append(" registrars, none selected");
            }
            return;
        }
        ServiceMatches matches;
        try {
            matches = lookup.lookup(tmpl, (match || isAdmin) ? 1000 : 0);
        } catch (Throwable t) {
            logger.log(Level.INFO, "lookup failed", t);
            return;
        }

        if (matches.items != null) {
            for (int i = 0; i < matches.items.length; i++) {
                if (matches.items[i].service != null) {
                    try {
                        matches.items[i].service =
                            servicePreparer.prepareProxy(
                                                            matches.items[i].service);
                    } catch (Throwable t) {
                        logger.log(Level.INFO, "proxy preparation failed", t);
                        matches.items[i].service = null;
                    }
                }
            }
        }

        if (isAdmin && matches.items != null) {
            for (int i = 0; i < matches.items.length; i++)
                listModel.addElement(new ServiceListItem(matches.items[i]));
            list.setModel(listModel);
            list.clearSelection();
            list.ensureIndexIsVisible(0);
            list.repaint();
            list.revalidate();
            listScrollPane.validate();
        }

        if (!match &&
            tmpl.serviceTypes.length == 0 &&
            tmpl.attributeSetTemplates.length == 0) {
            buf.append("Total services registered: ");
            buf.append(matches.totalMatches);
            return;
        }
        buf.append("\nMatching services: ");
        buf.append(matches.totalMatches);

        if (!isAdmin && matches.items != null) {
            if (!match)
                return;
            buf.append("\n\n");
            for (int i = 0; i < matches.items.length; i++) {
                ServiceItem item = matches.items[i];
                buf.append("Service ID: ");
                buf.append(item.serviceID);
                buf.append("\n");
                buf.append("Service instance: ");
                buf.append(item.service);
                buf.append("\n");
                genEntries(buf, item.attributeSets, true);
                buf.append("\n");
            }
        }
    }

    private static void addNone(JMenu menu) {
        JMenuItem item = new JMenuItem("(none)");
        item.setEnabled(false);
        menu.add(item);
    }

    private void addOne(ServiceRegistrar registrar) {
        LookupLocator loc;
        try {
            loc = registrar.getLocator();
        } catch (Throwable t) {
            logger.log(Level.INFO, "obtaining locator failed", t);
            return;
        }
        String host = loc.getHost();
        if (loc.getPort() != Constants.discoveryPort)
            host += ":" + loc.getPort();
        JRadioButtonMenuItem reg =
            new RegistrarMenuItem(host, registrar.getServiceID());
        reg.addActionListener(wrap(new Lookup(registrar)));
        if (!(registrars.getMenuComponent(0)
                  instanceof JRadioButtonMenuItem))
            registrars.removeAll();
        registrars.add(reg);
    }

    private static class RegistrarMenuItem extends JRadioButtonMenuItem {
        ServiceID id;

        RegistrarMenuItem(String host, ServiceID id) {
            super(host);
            this.id = id;
        }
    }

    static Class[] getInterfaces(Class c) {
        Set<Class> set = new HashSet<Class>();
        for (; c != null; c = c.getSuperclass()) {
            Class[] ifs = c.getInterfaces();
            for (int i = ifs.length; --i >= 0; )
                set.add(ifs[i]);
        }
        return set.toArray(new Class[set.size()]);
    }

    private class Services implements MenuListener {
        private JMenu menu;

        public Services(JMenu menu) {
            this.menu = menu;
        }

        public void menuSelected(MenuEvent ev) {
            if (lookup == null) {
                addNone(menu);
                return;
            }
            List<Class> all = new ArrayList<Class>();
            Class[] types = tmpl.serviceTypes;
            for (int i = 0; i < types.length; i++) {
                all.add(types[i]);
                JCheckBoxMenuItem item =
                    new JCheckBoxMenuItem(types[i].getName(), true);
                item.addActionListener(wrap(new Service(types[i], i)));
                menu.add(item);
            }
            try {
                types = lookup.getServiceTypes(tmpl, "");
            } catch (Throwable t) {
                failure(t);
                return;
            }
            if (types == null) {
                if (all.isEmpty())
                    addNone(menu);
                return;
            }
            for (Class type : types) {
                Class[] stypes;
                if (type == null) {
                    continue;
                }
                if (type.isInterface() || sclass.getState()) {
                    stypes = new Class[]{type};
                } else {
                    stypes = getInterfaces(type);
                }
                for (Class stype : stypes) {
                    addType(stype, all);
                }
            }
        }

        private void addType(Class type, List<Class> all) {
            if (all.contains(type))
                return;
            all.add(type);
            JCheckBoxMenuItem item =
                new JCheckBoxMenuItem(type.getName(), false);
            item.addActionListener(wrap(new Service(type, -1)));
            menu.add(item);
            if (!ssuper.getState())
                return;
            if (sclass.getState() && type.getSuperclass() != null)
                addType(type.getSuperclass(), all);
            Class[] stypes = type.getInterfaces();
            for (Class stype : stypes) {
                addType(stype, all);
            }
        }

        public void menuDeselected(MenuEvent ev) {
            menu.removeAll();
        }

        public void menuCanceled(MenuEvent ev) {
            menu.removeAll();
        }
    }

    /**
     * Indicates whether auto confirm is enabled to prevent from the user
     * having to click the 'Yes' button in the a popup window to confirm a
     * modification to the service browser pane is allowed to take place as
     * result of a service being removed, or its lookup attributes being
     * changed.
     *
     * @return <code>true</code> in case no popup is required to have the user
     *         confirm the modifications, <code>false</code> otherwise
     */
    boolean isAutoConfirm() {
        return autoConfirm;
    }

    ActionListener wrap(ActionListener l) {
        return (ActionListener) wrap(l, ActionListener.class);
    }

    MenuListener wrap(MenuListener l) {
        return (MenuListener) wrap(l, MenuListener.class);
    }

    MouseListener wrap(MouseListener l) {
        return (MouseListener) wrap(l, MouseListener.class);
    }

    WindowListener wrap(WindowListener a) {
        return (WindowListener) wrap(a, WindowListener.class);
    }

    Runnable wrap(Runnable r) {
        return (Runnable) wrap(r, Runnable.class);
    }

    private Object wrap(Object obj, Class iface) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                                      new Class[]{iface}, new Handler(obj));
    }

    private class Handler implements InvocationHandler {
        private final Object obj;

        Handler(Object obj) {
            this.obj = obj;
        }

        public Object invoke(Object proxy,
                             final Method method,
                             final Object[] args)
            throws Throwable {
            if (method.getDeclaringClass() == Object.class) {
                if ("equals".equals(method.getName()))
                    return proxy == args[0];
                else if ("hashCode".equals(method.getName()))
                    return System.identityHashCode(proxy);
            }
            try {
                return AccessController.doPrivileged(ctx.wrap(new PrivilegedExceptionAction() {
                                                            public Object run() throws Exception {
                                                                Thread t = Thread.currentThread();
                                                                ClassLoader occl = t.getContextClassLoader();
                                                                try {
                                                                    t.setContextClassLoader(ccl);
                                                                    try {
                                                                        return method.invoke(obj, args);
                                                                    } catch (InvocationTargetException e) {
                                                                        Throwable tt = e.getCause();
                                                                        if (tt instanceof Error)
                                                                            throw (Error) tt;
                                                                        throw (Exception) tt;
                                                                    }
                                                                } finally {
                                                                    t.setContextClassLoader(occl);
                                                                }
                                                            }
                                                        }), ctx.getAccessControlContext());
            } catch (PrivilegedActionException e) {
                throw e.getCause();
            }
        }
    }

    private class Show implements ActionListener {

        public void actionPerformed(ActionEvent ev) {
            setText(true);
        }
    }

    private void resetTmpl() {
        tmpl.serviceTypes = new Class[0];
        tmpl.attributeSetTemplates = new Entry[0];
        update();
    }

    private void reset() {
        ssuper.setState(false);
        esuper.setState(false);
        sclass.setState(false);
        resetTmpl();
    }

    private class Reset implements ActionListener {

        public void actionPerformed(ActionEvent ev) {
            reset();
        }
    }

    private class Service implements ActionListener {
        private Class type;
        private int index;

        public Service(Class type, int index) {
            this.type = type;
            this.index = index;
        }

        public void actionPerformed(ActionEvent ev) {
            int z = tmpl.serviceTypes.length;
            Class[] newTypes;
            if (index < 0) {
                newTypes = new Class[z + 1];
                System.arraycopy(tmpl.serviceTypes, 0, newTypes, 0, z);
                newTypes[z] = type;
            } else {
                newTypes = new Class[z - 1];
                System.arraycopy(tmpl.serviceTypes, 0,
                                 newTypes, 0, index);
                System.arraycopy(tmpl.serviceTypes, index + 1,
                                 newTypes, index, z - index - 1);
            }
            tmpl.serviceTypes = newTypes;
            update();
        }
    }

    private class Entries implements MenuListener {
        private JMenu menu;

        public Entries(JMenu menu) {
            this.menu = menu;
        }

        public void menuSelected(MenuEvent ev) {
            if (lookup == null) {
                addNone(menu);
                return;
            }
            Entry[] attrs = tmpl.attributeSetTemplates;
            for (int i = 0; i < attrs.length; i++) {
                Class type = attrs[i].getClass();
                JMenu item = new JMenu(typeName(type));
                item.addMenuListener(new Fields(item, i));
                menu.add(item);
            }
            Class[] types;
            try {
                types = lookup.getEntryClasses(tmpl);
            } catch (Throwable t) {
                failure(t);
                return;
            }
            if (types == null) {
                if (attrs.length == 0)
                    addNone(menu);
                return;
            }
            List<Class> all = new ArrayList<Class>();
            for (Class type : types) {
                if (type == null)
                    menu.add(new JMenuItem("null"));
                else
                    addType(type, all);
            }
        }

        private void addType(Class type, List<Class> all) {
            if (all.contains(type))
                return;
            all.add(type);
            JCheckBoxMenuItem item =
                new JCheckBoxMenuItem(typeName(type), false);
            item.addActionListener(wrap(new AttrSet(type)));
            menu.add(item);
            if (esuper.getState() &&
                Entry.class.isAssignableFrom(type.getSuperclass()))
                addType(type.getSuperclass(), all);
        }

        public void menuDeselected(MenuEvent ev) {
            menu.removeAll();
        }

        public void menuCanceled(MenuEvent ev) {
            menu.removeAll();
        }
    }

    private class AttrSet implements ActionListener {
        private Class type;

        public AttrSet(Class type) {
            this.type = type;
        }

        public void actionPerformed(ActionEvent ev) {
            Entry ent;
            try {
                ent = (Entry) type.newInstance();
            } catch (Throwable t) {
                logger.log(Level.INFO, "creating entry failed", t);
                return;
            }
            int z = tmpl.attributeSetTemplates.length;
            Entry[] newSets = new Entry[z + 1];
            System.arraycopy(tmpl.attributeSetTemplates, 0, newSets, 0, z);
            newSets[z] = ent;
            tmpl.attributeSetTemplates = newSets;
            update();
        }
    }

    private class Fields implements MenuListener {
        private JMenu menu;
        private int index;

        public Fields(JMenu menu, int index) {
            this.menu = menu;
            this.index = index;
        }

        public void menuSelected(MenuEvent ev) {
            JRadioButtonMenuItem match = new JRadioButtonMenuItem("(match)");
            match.setSelected(true);
            match.addActionListener(wrap(new Unmatch(index)));
            menu.add(match);
            Entry ent = tmpl.attributeSetTemplates[index];
            Field[] fields = ent.getClass().getFields();
            for (Field field : fields) {
                if (!valid(field))
                    continue;
                try {
                    if (field.get(ent) != null) {
                        JCheckBoxMenuItem item = new JCheckBoxMenuItem(field.getName(), true);
                        item.addActionListener(wrap(new Value(index, field, null)));
                        menu.add(item);
                    } else {
                        JMenu item = new JMenu(field.getName());
                        item.addMenuListener(wrap(new Values(item, index, field)));
                        menu.add(item);
                    }
                } catch (Throwable t) {
                    logger.log(Level.INFO, "getting fields failed", t);
                }
            }
        }

        public void menuDeselected(MenuEvent ev) {
            menu.removeAll();
        }

        public void menuCanceled(MenuEvent ev) {
            menu.removeAll();
        }
    }

    private class Unmatch implements ActionListener {
        private int index;

        public Unmatch(int index) {
            this.index = index;
        }

        public void actionPerformed(ActionEvent ev) {
            int z = tmpl.attributeSetTemplates.length;
            Entry[] newSets = new Entry[z - 1];
            System.arraycopy(tmpl.attributeSetTemplates, 0,
                             newSets, 0, index);
            System.arraycopy(tmpl.attributeSetTemplates, index + 1,
                             newSets, index, z - index - 1);
            tmpl.attributeSetTemplates = newSets;
            update();
        }
    }

    private class Values implements MenuListener {
        private JMenu menu;
        private int index;
        private Field field;

        public Values(JMenu menu, int index, Field field) {
            this.menu = menu;
            this.index = index;
            this.field = field;
        }

        public void menuSelected(MenuEvent ev) {
            Object[] values;
            try {
                values = lookup.getFieldValues(tmpl, index, field.getName());
            } catch (Throwable t) {
                failure(t);
                return;
            }
            if (values == null) {
                addNone(menu);
                return;
            }
            for (Object value : values) {
                JMenuItem item = new JMenuItem(value.toString());
                item.addActionListener(wrap(new Value(index, field, value)));
                menu.add(item);
            }
        }

        public void menuDeselected(MenuEvent ev) {
            menu.removeAll();
        }

        public void menuCanceled(MenuEvent ev) {
            menu.removeAll();
        }
    }

    private class Value implements ActionListener {
        private int index;
        private Field field;
        private Object value;

        public Value(int index, Field field, Object value) {
            this.index = index;
            this.field = field;
            this.value = value;
        }

        public void actionPerformed(ActionEvent ev) {
            try {
                field.set(tmpl.attributeSetTemplates[index], value);
            } catch (Throwable t) {
                logger.log(Level.INFO, "setting attribute value failed", t);
            }
            update();
        }
    }

    private class Listener implements RemoteEventListener, ServerProxyTrust {
        private final Exporter exporter;
        final RemoteEventListener proxy;

        public Listener() throws ConfigurationException, ExportException {
            exporter = (Exporter)Config.getNonNullEntry(config, 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(wrap(new Runnable() {
                public void run() {
                    if (eventID == ev.getID() &&
                        seqNo < ev.getSequenceNumber() &&
                        eventSource != null &&
                        eventSource.equals(ev.getSource())) {
                        seqNo = ev.getSequenceNumber();
                        setText(false);
                    }
                }
            }));
        }

        public TrustVerifier getProxyVerifier() {
            return new BasicProxyTrustVerifier(proxy);
        }

        void unexport() {
            exporter.unexport(true);
        }
    }

    private class LookupListener implements DiscoveryListener {

        public void discovered(DiscoveryEvent e) {
            final ServiceRegistrar[] newregs = e.getRegistrars();
            SwingUtilities.invokeLater(wrap(new Runnable() {
                public void run() {
                    for (ServiceRegistrar newreg : newregs) {
                        addOne(newreg);
                    }
                    if (lookup == null)
                        setText(false);
                }
            }));
        }

        public void discarded(DiscoveryEvent e) {
            final ServiceRegistrar[] regs = e.getRegistrars();
            SwingUtilities.invokeLater(wrap(new Runnable() {
                public void run() {
                    for (ServiceRegistrar reg : regs) {
                        ServiceID id = reg.getServiceID();
                        if (lookup != null &&
                            id.equals(lookup.getServiceID())) {
                            lookup = null;
                            seqNo = Long.MAX_VALUE;
                        }
                        for (int j = 0;
                             j < registrars.getMenuComponentCount();
                             j++) {
                            JMenuItem item =
                                (JMenuItem) registrars.getMenuComponent(j);
                            if (item instanceof RegistrarMenuItem &&
                                id.equals(((RegistrarMenuItem) item).id)) {
                                item.setSelected(false);
                                registrars.remove(item);
                                if (registrars.getMenuComponentCount() == 0)
                                    addNone(registrars);
                                break;
                            }
                        }
                    }
                    if (lookup == null)
                        resetTmpl();
                }
            }));
        }
    }

    private void setGroups(String[] groups) {
        ((DiscoveryLocatorManagement) disco).setLocators(new LookupLocator[0]);
        try {
            disco.setGroups(groups);
        } catch (Throwable t) {
            logger.log(Level.INFO, "setting groups failed", t);
        }
        resetTmpl();
    }

    private class AllFind implements ActionListener {

        public void actionPerformed(ActionEvent ev) {
            setGroups(null);
        }
    }

    private class PubFind implements ActionListener {

        public void actionPerformed(ActionEvent ev) {
            setGroups(new String[]{""});
        }
    }

    private class MultiFind implements ActionListener {

        public void actionPerformed(ActionEvent ev) {
            String names = JOptionPane.showInputDialog(Browser.this,
                                                       "Enter group names");
            if (names == null)
                return;
            setGroups(parseList(names, true));
        }
    }

    private class UniFind implements ActionListener {

        public void actionPerformed(ActionEvent ev) {
            String list =
                JOptionPane.showInputDialog(Browser.this,
                                            "Enter host[:port] addresses");
            if (list == null)
                return;
            String[] addrs = parseList(list, false);
            LookupLocator[] locs = new LookupLocator[addrs.length];
            for (int i = 0; i < addrs.length; i++) {
                try {
                    locs[i] = new ConstrainableLookupLocator(
                                                                "jini://" + addrs[i], locatorConstraints);
                } catch (MalformedURLException e) {
                    JOptionPane.showMessageDialog(Browser.this,
                                                  "\"" + addrs[i] + "\": " +
                                                  e.getMessage(),
                                                  "Bad Address",
                                                  JOptionPane.ERROR_MESSAGE);
                    return;
                }
            }
            try {
                disco.setGroups(new String[0]);
            } catch (Throwable t) {
                logger.log(Levels.HANDLED, "setting groups failed", t);
            }
            ((DiscoveryLocatorManagement) disco).setLocators(locs);
            resetTmpl();
        }
    }

    private class Lookup implements ActionListener {
        private ServiceRegistrar registrar;

        public Lookup(ServiceRegistrar registrar) {
            this.registrar = registrar;
        }

        public void actionPerformed(ActionEvent ev) {
            if (lookup == registrar) {
                lookup = null;
            } else {
                lookup = registrar;
            }
            seqNo = Long.MAX_VALUE;
            for (int i = 0; i < registrars.getMenuComponentCount(); i++) {
                JMenuItem item = (JMenuItem) registrars.getMenuComponent(i);
                if (item != ev.getSource())
                    item.setSelected(false);
            }
            resetTmpl();
        }
    }

    static class LeaseNotify implements LeaseListener {
        public void notify(LeaseRenewalEvent ev) {
            if (ev.getException() != null)
                logger.log(Level.INFO, "lease renewal failed",
                           ev.getException());
            else
                logger.log(Level.INFO, "lease renewal failed");
        }
    }

    private static String[] parseList(String names, boolean groups) {
        StringTokenizer st = new StringTokenizer(names, " \t\n\r\f,");
        String[] elts = new String[st.countTokens()];
        for (int i = 0; st.hasMoreTokens(); i++) {
            elts[i] = st.nextToken();
            if (groups && elts[i].equalsIgnoreCase("public"))
                elts[i] = "";
        }
        return elts;
    }

    private void cancelLease() {
        if (elease != null) {
            try {
                leaseMgr.cancel(elease);
            } catch (Throwable t) {
                logger.log(Levels.HANDLED, "lease cancellation failed", t);
            }
            elease = null;
            eventSource = null;
        }
    }

    private void update() {
        setText(false);
        cancelLease();
        if (lookup == null)
            return;
        try {
            EventRegistration reg =
                lookup.notify(tmpl,
                              ServiceRegistrar.TRANSITION_MATCH_NOMATCH |
                              ServiceRegistrar.TRANSITION_NOMATCH_MATCH |
                              ServiceRegistrar.TRANSITION_MATCH_MATCH,
                              listen.proxy, null, Lease.ANY);
            elease = (Lease) leasePreparer.prepareProxy(reg.getLease());
            leaseMgr.renewUntil(elease, Lease.ANY, lnotify);
            eventSource = reg.getSource();
            eventID = reg.getID();
            seqNo = reg.getSequenceNumber();
        } catch (Throwable t) {
            failure(t);
        }
    }

    private void failure(Throwable t) {
        logger.log(Level.INFO, "call to lookup service failed", t);
        ((DiscoveryManagement) disco).discard(lookup);
    }

    class ServiceItemRenderer implements ListCellRenderer {
        private JLabel label;

        public ServiceItemRenderer() {
            label = new JLabel();
            label.setOpaque(true);
        }

        public Component getListCellRendererComponent(JList list,
                                                      Object value,
                                                      int index,
                                                      boolean isSelected,
                                                      boolean cellHasFocus) {
            ServiceListItem item = null;
            if (value instanceof ServiceListItem)
                item = (ServiceListItem) value;

            label.setFont(list.getFont());

            if (isSelected) {
                label.setBackground(list.getSelectionBackground());
                label.setForeground(list.getSelectionForeground());
            } else {
                label.setBackground(list.getBackground());
                label.setForeground(list.getForeground());
            }
            if (item != null) {
                // accessible check done in this method
                label.setIcon(item.getIcon());
                label.setText(item.getTitle());
            } else
                label.setText(value.toString());

            return label;
        }
    }

    private static Icon[] icons = new Icon[3];

    static {
        // Administrable Service, Controllable Attribute
        icons[0] = MetalIcons.getBlueFolderIcon();
        // Non-administrable Service
        icons[1] = MetalIcons.getGrayFolderIcon();
        // "Connection Refused" Service
        icons[2] = MetalIcons.getUnusableFolderIcon();
    }

    private class ServiceListItem {
        private ServiceItem item;
        private boolean isAccessible;
        private Object admin = null;

        public ServiceListItem(ServiceItem item) {
            this.item = item;
            isAccessible = (item.service != null);
        }

        public String getTitle() {
            if (item.service == null)
                return "Unknown service";

            Set<String> set = new HashSet<String>();
            Class[] infs = getInterfaces(item.service.getClass());
            for (Class inf : infs)
                set.add(inf.getName());

            // remove known interfaces
            set.removeAll(ignoreInterfaces);

            String title;
            if (set.size() == 1) {
                Iterator iter = set.iterator();
                title = (String) iter.next();
            } else {
                title = item.service.getClass().getName();
                title += " [";
                for (Iterator iter = set.iterator(); iter.hasNext(); ) {
                    title += (String) iter.next();
                    if (iter.hasNext())
                        title += ", ";
                }
                title += "]";
            }
            if (!isAccessible)
                title += " (Stale service)";
            return title;
        }

        public boolean isAccessible() {
            getAdmin();
            return isAccessible;
        }

        public Object getAdmin() {
            if (admin == null &&
                isAccessible &&
                item.service instanceof Administrable) {
                try {
                    admin = adminPreparer.prepareProxy(((Administrable) item.service).getAdmin());
                } catch (Throwable t) {
                    logger.log(Levels.HANDLED, "failed to get admin proxy", t);
                    isAccessible = false;
                }
            }
            return admin;
        }

        public boolean isAdministrable() {
            getAdmin();
            return (admin instanceof DestroyAdmin ||
                    admin instanceof JoinAdmin ||
                    admin instanceof DiscoveryAdmin);
        }

        public ServiceItem getServiceItem() {
            return item;
        }

        public Icon getIcon() {
            if (!isAccessible())
                return icons[2];
            else if (isAdministrable())
                return icons[0];
            else
                return icons[1];
        }

        public String toString() {
            return isAccessible() ?
                   item.service.getClass().getName() : "Unknown service";
        }
    }

    private boolean isUI(ServiceItem item) {
        Entry[] attrs = item.attributeSets;
        if ((attrs != null) && (attrs.length != 0)) {
            for (Entry attr : attrs) {
                if (attr instanceof UIDescriptor) {
                    return true;
                }
            }
        }
        return false;
    }

    private class MouseReceiver extends MouseAdapter {
        private ServiceListPopup popup;

        public MouseReceiver(ServiceListPopup popup) {
            this.popup = popup;
        }

        public void mouseClicked(MouseEvent ev) {
            if (ev.getClickCount() >= 2) {
                ServiceListItem listItem = getTargetListItem(ev);
                if (listItem != null) {
                    ServiceItem item = listItem.getServiceItem();
                    if (listItem.isAdministrable()) {
                        JDialog dialog = ServiceEditor.getDialog(item, listItem.getAdmin(), lookup,
                                                                 Browser.this);
                        dialog.setVisible(true);
                    } else if (listItem.isAccessible()) {
                        new ServiceBrowser(item, lookup, Browser.this).setVisible(true);
                    }
                }
            }
        }

        public void mouseReleased(MouseEvent ev) {
            if (ev.isPopupTrigger() && (getTargetListItem(ev) != null)) {
                popup.setServiceItem(getTargetListItem(ev));
                popup.show(ev.getComponent(), ev.getX(), ev.getY());
            }
        }

        public void mousePressed(MouseEvent ev) {
            if (ev.isPopupTrigger() && (getTargetListItem(ev) != null)) {
                popup.setServiceItem(getTargetListItem(ev));
                popup.show(ev.getComponent(), ev.getX(), ev.getY());
            }
        }

        private ServiceListItem getTargetListItem(MouseEvent ev) {
            int index = list.locationToIndex(ev.getPoint());
            if (index >= 0)
                return (ServiceListItem) listModel.getElementAt(index);
            else
                return null;
        }
    }

    private class ServiceListPopup extends JPopupMenu implements ActionListener, PopupMenuListener {
        protected JMenuItem infoItem;
        protected JMenuItem browseItem;
        protected JMenuItem adminItem;
        protected JMenuItem spaceItem;
        protected ServiceListItem listItem;
        protected JMenuItem uiItem;
        protected ServiceItem item;

        public ServiceListPopup() {
            super();

            ActionListener me = wrap(this);
            infoItem = new JMenuItem("Show Info");
            infoItem.addActionListener(me);
            infoItem.setActionCommand("showInfo");
            add(infoItem);

            browseItem = new JMenuItem("Browse Service");
            browseItem.addActionListener(me);
            browseItem.setActionCommand("browseService");
            add(browseItem);

            adminItem = new JMenuItem("Admin Service");
            adminItem.addActionListener(me);
            adminItem.setActionCommand("adminService");
            add(adminItem);

            spaceItem = new JMenuItem("Browse Entries");
            spaceItem.addActionListener(me);
            spaceItem.setActionCommand("browseEntry");
            add(spaceItem);

            uiItem = new JMenuItem("Show UI");
            uiItem.addActionListener(me);
            uiItem.setActionCommand("showUI");
            add(uiItem);

            addPopupMenuListener(this);
            setOpaque(true);
            setLightWeightPopupEnabled(true);
        }

        public void setServiceItem(ServiceListItem listItem) {
            this.listItem = listItem;
            item = listItem.getServiceItem();
            infoItem.setEnabled(listItem.isAccessible());
            browseItem.setEnabled(listItem.isAccessible());
            adminItem.setEnabled(listItem.isAdministrable());
            uiItem.setEnabled(isUI(item));
        }

        public void actionPerformed(ActionEvent ev) {
            String command = ev.getActionCommand();

            if (command.equals("showInfo")) {
                Class[] infs = 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(Browser.this,
                                              msg,
                                              "ServiceItem Information",
                                              JOptionPane.INFORMATION_MESSAGE);
            } else if (command.equals("browseService")) {
                new ServiceBrowser(item, lookup, Browser.this).setVisible(true);
            } else if (command.equals("adminService")) {
                JDialog dialog = ServiceEditor.getDialog(item, listItem.getAdmin(), lookup, Browser.this);
                dialog.setVisible(true);
            } else if (command.equals("showUI")) {
                if (!isUI(item)) {
                    return;
                }
                try {
                    new AdminFrame(item, Browser.this);
                } catch (Exception e) {
                    Util.showError(e, Browser.this, "Unable to create AdminFrame");
                }
            }
        }

        public void popupMenuWillBecomeVisible(PopupMenuEvent ev) {
        }

        public void popupMenuWillBecomeInvisible(PopupMenuEvent ev) {
        }

        public void popupMenuCanceled(PopupMenuEvent ev) {
        }
    }
}
TOP

Related Classes of org.rioproject.tools.ui.browser.Browser$Handler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.