mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-12 19:35:24 +00:00
Merge
This commit is contained in:
commit
a9d034a33c
@ -32,6 +32,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
@ -390,7 +391,31 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
if (type instanceof Class)
|
||||
return ((Class) type).getName();
|
||||
else
|
||||
return type.toString();
|
||||
return genericTypeString(type);
|
||||
}
|
||||
|
||||
private static String genericTypeString(Type type) {
|
||||
if (type instanceof Class<?>) {
|
||||
Class<?> c = (Class<?>) type;
|
||||
if (c.isArray())
|
||||
return genericTypeString(c.getComponentType()) + "[]";
|
||||
else
|
||||
return c.getName();
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
GenericArrayType gat = (GenericArrayType) type;
|
||||
return genericTypeString(gat.getGenericComponentType()) + "[]";
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType) type;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(genericTypeString(pt.getRawType())).append("<");
|
||||
String sep = "";
|
||||
for (Type t : pt.getActualTypeArguments()) {
|
||||
sb.append(sep).append(genericTypeString(t));
|
||||
sep = ", ";
|
||||
}
|
||||
return sb.append(">").toString();
|
||||
} else
|
||||
return "???";
|
||||
}
|
||||
|
||||
private final PerInterfaceMap<ConvertingMethod>
|
||||
|
||||
@ -191,6 +191,9 @@ public abstract class SelectableChannel
|
||||
* @throws ClosedChannelException
|
||||
* If this channel is closed
|
||||
*
|
||||
* @throws ClosedSelectorException
|
||||
* If the selector is closed
|
||||
*
|
||||
* @throws IllegalBlockingModeException
|
||||
* If this channel is in blocking mode
|
||||
*
|
||||
@ -246,6 +249,9 @@ public abstract class SelectableChannel
|
||||
* @throws ClosedChannelException
|
||||
* If this channel is closed
|
||||
*
|
||||
* @throws ClosedSelectorException
|
||||
* If the selector is closed
|
||||
*
|
||||
* @throws IllegalBlockingModeException
|
||||
* If this channel is in blocking mode
|
||||
*
|
||||
|
||||
@ -175,6 +175,16 @@ public abstract class AbstractSelectableChannel
|
||||
* the selector is invoked while holding the appropriate locks. The
|
||||
* resulting key is added to this channel's key set before being returned.
|
||||
* </p>
|
||||
*
|
||||
* @throws ClosedSelectorException {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalBlockingModeException {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalSelectorException {@inheritDoc}
|
||||
*
|
||||
* @throws CancelledKeyException {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalArgumentException {@inheritDoc}
|
||||
*/
|
||||
public final SelectionKey register(Selector sel, int ops,
|
||||
Object att)
|
||||
|
||||
@ -265,12 +265,20 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) {
|
||||
ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
|
||||
"JMX EventClient lease renewer %d");
|
||||
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(
|
||||
20, daemonThreadFactory);
|
||||
exec.setKeepAliveTime(1, TimeUnit.SECONDS);
|
||||
exec.allowCoreThreadTimeOut(true);
|
||||
exec.setRemoveOnCancelPolicy(true);
|
||||
return exec;
|
||||
ScheduledThreadPoolExecutor executor =
|
||||
new ScheduledThreadPoolExecutor(20, daemonThreadFactory);
|
||||
executor.setKeepAliveTime(1, TimeUnit.SECONDS);
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
executor.setRemoveOnCancelPolicy(true);
|
||||
// By default, a ScheduledThreadPoolExecutor will keep jobs
|
||||
// in its queue even after they have been cancelled. They
|
||||
// will only be removed when their scheduled time arrives.
|
||||
// Since the job references the LeaseRenewer which references
|
||||
// this EventClient, this can lead to a moderately large number
|
||||
// of objects remaining referenced until the renewal time
|
||||
// arrives. Hence the above call, which removes the job from
|
||||
// the queue as soon as it is cancelled.
|
||||
return executor;
|
||||
}
|
||||
};
|
||||
return leaseRenewerThreadPool.getThreadPoolExecutor(create);
|
||||
@ -381,7 +389,7 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
listenerId =
|
||||
eventClientDelegate.addListener(clientId, name, filter);
|
||||
} catch (EventClientNotFoundException ecnfe) {
|
||||
final IOException ioe = new IOException();
|
||||
final IOException ioe = new IOException(ecnfe.getMessage());
|
||||
ioe.initCause(ecnfe);
|
||||
throw ioe;
|
||||
}
|
||||
@ -488,7 +496,7 @@ public class EventClient implements EventConsumer, NotificationManager {
|
||||
listenerId =
|
||||
eventClientDelegate.addSubscriber(clientId, name, filter);
|
||||
} catch (EventClientNotFoundException ecnfe) {
|
||||
final IOException ioe = new IOException();
|
||||
final IOException ioe = new IOException(ecnfe.getMessage());
|
||||
ioe.initCause(ecnfe);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ public class FetchingEventRelay implements EventRelay {
|
||||
* the fetching.
|
||||
*
|
||||
* @param delegate The {@code EventClientDelegateMBean} to work with.
|
||||
* @param executor Used to do the fetching. A new thread is created if
|
||||
* @param fetchExecutor Used to do the fetching. A new thread is created if
|
||||
* {@code null}.
|
||||
* @throws IOException If failed to work with the {@code delegate}.
|
||||
* @throws MBeanException if unable to add a client to the remote
|
||||
@ -101,12 +101,12 @@ public class FetchingEventRelay implements EventRelay {
|
||||
* @throws IllegalArgumentException If {@code delegate} is {@code null}.
|
||||
*/
|
||||
public FetchingEventRelay(EventClientDelegateMBean delegate,
|
||||
Executor executor) throws IOException, MBeanException {
|
||||
Executor fetchExecutor) throws IOException, MBeanException {
|
||||
this(delegate,
|
||||
DEFAULT_BUFFER_SIZE,
|
||||
DEFAULT_WAITING_TIMEOUT,
|
||||
DEFAULT_MAX_NOTIFICATIONS,
|
||||
executor);
|
||||
fetchExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +120,7 @@ public class FetchingEventRelay implements EventRelay {
|
||||
* @param timeout The waiting time in millseconds when fetching
|
||||
* notifications from an {@code EventClientDelegateMBean}.
|
||||
* @param maxNotifs The maximum notifications to fetch every time.
|
||||
* @param executor Used to do the fetching. A new thread is created if
|
||||
* @param fetchExecutor Used to do the fetching. A new thread is created if
|
||||
* {@code null}.
|
||||
* @throws IOException if failed to communicate with the {@code delegate}.
|
||||
* @throws MBeanException if unable to add a client to the remote
|
||||
@ -133,12 +133,12 @@ public class FetchingEventRelay implements EventRelay {
|
||||
int bufferSize,
|
||||
long timeout,
|
||||
int maxNotifs,
|
||||
Executor executor) throws IOException, MBeanException {
|
||||
Executor fetchExecutor) throws IOException, MBeanException {
|
||||
this(delegate,
|
||||
bufferSize,
|
||||
timeout,
|
||||
maxNotifs,
|
||||
executor,
|
||||
fetchExecutor,
|
||||
FetchingEventForwarder.class.getName(),
|
||||
new Object[] {bufferSize},
|
||||
new String[] {int.class.getName()});
|
||||
@ -155,7 +155,7 @@ public class FetchingEventRelay implements EventRelay {
|
||||
* @param timeout The waiting time in millseconds when fetching
|
||||
* notifications from an {@code EventClientDelegateMBean}.
|
||||
* @param maxNotifs The maximum notifications to fetch every time.
|
||||
* @param executor Used to do the fetching.
|
||||
* @param fetchExecutor Used to do the fetching.
|
||||
* @param forwarderName the class name of a user specific EventForwarder
|
||||
* to create in server to forward notifications to this object. The class
|
||||
* should be a subclass of the class {@link FetchingEventForwarder}.
|
||||
@ -174,7 +174,7 @@ public class FetchingEventRelay implements EventRelay {
|
||||
int bufferSize,
|
||||
long timeout,
|
||||
int maxNotifs,
|
||||
Executor executor,
|
||||
Executor fetchExecutor,
|
||||
String forwarderName,
|
||||
Object[] params,
|
||||
String[] sig) throws IOException, MBeanException {
|
||||
@ -184,11 +184,11 @@ public class FetchingEventRelay implements EventRelay {
|
||||
bufferSize+" "+
|
||||
timeout+" "+
|
||||
maxNotifs+" "+
|
||||
executor+" "+
|
||||
fetchExecutor+" "+
|
||||
forwarderName+" ");
|
||||
}
|
||||
|
||||
if(delegate == null) {
|
||||
if (delegate == null) {
|
||||
throw new NullPointerException("Null EventClientDelegateMBean!");
|
||||
}
|
||||
|
||||
@ -212,16 +212,16 @@ public class FetchingEventRelay implements EventRelay {
|
||||
this.timeout = timeout;
|
||||
this.maxNotifs = maxNotifs;
|
||||
|
||||
if (executor == null) {
|
||||
ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1,
|
||||
daemonThreadFactory);
|
||||
stpe.setKeepAliveTime(1, TimeUnit.SECONDS);
|
||||
stpe.allowCoreThreadTimeOut(true);
|
||||
executor = stpe;
|
||||
this.defaultExecutor = stpe;
|
||||
if (fetchExecutor == null) {
|
||||
ScheduledThreadPoolExecutor executor =
|
||||
new ScheduledThreadPoolExecutor(1, daemonThreadFactory);
|
||||
executor.setKeepAliveTime(1, TimeUnit.SECONDS);
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
fetchExecutor = executor;
|
||||
this.defaultExecutor = executor;
|
||||
} else
|
||||
this.defaultExecutor = null;
|
||||
this.executor = executor;
|
||||
this.fetchExecutor = fetchExecutor;
|
||||
|
||||
startSequenceNumber = 0;
|
||||
fetchingJob = new MyJob();
|
||||
@ -258,7 +258,7 @@ public class FetchingEventRelay implements EventRelay {
|
||||
|
||||
private class MyJob extends RepeatedSingletonJob {
|
||||
public MyJob() {
|
||||
super(executor);
|
||||
super(fetchExecutor);
|
||||
}
|
||||
|
||||
public boolean isSuspended() {
|
||||
@ -368,7 +368,7 @@ public class FetchingEventRelay implements EventRelay {
|
||||
private String clientId;
|
||||
private boolean stopped = false;
|
||||
|
||||
private final Executor executor;
|
||||
private final Executor fetchExecutor;
|
||||
private final ExecutorService defaultExecutor;
|
||||
private final MyJob fetchingJob;
|
||||
|
||||
|
||||
@ -181,7 +181,7 @@ public abstract class Monitor
|
||||
/**
|
||||
* Executor Service.
|
||||
*/
|
||||
private static final ExecutorService executor;
|
||||
private static final ThreadPoolExecutor executor;
|
||||
static {
|
||||
final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size";
|
||||
final String maximumPoolSizeStr = AccessController.doPrivileged(
|
||||
@ -218,7 +218,7 @@ public abstract class Monitor
|
||||
TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(),
|
||||
new DaemonThreadFactory("Executor"));
|
||||
((ThreadPoolExecutor)executor).allowCoreThreadTimeOut(true);
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -71,9 +71,8 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -421,12 +420,12 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
public ThreadPoolExecutor createThreadPool(ThreadGroup group) {
|
||||
ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
|
||||
"JMX RMIConnector listener dispatch %d");
|
||||
ThreadPoolExecutor exec = new ThreadPoolExecutor(
|
||||
ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
||||
1, 10, 1, TimeUnit.SECONDS,
|
||||
new LinkedBlockingDeque<Runnable>(),
|
||||
new LinkedBlockingQueue<Runnable>(),
|
||||
daemonThreadFactory);
|
||||
exec.allowCoreThreadTimeOut(true);
|
||||
return exec;
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
return executor;
|
||||
}
|
||||
};
|
||||
return listenerDispatchThreadPool.getThreadPoolExecutor(create);
|
||||
@ -1503,7 +1502,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
|
||||
super(period);
|
||||
}
|
||||
|
||||
public void gotIOException (IOException ioe) throws IOException {
|
||||
public void gotIOException(IOException ioe) throws IOException {
|
||||
if (ioe instanceof NoSuchObjectException) {
|
||||
// need to restart
|
||||
super.gotIOException(ioe);
|
||||
|
||||
@ -80,7 +80,7 @@ import sun.management.AgentConfigurationError;
|
||||
import static sun.management.AgentConfigurationError.*;
|
||||
import sun.management.ConnectorAddressLink;
|
||||
import sun.management.FileSystem;
|
||||
import sun.management.snmp.util.MibLogger;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
|
||||
import com.sun.jmx.remote.internal.RMIExporter;
|
||||
import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
|
||||
@ -99,6 +99,7 @@ public final class ConnectorBootstrap {
|
||||
public static final String PORT = "0";
|
||||
public static final String CONFIG_FILE_NAME = "management.properties";
|
||||
public static final String USE_SSL = "true";
|
||||
public static final String USE_LOCAL_ONLY = "true";
|
||||
public static final String USE_REGISTRY_SSL = "false";
|
||||
public static final String USE_AUTHENTICATION = "true";
|
||||
public static final String PASSWORD_FILE_NAME = "jmxremote.password";
|
||||
@ -115,6 +116,8 @@ public final class ConnectorBootstrap {
|
||||
"com.sun.management.jmxremote.port";
|
||||
public static final String CONFIG_FILE_NAME =
|
||||
"com.sun.management.config.file";
|
||||
public static final String USE_LOCAL_ONLY =
|
||||
"com.sun.management.jmxremote.local.only";
|
||||
public static final String USE_SSL =
|
||||
"com.sun.management.jmxremote.ssl";
|
||||
public static final String USE_REGISTRY_SSL =
|
||||
@ -384,7 +387,7 @@ public final class ConnectorBootstrap {
|
||||
checkAccessFile(accessFileName);
|
||||
}
|
||||
|
||||
if (log.isDebugOn()) {
|
||||
if (log.debugOn()) {
|
||||
log.debug("initialize",
|
||||
Agent.getText("jmxremote.ConnectorBootstrap.initialize") +
|
||||
"\n\t" + PropertyNames.PORT + "=" + port +
|
||||
@ -477,6 +480,18 @@ public final class ConnectorBootstrap {
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
try {
|
||||
JMXServiceURL url = new JMXServiceURL("rmi", localhost, 0);
|
||||
// Do we accept connections from local interfaces only?
|
||||
Properties props = Agent.getManagementProperties();
|
||||
if (props == null) {
|
||||
props = new Properties();
|
||||
}
|
||||
String useLocalOnlyStr = props.getProperty(
|
||||
PropertyNames.USE_LOCAL_ONLY, DefaultValues.USE_LOCAL_ONLY);
|
||||
boolean useLocalOnly = Boolean.valueOf(useLocalOnlyStr).booleanValue();
|
||||
if (useLocalOnly) {
|
||||
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
|
||||
new LocalRMIServerSocketFactory());
|
||||
}
|
||||
JMXConnectorServer server =
|
||||
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
|
||||
server.start();
|
||||
@ -764,7 +779,7 @@ public final class ConnectorBootstrap {
|
||||
private ConnectorBootstrap() {
|
||||
}
|
||||
|
||||
// XXX Revisit: should probably clone this MibLogger....
|
||||
private static final MibLogger log =
|
||||
new MibLogger(ConnectorBootstrap.class);
|
||||
private static final ClassLogger log =
|
||||
new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
|
||||
"ConnectorBootstrap");
|
||||
}
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package sun.management.jmxremote;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* This RMI server socket factory creates server sockets that
|
||||
* will only accept connection requests from clients running
|
||||
* on the host where the RMI remote objects have been exported.
|
||||
*/
|
||||
public final class LocalRMIServerSocketFactory implements RMIServerSocketFactory {
|
||||
/**
|
||||
* Creates a server socket that only accepts connection requests from
|
||||
* clients running on the host where the RMI remote objects have been
|
||||
* exported.
|
||||
*/
|
||||
public ServerSocket createServerSocket(int port) throws IOException {
|
||||
return new ServerSocket(port) {
|
||||
@Override
|
||||
public Socket accept() throws IOException {
|
||||
Socket socket = super.accept();
|
||||
InetAddress remoteAddr = socket.getInetAddress();
|
||||
final String msg = "The server sockets created using the " +
|
||||
"LocalRMIServerSocketFactory only accept connections " +
|
||||
"from clients running on the host where the RMI " +
|
||||
"remote objects have been exported.";
|
||||
if (remoteAddr.isAnyLocalAddress()) {
|
||||
// local address: accept the connection.
|
||||
return socket;
|
||||
}
|
||||
// Retrieve all the network interfaces on this host.
|
||||
Enumeration<NetworkInterface> nis;
|
||||
try {
|
||||
nis = NetworkInterface.getNetworkInterfaces();
|
||||
} catch (SocketException e) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
// Ignore...
|
||||
}
|
||||
throw new IOException(msg, e);
|
||||
}
|
||||
// Walk through the network interfaces to see
|
||||
// if any of them matches the client's address.
|
||||
// If true, then the client's address is local.
|
||||
while (nis.hasMoreElements()) {
|
||||
NetworkInterface ni = nis.nextElement();
|
||||
Enumeration<InetAddress> addrs = ni.getInetAddresses();
|
||||
while (addrs.hasMoreElements()) {
|
||||
InetAddress localAddr = addrs.nextElement();
|
||||
if (localAddr.equals(remoteAddr)) {
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The client's address is remote so refuse the connection.
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
// Ignore...
|
||||
}
|
||||
throw new IOException(msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Two LocalRMIServerSocketFactory objects
|
||||
* are equal if they are of the same type.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof LocalRMIServerSocketFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for this LocalRMIServerSocketFactory.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
}
|
||||
@ -58,6 +58,9 @@ abstract class AbstractPollSelectorImpl
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
|
||||
// Lock for close and cleanup
|
||||
private Object closeLock = new Object();
|
||||
|
||||
AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
|
||||
super(sp);
|
||||
this.totalChannels = channels;
|
||||
@ -65,7 +68,11 @@ abstract class AbstractPollSelectorImpl
|
||||
}
|
||||
|
||||
void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
pollWrapper.putEventOps(sk.getIndex(), ops);
|
||||
synchronized (closeLock) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
pollWrapper.putEventOps(sk.getIndex(), ops);
|
||||
}
|
||||
}
|
||||
|
||||
public Selector wakeup() {
|
||||
@ -76,7 +83,9 @@ abstract class AbstractPollSelectorImpl
|
||||
protected abstract int doSelect(long timeout) throws IOException;
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (!closed) {
|
||||
synchronized (closeLock) {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
// Deregister channels
|
||||
for(int i=channelOffset; i<totalChannels; i++) {
|
||||
@ -129,23 +138,28 @@ abstract class AbstractPollSelectorImpl
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
// Check to see if the array is large enough
|
||||
if (channelArray.length == totalChannels) {
|
||||
// Make a larger array
|
||||
int newSize = pollWrapper.totalChannels * 2;
|
||||
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
|
||||
// Copy over
|
||||
for (int i=channelOffset; i<totalChannels; i++)
|
||||
temp[i] = channelArray[i];
|
||||
channelArray = temp;
|
||||
// Grow the NativeObject poll array
|
||||
pollWrapper.grow(newSize);
|
||||
synchronized (closeLock) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
|
||||
// Check to see if the array is large enough
|
||||
if (channelArray.length == totalChannels) {
|
||||
// Make a larger array
|
||||
int newSize = pollWrapper.totalChannels * 2;
|
||||
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
|
||||
// Copy over
|
||||
for (int i=channelOffset; i<totalChannels; i++)
|
||||
temp[i] = channelArray[i];
|
||||
channelArray = temp;
|
||||
// Grow the NativeObject poll array
|
||||
pollWrapper.grow(newSize);
|
||||
}
|
||||
channelArray[totalChannels] = ski;
|
||||
ski.setIndex(totalChannels);
|
||||
pollWrapper.addEntry(ski.channel);
|
||||
totalChannels++;
|
||||
keys.add(ski);
|
||||
}
|
||||
channelArray[totalChannels] = ski;
|
||||
ski.setIndex(totalChannels);
|
||||
pollWrapper.addEntry(ski.channel);
|
||||
totalChannels++;
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
protected void implDereg(SelectionKeyImpl ski) throws IOException {
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
#
|
||||
# com.sun.management.snmp.interface=<InetAddress>
|
||||
# Specifies the local interface on which the SNMP agent will bind.
|
||||
# This is usefull when running on machines which have several
|
||||
# This is useful when running on machines which have several
|
||||
# interfaces defined. It makes it possible to listen to a specific
|
||||
# subnet accessible through that interface.
|
||||
# Default for this property is "localhost".
|
||||
@ -143,6 +143,26 @@
|
||||
# running MBean server, the connector, or the registry.
|
||||
#
|
||||
|
||||
#
|
||||
# ########## RMI connector settings for local management ##########
|
||||
#
|
||||
# com.sun.management.jmxremote.local.only=true|false
|
||||
# Default for this property is true. (Case for true/false ignored)
|
||||
# If this property is specified as true then the local JMX RMI connector
|
||||
# server will only accept connection requests from clients running on
|
||||
# the host where the out-of-the-box JMX management agent is running.
|
||||
# In order to ensure backwards compatibility this property could be
|
||||
# set to false. However, deploying the local management agent in this
|
||||
# way is discouraged because the local JMX RMI connector server will
|
||||
# accept connection requests from any client either local or remote.
|
||||
# For remote management the remote JMX RMI connector server should
|
||||
# be used instead with authentication and SSL/TLS encryption enabled.
|
||||
#
|
||||
|
||||
# For allowing the local management agent accept local
|
||||
# and remote connection requests use the following line
|
||||
# com.sun.management.jmxremote.local.only=false
|
||||
|
||||
#
|
||||
# ###################### RMI SSL #############################
|
||||
#
|
||||
|
||||
@ -46,15 +46,15 @@ class DevPollSelectorImpl
|
||||
// The poll object
|
||||
DevPollArrayWrapper pollWrapper;
|
||||
|
||||
// The number of valid channels in this Selector's poll array
|
||||
private int totalChannels;
|
||||
|
||||
// Maps from file descriptors to keys
|
||||
private Map<Integer,SelectionKeyImpl> fdToKey;
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
|
||||
// Lock for close/cleanup
|
||||
private Object closeLock = new Object();
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
private Object interruptLock = new Object();
|
||||
private boolean interruptTriggered = false;
|
||||
@ -72,7 +72,6 @@ class DevPollSelectorImpl
|
||||
pollWrapper = new DevPollArrayWrapper();
|
||||
pollWrapper.initInterrupt(fd0, fd1);
|
||||
fdToKey = new HashMap<Integer,SelectionKeyImpl>();
|
||||
totalChannels = 1;
|
||||
}
|
||||
|
||||
protected int doSelect(long timeout)
|
||||
@ -131,45 +130,39 @@ class DevPollSelectorImpl
|
||||
}
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcher.closeIntFD(fd0);
|
||||
FileDispatcher.closeIntFD(fd1);
|
||||
if (pollWrapper != null) {
|
||||
|
||||
pollWrapper.release(fd0);
|
||||
pollWrapper.closeDevPollFD();
|
||||
pollWrapper = null;
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
totalChannels = 0;
|
||||
|
||||
}
|
||||
fd0 = -1;
|
||||
fd1 = -1;
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcher.closeIntFD(fd0);
|
||||
FileDispatcher.closeIntFD(fd1);
|
||||
|
||||
pollWrapper.release(fd0);
|
||||
pollWrapper.closeDevPollFD();
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
fd0 = -1;
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||
fdToKey.put(Integer.valueOf(fd), ski);
|
||||
totalChannels++;
|
||||
keys.add(ski);
|
||||
}
|
||||
|
||||
@ -179,7 +172,6 @@ class DevPollSelectorImpl
|
||||
int fd = ski.channel.getFDVal();
|
||||
fdToKey.remove(Integer.valueOf(fd));
|
||||
pollWrapper.release(fd);
|
||||
totalChannels--;
|
||||
ski.setIndex(-1);
|
||||
keys.remove(ski);
|
||||
selectedKeys.remove(ski);
|
||||
@ -190,6 +182,8 @@ class DevPollSelectorImpl
|
||||
}
|
||||
|
||||
void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
int fd = IOUtil.fdVal(sk.channel.getFD());
|
||||
pollWrapper.setInterest(fd, ops);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,7 +31,6 @@ import java.nio.channels.spi.*;
|
||||
import java.util.*;
|
||||
import sun.misc.*;
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of Selector for Linux 2.6+ kernels that uses
|
||||
* the epoll event notification facility.
|
||||
@ -51,7 +50,7 @@ class EPollSelectorImpl
|
||||
private Map<Integer,SelectionKeyImpl> fdToKey;
|
||||
|
||||
// True if this Selector has been closed
|
||||
private boolean closed = false;
|
||||
private volatile boolean closed = false;
|
||||
|
||||
// Lock for interrupt triggering and clearing
|
||||
private Object interruptLock = new Object();
|
||||
@ -128,40 +127,41 @@ class EPollSelectorImpl
|
||||
}
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcher.closeIntFD(fd0);
|
||||
FileDispatcher.closeIntFD(fd1);
|
||||
if (pollWrapper != null) {
|
||||
|
||||
pollWrapper.release(fd0);
|
||||
pollWrapper.closeEPollFD();
|
||||
pollWrapper = null;
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
fd0 = -1;
|
||||
fd1 = -1;
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
|
||||
FileDispatcher.closeIntFD(fd0);
|
||||
FileDispatcher.closeIntFD(fd1);
|
||||
|
||||
pollWrapper.release(fd0);
|
||||
pollWrapper.closeEPollFD();
|
||||
// it is possible
|
||||
selectedKeys = null;
|
||||
|
||||
// Deregister channels
|
||||
Iterator i = keys.iterator();
|
||||
while (i.hasNext()) {
|
||||
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
|
||||
deregister(ski);
|
||||
SelectableChannel selch = ski.channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
i.remove();
|
||||
}
|
||||
|
||||
fd0 = -1;
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
int fd = IOUtil.fdVal(ski.channel.getFD());
|
||||
fdToKey.put(Integer.valueOf(fd), ski);
|
||||
pollWrapper.add(fd);
|
||||
@ -183,6 +183,8 @@ class EPollSelectorImpl
|
||||
}
|
||||
|
||||
void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
if (closed)
|
||||
throw new ClosedSelectorException();
|
||||
int fd = IOUtil.fdVal(sk.channel.getFD());
|
||||
pollWrapper.setInterest(fd, ops);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -80,6 +80,9 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
||||
// File descriptors corresponding to source and sink
|
||||
private final int wakeupSourceFd, wakeupSinkFd;
|
||||
|
||||
// Lock for close cleanup
|
||||
private Object closeLock = new Object();
|
||||
|
||||
// Maps file descriptors to their indices in pollArray
|
||||
private final static class FdMap extends HashMap<Integer, MapEntry> {
|
||||
static final long serialVersionUID = 0L;
|
||||
@ -473,42 +476,48 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
||||
}
|
||||
|
||||
protected void implClose() throws IOException {
|
||||
if (channelArray != null) {
|
||||
if (pollWrapper != null) {
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
wakeupPipe.sink().close();
|
||||
wakeupPipe.source().close();
|
||||
for(int i = 1; i < totalChannels; i++) { // Deregister channels
|
||||
if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
|
||||
deregister(channelArray[i]);
|
||||
SelectableChannel selch = channelArray[i].channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
synchronized (closeLock) {
|
||||
if (channelArray != null) {
|
||||
if (pollWrapper != null) {
|
||||
// prevent further wakeup
|
||||
synchronized (interruptLock) {
|
||||
interruptTriggered = true;
|
||||
}
|
||||
}
|
||||
pollWrapper.free();
|
||||
pollWrapper = null;
|
||||
selectedKeys = null;
|
||||
channelArray = null;
|
||||
threads.clear();
|
||||
// Call startThreads. All remaining helper threads now exit,
|
||||
// since threads.size() = 0;
|
||||
startLock.startThreads();
|
||||
wakeupPipe.sink().close();
|
||||
wakeupPipe.source().close();
|
||||
for(int i = 1; i < totalChannels; i++) { // Deregister channels
|
||||
if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
|
||||
deregister(channelArray[i]);
|
||||
SelectableChannel selch = channelArray[i].channel();
|
||||
if (!selch.isOpen() && !selch.isRegistered())
|
||||
((SelChImpl)selch).kill();
|
||||
}
|
||||
}
|
||||
pollWrapper.free();
|
||||
pollWrapper = null;
|
||||
selectedKeys = null;
|
||||
channelArray = null;
|
||||
threads.clear();
|
||||
// Call startThreads. All remaining helper threads now exit,
|
||||
// since threads.size() = 0;
|
||||
startLock.startThreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void implRegister(SelectionKeyImpl ski) {
|
||||
growIfNeeded();
|
||||
channelArray[totalChannels] = ski;
|
||||
ski.setIndex(totalChannels);
|
||||
fdMap.put(ski);
|
||||
keys.add(ski);
|
||||
pollWrapper.addEntry(totalChannels, ski);
|
||||
totalChannels++;
|
||||
synchronized (closeLock) {
|
||||
if (pollWrapper == null)
|
||||
throw new ClosedSelectorException();
|
||||
growIfNeeded();
|
||||
channelArray[totalChannels] = ski;
|
||||
ski.setIndex(totalChannels);
|
||||
fdMap.put(ski);
|
||||
keys.add(ski);
|
||||
pollWrapper.addEntry(totalChannels, ski);
|
||||
totalChannels++;
|
||||
}
|
||||
}
|
||||
|
||||
private void growIfNeeded() {
|
||||
@ -554,7 +563,11 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
||||
}
|
||||
|
||||
void putEventOps(SelectionKeyImpl sk, int ops) {
|
||||
pollWrapper.putEventOps(sk.getIndex(), ops);
|
||||
synchronized (closeLock) {
|
||||
if (pollWrapper == null)
|
||||
throw new ClosedSelectorException();
|
||||
pollWrapper.putEventOps(sk.getIndex(), ops);
|
||||
}
|
||||
}
|
||||
|
||||
public Selector wakeup() {
|
||||
|
||||
48
jdk/test/java/nio/channels/Selector/CloseThenRegister.java
Normal file
48
jdk/test/java/nio/channels/Selector/CloseThenRegister.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 5025260
|
||||
* @summary ClosedSelectorException is expected when register after close
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
public class CloseThenRegister {
|
||||
|
||||
public static void main (String [] args) throws Exception {
|
||||
try {
|
||||
Selector s = Selector.open();
|
||||
s.close();
|
||||
ServerSocketChannel c = ServerSocketChannel.open();
|
||||
c.socket().bind(new InetSocketAddress(40000));
|
||||
c.configureBlocking(false);
|
||||
c.register(s, SelectionKey.OP_ACCEPT);
|
||||
} catch (ClosedSelectorException cse) {
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("register after close does not cause CSE!");
|
||||
}
|
||||
|
||||
}
|
||||
97
jdk/test/javax/management/mxbean/TypeNameTest.java
Normal file
97
jdk/test/javax/management/mxbean/TypeNameTest.java
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6757225
|
||||
* @summary Test that type names in MXBeans match their spec.
|
||||
* @author Eamonn McManus
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.StandardMBean;
|
||||
|
||||
public class TypeNameTest {
|
||||
public static interface TestMXBean {
|
||||
public int getInt();
|
||||
public String IntName = "int";
|
||||
|
||||
public Map<String, Integer> getMapSI();
|
||||
public String MapSIName = "java.util.Map<java.lang.String, java.lang.Integer>";
|
||||
|
||||
public Map<String, int[]> getMapSInts();
|
||||
public String MapSIntsName = "java.util.Map<java.lang.String, int[]>";
|
||||
|
||||
public List<List<int[]>> getListListInts();
|
||||
public String ListListIntsName = "java.util.List<java.util.List<int[]>>";
|
||||
}
|
||||
|
||||
private static InvocationHandler nullIH = new InvocationHandler() {
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
static String failure;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
TestMXBean testImpl = (TestMXBean) Proxy.newProxyInstance(
|
||||
TestMXBean.class.getClassLoader(), new Class<?>[] {TestMXBean.class}, nullIH);
|
||||
Object mxbean = new StandardMBean(testImpl, TestMXBean.class, true);
|
||||
MBeanServer mbs = MBeanServerFactory.newMBeanServer();
|
||||
ObjectName name = new ObjectName("a:b=c");
|
||||
mbs.registerMBean(mxbean, name);
|
||||
MBeanInfo mbi = mbs.getMBeanInfo(name);
|
||||
MBeanAttributeInfo[] mbais = mbi.getAttributes();
|
||||
for (MBeanAttributeInfo mbai : mbais) {
|
||||
String attrName = mbai.getName();
|
||||
String attrTypeName = (String) mbai.getDescriptor().getFieldValue("originalType");
|
||||
String fieldName = attrName + "Name";
|
||||
Field nameField = TestMXBean.class.getField(fieldName);
|
||||
String expectedTypeName = (String) nameField.get(null);
|
||||
if (expectedTypeName.equals(attrTypeName)) {
|
||||
System.out.println("OK: " + attrName + ": " + attrTypeName);
|
||||
} else {
|
||||
failure = "For attribute " + attrName + " expected type name \"" +
|
||||
expectedTypeName + "\", found type name \"" + attrTypeName +
|
||||
"\"";
|
||||
System.out.println("FAIL: " + failure);
|
||||
}
|
||||
}
|
||||
if (failure == null)
|
||||
System.out.println("TEST PASSED");
|
||||
else
|
||||
throw new Exception("TEST FAILED: " + failure);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user