blob: 16933fb01a6f52ba6c0efc0c15a9ee1bd403c0b9 [file] [log] [blame]
/*
* 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.apache.river.container.examples.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 com.sun.jini.start.LifeCycle;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.rmi.server.ExportException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
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 net.jini.admin.Administrable;
import net.jini.admin.JoinAdmin;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import net.jini.config.ConfigurationProvider;
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.ServiceID;
import net.jini.core.lookup.ServiceItem;
import net.jini.core.lookup.ServiceMatches;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.discovery.Constants;
import net.jini.discovery.ConstrainableLookupLocator;
import net.jini.discovery.DiscoveryEvent;
import net.jini.discovery.DiscoveryGroupManagement;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryLocatorManagement;
import net.jini.discovery.DiscoveryManagement;
import net.jini.discovery.LookupDiscoveryManager;
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.ui.factory.JFrameFactory;
import net.jini.lookup.entry.UIDescriptor;
import net.jini.security.BasicProxyPreparer;
import net.jini.security.ProxyPreparer;
import net.jini.security.Security;
import net.jini.security.SecurityContext;
import net.jini.security.TrustVerifier;
import net.jini.security.proxytrust.ServerProxyTrust;
import net.jini.space.JavaSpace05;
import net.jini.space.JavaSpace;
/*
* 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.
*
* @author Sun Microsystems, Inc.
*/
public class Browser extends JFrame {
static final String BROWSER = "org.apache.river.container.examples.browser";
static final Logger logger = Logger.getLogger(BROWSER);
private transient SecurityContext ctx;
private transient ClassLoader ccl;
transient Configuration config;
private transient DiscoveryGroupManagement disco;
private transient ServiceRegistrar lookup = null;
private transient Object eventSource = null;
private transient long eventID = 0;
private transient long seqNo = Long.MAX_VALUE;
private transient ActionListener exiter;
private transient ServiceTemplate tmpl;
private transient Listener listen;
private transient LookupListener adder;
private transient Lease elease = null;
transient ProxyPreparer leasePreparer;
transient ProxyPreparer servicePreparer;
transient ProxyPreparer adminPreparer;
private transient MethodConstraints locatorConstraints;
transient LeaseRenewalManager leaseMgr;
private transient LeaseListener lnotify;
private transient List ignoreInterfaces;
private transient JTextArea text;
private transient JMenu registrars;
private transient JCheckBoxMenuItem esuper;
private transient JCheckBoxMenuItem ssuper;
private transient JCheckBoxMenuItem sclass;
private transient boolean isAdmin;
private volatile transient boolean autoConfirm;
private transient JList list;
private transient DefaultListModel listModel;
private transient DefaultListModel dummyModel = new DefaultListModel();
private transient JScrollPane listScrollPane;
/**
* Creates an instance with the given action listener for the Exit menu item
* and the given configuration. The action listener defaults to an instance
* of {@link Exit Exit}. The action listener can be overridden by a
* configuration entry. The configuration defaults to an empty
* configuration.
*
* @param exiter the action listener, or <code>null</code>
* @param config the configuration, or <code>null</code>
*/
public Browser(ActionListener exiter, Configuration config)
throws ConfigurationException, IOException {
if (exiter == null) {
exiter = new Exit();
}
if (config == null) {
config = EmptyConfiguration.INSTANCE;
}
init(exiter, config);
}
private void init(ActionListener exiter, Configuration config)
throws ConfigurationException, IOException {
exiter = wrap((ActionListener) Config.getNonNullEntry(config, BROWSER, "exitActionListener",
ActionListener.class, exiter));
this.exiter = exiter;
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)).booleanValue();
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)).booleanValue();
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(exiter);
file.add(exit);
bar.add(file);
addWindowListener(new Exiter());
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;
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, "Center");
getContentPane().add(bpanel, "South");
}
text = new JTextArea(genText(false), textRows, 40);
text.setEditable(false);
JScrollPane scroll = new JScrollPane(text);
getContentPane().add(scroll, "Center");
validate();
SwingUtilities.invokeLater(wrap(new Runnable() {
public void run() {
pack();
show();
}
}));
adder = new LookupListener();
lnotify = new LeaseNotify();
((DiscoveryManagement) disco).addDiscoveryListener(adder);
}
/**
* Creates an instance with the given command line arguments and life cycle
* callback. See the package documentation for details of the command line
* arguments. The default action listener for the Exit menu item calls the
* {@link #dispose dispose} method of this instance, cancels any lookup
* service event registration lease, unexports any remote event listener,
* and calls the {@link LifeCycle#unregister unregister} method of the life
* cycle callback. The action listener can be overridden by a configuration
* entry.
*
* @param args command line arguments
* @param lc life cycle callback, or <code>null</code>.
*/
public Browser(String[] args, final LifeCycle lc)
throws ConfigurationException, LoginException, IOException {
final ActionListener exiter = new ActionListener() {
public void actionPerformed(ActionEvent ev) {
Browser.this.dispose();
cancelLease();
listen.unexport();
if (lc != null) {
lc.unregister(Browser.this);
}
System.exit(0);
}
};
final Configuration config =
ConfigurationProvider.getInstance(
args, Browser.class.getClassLoader());
LoginContext login =
(LoginContext) config.getEntry(BROWSER, "loginContext",
LoginContext.class, null);
if (login == null) {
init(exiter, config);
} else {
login.login();
try {
Subject.doAsPrivileged(
login.getSubject(),
new PrivilegedExceptionAction() {
public Object run()
throws ConfigurationException, IOException {
init(exiter, config);
return null;
}
},
null);
} catch (PrivilegedActionException pae) {
Exception e = pae.getException();
if (e instanceof ConfigurationException) {
throw (ConfigurationException) e;
}
throw (IOException) e;
}
}
}
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 (int i = 0; i < entries.length; i++) {
Entry ent = entries[i];
if (ent == null) {
buf.append("null\n");
continue;
}
buf.append(typeName(ent.getClass()));
buf.append(": ");
try {
Field[] fields = ent.getClass().getFields();
for (int j = 0; j < fields.length; j++) {
if (!valid(fields[j])) {
continue;
}
Object val = fields[j].get(ent);
if (val != null || showNulls) {
buf.append(fields[j].getName());
buf.append("=");
buf.append(val);
buf.append(" ");
}
}
} catch (Exception e) {
}
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 (int i = 0; i < groups.length; i++) {
String group = groups[i];
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 (int i = 0; i < locators.length; i++) {
buf.append(" ");
buf.append(locators[i].getHost());
if (locators[i].getPort() != Constants.discoveryPort) {
buf.append(":");
buf.append(locators[i].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) {
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) {
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 set = new HashSet();
for (; c != null; c = c.getSuperclass()) {
Class[] ifs = c.getInterfaces();
for (int i = ifs.length; --i >= 0;) {
set.add(ifs[i]);
}
}
return (Class[]) 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;
}
Vector all = new Vector();
Class[] types = tmpl.serviceTypes;
for (int i = 0; i < types.length; i++) {
all.addElement(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 (int i = 0; i < types.length; i++) {
Class[] stypes;
if (types[i] == null) {
all.addElement(new JMenuItem("null"));
continue;
}
if (types[i].isInterface() || sclass.getState()) {
stypes = new Class[]{types[i]};
} else {
stypes = getInterfaces(types[i]);
}
for (int j = 0; j < stypes.length; j++) {
addType(stypes[j], all);
}
}
}
private void addType(Class type, Vector all) {
if (all.contains(type)) {
return;
}
all.addElement(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 (int i = 0; i < stypes.length; i++) {
addType(stypes[i], 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((Object) l, ActionListener.class);
}
MenuListener wrap(MenuListener l) {
return (MenuListener) wrap((Object) l, MenuListener.class);
}
MouseListener wrap(MouseListener l) {
return (MouseListener) wrap((Object) l, MouseListener.class);
}
WindowListener wrap(WindowListener a) {
return (WindowListener) wrap((Object) a, WindowListener.class);
}
Runnable wrap(Runnable r) {
return (Runnable) wrap((Object) 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 Boolean.valueOf(proxy == args[0]);
} else if ("hashCode".equals(method.getName())) {
return new Integer(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;
}
Vector all = new Vector();
for (int i = 0; i < types.length; i++) {
if (types[i] == null) {
menu.add(new JMenuItem("null"));
} else {
addType(types[i], all);
}
}
}
private void addType(Class type, Vector all) {
if (all.contains(type)) {
return;
}
all.addElement(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 (int i = 0; i < fields.length; i++) {
Field field = fields[i];
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 (int i = 0; i < values.length; i++) {
JMenuItem item = new JMenuItem(values[i].toString());
item.addActionListener(
wrap(new Value(index, field, values[i])));
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 (int i = 0; i < newregs.length; i++) {
addOne(newregs[i]);
}
if (lookup == null) {
setText(false);
}
}
}));
}
public void discarded(DiscoveryEvent e) {
final ServiceRegistrar[] regs = e.getRegistrars();
SwingUtilities.invokeLater(wrap(new Runnable() {
public void run() {
for (int i = 0; i < regs.length; i++) {
ServiceID id = regs[i].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";
}
HashSet set = new HashSet();
Class[] infs = getInterfaces(item.service.getClass());
for (int j = 0; j < infs.length; j++) {
set.add(infs[j].getName());
}
// remove known interfaces
set.removeAll(ignoreInterfaces);
String title = null;
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 boolean isSpaceBrowsable() {
return false;
}
private boolean isUI() {
Entry[] attrs = item.attributeSets;
if ((attrs != null) && (attrs.length != 0)) {
for (int i = 0; i < attrs.length; i++) {
if (attrs[i] instanceof UIDescriptor) {
return true;
}
}
}
return false;
}
public ServiceItem getServiceItem() {
return item;
}
public Entry[] getAttributes() {
return item.attributeSets;
}
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 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()) {
new ServiceEditor(item, listItem.getAdmin(), lookup,
Browser.this).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());
spaceItem.setEnabled(listItem.isSpaceBrowsable());
uiItem.setEnabled(listItem.isUI());
}
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")) {
new ServiceEditor(item, listItem.getAdmin(),
lookup, Browser.this).setVisible(true);
} else if (command.equals("browseEntry")) {
// Not supported at the present time.
} else if (command.equals("showUI")) {
UIDescriptor uiDescriptor = getSelectedUIDescriptor();
if (uiDescriptor == null) {
return;
}
try {
JFrameFactory uiFactory = (JFrameFactory) uiDescriptor.getUIFactory(
Thread.currentThread().getContextClassLoader());
JFrame frame = uiFactory.getJFrame(item);
frame.validate();
frame.setVisible(true);
} catch (Exception e) {
logger.log(Level.INFO, "show ui failed", e);
JOptionPane.showMessageDialog(Browser.this,
e.getMessage(),
e.getClass().getName(),
JOptionPane.WARNING_MESSAGE);
return;
}
}
}
public void popupMenuWillBecomeVisible(PopupMenuEvent ev) {
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent ev) {
}
public void popupMenuCanceled(PopupMenuEvent ev) {
}
private UIDescriptor getSelectedUIDescriptor() {
if (!(new ServiceListItem(item)).isUI()) {
return null;
}
Entry[] attrs = item.attributeSets;
if ((attrs != null) && (attrs.length != 0)) {
for (int i = 0; i < attrs.length; i++) {
if (attrs[i] instanceof UIDescriptor) {
UIDescriptor desc = (UIDescriptor) attrs[i];
if (!"javax.swing".equals(desc.toolkit)) {
continue;
}
return desc;
}
}
}
return null;
}
}
private class Exiter extends WindowAdapter {
public void windowClosing(WindowEvent e) {
Browser.this.exiter.actionPerformed(
new ActionEvent(e.getSource(), e.getID(),
"Exit", System.currentTimeMillis(), 0));
}
}
/**
* An action listener that cancels any lookup service event registration
* lease and then calls {@link System#exit System.exit}.
*/
public static class Exit implements ActionListener {
/**
* Cancels any lookup service event registration lease and calls {@link System#exit System.exit}
* <code>(0)</code>.
*/
public void actionPerformed(ActionEvent ev) {
Object src = ev.getSource();
while (!(src instanceof Browser) && src instanceof Component) {
if (src instanceof JPopupMenu) {
src = ((JPopupMenu) src).getInvoker();
} else {
src = ((Component) src).getParent();
}
}
if (src instanceof Browser) {
try {
((Browser) src).cancelLease();
} catch (Throwable t) {
t.printStackTrace();
}
}
System.exit(0);
}
}
/**
* Runs the service browser. See the package documentation for details.
*
* @param args command line arguments
*/
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
try {
final Configuration config =
ConfigurationProvider.getInstance(
args, Browser.class.getClassLoader());
LoginContext login =
(LoginContext) config.getEntry(BROWSER, "loginContext",
LoginContext.class, null);
if (login != null) {
login.login();
}
PrivilegedExceptionAction action =
new PrivilegedExceptionAction() {
public Object run() throws Exception {
return new Browser(null, config);
}
};
if (login != null) {
Subject.doAsPrivileged(login.getSubject(), action, null);
} else {
action.run();
}
} catch (Throwable t) {
if (t instanceof PrivilegedActionException) {
t = t.getCause();
}
logger.log(Level.SEVERE, "browser initialization failed", t);
}
}
}