/*
* 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) {
}
}
}