diff options
Diffstat (limited to 'java-compat/src')
340 files changed, 68699 insertions, 0 deletions
diff --git a/java-compat/src/Glacier2/build.gradle b/java-compat/src/Glacier2/build.gradle new file mode 100644 index 00000000000..d087e401336 --- /dev/null +++ b/java-compat/src/Glacier2/build.gradle @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "Glacier2 Compat" +project.ext.description = "Firewall traversal for Ice" + +slice { + java { + set1 { + args = "--ice --tie --checksum Glacier2.SliceChecksums" + files = fileTree(dir: "${sliceDir}/Glacier2", includes:['*.ice'], excludes:["*F.ice"]) + } + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/Glacier2/src/main/java/Glacier2/Application.java b/java-compat/src/Glacier2/src/main/java/Glacier2/Application.java new file mode 100644 index 00000000000..2d5768fdf1c --- /dev/null +++ b/java-compat/src/Glacier2/src/main/java/Glacier2/Application.java @@ -0,0 +1,515 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Glacier2; + +/** + * An extension of Ice.Application that makes it easy to write + * Glacier2 applications. + * + * <p> Applications must create a derived class that implements the + * {@link #createSession} and {@link #runWithSession} methods.<p> + * + * The base class invokes {@link #createSession} to create a new + * Glacier2 session and then invokes {@link #runWithSession} in + * which the subclass performs its application logic. The base class + * automatically destroys the session when {@link #runWithSession} + * returns. + * + * If {@link #runWithSession} calls {@link #restart} or raises any of + * the exceptions Ice.ConnectionRefusedException, + * Ice.ConnectionLostException, Ice.UnknownLocalException, + * Ice.RequestFailedException, or Ice.TimeoutException, the base + * class destroys the current session and restarts the application + * with another call to {@link #createSession} followed by + * {@link #runWithSession}. + * + * The application can optionally override the {@link #sessionDestroyed} + * callback method if it needs to take action when connectivity with + * the Glacier2 router is lost. + * + * A program can contain only one instance of this class. + * + * @see Ice.Application + * @see Glacier2.Router + * @see Glacier2.Session + * @see Ice.Communicator + * @see Ice.Logger + * @see #runWithSession + **/ +public abstract class Application extends Ice.Application +{ + /** + * This exception is raised if the session should be restarted. + */ + public class RestartSessionException extends Exception + { + } + + /** + * Initializes an instance that calls {@link Communicator#shutdown} if + * a signal is received. + **/ + public + Application() + { + } + + /** + * Initializes an instance that handles signals according to the signal + * policy. + * + * @param signalPolicy Determines how to respond to signals. + * + * @see SignalPolicy + **/ + public + Application(Ice.SignalPolicy signalPolicy) + { + super(signalPolicy); + } + + /** + * Called once the communicator has been initialized and the Glacier2 session + * has been established. A derived class must implement <code>runWithSession</code>, + * which is the application's starting method. + * + * @param args The argument vector for the application. <code>Application</code> + * scans the argument vector passed to <code>main</code> for options that are + * specific to the Ice run time and removes them; therefore, the vector passed + * to <code>run</code> is free from Ice-related options and contains only options + * and arguments that are application-specific. + * + * @return The <code>runWithSession</code> method should return zero for successful + * termination, and non-zero otherwise. <code>Application.main</code> returns the + * value returned by <code>runWithSession</code>. + **/ + public abstract int + runWithSession(String[] args) + throws RestartSessionException; + + /** + * Run should not be overridden for Glacier2.Application. Instead + * <code>runWithSession</code> should be used. + */ + @Override + final public int + run(String[] args) + { + // This shouldn't be called. + assert false; + return 0; + } + + /** + * Called to restart the application's Glacier2 session. This + * method never returns. The exception produce an application restart + * when called from the Application main thread. + * + * @throws RestartSessionException This exception is always thrown. + **/ + public void + restart() + throws RestartSessionException + { + throw new RestartSessionException(); + } + + /** + * Creates a new Glacier2 session. A call to + * <code>createSession</code> always precedes a call to + * <code>runWithSession</code>. If <code>Ice.LocalException</code> + * is thrown from this method, the application is terminated. + * + * @return The Glacier2 session. + **/ + abstract public Glacier2.SessionPrx + createSession(); + + /** + * Called when the session refresh thread detects that the session has been + * destroyed. A subclass can override this method to take action after the + * loss of connectivity with the Glacier2 router. This method is called + * according to the Ice invocation dipsatch rules (in other words, it + * uses the same rules as an servant upcall or AMI callback). + **/ + public void + sessionDestroyed() + { + } + + /** + * Returns the Glacier2 router proxy + * @return The router proxy. + **/ + public static Glacier2.RouterPrx + router() + { + return _router; + } + + /** + * Returns the Glacier2 session proxy + * @return The session proxy. + **/ + public static Glacier2.SessionPrx + session() + { + return _session; + } + + /** + * Returns the category to be used in the identities of all of the client's + * callback objects. Clients must use this category for the router to + * forward callback requests to the intended client. + * @return The category. + * @throws SessionNotExistException No session exists. + **/ + public String + categoryForClient() + throws SessionNotExistException + { + if(_router == null) + { + throw new SessionNotExistException(); + } + return _category; + } + + /** + * Create a new Ice identity for callback objects with the given + * identity name field. + * @return The identity. + * @throws SessionNotExistException No session exists. + **/ + public Ice.Identity + createCallbackIdentity(String name) + throws SessionNotExistException + { + return new Ice.Identity(name, categoryForClient()); + } + + /** + * Adds a servant to the callback object adapter's Active Servant Map with a UUID. + * @param servant The servant to add. + * @return The proxy for the servant. + * @throws SessionNotExistException No session exists. + **/ + public Ice.ObjectPrx + addWithUUID(Ice.Object servant) + throws SessionNotExistException + { + return objectAdapter().add(servant, createCallbackIdentity(java.util.UUID.randomUUID().toString())); + } + + /** + * Creates an object adapter for callback objects. + * @return The object adapter. + * @throws SessionNotExistException No session exists. + */ + public Ice.ObjectAdapter + objectAdapter() + throws SessionNotExistException + { + if(_router == null) + { + throw new SessionNotExistException(); + } + + synchronized(this) + { + if(_adapter == null) + { + _adapter = communicator().createObjectAdapterWithRouter("", _router); + _adapter.activate(); + } + } + return _adapter; + } + + private class CloseCallbackI implements Ice.CloseCallback + { + @Override + public void closed(Ice.Connection con) + { + sessionDestroyed(); + } + } + + @Override + protected int + doMain(Ice.StringSeqHolder argHolder, Ice.InitializationData initData) + { + // + // Set the default properties for all Glacier2 applications. + // + initData.properties.setProperty("Ice.RetryIntervals", "-1"); + + boolean restart; + Ice.Holder<Integer> ret = new Ice.Holder<Integer>(); + do + { + // + // A copy of the initialization data and the string array + // needs to be passed to doMainInternal, as these can be + // changed by the application. + // + Ice.InitializationData id = initData.clone(); + id.properties = id.properties._clone(); + Ice.StringSeqHolder h = new Ice.StringSeqHolder(); + h.value = argHolder.value.clone(); + + restart = doMain(h, id, ret); + } + while(restart); + return ret.value; + } + + private boolean + doMain(Ice.StringSeqHolder argHolder, Ice.InitializationData initData, Ice.Holder<Integer> status) + { + // + // Reset internal state variables from Ice.Application. The + // remainder are reset at the end of this method. + // + _callbackInProgress = false; + _destroyed = false; + _interrupted = false; + + boolean restart = false; + status.value = 0; + + try + { + _communicator = Ice.Util.initialize(argHolder, initData); + + _router = Glacier2.RouterPrxHelper.uncheckedCast(communicator().getDefaultRouter()); + if(_router == null) + { + Ice.Util.getProcessLogger().error("no glacier2 router configured"); + status.value = 1; + } + else + { + // + // The default is to destroy when a signal is received. + // + if(_signalPolicy == Ice.SignalPolicy.HandleSignals) + { + destroyOnInterrupt(); + } + + // + // If createSession throws, we're done. + // + try + { + _session = createSession(); + _createdSession = true; + } + catch(Ice.LocalException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + status.value = 1; + } + + if(_createdSession) + { + int acmTimeout = 0; + try + { + acmTimeout = _router.getACMTimeout(); + } + catch(Ice.OperationNotExistException ex) + { + } + if(acmTimeout <= 0) + { + acmTimeout = (int)_router.getSessionTimeout(); + } + if(acmTimeout > 0) + { + Ice.Connection connection = _router.ice_getCachedConnection(); + assert(connection != null); + connection.setACM(new Ice.IntOptional(acmTimeout), + null, + new Ice.Optional<Ice.ACMHeartbeat>(Ice.ACMHeartbeat.HeartbeatAlways)); + connection.setCloseCallback(new CloseCallbackI()); + } + _category = _router.getCategoryForClient(); + status.value = runWithSession(argHolder.value); + } + } + } + // + // We want to restart on those exceptions that indicate a + // break down in communications, but not those exceptions that + // indicate a programming logic error (i.e., marshal, protocol + // failure, etc). + // + catch(RestartSessionException ex) + { + restart = true; + } + catch(Ice.ConnectionRefusedException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + restart = true; + } + catch(Ice.ConnectionLostException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + restart = true; + } + catch(Ice.UnknownLocalException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + restart = true; + } + catch(Ice.RequestFailedException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + restart = true; + } + catch(Ice.TimeoutException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + restart = true; + } + catch(Ice.LocalException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + status.value = 1; + } + catch(java.lang.Exception ex) + { + Ice.Util.getProcessLogger().error("unknown exception:\n" + IceInternal.Ex.toString(ex)); + status.value = 1; + } + catch(java.lang.Error err) + { + // + // We catch Error to avoid hangs in some non-fatal situations + // + Ice.Util.getProcessLogger().error("Java error:\n" + IceInternal.Ex.toString(err)); + status.value = 1; + } + + // + // This clears any set interrupt. + // + if(_signalPolicy == Ice.SignalPolicy.HandleSignals) + { + defaultInterrupt(); + } + + synchronized(_mutex) + { + while(_callbackInProgress) + { + try + { + _mutex.wait(); + } + catch(java.lang.InterruptedException ex) + { + } + } + + if(_destroyed) + { + _communicator = null; + } + else + { + _destroyed = true; + // + // And _communicator != null, meaning will be + // destroyed next, _destroyed = true also ensures that + // any remaining callback won't do anything. + // + } + } + + if(_createdSession && _router != null) + { + try + { + _router.destroySession(); + } + catch(Ice.ConnectionLostException ex) + { + // + // Expected if another thread invoked on an object from the session concurrently. + // + } + catch(Glacier2.SessionNotExistException ex) + { + // + // This can also occur. + // + } + catch(Throwable ex) + { + // + // Not expected. + // + Ice.Util.getProcessLogger().error("unexpected exception when destroying the session:\n" + + IceInternal.Ex.toString(ex)); + } + _router = null; + } + + if(_communicator != null) + { + try + { + _communicator.destroy(); + } + catch(Ice.LocalException ex) + { + Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + status.value = 1; + } + catch(java.lang.Exception ex) + { + Ice.Util.getProcessLogger().error("unknown exception:\n" + IceInternal.Ex.toString(ex)); + status.value = 1; + } + _communicator = null; + } + + synchronized(_mutex) + { + if(_appHook != null) + { + _appHook.done(); + } + } + + // + // Reset internal state. We cannot reset the Application state + // here, since _destroyed must remain true until we re-run + // this method. + // + _adapter = null; + _router = null; + _session = null; + _createdSession = false; + _category = null; + + return restart; + } + + private static Ice.ObjectAdapter _adapter; + private static Glacier2.RouterPrx _router; + private static Glacier2.SessionPrx _session; + private static boolean _createdSession = false; + private static String _category; +} diff --git a/java-compat/src/Glacier2/src/main/java/Glacier2/SessionCallback.java b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionCallback.java new file mode 100644 index 00000000000..b1532e1fbd0 --- /dev/null +++ b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionCallback.java @@ -0,0 +1,48 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Glacier2; + +/** + * A callback class to get notifications of status changes in the Glacier2 session. + * All callbacks on the <code>Callback</code> interface occur in the main swing thread. + */ +public interface SessionCallback +{ + /** + * Notifies the application that the communicator was created. + * + * @param session The Glacier2 session. + */ + void createdCommunicator(SessionHelper session); + + /** + * Notifies the application that the Glacier2 session has been established. + * + * @param session The established session. + */ + void connected(SessionHelper session) + throws SessionNotExistException; + + /** + * Notifies the application that the Glacier2 session has been disconnected. + * + * @param session The disconnected session. + */ + void disconnected(SessionHelper session); + + /** + * Notifies the application that the Glacier2 session establishment failed. + * + * @param session The session reporting the connection + * failure. + * @param ex The exception. + */ + void connectFailed(SessionHelper session, Throwable ex); +} diff --git a/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java new file mode 100644 index 00000000000..b7b086a8798 --- /dev/null +++ b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionFactoryHelper.java @@ -0,0 +1,398 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Glacier2; + +/** + * A helper class for using Glacier2 with GUI applications. + * + * Applications should create a session factory for each Glacier2 router to which the application will + * connect. To connect with the Glacier2 router, call {@link SessionFactory#connect}. The callback object is + * notified of the various life cycle events. Once the session is torn down for whatever reason, the application + * can use the session factory to create another connection. + */ +public class SessionFactoryHelper +{ + /** + * Creates a SessionFactory object. + * + * @param callback The callback object for notifications. + * @throws {@link Ice.InitializationException} + */ + public + SessionFactoryHelper(SessionCallback callback) + throws Ice.InitializationException + { + initialize(callback, new Ice.InitializationData(), Ice.Util.createProperties()); + } + + /** + * Creates a SessionFactory object. + * + * @param initData The initialization data to use when creating the communicator. + * @param callback The callback object for notifications. + * @throws {@link Ice.InitializationException} + */ + public + SessionFactoryHelper(Ice.InitializationData initData, SessionCallback callback) + throws Ice.InitializationException + { + initialize(callback, initData, initData.properties); + } + + /** + * Creates a SessionFactory object. + * + * @param properties The properties to use when creating the communicator. + * @param callback The callback object for notifications. + * @throws {@link Ice.InitializationException} + */ + public + SessionFactoryHelper(Ice.Properties properties, SessionCallback callback) + throws Ice.InitializationException + { + initialize(callback, new Ice.InitializationData(), properties); + } + + private void + initialize(SessionCallback callback, Ice.InitializationData initData, Ice.Properties properties) + throws Ice.InitializationException + { + if(callback == null) + { + throw new Ice.InitializationException("Attempt to create a SessionFactoryHelper with a null " + + "SessionCallback argument"); + } + + if(initData == null) + { + throw new Ice.InitializationException("Attempt to create a SessionFactoryHelper with a null " + + "InitializationData argument"); + } + + if(properties == null) + { + throw new Ice.InitializationException("Attempt to create a SessionFactoryHelper with a null Properties " + + "argument"); + } + + _callback = callback; + _initData = initData; + _initData.properties = properties; + + // + // Set default properties; + // + _initData.properties.setProperty("Ice.RetryIntervals", "-1"); + } + + /** + * Set the router object identity. + * + * @param identity The Glacier2 router's identity. + */ + synchronized public void + setRouterIdentity(Ice.Identity identity) + { + _identity = identity; + } + + /** + * Returns the object identity of the Glacier2 router. + * + * @return The Glacier2 router's identity. + */ + synchronized public Ice.Identity + getRouterIdentity() + { + return _identity; + } + + /** + * Sets the host on which the Glacier2 router runs. + * + * @param hostname The host name (or IP address) of the router host. + */ + synchronized public void + setRouterHost(String hostname) + { + _routerHost = hostname; + } + + /** + * Returns the host on which the Glacier2 router runs. + * + * @return The Glacier2 router host. + */ + synchronized public String + getRouterHost() + { + return _routerHost; + } + + /** + * Sets whether to connect with the Glacier2 router securely. + * + * @param secure If <code>true</code>, the client connects to the router + * via SSL; otherwise, the client connects via TCP. + * @deprecated deprecated, use SessionFactoryHelper.setProtocol instead + */ + @Deprecated + public void + setSecure(boolean secure) + { + setProtocol(secure ? "ssl" : "tcp"); + } + + /** + * Returns whether the session factory will establish a secure connection to the Glacier2 router. + * + * @return The secure flag. + * @deprecated deprecated, use SessionFactoryHelper.getProtocol instead + */ + @Deprecated + public boolean + getSecure() + { + return getProtocol().equals("ssl"); + } + + /** + * + * Sets the protocol that will be used by the session factory to establish the connection. + * + * @param protocol. + */ + synchronized public void setProtocol(String protocol) + { + if(protocol == null) + { + throw new IllegalArgumentException("You must use a valid protocol"); + } + + if(!protocol.equals("tcp") && + !protocol.equals("ssl") && + !protocol.equals("wss") && + !protocol.equals("ws")) + { + throw new IllegalArgumentException("Unknow protocol `" + protocol + "'"); + } + + _protocol = protocol; + } + + /** + * + * Returns the protocol that will be used by the session factory to establish the connection. + * + * @return The protocol. + */ + synchronized public String getProtocol() + { + return _protocol; + } + + /** + * Sets the connect and connection timeout for the Glacier2 router. + * + * @param timeoutMillisecs The timeout in milliseconds. A zero + * or negative timeout value indicates that the router proxy has no associated timeout. + */ + synchronized public void + setTimeout(int timeoutMillisecs) + { + _timeout = timeoutMillisecs; + } + + /** + * Returns the connect and connection timeout associated with the Glacier2 router. + * + * @return The timeout. + */ + synchronized public int + getTimeout() + { + return _timeout; + } + + /** + * Sets the Glacier2 router port to connect to. + * + * @param port The port. If 0, then the default port (4063 for TCP or 4064 for SSL) is used. + */ + synchronized public void + setPort(int port) + { + _port = port; + } + + /** + * Returns the Glacier2 router port to connect to. + * + * @return The port. + */ + synchronized public int + getPort() + { + return getPortInternal(); + } + + private int getPortInternal() + { + return _port == 0 ? ((_protocol.equals("ssl") || + _protocol.equals("wss"))? GLACIER2_SSL_PORT : GLACIER2_TCP_PORT) : _port; + } + + /** + * Returns the initialization data used to initialize the communicator. + * + * @return The initialization data. + */ + synchronized public Ice.InitializationData + getInitializationData() + { + return _initData; + } + + /** + * Sets the request context to use while establishing a connection to the Glacier2 router. + * + * @param context The request context. + */ + synchronized public void + setConnectContext(final java.util.Map<String, String> context) + { + _context = context; + } + + /** + * Determines whether the session should create an object adapter that the client + * can use for receiving callbacks. + * + * @param useCallbacks True if the session should create an object adapter. + */ + synchronized public void + setUseCallbacks(boolean useCallbacks) + { + _useCallbacks = useCallbacks; + } + + /** + * Indicates whether a newly-created session will also create an object adapter that + * the client can use for receiving callbacks. + * + * @return True if the session will create an object adapter. + */ + synchronized public boolean + getUseCallbacks() + { + return _useCallbacks; + } + + /** + * Connects to the Glacier2 router using the associated SSL credentials. + * + * Once the connection is established, {@link SessionCallback#connected} is called on the callback object; + * upon failure, {@link SessionCallback#connectFailed} is called with the exception. + * + * @return The connected session. + */ + synchronized public SessionHelper + connect() + { + SessionHelper session = new SessionHelper(_callback, createInitData(), getRouterFinderStr(), _useCallbacks); + session.connect(_context); + return session; + } + + /** + * Connect the Glacier2 session using user name and password credentials. + * + * Once the connection is established, {@link SessionCallback#connected} is called on the callback object; + * upon failure, {@link SessionCallback#connectFailed) is called with the exception. + * + * @param username The user name. + * @param password The password. + * @return The connected session. + */ + synchronized public SessionHelper + connect(final String username, final String password) + { + SessionHelper session = new SessionHelper(_callback, createInitData(), getRouterFinderStr(), _useCallbacks); + session.connect(username, password, _context); + return session; + } + + private Ice.InitializationData + createInitData() + { + // + // Clone the initialization data and properties. + // + Ice.InitializationData initData = _initData.clone(); + initData.properties = initData.properties._clone(); + + if(initData.properties.getProperty("Ice.Default.Router").length() == 0 && _identity != null) + { + initData.properties.setProperty("Ice.Default.Router", getProxyStr(_identity)); + } + + // + // If using a secure connection setup the IceSSL plug-in, if IceSSL + // plug-in has already been setup we don't want to override the + // configuration so it can be loaded from a custom location. + // + if((_protocol.equals("ssl") || _protocol.equals("wss")) && + initData.properties.getProperty("Ice.Plugin.IceSSL").length() == 0) + { + initData.properties.setProperty("Ice.Plugin.IceSSL", "IceSSL.PluginFactory"); + } + + return initData; + } + + private String + getRouterFinderStr() + { + Ice.Identity ident = new Ice.Identity("RouterFinder", "Ice"); + return getProxyStr(ident); + } + + private String + getProxyStr(Ice.Identity ident) + { + StringBuilder sb = new StringBuilder(); + sb.append("\""); + sb.append(Ice.Util.identityToString(ident)); + sb.append("\":"); + sb.append(_protocol + " -p "); + sb.append(getPortInternal()); + sb.append(" -h \""); + sb.append(_routerHost); + sb.append("\""); + if(_timeout > 0) + { + sb.append(" -t "); + sb.append(_timeout); + } + return sb.toString(); + } + + private SessionCallback _callback; + private String _routerHost = "localhost"; + private Ice.InitializationData _initData; + private Ice.Identity _identity = null; + private String _protocol = "ssl"; + private int _port = 0; + private int _timeout = 10000; + private java.util.Map<String, String> _context; + private boolean _useCallbacks = true; + private static final int GLACIER2_SSL_PORT = 4064; + private static final int GLACIER2_TCP_PORT = 4063; +} diff --git a/java-compat/src/Glacier2/src/main/java/Glacier2/SessionHelper.java b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionHelper.java new file mode 100644 index 00000000000..70257c9f66d --- /dev/null +++ b/java-compat/src/Glacier2/src/main/java/Glacier2/SessionHelper.java @@ -0,0 +1,627 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Glacier2; + +/** + * A helper class for using Glacier2 with GUI applications. + */ +public class SessionHelper +{ + /** + * Creates a Glacier2 session. + * + * @param callback The callback for notifications about session establishment. + * @param initData The {@link Ice.InitializationData} for initializing the communicator. + * @param finderStr The stringified Ice.RouterFinder proxy. + * @param useCallbacks True if the session should create an object adapter for receiving callbacks. + */ + public SessionHelper(SessionCallback callback, Ice.InitializationData initData, String finderStr, + boolean useCallbacks) + { + _callback = callback; + _initData = initData; + _finderStr = finderStr; + _useCallbacks = useCallbacks; + } + + /** + * Destroys the Glacier2 session. + * + * Once the session has been destroyed, {@link SessionCallback.disconnected} is called on + * the associated callback object. + */ + public void + destroy() + { + synchronized(this) + { + if(_destroy) + { + return; + } + _destroy = true; + if(!_connected) + { + // + // In this case a connecting session is being destroyed. + // We destroy the communicator to trigger the immediate + // failure of the connection establishment. + // + new Thread(new Runnable() + { + @Override + public void run() + { + destroyCommunicator(); + } + }).start(); + return; + } + _session = null; + _connected = false; + + try + { + Runtime.getRuntime().removeShutdownHook(_shutdownHook); + } + catch(IllegalStateException ex) + { + // Ignore + } + catch(SecurityException ex) + { + // Ignore + } + } + + // + // Run destroyInternal in a thread because it makes remote invocations. + // + new Thread(new Runnable() + { + @Override + public void run() + { + destroyInternal(); + } + }).start(); + } + + /** + * Returns the session's communicator object. + * @return The communicator. + */ + synchronized public Ice.Communicator + communicator() + { + return _communicator; + } + + /** + * Returns the category to be used in the identities of all of the client's + * callback objects. Clients must use this category for the router to + * forward callback requests to the intended client. + * @return The category. + * @throws SessionNotExistException No session exists. + **/ + synchronized public String + categoryForClient() + throws SessionNotExistException + { + if(_router == null) + { + throw new SessionNotExistException(); + } + + return _category; + } + + /** + * Adds a servant to the callback object adapter's Active Servant Map with a UUID. + * @param servant The servant to add. + * @return The proxy for the servant. + * @throws SessionNotExistException No session exists. + **/ + synchronized public Ice.ObjectPrx + addWithUUID(Ice.Object servant) + throws SessionNotExistException + { + if(_router == null) + { + throw new SessionNotExistException(); + } + return internalObjectAdapter().add(servant, new Ice.Identity(java.util.UUID.randomUUID().toString(), + _category)); + } + + /** + * Returns the Glacier2 session proxy. If the session hasn't been established yet, + * or the session has already been destroyed, throws SessionNotExistException. + * @return The session proxy, or throws SessionNotExistException if no session exists. + * @throws SessionNotExistException No session exists. + */ + synchronized public Glacier2.SessionPrx + session() + throws SessionNotExistException + { + if(_session == null) + { + throw new SessionNotExistException(); + } + + return _session; + } + + /** + * Returns true if there is an active session, otherwise returns false. + * @return <code>true</code>if session exists or false if no session exists. + */ + synchronized public boolean + isConnected() + { + return _connected; + } + + /** + * Creates an object adapter for callback objects. + * @return The object adapter. + * @throws SessionNotExistException No session exists. + */ + synchronized public Ice.ObjectAdapter + objectAdapter() + throws SessionNotExistException + { + return internalObjectAdapter(); + } + + // + // Only call this method when the calling thread owns the lock + // + private Ice.ObjectAdapter + internalObjectAdapter() + throws SessionNotExistException + { + if(_router == null) + { + throw new SessionNotExistException(); + } + if(!_useCallbacks) + { + throw new Ice.InitializationException( + "Object adapter not available, call SessionFactoryHelper.setUseCallbacks(true)"); + } + return _adapter; + } + + private interface ConnectStrategy + { + Glacier2.SessionPrx + connect(Glacier2.RouterPrx router) + throws CannotCreateSessionException, PermissionDeniedException; + } + + /** + * Connects to the Glacier2 router using the associated SSL credentials. + * + * Once the connection is established, {@link SessionCallback#connected} is called on the callback object; + * upon failure, {@link SessionCallback#exception} is called with the exception. + * + * @param context The request context to use when creating the session. + */ + synchronized protected void + connect(final java.util.Map<String, String> context) + { + connectImpl(new ConnectStrategy() + { + @Override + public SessionPrx connect(RouterPrx router) + throws CannotCreateSessionException, PermissionDeniedException + { + return router.createSessionFromSecureConnection(context); + } + }); + } + + /** + * Connects a Glacier2 session using user name and password credentials. + * + * Once the connection is established, {@link SessionCallback#connected} is called on the callback object; + * upon failure {@link SessionCallback.exception} is called with the exception. + * + * @param username The user name. + * @param password The password. + * @param context The request context to use when creating the session. + */ + synchronized protected void + connect(final String username, final String password, final java.util.Map<String, String> context) + { + connectImpl(new ConnectStrategy() + { + @Override + public SessionPrx connect(RouterPrx router) + throws CannotCreateSessionException, PermissionDeniedException + { + return router.createSession(username, password, context); + } + }); + } + + private void + connected(RouterPrx router, SessionPrx session) + { + // + // Remote invocation should be done without acquiring a mutex lock. + // + assert(router != null); + Ice.Connection conn = router.ice_getCachedConnection(); + String category = router.getCategoryForClient(); + int acmTimeout = 0; + try + { + acmTimeout = router.getACMTimeout(); + } + catch(Ice.OperationNotExistException ex) + { + } + + if(acmTimeout <= 0) + { + acmTimeout = (int)router.getSessionTimeout(); + } + + // + // We create the callback object adapter here because createObjectAdapter internally + // makes synchronous RPCs to the router. We can't create the OA on-demand when the + // client calls objectAdapter() or addWithUUID() because they can be called from the + // GUI thread. + // + if(_useCallbacks) + { + assert(_adapter == null); + _adapter = _communicator.createObjectAdapterWithRouter("", router); + _adapter.activate(); + } + + synchronized(this) + { + _router = router; + + if(_destroy) + { + // + // Run destroyInternal in a thread because it makes remote invocations. + // + new Thread(new Runnable() + { + @Override + public void run() + { + destroyInternal(); + } + }).start(); + return; + } + + // + // Cache the category. + // + _category = category; + + // + // Assign the session after _destroy is checked. + // + _session = session; + _connected = true; + + if(acmTimeout > 0) + { + Ice.Connection connection = _router.ice_getCachedConnection(); + assert(connection != null); + connection.setACM(new Ice.IntOptional(acmTimeout), + null, + new Ice.Optional<Ice.ACMHeartbeat>(Ice.ACMHeartbeat.HeartbeatAlways)); + connection.setCloseCallback(new Ice.CloseCallback() + { + @Override + public void closed(Ice.Connection con) + { + destroy(); + } + }); + } + + _shutdownHook = new Thread("Shutdown hook") + { + @Override + public void run() + { + SessionHelper.this.destroy(); + } + }; + + try + { + Runtime.getRuntime().addShutdownHook(_shutdownHook); + } + catch(IllegalStateException e) + { + // + // Shutdown in progress, ignored + // + } + catch(SecurityException ex) + { + // + // Ignore. Unsigned applets cannot registered shutdown hooks. + // + } + } + + dispatchCallback(new Runnable() + { + @Override + public void run() + { + try + { + _callback.connected(SessionHelper.this); + } + catch(SessionNotExistException ex) + { + SessionHelper.this.destroy(); + } + } + }, conn); + } + + private void + destroyInternal() + { + assert _destroy; + Glacier2.RouterPrx router = null; + Ice.Communicator communicator = null; + synchronized(this) + { + if(_router == null) + { + return; + } + + router = _router; + _router = null; + + communicator = _communicator; + } + + assert communicator != null; + + try + { + router.destroySession(); + } + catch(Ice.ConnectionLostException e) + { + // + // Expected if another thread invoked on an object from the session concurrently. + // + } + catch(SessionNotExistException e) + { + // + // This can also occur. + // + } + catch(Throwable e) + { + // + // Not expected. + // + communicator.getLogger().warning("SessionHelper: unexpected exception when destroying the session:\n" + e); + } + + try + { + communicator.destroy(); + } + catch(Throwable ex) + { + } + + // + // Notify the callback that the session is gone. + // + dispatchCallback(new Runnable() + { + @Override + public void run() + { + _callback.disconnected(SessionHelper.this); + } + }, null); + } + + private void + destroyCommunicator() + { + Ice.Communicator communicator = null; + synchronized(this) + { + communicator = _communicator; + } + + if(communicator != null) + { + try + { + _communicator.destroy(); + } + catch(Throwable ex) + { + } + } + } + + private void + connectImpl(final ConnectStrategy factory) + { + assert !_destroy; + + try + { + _communicator = Ice.Util.initialize(_initData); + } + catch(final Ice.LocalException ex) + { + _destroy = true; + new Thread(new Runnable() + { + @Override + public void run() + { + dispatchCallback(new Runnable() + { + @Override + public void run() + { + _callback.connectFailed(SessionHelper.this, ex); + } + }, null); + } + }).start(); + return; + } + + final Ice.RouterFinderPrx finder = + Ice.RouterFinderPrxHelper.uncheckedCast(_communicator.stringToProxy(_finderStr)); + new Thread(new Runnable() + { + @Override + public void run() + { + if(_communicator.getDefaultRouter() == null) + { + try + { + _communicator.setDefaultRouter(finder.getRouter()); + } + catch(final Ice.CommunicatorDestroyedException ex) + { + dispatchCallback(new Runnable() + { + @Override + public void run() + { + _callback.connectFailed(SessionHelper.this, ex); + } + }, null); + return; + } + catch(Exception ex) + { + // + // In case of error getting router identity from RouterFinder use + // default identity. + // + Ice.Identity ident = new Ice.Identity("router", "Glacier2"); + _communicator.setDefaultRouter(Ice.RouterPrxHelper.uncheckedCast(finder.ice_identity(ident))); + } + } + + try + { + dispatchCallbackAndWait(new Runnable() + { + @Override + public void run() + { + _callback.createdCommunicator(SessionHelper.this); + } + }); + + Glacier2.RouterPrx routerPrx = Glacier2.RouterPrxHelper.uncheckedCast( + _communicator.getDefaultRouter()); + Glacier2.SessionPrx session = factory.connect(routerPrx); + connected(routerPrx, session); + } + catch(final Exception ex) + { + try + { + _communicator.destroy(); + } + catch(Throwable ex1) + { + } + + dispatchCallback(new Runnable() + { + @Override + public void run() + { + _callback.connectFailed(SessionHelper.this, ex); + } + }, null); + } + } + }).start(); + } + + private void + dispatchCallback(Runnable runnable, Ice.Connection conn) + { + if(_initData.dispatcher != null) + { + _initData.dispatcher.dispatch(runnable, conn); + } + else + { + runnable.run(); + } + } + + private void + dispatchCallbackAndWait(final Runnable runnable) + { + if(_initData.dispatcher != null) + { + final java.util.concurrent.Semaphore sem = new java.util.concurrent.Semaphore(0); + _initData.dispatcher.dispatch( + new Runnable() + { + @Override + public void + run() + { + runnable.run(); + sem.release(); + } + }, null); + sem.acquireUninterruptibly(); + } + else + { + runnable.run(); + } + } + + private final Ice.InitializationData _initData; + private Ice.Communicator _communicator; + private Ice.ObjectAdapter _adapter; + private Glacier2.RouterPrx _router; + private Glacier2.SessionPrx _session; + private String _category; + private String _finderStr; + private boolean _useCallbacks; + + private final SessionCallback _callback; + private boolean _destroy = false; + private boolean _connected = false; + private Thread _shutdownHook; +} diff --git a/java-compat/src/Ice/build.gradle b/java-compat/src/Ice/build.gradle new file mode 100644 index 00000000000..3edcb8df149 --- /dev/null +++ b/java-compat/src/Ice/build.gradle @@ -0,0 +1,26 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "Ice Compat" +project.ext.description = "Ice is a comprehensive RPC framework that helps you build distributed applications" + + " with minimal effort using familiar object-oriented idioms" + +slice { + java { + set1 { + args = "--ice" + files = fileTree(dir: "$sliceDir", includes:['Ice/*.ice', 'IceSSL/*.ice'], excludes:['Ice/*F.ice']) + } + } +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/Ice/src/main/java/Ice/AMDCallback.java b/java-compat/src/Ice/src/main/java/Ice/AMDCallback.java new file mode 100644 index 00000000000..9ece32a5899 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/AMDCallback.java @@ -0,0 +1,23 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * AMDCallback is the interface from which all AMD callbacks are derived. + **/ +public interface AMDCallback +{ + /** + * ice_exception indicates to the Ice run time that + * the operation completed with an exception. + * @param ex The exception to be raised. + **/ + public void ice_exception(java.lang.Exception ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/AMD_Object_ice_invoke.java b/java-compat/src/Ice/src/main/java/Ice/AMD_Object_ice_invoke.java new file mode 100644 index 00000000000..5fbeb9649c6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/AMD_Object_ice_invoke.java @@ -0,0 +1,40 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback interface for <Blobject> AMD servants. + * + @see BlobjectAsync + **/ +public interface AMD_Object_ice_invoke +{ + /** + * Indicates to the Ice run time that an operation + * completed. + * + * @param ok <code>true</code> indicates that the operation + * completed successfully; <code>false</code> indicates that the + * operation raised a user exception. + * @param outEncaps The encoded out-parameters for the operation or, + * if <code>ok</code> is <code>false</code>, the encoded user exception. + **/ + void ice_response(boolean ok, byte[] outEncaps); + + /** + * Indicates to the Ice run time that an operation completed + * with a run-time exception. + * + * @param ex The encoded Ice run-time exception. Note that, if <code>ex</code> + * is a user exception, the caller receives {@link UnknownUserException}. + * Use {@link #ice_response} to raise user exceptions. + **/ + void ice_exception(java.lang.Exception ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Application.java b/java-compat/src/Ice/src/main/java/Ice/Application.java new file mode 100644 index 00000000000..3562445becb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Application.java @@ -0,0 +1,696 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Utility base class that makes it easy to correctly initialize and finalize + * the Ice run time, as well as handle signals. Unless the application specifies + * a logger, <Application> installs a per-process logger that logs to the standard + * error output. + * <p> + * Applications must create a derived class that implements the {@link #run} method. + * <p> + * A program can contain only one instance of this class. + * + * @see #run + * @see Communicator + * @see Logger + **/ +public abstract class Application +{ + /** + * Initializes an instance that calls {@link Communicator#shutdown} if + * a signal is received. + **/ + public + Application() + { + } + + /** + * Initializes an instance that handles signals according to the signal + * policy. + * + * @param signalPolicy Determines how to respond to signals. + * + * @see SignalPolicy + **/ + public + Application(SignalPolicy signalPolicy) + { + _signalPolicy = signalPolicy; + } + + /** + * The application must call <code>main</code> after it has + * instantiated the derived class. <code>main</code> creates + * a communicator, establishes the specified signal policy, and, + * once <code>run</code> returns, destroys the communicator. + * <p> + * The method prints an error message for any exception that propagates + * out of <code>run</code> and ensures that the communicator is + * destroyed correctly even if <code>run</code> completes abnormally. + * + * @param appName The name of the application. This parameter is used to initialize + * the value of the <code>Ice.ProgramName</code> property. + * @param args The arguments for the application (as passed to <code>Main(String[])</code> + * by the operating system. + * @return The value returned by <code>run</code>. If <code>run</code> terminates with an exception, + * the return value is non-zero. + **/ + public final int + main(String appName, String[] args) + { + return main(appName, args, new InitializationData()); + } + + /** + * The application must call <code>main</code> after it has + * instantiated the derived class. <code>main</code> creates + * a communicator, establishes the specified signal policy, and, + * once <code>run</code> returns, destroys the communicator. + * <p> + * The method prints an error message for any exception that propagates + * out of <code>run</code> and ensures that the communicator is + * destroyed correctly even if <code>run</code> completes abnormally. + * + * @param appName The name of the application. This parameter is used to initialize + * the value of the <code>Ice.ProgramName</code> property. + * @param configFile The configuration file with which to initialize + * Ice properties. + * @return The value returned by <code>run</code>. If <code>run</code> terminates with an exception, + * the return value is non-zero. + **/ + public final int + main(String appName, String[] args, String configFile) + { + if(Util.getProcessLogger() instanceof LoggerI) + { + Util.setProcessLogger(new LoggerI(appName, "")); + } + + InitializationData initData = new InitializationData(); + if(configFile != null) + { + try + { + initData.properties = Util.createProperties(); + initData.properties.load(configFile); + } + catch(LocalException ex) + { + Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + return 1; + } + catch(java.lang.Exception ex) + { + Util.getProcessLogger().error("unknown exception: " + IceInternal.Ex.toString(ex)); + return 1; + } + } + return main(appName, args, initData); + } + + /** + * The application must call <code>main</code> after it has + * instantiated the derived class. <code>main</code> creates + * a communicator, establishes the specified signal policy, and, + * once <code>run</code> returns, destroys the communicator. + * <p> + * The method prints an error message for any exception that propagates + * out of <code>run</code> and ensures that the communicator is + * destroyed correctly even if <code>run</code> completes abnormally. + * + * @param appName The name of the application. This parameter is used to initialize + * the value of the <code>Ice.ProgramName</code> property. + * @param args The arguments for the application (as passed to <code>Main(String[])</code>. + * @param initializationData Additional data used to initialize the communicator. + * @return The value returned by <code>run</code>. If <code>run</code> terminates with an exception, + * the return value is non-zero. + * + * @see InitializationData + **/ + public final int + main(String appName, String[] args, InitializationData initializationData) + { + if(Util.getProcessLogger() instanceof LoggerI) + { + Util.setProcessLogger(new LoggerI(appName, "")); + } + + if(_communicator != null) + { + Util.getProcessLogger().error("only one instance of the Application class can be used"); + return 1; + } + + _appName = appName; + + // + // We parse the properties here to extract Ice.ProgramName. + // + InitializationData initData; + if(initializationData != null) + { + initData = initializationData.clone(); + } + else + { + initData = new InitializationData(); + } + StringSeqHolder argHolder = new StringSeqHolder(args); + try + { + initData.properties = Util.createProperties(argHolder, initData.properties); + } + catch(LocalException ex) + { + Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + return 1; + } + catch(java.lang.Exception ex) + { + Util.getProcessLogger().error("unknown exception: " + IceInternal.Ex.toString(ex)); + return 1; + } + _appName = initData.properties.getPropertyWithDefault("Ice.ProgramName", _appName); + + // + // If the process logger is the default logger, we replace it with a + // a logger which is using the program name for the prefix. + // + if(!initData.properties.getProperty("Ice.ProgramName").equals("") && Util.getProcessLogger() instanceof LoggerI) + { + Util.setProcessLogger(new LoggerI(initData.properties.getProperty("Ice.ProgramName"), "")); + } + + return doMain(argHolder, initData); + } + + protected int + doMain(StringSeqHolder argHolder, Ice.InitializationData initData) + { + int status = 0; + + try + { + _communicator = Util.initialize(argHolder, initData); + + // + // The default is to destroy when a signal is received. + // + if(_signalPolicy == SignalPolicy.HandleSignals) + { + destroyOnInterrupt(); + } + + status = run(argHolder.value); + } + catch(LocalException ex) + { + Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + status = 1; + } + catch(java.lang.Exception ex) + { + Util.getProcessLogger().error("unknown exception: " + IceInternal.Ex.toString(ex)); + status = 1; + } + catch(java.lang.Error err) + { + // + // We catch Error to avoid hangs in some non-fatal situations + // + Util.getProcessLogger().error("Java error: " + IceInternal.Ex.toString(err)); + status = 1; + } + + // This clears any set interrupt. + if(_signalPolicy == SignalPolicy.HandleSignals) + { + defaultInterrupt(); + } + + synchronized(_mutex) + { + boolean interrupted = false; + while(_callbackInProgress) + { + try + { + _mutex.wait(); + } + catch(InterruptedException ex) + { + interrupted = true; + } + } + if(interrupted) + { + Thread.currentThread().interrupt(); + } + + if(_destroyed) + { + _communicator = null; + } + else + { + _destroyed = true; + // + // And _communicator != null, meaning will be + // destroyed next, _destroyed = true also ensures that + // any remaining callback won't do anything + // + } + } + + if(_communicator != null) + { + try + { + try + { + _communicator.destroy(); + } + catch(Ice.OperationInterruptedException ex) + { + Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + // Retry communicator destroy in case of an operation + // interrupt exception, but don't do so in a loop + // otherwise it could go on forever. + _communicator.destroy(); + } + } + catch(LocalException ex) + { + Util.getProcessLogger().error(IceInternal.Ex.toString(ex)); + status = 1; + } + catch(java.lang.Exception ex) + { + Util.getProcessLogger().error("unknown exception: " + IceInternal.Ex.toString(ex)); + status = 1; + } + _communicator = null; + } + + synchronized(_mutex) + { + if(_appHook != null) + { + _appHook.done(); + } + } + + return status; + } + + /** + * Called once the communicator has been initialized. The derived class must + * implement <code>run</code>, which is the application's starting method. + * + * @param args The argument vector for the application. <code>Application</code> + * scans the argument vector passed to <code>main</code> for options that are + * specific to the Ice run time and removes them; therefore, the vector passed + * to <code>run</code> is free from Ice-related options and contains only options + * and arguments that are application-specific. + * + * @return The <code>run</code> method should return zero for successful termination, and + * non-zero otherwise. <code>Application.main</code> returns the value returned by <code>run</code>. + **/ + public abstract int + run(String[] args); + + /** + * Returns the value of <code>appName</code> that is passed to <code>main</code> (which is also the + * the value of <code>Ice.ProgramName</code>). This method is useful mainly for error messages that + * include the application name. Because <appName> is a static method, it is available from anywhere + * in the program. + * + * @return The name of the application. + **/ + public static String + appName() + { + return _appName; + } + + /** + * Returns the communicator for the application. Because <communicator> is a static method, + * it permits access to the communicator from anywhere in the program. Note that, as a consequence, + * you cannot have more than one instance of <code>Application</code> in a program. + * + * @return The communicator for the application. + **/ + public static Communicator + communicator() + { + return _communicator; + } + + /** + * Instructs <code>Application</code> to call {@link Communicator#destroy} on receipt of a signal. + * This is default signal handling policy established by the default constructor. + * + * @see Communicator#destroy + **/ + public static void + destroyOnInterrupt() + { + if(_signalPolicy == SignalPolicy.HandleSignals) + { + synchronized(_mutex) + { + // + // As soon as the destroy hook ends all the threads are + // terminated. So the destroy hook will join the current + // thread before to end. + // + try + { + changeHook(new DestroyHook()); + } + catch(java.lang.IllegalStateException ex) + { + if(_communicator != null) + { + _communicator.destroy(); + } + } + } + } + else + { + Util.getProcessLogger().warning( + "interrupt method called on Application configured to not handle interrupts."); + } + } + + /** + * Instructs <code>Application</code> to call {@link Communicator#shutdown} on receipt of a signal. + * + * @see Communicator#shutdown + **/ + public static void + shutdownOnInterrupt() + { + if(_signalPolicy == SignalPolicy.HandleSignals) + { + synchronized(_mutex) + { + // + // As soon as the shutdown hook ends all the threads are + // terminated. So the shutdown hook will join the current + // thread before to end. + // + try + { + changeHook(new ShutdownHook()); + } + catch(java.lang.IllegalStateException ex) + { + if(_communicator != null) + { + _communicator.shutdown(); + } + } + } + } + else + { + Util.getProcessLogger().warning( + "interrupt method called on Application configured to not handle interrupts."); + } + } + + /** + * Installs a custom shutdown hook. The implementation of the shutdown + * hook can do whatever cleanup is necessary to shut down the application. + * The hook is unregistered once <code>run</code> returns. + * Note that the hook must obey the rules for shutdown hooks; specifically, + * it must not call <code>exit</code>. + * + * @param newHook The thread to run on shutdown. + * + * @see java.lang.Runtime#addShutdownHook + **/ + public static void + setInterruptHook(java.lang.Thread newHook) // Pun intended. + { + if(_signalPolicy == SignalPolicy.HandleSignals) + { + try + { + changeHook(new CustomHook(newHook)); + } + catch(java.lang.IllegalStateException ex) + { + // Ignore. + } + } + else + { + Util.getProcessLogger().warning( + "interrupt method called on Application configured to not handle interrupts."); + } + } + + /** + * Clears any shutdown hooks, including any hook established with {@link #destroyOnInterrupt} or + * {@link #shutdownOnInterrupt}. + **/ + public static void + defaultInterrupt() + { + if(_signalPolicy == SignalPolicy.HandleSignals) + { + changeHook(null); + } + else + { + Util.getProcessLogger().warning( + "interrupt method called on Application configured to not handle interrupts."); + } + } + + /** + * Determines whether the application shut down intentionally or was forced to shut down by the JVM. This + * is useful for logging purposes. + * + * @return <code>true</code> if a shutdown hook caused the communicator to shut down; false otherwise. + **/ + public static boolean + interrupted() + { + synchronized(_mutex) + { + return _interrupted; + } + } + + private static void + changeHook(AppHook newHook) + { + synchronized(_mutex) + { + // + // Remove any existing shutdown hooks. + // + try + { + if(_appHook != null) + { + Runtime.getRuntime().removeShutdownHook(_appHook); + _appHook.done(); + _appHook = null; + } + } + catch(java.lang.IllegalStateException ex) + { + // + // Expected if we are in the process of shutting down. + // + } + + // + // Note that we let the IllegalStateException propagate + // out if necessary. + // + if(newHook != null) + { + Runtime.getRuntime().addShutdownHook(newHook); + _appHook = newHook; + } + } + } + + private static boolean + setCallbackInProgress(boolean destroy) + { + synchronized(_mutex) + { + if(_destroyed) + { + // + // Being destroyed by main thread + // + return false; + } + _callbackInProgress = true; + _destroyed = destroy; + _interrupted = true; + return true; + } + } + + private static void + clearCallbackInProgress() + { + synchronized(_mutex) + { + _callbackInProgress = false; + _mutex.notify(); + } + } + + // For use by Glacier2.Application + static public class AppHook extends Thread + { + public void + done() + { + synchronized(_doneMutex) + { + _done = true; + _doneMutex.notify(); + } + } + + protected boolean _done = false; + protected final java.lang.Object _doneMutex = new java.lang.Object(); + } + + static class DestroyHook extends AppHook + { + @Override + public void + run() + { + synchronized(_doneMutex) + { + if(!setCallbackInProgress(true)) + { + return; + } + + Communicator communicator = communicator(); + if(communicator != null) + { + communicator.destroy(); + } + + clearCallbackInProgress(); + + while(!_done) + { + try + { + _doneMutex.wait(); + } + catch(InterruptedException ex) + { + break; + } + } + } + } + } + + static class ShutdownHook extends AppHook + { + @Override + public void + run() + { + synchronized(_doneMutex) + { + if(!setCallbackInProgress(false)) + { + return; + } + + Communicator communicator = communicator(); + if(communicator != null) + { + communicator.shutdown(); + } + + clearCallbackInProgress(); + + while(!_done) + { + try + { + _doneMutex.wait(); + } + catch(InterruptedException ex) + { + break; + } + } + } + } + } + + // Although this class doesn't actually use any of the AppHook + // done stuff, its more trouble than its worth to add all of the + // code necessary to support another hook member variable and + // support code. + static class CustomHook extends AppHook + { + CustomHook(Thread hook) + { + _hook = hook; + } + + @Override + public void + run() + { + synchronized(_doneMutex) + { + if(!setCallbackInProgress(false)) + { + return; + } + + _hook.run(); + + clearCallbackInProgress(); + + // + // Don't bother to join with main, we're done. + // + } + } + + private Thread _hook; + } + + protected static String _appName; + protected static Communicator _communicator; + protected static AppHook _appHook; + protected final static java.lang.Object _mutex = new java.lang.Object(); + protected static boolean _callbackInProgress = false; + protected static boolean _destroyed = false; + protected static boolean _interrupted = false; + protected static SignalPolicy _signalPolicy = SignalPolicy.HandleSignals; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/AsyncCallback.java b/java-compat/src/Ice/src/main/java/Ice/AsyncCallback.java new file mode 100644 index 00000000000..7ec2a2837ac --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/AsyncCallback.java @@ -0,0 +1,22 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * An application can optionally supply an instance of this class in an + * asynchronous invocation. The application must create a subclass and + * implement the completed method. + * + * @deprecated This class is deprecated, use Ice.Callback instead. + **/ +@Deprecated +public abstract class AsyncCallback extends Callback +{ +} diff --git a/java-compat/src/Ice/src/main/java/Ice/AsyncResult.java b/java-compat/src/Ice/src/main/java/Ice/AsyncResult.java new file mode 100644 index 00000000000..f62006ecc43 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/AsyncResult.java @@ -0,0 +1,105 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * An AsyncResult object is the return value of an asynchronous invocation. + * With this object, an application can obtain several attributes of the + * invocation and discover its outcome. + **/ +public interface AsyncResult +{ + /** + * If not completed, cancels the request. This is a local + * operation, it won't cancel the request on the server side. + * Calling <code>cancel</code> prevents a queued request from + * being sent or ignores a reply if the request has already + * been sent. + **/ + public void cancel(); + + /** + * Returns the communicator that sent the invocation. + * + * @return The communicator. + **/ + public Communicator getCommunicator(); + + /** + * Returns the connection that was used to call the <code>begin_</code> method, or nil + * if this AsyncResult object was not obtained via an asynchronous connection invocation + * (such as <code>begin_flushBatchRequests</code>). + * + * @return The connection. + **/ + public Connection getConnection(); + + /** + * Returns the proxy that was used to call the <code>begin_</code> method, or nil + * if this AsyncResult object was not obtained via an asynchronous proxy invocation. + * + * @return The proxy. + **/ + public ObjectPrx getProxy(); + + /** + * Indicates whether the result of an invocation is available. + * + * @return True if the result is available, which means a call to the <code>end_</code> + * method will not block. The method returns false if the result is not yet available. + **/ + public boolean isCompleted(); + + /** + * Blocks the caller until the result of the invocation is available. + **/ + public void waitForCompleted(); + + /** + * When you call the <code>begin_</code> method, the Ice run time attempts to + * write the corresponding request to the client-side transport. If the + * transport cannot accept the request, the Ice run time queues the request + * for later transmission. This method returns true if, at the time it is called, + * the request has been written to the local transport (whether it was initially + * queued or not). Otherwise, if the request is still queued, this method returns + * false. + * + * @return True if the request has been sent, or false if the request is queued. + **/ + public boolean isSent(); + + /** + * Blocks the caller until the request has been written to the client-side transport. + **/ + public void waitForSent(); + + /** + * If the invocation failed with a local exception, throws the local exception. + **/ + public void throwLocalException(); + + /** + * This method returns true if a request was written to the client-side + * transport without first being queued. If the request was initially + * queued, this method returns false (independent of whether the request + * is still in the queue or has since been written to the client-side transport). + * + * @return True if the request was sent without being queued, or false + * otherwise. + **/ + public boolean sentSynchronously(); + + /** + * Returns the name of the operation. + * + * @return The operation name. + **/ + public String getOperation(); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/BatchRequest.java b/java-compat/src/Ice/src/main/java/Ice/BatchRequest.java new file mode 100644 index 00000000000..c18b6da917a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/BatchRequest.java @@ -0,0 +1,33 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface BatchRequest +{ + /** + * Confirms the queuing of the batch request. + **/ + void enqueue(); + + /** + * The marshalled size of the request. + **/ + int getSize(); + + /** + * The name of the operation + **/ + String getOperation(); + + /** + * The proxy used to invoke the batch request. + **/ + Ice.ObjectPrx getProxy(); +}; diff --git a/java-compat/src/Ice/src/main/java/Ice/BatchRequestInterceptor.java b/java-compat/src/Ice/src/main/java/Ice/BatchRequestInterceptor.java new file mode 100644 index 00000000000..148225cbd21 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/BatchRequestInterceptor.java @@ -0,0 +1,28 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base interface for listening to batch request queues. + **/ +public interface BatchRequestInterceptor +{ + /** + * Called by the Ice runtime when a batch request is about to be + * added to the batch request queue of a proxy or connection. + * + * The implementation of this method must call enqueue() on the + * request to confirm its addition to the queue, if not called + * the request isn't added to the queue. The implementation can + * raise an Ice local exception to notify the caller of a failure. + * + **/ + void enqueue(Ice.BatchRequest request, int queueBatchRequestCount, int queueBatchRequestSize); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Blobject.java b/java-compat/src/Ice/src/main/java/Ice/Blobject.java new file mode 100644 index 00000000000..0a3fda4b795 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Blobject.java @@ -0,0 +1,53 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for dynamic dispatch servants. A server application + * derives a concrete servant class from <code>Blobject</code> that + * implements the {@link Blobject#ice_invoke} method. + **/ +public abstract class Blobject extends Ice.ObjectImpl +{ + /** + * Dispatch an incoming request. + * + * @param inEncaps The encoded in-parameters for the operation. + * @param outEncaps The encoded out-paramaters and return value + * for the operation. The return value follows any out-parameters. + * @param current The Current object to pass to the operation. + * @return If the operation completed successfully, the return value + * is <code>true</code>. If the operation raises a user exception, + * the return value is <code>false</code>; in this case, <code>outEncaps</code> + * must contain the encoded user exception. If the operation raises an + * Ice run-time exception, it must throw it directly. + **/ + public abstract boolean + ice_invoke(byte[] inEncaps, ByteSeqHolder outEncaps, Current current); + + @Override + public DispatchStatus + __dispatch(IceInternal.Incoming in, Current current) + { + byte[] inEncaps; + ByteSeqHolder outEncaps = new ByteSeqHolder(); + inEncaps = in.readParamEncaps(); + boolean ok = ice_invoke(inEncaps, outEncaps, current); + in.__writeParamEncaps(outEncaps.value, ok); + if(ok) + { + return DispatchStatus.DispatchOK; + } + else + { + return DispatchStatus.DispatchUserException; + } + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/BlobjectAsync.java b/java-compat/src/Ice/src/main/java/Ice/BlobjectAsync.java new file mode 100644 index 00000000000..4521de71e11 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/BlobjectAsync.java @@ -0,0 +1,50 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * <code>BlobjectAsync</code> is the base class for asynchronous dynamic + * dispatch servants. A server application derives a concrete servant + * class that implements the {@link BlobjectAsync#ice_invoke_async} method, + * which is called by the Ice run time to deliver every request on this + * object. + **/ +public abstract class BlobjectAsync extends Ice.ObjectImpl +{ + /** + * Dispatch an incoming request. + * + * @param cb The callback object through which the invocation's results + * must be delivered. + * @param inEncaps The encoded input parameters. + * @param current The Current object, which provides important information + * about the request, such as the identity of the target object and the + * name of the operation. + **/ + public abstract void + ice_invoke_async(AMD_Object_ice_invoke cb, byte[] inEncaps, Current current); + + @Override + public DispatchStatus + __dispatch(IceInternal.Incoming in, Current current) + { + byte[] inEncaps = in.readParamEncaps(); + AMD_Object_ice_invoke cb = new _AMD_Object_ice_invoke(in); + try + { + ice_invoke_async(cb, inEncaps, current); + } + catch(java.lang.Exception ex) + { + cb.ice_exception(ex); + } + return DispatchStatus.DispatchAsync; + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/BooleanHolder.java b/java-compat/src/Ice/src/main/java/Ice/BooleanHolder.java new file mode 100644 index 00000000000..7233a0d27fc --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/BooleanHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for booleans that are out- or inout-parameters. + **/ +public final class BooleanHolder extends Holder<Boolean> +{ + /** + * Instantiates the class with the value <code>false</code>. + **/ + public + BooleanHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * @param value The <code>boolean</code> value stored by this holder. + **/ + public + BooleanHolder(boolean value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/BooleanOptional.java b/java-compat/src/Ice/src/main/java/Ice/BooleanOptional.java new file mode 100644 index 00000000000..e6275db43ae --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/BooleanOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional boolean parameter. + **/ +public class BooleanOptional +{ + /** + * The value defaults to unset. + **/ + public BooleanOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public BooleanOptional(boolean v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public BooleanOptional(BooleanOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public boolean get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(boolean v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(BooleanOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = false; + } + + private boolean _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ByteHolder.java b/java-compat/src/Ice/src/main/java/Ice/ByteHolder.java new file mode 100644 index 00000000000..ac54599f84d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ByteHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for bytes that are out- or inout-parameters. + **/ +public final class ByteHolder extends Holder<Byte> +{ + /** + * Instantiates the class with the value zero. + **/ + public + ByteHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * @param value The <code>byte</code> value stored by this holder. + **/ + public + ByteHolder(byte value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ByteOptional.java b/java-compat/src/Ice/src/main/java/Ice/ByteOptional.java new file mode 100644 index 00000000000..493bfaf34a4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ByteOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional byte parameter. + **/ +public class ByteOptional +{ + /** + * The value defaults to unset. + **/ + public ByteOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public ByteOptional(byte v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public ByteOptional(ByteOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public byte get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(byte v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(ByteOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = 0; + } + + private byte _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback.java b/java-compat/src/Ice/src/main/java/Ice/Callback.java new file mode 100644 index 00000000000..0d852d6d4c6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback.java @@ -0,0 +1,57 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * An application can optionally supply an instance of this class in an + * asynchronous invocation. The application must create a subclass and + * implement the completed method. + **/ +public abstract class Callback extends IceInternal.CallbackBase +{ + /** + * Invoked when the invocation completes. The subclass should + * call the matching <code>end_OP</code> method on the proxy and + * must be prepared to handle exceptions. + * + * @param r The asynchronous result object returned by the <code>begin_OP</code> method. + **/ + public abstract void completed(AsyncResult r); + + /** + * Invoked when the Ice run time has passed the outgoing message + * buffer to the transport. The default implementation does nothing, + * a subclass can override it if it needs to take action when the + * message is successfully sent. + * + * @param r The asynchronous result object returned by the <code>begin_OP</code> method. + **/ + public void sent(AsyncResult r) + { + } + + @Override + public final void __completed(AsyncResult r) + { + completed(r); + } + + @Override + public final void __sent(AsyncResult r) + { + sent(r); + } + + @Override + public final boolean __hasSentCallback() + { + return true; + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Communicator_flushBatchRequests.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Communicator_flushBatchRequests.java new file mode 100644 index 00000000000..ef8fabded16 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Communicator_flushBatchRequests.java @@ -0,0 +1,55 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Asynchronous callback base class for Communicator.begin_flushBatchRequests. + **/ +public abstract class Callback_Communicator_flushBatchRequests extends IceInternal.CallbackBase +{ + /** + * Called when the invocation raises an Ice run-time exception. + * + * @param ex The Ice run-time exception raised by the operation. + **/ + public abstract void exception(LocalException ex); + + /** + * Called when a queued invocation is sent successfully. + **/ + public void sent(boolean sentSynchronously) + { + } + + @Override + public final void __completed(AsyncResult __result) + { + try + { + __result.getCommunicator().end_flushBatchRequests(__result); + } + catch(LocalException __ex) + { + exception(__ex); + } + } + + @Override + public final void __sent(AsyncResult __result) + { + sent(__result.sentSynchronously()); + } + + @Override + public final boolean __hasSentCallback() + { + return true; + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Connection_flushBatchRequests.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Connection_flushBatchRequests.java new file mode 100644 index 00000000000..0386c6c8abf --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Connection_flushBatchRequests.java @@ -0,0 +1,55 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Asynchronous callback base class for Connection.begin_flushBatchRequests. + **/ +public abstract class Callback_Connection_flushBatchRequests extends IceInternal.CallbackBase +{ + /** + * Called when the invocation raises an Ice run-time exception. + * + * @param ex The Ice run-time exception raised by the operation. + **/ + public abstract void exception(LocalException ex); + + /** + * Called when a queued invocation is sent successfully. + **/ + public void sent(boolean sentSynchronously) + { + } + + @Override + public final void __completed(AsyncResult __result) + { + try + { + __result.getConnection().end_flushBatchRequests(__result); + } + catch(LocalException __ex) + { + exception(__ex); + } + } + + @Override + public final void __sent(AsyncResult __result) + { + sent(__result.sentSynchronously()); + } + + @Override + public final boolean __hasSentCallback() + { + return true; + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_flushBatchRequests.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_flushBatchRequests.java new file mode 100644 index 00000000000..2154e37cfa4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_flushBatchRequests.java @@ -0,0 +1,22 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_flushBatchRequests}. + **/ +public abstract class Callback_Object_ice_flushBatchRequests extends OnewayCallback +{ + @Override + public final void response() + { + // Not used. + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_getConnection.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_getConnection.java new file mode 100644 index 00000000000..f65533fdaf1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_getConnection.java @@ -0,0 +1,31 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_getConnection}. + **/ +public abstract class Callback_Object_ice_getConnection extends IceInternal.TwowayCallback + implements Ice.TwowayCallbackArg1<Ice.Connection> +{ + /** + * Called when the invocation completes successfully. + * + * @param __ret The connection being used by the proxy. + **/ + @Override + public abstract void response(Ice.Connection __ret); + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_getConnection_completed(this, __result); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_id.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_id.java new file mode 100644 index 00000000000..541989f45da --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_id.java @@ -0,0 +1,31 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_id}. + **/ +public abstract class Callback_Object_ice_id extends IceInternal.TwowayCallback + implements Ice.TwowayCallbackArg1<String> +{ + /** + * Called when the invocation completes successfully. + * + * @param __ret The Slice type id of the most-derived interface supported by the target object. + **/ + @Override + public abstract void response(String __ret); + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_id_completed(this, __result); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_ids.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_ids.java new file mode 100644 index 00000000000..ab2ecbd5a95 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_ids.java @@ -0,0 +1,31 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_ids}. + **/ +public abstract class Callback_Object_ice_ids extends IceInternal.TwowayCallback + implements Ice.TwowayCallbackArg1<String[]> +{ + /** + * Called when the invocation completes successfully. + * + * @param __ret The Slice type ids of the interfaces supported by the target object. + **/ + @Override + public abstract void response(String[] __ret); + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_ids_completed(this, __result); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_invoke.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_invoke.java new file mode 100644 index 00000000000..a60a22ce7ff --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_invoke.java @@ -0,0 +1,36 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_invoke}. + **/ +public abstract class Callback_Object_ice_invoke + extends IceInternal.TwowayCallback implements _Callback_Object_ice_invoke +{ + /** + * The Ice run time calls <code>response</code> when an asynchronous operation invocation + * completes successfully or raises a user exception. + * + * @param ret Indicates the result of the invocation. If <code>true</code>, the operation + * completed succesfully; if <code>false</code>, the operation raised a user exception. + * @param outParams Contains the encoded out-parameters of the operation (if any) if <code>ok</code> + * is <code>true</code>; otherwise, if <code>ok</code> is <code>false</code>, contains the + * encoded user exception raised by the operation. + **/ + @Override + public abstract void response(boolean ret, byte[] outParams); + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_invoke_completed(this, __result); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_isA.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_isA.java new file mode 100644 index 00000000000..8ccba433133 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_isA.java @@ -0,0 +1,30 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_isA}. + **/ +public abstract class Callback_Object_ice_isA extends IceInternal.TwowayCallback implements Ice.TwowayCallbackBool +{ + /** + * Called when the invocation completes successfully. + * + * @param __ret True if the target object supports the given interface, false otherwise. + **/ + @Override + public abstract void response(boolean __ret); + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_isA_completed(this, __result); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_ping.java b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_ping.java new file mode 100644 index 00000000000..61be444f1bc --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Callback_Object_ice_ping.java @@ -0,0 +1,17 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_ping}. + **/ +public abstract class Callback_Object_ice_ping extends OnewayCallback +{ +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ClassResolver.java b/java-compat/src/Ice/src/main/java/Ice/ClassResolver.java new file mode 100644 index 00000000000..87be1d49ce3 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ClassResolver.java @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * + * A ClassResolver translates a Slice type Id into a Java class using + * an implementation-defined algorithm. + * + **/ +public interface ClassResolver +{ + /** + * Resolve a Slice type Id into a Java class. The type Id corresponds to a + * Slice value or user exception. + * + * @param typeId A string type ID (such as <code>"::Module::Class"</code>). + * @return The Java class object corresponding to the Slice type ID, or null + * if no class could be found. + **/ + Class<?> resolveClass(String typeId); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java b/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java new file mode 100644 index 00000000000..5523f7663b4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/CommunicatorI.java @@ -0,0 +1,389 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public final class CommunicatorI implements Communicator +{ + @Override + public void + destroy() + { + _instance.destroy(); + } + + @Override + public void + shutdown() + { + _instance.objectAdapterFactory().shutdown(); + } + + @Override + public void + waitForShutdown() + { + _instance.objectAdapterFactory().waitForShutdown(); + } + + @Override + public boolean + isShutdown() + { + return _instance.objectAdapterFactory().isShutdown(); + } + + @Override + public Ice.ObjectPrx + stringToProxy(String s) + { + return _instance.proxyFactory().stringToProxy(s); + } + + @Override + public String + proxyToString(Ice.ObjectPrx proxy) + { + return _instance.proxyFactory().proxyToString(proxy); + } + + @Override + public Ice.ObjectPrx + propertyToProxy(String s) + { + return _instance.proxyFactory().propertyToProxy(s); + } + + @Override + public java.util.Map<String, String> + proxyToProperty(Ice.ObjectPrx proxy, String prefix) + { + return _instance.proxyFactory().proxyToProperty(proxy, prefix); + } + + @Override @SuppressWarnings("deprecation") + public Ice.Identity + stringToIdentity(String s) + { + return Ice.Util.stringToIdentity(s); + } + + @Override @SuppressWarnings("deprecation") + public String + identityToString(Ice.Identity ident) + { + return Ice.Util.identityToString(ident); + } + + @Override + public ObjectAdapter + createObjectAdapter(String name) + { + return _instance.objectAdapterFactory().createObjectAdapter(name, null); + } + + @Override + public ObjectAdapter + createObjectAdapterWithEndpoints(String name, String endpoints) + { + if(name.length() == 0) + { + name = java.util.UUID.randomUUID().toString(); + } + + getProperties().setProperty(name + ".Endpoints", endpoints); + return _instance.objectAdapterFactory().createObjectAdapter(name, null); + } + + @Override + public ObjectAdapter + createObjectAdapterWithRouter(String name, RouterPrx router) + { + if(name.length() == 0) + { + name = java.util.UUID.randomUUID().toString(); + } + + // + // We set the proxy properties here, although we still use the proxy supplied. + // + java.util.Map<String, String> properties = proxyToProperty(router, name + ".Router"); + for(java.util.Map.Entry<String, String> p : properties.entrySet()) + { + getProperties().setProperty(p.getKey(), p.getValue()); + } + + return _instance.objectAdapterFactory().createObjectAdapter(name, router); + } + + @Override @SuppressWarnings("deprecation") + public void addObjectFactory(ObjectFactory factory, String id) + { + _instance.addObjectFactory(factory, id); + } + + @Override @SuppressWarnings("deprecation") + public ObjectFactory findObjectFactory(String id) + { + return _instance.findObjectFactory(id); + } + + @Override + public ValueFactoryManager getValueFactoryManager() + { + return _instance.initializationData().valueFactoryManager; + } + + @Override + public Properties + getProperties() + { + return _instance.initializationData().properties; + } + + @Override + public Logger + getLogger() + { + return _instance.initializationData().logger; + } + + @Override + public Ice.Instrumentation.CommunicatorObserver + getObserver() + { + return _instance.initializationData().observer; + } + + @Override + public RouterPrx + getDefaultRouter() + { + return _instance.referenceFactory().getDefaultRouter(); + } + + @Override + public void + setDefaultRouter(RouterPrx router) + { + _instance.setDefaultRouter(router); + } + + @Override + public LocatorPrx + getDefaultLocator() + { + return _instance.referenceFactory().getDefaultLocator(); + } + + @Override + public void + setDefaultLocator(LocatorPrx locator) + { + _instance.setDefaultLocator(locator); + } + + @Override + public ImplicitContext + getImplicitContext() + { + return _instance.getImplicitContext(); + } + + @Override + public PluginManager + getPluginManager() + { + return _instance.pluginManager(); + } + + @Override + public void + flushBatchRequests() + { + end_flushBatchRequests(begin_flushBatchRequests()); + } + + @Override + public AsyncResult + begin_flushBatchRequests() + { + return begin_flushBatchRequestsInternal(null); + } + + @Override + public AsyncResult + begin_flushBatchRequests(Callback cb) + { + return begin_flushBatchRequestsInternal(cb); + } + + @Override + public AsyncResult + begin_flushBatchRequests(Callback_Communicator_flushBatchRequests cb) + { + return begin_flushBatchRequestsInternal(cb); + } + + @Override + public AsyncResult + begin_flushBatchRequests(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_flushBatchRequestsInternal( + new IceInternal.Functional_CallbackBase(false, __exceptionCb, __sentCb) + { + @Override + public final void __completed(AsyncResult __result) + { + try + { + __result.getCommunicator().end_flushBatchRequests(__result); + } + catch(Exception __ex) + { + __exceptionCb.apply(__ex); + } + } + }); + } + + private static final String __flushBatchRequests_name = "flushBatchRequests"; + + private Ice.AsyncResult + begin_flushBatchRequestsInternal(IceInternal.CallbackBase cb) + { + IceInternal.OutgoingConnectionFactory connectionFactory = _instance.outgoingConnectionFactory(); + IceInternal.ObjectAdapterFactory adapterFactory = _instance.objectAdapterFactory(); + + // + // This callback object receives the results of all invocations + // of Connection.begin_flushBatchRequests. + // + IceInternal.CommunicatorFlushBatch result = new IceInternal.CommunicatorFlushBatch(this, + _instance, + __flushBatchRequests_name, + cb); + + connectionFactory.flushAsyncBatchRequests(result); + adapterFactory.flushAsyncBatchRequests(result); + + // + // Inform the callback that we have finished initiating all of the + // flush requests. + // + result.ready(); + + return result; + } + + @Override + public void + end_flushBatchRequests(AsyncResult r) + { + IceInternal.CommunicatorFlushBatch ri = + IceInternal.CommunicatorFlushBatch.check(r, this, __flushBatchRequests_name); + ri.__wait(); + } + + + @Override + public ObjectPrx + createAdmin(ObjectAdapter adminAdapter, Identity adminId) + { + return _instance.createAdmin(adminAdapter, adminId); + } + + @Override + public ObjectPrx + getAdmin() + { + return _instance.getAdmin(); + } + + @Override + public void + addAdminFacet(Object servant, String facet) + { + _instance.addAdminFacet(servant, facet); + } + + @Override + public Object + removeAdminFacet(String facet) + { + return _instance.removeAdminFacet(facet); + } + + @Override + public Object + findAdminFacet(String facet) + { + return _instance.findAdminFacet(facet); + } + + @Override + public java.util.Map<String, Ice.Object> + findAllAdminFacets() + { + return _instance.findAllAdminFacets(); + } + + CommunicatorI(InitializationData initData) + { + _instance = new IceInternal.Instance(this, initData); + } + + /** + * For compatibility with C#, we do not invoke methods on other objects + * from within a finalizer. + * + protected synchronized void + finalize() + throws Throwable + { + if(!_instance.destroyed()) + { + _instance.logger().warning("Ice::Communicator::destroy() has not been called"); + } + + super.finalize(); + } + */ + + // + // Certain initialization tasks need to be completed after the + // constructor. + // + void + finishSetup(StringSeqHolder args) + { + try + { + _instance.finishSetup(args, this); + } + catch(RuntimeException ex) + { + _instance.destroy(); + throw ex; + } + } + + // + // For use by IceInternal.Util.getInstance() + // + public IceInternal.Instance + getInstance() + { + return _instance; + } + + private IceInternal.Instance _instance; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/CompactIdResolver.java b/java-compat/src/Ice/src/main/java/Ice/CompactIdResolver.java new file mode 100644 index 00000000000..d959ab38904 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/CompactIdResolver.java @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Applications that make use of compact type IDs to conserve space + * when marshaling class instances, and also use the streaming API to + * extract such classes, can intercept the translation between compact + * type IDs and their corresponding string type IDs by installing an + * instance of <code>CompactIdResolver</code> in <code>InitializationData</code>. + **/ +public interface CompactIdResolver +{ + /** + * Translates a compact (integer) ID into its string equivalent. + * + * @param id The compact ID. + * @return A string type ID (such as <code>"::Module::Class"</code>), + * or an empty string if the compact ID is unknown. + **/ + String resolve(int id); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java b/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java new file mode 100644 index 00000000000..cac2a6fb3d2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ConnectionI.java @@ -0,0 +1,3030 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +import java.util.concurrent.Callable; + +public final class ConnectionI extends IceInternal.EventHandler + implements Connection, IceInternal.ResponseHandler, IceInternal.CancellationHandler +{ + public interface StartCallback + { + void connectionStartCompleted(ConnectionI connection); + + void connectionStartFailed(ConnectionI connection, Ice.LocalException ex); + } + + private class TimeoutCallback implements Runnable + { + @Override + public void run() + { + timedOut(); + } + } + + public void start(StartCallback callback) + { + try + { + synchronized(this) + { + // The connection might already be closed if the communicator + // was destroyed. + if(_state >= StateClosed) + { + assert (_exception != null); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + if(!initialize(IceInternal.SocketOperation.None) || !validate(IceInternal.SocketOperation.None)) + { + _startCallback = callback; + return; + } + + // + // We start out in holding state. + // + setState(StateHolding); + } + } + catch(Ice.LocalException ex) + { + exception(ex); + callback.connectionStartFailed(this, _exception); + return; + } + + callback.connectionStartCompleted(this); + } + + public void startAndWait() throws InterruptedException + { + try + { + synchronized(this) + { + // The connection might already be closed if the communicator + // was destroyed. + if(_state >= StateClosed) + { + assert (_exception != null); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + if(!initialize(IceInternal.SocketOperation.None) || !validate(IceInternal.SocketOperation.None)) + { + while(_state <= StateNotValidated) + { + wait(); + } + + if(_state >= StateClosing) + { + assert (_exception != null); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + } + + // + // We start out in holding state. + // + setState(StateHolding); + } + } + catch(Ice.LocalException ex) + { + exception(ex); + waitUntilFinished(); + } + } + + public synchronized void activate() + { + if(_state <= StateNotValidated) + { + return; + } + + if(_acmLastActivity > 0) + { + _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); + } + + setState(StateActive); + } + + public synchronized void hold() + { + if(_state <= StateNotValidated) + { + return; + } + + setState(StateHolding); + } + + // DestructionReason. + public final static int ObjectAdapterDeactivated = 0; + public final static int CommunicatorDestroyed = 1; + + synchronized public void destroy(int reason) + { + switch(reason) + { + case ObjectAdapterDeactivated: + { + setState(StateClosing, new ObjectAdapterDeactivatedException()); + break; + } + + case CommunicatorDestroyed: + { + setState(StateClosing, new CommunicatorDestroyedException()); + break; + } + } + } + + @Override + synchronized public void close(boolean force) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + if(force) + { + setState(StateClosed, new ForcedCloseConnectionException()); + } + else + { + // + // If we do a graceful shutdown, then we wait until all + // outstanding requests have been completed. Otherwise, + // the CloseConnectionException will cause all outstanding + // requests to be retried, regardless of whether the + // server has processed them or not. + // + while(!_asyncRequests.isEmpty()) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + + setState(StateClosing, new CloseConnectionException()); + } + } + + public synchronized boolean isActiveOrHolding() + { + return _state > StateNotValidated && _state < StateClosing; + } + + public synchronized boolean isFinished() + { + if(_state != StateFinished || _dispatchCount != 0) + { + return false; + } + + assert (_state == StateFinished); + return true; + } + + public synchronized void throwException() + { + if(_exception != null) + { + assert (_state >= StateClosing); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + } + + public synchronized void waitUntilHolding() throws InterruptedException + { + while(_state < StateHolding || _dispatchCount > 0) + { + wait(); + } + } + + public synchronized void waitUntilFinished() throws InterruptedException + { + // + // We wait indefinitely until the connection is finished and all + // outstanding requests are completed. Otherwise we couldn't + // guarantee that there are no outstanding calls when deactivate() + // is called on the servant locators. + // + while(_state < StateFinished || _dispatchCount > 0) + { + wait(); + } + + assert (_state == StateFinished); + + // + // Clear the OA. See bug 1673 for the details of why this is necessary. + // + _adapter = null; + } + + synchronized public void updateObserver() + { + if(_state < StateNotValidated || _state > StateClosed) + { + return; + } + + assert (_instance.initializationData().observer != null); + _observer = _instance.initializationData().observer.getConnectionObserver(initConnectionInfo(), + _endpoint, + toConnectionState(_state), + _observer); + if(_observer != null) + { + _observer.attach(); + } + else + { + _writeStreamPos = -1; + _readStreamPos = -1; + } + } + + synchronized public void monitor(long now, IceInternal.ACMConfig acm) + { + if(_state != StateActive) + { + return; + } + + // + // We send a heartbeat if there was no activity in the last + // (timeout / 4) period. Sending a heartbeat sooner than + // really needed is safer to ensure that the receiver will + // receive in time the heartbeat. Sending the heartbeat if + // there was no activity in the last (timeout / 2) period + // isn't enough since monitor() is called only every (timeout + // / 2) period. + // + // Note that this doesn't imply that we are sending 4 + // heartbeats per timeout period because the monitor() method + // is sill only called every (timeout / 2) period. + // + if(acm.heartbeat == ACMHeartbeat.HeartbeatAlways || + (acm.heartbeat != ACMHeartbeat.HeartbeatOff && _writeStream.isEmpty() && + now >= (_acmLastActivity + acm.timeout / 4))) + { + if(acm.heartbeat != ACMHeartbeat.HeartbeatOnInvocation || _dispatchCount > 0) + { + heartbeat(); + } + } + + if(_readStream.size() > IceInternal.Protocol.headerSize || !_writeStream.isEmpty()) + { + // + // If writing or reading, nothing to do, the connection + // timeout will kick-in if writes or reads don't progress. + // This check is necessary because the activity timer is + // only set when a message is fully read/written. + // + return; + } + + if(acm.close != ACMClose.CloseOff && now >= (_acmLastActivity + acm.timeout)) + { + if(acm.close == ACMClose.CloseOnIdleForceful || + (acm.close != ACMClose.CloseOnIdle && (!_asyncRequests.isEmpty()))) + { + // + // Close the connection if we didn't receive a heartbeat in + // the last period. + // + setState(StateClosed, new ConnectionTimeoutException()); + } + else if(acm.close != ACMClose.CloseOnInvocation && _dispatchCount == 0 && _batchRequestQueue.isEmpty() && + _asyncRequests.isEmpty()) + { + // + // The connection is idle, close it. + // + setState(StateClosing, new ConnectionTimeoutException()); + } + } + } + + synchronized public int + sendAsyncRequest(IceInternal.OutgoingAsyncBase out, boolean compress, boolean response, int batchRequestNum) + throws IceInternal.RetryException + { + final OutputStream os = out.getOs(); + + if(_exception != null) + { + // + // If the connection is closed before we even have a chance + // to send our request, we always try to send the request + // again. + // + throw new IceInternal.RetryException((Ice.LocalException) _exception.fillInStackTrace()); + } + + assert (_state > StateNotValidated); + assert (_state < StateClosing); + + // + // Ensure the message isn't bigger than what we can send with the + // transport. + // + _transceiver.checkSendSize(os.getBuffer()); + + // + // Notify the request that it's cancelable with this connection. + // This will throw if the request is canceled. + // + out.cancelable(this); + + int requestId = 0; + if(response) + { + // + // Create a new unique request ID. + // + requestId = _nextRequestId++; + if(requestId <= 0) + { + _nextRequestId = 1; + requestId = _nextRequestId++; + } + + // + // Fill in the request ID. + // + os.pos(IceInternal.Protocol.headerSize); + os.writeInt(requestId); + } + else if(batchRequestNum > 0) + { + os.pos(IceInternal.Protocol.headerSize); + os.writeInt(batchRequestNum); + } + + out.attachRemoteObserver(initConnectionInfo(), _endpoint, requestId); + + int status; + try + { + status = sendMessage(new OutgoingMessage(out, os, compress, requestId)); + } + catch(Ice.LocalException ex) + { + setState(StateClosed, ex); + assert (_exception != null); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + if(response) + { + // + // Add to the async requests map. + // + _asyncRequests.put(requestId, out); + } + return status; + } + + public IceInternal.BatchRequestQueue + getBatchRequestQueue() + { + return _batchRequestQueue; + } + + @Override + public void flushBatchRequests() + { + end_flushBatchRequests(begin_flushBatchRequests()); + } + + private static final String __flushBatchRequests_name = "flushBatchRequests"; + + @Override + public Ice.AsyncResult begin_flushBatchRequests() + { + return begin_flushBatchRequestsInternal(null); + } + + @Override + public Ice.AsyncResult begin_flushBatchRequests(Callback cb) + { + return begin_flushBatchRequestsInternal(cb); + } + + @Override + public Ice.AsyncResult begin_flushBatchRequests(Callback_Connection_flushBatchRequests cb) + { + return begin_flushBatchRequestsInternal(cb); + } + + @Override + public AsyncResult begin_flushBatchRequests(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_flushBatchRequestsInternal(new IceInternal.Functional_CallbackBase(false, __exceptionCb, __sentCb) + { + @Override + public final void __completed(AsyncResult __result) + { + try + { + __result.getConnection().end_flushBatchRequests(__result); + } + catch(Exception __ex) + { + __exceptionCb.apply(__ex); + } + } + }); + } + + private Ice.AsyncResult begin_flushBatchRequestsInternal(IceInternal.CallbackBase cb) + { + IceInternal.ConnectionFlushBatch result = + new IceInternal.ConnectionFlushBatch(this, _communicator, _instance, __flushBatchRequests_name, cb); + result.invoke(); + return result; + } + + @Override + public void end_flushBatchRequests(AsyncResult ir) + { + IceInternal.ConnectionFlushBatch r = + IceInternal.ConnectionFlushBatch.check(ir, this, __flushBatchRequests_name); + r.__wait(); + } + + @Override + synchronized public void setCloseCallback(final CloseCallback callback) + { + if(_state >= StateClosed) + { + if(callback != null) + { + _threadPool.dispatch(new IceInternal.DispatchWorkItem(this) + { + @Override + public void run() + { + try + { + callback.closed(ConnectionI.this); + } + catch(Exception ex) + { + _logger.error("connection callback exception:\n" + ex + '\n' + _desc); + } + } + }); + } + } + else + { + _closeCallback = callback; + } + } + + @Override + synchronized public void setHeartbeatCallback(final HeartbeatCallback callback) + { + _heartbeatCallback = callback; + } + + @Override + synchronized public void setACM(Ice.IntOptional timeout, Ice.Optional<ACMClose> close, + Ice.Optional<ACMHeartbeat> heartbeat) + { + if(_monitor == null || _state >= StateClosed) + { + return; + } + + if(_state == StateActive) + { + _monitor.remove(this); + } + _monitor = _monitor.acm(timeout, close, heartbeat); + + if(_monitor.getACM().timeout <= 0) + { + _acmLastActivity = -1; // Disable the recording of last activity. + } + else if(_state == StateActive && _acmLastActivity == -1) + { + _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); + } + + if(_state == StateActive) + { + _monitor.add(this); + } + } + + @Override + synchronized public Ice.ACM getACM() + { + return _monitor != null ? _monitor.getACM() : new ACM(0, ACMClose.CloseOff, ACMHeartbeat.HeartbeatOff); + } + + @Override + synchronized public void asyncRequestCanceled(IceInternal.OutgoingAsyncBase outAsync, Ice.LocalException ex) + { + if(_state >= StateClosed) + { + return; // The request has already been or will be shortly notified of the failure. + } + + java.util.Iterator<OutgoingMessage> it = _sendStreams.iterator(); + while(it.hasNext()) + { + OutgoingMessage o = it.next(); + if(o.outAsync == outAsync) + { + if(o.requestId > 0) + { + _asyncRequests.remove(o.requestId); + } + + if(ex instanceof ConnectionTimeoutException) + { + setState(StateClosed, ex); + } + else + { + // + // If the request is being sent, don't remove it from the send + // streams, it will be removed once the sending is finished. + // + // Note that since we swapped the message stream to _writeStream + // it's fine if the OutgoingAsync output stream is released (and + // as long as canceled requests cannot be retried). + // + o.canceled(); + if(o != _sendStreams.getFirst()) + { + it.remove(); + } + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + } + return; + } + } + + if(outAsync instanceof IceInternal.OutgoingAsync) + { + IceInternal.OutgoingAsync o = (IceInternal.OutgoingAsync) outAsync; + java.util.Iterator<IceInternal.OutgoingAsyncBase> it2 = _asyncRequests.values().iterator(); + while(it2.hasNext()) + { + if(it2.next() == o) + { + if(ex instanceof ConnectionTimeoutException) + { + setState(StateClosed, ex); + } + else + { + it2.remove(); + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + } + return; + } + } + } + } + + @Override + synchronized public void sendResponse(int requestId, OutputStream os, byte compressFlag, boolean amd) + { + assert (_state > StateNotValidated); + + try + { + if(--_dispatchCount == 0) + { + if(_state == StateFinished) + { + reap(); + } + notifyAll(); + } + + if(_state >= StateClosed) + { + assert (_exception != null); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + sendMessage(new OutgoingMessage(os, compressFlag != 0, true)); + + if(_state == StateClosing && _dispatchCount == 0) + { + initiateShutdown(); + } + } + catch(LocalException ex) + { + setState(StateClosed, ex); + } + } + + @Override + synchronized public void sendNoResponse() + { + assert (_state > StateNotValidated); + try + { + if(--_dispatchCount == 0) + { + if(_state == StateFinished) + { + reap(); + } + notifyAll(); + } + + if(_state >= StateClosed) + { + assert (_exception != null); + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + if(_state == StateClosing && _dispatchCount == 0) + { + initiateShutdown(); + } + } + catch(LocalException ex) + { + setState(StateClosed, ex); + } + } + + @Override + public boolean systemException(int requestId, Ice.SystemException ex, boolean amd) + { + return false; // System exceptions aren't marshalled. + } + + @Override + public synchronized void invokeException(int requestId, LocalException ex, int invokeNum, boolean amd) + { + // + // Fatal exception while invoking a request. Since + // sendResponse/sendNoResponse isn't + // called in case of a fatal exception we decrement _dispatchCount here. + // + + setState(StateClosed, ex); + + if(invokeNum > 0) + { + assert (_dispatchCount > 0); + _dispatchCount -= invokeNum; + assert (_dispatchCount >= 0); + if(_dispatchCount == 0) + { + if(_state == StateFinished) + { + reap(); + } + notifyAll(); + } + } + } + + public IceInternal.EndpointI endpoint() + { + return _endpoint; // No mutex protection necessary, _endpoint is + // immutable. + } + + public IceInternal.Connector connector() + { + return _connector; // No mutex protection necessary, _connector is + // immutable. + } + + @Override + public synchronized void setAdapter(ObjectAdapter adapter) + { + if(_state <= StateNotValidated || _state >= StateClosing) + { + return; + } + + _adapter = adapter; + + if(_adapter != null) + { + _servantManager = ((ObjectAdapterI) _adapter).getServantManager(); + if(_servantManager == null) + { + _adapter = null; + } + } + else + { + _servantManager = null; + } + + // + // We never change the thread pool with which we were + // initially registered, even if we add or remove an object + // adapter. + // + } + + @Override + public synchronized ObjectAdapter getAdapter() + { + return _adapter; + } + + @Override + public Endpoint getEndpoint() + { + return _endpoint; // No mutex protection necessary, _endpoint is + // immutable. + } + + @Override + public ObjectPrx createProxy(Identity ident) + { + // + // Create a reference and return a reverse proxy for this + // reference. + // + return _instance.proxyFactory().referenceToProxy(_instance.referenceFactory().create(ident, this)); + } + + // + // Operations from EventHandler + // + @Override + public void message(IceInternal.ThreadPoolCurrent current) + { + StartCallback startCB = null; + java.util.List<OutgoingMessage> sentCBs = null; + MessageInfo info = null; + int dispatchCount = 0; + + synchronized(this) + { + if(_state >= StateClosed) + { + return; + } + + if(!current.ioReady()) + { + return; + } + + int readyOp = current.operation; + try + { + unscheduleTimeout(current.operation); + + int writeOp = IceInternal.SocketOperation.None; + int readOp = IceInternal.SocketOperation.None; + + if((readyOp & IceInternal.SocketOperation.Write) != 0) + { + final IceInternal.Buffer buf = _writeStream.getBuffer(); + if(_observer != null) + { + observerStartWrite(buf); + } + writeOp = write(buf); + if(_observer != null && (writeOp & IceInternal.SocketOperation.Write) == 0) + { + observerFinishWrite(buf); + } + } + + while((readyOp & IceInternal.SocketOperation.Read) != 0) + { + final IceInternal.Buffer buf = _readStream.getBuffer(); + if(_observer != null && !_readHeader) + { + observerStartRead(buf); + } + + readOp = read(buf); + if((readOp & IceInternal.SocketOperation.Read) != 0) + { + break; + } + if(_observer != null && !_readHeader) + { + assert (!buf.b.hasRemaining()); + observerFinishRead(buf); + } + + if(_readHeader) // Read header if necessary. + { + _readHeader = false; + + if(_observer != null) + { + _observer.receivedBytes(IceInternal.Protocol.headerSize); + } + + int pos = _readStream.pos(); + if(pos < IceInternal.Protocol.headerSize) + { + // + // This situation is possible for small UDP packets. + // + throw new Ice.IllegalMessageSizeException(); + } + + _readStream.pos(0); + byte[] m = new byte[4]; + m[0] = _readStream.readByte(); + m[1] = _readStream.readByte(); + m[2] = _readStream.readByte(); + m[3] = _readStream.readByte(); + if(m[0] != IceInternal.Protocol.magic[0] || m[1] != IceInternal.Protocol.magic[1] || + m[2] != IceInternal.Protocol.magic[2] || m[3] != IceInternal.Protocol.magic[3]) + { + Ice.BadMagicException ex = new Ice.BadMagicException(); + ex.badMagic = m; + throw ex; + } + + _readProtocol.__read(_readStream); + IceInternal.Protocol.checkSupportedProtocol(_readProtocol); + + _readProtocolEncoding.__read(_readStream); + IceInternal.Protocol.checkSupportedProtocolEncoding(_readProtocolEncoding); + + _readStream.readByte(); // messageType + _readStream.readByte(); // compress + int size = _readStream.readInt(); + if(size < IceInternal.Protocol.headerSize) + { + throw new Ice.IllegalMessageSizeException(); + } + if(size > _messageSizeMax) + { + IceInternal.Ex.throwMemoryLimitException(size, _messageSizeMax); + } + if(size > _readStream.size()) + { + _readStream.resize(size); + } + _readStream.pos(pos); + } + + if(_readStream.pos() != _readStream.size()) + { + if(_endpoint.datagram()) + { + // The message was truncated. + throw new Ice.DatagramLimitException(); + } + continue; + } + break; + } + + int newOp = readOp | writeOp; + readyOp = readyOp & ~newOp; + assert (readyOp != 0 || newOp != 0); + + if(_state <= StateNotValidated) + { + if(newOp != 0) + { + // + // Wait for all the transceiver conditions to be + // satisfied before continuing. + // + scheduleTimeout(newOp); + _threadPool.update(this, current.operation, newOp); + return; + } + + if(_state == StateNotInitialized && !initialize(current.operation)) + { + return; + } + + if(_state <= StateNotValidated && !validate(current.operation)) + { + return; + } + + _threadPool.unregister(this, current.operation); + + // + // We start out in holding state. + // + setState(StateHolding); + if(_startCallback != null) + { + startCB = _startCallback; + _startCallback = null; + if(startCB != null) + { + ++dispatchCount; + } + } + } + else + { + assert (_state <= StateClosingPending); + + // + // We parse messages first, if we receive a close + // connection message we won't send more messages. + // + if((readyOp & IceInternal.SocketOperation.Read) != 0) + { + // Optimization: use the thread's stream. + info = new MessageInfo(current.stream); + newOp |= parseMessage(info); + dispatchCount += info.messageDispatchCount; + } + + if((readyOp & IceInternal.SocketOperation.Write) != 0) + { + sentCBs = new java.util.LinkedList<OutgoingMessage>(); + newOp |= sendNextMessage(sentCBs); + if(!sentCBs.isEmpty()) + { + ++dispatchCount; + } + else + { + sentCBs = null; + } + } + + if(_state < StateClosed) + { + scheduleTimeout(newOp); + _threadPool.update(this, current.operation, newOp); + } + } + + if(_acmLastActivity > 0) + { + _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); + } + + if(dispatchCount == 0) + { + return; // Nothing to dispatch we're done! + } + + _dispatchCount += dispatchCount; + current.ioCompleted(); + } + catch(DatagramLimitException ex) // Expected. + { + if(_warnUdp) + { + _logger.warning("maximum datagram size of " + _readStream.pos() + " exceeded"); + } + _readStream.resize(IceInternal.Protocol.headerSize); + _readStream.pos(0); + _readHeader = true; + return; + } + catch(SocketException ex) + { + setState(StateClosed, ex); + return; + } + catch(LocalException ex) + { + if(_endpoint.datagram()) + { + if(_warn) + { + String s = "datagram connection exception:\n" + ex + '\n' + _desc; + _logger.warning(s); + } + _readStream.resize(IceInternal.Protocol.headerSize); + _readStream.pos(0); + _readHeader = true; + } + else + { + setState(StateClosed, ex); + } + return; + } + } + + if(!_dispatcher) // Optimization, call dispatch() directly if there's no dispatcher. + { + dispatch(startCB, sentCBs, info); + } + else + { + // No need for the stream if heartbeat callback + if(info != null && info.heartbeatCallback == null) + { + // + // Create a new stream for the dispatch instead of using the + // thread pool's thread stream. + // + assert (info.stream == current.stream); + InputStream stream = info.stream; + info.stream = new InputStream(_instance, IceInternal.Protocol.currentProtocolEncoding); + info.stream.swap(stream); + } + + final StartCallback finalStartCB = startCB; + final java.util.List<OutgoingMessage> finalSentCBs = sentCBs; + final MessageInfo finalInfo = info; + _threadPool.dispatchFromThisThread(new IceInternal.DispatchWorkItem(this) + { + @Override + public void run() + { + dispatch(finalStartCB, finalSentCBs, finalInfo); + } + }); + } + } + + protected void dispatch(StartCallback startCB, java.util.List<OutgoingMessage> sentCBs, MessageInfo info) + { + int dispatchedCount = 0; + + // + // Notify the factory that the connection establishment and + // validation has completed. + // + if(startCB != null) + { + startCB.connectionStartCompleted(this); + ++dispatchedCount; + } + + // + // Notify AMI calls that the message was sent. + // + if(sentCBs != null) + { + for(OutgoingMessage msg : sentCBs) + { + msg.outAsync.invokeSent(); + } + ++dispatchedCount; + } + + if(info != null) + { + // + // Asynchronous replies must be handled outside the thread + // synchronization, so that nested calls are possible. + // + if(info.outAsync != null) + { + info.outAsync.invokeCompleted(); + ++dispatchedCount; + } + + if(info.heartbeatCallback != null) + { + try + { + info.heartbeatCallback.heartbeat(this); + } + catch(Exception ex) + { + _logger.error("connection callback exception:\n" + ex + '\n' + _desc); + } + ++dispatchedCount; + } + + // + // Method invocation (or multiple invocations for batch messages) + // must be done outside the thread synchronization, so that nested + // calls are possible. + // + if(info.invokeNum > 0) + { + invokeAll(info.stream, info.invokeNum, info.requestId, info.compress, info.servantManager, info.adapter); + + // + // Don't increase dispatchedCount, the dispatch count is + // decreased when the incoming reply is sent. + // + } + } + + // + // Decrease dispatch count. + // + if(dispatchedCount > 0) + { + boolean queueShutdown = false; + + synchronized(this) + { + _dispatchCount -= dispatchedCount; + if(_dispatchCount == 0) + { + // + // Only initiate shutdown if not already done. It might + // have already been done if the sent callback or AMI + // callback was dispatched when the connection was already + // in the closing state. + // + if(_state == StateClosing) + { + if(_instance.queueRequests()) + { + // + // We can't call initiateShutdown() from this thread in certain + // situations (such as in Android). + // + queueShutdown = true; + } + else + { + try + { + initiateShutdown(); + } + catch(Ice.LocalException ex) + { + setState(StateClosed, ex); + } + } + } + else if(_state == StateFinished) + { + reap(); + } + if(!queueShutdown) + { + notifyAll(); + } + } + } + + if(queueShutdown) + { + _instance.getQueueExecutor().executeNoThrow(new Callable<Void>() + { + @Override + public Void call() throws Exception + { + synchronized(ConnectionI.this) + { + try + { + initiateShutdown(); + } + catch(Ice.LocalException ex) + { + setState(StateClosed, ex); + } + ConnectionI.this.notifyAll(); + } + return null; + } + }); + } + } + } + + @Override + public void finished(IceInternal.ThreadPoolCurrent current, final boolean close) + { + synchronized(this) + { + assert (_state == StateClosed); + unscheduleTimeout(IceInternal.SocketOperation.Read | IceInternal.SocketOperation.Write); + } + + // + // If there are no callbacks to call, we don't call ioCompleted() since + // we're not going to call code that will potentially block (this avoids + // promoting a new leader and unecessary thread creation, especially if + // this is called on shutdown). + // + if(_startCallback == null && _sendStreams.isEmpty() && _asyncRequests.isEmpty() && + _closeCallback == null && _heartbeatCallback == null) + { + finish(close); + return; + } + + current.ioCompleted(); + if(!_dispatcher) // Optimization, call finish() directly if there's no + // dispatcher. + { + finish(close); + } + else + { + _threadPool.dispatchFromThisThread(new IceInternal.DispatchWorkItem(this) + { + @Override + public void run() + { + finish(close); + } + }); + } + } + + public void finish(boolean close) + { + if(!_initialized) + { + if(_instance.traceLevels().network >= 2) + { + StringBuffer s = new StringBuffer("failed to "); + s.append(_connector != null ? "establish" : "accept"); + s.append(" "); + s.append(_endpoint.protocol()); + s.append(" connection\n"); + s.append(toString()); + s.append("\n"); + s.append(_exception); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + } + else + { + if(_instance.traceLevels().network >= 1) + { + StringBuffer s = new StringBuffer("closed "); + s.append(_endpoint.protocol()); + s.append(" connection\n"); + s.append(toString()); + + // + // Trace the cause of unexpected connection closures + // + if(!(_exception instanceof CloseConnectionException || + _exception instanceof ForcedCloseConnectionException || + _exception instanceof ConnectionTimeoutException || + _exception instanceof CommunicatorDestroyedException || + _exception instanceof ObjectAdapterDeactivatedException)) + { + s.append("\n"); + s.append(_exception); + } + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + } + + if(close) + { + try + { + _transceiver.close(); + } + catch(Ice.LocalException ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + String s = "unexpected connection exception:\n " + _desc + "\n" + sw.toString(); + _instance.initializationData().logger.error(s); + } + } + + if(_startCallback != null) + { + if(_instance.queueRequests()) + { + // The connectStartFailed method might try to connect with another + // connector. + _instance.getQueueExecutor().executeNoThrow(new Callable<Void>() + { + @Override + public Void call() throws Exception + { + _startCallback.connectionStartFailed(ConnectionI.this, _exception); + return null; + } + }); + } + else + { + _startCallback.connectionStartFailed(this, _exception); + } + _startCallback = null; + } + + if(!_sendStreams.isEmpty()) + { + if(!_writeStream.isEmpty()) + { + // + // Return the stream to the outgoing call. This is important for + // retriable AMI calls which are not marshalled again. + // + OutgoingMessage message = _sendStreams.getFirst(); + _writeStream.swap(message.stream); + } + + for(OutgoingMessage p : _sendStreams) + { + p.completed(_exception); + if(p.requestId > 0) // Make sure finished isn't called twice. + { + _asyncRequests.remove(p.requestId); + } + } + _sendStreams.clear(); + } + + for(IceInternal.OutgoingAsyncBase p : _asyncRequests.values()) + { + if(p.completed(_exception)) + { + p.invokeCompleted(); + } + } + _asyncRequests.clear(); + + // + // Don't wait to be reaped to reclaim memory allocated by read/write streams. + // + _writeStream.clear(); + _writeStream.getBuffer().clear(); + _readStream.clear(); + _readStream.getBuffer().clear(); + + if(_closeCallback != null) + { + try + { + _closeCallback.closed(this); + } + catch(Exception ex) + { + _logger.error("connection callback exception:\n" + ex + '\n' + _desc); + } + _closeCallback = null; + } + + _heartbeatCallback = null; + + // + // This must be done last as this will cause waitUntilFinished() to + // return (and communicator objects such as the timer might be destroyed + // too). + // + synchronized(this) + { + setState(StateFinished); + + if(_dispatchCount == 0) + { + reap(); + } + } + } + + @Override + public String toString() + { + return _toString(); + } + + @Override + public java.nio.channels.SelectableChannel fd() + { + return _transceiver.fd(); + } + + @Override + public void setReadyCallback(IceInternal.ReadyCallback callback) + { + _transceiver.setReadyCallback(callback); + } + + public synchronized void timedOut() + { + if(_state <= StateNotValidated) + { + setState(StateClosed, new ConnectTimeoutException()); + } + else if(_state < StateClosing) + { + setState(StateClosed, new TimeoutException()); + } + else if(_state < StateClosed) + { + setState(StateClosed, new CloseTimeoutException()); + } + } + + @Override + public String type() + { + return _type; // No mutex lock, _type is immutable. + } + + @Override + public int timeout() + { + return _endpoint.timeout(); // No mutex protection necessary, _endpoint + // is immutable. + } + + @Override + public synchronized ConnectionInfo getInfo() + { + if(_state >= StateClosed) + { + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + return initConnectionInfo(); + } + + @Override + public synchronized void setBufferSize(int rcvSize, int sndSize) + { + if(_state >= StateClosed) + { + throw (Ice.LocalException) _exception.fillInStackTrace(); + } + _transceiver.setBufferSize(rcvSize, sndSize); + _info = null; // Invalidate the cached connection info + } + + @Override + public String _toString() + { + return _desc; // No mutex lock, _desc is immutable. + } + + public synchronized void exception(LocalException ex) + { + setState(StateClosed, ex); + } + + public ConnectionI(Communicator communicator, IceInternal.Instance instance, IceInternal.ACMMonitor monitor, + IceInternal.Transceiver transceiver, IceInternal.Connector connector, + IceInternal.EndpointI endpoint, ObjectAdapterI adapter) + { + _communicator = communicator; + _instance = instance; + _monitor = monitor; + _transceiver = transceiver; + _desc = transceiver.toString(); + _type = transceiver.protocol(); + _connector = connector; + _endpoint = endpoint; + _adapter = adapter; + final Ice.InitializationData initData = instance.initializationData(); + // Cached for better performance. + _dispatcher = initData.dispatcher != null; + _logger = initData.logger; // Cached for better performance. + _traceLevels = instance.traceLevels(); // Cached for better performance. + _timer = instance.timer(); + _writeTimeout = new TimeoutCallback(); + _writeTimeoutFuture = null; + _readTimeout = new TimeoutCallback(); + _readTimeoutFuture = null; + _warn = initData.properties.getPropertyAsInt("Ice.Warn.Connections") > 0; + _warnUdp = instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Datagrams") > 0; + _cacheBuffers = instance.cacheMessageBuffers(); + if(_monitor != null && _monitor.getACM().timeout > 0) + { + _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); + } + else + { + _acmLastActivity = -1; + } + _nextRequestId = 1; + _messageSizeMax = adapter != null ? adapter.messageSizeMax() : instance.messageSizeMax(); + _batchRequestQueue = new IceInternal.BatchRequestQueue(instance, _endpoint.datagram()); + _readStream = new InputStream(instance, IceInternal.Protocol.currentProtocolEncoding); + _readHeader = false; + _readStreamPos = -1; + _writeStream = new OutputStream(instance, IceInternal.Protocol.currentProtocolEncoding); + _writeStreamPos = -1; + _dispatchCount = 0; + _state = StateNotInitialized; + + int compressionLevel = initData.properties.getPropertyAsIntWithDefault("Ice.Compression.Level", 1); + if(compressionLevel < 1) + { + compressionLevel = 1; + } + else if(compressionLevel > 9) + { + compressionLevel = 9; + } + _compressionLevel = compressionLevel; + + if(adapter != null) + { + _servantManager = adapter.getServantManager(); + } + else + { + _servantManager = null; + } + + try + { + if(adapter != null) + { + _threadPool = adapter.getThreadPool(); + } + else + { + _threadPool = _instance.clientThreadPool(); + } + _threadPool.initialize(this); + } + catch(Ice.LocalException ex) + { + throw ex; + } + catch(java.lang.Exception ex) + { + throw new Ice.SyscallException(ex); + } + } + + @Override + protected synchronized void finalize() throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_startCallback == null); + IceUtilInternal.Assert.FinalizerAssert(_state == StateFinished); + IceUtilInternal.Assert.FinalizerAssert(_dispatchCount == 0); + IceUtilInternal.Assert.FinalizerAssert(_sendStreams.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_asyncRequests.isEmpty()); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private static final int StateNotInitialized = 0; + private static final int StateNotValidated = 1; + private static final int StateActive = 2; + private static final int StateHolding = 3; + private static final int StateClosing = 4; + private static final int StateClosingPending = 5; + private static final int StateClosed = 6; + private static final int StateFinished = 7; + + private void setState(int state, LocalException ex) + { + // + // If setState() is called with an exception, then only closed + // and closing states are permissible. + // + assert state >= StateClosing; + + if(_state == state) // Don't switch twice. + { + return; + } + + if(_exception == null) + { + // + // If we are in closed state, an exception must be set. + // + assert (_state != StateClosed); + + _exception = ex; + + // + // We don't warn if we are not validated. + // + if(_warn && _validated) + { + // + // Don't warn about certain expected exceptions. + // + if(!(_exception instanceof CloseConnectionException || + _exception instanceof ForcedCloseConnectionException || + _exception instanceof ConnectionTimeoutException || + _exception instanceof CommunicatorDestroyedException || + _exception instanceof ObjectAdapterDeactivatedException || + (_exception instanceof ConnectionLostException && _state >= StateClosing))) + { + warning("connection exception", _exception); + } + } + } + + // + // We must set the new state before we notify requests of any + // exceptions. Otherwise new requests may retry on a + // connection that is not yet marked as closed or closing. + // + setState(state); + } + + private void setState(int state) + { + // + // We don't want to send close connection messages if the endpoint + // only supports oneway transmission from client to server. + // + if(_endpoint.datagram() && state == StateClosing) + { + state = StateClosed; + } + + // + // Skip graceful shutdown if we are destroyed before validation. + // + if(_state <= StateNotValidated && state == StateClosing) + { + state = StateClosed; + } + + if(_state == state) // Don't switch twice. + { + return; + } + + try + { + switch(state) + { + case StateNotInitialized: + { + assert (false); + break; + } + + case StateNotValidated: + { + if(_state != StateNotInitialized) + { + assert (_state == StateClosed); + return; + } + break; + } + + case StateActive: + { + // + // Can only switch from holding or not validated to + // active. + // + if(_state != StateHolding && _state != StateNotValidated) + { + return; + } + _threadPool.register(this, IceInternal.SocketOperation.Read); + break; + } + + case StateHolding: + { + // + // Can only switch from active or not validated to + // holding. + // + if(_state != StateActive && _state != StateNotValidated) + { + return; + } + if(_state == StateActive) + { + _threadPool.unregister(this, IceInternal.SocketOperation.Read); + } + break; + } + + case StateClosing: + case StateClosingPending: + { + // + // Can't change back from closing pending. + // + if(_state >= StateClosingPending) + { + return; + } + break; + } + + case StateClosed: + { + if(_state == StateFinished) + { + return; + } + + _batchRequestQueue.destroy(_exception); + + // + // Don't need to close now for connections so only close the transceiver + // if the selector request it. + // + if(_threadPool.finish(this, false)) + { + _transceiver.close(); + } + break; + } + + case StateFinished: + { + assert (_state == StateClosed); + _communicator = null; + break; + } + } + } + catch(Ice.LocalException ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + String s = "unexpected connection exception:\n " + _desc + "\n" + sw.toString(); + _instance.initializationData().logger.error(s); + } + + // + // We only register with the connection monitor if our new state + // is StateActive. Otherwise we unregister with the connection + // monitor, but only if we were registered before, i.e., if our + // old state was StateActive. + // + if(_monitor != null) + { + if(state == StateActive) + { + if(_acmLastActivity > 0) + { + _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); + } + _monitor.add(this); + } + else if(_state == StateActive) + { + _monitor.remove(this); + } + } + + if(_instance.initializationData().observer != null) + { + Ice.Instrumentation.ConnectionState oldState = toConnectionState(_state); + Ice.Instrumentation.ConnectionState newState = toConnectionState(state); + if(oldState != newState) + { + _observer = _instance.initializationData().observer.getConnectionObserver(initConnectionInfo(), + _endpoint, + newState, + _observer); + if(_observer != null) + { + _observer.attach(); + } + else + { + _writeStreamPos = -1; + _readStreamPos = -1; + } + } + if(_observer != null && state == StateClosed && _exception != null) + { + if(!(_exception instanceof CloseConnectionException || + _exception instanceof ForcedCloseConnectionException || + _exception instanceof ConnectionTimeoutException || + _exception instanceof CommunicatorDestroyedException || + _exception instanceof ObjectAdapterDeactivatedException || + (_exception instanceof ConnectionLostException && _state >= StateClosing))) + { + _observer.failed(_exception.ice_id()); + } + } + } + _state = state; + + notifyAll(); + + if(_state == StateClosing && _dispatchCount == 0) + { + try + { + initiateShutdown(); + } + catch(LocalException ex) + { + setState(StateClosed, ex); + } + } + } + + private void initiateShutdown() + { + assert (_state == StateClosing); + assert (_dispatchCount == 0); + + if(_shutdownInitiated) + { + return; + } + _shutdownInitiated = true; + + if(!_endpoint.datagram()) + { + // + // Before we shut down, we send a close connection message. + // + OutputStream os = new OutputStream(_instance, IceInternal.Protocol.currentProtocolEncoding); + os.writeBlob(IceInternal.Protocol.magic); + IceInternal.Protocol.currentProtocol.__write(os); + IceInternal.Protocol.currentProtocolEncoding.__write(os); + os.writeByte(IceInternal.Protocol.closeConnectionMsg); + os.writeByte((byte) 0); // compression status: always report 0 for + // CloseConnection in Java. + os.writeInt(IceInternal.Protocol.headerSize); // Message size. + + if((sendMessage(new OutgoingMessage(os, false, false)) & IceInternal.AsyncStatus.Sent) > 0) + { + setState(StateClosingPending); + + // + // Notify the the transceiver of the graceful connection + // closure. + // + int op = _transceiver.closing(true, _exception); + if(op != 0) + { + scheduleTimeout(op); + _threadPool.register(this, op); + } + } + } + } + + private void heartbeat() + { + assert (_state == StateActive); + + if(!_endpoint.datagram()) + { + OutputStream os = new OutputStream(_instance, IceInternal.Protocol.currentProtocolEncoding); + os.writeBlob(IceInternal.Protocol.magic); + IceInternal.Protocol.currentProtocol.__write(os); + IceInternal.Protocol.currentProtocolEncoding.__write(os); + os.writeByte(IceInternal.Protocol.validateConnectionMsg); + os.writeByte((byte) 0); + os.writeInt(IceInternal.Protocol.headerSize); // Message size. + + try + { + OutgoingMessage message = new OutgoingMessage(os, false, false); + sendMessage(message); + } + catch(Ice.LocalException ex) + { + setState(StateClosed, ex); + assert (_exception != null); + } + } + } + + private boolean initialize(int operation) + { + int s = _transceiver.initialize(_readStream.getBuffer(), _writeStream.getBuffer()); + if(s != IceInternal.SocketOperation.None) + { + scheduleTimeout(s); + _threadPool.update(this, operation, s); + return false; + } + + // + // Update the connection description once the transceiver is + // initialized. + // + _desc = _transceiver.toString(); + _initialized = true; + setState(StateNotValidated); + + return true; + } + + private boolean validate(int operation) + { + if(!_endpoint.datagram()) // Datagram connections are always implicitly + // validated. + { + if(_adapter != null) // The server side has the active role for + // connection validation. + { + if(_writeStream.isEmpty()) + { + _writeStream.writeBlob(IceInternal.Protocol.magic); + IceInternal.Protocol.currentProtocol.__write(_writeStream); + IceInternal.Protocol.currentProtocolEncoding.__write(_writeStream); + _writeStream.writeByte(IceInternal.Protocol.validateConnectionMsg); + _writeStream.writeByte((byte) 0); // Compression status + // (always zero for + // validate connection). + _writeStream.writeInt(IceInternal.Protocol.headerSize); // Message + // size. + IceInternal.TraceUtil.traceSend(_writeStream, _logger, _traceLevels); + _writeStream.prepareWrite(); + } + + if(_observer != null) + { + observerStartWrite(_writeStream.getBuffer()); + } + + if(_writeStream.pos() != _writeStream.size()) + { + int op = write(_writeStream.getBuffer()); + if(op != 0) + { + scheduleTimeout(op); + _threadPool.update(this, operation, op); + return false; + } + } + + if(_observer != null) + { + observerFinishWrite(_writeStream.getBuffer()); + } + } + else + // The client side has the passive role for connection validation. + { + if(_readStream.isEmpty()) + { + _readStream.resize(IceInternal.Protocol.headerSize); + _readStream.pos(0); + } + + if(_observer != null) + { + observerStartRead(_readStream.getBuffer()); + } + + if(_readStream.pos() != _readStream.size()) + { + int op = read(_readStream.getBuffer()); + if(op != 0) + { + scheduleTimeout(op); + _threadPool.update(this, operation, op); + return false; + } + } + + if(_observer != null) + { + observerFinishRead(_readStream.getBuffer()); + } + + assert (_readStream.pos() == IceInternal.Protocol.headerSize); + _readStream.pos(0); + byte[] m = _readStream.readBlob(4); + if(m[0] != IceInternal.Protocol.magic[0] || m[1] != IceInternal.Protocol.magic[1] || + m[2] != IceInternal.Protocol.magic[2] || m[3] != IceInternal.Protocol.magic[3]) + { + BadMagicException ex = new BadMagicException(); + ex.badMagic = m; + throw ex; + } + + _readProtocol.__read(_readStream); + IceInternal.Protocol.checkSupportedProtocol(_readProtocol); + + _readProtocolEncoding.__read(_readStream); + IceInternal.Protocol.checkSupportedProtocolEncoding(_readProtocolEncoding); + + byte messageType = _readStream.readByte(); + if(messageType != IceInternal.Protocol.validateConnectionMsg) + { + throw new ConnectionNotValidatedException(); + } + _readStream.readByte(); // Ignore compression status for + // validate connection. + int size = _readStream.readInt(); + if(size != IceInternal.Protocol.headerSize) + { + throw new IllegalMessageSizeException(); + } + IceInternal.TraceUtil.traceRecv(_readStream, _logger, _traceLevels); + + _validated = true; + } + } + + _writeStream.resize(0); + _writeStream.pos(0); + + _readStream.resize(IceInternal.Protocol.headerSize); + _readStream.pos(0); + _readHeader = true; + + if(_instance.traceLevels().network >= 1) + { + StringBuffer s = new StringBuffer(); + if(_endpoint.datagram()) + { + s.append("starting to "); + s.append(_connector != null ? "send" : "receive"); + s.append(" "); + s.append(_endpoint.protocol()); + s.append(" messages\n"); + s.append(_transceiver.toDetailedString()); + } + else + { + s.append(_connector != null ? "established" : "accepted"); + s.append(" "); + s.append(_endpoint.protocol()); + s.append(" connection\n"); + s.append(toString()); + } + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + + return true; + } + + private int sendNextMessage(java.util.List<OutgoingMessage> callbacks) + { + if(_sendStreams.isEmpty()) + { + return IceInternal.SocketOperation.None; + } + else if(_state == StateClosingPending && _writeStream.pos() == 0) + { + // Message wasn't sent, empty the _writeStream, we're not going to + // send more data. + OutgoingMessage message = _sendStreams.getFirst(); + _writeStream.swap(message.stream); + return IceInternal.SocketOperation.None; + } + + assert (!_writeStream.isEmpty() && _writeStream.pos() == _writeStream.size()); + try + { + while(true) + { + // + // Notify the message that it was sent. + // + OutgoingMessage message = _sendStreams.getFirst(); + _writeStream.swap(message.stream); + if(message.sent()) + { + callbacks.add(message); + } + _sendStreams.removeFirst(); + + // + // If there's nothing left to send, we're done. + // + if(_sendStreams.isEmpty()) + { + break; + } + + // + // If we are in the closed state or if the close is + // pending, don't continue sending. + // + // This can occur if parseMessage (called before + // sendNextMessage by message()) closes the connection. + // + if(_state >= StateClosingPending) + { + return IceInternal.SocketOperation.None; + } + + // + // Otherwise, prepare the next message stream for writing. + // + message = _sendStreams.getFirst(); + assert (!message.prepared); + OutputStream stream = message.stream; + + message.stream = doCompress(stream, message.compress); + message.stream.prepareWrite(); + message.prepared = true; + + IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels); + + _writeStream.swap(message.stream); + + // + // Send the message. + // + if(_observer != null) + { + observerStartWrite(_writeStream.getBuffer()); + } + if(_writeStream.pos() != _writeStream.size()) + { + int op = write(_writeStream.getBuffer()); + if(op != 0) + { + return op; + } + } + if(_observer != null) + { + observerFinishWrite(_writeStream.getBuffer()); + } + } + + // + // If all the messages were sent and we are in the closing state, we + // schedule the close timeout to wait for the peer to close the + // connection. + // + if(_state == StateClosing && _shutdownInitiated) + { + setState(StateClosingPending); + int op = _transceiver.closing(true, _exception); + if(op != 0) + { + return op; + } + } + } + catch(Ice.LocalException ex) + { + setState(StateClosed, ex); + } + return IceInternal.SocketOperation.None; + } + + private int sendMessage(OutgoingMessage message) + { + assert (_state < StateClosed); + + if(!_sendStreams.isEmpty()) + { + message.adopt(); + _sendStreams.addLast(message); + return IceInternal.AsyncStatus.Queued; + } + + // + // Attempt to send the message without blocking. If the send blocks, we + // register the connection with the selector thread. + // + + assert (!message.prepared); + + OutputStream stream = message.stream; + + message.stream = doCompress(stream, message.compress); + message.stream.prepareWrite(); + message.prepared = true; + int op; + + IceInternal.TraceUtil.traceSend(stream, _logger, _traceLevels); + + // + // Send the message without blocking. + // + if(_observer != null) + { + observerStartWrite(message.stream.getBuffer()); + } + op = write(message.stream.getBuffer()); + if(op == 0) + { + if(_observer != null) + { + observerFinishWrite(message.stream.getBuffer()); + } + + int status = IceInternal.AsyncStatus.Sent; + if(message.sent()) + { + status |= IceInternal.AsyncStatus.InvokeSentCallback; + } + + if(_acmLastActivity > 0) + { + _acmLastActivity = IceInternal.Time.currentMonotonicTimeMillis(); + } + return status; + } + + message.adopt(); + + _writeStream.swap(message.stream); + _sendStreams.addLast(message); + scheduleTimeout(op); + _threadPool.register(this, op); + return IceInternal.AsyncStatus.Queued; + } + + private OutputStream doCompress(OutputStream uncompressed, boolean compress) + { + boolean compressionSupported = false; + if(compress) + { + // + // Don't check whether compression support is available unless the + // proxy is configured for compression. + // + compressionSupported = IceInternal.BZip2.supported(); + } + + if(compressionSupported && uncompressed.size() >= 100) + { + // + // Do compression. + // + IceInternal.Buffer cbuf = IceInternal.BZip2.compress(uncompressed.getBuffer(), + IceInternal.Protocol.headerSize, _compressionLevel); + if(cbuf != null) + { + OutputStream cstream = + new OutputStream(uncompressed.instance(), uncompressed.getEncoding(), cbuf, true); + + // + // Set compression status. + // + cstream.pos(9); + cstream.writeByte((byte) 2); + + // + // Write the size of the compressed stream into the header. + // + cstream.pos(10); + cstream.writeInt(cstream.size()); + + // + // Write the compression status and size of the compressed + // stream into the header of the uncompressed stream -- we need + // this to trace requests correctly. + // + uncompressed.pos(9); + uncompressed.writeByte((byte) 2); + uncompressed.writeInt(cstream.size()); + + return cstream; + } + } + + uncompressed.pos(9); + uncompressed.writeByte((byte) (compressionSupported ? 1 : 0)); + + // + // Not compressed, fill in the message size. + // + uncompressed.pos(10); + uncompressed.writeInt(uncompressed.size()); + + return uncompressed; + } + + private static class MessageInfo + { + MessageInfo(InputStream stream) + { + this.stream = stream; + } + + InputStream stream; + int invokeNum; + int requestId; + byte compress; + IceInternal.ServantManager servantManager; + ObjectAdapter adapter; + IceInternal.OutgoingAsyncBase outAsync; + HeartbeatCallback heartbeatCallback; + int messageDispatchCount; + } + + private int parseMessage(MessageInfo info) + { + assert (_state > StateNotValidated && _state < StateClosed); + + _readStream.swap(info.stream); + _readStream.resize(IceInternal.Protocol.headerSize); + _readStream.pos(0); + _readHeader = true; + + assert (info.stream.pos() == info.stream.size()); + + // + // Connection is validated on first message. This is only used by + // setState() to check wether or not we can print a connection + // warning (a client might close the connection forcefully if the + // connection isn't validated). + // + _validated = true; + + try + { + // + // We don't need to check magic and version here. This has already + // been done by the ThreadPool which provides us with the stream. + // + info.stream.pos(8); + byte messageType = info.stream.readByte(); + info.compress = info.stream.readByte(); + if(info.compress == (byte)2) + { + if(IceInternal.BZip2.supported()) + { + IceInternal.Buffer ubuf = IceInternal.BZip2.uncompress(info.stream.getBuffer(), + IceInternal.Protocol.headerSize, + _messageSizeMax); + info.stream = new InputStream(info.stream.instance(), info.stream.getEncoding(), ubuf, true); + } + else + { + FeatureNotSupportedException ex = new FeatureNotSupportedException(); + ex.unsupportedFeature = "Cannot uncompress compressed message: " + + "org.apache.tools.bzip2.CBZip2OutputStream was not found"; + throw ex; + } + } + info.stream.pos(IceInternal.Protocol.headerSize); + + switch(messageType) + { + case IceInternal.Protocol.closeConnectionMsg: + { + IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels); + if(_endpoint.datagram()) + { + if(_warn) + { + _logger.warning("ignoring close connection message for datagram connection:\n" + _desc); + } + } + else + { + setState(StateClosingPending, new CloseConnectionException()); + + // + // Notify the the transceiver of the graceful connection + // closure. + // + int op = _transceiver.closing(false, _exception); + if(op != 0) + { + return op; + } + setState(StateClosed); + } + break; + } + + case IceInternal.Protocol.requestMsg: + { + if(_state >= StateClosing) + { + IceInternal.TraceUtil.trace("received request during closing\n" + + "(ignored by server, client will retry)", info.stream, _logger, + _traceLevels); + } + else + { + IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels); + info.requestId = info.stream.readInt(); + info.invokeNum = 1; + info.servantManager = _servantManager; + info.adapter = _adapter; + ++info.messageDispatchCount; + } + break; + } + + case IceInternal.Protocol.requestBatchMsg: + { + if(_state >= StateClosing) + { + IceInternal.TraceUtil.trace("received batch request during closing\n" + + "(ignored by server, client will retry)", info.stream, _logger, + _traceLevels); + } + else + { + IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels); + info.invokeNum = info.stream.readInt(); + if(info.invokeNum < 0) + { + info.invokeNum = 0; + throw new UnmarshalOutOfBoundsException(); + } + info.servantManager = _servantManager; + info.adapter = _adapter; + info.messageDispatchCount += info.invokeNum; + } + break; + } + + case IceInternal.Protocol.replyMsg: + { + IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels); + info.requestId = info.stream.readInt(); + + IceInternal.OutgoingAsyncBase outAsync = _asyncRequests.remove(info.requestId); + if(outAsync != null && outAsync.completed(info.stream)) + { + info.outAsync = outAsync; + ++info.messageDispatchCount; + } + notifyAll(); // Notify threads blocked in close(false) + break; + } + + case IceInternal.Protocol.validateConnectionMsg: + { + IceInternal.TraceUtil.traceRecv(info.stream, _logger, _traceLevels); + if(_heartbeatCallback != null) + { + info.heartbeatCallback = _heartbeatCallback; + ++info.messageDispatchCount; + } + break; + } + + default: + { + IceInternal.TraceUtil.trace("received unknown message\n(invalid, closing connection)", info.stream, + _logger, _traceLevels); + throw new UnknownMessageException(); + } + } + } + catch(LocalException ex) + { + if(_endpoint.datagram()) + { + if(_warn) + { + _logger.warning("datagram connection exception:\n" + ex + '\n' + _desc); + } + } + else + { + setState(StateClosed, ex); + } + } + + return _state == StateHolding ? IceInternal.SocketOperation.None : IceInternal.SocketOperation.Read; + } + + private void invokeAll(InputStream stream, int invokeNum, int requestId, byte compress, + IceInternal.ServantManager servantManager, ObjectAdapter adapter) + { + // + // Note: In contrast to other private or protected methods, this + // operation must be called *without* the mutex locked. + // + + IceInternal.Incoming in = null; + try + { + while(invokeNum > 0) + { + + // + // Prepare the invocation. + // + boolean response = !_endpoint.datagram() && requestId != 0; + in = getIncoming(adapter, response, compress, requestId); + + // + // Dispatch the invocation. + // + in.invoke(servantManager, stream); + + --invokeNum; + + reclaimIncoming(in); + in = null; + } + + stream.clear(); + } + catch(LocalException ex) + { + invokeException(requestId, ex, invokeNum, false); + } + catch(IceInternal.ServantError ex) + { + // + // ServantError is thrown when an Error has been raised by servant (or servant locator) + // code. We've already attempted to complete the invocation and send a response. + // + Throwable t = ex.getCause(); + // + // Suppress AssertionError and OutOfMemoryError, rethrow everything else. + // + if(!(t instanceof java.lang.AssertionError || t instanceof java.lang.OutOfMemoryError)) + { + throw (java.lang.Error)t; + } + } + catch(java.lang.Error ex) + { + // + // An Error was raised outside of servant code (i.e., by Ice code). + // Attempt to log the error and clean up. This may still fail + // depending on the severity of the error. + // + // Note that this does NOT send a response to the client. + // + UnknownException uex = new UnknownException(ex); + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + uex.unknown = sw.toString(); + _logger.error(uex.unknown); + invokeException(requestId, uex, invokeNum, false); + // + // Suppress AssertionError and OutOfMemoryError, rethrow everything else. + // + if(!(ex instanceof java.lang.AssertionError || ex instanceof java.lang.OutOfMemoryError)) + { + throw ex; + } + } + finally + { + if(in != null) + { + reclaimIncoming(in); + } + } + } + + private void scheduleTimeout(int status) + { + int timeout; + if(_state < StateActive) + { + IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideConnectTimeout) + { + timeout = defaultsAndOverrides.overrideConnectTimeoutValue; + } + else + { + timeout = _endpoint.timeout(); + } + } + else if(_state < StateClosingPending) + { + if(_readHeader) // No timeout for reading the header. + { + status &= ~IceInternal.SocketOperation.Read; + } + timeout = _endpoint.timeout(); + } + else + { + IceInternal.DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideCloseTimeout) + { + timeout = defaultsAndOverrides.overrideCloseTimeoutValue; + } + else + { + timeout = _endpoint.timeout(); + } + } + + if(timeout < 0) + { + return; + } + + try + { + if((status & IceInternal.SocketOperation.Read) != 0) + { + if(_readTimeoutFuture != null) + { + _readTimeoutFuture.cancel(false); + } + _readTimeoutFuture = _timer.schedule(_readTimeout, timeout, java.util.concurrent.TimeUnit.MILLISECONDS); + } + if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0) + { + if(_writeTimeoutFuture != null) + { + _writeTimeoutFuture.cancel(false); + } + _writeTimeoutFuture = _timer.schedule(_writeTimeout, timeout, + java.util.concurrent.TimeUnit.MILLISECONDS); + } + } + catch(Throwable ex) + { + assert (false); + } + } + + private void unscheduleTimeout(int status) + { + if((status & IceInternal.SocketOperation.Read) != 0 && _readTimeoutFuture != null) + { + _readTimeoutFuture.cancel(false); + _readTimeoutFuture = null; + } + if((status & (IceInternal.SocketOperation.Write | IceInternal.SocketOperation.Connect)) != 0 && + _writeTimeoutFuture != null) + { + _writeTimeoutFuture.cancel(false); + _writeTimeoutFuture = null; + } + } + + private ConnectionInfo initConnectionInfo() + { + if(_state > StateNotInitialized && _info != null) // Update the connection information until it's initialized + { + return _info; + } + + try + { + _info = _transceiver.getInfo(); + } + catch(Ice.LocalException ex) + { + _info = new ConnectionInfo(); + } + for(ConnectionInfo info = _info; info != null; info = info.underlying) + { + info.connectionId = _endpoint.connectionId(); + info.adapterName = _adapter != null ? _adapter.getName() : ""; + info.incoming = _connector == null; + } + return _info; + } + + private Ice.Instrumentation.ConnectionState toConnectionState(int state) + { + return connectionStateMap[state]; + } + + private void warning(String msg, java.lang.Exception ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + String s = msg + ":\n" + _desc + "\n" + sw.toString(); + _logger.warning(s); + } + + private void observerStartRead(IceInternal.Buffer buf) + { + if(_readStreamPos >= 0) + { + assert (!buf.empty()); + _observer.receivedBytes(buf.b.position() - _readStreamPos); + } + _readStreamPos = buf.empty() ? -1 : buf.b.position(); + } + + private void observerFinishRead(IceInternal.Buffer buf) + { + if(_readStreamPos == -1) + { + return; + } + assert (buf.b.position() >= _readStreamPos); + _observer.receivedBytes(buf.b.position() - _readStreamPos); + _readStreamPos = -1; + } + + private void observerStartWrite(IceInternal.Buffer buf) + { + if(_writeStreamPos >= 0) + { + assert (!buf.empty()); + _observer.sentBytes(buf.b.position() - _writeStreamPos); + } + _writeStreamPos = buf.empty() ? -1 : buf.b.position(); + } + + private void observerFinishWrite(IceInternal.Buffer buf) + { + if(_writeStreamPos == -1) + { + return; + } + if(buf.b.position() > _writeStreamPos) + { + _observer.sentBytes(buf.b.position() - _writeStreamPos); + } + _writeStreamPos = -1; + } + + private IceInternal.Incoming getIncoming(ObjectAdapter adapter, boolean response, byte compress, int requestId) + { + IceInternal.Incoming in = null; + + if(_cacheBuffers > 0) + { + synchronized(_incomingCacheMutex) + { + if(_incomingCache == null) + { + in = new IceInternal.Incoming(_instance, this, this, adapter, response, compress, requestId); + } + else + { + in = _incomingCache; + _incomingCache = _incomingCache.next; + in.reset(_instance, this, this, adapter, response, compress, requestId); + in.next = null; + } + } + } + else + { + in = new IceInternal.Incoming(_instance, this, this, adapter, response, compress, requestId); + } + + return in; + } + + private void reclaimIncoming(IceInternal.Incoming in) + { + if(_cacheBuffers > 0) + { + synchronized(_incomingCacheMutex) + { + in.next = _incomingCache; + _incomingCache = in; + // + // Clear references to Ice objects as soon as possible. + // + _incomingCache.reclaim(); + } + } + } + + private void reap() + { + if(_monitor != null) + { + _monitor.reap(this); + } + if(_observer != null) + { + _observer.detach(); + } + } + + private int read(IceInternal.Buffer buf) + { + int start = buf.b.position(); + int op = _transceiver.read(buf); + if(_instance.traceLevels().network >= 3 && buf.b.position() != start) + { + StringBuffer s = new StringBuffer("received "); + if(_endpoint.datagram()) + { + s.append(buf.b.limit()); + } + else + { + s.append(buf.b.position() - start); + s.append(" of "); + s.append(buf.b.limit() - start); + } + s.append(" bytes via "); + s.append(_endpoint.protocol()); + s.append("\n"); + s.append(toString()); + + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + return op; + } + + private int write(IceInternal.Buffer buf) + { + int start = buf.b.position(); + int op = _transceiver.write(buf); + if(_instance.traceLevels().network >= 3 && buf.b.position() != start) + { + StringBuffer s = new StringBuffer("sent "); + s.append(buf.b.position() - start); + if(!_endpoint.datagram()) + { + s.append(" of "); + s.append(buf.b.limit() - start); + } + s.append(" bytes via "); + s.append(_endpoint.protocol()); + s.append("\n"); + s.append(toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + return op; + } + + private static class OutgoingMessage + { + OutgoingMessage(OutputStream stream, boolean compress, boolean adopt) + { + this.stream = stream; + this.compress = compress; + this.adopt = adopt; + this.requestId = 0; + } + + OutgoingMessage(IceInternal.OutgoingAsyncBase out, OutputStream stream, boolean compress, + int requestId) + { + this.stream = stream; + this.compress = compress; + this.outAsync = out; + this.requestId = requestId; + } + + public void canceled() + { + assert (outAsync != null); + outAsync = null; + } + + public void adopt() + { + if(adopt) + { + OutputStream stream = + new OutputStream(this.stream.instance(), IceInternal.Protocol.currentProtocolEncoding); + stream.swap(this.stream); + this.stream = stream; + adopt = false; + } + } + + public boolean sent() + { + if(outAsync != null) + { + return outAsync.sent(); + } + return false; + } + + public void completed(Ice.LocalException ex) + { + if(outAsync != null && outAsync.completed(ex)) + { + outAsync.invokeCompleted(); + } + } + + public OutputStream stream; + public IceInternal.OutgoingAsyncBase outAsync; + public boolean compress; + public int requestId; + boolean adopt; + boolean prepared; + } + + private Communicator _communicator; + private final IceInternal.Instance _instance; + private IceInternal.ACMMonitor _monitor; + private final IceInternal.Transceiver _transceiver; + private String _desc; + private final String _type; + private final IceInternal.Connector _connector; + private final IceInternal.EndpointI _endpoint; + + private ObjectAdapter _adapter; + private IceInternal.ServantManager _servantManager; + + private final boolean _dispatcher; + private final Logger _logger; + private final IceInternal.TraceLevels _traceLevels; + private final IceInternal.ThreadPool _threadPool; + + private final java.util.concurrent.ScheduledExecutorService _timer; + private final Runnable _writeTimeout; + private java.util.concurrent.Future<?> _writeTimeoutFuture; + private final Runnable _readTimeout; + private java.util.concurrent.Future<?> _readTimeoutFuture; + + private StartCallback _startCallback = null; + + private final boolean _warn; + private final boolean _warnUdp; + + private long _acmLastActivity; + + private final int _compressionLevel; + + private int _nextRequestId; + + private java.util.Map<Integer, IceInternal.OutgoingAsyncBase> _asyncRequests = + new java.util.HashMap<Integer, IceInternal.OutgoingAsyncBase>(); + + private LocalException _exception; + + private final int _messageSizeMax; + private IceInternal.BatchRequestQueue _batchRequestQueue; + + private java.util.LinkedList<OutgoingMessage> _sendStreams = new java.util.LinkedList<OutgoingMessage>(); + + private InputStream _readStream; + private boolean _readHeader; + private OutputStream _writeStream; + + private Ice.Instrumentation.ConnectionObserver _observer; + private int _readStreamPos; + private int _writeStreamPos; + + private int _dispatchCount; + + private int _state; // The current state. + private boolean _shutdownInitiated = false; + private boolean _initialized = false; + private boolean _validated = false; + + private IceInternal.Incoming _incomingCache; + private final java.lang.Object _incomingCacheMutex = new java.lang.Object(); + + private Ice.ProtocolVersion _readProtocol = new Ice.ProtocolVersion(); + private Ice.EncodingVersion _readProtocolEncoding = new Ice.EncodingVersion(); + + private int _cacheBuffers; + + private Ice.ConnectionInfo _info; + + private CloseCallback _closeCallback; + private HeartbeatCallback _heartbeatCallback; + + private static Ice.Instrumentation.ConnectionState connectionStateMap[] = { + Ice.Instrumentation.ConnectionState.ConnectionStateValidating, // StateNotInitialized + Ice.Instrumentation.ConnectionState.ConnectionStateValidating, // StateNotValidated + Ice.Instrumentation.ConnectionState.ConnectionStateActive, // StateActive + Ice.Instrumentation.ConnectionState.ConnectionStateHolding, // StateHolding + Ice.Instrumentation.ConnectionState.ConnectionStateClosing, // StateClosing + Ice.Instrumentation.ConnectionState.ConnectionStateClosing, // StateClosingPending + Ice.Instrumentation.ConnectionState.ConnectionStateClosed, // StateClosed + Ice.Instrumentation.ConnectionState.ConnectionStateClosed, // StateFinished + }; + +} diff --git a/java-compat/src/Ice/src/main/java/Ice/DispatchInterceptor.java b/java-compat/src/Ice/src/main/java/Ice/DispatchInterceptor.java new file mode 100644 index 00000000000..d5cb1519f58 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/DispatchInterceptor.java @@ -0,0 +1,71 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class that allows a server intercept incoming requests. + * The application must derive a concrete class from <code>DispatchInterceptor</code> + * that implements the {@link DispatchInterceptor#dispatch} operation. An instance of this derived + * class can be registered with an object adapter like any other servant. + * <p> + * A dispatch interceptor is useful particularly to automatically retry requests + * that have failed due to a recoverable error condition. + **/ +public abstract class DispatchInterceptor extends ObjectImpl +{ + /** + * Called by the Ice run time to dispatch an incoming request. The implementation + * of <code>dispatch</code> must dispatch the request to the actual servant. + * + * @param request The details of the incoming request. + * @return For synchronous dispatch, the return value must be whatever is + * returned {@link #ice_dispatch}. For asynchronous dispatch, the return + * value must be <code>DispatchAsync</code>. + * + * @see Request + * @see DispatchStatus + **/ + public abstract DispatchStatus + dispatch(Request request); + + @Override + public DispatchStatus + __dispatch(IceInternal.Incoming in, Current current) + { + try + { + DispatchStatus status = dispatch(in); + if(status != DispatchStatus.DispatchAsync) + { + // + // Make sure 'in' owns the connection etc. + // + in.killAsync(); + } + return status; + } + catch(ResponseSentException e) + { + return DispatchStatus.DispatchAsync; + } + catch(java.lang.RuntimeException e) + { + try + { + in.killAsync(); + throw e; + } + catch(ResponseSentException rse) + { + return DispatchStatus.DispatchAsync; + } + } + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/DispatchInterceptorAsyncCallback.java b/java-compat/src/Ice/src/main/java/Ice/DispatchInterceptorAsyncCallback.java new file mode 100644 index 00000000000..fdbf42ebe06 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/DispatchInterceptorAsyncCallback.java @@ -0,0 +1,35 @@ +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * The callback object for asynchronous dispatch. + **/ +public interface DispatchInterceptorAsyncCallback +{ + /** + * Called when the operation succeeded or raised a user exception, + * as indicated by the <code>ok</code> parameter. + * + * @param ok True if the operation succeeded, or false if the + * operation raised a user exception. + * @return True to allow the Ice run time to handle the result + * as it normally would, or false if the interceptor has handled + * the operation. + **/ + boolean response(boolean ok); + + /** + * Called when the operation failed with a run-time exception. + * + * @param ex The exception raised by the operation. + * @return True to allow the Ice run time to handle the result + * as it normally would, or false if the interceptor has handled + * the operation. + **/ + boolean exception(java.lang.Exception ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/DispatchStatus.java b/java-compat/src/Ice/src/main/java/Ice/DispatchStatus.java new file mode 100644 index 00000000000..beb91152d03 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/DispatchStatus.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Indicates the status of operation dispatch. + * + * @see DispatchInterceptor + **/ +public enum DispatchStatus implements java.io.Serializable +{ + /** + * Indicates that an operation was dispatched synchronously and successfully. + **/ + DispatchOK, + + /** + * Indicates that an operation was dispatched synchronously and raised a user exception. + **/ + DispatchUserException, + + /** + * Indicates that an operation was dispatched asynchronously. + **/ + DispatchAsync; + + public static final long serialVersionUID = 0L; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Dispatcher.java b/java-compat/src/Ice/src/main/java/Ice/Dispatcher.java new file mode 100644 index 00000000000..83975f9b8c9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Dispatcher.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * You can control which thread receives operation invocations and AMI + * callbacks by implementing the <code>Dispatcher</code> interface and + * supplying an instance in <code>InitializationData</code> when + * initializing a communicator. + * <p> + * For example, you can use this dispatching facility to ensure that + * all invocations and callbacks are dispatched in a GUI event loop + * thread so that it is safe to invoke directly on GUI objects. + **/ +public interface Dispatcher +{ + /** + * Responsible for dispatching an invocation or AMI callback. + * The method must eventually invoke <code>run</code> on the + * supplied <code>Runnable</code> object. + * + * @param runnable The object encapsulating the invocation or + * callback to be dispatched. + * @param con The connection associated with the dispatch. + **/ + void dispatch(Runnable runnable, Ice.Connection con); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/DoubleHolder.java b/java-compat/src/Ice/src/main/java/Ice/DoubleHolder.java new file mode 100644 index 00000000000..db51782dc22 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/DoubleHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for doubles that are out- or inout-parameters. + **/ +public final class DoubleHolder extends Holder<Double> +{ + /** + * Instantiates the class with the value zero. + **/ + public + DoubleHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * @param value The <code>double</code> value stored by this holder. + **/ + public + DoubleHolder(double value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/DoubleOptional.java b/java-compat/src/Ice/src/main/java/Ice/DoubleOptional.java new file mode 100644 index 00000000000..7efd476babd --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/DoubleOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional double parameter. + **/ +public class DoubleOptional +{ + /** + * The value defaults to unset. + **/ + public DoubleOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public DoubleOptional(double v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public DoubleOptional(DoubleOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public double get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(double v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(DoubleOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = 0; + } + + private double _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Exception.java b/java-compat/src/Ice/src/main/java/Ice/Exception.java new file mode 100644 index 00000000000..2cd7cd585c1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Exception.java @@ -0,0 +1,91 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for Ice local and system exceptions. Those exceptions + * are not checked so we inherit from java.lang.RuntimeException. User + * exceptions are checked exceptions and therefore inherit directly + * from java.lang.Exception. + **/ +public abstract class Exception extends RuntimeException implements Cloneable +{ + public Exception() + { + } + + public Exception(Throwable cause) + { + super(cause); + } + + /** + * Creates a copy of this exception. + * + * @return The copy of this exception. + **/ + @Override + public Exception clone() + { + Exception c = null; + + try + { + c = (Exception)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; + } + + /** + * Returns the name of this exception. + * + * @return The name of this exception. + * + * @deprecated ice_name() is deprecated, use ice_id() instead. + **/ + @Deprecated + public String + ice_name() + { + return ice_id().substring(2); + } + + /** + * Returns the type id of this exception. + * + * @return The type id of this exception. + **/ + public abstract String + ice_id(); + + /** + * Returns a string representation of this exception. + * + * @return A string representation of this exception. + **/ + @Override + public String + toString() + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + IceUtilInternal.OutputBase out = new IceUtilInternal.OutputBase(pw); + out.setUseTab(false); + out.print(getClass().getName()); + out.inc(); + IceInternal.ValueWriter.write(this, out); + pw.flush(); + return sw.toString(); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/FloatHolder.java b/java-compat/src/Ice/src/main/java/Ice/FloatHolder.java new file mode 100644 index 00000000000..4abd74438e5 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/FloatHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for floats that are out- or inout-parameters. + **/ +public final class FloatHolder extends Holder<Float> +{ + /** + * Instantiates the class with the value zero. + **/ + public + FloatHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * @param value The <code>float</code> value stored by this holder. + **/ + public + FloatHolder(float value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/FloatOptional.java b/java-compat/src/Ice/src/main/java/Ice/FloatOptional.java new file mode 100644 index 00000000000..92f67c32071 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/FloatOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional float parameter. + **/ +public class FloatOptional +{ + /** + * The value defaults to unset. + **/ + public FloatOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public FloatOptional(float v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public FloatOptional(FloatOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public float get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(float v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(FloatOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = 0; + } + + private float _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/FormatType.java b/java-compat/src/Ice/src/main/java/Ice/FormatType.java new file mode 100644 index 00000000000..7d421f259fd --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/FormatType.java @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * This enumeration describes the possible formats for classes and exceptions. + **/ +public enum FormatType +{ + /** + * Indicates that no preference was specified. + **/ + DefaultFormat, + /** + * A minimal format that eliminates the possibility for slicing unrecognized types. + **/ + CompactFormat, + /** + * Allow slicing and preserve slices for unknown types. + **/ + SlicedFormat +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Holder.java b/java-compat/src/Ice/src/main/java/Ice/Holder.java new file mode 100644 index 00000000000..bc086b1683b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Holder.java @@ -0,0 +1,40 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Generic holder class for values that are in- or in-out parameters. + **/ +public class Holder<T> +{ + /** + * Instantiates the class with the default-initialized value of type <code>T</code>. + **/ + public + Holder() + { + } + + /** + * Instantiates the class with the passed value. + * + * @param value The value stored by this holder. + **/ + public + Holder(T value) + { + this.value = value; + } + + /** + * The <code>T</code> value stored by this holder. + **/ + public T value; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ImplicitContextI.java b/java-compat/src/Ice/src/main/java/Ice/ImplicitContextI.java new file mode 100644 index 00000000000..8dd39e414b9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ImplicitContextI.java @@ -0,0 +1,318 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +// +// The base class for all ImplicitContext implementations +// +public abstract class ImplicitContextI implements ImplicitContext +{ + public static ImplicitContextI create(String kind) + { + if(kind.equals("None") || kind.equals("")) + { + return null; + } + else if(kind.equals("Shared")) + { + return new Shared(); + } + else if(kind.equals("PerThread")) + { + return new PerThread(); + } + else + { + throw new Ice.InitializationException( + "'" + kind + "' is not a valid value for Ice.ImplicitContext"); + } + } + + abstract public void write(java.util.Map<String, String> prxContext, OutputStream os); + abstract java.util.Map<String, String> combine(java.util.Map<String, String> prxContext); + + static class Shared extends ImplicitContextI + { + @Override + public synchronized java.util.Map<String, String> getContext() + { + return new java.util.HashMap<String, String>(_context); + } + + @Override + public synchronized void setContext(java.util.Map<String, String> context) + { + _context.clear(); + if(context != null && !context.isEmpty()) + { + _context.putAll(context); + } + } + + @Override + public synchronized boolean containsKey(String key) + { + if(key == null) + { + key = ""; + } + + return _context.containsKey(key); + } + + @Override + public synchronized String get(String key) + { + if(key == null) + { + key = ""; + } + + String val = _context.get(key); + if(val == null) + { + val = ""; + } + + return val; + } + + @Override + public synchronized String put(String key, String value) + { + if(key == null) + { + key = ""; + } + if(value == null) + { + value = ""; + } + + String oldVal = _context.put(key, value); + if(oldVal == null) + { + oldVal = ""; + } + return oldVal; + } + + @Override + public synchronized String remove(String key) + { + if(key == null) + { + key = ""; + } + + String val = _context.remove(key); + + if(val == null) + { + val = ""; + } + return val; + } + + @Override + public void write(java.util.Map<String, String> prxContext, OutputStream os) + { + if(prxContext.isEmpty()) + { + synchronized(this) + { + ContextHelper.write(os, _context); + } + } + else + { + java.util.Map<String, String> ctx = null; + synchronized(this) + { + ctx = _context.isEmpty() ? prxContext : combine(prxContext); + } + ContextHelper.write(os, ctx); + } + } + + @Override + synchronized java.util.Map<String, String> combine(java.util.Map<String, String> prxContext) + { + java.util.Map<String, String> combined = new java.util.HashMap<String, String>(_context); + combined.putAll(prxContext); + return combined; + } + + private java.util.Map<String, String> _context = new java.util.HashMap<String, String>(); + } + + static class PerThread extends ImplicitContextI + { + + @Override + public java.util.Map<String, String> getContext() + { + // + // Note that _map is a *synchronized* map + // + java.util.Map<String, String> threadContext = _map.get(Thread.currentThread()); + + if(threadContext == null) + { + threadContext = new java.util.HashMap<String, String>(); + } + return threadContext; + } + + @Override + public void setContext(java.util.Map<String, String> context) + { + if(context == null || context.isEmpty()) + { + _map.remove(Thread.currentThread()); + } + else + { + java.util.Map<String, String> threadContext = new java.util.HashMap<String, String>(context); + _map.put(Thread.currentThread(), threadContext); + } + } + + @Override + public boolean containsKey(String key) + { + if(key == null) + { + key = ""; + } + + java.util.Map<String, String> threadContext = _map.get(Thread.currentThread()); + + if(threadContext == null) + { + return false; + } + + return threadContext.containsKey(key); + } + + @Override + public String get(String key) + { + if(key == null) + { + key = ""; + } + + java.util.Map<String, String> threadContext = _map.get(Thread.currentThread()); + + if(threadContext == null) + { + return ""; + } + String val = threadContext.get(key); + if(val == null) + { + val = ""; + } + return val; + } + + @Override + public String put(String key, String value) + { + if(key == null) + { + key = ""; + } + if(value == null) + { + value = ""; + } + + Thread currentThread = Thread.currentThread(); + java.util.Map<String, String> threadContext = _map.get(currentThread); + + if(threadContext == null) + { + threadContext = new java.util.HashMap<String, String>(); + _map.put(currentThread, threadContext); + } + + String oldVal = threadContext.put(key, value); + if(oldVal == null) + { + oldVal = ""; + } + return oldVal; + } + + @Override + public String remove(String key) + { + if(key == null) + { + key = ""; + } + + java.util.Map<String, String> threadContext = _map.get(Thread.currentThread()); + + if(threadContext == null) + { + return null; + } + + String val = threadContext.remove(key); + + if(val == null) + { + val = ""; + } + return val; + } + + @Override + public void write(java.util.Map<String, String> prxContext, OutputStream os) + { + java.util.Map<String, String> threadContext = _map.get(Thread.currentThread()); + + if(threadContext == null || threadContext.isEmpty()) + { + ContextHelper.write(os, prxContext); + } + else if(prxContext.isEmpty()) + { + ContextHelper.write(os, threadContext); + } + else + { + java.util.Map<String, String> combined = new java.util.HashMap<String, String>(threadContext); + combined.putAll(prxContext); + ContextHelper.write(os, combined); + } + } + + @Override + java.util.Map<String, String> combine(java.util.Map<String, String> prxContext) + { + java.util.Map<String, String> threadContext = _map.get(Thread.currentThread()); + + java.util.Map<String, String> combined = new java.util.HashMap<String, String>(threadContext); + combined.putAll(prxContext); + return combined; + } + + // + // Synchronized map Thread -> Context + // + private java.util.Map<Thread, java.util.Map<String, String> > _map = + java.util.Collections.synchronizedMap(new java.util.HashMap<Thread, java.util.Map<String, String> >()); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/InitializationData.java b/java-compat/src/Ice/src/main/java/Ice/InitializationData.java new file mode 100644 index 00000000000..860557563e6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/InitializationData.java @@ -0,0 +1,96 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * A class that encapsulates data to initialize a communicator. + * + * @see Util#initialize + * @see Properties + * @see Logger + * @see ThreadNotification + **/ +public final class InitializationData implements Cloneable +{ + /** + * Creates an instance with all members set to <code>null</code>. + **/ + public + InitializationData() + { + } + + /** + * Creates and returns a copy of this object. + **/ + @Override + public InitializationData + clone() + { + // + // A member-wise copy is safe because the members are immutable. + // + InitializationData c = null; + try + { + c = (InitializationData)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; + } + + /** + * The properties for the communicator. + **/ + public Properties properties; + + /** + * The logger for the communicator. + **/ + public Logger logger; + + /** + * The communicator observer used by the Ice run-time. + **/ + public Ice.Instrumentation.CommunicatorObserver observer; + + /** + * The thread hook for the communicator. + **/ + public ThreadNotification threadHook; + + /** + * The custom class loader for the communicator. + **/ + public ClassLoader classLoader; + + /** + * The call dispatcher for the communicator. + **/ + public Dispatcher dispatcher; + + /** + * The compact type ID resolver. + **/ + public CompactIdResolver compactIdResolver; + + /** + * The batch request interceptor. + **/ + public BatchRequestInterceptor batchRequestInterceptor; + + /** + * The value factory manager. + **/ + public ValueFactoryManager valueFactoryManager; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/InputStream.java b/java-compat/src/Ice/src/main/java/Ice/InputStream.java new file mode 100644 index 00000000000..2027f53d03b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/InputStream.java @@ -0,0 +1,3422 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +import java.io.IOException; + +/** + * Interface for input streams used to extract Slice types from a sequence + * of bytes. + * + * @see OutputStream + **/ +public class InputStream +{ + /** + * Constructing an InputStream without providing a communicator means the stream will + * use the default encoding version. A communicator is required in order to unmarshal + * proxies. You can supply a communicator later by calling initialize(). + **/ + public InputStream() + { + initialize(IceInternal.Protocol.currentEncoding); + _buf = new IceInternal.Buffer(false); + } + + /** + * Constructing an InputStream without providing a communicator means the stream will + * use the default encoding version. A communicator is required in order to unmarshal + * proxies. You can supply a communicator later by calling initialize(). + * + * @param data The byte array containing encoded Slice types. + **/ + public InputStream(byte[] data) + { + initialize(IceInternal.Protocol.currentEncoding); + _buf = new IceInternal.Buffer(data); + } + + /** + * Constructing an InputStream without providing a communicator means the stream will + * use the default encoding version. A communicator is required in order to unmarshal + * proxies. You can supply a communicator later by calling initialize(). + * + * @param buf The byte buffer containing encoded Slice types. + **/ + public InputStream(java.nio.ByteBuffer buf) + { + initialize(IceInternal.Protocol.currentEncoding); + _buf = new IceInternal.Buffer(buf); + } + + public InputStream(IceInternal.Buffer buf) + { + this(buf, false); + } + + public InputStream(IceInternal.Buffer buf, boolean adopt) + { + initialize(IceInternal.Protocol.currentEncoding); + _buf = new IceInternal.Buffer(buf, adopt); + } + + /** + * This constructor uses the communicator's default encoding version. + * + * @param communicator The communicator to use when initializing the stream. + **/ + public InputStream(Communicator communicator) + { + IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, instance.defaultsAndOverrides().defaultEncoding); + _buf = new IceInternal.Buffer(instance.cacheMessageBuffers() > 1); + } + + /** + * This constructor uses the communicator's default encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param data The byte array containing encoded Slice types. + **/ + public InputStream(Communicator communicator, byte[] data) + { + initialize(communicator); + _buf = new IceInternal.Buffer(data); + } + + /** + * This constructor uses the communicator's default encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param buf The byte buffer containing encoded Slice types. + **/ + public InputStream(Communicator communicator, java.nio.ByteBuffer buf) + { + initialize(communicator); + _buf = new IceInternal.Buffer(buf); + } + + public InputStream(Communicator communicator, IceInternal.Buffer buf) + { + this(communicator, buf, false); + } + + public InputStream(Communicator communicator, IceInternal.Buffer buf, boolean adopt) + { + initialize(communicator); + _buf = new IceInternal.Buffer(buf, adopt); + } + + /** + * This constructor uses the given encoding version. + **/ + public InputStream(EncodingVersion encoding) + { + initialize(encoding); + _buf = new IceInternal.Buffer(false); + } + + /** + * This constructor uses the given encoding version. + * + * @param data The byte array containing encoded Slice types. + **/ + public InputStream(EncodingVersion encoding, byte[] data) + { + initialize(encoding); + _buf = new IceInternal.Buffer(data); + } + + /** + * This constructor uses the given encoding version. + * + * @param buf The byte buffer containing encoded Slice types. + **/ + public InputStream(EncodingVersion encoding, java.nio.ByteBuffer buf) + { + initialize(encoding); + _buf = new IceInternal.Buffer(buf); + } + + public InputStream(EncodingVersion encoding, IceInternal.Buffer buf) + { + this(encoding, buf, false); + } + + public InputStream(EncodingVersion encoding, IceInternal.Buffer buf, boolean adopt) + { + initialize(encoding); + _buf = new IceInternal.Buffer(buf, adopt); + } + + /** + * This constructor uses the given communicator and encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired encoding version. + **/ + public InputStream(Communicator communicator, EncodingVersion encoding) + { + IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, encoding); + _buf = new IceInternal.Buffer(instance.cacheMessageBuffers() > 1); + } + + /** + * This constructor uses the given communicator and encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired encoding version. + * @param data The byte array containing encoded Slice types. + **/ + public InputStream(Communicator communicator, EncodingVersion encoding, byte[] data) + { + initialize(communicator, encoding); + _buf = new IceInternal.Buffer(data); + } + + /** + * This constructor uses the given communicator and encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired encoding version. + * @param buf The byte buffer containing encoded Slice types. + **/ + public InputStream(Communicator communicator, EncodingVersion encoding, java.nio.ByteBuffer buf) + { + initialize(communicator, encoding); + _buf = new IceInternal.Buffer(buf); + } + + public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf) + { + this(communicator, encoding, buf, false); + } + + public InputStream(Communicator communicator, EncodingVersion encoding, IceInternal.Buffer buf, boolean adopt) + { + initialize(communicator, encoding); + _buf = new IceInternal.Buffer(buf, adopt); + } + + public InputStream(IceInternal.Instance instance, EncodingVersion encoding) + { + this(instance, encoding, instance.cacheMessageBuffers() > 1); + } + + public InputStream(IceInternal.Instance instance, EncodingVersion encoding, boolean direct) + { + initialize(instance, encoding); + _buf = new IceInternal.Buffer(direct); + } + + public InputStream(IceInternal.Instance instance, EncodingVersion encoding, byte[] data) + { + initialize(instance, encoding); + _buf = new IceInternal.Buffer(data); + } + + public InputStream(IceInternal.Instance instance, EncodingVersion encoding, java.nio.ByteBuffer data) + { + initialize(instance, encoding); + _buf = new IceInternal.Buffer(data); + } + + public InputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, boolean adopt) + { + initialize(instance, encoding); + _buf = new IceInternal.Buffer(buf, adopt); + } + + /** + * Initializes the stream to use the communicator's default encoding version. + * + * @param communicator The communicator to use when initializing the stream. + **/ + public void initialize(Communicator communicator) + { + IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, instance.defaultsAndOverrides().defaultEncoding); + } + + /** + * Initializes the stream to use the given communicator and encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired encoding version. + **/ + public void initialize(Communicator communicator, EncodingVersion encoding) + { + IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, encoding); + } + + private void initialize(IceInternal.Instance instance, EncodingVersion encoding) + { + initialize(encoding); + + _instance = instance; + _traceSlicing = _instance.traceLevels().slicing > 0; + + _valueFactoryManager = _instance.initializationData().valueFactoryManager; + _logger = _instance.initializationData().logger; + _classResolver = _instance; + } + + private void initialize(EncodingVersion encoding) + { + _instance = null; + _encoding = encoding; + _encapsStack = null; + _encapsCache = null; + _traceSlicing = false; + _closure = null; + _sliceValues = true; + _startSeq = -1; + _minSeqSize = 0; + } + + /** + * Resets this stream. This method allows the stream to be reused, to avoid creating + * unnecessary garbage. + **/ + public void reset() + { + _buf.reset(); + clear(); + } + + /** + * Releases any data retained by encapsulations. The {@link #reset} method internally calls </code>clear</code>. + **/ + public void clear() + { + if(_encapsStack != null) + { + assert(_encapsStack.next == null); + _encapsStack.next = _encapsCache; + _encapsCache = _encapsStack; + _encapsCache.reset(); + _encapsStack = null; + } + + _startSeq = -1; + _sliceValues = true; + } + + /** + * Sets the value factory manager to use when marshaling value instances. If the stream + * was initialized with a communicator, the communicator's value factory manager will + * be used by default. + * + * @param vfm The value factory manager. + **/ + public void setValueFactoryManager(ValueFactoryManager vfm) + { + _valueFactoryManager = vfm; + } + + /** + * Sets the logger to use when logging trace messages. If the stream + * was initialized with a communicator, the communicator's logger will + * be used by default. + * + * @param logger The logger to use for logging trace messages. + **/ + public void setLogger(Logger logger) + { + _logger = logger; + } + + /** + * Sets the compact ID resolver to use when unmarshaling value and exception + * instances. If the stream was initialized with a communicator, the communicator's + * resolver will be used by default. + * + * @param r The compact ID resolver. + **/ + public void setCompactIdResolver(CompactIdResolver r) + { + _compactIdResolver = r; + } + + /** + * Sets the class resolver, which the stream will use when attempting to unmarshal + * a value or exception. If the stream was initialized with a communicator, the communicator's + * resolver will be used by default. + * + * @param r The class resolver. + **/ + public void setClassResolver(ClassResolver r) + { + _classResolver = r; + } + + /** + * Determines the behavior of the stream when extracting instances of Slice classes. + * An instance is "sliced" when a factory cannot be found for a Slice type ID. + * The stream's default behavior is to slice instances. + * + * @param b If <code>true</code> (the default), slicing is enabled; if <code>false</code>, + * slicing is disabled. If slicing is disabled and the stream encounters a Slice type ID + * during decoding for which no value factory is installed, it raises {@link NoValueFactoryException}. + **/ + public void setSliceValues(boolean b) + { + _sliceValues = b; + } + + /** + * Determines whether the stream logs messages about slicing instances of Slice values. + * + * @param b True to enable logging, false to disable logging. + **/ + public void setTraceSlicing(boolean b) + { + _traceSlicing = b; + } + + /** + * Retrieves the closure object associated with this stream. + * + * @return The closure object. + **/ + public Object getClosure() + { + return _closure; + } + + /** + * Associates a closure object with this stream. + * + * @param p The new closure object. + * @return The previous closure object, or null. + **/ + public Object setClosure(Object p) + { + Object prev = _closure; + _closure = p; + return prev; + } + + public IceInternal.Instance instance() + { + return _instance; + } + + /** + * Swaps the contents of one stream with another. + * + * @param other The other stream. + **/ + public void swap(InputStream other) + { + assert(_instance == other._instance); + + IceInternal.Buffer tmpBuf = other._buf; + other._buf = _buf; + _buf = tmpBuf; + + EncodingVersion tmpEncoding = other._encoding; + other._encoding = _encoding; + _encoding = tmpEncoding; + + boolean tmpTraceSlicing = other._traceSlicing; + other._traceSlicing = _traceSlicing; + _traceSlicing = tmpTraceSlicing; + + Object tmpClosure = other._closure; + other._closure = _closure; + _closure = tmpClosure; + + boolean tmpSliceValues = other._sliceValues; + other._sliceValues = _sliceValues; + _sliceValues = tmpSliceValues; + + // + // Swap is never called for streams that have encapsulations being read. However, + // encapsulations might still be set in case unmarshaling failed. We just + // reset the encapsulations if there are still some set. + // + resetEncapsulation(); + other.resetEncapsulation(); + + int tmpStartSeq = other._startSeq; + other._startSeq = _startSeq; + _startSeq = tmpStartSeq; + + int tmpMinSeqSize = other._minSeqSize; + other._minSeqSize = _minSeqSize; + _minSeqSize = tmpMinSeqSize; + + ValueFactoryManager tmpVfm = other._valueFactoryManager; + other._valueFactoryManager = _valueFactoryManager; + _valueFactoryManager = tmpVfm; + + Logger tmpLogger = other._logger; + other._logger = _logger; + _logger = tmpLogger; + + CompactIdResolver tmpCompactIdResolver = other._compactIdResolver; + other._compactIdResolver = _compactIdResolver; + _compactIdResolver = tmpCompactIdResolver; + + ClassResolver tmpClassResolver = other._classResolver; + other._classResolver = _classResolver; + _classResolver = tmpClassResolver; + } + + private void resetEncapsulation() + { + _encapsStack = null; + } + + /** + * Resizes the stream to a new size. + * + * @param sz The new size. + **/ + public void resize(int sz) + { + _buf.resize(sz, true); + _buf.b.position(sz); + } + + public IceInternal.Buffer getBuffer() + { + return _buf; + } + + /** + * Marks the start of a class instance. + **/ + public void startValue() + { + assert(_encapsStack != null && _encapsStack.decoder != null); + _encapsStack.decoder.startInstance(SliceType.ValueSlice); + } + + /** + * Marks the end of a class instance. + * + * @param preserve Pass true and the stream will preserve the unknown slices of the instance, or false + * to discard the unknown slices. + * @return An object that encapsulates the unknown slice data. + **/ + public SlicedData endValue(boolean preserve) + { + assert(_encapsStack != null && _encapsStack.decoder != null); + return _encapsStack.decoder.endInstance(preserve); + } + + /** + * Marks the start of a user exception. + **/ + public void startException() + { + assert(_encapsStack != null && _encapsStack.decoder != null); + _encapsStack.decoder.startInstance(SliceType.ExceptionSlice); + } + + /** + * Marks the end of a user exception. + * + * @param preserve Pass true and the stream will preserve the unknown slices of the exception, or false + * to discard the unknown slices. + * @return An object that encapsulates the unknown slice data. + **/ + public SlicedData endException(boolean preserve) + { + assert(_encapsStack != null && _encapsStack.decoder != null); + return _encapsStack.decoder.endInstance(preserve); + } + + /** + * Reads the start of an encapsulation. + * + * @return The encoding version used by the encapsulation. + **/ + public EncodingVersion startEncapsulation() + { + Encaps curr = _encapsCache; + if(curr != null) + { + curr.reset(); + _encapsCache = _encapsCache.next; + } + else + { + curr = new Encaps(); + } + curr.next = _encapsStack; + _encapsStack = curr; + + _encapsStack.start = _buf.b.position(); + + // + // I don't use readSize() for encapsulations, because when creating an encapsulation, + // I must know in advance how many bytes the size information will require in the data + // stream. If I use an Int, it is always 4 bytes. For readSize(), it could be 1 or 5 bytes. + // + int sz = readInt(); + if(sz < 6) + { + throw new UnmarshalOutOfBoundsException(); + } + if(sz - 4 > _buf.b.remaining()) + { + throw new UnmarshalOutOfBoundsException(); + } + _encapsStack.sz = sz; + + EncodingVersion encoding = new EncodingVersion(); + encoding.__read(this); + IceInternal.Protocol.checkSupportedEncoding(encoding); // Make sure the encoding is supported. + _encapsStack.setEncoding(encoding); + + return encoding; + } + + /** + * Ends the previous encapsulation. + **/ + public void endEncapsulation() + { + assert(_encapsStack != null); + + if(!_encapsStack.encoding_1_0) + { + skipOptionals(); + if(_buf.b.position() != _encapsStack.start + _encapsStack.sz) + { + throw new EncapsulationException(); + } + } + else if(_buf.b.position() != _encapsStack.start + _encapsStack.sz) + { + if(_buf.b.position() + 1 != _encapsStack.start + _encapsStack.sz) + { + throw new EncapsulationException(); + } + + // + // Ice version < 3.3 had a bug where user exceptions with + // class members could be encoded with a trailing byte + // when dispatched with AMD. So we tolerate an extra byte + // in the encapsulation. + // + try + { + _buf.b.get(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + Encaps curr = _encapsStack; + _encapsStack = curr.next; + curr.next = _encapsCache; + _encapsCache = curr; + _encapsCache.reset(); + } + + /** + * Skips an empty encapsulation. + * + * @return The encapsulation's encoding version. + **/ + public EncodingVersion skipEmptyEncapsulation() + { + int sz = readInt(); + if(sz < 6) + { + throw new Ice.EncapsulationException(); + } + if(sz - 4 > _buf.b.remaining()) + { + throw new Ice.UnmarshalOutOfBoundsException(); + } + + EncodingVersion encoding = EncodingVersion.read(this, null); + if(encoding.equals(Ice.Util.Encoding_1_0)) + { + if(sz != 6) + { + throw new Ice.EncapsulationException(); + } + } + else + { + // + // Skip the optional content of the encapsulation if we are expecting an + // empty encapsulation. + // + _buf.b.position(_buf.b.position() + sz - 6); + } + return encoding; + } + + /** + * Returns a blob of bytes representing an encapsulation. The encapsulation's encoding version + * is returned in the argument. + * + * @param encoding The encapsulation's encoding version. + * @return The encoded encapuslation. + **/ + public byte[] readEncapsulation(EncodingVersion encoding) + { + int sz = readInt(); + if(sz < 6) + { + throw new UnmarshalOutOfBoundsException(); + } + + if(sz - 4 > _buf.b.remaining()) + { + throw new UnmarshalOutOfBoundsException(); + } + + if(encoding != null) + { + encoding.__read(this); + _buf.b.position(_buf.b.position() - 6); + } + else + { + _buf.b.position(_buf.b.position() - 4); + } + + byte[] v = new byte[sz]; + try + { + _buf.b.get(v); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Determines the current encoding version. + * + * @return The encoding version. + **/ + public EncodingVersion getEncoding() + { + return _encapsStack != null ? _encapsStack.encoding : _encoding; + } + + /** + * Determines the size of the current encapsulation, excluding the encapsulation header. + * + * @return The size of the encapsulated data. + **/ + public int getEncapsulationSize() + { + assert(_encapsStack != null); + return _encapsStack.sz - 6; + } + + /** + * Skips over an encapsulation. + * + * @return The encoding version of the skipped encapsulation. + **/ + public EncodingVersion skipEncapsulation() + { + int sz = readInt(); + if(sz < 6) + { + throw new UnmarshalOutOfBoundsException(); + } + EncodingVersion encoding = new EncodingVersion(); + encoding.__read(this); + try + { + _buf.b.position(_buf.b.position() + sz - 6); + } + catch(IllegalArgumentException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + return encoding; + } + + /** + * Reads the start of a value or exception slice. + * + * @return The Slice type ID for this slice. + **/ + public String startSlice() // Returns type ID of next slice + { + assert(_encapsStack != null && _encapsStack.decoder != null); + return _encapsStack.decoder.startSlice(); + } + + /** + * Indicates that the end of a value or exception slice has been reached. + **/ + public void endSlice() + { + assert(_encapsStack != null && _encapsStack.decoder != null); + _encapsStack.decoder.endSlice(); + } + + /** + * Skips over a value or exception slice. + **/ + public void skipSlice() + { + assert(_encapsStack != null && _encapsStack.decoder != null); + _encapsStack.decoder.skipSlice(); + } + + /** + * Indicates that unmarshaling is complete, except for any class instances. The application must call this method + * only if the stream actually contains class instances. Calling <code>readPendingValues</code> triggers the + * calls to {@link ReadValueCallback#valueReady} that inform the application that unmarshaling of an instance + * is complete. + **/ + public void readPendingValues() + { + if(_encapsStack != null && _encapsStack.decoder != null) + { + _encapsStack.decoder.readPendingValues(); + } + else if(_encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.equals(Util.Encoding_1_0)) + { + // + // If using the 1.0 encoding and no instances were read, we + // still read an empty sequence of pending instances if + // requested (i.e.: if this is called). + // + // This is required by the 1.0 encoding, even if no instances + // are written we do marshal an empty sequence if marshaled + // data types use classes. + // + skipSize(); + } + } + + /** + * Extracts a size from the stream. + * + * @return The extracted size. + **/ + public int readSize() + { + try + { + byte b = _buf.b.get(); + if(b == -1) + { + int v = _buf.b.getInt(); + if(v < 0) + { + throw new UnmarshalOutOfBoundsException(); + } + return v; + } + else + { + return b < 0 ? b + 256 : b; + } + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Reads and validates a sequence size. + * + * @return The extracted size. + **/ + public int readAndCheckSeqSize(int minSize) + { + int sz = readSize(); + + if(sz == 0) + { + return sz; + } + + // + // The _startSeq variable points to the start of the sequence for which + // we expect to read at least _minSeqSize bytes from the stream. + // + // If not initialized or if we already read more data than _minSeqSize, + // we reset _startSeq and _minSeqSize for this sequence (possibly a + // top-level sequence or enclosed sequence it doesn't really matter). + // + // Otherwise, we are reading an enclosed sequence and we have to bump + // _minSeqSize by the minimum size that this sequence will require on + // the stream. + // + // The goal of this check is to ensure that when we start un-marshalling + // a new sequence, we check the minimal size of this new sequence against + // the estimated remaining buffer size. This estimatation is based on + // the minimum size of the enclosing sequences, it's _minSeqSize. + // + if(_startSeq == -1 || _buf.b.position() > (_startSeq + _minSeqSize)) + { + _startSeq = _buf.b.position(); + _minSeqSize = sz * minSize; + } + else + { + _minSeqSize += sz * minSize; + } + + // + // If there isn't enough data to read on the stream for the sequence (and + // possibly enclosed sequences), something is wrong with the marshalled + // data: it's claiming having more data that what is possible to read. + // + if(_startSeq + _minSeqSize > _buf.size()) + { + throw new UnmarshalOutOfBoundsException(); + } + + return sz; + } + + /** + * Reads a blob of bytes from the stream. + * + * @param sz The number of bytes to read. + * @return The requested bytes as a byte array. + **/ + public byte[] readBlob(int sz) + { + if(_buf.b.remaining() < sz) + { + throw new UnmarshalOutOfBoundsException(); + } + byte[] v = new byte[sz]; + try + { + _buf.b.get(v); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Determine if an optional value is available for reading. + * + * @param tag The tag associated with the value. + * @param expectedFormat The optional format for the value. + * @return True if the value is present, false otherwise. + **/ + public boolean readOptional(int tag, OptionalFormat expectedFormat) + { + assert(_encapsStack != null); + if(_encapsStack.decoder != null) + { + return _encapsStack.decoder.readOptional(tag, expectedFormat); + } + else + { + return readOptImpl(tag, expectedFormat); + } + } + + /** + * Extracts a byte value from the stream. + * + * @return The extracted byte. + **/ + public byte readByte() + { + try + { + return _buf.b.get(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional byte value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readByte(int tag, ByteOptional v) + { + if(readOptional(tag, OptionalFormat.F1)) + { + v.set(readByte()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of byte values from the stream. + * + * @return The extracted byte sequence. + **/ + public byte[] readByteSeq() + { + try + { + final int sz = readAndCheckSeqSize(1); + byte[] v = new byte[sz]; + _buf.b.get(v); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional byte sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readByteSeq(int tag, Optional<byte[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + v.set(readByteSeq()); + } + else + { + v.clear(); + } + } + + /** + * Returns a byte buffer representing a sequence of bytes. This method does not copy the data. + * + * @return A byte buffer "slice" of the internal buffer. + **/ + public java.nio.ByteBuffer readByteBuffer() + { + try + { + final int sz = readAndCheckSeqSize(1); + java.nio.ByteBuffer v = _buf.b.slice(); + v.limit(sz); + _buf.b.position(_buf.b.position() + sz); + return v.asReadOnlyBuffer(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts a serializable Java object from the stream. + * + * @return The deserialized Java object. + **/ + public java.io.Serializable readSerializable() + { + int sz = readAndCheckSeqSize(1); + if (sz == 0) + { + return null; + } + IceInternal.ObjectInputStream in = null; + try + { + IceInternal.InputStreamWrapper w = new IceInternal.InputStreamWrapper(sz, _buf.b); + in = new IceInternal.ObjectInputStream(_instance, w); + return (java.io.Serializable)in.readObject(); + } + catch(LocalException ex) + { + throw ex; + } + catch(java.lang.Exception ex) + { + throw new MarshalException("cannot deserialize object", ex); + } + finally + { + if(in != null) + { + try + { + in.close(); + } + catch (IOException ex) + { + throw new MarshalException("cannot deserialize object", ex); + } + } + } + } + + /** + * Extracts a boolean value from the stream. + * + * @return The extracted boolean. + **/ + public boolean readBool() + { + try + { + return _buf.b.get() == 1; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional boolean value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readBool(int tag, BooleanOptional v) + { + if(readOptional(tag, OptionalFormat.F1)) + { + v.set(readBool()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of boolean values from the stream. + * + * @return The extracted boolean sequence. + **/ + public boolean[] readBoolSeq() + { + try + { + final int sz = readAndCheckSeqSize(1); + boolean[] v = new boolean[sz]; + for(int i = 0; i < sz; i++) + { + v[i] = _buf.b.get() == 1; + } + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional boolean sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readBoolSeq(int tag, Optional<boolean[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + v.set(readBoolSeq()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a short value from the stream. + * + * @return The extracted short. + **/ + public short readShort() + { + try + { + return _buf.b.getShort(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional short value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readShort(int tag, ShortOptional v) + { + if(readOptional(tag, OptionalFormat.F2)) + { + v.set(readShort()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of short values from the stream. + * + * @return The extracted short sequence. + **/ + public short[] readShortSeq() + { + try + { + final int sz = readAndCheckSeqSize(2); + short[] v = new short[sz]; + java.nio.ShortBuffer shortBuf = _buf.b.asShortBuffer(); + shortBuf.get(v); + _buf.b.position(_buf.b.position() + sz * 2); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional short sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readShortSeq(int tag, Optional<short[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + skipSize(); + v.set(readShortSeq()); + } + else + { + v.clear(); + } + } + + /** + * Returns a short buffer representing a sequence of shorts. This method does not copy the data. + * + * @return A short buffer "slice" of the internal buffer. + **/ + public java.nio.ShortBuffer readShortBuffer() + { + try + { + final int sz = readAndCheckSeqSize(2); + java.nio.ShortBuffer shortBuf = _buf.b.asShortBuffer(); + java.nio.ShortBuffer v = shortBuf.slice(); + v.limit(sz); + _buf.b.position(_buf.b.position() + sz * 2); + return v.asReadOnlyBuffer(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an int value from the stream. + * + * @return The extracted int. + **/ + public int readInt() + { + try + { + return _buf.b.getInt(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional int value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readInt(int tag, IntOptional v) + { + if(readOptional(tag, OptionalFormat.F4)) + { + v.set(readInt()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of int values from the stream. + * + * @return The extracted int sequence. + **/ + public int[] readIntSeq() + { + try + { + final int sz = readAndCheckSeqSize(4); + int[] v = new int[sz]; + java.nio.IntBuffer intBuf = _buf.b.asIntBuffer(); + intBuf.get(v); + _buf.b.position(_buf.b.position() + sz * 4); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional int sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readIntSeq(int tag, Optional<int[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + skipSize(); + v.set(readIntSeq()); + } + else + { + v.clear(); + } + } + + /** + * Returns an int buffer representing a sequence of ints. This method does not copy the data. + * + * @return An int buffer "slice" of the internal buffer. + **/ + public java.nio.IntBuffer readIntBuffer() + { + try + { + final int sz = readAndCheckSeqSize(4); + java.nio.IntBuffer intBuf = _buf.b.asIntBuffer(); + java.nio.IntBuffer v = intBuf.slice(); + v.limit(sz); + _buf.b.position(_buf.b.position() + sz * 4); + return v.asReadOnlyBuffer(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts a long value from the stream. + * + * @return The extracted long. + **/ + public long readLong() + { + try + { + return _buf.b.getLong(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional long value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readLong(int tag, LongOptional v) + { + if(readOptional(tag, OptionalFormat.F8)) + { + v.set(readLong()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of long values from the stream. + * + * @return The extracted long sequence. + **/ + public long[] readLongSeq() + { + try + { + final int sz = readAndCheckSeqSize(8); + long[] v = new long[sz]; + java.nio.LongBuffer longBuf = _buf.b.asLongBuffer(); + longBuf.get(v); + _buf.b.position(_buf.b.position() + sz * 8); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional long sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readLongSeq(int tag, Optional<long[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + skipSize(); + v.set(readLongSeq()); + } + else + { + v.clear(); + } + } + + /** + * Returns a long buffer representing a sequence of longs. This method does not copy the data. + * + * @return A long buffer "slice" of the internal buffer. + **/ + public java.nio.LongBuffer readLongBuffer() + { + try + { + final int sz = readAndCheckSeqSize(8); + java.nio.LongBuffer longBuf = _buf.b.asLongBuffer(); + java.nio.LongBuffer v = longBuf.slice(); + v.limit(sz); + _buf.b.position(_buf.b.position() + sz * 8); + return v.asReadOnlyBuffer(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts a float value from the stream. + * + * @return The extracted float. + **/ + public float readFloat() + { + try + { + return _buf.b.getFloat(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional float value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readFloat(int tag, FloatOptional v) + { + if(readOptional(tag, OptionalFormat.F4)) + { + v.set(readFloat()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of float values from the stream. + * + * @return The extracted float sequence. + **/ + public float[] readFloatSeq() + { + try + { + final int sz = readAndCheckSeqSize(4); + float[] v = new float[sz]; + java.nio.FloatBuffer floatBuf = _buf.b.asFloatBuffer(); + floatBuf.get(v); + _buf.b.position(_buf.b.position() + sz * 4); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional float sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readFloatSeq(int tag, Optional<float[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + skipSize(); + v.set(readFloatSeq()); + } + else + { + v.clear(); + } + } + + /** + * Returns a float buffer representing a sequence of floats. This method does not copy the data. + * + * @return A float buffer "slice" of the internal buffer. + **/ + public java.nio.FloatBuffer readFloatBuffer() + { + try + { + final int sz = readAndCheckSeqSize(4); + java.nio.FloatBuffer floatBuf = _buf.b.asFloatBuffer(); + java.nio.FloatBuffer v = floatBuf.slice(); + v.limit(sz); + _buf.b.position(_buf.b.position() + sz * 4); + return v.asReadOnlyBuffer(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts a double value from the stream. + * + * @return The extracted double. + **/ + public double readDouble() + { + try + { + return _buf.b.getDouble(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional double value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readDouble(int tag, DoubleOptional v) + { + if(readOptional(tag, OptionalFormat.F8)) + { + v.set(readDouble()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of double values from the stream. + * + * @return The extracted double sequence. + **/ + public double[] readDoubleSeq() + { + try + { + final int sz = readAndCheckSeqSize(8); + double[] v = new double[sz]; + java.nio.DoubleBuffer doubleBuf = _buf.b.asDoubleBuffer(); + doubleBuf.get(v); + _buf.b.position(_buf.b.position() + sz * 8); + return v; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + /** + * Extracts an optional double sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readDoubleSeq(int tag, Optional<double[]> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + skipSize(); + v.set(readDoubleSeq()); + } + else + { + v.clear(); + } + } + + /** + * Returns a double buffer representing a sequence of doubles. This method does not copy the data. + * + * @return A double buffer "slice" of the internal buffer. + **/ + public java.nio.DoubleBuffer readDoubleBuffer() + { + try + { + final int sz = readAndCheckSeqSize(8); + java.nio.DoubleBuffer doubleBuf = _buf.b.asDoubleBuffer(); + java.nio.DoubleBuffer v = doubleBuf.slice(); + v.limit(sz); + _buf.b.position(_buf.b.position() + sz * 8); + return v.asReadOnlyBuffer(); + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + + final static java.nio.charset.Charset _utf8 = java.nio.charset.Charset.forName("UTF8"); + private java.nio.charset.CharsetEncoder _charEncoder = null; + + /** + * Extracts a string from the stream. + * + * @return The extracted string. + **/ + public String readString() + { + final int len = readSize(); + + if(len == 0) + { + return ""; + } + else + { + // + // Check the buffer has enough bytes to read. + // + if(_buf.b.remaining() < len) + { + throw new UnmarshalOutOfBoundsException(); + } + + try + { + // + // We reuse the _stringBytes array to avoid creating + // excessive garbage. + // + if(_stringBytes == null || len > _stringBytes.length) + { + _stringBytes = new byte[len]; + } + if(_stringChars == null || len > _stringChars.length) + { + _stringChars = new char[len]; + } + _buf.b.get(_stringBytes, 0, len); + + // + // It's more efficient to construct a string using a + // character array instead of a byte array, because + // byte arrays require conversion. + // + for(int i = 0; i < len; i++) + { + if(_stringBytes[i] < 0) + { + // + // Multi-byte character found - we must use + // conversion. + // + // TODO: If the string contains garbage bytes + // that won't correctly decode as UTF, the + // behavior of this constructor is + // undefined. It would be better to explicitly + // decode using + // java.nio.charset.CharsetDecoder and to + // throw MarshalException if the string won't + // decode. + // + return new String(_stringBytes, 0, len, "UTF8"); + } + else + { + _stringChars[i] = (char)_stringBytes[i]; + } + } + return new String(_stringChars, 0, len); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + return ""; + } + catch(java.nio.BufferUnderflowException ex) + { + throw new UnmarshalOutOfBoundsException(); + } + } + } + + /** + * Extracts an optional string value from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readString(int tag, Optional<String> v) + { + if(readOptional(tag, OptionalFormat.VSize)) + { + v.set(readString()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a sequence of string values from the stream. + * + * @return The extracted string sequence. + **/ + public String[] readStringSeq() + { + final int sz = readAndCheckSeqSize(1); + String[] v = new String[sz]; + for(int i = 0; i < sz; i++) + { + v[i] = readString(); + } + return v; + } + + /** + * Extracts an optional string sequence from the stream. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readStringSeq(int tag, Optional<String[]> v) + { + if(readOptional(tag, OptionalFormat.FSize)) + { + skip(4); + v.set(readStringSeq()); + } + else + { + v.clear(); + } + } + + /** + * Extracts a proxy from the stream. The stream must have been initialized with a communicator. + * + * @return The extracted proxy. + **/ + public ObjectPrx readProxy() + { + if(_instance == null) + { + throw new MarshalException("cannot unmarshal a proxy without a communicator"); + } + + return _instance.proxyFactory().streamToProxy(this); + } + + /** + * Extracts an optional proxy from the stream. The stream must have been initialized with a communicator. + * + * @param tag The numeric tag associated with the value. + * @param v Holds the optional value (if any). + **/ + public void readProxy(int tag, Optional<ObjectPrx> v) + { + if(readOptional(tag, OptionalFormat.FSize)) + { + skip(4); + v.set(readProxy()); + } + else + { + v.clear(); + } + } + + /** + * Read an enumerated value. + * + * @param maxValue The maximum enumerator value in the definition. + * @return The enumerator. + **/ + public int readEnum(int maxValue) + { + if(getEncoding().equals(Util.Encoding_1_0)) + { + if(maxValue < 127) + { + return readByte(); + } + else if(maxValue < 32767) + { + return readShort(); + } + else + { + return readInt(); + } + } + else + { + return readSize(); + } + } + + /** + * Extracts the index of a Slice value from the stream. + * + * @param cb The callback to notify the application when the extracted instance is available. + * The stream extracts Slice values in stages. The Ice run time calls {@link ReadValueCallback#valueReady} + * when the corresponding instance has been fully unmarshaled. + * + * @see ReadValueCallback + **/ + public void readValue(ReadValueCallback cb) + { + initEncaps(); + _encapsStack.decoder.readValue(cb); + } + + /** + * Extracts the index of an optional Slice value from the stream. + * + * @param v Holds the optional value (if any). If a value is present, it will not be set in the + * argument until after {@link #readPendingValues} has completed. + **/ + public void readValue(int tag, Optional<Ice.Object> v) + { + if(readOptional(tag, OptionalFormat.Class)) + { + OptionalObject opt = new OptionalObject(v, Ice.Object.class, ObjectImpl.ice_staticId()); + readValue(opt); + } + else + { + v.clear(); + } + } + + /** + * Extracts a user exception from the stream and throws it. + **/ + public void throwException() + throws UserException + { + throwException(null); + } + + /** + * Extracts a user exception from the stream and throws it. The caller can supply a factory + * to instantiate exception instances. + * + * @param factory The user exception factory, or null to use the stream's default behavior. + **/ + public void throwException(UserExceptionFactory factory) + throws UserException + { + initEncaps(); + _encapsStack.decoder.throwException(factory); + } + + private boolean readOptImpl(int readTag, OptionalFormat expectedFormat) + { + if(isEncoding_1_0()) + { + return false; // Optional members aren't supported with the 1.0 encoding. + } + + while(true) + { + if(_buf.b.position() >= _encapsStack.start + _encapsStack.sz) + { + return false; // End of encapsulation also indicates end of optionals. + } + + final byte b = readByte(); + final int v = b < 0 ? b + 256 : b; + if(v == IceInternal.Protocol.OPTIONAL_END_MARKER) + { + _buf.b.position(_buf.b.position() - 1); // Rewind. + return false; + } + + OptionalFormat format = OptionalFormat.valueOf(v & 0x07); // First 3 bits. + int tag = v >> 3; + if(tag == 30) + { + tag = readSize(); + } + + if(tag > readTag) + { + int offset = tag < 30 ? 1 : (tag < 255 ? 2 : 6); // Rewind + _buf.b.position(_buf.b.position() - offset); + return false; // No optional data members with the requested tag. + } + else if(tag < readTag) + { + skipOptional(format); // Skip optional data members + } + else + { + if(format != expectedFormat) + { + throw new MarshalException("invalid optional data member `" + tag + "': unexpected format"); + } + return true; + } + } + } + + private void skipOptional(OptionalFormat format) + { + switch(format) + { + case F1: + { + skip(1); + break; + } + case F2: + { + skip(2); + break; + } + case F4: + { + skip(4); + break; + } + case F8: + { + skip(8); + break; + } + case Size: + { + skipSize(); + break; + } + case VSize: + { + skip(readSize()); + break; + } + case FSize: + { + skip(readInt()); + break; + } + case Class: + { + readValue(null); + break; + } + } + } + + private void skipOptionals() + { + // + // Skip remaining un-read optional members. + // + while(true) + { + if(_buf.b.position() >= _encapsStack.start + _encapsStack.sz) + { + return; // End of encapsulation also indicates end of optionals. + } + + final byte b = readByte(); + final int v = b < 0 ? b + 256 : b; + if(v == IceInternal.Protocol.OPTIONAL_END_MARKER) + { + return; + } + + OptionalFormat format = OptionalFormat.valueOf(v & 0x07); // Read first 3 bits. + if((v >> 3) == 30) + { + skipSize(); + } + skipOptional(format); + } + } + + /** + * Skip the given number of bytes. + * + * @param size The number of bytes to skip. + **/ + public void skip(int size) + { + if(size < 0 || size > _buf.b.remaining()) + { + throw new UnmarshalOutOfBoundsException(); + } + _buf.b.position(_buf.b.position() + size); + } + + /** + * Skip over a size value. + **/ + public void skipSize() + { + byte b = readByte(); + if(b == -1) + { + skip(4); + } + } + + /** + * Determines the current position in the stream. + * + * @return The current position. + **/ + public int pos() + { + return _buf.b.position(); + } + + /** + * Sets the current position in the stream. + * + * @param n The new position. + **/ + public void pos(int n) + { + _buf.b.position(n); + } + + /** + * Determines the current size of the stream. + * + * @return The current size. + **/ + public int size() + { + return _buf.size(); + } + + /** + * Determines whether the stream is empty. + * + * @return True if the internal buffer has no data, false otherwise. + **/ + public boolean isEmpty() + { + return _buf.empty(); + } + + private UserException createUserException(String id) + { + UserException userEx = null; + + try + { + if(_classResolver != null) + { + Class<?> c = _classResolver.resolveClass(id); + if(c != null) + { + userEx = (UserException)c.newInstance(); + } + } + } + catch(java.lang.Exception ex) + { + throw new MarshalException(ex); + } + + return userEx; + } + + private IceInternal.Instance _instance; + private IceInternal.Buffer _buf; + private Object _closure; + private byte[] _stringBytes; // Reusable array for reading strings. + private char[] _stringChars; // Reusable array for reading strings. + + private enum SliceType { NoSlice, ValueSlice, ExceptionSlice } + + abstract private static class EncapsDecoder + { + EncapsDecoder(InputStream stream, boolean sliceValues, ValueFactoryManager f, ClassResolver cr) + { + _stream = stream; + _sliceValues = sliceValues; + _valueFactoryManager = f; + _classResolver = cr; + _typeIdIndex = 0; + _unmarshaledMap = new java.util.TreeMap<Integer, Ice.Object>(); + } + + abstract void readValue(ReadValueCallback cb); + abstract void throwException(UserExceptionFactory factory) + throws UserException; + + abstract void startInstance(SliceType type); + abstract SlicedData endInstance(boolean preserve); + abstract String startSlice(); + abstract void endSlice(); + abstract void skipSlice(); + + boolean readOptional(int tag, OptionalFormat format) + { + return false; + } + + void readPendingValues() + { + } + + protected String readTypeId(boolean isIndex) + { + if(_typeIdMap == null) // Lazy initialization + { + _typeIdMap = new java.util.TreeMap<Integer, String>(); + } + + if(isIndex) + { + int index = _stream.readSize(); + String typeId = _typeIdMap.get(index); + if(typeId == null) + { + throw new UnmarshalOutOfBoundsException(); + } + return typeId; + } + else + { + String typeId = _stream.readString(); + _typeIdMap.put(++_typeIdIndex, typeId); + return typeId; + } + } + + protected Class<?> resolveClass(String typeId) + { + Class<?> cls = null; + if(_typeIdCache == null) + { + _typeIdCache = new java.util.HashMap<String, Class<?> >(); // Lazy initialization. + } + else + { + cls = _typeIdCache.get(typeId); + } + + if(cls == EncapsDecoder.class) // Marker for non-existent class. + { + cls = null; + } + else if(cls == null) + { + try + { + if(_classResolver != null) + { + cls = _classResolver.resolveClass(typeId); + _typeIdCache.put(typeId, cls != null ? cls : EncapsDecoder.class); + } + } + catch(java.lang.Exception ex) + { + throw new NoValueFactoryException("no value factory", typeId, ex); + } + } + + return cls; + } + + protected Ice.Object newInstance(String typeId) + { + // + // Try to find a factory registered for the specific type. + // + ValueFactory userFactory = _valueFactoryManager.find(typeId); + Ice.Object v = null; + if(userFactory != null) + { + v = userFactory.create(typeId); + } + + // + // If that fails, invoke the default factory if one has been + // registered. + // + if(v == null) + { + userFactory = _valueFactoryManager.find(""); + if(userFactory != null) + { + v = userFactory.create(typeId); + } + } + + // + // Last chance: try to instantiate the class dynamically. + // + if(v == null) + { + Class<?> cls = resolveClass(typeId); + + if(cls != null) + { + try + { + v = (Ice.Object)cls.newInstance(); + } + catch(java.lang.Exception ex) + { + throw new NoValueFactoryException("no value factory", typeId, ex); + } + } + } + + return v; + } + + protected void addPatchEntry(int index, ReadValueCallback cb) + { + assert(index > 0); + + // + // Check if we have already unmarshalled the instance. If that's the case, + // just invoke the callback and we're done. + // + Ice.Object obj = _unmarshaledMap.get(index); + if(obj != null) + { + cb.valueReady(obj); + return; + } + + if(_patchMap == null) // Lazy initialization + { + _patchMap = new java.util.TreeMap<Integer, java.util.LinkedList<ReadValueCallback> >(); + } + + // + // Add patch entry if the instance isn't unmarshaled yet, + // the callback will be called when the instance is + // unmarshaled. + // + java.util.LinkedList<ReadValueCallback> l = _patchMap.get(index); + if(l == null) + { + // + // We have no outstanding instances to be patched for this + // index, so make a new entry in the patch map. + // + l = new java.util.LinkedList<ReadValueCallback>(); + _patchMap.put(index, l); + } + + // + // Append a patch entry for this instance. + // + l.add(cb); + } + + protected void unmarshal(int index, Ice.Object v) + { + // + // Add the instance to the map of unmarshaled instances, this must + // be done before reading the instances (for circular references). + // + _unmarshaledMap.put(index, v); + + // + // Read the instance. + // + v.__read(_stream); + + if(_patchMap != null) + { + // + // Patch all instances now that the instance is unmarshaled. + // + java.util.LinkedList<ReadValueCallback> l = _patchMap.get(index); + if(l != null) + { + assert(l.size() > 0); + + // + // Patch all pointers that refer to the instance. + // + for(ReadValueCallback cb : l) + { + cb.valueReady(v); + } + + // + // Clear out the patch map for that index -- there is nothing left + // to patch for that index for the time being. + // + _patchMap.remove(index); + } + } + + if((_patchMap == null || _patchMap.isEmpty()) && _valueList == null) + { + try + { + v.ice_postUnmarshal(); + } + catch(java.lang.Exception ex) + { + String s = "exception raised by ice_postUnmarshal:\n" + IceInternal.Ex.toString(ex); + _stream.instance().initializationData().logger.warning(s); + } + } + else + { + if(_valueList == null) // Lazy initialization + { + _valueList = new java.util.ArrayList<Ice.Object>(); + } + _valueList.add(v); + + if(_patchMap == null || _patchMap.isEmpty()) + { + // + // Iterate over the instance list and invoke ice_postUnmarshal on + // each instance. We must do this after all instances have been + // unmarshaled in order to ensure that any instance data members + // have been properly patched. + // + for(Ice.Object p : _valueList) + { + try + { + p.ice_postUnmarshal(); + } + catch(java.lang.Exception ex) + { + String s = "exception raised by ice_postUnmarshal:\n" + IceInternal.Ex.toString(ex); + _stream.instance().initializationData().logger.warning(s); + } + } + _valueList.clear(); + } + } + } + + protected final InputStream _stream; + protected final boolean _sliceValues; + protected ValueFactoryManager _valueFactoryManager; + protected ClassResolver _classResolver; + + // + // Encapsulation attributes for value unmarshaling. + // + protected java.util.TreeMap<Integer, java.util.LinkedList<ReadValueCallback> > _patchMap; + private java.util.TreeMap<Integer, Ice.Object> _unmarshaledMap; + private java.util.TreeMap<Integer, String> _typeIdMap; + private int _typeIdIndex; + private java.util.List<Ice.Object> _valueList; + private java.util.HashMap<String, Class<?> > _typeIdCache; + } + + private static final class EncapsDecoder10 extends EncapsDecoder + { + EncapsDecoder10(InputStream stream, boolean sliceValues, ValueFactoryManager f, ClassResolver cr) + { + super(stream, sliceValues, f, cr); + _sliceType = SliceType.NoSlice; + } + + @Override + void readValue(ReadValueCallback cb) + { + assert(cb != null); + + // + // Object references are encoded as a negative integer in 1.0. + // + int index = _stream.readInt(); + if(index > 0) + { + throw new MarshalException("invalid object id"); + } + index = -index; + + if(index == 0) + { + cb.valueReady(null); + } + else + { + addPatchEntry(index, cb); + } + } + + @Override + void throwException(UserExceptionFactory factory) + throws UserException + { + assert(_sliceType == SliceType.NoSlice); + + // + // User exception with the 1.0 encoding start with a boolean flag + // that indicates whether or not the exception has classes. + // + // This allows reading the pending instances even if some part of + // the exception was sliced. + // + boolean usesClasses = _stream.readBool(); + + _sliceType = SliceType.ExceptionSlice; + _skipFirstSlice = false; + + // + // Read the first slice header. + // + startSlice(); + final String mostDerivedId = _typeId; + while(true) + { + UserException userEx = null; + + // + // Use a factory if one was provided. + // + if(factory != null) + { + try + { + factory.createAndThrow(_typeId); + } + catch(UserException ex) + { + userEx = ex; + } + } + + if(userEx == null) + { + userEx = _stream.createUserException(_typeId); + } + + // + // We found the exception. + // + if(userEx != null) + { + userEx.__read(_stream); + if(usesClasses) + { + readPendingValues(); + } + throw userEx; + + // Never reached. + } + + // + // Slice off what we don't understand. + // + skipSlice(); + try + { + startSlice(); + } + catch(UnmarshalOutOfBoundsException ex) + { + // + // An oversight in the 1.0 encoding means there is no marker to indicate + // the last slice of an exception. As a result, we just try to read the + // next type ID, which raises UnmarshalOutOfBoundsException when the + // input buffer underflows. + // + // Set the reason member to a more helpful message. + // + ex.reason = "unknown exception type `" + mostDerivedId + "'"; + throw ex; + } + } + } + + @Override + void startInstance(SliceType sliceType) + { + assert(_sliceType == sliceType); + _skipFirstSlice = true; + } + + @Override + SlicedData endInstance(boolean preserve) + { + // + // Read the Ice::Object slice. + // + if(_sliceType == SliceType.ValueSlice) + { + startSlice(); + int sz = _stream.readSize(); // For compatibility with the old AFM. + if(sz != 0) + { + throw new MarshalException("invalid Object slice"); + } + endSlice(); + } + + _sliceType = SliceType.NoSlice; + return null; + } + + @Override + String startSlice() + { + // + // If first slice, don't read the header, it was already read in + // readInstance or throwException to find the factory. + // + if(_skipFirstSlice) + { + _skipFirstSlice = false; + return _typeId; + } + + // + // For class instances, first read the type ID boolean which indicates + // whether or not the type ID is encoded as a string or as an + // index. For exceptions, the type ID is always encoded as a + // string. + // + if(_sliceType == SliceType.ValueSlice) // For exceptions, the type ID is always encoded as a string + { + boolean isIndex = _stream.readBool(); + _typeId = readTypeId(isIndex); + } + else + { + _typeId = _stream.readString(); + } + + _sliceSize = _stream.readInt(); + if(_sliceSize < 4) + { + throw new UnmarshalOutOfBoundsException(); + } + + return _typeId; + } + + @Override + void endSlice() + { + } + + @Override + void skipSlice() + { + _stream.traceSkipSlice(_typeId, _sliceType); + assert(_sliceSize >= 4); + _stream.skip(_sliceSize - 4); + } + + @Override + void readPendingValues() + { + int num; + do + { + num = _stream.readSize(); + for(int k = num; k > 0; --k) + { + readInstance(); + } + } + while(num > 0); + + if(_patchMap != null && !_patchMap.isEmpty()) + { + // + // If any entries remain in the patch map, the sender has sent an index for an object, but failed + // to supply the object. + // + throw new MarshalException("index for class received, but no instance"); + } + } + + private void readInstance() + { + int index = _stream.readInt(); + + if(index <= 0) + { + throw new MarshalException("invalid object id"); + } + + _sliceType = SliceType.ValueSlice; + _skipFirstSlice = false; + + // + // Read the first slice header. + // + startSlice(); + final String mostDerivedId = _typeId; + Ice.Object v = null; + while(true) + { + // + // For the 1.0 encoding, the type ID for the base Object class + // marks the last slice. + // + if(_typeId.equals(ObjectImpl.ice_staticId())) + { + throw new NoValueFactoryException("", mostDerivedId); + } + + v = newInstance(_typeId); + + // + // We found a factory, we get out of this loop. + // + if(v != null) + { + break; + } + + // + // If slicing is disabled, stop unmarshaling. + // + if(!_sliceValues) + { + throw new NoValueFactoryException("no value factory found and slicing is disabled", _typeId); + } + + // + // Slice off what we don't understand. + // + skipSlice(); + startSlice(); // Read next Slice header for next iteration. + } + + // + // Unmarshal the instance and add it to the map of unmarshaled instances. + // + unmarshal(index, v); + } + + // Value/exception attributes + private SliceType _sliceType; + private boolean _skipFirstSlice; + + // Slice attributes + private int _sliceSize; + private String _typeId; + } + + private static class EncapsDecoder11 extends EncapsDecoder + { + EncapsDecoder11(InputStream stream, boolean sliceValues, ValueFactoryManager f, ClassResolver cr, + CompactIdResolver r) + { + super(stream, sliceValues, f, cr); + _compactIdResolver = r; + _current = null; + _valueIdIndex = 1; + } + + @Override + void readValue(ReadValueCallback cb) + { + int index = _stream.readSize(); + if(index < 0) + { + throw new MarshalException("invalid object id"); + } + else if(index == 0) + { + if(cb != null) + { + cb.valueReady(null); + } + } + else if(_current != null && (_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0) + { + // + // When reading a class instance within a slice and there's an + // indirect instance table, always read an indirect reference + // that points to an instance from the indirect instance table + // marshaled at the end of the Slice. + // + // Maintain a list of indirect references. Note that the + // indirect index starts at 1, so we decrement it by one to + // derive an index into the indirection table that we'll read + // at the end of the slice. + // + if(cb != null) + { + if(_current.indirectPatchList == null) // Lazy initialization + { + _current.indirectPatchList = new java.util.ArrayDeque<IndirectPatchEntry>(); + } + IndirectPatchEntry e = new IndirectPatchEntry(); + e.index = index - 1; + e.cb = cb; + _current.indirectPatchList.push(e); + } + } + else + { + readInstance(index, cb); + } + } + + @Override + void throwException(UserExceptionFactory factory) + throws UserException + { + assert(_current == null); + + push(SliceType.ExceptionSlice); + + // + // Read the first slice header. + // + startSlice(); + final String mostDerivedId = _current.typeId; + while(true) + { + UserException userEx = null; + + // + // Use a factory if one was provided. + // + if(factory != null) + { + try + { + factory.createAndThrow(_current.typeId); + } + catch(UserException ex) + { + userEx = ex; + } + } + + if(userEx == null) + { + userEx = _stream.createUserException(_current.typeId); + } + + // + // We found the exception. + // + if(userEx != null) + { + userEx.__read(_stream); + throw userEx; + + // Never reached. + } + + // + // Slice off what we don't understand. + // + skipSlice(); + + if((_current.sliceFlags & IceInternal.Protocol.FLAG_IS_LAST_SLICE) != 0) + { + if(mostDerivedId.startsWith("::")) + { + throw new UnknownUserException(mostDerivedId.substring(2)); + } + else + { + throw new UnknownUserException(mostDerivedId); + } + } + + startSlice(); + } + } + + @Override + void startInstance(SliceType sliceType) + { + assert(_current.sliceType == sliceType); + _current.skipFirstSlice = true; + } + + @Override + SlicedData endInstance(boolean preserve) + { + SlicedData slicedData = null; + if(preserve) + { + slicedData = readSlicedData(); + } + if(_current.slices != null) + { + _current.slices.clear(); + _current.indirectionTables.clear(); + } + _current = _current.previous; + return slicedData; + } + + @Override + String startSlice() + { + // + // If first slice, don't read the header, it was already read in + // readInstance or throwException to find the factory. + // + if(_current.skipFirstSlice) + { + _current.skipFirstSlice = false; + return _current.typeId; + } + + _current.sliceFlags = _stream.readByte(); + + // + // Read the type ID, for value slices the type ID is encoded as a + // string or as an index, for exceptions it's always encoded as a + // string. + // + if(_current.sliceType == SliceType.ValueSlice) + { + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_TYPE_ID_COMPACT) == + IceInternal.Protocol.FLAG_HAS_TYPE_ID_COMPACT) // Must be checked 1st! + { + _current.typeId = ""; + _current.compactId = _stream.readSize(); + } + else if((_current.sliceFlags & (IceInternal.Protocol.FLAG_HAS_TYPE_ID_INDEX | + IceInternal.Protocol.FLAG_HAS_TYPE_ID_STRING)) != 0) + { + _current.typeId = + readTypeId((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_TYPE_ID_INDEX) != 0); + _current.compactId = -1; + } + else + { + // + // Only the most derived slice encodes the type ID for the compact format. + // + _current.typeId = ""; + _current.compactId = -1; + } + } + else + { + _current.typeId = _stream.readString(); + _current.compactId = -1; + } + + // + // Read the slice size if necessary. + // + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_SLICE_SIZE) != 0) + { + _current.sliceSize = _stream.readInt(); + if(_current.sliceSize < 4) + { + throw new UnmarshalOutOfBoundsException(); + } + } + else + { + _current.sliceSize = 0; + } + + return _current.typeId; + } + + @Override + void endSlice() + { + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0) + { + _stream.skipOptionals(); + } + + // + // Read the indirection table if one is present and transform the + // indirect patch list into patch entries with direct references. + // + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0) + { + // + // The table is written as a sequence<size> to conserve space. + // + int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)]; + for(int i = 0; i < indirectionTable.length; ++i) + { + indirectionTable[i] = readInstance(_stream.readSize(), null); + } + + // + // Sanity checks. If there are optional members, it's possible + // that not all instance references were read if they are from + // unknown optional data members. + // + if(indirectionTable.length == 0) + { + throw new MarshalException("empty indirection table"); + } + if((_current.indirectPatchList == null || _current.indirectPatchList.isEmpty()) && + (_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS) == 0) + { + throw new MarshalException("no references to indirection table"); + } + + // + // Convert indirect references into direct references. + // + if(_current.indirectPatchList != null) + { + for(IndirectPatchEntry e : _current.indirectPatchList) + { + assert(e.index >= 0); + if(e.index >= indirectionTable.length) + { + throw new MarshalException("indirection out of range"); + } + addPatchEntry(indirectionTable[e.index], e.cb); + } + _current.indirectPatchList.clear(); + } + } + } + + @Override + void skipSlice() + { + _stream.traceSkipSlice(_current.typeId, _current.sliceType); + + int start = _stream.pos(); + + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_SLICE_SIZE) != 0) + { + assert(_current.sliceSize >= 4); + _stream.skip(_current.sliceSize - 4); + } + else + { + if(_current.sliceType == SliceType.ValueSlice) + { + throw new NoValueFactoryException("no value factory found and compact format prevents " + + "slicing (the sender should use the sliced format instead)", + _current.typeId); + } + else + { + if(_current.typeId.startsWith("::")) + { + throw new UnknownUserException(_current.typeId.substring(2)); + } + else + { + throw new UnknownUserException(_current.typeId); + } + } + } + + // + // Preserve this slice. + // + SliceInfo info = new SliceInfo(); + info.typeId = _current.typeId; + info.compactId = _current.compactId; + info.hasOptionalMembers = (_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0; + info.isLastSlice = (_current.sliceFlags & IceInternal.Protocol.FLAG_IS_LAST_SLICE) != 0; + java.nio.ByteBuffer b = _stream.getBuffer().b; + final int end = b.position(); + int dataEnd = end; + if(info.hasOptionalMembers) + { + // + // Don't include the optional member end marker. It will be re-written by + // endSlice when the sliced data is re-written. + // + --dataEnd; + } + info.bytes = new byte[dataEnd - start]; + b.position(start); + b.get(info.bytes); + b.position(end); + + if(_current.slices == null) // Lazy initialization + { + _current.slices = new java.util.ArrayList<SliceInfo>(); + _current.indirectionTables = new java.util.ArrayList<int[]>(); + } + + // + // Read the indirect instance table. We read the instances or their + // IDs if the instance is a reference to an already unmarhsaled + // instance. + // + // The SliceInfo object sequence is initialized only if + // readSlicedData is called. + // + + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_INDIRECTION_TABLE) != 0) + { + int[] indirectionTable = new int[_stream.readAndCheckSeqSize(1)]; + for(int i = 0; i < indirectionTable.length; ++i) + { + indirectionTable[i] = readInstance(_stream.readSize(), null); + } + _current.indirectionTables.add(indirectionTable); + } + else + { + _current.indirectionTables.add(null); + } + + _current.slices.add(info); + } + + @Override + boolean readOptional(int readTag, OptionalFormat expectedFormat) + { + if(_current == null) + { + return _stream.readOptImpl(readTag, expectedFormat); + } + else if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0) + { + return _stream.readOptImpl(readTag, expectedFormat); + } + return false; + } + + private int readInstance(int index, ReadValueCallback cb) + { + assert(index > 0); + + if(index > 1) + { + if(cb != null) + { + addPatchEntry(index, cb); + } + return index; + } + + push(SliceType.ValueSlice); + + // + // Get the instance ID before we start reading slices. If some + // slices are skipped, the indirect instance table is still read and + // might read other instances. + // + index = ++_valueIdIndex; + + // + // Read the first slice header. + // + startSlice(); + final String mostDerivedId = _current.typeId; + Ice.Object v = null; + while(true) + { + boolean updateCache = false; + + if(_current.compactId >= 0) + { + updateCache = true; + + // + // Translate a compact (numeric) type ID into a class. + // + if(_compactIdCache == null) + { + _compactIdCache = new java.util.TreeMap<Integer, Class<?> >(); // Lazy initialization. + } + else + { + // + // Check the cache to see if we've already translated the compact type ID into a class. + // + Class<?> cls = _compactIdCache.get(_current.compactId); + if(cls != null) + { + try + { + v = (Ice.Object)cls.newInstance(); + updateCache = false; + } + catch(java.lang.Exception ex) + { + throw new NoValueFactoryException("no value factory", "compact ID " + + _current.compactId, ex); + } + } + } + + // + // If we haven't already cached a class for the compact ID, then try to translate the + // compact ID into a type ID. + // + if(v == null) + { + _current.typeId = ""; + if(_compactIdResolver != null) + { + try + { + _current.typeId = _compactIdResolver.resolve(_current.compactId); + } + catch(Ice.LocalException ex) + { + throw ex; + } + catch(Throwable ex) + { + throw new Ice.MarshalException("exception in CompactIdResolver for ID " + + _current.compactId, ex); + } + } + + if(_current.typeId.isEmpty()) + { + _current.typeId = _stream.instance().resolveCompactId(_current.compactId); + } + } + } + + if(v == null && !_current.typeId.isEmpty()) + { + v = newInstance(_current.typeId); + } + + if(v != null) + { + if(updateCache) + { + assert(_current.compactId >= 0); + _compactIdCache.put(_current.compactId, v.getClass()); + } + + // + // We have an instance, get out of this loop. + // + break; + } + + // + // If slicing is disabled, stop unmarshaling. + // + if(!_sliceValues) + { + throw new NoValueFactoryException("no value factory found and slicing is disabled", + _current.typeId); + } + + // + // Slice off what we don't understand. + // + skipSlice(); + + // + // If this is the last slice, keep the instance as an opaque + // UnknownSlicedValue object. + // + if((_current.sliceFlags & IceInternal.Protocol.FLAG_IS_LAST_SLICE) != 0) + { + // + // Provide a factory with an opportunity to supply the instance. + // We pass the "::Ice::Object" ID to indicate that this is the + // last chance to preserve the instance. + // + v = newInstance(ObjectImpl.ice_staticId()); + if(v == null) + { + v = new UnknownSlicedValue(mostDerivedId); + } + + break; + } + + startSlice(); // Read next Slice header for next iteration. + } + + // + // Unmarshal the instance. + // + unmarshal(index, v); + + if(_current == null && _patchMap != null && !_patchMap.isEmpty()) + { + // + // If any entries remain in the patch map, the sender has sent an index for an instance, but failed + // to supply the instance. + // + throw new MarshalException("index for class received, but no instance"); + } + + if(cb != null) + { + cb.valueReady(v); + } + + return index; + } + + private SlicedData readSlicedData() + { + if(_current.slices == null) // No preserved slices. + { + return null; + } + + // + // The _indirectionTables member holds the indirection table for each slice + // in _slices. + // + assert(_current.slices.size() == _current.indirectionTables.size()); + for(int n = 0; n < _current.slices.size(); ++n) + { + // + // We use the "instances" list in SliceInfo to hold references + // to the target instances. Note that the instances might not have + // been read yet in the case of a circular reference to an + // enclosing instance. + // + final int[] table = _current.indirectionTables.get(n); + SliceInfo info = _current.slices.get(n); + info.instances = new Ice.Object[table != null ? table.length : 0]; + for(int j = 0; j < info.instances.length; ++j) + { + addPatchEntry(table[j], new IceInternal.SequencePatcher(info.instances, Ice.Object.class, j)); + } + } + + SliceInfo[] arr = new SliceInfo[_current.slices.size()]; + _current.slices.toArray(arr); + return new SlicedData(arr); + } + + private void push(SliceType sliceType) + { + if(_current == null) + { + _current = new InstanceData(null); + } + else + { + _current = _current.next == null ? new InstanceData(_current) : _current.next; + } + _current.sliceType = sliceType; + _current.skipFirstSlice = false; + } + + private static final class IndirectPatchEntry + { + int index; + ReadValueCallback cb; + } + + private static final class InstanceData + { + InstanceData(InstanceData previous) + { + if(previous != null) + { + previous.next = this; + } + this.previous = previous; + this.next = null; + } + + // Instance attributes + SliceType sliceType; + boolean skipFirstSlice; + java.util.List<SliceInfo> slices; // Preserved slices. + java.util.List<int[]> indirectionTables; + + // Slice attributes + byte sliceFlags; + int sliceSize; + String typeId; + int compactId; + java.util.Deque<IndirectPatchEntry> indirectPatchList; + + final InstanceData previous; + InstanceData next; + } + + private CompactIdResolver _compactIdResolver; + private InstanceData _current; + private int _valueIdIndex; // The ID of the next instance to unmarshal. + private java.util.TreeMap<Integer, Class<?> > _compactIdCache; // Cache of compact type IDs. + } + + private static final class Encaps + { + void reset() + { + decoder = null; + } + + void setEncoding(EncodingVersion encoding) + { + this.encoding = encoding; + encoding_1_0 = encoding.equals(Util.Encoding_1_0); + } + + int start; + int sz; + EncodingVersion encoding; + boolean encoding_1_0; + + EncapsDecoder decoder; + + Encaps next; + } + + // + // The encoding version to use when there's no encapsulation to + // read from. This is for example used to read message headers. + // + private EncodingVersion _encoding; + + private boolean isEncoding_1_0() + { + return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.equals(Util.Encoding_1_0); + } + + private Encaps _encapsStack; + private Encaps _encapsCache; + + private void initEncaps() + { + if(_encapsStack == null) // Lazy initialization + { + _encapsStack = _encapsCache; + if(_encapsStack != null) + { + _encapsCache = _encapsCache.next; + } + else + { + _encapsStack = new Encaps(); + } + _encapsStack.setEncoding(_encoding); + _encapsStack.sz = _buf.b.limit(); + } + + if(_encapsStack.decoder == null) // Lazy initialization. + { + if(_encapsStack.encoding_1_0) + { + _encapsStack.decoder = new EncapsDecoder10(this, _sliceValues, _valueFactoryManager, _classResolver); + } + else + { + _encapsStack.decoder = new EncapsDecoder11(this, _sliceValues, _valueFactoryManager, _classResolver, + _compactIdResolver); + } + } + } + + private void traceSkipSlice(String typeId, SliceType sliceType) + { + if(_traceSlicing && _logger != null) + { + IceInternal.TraceUtil.traceSlicing(sliceType == SliceType.ExceptionSlice ? "exception" : "object", typeId, + "Slicing", _logger); + } + } + + private boolean _sliceValues; + private boolean _traceSlicing; + + private int _startSeq; + private int _minSeqSize; + + private ValueFactoryManager _valueFactoryManager; + private Logger _logger; + private CompactIdResolver _compactIdResolver; + private ClassResolver _classResolver; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/IntHolder.java b/java-compat/src/Ice/src/main/java/Ice/IntHolder.java new file mode 100644 index 00000000000..c79285985d6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/IntHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for integers that are out- or inout-parameters. + **/ +public final class IntHolder extends Holder<Integer> +{ + /** + * Instantiates the class with the value zero. + **/ + public + IntHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * The <code>int</code> value for this holder. + **/ + public + IntHolder(int value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/IntOptional.java b/java-compat/src/Ice/src/main/java/Ice/IntOptional.java new file mode 100644 index 00000000000..825ae76b1d7 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/IntOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional int parameter. + **/ +public class IntOptional +{ + /** + * The value defaults to unset. + **/ + public IntOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public IntOptional(int v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public IntOptional(IntOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public int get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(int v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(IntOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = 0; + } + + private int _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/LocalException.java b/java-compat/src/Ice/src/main/java/Ice/LocalException.java new file mode 100644 index 00000000000..2052b64a0c7 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/LocalException.java @@ -0,0 +1,25 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for all Ice run-time exceptions. + **/ +public abstract class LocalException extends Exception +{ + public LocalException() + { + } + + public LocalException(Throwable cause) + { + super(cause); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/LocalObjectHolder.java b/java-compat/src/Ice/src/main/java/Ice/LocalObjectHolder.java new file mode 100644 index 00000000000..704aa31b234 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/LocalObjectHolder.java @@ -0,0 +1,33 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for local objects that are out- or inout-parameters. + **/ +public final class LocalObjectHolder extends Holder<java.lang.Object> +{ + /** + * Instantiates the class with a <code>null</code> value. + **/ + public + LocalObjectHolder() + { + } + + /** + * Instantiates the class with the passed local object. + **/ + public + LocalObjectHolder(java.lang.Object value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/LoggerI.java b/java-compat/src/Ice/src/main/java/Ice/LoggerI.java new file mode 100644 index 00000000000..a1108e6df55 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/LoggerI.java @@ -0,0 +1,163 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public class LoggerI implements Logger +{ + public + LoggerI(String prefix, String file) + { + _prefix = prefix; + + if(prefix.length() > 0) + { + _formattedPrefix = prefix + ": "; + } + + _lineSeparator = System.getProperty("line.separator"); + _date = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); + _time = new java.text.SimpleDateFormat(" HH:mm:ss:SSS"); + + if(file.length() != 0) + { + _file = file; + try + { + _out = new java.io.FileOutputStream(new java.io.File(_file), true); + } + catch(java.io.FileNotFoundException ex) + { + throw new InitializationException("FileLogger: cannot open " + _file); + } + } + } + + @Override + public void + print(String message) + { + StringBuilder s = new StringBuilder(256); + s.append(message); + write(s, false); + } + + @Override + public void + trace(String category, String message) + { + StringBuilder s = new StringBuilder(256); + s.append("-- "); + synchronized(this) + { + java.util.Date date = new java.util.Date(); + s.append(_date.format(date)); + s.append(_time.format(date)); + } + s.append(' '); + s.append(_formattedPrefix); + s.append(category); + s.append(": "); + s.append(message); + write(s, true); + } + + @Override + public void + warning(String message) + { + StringBuilder s = new StringBuilder(256); + s.append("-! "); + synchronized(this) + { + s.append(_date.format(new java.util.Date())); + s.append(_time.format(new java.util.Date())); + } + s.append(' '); + s.append(_formattedPrefix); + s.append("warning: "); + s.append(Thread.currentThread().getName()); + s.append(": "); + s.append(message); + write(s, true); + } + + @Override + public void + error(String message) + { + StringBuilder s = new StringBuilder(256); + s.append("!! "); + synchronized(this) + { + s.append(_date.format(new java.util.Date())); + s.append(_time.format(new java.util.Date())); + } + s.append(' '); + s.append(_formattedPrefix); + s.append("error: "); + s.append(Thread.currentThread().getName()); + s.append(": "); + s.append(message); + write(s, true); + } + + + @Override + public String + getPrefix() + { + return _prefix; + } + + @Override + public Logger + cloneWithPrefix(String prefix) + { + return new LoggerI(prefix, _file); + } + + private void + write(StringBuilder message, boolean indent) + { + if(indent) + { + int idx = 0; + while((idx = message.indexOf("\n", idx)) != -1) + { + message.insert(idx + 1, " "); + ++idx; + } + } + message.append(_lineSeparator); + + if(_out == null) + { + System.err.print(message.toString()); + } + else + { + try + { + _out.write(message.toString().getBytes()); + } + catch(java.io.IOException ex) + { + } + } + } + + String _prefix = ""; + String _formattedPrefix = ""; + String _file = ""; + String _lineSeparator; + java.text.DateFormat _date; + java.text.SimpleDateFormat _time; + java.io.FileOutputStream _out = null; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/LoggerPlugin.java b/java-compat/src/Ice/src/main/java/Ice/LoggerPlugin.java new file mode 100644 index 00000000000..90af9141202 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/LoggerPlugin.java @@ -0,0 +1,70 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Class to support custom loggers. Applications using a custom logger + * instantiate a <code>LoggerPlugin</code> with a custom logger and + * return the instance from their {@link PluginFactory} implementation. + * + * @see PluginFactory + * @see Plugin + **/ +public class LoggerPlugin implements Ice.Plugin +{ + /** + * Installs a custom logger for a communicator. + * + * @param communicator The communicator using the custom logger. + * @param logger The custom logger for the communicator. + **/ + public + LoggerPlugin(Communicator communicator, Logger logger) + { + if(communicator == null) + { + PluginInitializationException ex = new PluginInitializationException(); + ex.reason = "Communicator cannot be null"; + throw ex; + } + + if(logger == null) + { + PluginInitializationException ex = new PluginInitializationException(); + ex.reason = "Logger cannot be null"; + throw ex; + } + + IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + instance.setLogger(logger); + } + + /** + * Called by the Ice run time during communicator initialization. The derived class + * can override this method to perform any initialization that might be required + * by a custom logger. + **/ + @Override + public void + initialize() + { + } + + /** + * Called by the Ice run time when the communicator is destroyed. The derived class + * can override this method to perform any finalization that might be required + * by a custom logger. + **/ + @Override + public void + destroy() + { + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/LongHolder.java b/java-compat/src/Ice/src/main/java/Ice/LongHolder.java new file mode 100644 index 00000000000..6027d071be6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/LongHolder.java @@ -0,0 +1,33 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for longs that are out- or inout-parameters. + **/ +public final class LongHolder extends Holder<Long> +{ + /** + * Instantiates the class with the value zero. + **/ + public + LongHolder() + { + } + + /** + * Instantiates the class with the passed value. + **/ + public + LongHolder(long value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/LongOptional.java b/java-compat/src/Ice/src/main/java/Ice/LongOptional.java new file mode 100644 index 00000000000..e7301ae8dc6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/LongOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional long parameter. + **/ +public class LongOptional +{ + /** + * The value defaults to unset. + **/ + public LongOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public LongOptional(long v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public LongOptional(LongOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public long get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(long v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(LongOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = 0; + } + + private long _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/NativePropertiesAdmin.java b/java-compat/src/Ice/src/main/java/Ice/NativePropertiesAdmin.java new file mode 100644 index 00000000000..1e5df346592 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/NativePropertiesAdmin.java @@ -0,0 +1,16 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface NativePropertiesAdmin +{ + void addUpdateCallback(PropertiesAdminUpdateCallback callback); + void removeUpdateCallback(PropertiesAdminUpdateCallback callback); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Object.java b/java-compat/src/Ice/src/main/java/Ice/Object.java new file mode 100644 index 00000000000..e83fc29756f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Object.java @@ -0,0 +1,162 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * The base interface for servants. + **/ +public interface Object +{ + /** + * Returns a copy of the object. The cloned object contains field-for-field copies + * of the state. + * + * @return The cloned object. + **/ + Object clone() throws java.lang.CloneNotSupportedException; + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param s The type ID of the Slice interface to test against. + * @return <code>true</code> if this object has the interface + * specified by <code>s</code> or derives from the interface + * specified by <code>s</code>. + **/ + boolean ice_isA(String s); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param s The type ID of the Slice interface to test against. + * @param current The {@link Current} object for the invocation. + * @return <code>true</code> if this object has the interface + * specified by <code>s</code> or derives from the interface + * specified by <code>s</code>. + **/ + boolean ice_isA(String s, Current current); + + /** + * Tests whether this object can be reached. + **/ + void ice_ping(); + + /** + * Tests whether this object can be reached. + * + * @param current The {@link Current} object for the invocation. + **/ + void ice_ping(Current current); + + /** + * Returns the Slice type IDs of the interfaces supported by this object. + * + * @return The Slice type IDs of the interfaces supported by this object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + String[] ice_ids(); + + /** + * Returns the Slice type IDs of the interfaces supported by this object. + * + * @param current The {@link Current} object for the invocation. + * @return The Slice type IDs of the interfaces supported by this object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + String[] ice_ids(Current current); + + /** + * Returns the Slice type ID of the most-derived interface supported by this object. + * + * @return The Slice type ID of the most-derived interface. + **/ + String ice_id(); + + /** + * Returns the Slice type ID of the most-derived interface supported by this object. + * + * @param current The {@link Current} object for the invocation. + * @return The Slice type ID of the most-derived interface. + **/ + String ice_id(Current current); + + /** + * Returns the Freeze metadata attributes for an operation. + * + * @param operation The name of the operation. + * @return The least significant bit indicates whether the operation is a read + * or write operation. If the bit is set, the operation is a write operation. + * The expression <code>ice_operationAttributes("op") & 0x1</code> is true if + * the operation has a <code>["freeze:write"]</code> metadata directive. + * <p> + * The second- and third least significant bit indicate the transactional mode + * of the operation. The expression <code>ice_operationAttributes("op") & 0x6 >> 1</code> + * indicates the transactional mode as follows: + * <dl> + * <dt>0</dt> + * <dd><code>["freeze:read:supports"]</code></dd> + * <dt>1</dt> + * <dd><code>["freeze:read:mandatory"]</code> or <code>["freeze:write:mandatory"]</code></dd> + * <dt>2</dt> + * <dd><code>["freeze:read:required"]</code> or <code>["freeze:write:required"]</code></dd> + * <dt>3</dt> + * <dd><code>["freeze:read:never"]</code></dd> + * </dl> + * + * Refer to the Freeze manual for more information on the TransactionalEvictor. + **/ + int ice_operationAttributes(String operation); + + /** + * The Ice run time invokes this method prior to marshaling an object's data members. This allows a subclass + * to override this method in order to validate its data members. + **/ + void ice_preMarshal(); + + /** + * The Ice run time invokes this method vafter unmarshaling an object's data members. This allows a + * subclass to override this method in order to perform additional initialization. + **/ + void ice_postUnmarshal(); + + /** + * Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation + * to a servant (or to another interceptor). + * + * @param request The details of the invocation. + * @param cb The callback object for asynchronous dispatch. For synchronous dispatch, the callback object + * must be <code>null</code>. + * @return The dispatch status for the operation. + * + * @see DispatchInterceptor + * @see DispatchInterceptorAsyncCallback + * @see DispatchStatus + **/ + DispatchStatus ice_dispatch(Request request, DispatchInterceptorAsyncCallback cb); + + /** + * Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation + * to a servant (or to another interceptor). + * + * @param request The details of the invocation. + * @return The dispatch status for the operation. + * + * @see DispatchInterceptor + * @see DispatchStatus + **/ + DispatchStatus ice_dispatch(Request request); + + DispatchStatus __dispatch(IceInternal.Incoming in, Current current); + + void __write(OutputStream __os); + void __read(InputStream __is); + + public static final String ice_staticId = "::Ice::Object"; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java b/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java new file mode 100644 index 00000000000..1aeef2206fa --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectAdapterI.java @@ -0,0 +1,1559 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +import java.util.Map; +import java.util.List; +import java.util.ArrayList; + +import IceInternal.IncomingConnectionFactory; + +public final class ObjectAdapterI implements ObjectAdapter +{ + @Override + public String + getName() + { + // + // No mutex lock necessary, _name is immutable. + // + return _noConfig ? "" : _name; + } + + @Override + public Communicator + getCommunicator() + { + return _communicator; + } + + @Override + public void + activate() + { + IceInternal.LocatorInfo locatorInfo = null; + boolean printAdapterReady = false; + + synchronized(this) + { + checkForDeactivation(); + + // + // If we've previously been initialized we just need to activate the + // incoming connection factories and we're done. + // + if(_state != StateUninitialized) + { + for(IncomingConnectionFactory factory : _incomingConnectionFactories) + { + factory.activate(); + } + return; + } + + // + // One off initializations of the adapter: update the + // locator registry and print the "adapter ready" + // message. We set set state to StateActivating to prevent + // deactivation from other threads while these one off + // initializations are done. + // + _state = StateActivating; + + locatorInfo = _locatorInfo; + if(!_noConfig) + { + final Properties properties = _instance.initializationData().properties; + printAdapterReady = properties.getPropertyAsInt("Ice.PrintAdapterReady") > 0; + } + } + + try + { + Ice.Identity dummy = new Ice.Identity(); + dummy.name = "dummy"; + updateLocatorRegistry(locatorInfo, createDirectProxy(dummy)); + } + catch(Ice.LocalException ex) + { + // + // If we couldn't update the locator registry, we let the + // exception go through and don't activate the adapter to + // allow to user code to retry activating the adapter + // later. + // + synchronized(this) + { + _state = StateUninitialized; + notifyAll(); + } + throw ex; + } + + if(printAdapterReady) + { + System.out.println(_name + " ready"); + } + + synchronized(this) + { + assert(_state == StateActivating); + + // + // Signal threads waiting for the activation. + // + _state = StateActive; + notifyAll(); + + for(IncomingConnectionFactory factory : _incomingConnectionFactories) + { + factory.activate(); + } + } + } + + @Override + public synchronized void + hold() + { + checkForDeactivation(); + _state = StateHeld; + for(IncomingConnectionFactory factory : _incomingConnectionFactories) + { + factory.hold(); + } + } + + @Override + public void + waitForHold() + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + List<IncomingConnectionFactory> incomingConnectionFactories; + synchronized(this) + { + checkForDeactivation(); + incomingConnectionFactories = new ArrayList<IncomingConnectionFactory>(_incomingConnectionFactories); + } + + for(IncomingConnectionFactory factory : incomingConnectionFactories) + { + try + { + factory.waitUntilHolding(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + } + + + @Override + public void + deactivate() + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + synchronized(this) + { + // + // Wait for activation to complete. This is necessary to + // not get out of order locator updates. + // + while(_state == StateActivating) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + if(_state > StateDeactivating) + { + return; + } + _state = StateDeactivating; + } + + // + // NOTE: the router/locator infos and incoming connection + // facatory list are immutable at this point. + // + + if(_routerInfo != null) + { + // + // Remove entry from the router manager. + // + _instance.routerManager().erase(_routerInfo.getRouter()); + + // + // Clear this object adapter with the router. + // + _routerInfo.setAdapter(null); + } + + try + { + updateLocatorRegistry(_locatorInfo, null); + } + catch(Ice.LocalException ex) + { + // + // We can't throw exceptions in deactivate so we ignore + // failures to update the locator registry. + // + } + + // + // Must be called outside the thread synchronization, because + // Connection::destroy() might block when sending a + // CloseConnection message. + // + for(IncomingConnectionFactory factory : _incomingConnectionFactories) + { + factory.destroy(); + } + + // + // Must be called outside the thread synchronization, because + // changing the object adapter might block if there are still + // requests being dispatched. + // + _instance.outgoingConnectionFactory().removeAdapter(this); + + synchronized(this) + { + _state = StateDeactivated; + notifyAll(); + } + } + + @Override + public void + waitForDeactivate() + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + try + { + List<IncomingConnectionFactory> incomingConnectionFactories; + synchronized(this) + { + // + // Wait for deactivation of the adapter itself, and + // for the return of all direct method calls using + // this adapter. + // + while((_state < StateDeactivated) || _directCount > 0) + { + wait(); + } + if(_state > StateDeactivated) + { + return; + } + incomingConnectionFactories = new ArrayList<IncomingConnectionFactory>(_incomingConnectionFactories); + } + + // + // Now we wait for until all incoming connection factories are + // finished (the incoming connection factory list is immutable + // at this point). + // + for(IncomingConnectionFactory f : incomingConnectionFactories) + { + f.waitUntilFinished(); + } + } + catch(InterruptedException e) + { + throw new Ice.OperationInterruptedException(); + } + } + + @Override + public synchronized boolean + isDeactivated() + { + return _state >= StateDeactivated; + } + + @Override + public void + destroy() + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + // + // Deactivate and wait for completion. + // + deactivate(); + waitForDeactivate(); + + synchronized(this) + { + assert(_state >= StateDeactivated); + + // + // Only a single thread is allowed to destroy the object + // adapter. Other threads wait for the destruction to be + // completed. + // + while(_state == StateDestroying) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + if(_state == StateDestroyed) + { + return; + } + + _state = StateDestroying; + } + + // + // Now it's also time to clean up our servants and servant + // locators. + // + _servantManager.destroy(); + + // + // Destroy the thread pool. + // + if(_threadPool != null) + { + _threadPool.destroy(); + try + { + _threadPool.joinWithAllThreads(); + } + catch (InterruptedException e) + { + throw new Ice.OperationInterruptedException(); + } + } + + _objectAdapterFactory.removeObjectAdapter(this); + + synchronized(this) + { + _incomingConnectionFactories.clear(); + + // + // Remove object references (some of them cyclic). + // + _instance = null; + _threadPool = null; + _routerEndpoints = null; + _routerInfo = null; + _publishedEndpoints = null; + _locatorInfo = null; + _reference = null; + _objectAdapterFactory = null; + + // + // Signal that destroying is complete. + // + _state = StateDestroyed; + notifyAll(); + } + } + + @Override + public ObjectPrx + add(Ice.Object object, Identity ident) + { + return addFacet(object, ident, ""); + } + + @Override + public synchronized ObjectPrx + addFacet(Ice.Object object, Identity ident, String facet) + { + checkForDeactivation(); + checkIdentity(ident); + checkServant(object); + + // + // Create a copy of the Identity argument, in case the caller + // reuses it. + // + Identity id = new Identity(); + id.category = ident.category; + id.name = ident.name; + + _servantManager.addServant(object, id, facet); + + return newProxy(id, facet); + } + + @Override + public ObjectPrx + addWithUUID(Ice.Object object) + { + return addFacetWithUUID(object, ""); + } + + @Override + public ObjectPrx + addFacetWithUUID(Ice.Object object, String facet) + { + Identity ident = new Identity(); + ident.category = ""; + ident.name = java.util.UUID.randomUUID().toString(); + + return addFacet(object, ident, facet); + } + + @Override + public synchronized void + addDefaultServant(Ice.Object servant, String category) + { + checkServant(servant); + checkForDeactivation(); + + _servantManager.addDefaultServant(servant, category); + } + + @Override + public Ice.Object + remove(Identity ident) + { + return removeFacet(ident, ""); + } + + @Override + public synchronized Ice.Object + removeFacet(Identity ident, String facet) + { + checkForDeactivation(); + checkIdentity(ident); + + return _servantManager.removeServant(ident, facet); + } + + @Override + public synchronized Map<String, Object> + removeAllFacets(Identity ident) + { + checkForDeactivation(); + checkIdentity(ident); + + return _servantManager.removeAllFacets(ident); + } + + @Override + public synchronized Ice.Object + removeDefaultServant(String category) + { + checkForDeactivation(); + + return _servantManager.removeDefaultServant(category); + } + + @Override + public Ice.Object + find(Identity ident) + { + return findFacet(ident, ""); + } + + @Override + public synchronized Ice.Object + findFacet(Identity ident, String facet) + { + checkForDeactivation(); + checkIdentity(ident); + + return _servantManager.findServant(ident, facet); + } + + @Override + public synchronized java.util.Map<String, Ice.Object> + findAllFacets(Identity ident) + { + checkForDeactivation(); + checkIdentity(ident); + + return _servantManager.findAllFacets(ident); + } + + @Override + public synchronized Ice.Object + findByProxy(ObjectPrx proxy) + { + checkForDeactivation(); + + IceInternal.Reference ref = ((ObjectPrxHelperBase)proxy).__reference(); + return findFacet(ref.getIdentity(), ref.getFacet()); + } + + @Override + public synchronized Ice.Object + findDefaultServant(String category) + { + checkForDeactivation(); + + return _servantManager.findDefaultServant(category); + } + + @Override + public synchronized void + addServantLocator(ServantLocator locator, String prefix) + { + checkForDeactivation(); + + _servantManager.addServantLocator(locator, prefix); + } + + @Override + public synchronized ServantLocator + removeServantLocator(String prefix) + { + checkForDeactivation(); + + return _servantManager.removeServantLocator(prefix); + } + + @Override + public synchronized ServantLocator + findServantLocator(String prefix) + { + checkForDeactivation(); + + return _servantManager.findServantLocator(prefix); + } + + @Override + public synchronized ObjectPrx + createProxy(Identity ident) + { + checkForDeactivation(); + checkIdentity(ident); + + return newProxy(ident, ""); + } + + @Override + public synchronized ObjectPrx + createDirectProxy(Identity ident) + { + checkForDeactivation(); + checkIdentity(ident); + + return newDirectProxy(ident, ""); + } + + @Override + public synchronized ObjectPrx + createIndirectProxy(Identity ident) + { + checkForDeactivation(); + checkIdentity(ident); + + return newIndirectProxy(ident, "", _id); + } + + @Override + public synchronized void + setLocator(LocatorPrx locator) + { + checkForDeactivation(); + + _locatorInfo = _instance.locatorManager().get(locator); + } + + @Override + public synchronized LocatorPrx + getLocator() + { + if(_locatorInfo == null) + { + return null; + } + else + { + return _locatorInfo.getLocator(); + } + } + + @Override + public void + refreshPublishedEndpoints() + { + IceInternal.LocatorInfo locatorInfo = null; + List<IceInternal.EndpointI> oldPublishedEndpoints; + + synchronized(this) + { + checkForDeactivation(); + + oldPublishedEndpoints = _publishedEndpoints; + _publishedEndpoints = parsePublishedEndpoints(); + + locatorInfo = _locatorInfo; + } + + try + { + Ice.Identity dummy = new Ice.Identity(); + dummy.name = "dummy"; + updateLocatorRegistry(locatorInfo, createDirectProxy(dummy)); + } + catch(Ice.LocalException ex) + { + synchronized(this) + { + // + // Restore the old published endpoints. + // + _publishedEndpoints = oldPublishedEndpoints; + throw ex; + } + } + } + + @Override + public synchronized Endpoint[] + getEndpoints() + { + List<Endpoint> endpoints = new ArrayList<Endpoint>(); + for(IncomingConnectionFactory factory : _incomingConnectionFactories) + { + endpoints.add(factory.endpoint()); + } + return endpoints.toArray(new Endpoint[0]); + } + + @Override + public synchronized Endpoint[] + getPublishedEndpoints() + { + return _publishedEndpoints.toArray(new Endpoint[0]); + } + + public boolean + isLocal(ObjectPrx proxy) + { + // + // NOTE: it's important that isLocal() doesn't perform any blocking operations as + // it can be called for AMI invocations if the proxy has no delegate set yet. + // + + IceInternal.Reference ref = ((ObjectPrxHelperBase)proxy).__reference(); + if(ref.isWellKnown()) + { + // + // Check the active servant map to see if the well-known + // proxy is for a local object. + // + return _servantManager.hasServant(ref.getIdentity()); + } + else if(ref.isIndirect()) + { + // + // Proxy is local if the reference adapter id matches this + // adapter id or replica group id. + // + return ref.getAdapterId().equals(_id) || ref.getAdapterId().equals(_replicaGroupId); + } + else + { + IceInternal.EndpointI[] endpoints = ref.getEndpoints(); + + synchronized(this) + { + checkForDeactivation(); + + // + // Proxies which have at least one endpoint in common with the + // endpoints used by this object adapter's incoming connection + // factories are considered local. + // + for(IceInternal.EndpointI endpoint : endpoints) + { + for(IceInternal.EndpointI p : _publishedEndpoints) + { + if(endpoint.equivalent(p)) + { + return true; + } + } + for(IncomingConnectionFactory p : _incomingConnectionFactories) + { + if(endpoint.equivalent(p.endpoint())) + { + return true; + } + } + } + + // + // Proxies which have at least one endpoint in common with the + // router's server proxy endpoints (if any), are also considered + // local. + // + if(_routerInfo != null && _routerInfo.getRouter().equals(proxy.ice_getRouter())) + { + for(IceInternal.EndpointI endpoint : endpoints) + { + for(IceInternal.EndpointI p : _routerEndpoints) + { + if(endpoint.equivalent(p)) + { + return true; + } + } + } + } + } + } + + return false; + } + + public void + flushAsyncBatchRequests(IceInternal.CommunicatorFlushBatch outAsync) + { + List<IncomingConnectionFactory> f; + synchronized(this) + { + f = new ArrayList<IncomingConnectionFactory>(_incomingConnectionFactories); + } + for(IncomingConnectionFactory p : f) + { + p.flushAsyncBatchRequests(outAsync); + } + } + + public void + updateConnectionObservers() + { + List<IncomingConnectionFactory> f; + synchronized(this) + { + f = new ArrayList<IncomingConnectionFactory>(_incomingConnectionFactories); + } + for(IncomingConnectionFactory p : f) + { + p.updateConnectionObservers(); + } + } + + public void + updateThreadObservers() + { + IceInternal.ThreadPool threadPool = null; + synchronized(this) + { + threadPool = _threadPool; + } + if(threadPool != null) + { + threadPool.updateObservers(); + } + } + + public synchronized void + incDirectCount() + { + checkForDeactivation(); + + assert(_directCount >= 0); + ++_directCount; + } + + public synchronized void + decDirectCount() + { + // Not check for deactivation here! + + assert(_instance != null); // Must not be called after destroy(). + + assert(_directCount > 0); + if(--_directCount == 0) + { + notifyAll(); + } + } + + public IceInternal.ThreadPool + getThreadPool() + { + // No mutex lock necessary, _threadPool and _instance are + // immutable after creation until they are removed in + // destroy(). + + // Not check for deactivation here! + + assert(_instance != null); // Must not be called after destroy(). + + if(_threadPool != null) + { + return _threadPool; + } + else + { + return _instance.serverThreadPool(); + } + } + + public IceInternal.ServantManager + getServantManager() + { + // + // No mutex lock necessary, _servantManager is immutable. + // + return _servantManager; + } + + public IceInternal.ACMConfig + getACM() + { + // No check for deactivation here! + assert(_instance != null); // Must not be called after destroy(). + return _acm; + } + + public int + messageSizeMax() + { + // No mutex lock, immutable. + return _messageSizeMax; + } + + // + // Only for use by IceInternal.ObjectAdapterFactory + // + public + ObjectAdapterI(IceInternal.Instance instance, Communicator communicator, + IceInternal.ObjectAdapterFactory objectAdapterFactory, String name, + RouterPrx router, boolean noConfig) + { + _instance = instance; + _communicator = communicator; + _objectAdapterFactory = objectAdapterFactory; + _servantManager = new IceInternal.ServantManager(instance, name); + _name = name; + _directCount = 0; + _noConfig = noConfig; + + if(_noConfig) + { + _id = ""; + _replicaGroupId = ""; + _reference = _instance.referenceFactory().create("dummy -t", ""); + _acm = _instance.serverACM(); + _messageSizeMax = _instance.messageSizeMax(); + return; + } + + final Properties properties = _instance.initializationData().properties; + List<String> unknownProps = new ArrayList<String>(); + boolean noProps = filterProperties(unknownProps); + + // + // Warn about unknown object adapter properties. + // + if(unknownProps.size() != 0 && properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0) + { + StringBuffer message = new StringBuffer("found unknown properties for object adapter `"); + message.append(_name); + message.append("':"); + for(String p : unknownProps) + { + message.append("\n "); + message.append(p); + } + _instance.initializationData().logger.warning(message.toString()); + } + + // + // Make sure named adapter has some configuration. + // + if(router == null && noProps) + { + // + // These need to be set to prevent finalizer from complaining. + // + _state = StateDestroyed; + _instance = null; + _incomingConnectionFactories = null; + + InitializationException ex = new InitializationException(); + ex.reason = "object adapter `" + _name + "' requires configuration"; + throw ex; + } + + _id = properties.getProperty(_name + ".AdapterId"); + _replicaGroupId = properties.getProperty(_name + ".ReplicaGroupId"); + + // + // Setup a reference to be used to get the default proxy options + // when creating new proxies. By default, create twoway proxies. + // + String proxyOptions = properties.getPropertyWithDefault(_name + ".ProxyOptions", "-t"); + try + { + _reference = _instance.referenceFactory().create("dummy " + proxyOptions, ""); + } + catch(ProxyParseException e) + { + InitializationException ex = new InitializationException(); + ex.reason = "invalid proxy options `" + proxyOptions + "' for object adapter `" + _name + "'"; + throw ex; + } + + _acm = new IceInternal.ACMConfig(properties, communicator.getLogger(), _name + ".ACM", instance.serverACM()); + + { + final int defaultMessageSizeMax = instance.messageSizeMax() / 1024; + int num = properties.getPropertyAsIntWithDefault(_name + ".MessageSizeMax", defaultMessageSizeMax); + if(num < 1 || num > 0x7fffffff / 1024) + { + _messageSizeMax = 0x7fffffff; + } + else + { + _messageSizeMax = num * 1024; // Property is in kilobytes, _messageSizeMax in bytes + } + } + + try + { + int threadPoolSize = properties.getPropertyAsInt(_name + ".ThreadPool.Size"); + int threadPoolSizeMax = properties.getPropertyAsInt(_name + ".ThreadPool.SizeMax"); + + // + // Create the per-adapter thread pool, if necessary. + // + if(threadPoolSize > 0 || threadPoolSizeMax > 0) + { + _threadPool = new IceInternal.ThreadPool(_instance, _name + ".ThreadPool", 0); + } + + if(router == null) + { + router = RouterPrxHelper.uncheckedCast(_instance.proxyFactory().propertyToProxy(name + ".Router")); + } + if(router != null) + { + _routerInfo = _instance.routerManager().get(router); + if(_routerInfo != null) + { + // + // Make sure this router is not already registered with another adapter. + // + if(_routerInfo.getAdapter() != null) + { + throw new AlreadyRegisteredException("object adapter with router", + Ice.Util.identityToString(router.ice_getIdentity())); + } + + // + // Add the router's server proxy endpoints to this object + // adapter. + // + IceInternal.EndpointI[] endpoints = _routerInfo.getServerEndpoints(); + for(IceInternal.EndpointI endpoint : endpoints) + { + _routerEndpoints.add(endpoint); + } + java.util.Collections.sort(_routerEndpoints); // Must be sorted. + + // + // Remove duplicate endpoints, so we have a list of unique + // endpoints. + // + for(int i = 0; i < _routerEndpoints.size() - 1;) + { + IceInternal.EndpointI e1 = _routerEndpoints.get(i); + IceInternal.EndpointI e2 = _routerEndpoints.get(i + 1); + if(e1.equals(e2)) + { + _routerEndpoints.remove(i); + } + else + { + ++i; + } + } + + // + // Associate this object adapter with the router. This way, + // new outgoing connections to the router's client proxy will + // use this object adapter for callbacks. + // + _routerInfo.setAdapter(this); + + // + // Also modify all existing outgoing connections to the + // router's client proxy to use this object adapter for + // callbacks. + // + _instance.outgoingConnectionFactory().setRouterInfo(_routerInfo); + } + } + else + { + // + // Parse the endpoints, but don't store them in the adapter. The connection + // factory might change it, for example, to fill in the real port number. + // + List<IceInternal.EndpointI> endpoints = + parseEndpoints(properties.getProperty(_name + ".Endpoints"), true); + for(IceInternal.EndpointI endp : endpoints) + { + IncomingConnectionFactory factory = new IncomingConnectionFactory(instance, endp, this); + _incomingConnectionFactories.add(factory); + } + if(endpoints.size() == 0) + { + IceInternal.TraceLevels tl = _instance.traceLevels(); + if(tl.network >= 2) + { + _instance.initializationData().logger.trace(tl.networkCat, + "created adapter `" + name + "' without endpoints"); + } + } + + // + // Parse the publsihed endpoints. + // + _publishedEndpoints = parsePublishedEndpoints(); + } + + if(properties.getProperty(_name + ".Locator").length() > 0) + { + setLocator(LocatorPrxHelper.uncheckedCast( + _instance.proxyFactory().propertyToProxy(_name + ".Locator"))); + } + else + { + setLocator(_instance.referenceFactory().getDefaultLocator()); + } + } + catch(LocalException ex) + { + destroy(); + throw ex; + } + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + if(_state < StateDeactivated) + { + _instance.initializationData().logger.warning("object adapter `" + getName() + + "' has not been deactivated"); + } + else if(_state != StateDestroyed) + { + _instance.initializationData().logger.warning("object adapter `" + getName() + + "' has not been destroyed"); + } + else + { + IceUtilInternal.Assert.FinalizerAssert(_threadPool == null); + // Not cleared, it needs to be immutable. + //IceUtilInternal.Assert.FinalizerAssert(_servantManager == null); + //IceUtilInternal.Assert.FinalizerAssert(_incomingConnectionFactories.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_directCount == 0); + } + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private ObjectPrx + newProxy(Identity ident, String facet) + { + if(_id.length() == 0) + { + return newDirectProxy(ident, facet); + } + else if(_replicaGroupId.length() == 0) + { + return newIndirectProxy(ident, facet, _id); + } + else + { + return newIndirectProxy(ident, facet, _replicaGroupId); + } + } + + private ObjectPrx + newDirectProxy(Identity ident, String facet) + { + IceInternal.EndpointI[] endpoints; + + int sz = _publishedEndpoints.size(); + endpoints = new IceInternal.EndpointI[sz + _routerEndpoints.size()]; + _publishedEndpoints.toArray(endpoints); + + // + // Now we also add the endpoints of the router's server proxy, if + // any. This way, object references created by this object adapter + // will also point to the router's server proxy endpoints. + // + for(int i = 0; i < _routerEndpoints.size(); ++i) + { + endpoints[sz + i] = _routerEndpoints.get(i); + } + + // + // Create a reference and return a proxy for this reference. + // + IceInternal.Reference ref = _instance.referenceFactory().create(ident, facet, _reference, endpoints); + return _instance.proxyFactory().referenceToProxy(ref); + } + + private ObjectPrx + newIndirectProxy(Identity ident, String facet, String id) + { + // + // Create a reference with the adapter id and return a proxy + // for the reference. + // + IceInternal.Reference ref = _instance.referenceFactory().create(ident, facet, _reference, id); + return _instance.proxyFactory().referenceToProxy(ref); + } + + private void + checkForDeactivation() + { + if(_state >= StateDeactivating) + { + ObjectAdapterDeactivatedException ex = new ObjectAdapterDeactivatedException(); + ex.name = getName(); + throw ex; + } + } + + private static void + checkIdentity(Identity ident) + { + if(ident.name == null || ident.name.length() == 0) + { + throw new IllegalIdentityException(ident); + } + + if(ident.category == null) + { + ident.category = ""; + } + } + + private static void + checkServant(Ice.Object servant) + { + if(servant == null) + { + throw new IllegalServantException("cannot add null servant to Object Adapter"); + } + } + + private List<IceInternal.EndpointI> + parseEndpoints(String endpts, boolean oaEndpoints) + { + int beg; + int end = 0; + + final String delim = " \t\n\r"; + + List<IceInternal.EndpointI> endpoints = new ArrayList<IceInternal.EndpointI>(); + while(end < endpts.length()) + { + beg = IceUtilInternal.StringUtil.findFirstNotOf(endpts, delim, end); + if(beg == -1) + { + break; + } + + end = beg; + while(true) + { + end = endpts.indexOf(':', end); + if(end == -1) + { + end = endpts.length(); + break; + } + else + { + boolean quoted = false; + int quote = beg; + while(true) + { + quote = endpts.indexOf('\"', quote); + if(quote == -1 || end < quote) + { + break; + } + else + { + quote = endpts.indexOf('\"', ++quote); + if(quote == -1) + { + break; + } + else if(end < quote) + { + quoted = true; + break; + } + ++quote; + } + } + if(!quoted) + { + break; + } + ++end; + } + } + + if(end == beg) + { + ++end; + continue; + } + + String s = endpts.substring(beg, end); + IceInternal.EndpointI endp = _instance.endpointFactoryManager().create(s, oaEndpoints); + if(endp == null) + { + Ice.EndpointParseException e = new Ice.EndpointParseException(); + e.str = "invalid object adapter endpoint `" + s + "'"; + throw e; + } + endpoints.add(endp); + + ++end; + } + + return endpoints; + } + + private List<IceInternal.EndpointI> + parsePublishedEndpoints() + { + // + // Parse published endpoints. If set, these are used in proxies + // instead of the connection factory Endpoints. + // + String endpts = _instance.initializationData().properties.getProperty(_name + ".PublishedEndpoints"); + List<IceInternal.EndpointI> endpoints = parseEndpoints(endpts, false); + if(endpoints.isEmpty()) + { + // + // If the PublishedEndpoints property isn't set, we compute the published enpdoints + // from the OA endpoints, expanding any endpoints that may be listening on INADDR_ANY + // to include actual addresses in the published endpoints. + // + for(IncomingConnectionFactory factory : _incomingConnectionFactories) + { + endpoints.addAll(factory.endpoint().expand()); + } + } + + if(_instance.traceLevels().network >= 1 && !endpoints.isEmpty()) + { + StringBuffer s = new StringBuffer("published endpoints for object adapter `"); + s.append(_name); + s.append("':\n"); + boolean first = true; + for(IceInternal.EndpointI endpoint : endpoints) + { + if(!first) + { + s.append(":"); + } + s.append(endpoint.toString()); + first = false; + } + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + return endpoints; + } + + private void + updateLocatorRegistry(IceInternal.LocatorInfo locatorInfo, Ice.ObjectPrx proxy) + { + if(_id.length() == 0 || locatorInfo == null) + { + return; // Nothing to update. + } + + // + // Call on the locator registry outside the synchronization to + // blocking other threads that need to lock this OA. + // + LocatorRegistryPrx locatorRegistry = locatorInfo.getLocatorRegistry(); + if(locatorRegistry == null) + { + return; + } + + try + { + if(_replicaGroupId.length() == 0) + { + locatorRegistry.setAdapterDirectProxy(_id, proxy); + } + else + { + locatorRegistry.setReplicatedAdapterDirectProxy(_id, _replicaGroupId, proxy); + } + } + catch(AdapterNotFoundException ex) + { + if(_instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't update object adapter `"); + s.append(_id); + s.append("' endpoints with the locator registry:\n"); + s.append("the object adapter is not known to the locator registry"); + _instance.initializationData().logger.trace(_instance.traceLevels().locationCat, s.toString()); + } + + NotRegisteredException ex1 = new NotRegisteredException(); + ex1.kindOfObject = "object adapter"; + ex1.id = _id; + throw ex1; + } + catch(InvalidReplicaGroupIdException ex) + { + if(_instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't update object adapter `"); + s.append(_id); + s.append("' endpoints with the locator registry:\n"); + s.append("the replica group `"); + s.append(_replicaGroupId); + s.append("' is not known to the locator registry"); + _instance.initializationData().logger.trace(_instance.traceLevels().locationCat, s.toString()); + } + + NotRegisteredException ex1 = new NotRegisteredException(); + ex1.kindOfObject = "replica group"; + ex1.id = _replicaGroupId; + throw ex1; + } + catch(AdapterAlreadyActiveException ex) + { + if(_instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't update object adapter `"); + s.append(_id); + s.append("' endpoints with the locator registry:\n"); + s.append("the object adapter endpoints are already set"); + _instance.initializationData().logger.trace(_instance.traceLevels().locationCat, s.toString()); + } + + ObjectAdapterIdInUseException ex1 = new ObjectAdapterIdInUseException(); + ex1.id = _id; + throw ex1; + } + catch(ObjectAdapterDeactivatedException e) + { + // Expected if collocated call and OA is deactivated, ignore. + } + catch(CommunicatorDestroyedException e) + { + // Ignore + } + catch(LocalException e) + { + if(_instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't update object adapter `"); + s.append(_id); + s.append("' endpoints with the locator registry:\n"); + s.append(e.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().locationCat, s.toString()); + } + throw e; // TODO: Shall we raise a special exception instead of a non obvious local exception? + } + + if(_instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("updated object adapter `"); + s.append(_id); + s.append("' endpoints with the locator registry\n"); + s.append("endpoints = "); + if(proxy != null) + { + Ice.Endpoint[] endpoints = proxy.ice_getEndpoints(); + for(int i = 0; i < endpoints.length; i++) + { + s.append(endpoints[i].toString()); + if(i + 1 < endpoints.length) + { + s.append(":"); + } + } + } + _instance.initializationData().logger.trace(_instance.traceLevels().locationCat, s.toString()); + } + } + + static private String[] _suffixes = + { + "ACM", + "ACM.Timeout", + "ACM.Heartbeat", + "ACM.Close", + "AdapterId", + "Endpoints", + "Locator", + "Locator.EncodingVersion", + "Locator.EndpointSelection", + "Locator.ConnectionCached", + "Locator.PreferSecure", + "Locator.CollocationOptimized", + "Locator.Router", + "MessageSizeMax", + "PublishedEndpoints", + "ReplicaGroupId", + "Router", + "Router.EncodingVersion", + "Router.EndpointSelection", + "Router.ConnectionCached", + "Router.PreferSecure", + "Router.CollocationOptimized", + "Router.Locator", + "Router.Locator.EndpointSelection", + "Router.Locator.ConnectionCached", + "Router.Locator.PreferSecure", + "Router.Locator.CollocationOptimized", + "Router.Locator.LocatorCacheTimeout", + "Router.Locator.InvocationTimeout", + "Router.LocatorCacheTimeout", + "Router.InvocationTimeout", + "ProxyOptions", + "ThreadPool.Size", + "ThreadPool.SizeMax", + "ThreadPool.SizeWarn", + "ThreadPool.StackSize", + "ThreadPool.Serialize" + }; + + boolean + filterProperties(List<String> unknownProps) + { + // + // Do not create unknown properties list if Ice prefix, ie Ice, Glacier2, etc + // + boolean addUnknown = true; + String prefix = _name + "."; + for(int i = 0; IceInternal.PropertyNames.clPropNames[i] != null; ++i) + { + if(prefix.startsWith(IceInternal.PropertyNames.clPropNames[i] + ".")) + { + addUnknown = false; + break; + } + } + + boolean noProps = true; + Map<String, String> props = _instance.initializationData().properties.getPropertiesForPrefix(prefix); + for(String prop : props.keySet()) + { + boolean valid = false; + for(String suffix : _suffixes) + { + if(prop.equals(prefix + suffix)) + { + noProps = false; + valid = true; + break; + } + } + + if(!valid && addUnknown) + { + unknownProps.add(prop); + } + } + + return noProps; + } + + private static final int StateUninitialized = 0; // Just constructed. + private static final int StateHeld = 1; + private static final int StateActivating = 2; + private static final int StateActive = 3; + private static final int StateDeactivating = 4; + private static final int StateDeactivated = 5; + private static final int StateDestroying = 6; + private static final int StateDestroyed = 7; + + private int _state = StateUninitialized; + private IceInternal.Instance _instance; + private Communicator _communicator; + private IceInternal.ObjectAdapterFactory _objectAdapterFactory; + private IceInternal.ThreadPool _threadPool; + private IceInternal.ACMConfig _acm; + private IceInternal.ServantManager _servantManager; + final private String _name; + final private String _id; + final private String _replicaGroupId; + private IceInternal.Reference _reference; + private List<IncomingConnectionFactory> _incomingConnectionFactories = new ArrayList<IncomingConnectionFactory>(); + private List<IceInternal.EndpointI> _routerEndpoints = new ArrayList<IceInternal.EndpointI>(); + private IceInternal.RouterInfo _routerInfo = null; + private List<IceInternal.EndpointI> _publishedEndpoints = new ArrayList<IceInternal.EndpointI>(); + private IceInternal.LocatorInfo _locatorInfo; + private int _directCount; // The number of direct proxies dispatching on this object adapter. + private boolean _noConfig; + private final int _messageSizeMax; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectHolder.java b/java-compat/src/Ice/src/main/java/Ice/ObjectHolder.java new file mode 100644 index 00000000000..c570288a292 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectHolder.java @@ -0,0 +1,41 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for Ice objects that are out- or inout-parameters. + **/ +public final class ObjectHolder extends ObjectHolderBase<Ice.Object> +{ + /** + * Instantiates the class with a <code>null</code> value. + **/ + public ObjectHolder() + { + } + + /** + * Instantiates the class with the passed Ice object. + **/ + public ObjectHolder(Ice.Object value) + { + super(value); + } + + /** + * Sets the value of this holder to the passed instance. + * + * @param v The new value for this holder. + **/ + public void valueReady(Ice.Object v) + { + value = v; + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectHolderBase.java b/java-compat/src/Ice/src/main/java/Ice/ObjectHolderBase.java new file mode 100644 index 00000000000..62fa4ac1591 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectHolderBase.java @@ -0,0 +1,38 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder base class for Ice objects that are in- or inout-parameters. + **/ +public abstract class ObjectHolderBase<T extends Ice.Object> implements ReadValueCallback +{ + /** + * Instantiates the class with a <code>null</code> value. + **/ + public + ObjectHolderBase() + { + } + + /** + * Instantiates the class with the passed Ice object. + **/ + public + ObjectHolderBase(T obj) + { + this.value = obj; + } + + /** + * The Ice object stored by this holder. + **/ + public T value; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectImpl.java b/java-compat/src/Ice/src/main/java/Ice/ObjectImpl.java new file mode 100644 index 00000000000..b6a253d13ef --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectImpl.java @@ -0,0 +1,429 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for all Slice classes. + **/ +public abstract class ObjectImpl implements Object, java.lang.Cloneable, java.io.Serializable +{ + /** + * Instantiates an Ice object. + **/ + public + ObjectImpl() + { + } + + /** + * Returns a copy of the object. The cloned object contains field-for-field copies + * of the state. + * + * @return The cloned object. + **/ + @Override + public ObjectImpl + clone() + { + ObjectImpl c = null; + + try + { + c = (ObjectImpl)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; + } + + public final static String[] __ids = + { + "::Ice::Object" + }; + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param s The type ID of the Slice interface to test against. + * @return The return value is <code>true</code> if <code>s</code> is + * <code>::Ice::Object</code>. + **/ + @Override + public boolean + ice_isA(String s) + { + return s.equals(__ids[0]); + } + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param s The type ID of the Slice interface to test against. + * @param current The current object for the invocation. + * @return The return value is <code>true</code> if <code>s</code> is + * <code>::Ice::Object</code>. + **/ + @Override + public boolean + ice_isA(String s, Current current) + { + return s.equals(__ids[0]); + } + + public static DispatchStatus + ___ice_isA(Ice.Object __obj, IceInternal.Incoming __inS, Current __current) + { + InputStream __is = __inS.startReadParams(); + String __id = __is.readString(); + __inS.endReadParams(); + boolean __ret = __obj.ice_isA(__id, __current); + OutputStream __os = __inS.__startWriteParams(Ice.FormatType.DefaultFormat); + __os.writeBool(__ret); + __inS.__endWriteParams(true); + return DispatchStatus.DispatchOK; + } + + /** + * Tests whether this object can be reached. + **/ + @Override + public void + ice_ping() + { + // Nothing to do. + } + + /** + * Tests whether this object can be reached. + * + * @param current The current object for the invocation. + **/ + @Override + public void + ice_ping(Current current) + { + // Nothing to do. + } + + public static DispatchStatus + ___ice_ping(Ice.Object __obj, IceInternal.Incoming __inS, Current __current) + { + __inS.readEmptyParams(); + __obj.ice_ping(__current); + __inS.__writeEmptyParams(); + return DispatchStatus.DispatchOK; + } + + /** + * Returns the Slice type IDs of the interfaces supported by this object. + * + * @return An array whose only element is <code>::Ice::Object</code>. + **/ + @Override + public String[] + ice_ids() + { + return __ids; + } + + /** + * Returns the Slice type IDs of the interfaces supported by this object. + * + * @param current The current object for the invocation. + * @return An array whose only element is <code>::Ice::Object</code>. + **/ + @Override + public String[] + ice_ids(Current current) + { + return __ids; + } + + public static DispatchStatus + ___ice_ids(Ice.Object __obj, IceInternal.Incoming __inS, Current __current) + { + __inS.readEmptyParams(); + String[] __ret = __obj.ice_ids(__current); + OutputStream __os = __inS.__startWriteParams(Ice.FormatType.DefaultFormat); + __os.writeStringSeq(__ret); + __inS.__endWriteParams(true); + return DispatchStatus.DispatchOK; + } + + /** + * Returns the Slice type ID of the most-derived interface supported by this object. + * + * @return The return value is always <code>::Ice::Object</code>. + **/ + @Override + public String + ice_id() + { + return __ids[0]; + } + + /** + * Returns the Slice type ID of the most-derived interface supported by this object. + * + * @param current The current object for the invocation. + * @return A Slice type ID. + **/ + @Override + public String + ice_id(Current current) + { + return __ids[0]; + } + + public static DispatchStatus + ___ice_id(Ice.Object __obj, IceInternal.Incoming __inS, Current __current) + { + __inS.readEmptyParams(); + String __ret = __obj.ice_id(__current); + OutputStream __os = __inS.__startWriteParams(Ice.FormatType.DefaultFormat); + __os.writeString(__ret); + __inS.__endWriteParams(true); + return DispatchStatus.DispatchOK; + } + + /** + * Returns the Slice type ID of the interface supported by this object. + * + * @return The return value is always ::Ice::Object. + **/ + public static String + ice_staticId() + { + return __ids[0]; + } + + /** + * Returns the Freeze metadata attributes for an operation. + * + * @param operation The name of the operation. + * @return The least significant bit indicates whether the operation is a read + * or write operation. If the bit is set, the operation is a write operation. + * The expression <code>ice_operationAttributes("op") & 0x1</code> is true if + * the operation has a <code>["freeze:write"]</code> metadata directive. + * <p> + * The second- and third least significant bit indicate the transactional mode + * of the operation. The expression <code>ice_operationAttributes("op") & 0x6 >> 1</code> + * indicates the transactional mode as follows: + * <dl> + * <dt>0</dt> + * <dd><code>["freeze:read:supports"]</code></dd> + * <dt>1</dt> + * <dd><code>["freeze:read:mandatory"]</code> or <code>["freeze:write:mandatory"]</code></dd> + * <dt>2</dt> + * <dd><code>["freeze:read:required"]</code> or <code>["freeze:write:required"]</code></dd> + * <dt>3</dt> + * <dd><code>["freeze:read:never"]</code></dd> + * </dl> + * + * Refer to the Freeze manual for more information on the TransactionalEvictor. + **/ + @Override + public int ice_operationAttributes(String operation) + { + return 0; + } + + /** + * The Ice run time invokes this method prior to marshaling an object's data members. This allows a subclass + * to override this method in order to validate its data members. This default implementation does nothing. + **/ + @Override + public void + ice_preMarshal() + { + } + + /** + * This Ice run time invokes this method vafter unmarshaling an object's data members. This allows a + * subclass to override this method in order to perform additional initialization. This default + * implementation does nothing. + **/ + @Override + public void + ice_postUnmarshal() + { + } + + private final static String[] __all = + { + "ice_id", + "ice_ids", + "ice_isA", + "ice_ping" + }; + + /** + * Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation + * to a servant (or to another interceptor). + * + * @param request The details of the invocation. + * @param cb The callback object for asynchchronous dispatch. For synchronous dispatch, the callback object must + * be <code>null</code>. + * @return The dispatch status for the operation. + * + * @see DispatchInterceptor + * @see DispatchInterceptorAsyncCallback + * @see DispatchStatus + **/ + @Override + public DispatchStatus + ice_dispatch(Request request, DispatchInterceptorAsyncCallback cb) + { + IceInternal.Incoming in = (IceInternal.Incoming)request; + if(cb != null) + { + in.push(cb); + } + try + { + in.startOver(); // may raise ResponseSentException + return __dispatch(in, in.getCurrent()); + } + finally + { + if(cb != null) + { + in.pop(); + } + } + } + + /** + * Dispatches an invocation to a servant. This method is used by dispatch interceptors to forward an invocation + * to a servant (or to another interceptor). + * + * @param request The details of the invocation. + * @return The dispatch status for the operation. + * + * @see DispatchInterceptor + * @see DispatchStatus + **/ + @Override + public DispatchStatus + ice_dispatch(Request request) + { + return ice_dispatch(request, null); + } + + @Override + public DispatchStatus + __dispatch(IceInternal.Incoming in, Current current) + { + int pos = java.util.Arrays.binarySearch(__all, current.operation); + if(pos < 0) + { + throw new Ice.OperationNotExistException(current.id, current.facet, current.operation); + } + + switch(pos) + { + case 0: + { + return ___ice_id(this, in, current); + } + case 1: + { + return ___ice_ids(this, in, current); + } + case 2: + { + return ___ice_isA(this, in, current); + } + case 3: + { + return ___ice_ping(this, in, current); + } + } + + assert(false); + throw new Ice.OperationNotExistException(current.id, current.facet, current.operation); + } + + @Override + public void + __write(OutputStream os) + { + os.startValue(null); + __writeImpl(os); + os.endValue(); + } + + @Override + public void + __read(InputStream is) + { + is.startValue(); + __readImpl(is); + is.endValue(false); + } + + protected void + __writeImpl(OutputStream os) + { + } + + protected void + __readImpl(InputStream is) + { + } + + private static String + operationModeToString(OperationMode mode) + { + if(mode == Ice.OperationMode.Normal) + { + return "::Ice::Normal"; + } + if(mode == Ice.OperationMode.Nonmutating) + { + return "::Ice::Nonmutating"; + } + + if(mode == Ice.OperationMode.Idempotent) + { + return "::Ice::Idempotent"; + } + + return "???"; + } + + protected static void + __checkMode(OperationMode expected, OperationMode received) + { + if(expected != received) + { + if(expected == Ice.OperationMode.Idempotent + && received == Ice.OperationMode.Nonmutating) + { + // + // Fine: typically an old client still using the + // deprecated nonmutating keyword + // + } + else + { + Ice.MarshalException ex = new Ice.MarshalException(); + ex.reason = "unexpected operation mode. expected = " + + operationModeToString(expected) + " received = " + + operationModeToString(received); + throw ex; + } + } + } + + public static final long serialVersionUID = 0L; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectInputStream.java b/java-compat/src/Ice/src/main/java/Ice/ObjectInputStream.java new file mode 100644 index 00000000000..0d635b49b32 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectInputStream.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * For deserialization of Slice types that contain a proxy, the application + * must instantiate a subclass of <code>ObjectInputStream</code> and supply + * a communicator that is used to reconstruct the proxy. + **/ +public class ObjectInputStream extends java.io.ObjectInputStream +{ + /** + * Instantiates this class for the specified communicator and input stream. + * + * @param communicator The communicator to use to deserialize proxies. + * @param stream The input stream to read from. + **/ + public + ObjectInputStream(Communicator communicator, java.io.InputStream stream) + throws java.io.IOException + { + super(stream); + _communicator = communicator; + } + + /** + * Returns the communicator for this stream. + **/ + public Communicator + getCommunicator() + { + return _communicator; + } + + private Communicator _communicator; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectPrx.java b/java-compat/src/Ice/src/main/java/Ice/ObjectPrx.java new file mode 100644 index 00000000000..ad077d2edb1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectPrx.java @@ -0,0 +1,1214 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base interface of all object proxies. + **/ +public interface ObjectPrx +{ + /** + * Returns the communicator that created this proxy. + * + * @return The communicator that created this proxy. + **/ + Communicator ice_getCommunicator(); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @return <code>true</code> if the target object has the interface + * specified by <code>__id</code> or derives from the interface + * specified by <code>__id</code>. + **/ + boolean ice_isA(String __id); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @param __context The context map for the invocation. + * @return <code>true</code> if the target object has the interface + * specified by <code>__id</code> or derives from the interface + * specified by <code>__id</code>. + **/ + boolean ice_isA(String __id, java.util.Map<String, String> __context); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, java.util.Map<String, String> __context); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, Callback __cb); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, java.util.Map<String, String> __context, Callback __cb); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, Callback_Object_ice_isA __cb); + + /** + * Tests whether this object supports a specific Slice interface. + * + * @param __id The type ID of the Slice interface to test against. + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, java.util.Map<String, String> __context, Callback_Object_ice_isA __cb); + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, java.util.Map<String, String> __context, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_isA(String __id, java.util.Map<String, String> __context, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Completes the asynchronous ice_isA request. + * + * @param __result The asynchronous result. + * @return <code>true</code> if this proxy supports the specified interface; <code>false</code>, otherwise. + **/ + boolean end_ice_isA(AsyncResult __result); + + /** + * Tests whether the target object of this proxy can be reached. + **/ + void ice_ping(); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + **/ + void ice_ping(java.util.Map<String, String> __context); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(java.util.Map<String, String> __context); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(Callback __cb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(java.util.Map<String, String> __context, Callback __cb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(Callback_Object_ice_ping __cb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(java.util.Map<String, String> __context, Callback_Object_ice_ping __cb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(java.util.Map<String, String> __context, + IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ping(java.util.Map<String, String> __context, + IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Completes the asynchronous ice_ping request. + * + * @param __result The asynchronous result. + **/ + void end_ice_ping(AsyncResult __result); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @return The Slice type IDs of the interfaces supported by the target object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + String[] ice_ids(); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @return The Slice type IDs of the interfaces supported by the target object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + String[] ice_ids(java.util.Map<String, String> __context); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(java.util.Map<String, String> __context); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(Callback __cb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(java.util.Map<String, String> __context, Callback __cb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(Callback_Object_ice_ids __cb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(java.util.Map<String, String> __context, Callback_Object_ice_ids __cb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_ids(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Completes the asynchronous ice_ids request. + * + * @param __result The asynchronous result. + * @return The Slice type IDs of the interfaces supported by the target object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + String[] end_ice_ids(AsyncResult __result); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @return The Slice type ID of the most-derived interface. + **/ + String ice_id(); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @return The Slice type ID of the most-derived interface. + **/ + String ice_id(java.util.Map<String, String> __context); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(java.util.Map<String, String> __context); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(Callback __cb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(java.util.Map<String, String> __context, Callback __cb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(Callback_Object_ice_id __cb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(java.util.Map<String, String> __context, Callback_Object_ice_id __cb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_id(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Completes the asynchronous ice_id request. + * + * @param __result The asynchronous result. + * @return The Slice type ID of the most-derived interface. + **/ + String end_ice_id(AsyncResult __result); + + /** + * Invokes an operation dynamically. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param outParams The encoded out-paramaters and return value + * for the operation. The return value follows any out-parameters. + * @return If the operation completed successfully, the return value + * is <code>true</code>. If the operation raises a user exception, + * the return value is <code>false</code>; in this case, <code>outParams</code> + * contains the encoded user exception. If the operation raises a run-time exception, + * it throws it directly. + * + * @see Blobject + * @see OperationMode + **/ + boolean ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams); + + /** + * Invokes an operation dynamically. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param outParams The encoded out-paramaters and return value + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @return If the operation completed successfully, the return value + * is <code>true</code>. If the operation raises a user exception, + * the return value is <code>false</code>; in this case, <code>outParams</code> + * contains the encoded user exception. If the operation raises a run-time exception, + * it throws it directly. + * + * @see Blobject + * @see OperationMode + **/ + boolean ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams, + java.util.Map<String, String> __context); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, Callback __cb); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context, Callback __cb); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + Callback_Object_ice_invoke __cb); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context, Callback_Object_ice_invoke __cb); + + public interface FunctionalCallback_Object_ice_invoke_Response + { + void apply(boolean result, byte[] outArgs); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + FunctionalCallback_Object_ice_invoke_Response __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + FunctionalCallback_Object_ice_invoke_Response __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param __context The context map for the invocation. + * for the operation. The return value follows any out-parameters. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context, + FunctionalCallback_Object_ice_invoke_Response __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param __context The context map for the invocation. + * for the operation. The return value follows any out-parameters. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context, + FunctionalCallback_Object_ice_invoke_Response __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Completes the asynchronous ice_invoke request. + * + * @param outParams The encoded out-paramaters and return value. + * @param __result The asynchronous result. + * @return If the operation completed successfully, the return value + * is <code>true</code>. If the operation raises a user exception, + * the return value is <code>false</code>; in this case, <code>outParams</code> + * contains the encoded user exception. If the operation raises a run-time exception, + * it throws it directly. + **/ + boolean end_ice_invoke(ByteSeqHolder outParams, AsyncResult __result); + + /** + * Returns the identity embedded in this proxy. + * + * @return The identity of the target object. + **/ + Identity ice_getIdentity(); + + /** + * Creates a new proxy that is identical to this proxy, except for the identity. + * + * @param newIdentity The identity for the new proxy. + * @return The proxy with the new identity. + **/ + ObjectPrx ice_identity(Identity newIdentity); + + /** + * Returns the per-proxy context for this proxy. + * + * @return The per-proxy context. If the proxy does not have a per-proxy (implicit) context, the return value + * is <code>null</code>. + **/ + java.util.Map<String, String> ice_getContext(); + + /** + * Creates a new proxy that is identical to this proxy, except for the per-proxy context. + * + * @param newContext The context for the new proxy. + * @return The proxy with the new per-proxy context. + **/ + ObjectPrx ice_context(java.util.Map<String, String> newContext); + + /** + * Returns the facet for this proxy. + * + * @return The facet for this proxy. If the proxy uses the default facet, the return value is the empty string. + **/ + String ice_getFacet(); + + /** + * Creates a new proxy that is identical to this proxy, except for the facet. + * + * @param newFacet The facet for the new proxy. + * @return The proxy with the new facet. + **/ + ObjectPrx ice_facet(String newFacet); + + /** + * Returns the adapter ID for this proxy. + * + * @return The adapter ID. If the proxy does not have an adapter ID, the return value is the empty string. + **/ + String ice_getAdapterId(); + + /** + * Creates a new proxy that is identical to this proxy, except for the adapter ID. + * + * @param newAdapterId The adapter ID for the new proxy. + * @return The proxy with the new adapter ID. + **/ + ObjectPrx ice_adapterId(String newAdapterId); + + /** + * Returns the endpoints used by this proxy. + * + * @return The endpoints used by this proxy. + * + * @see Endpoint + **/ + Endpoint[] ice_getEndpoints(); + + /** + * Creates a new proxy that is identical to this proxy, except for the endpoints. + * + * @param newEndpoints The endpoints for the new proxy. + * @return The proxy with the new endpoints. + **/ + ObjectPrx ice_endpoints(Endpoint[] newEndpoints); + + /** + * Returns the locator cache timeout of this proxy. + * + * @return The locator cache timeout value (in seconds). + * + * @see Locator + **/ + int ice_getLocatorCacheTimeout(); + + /** + * Returns the invocation timeout of this proxy. + * + * @return The invocation timeout value (in seconds). + **/ + int ice_getInvocationTimeout(); + + /** + * Returns the connection id of this proxy. + * + * @return The connection id. + * + **/ + String ice_getConnectionId(); + + /** + * Creates a new proxy that is identical to this proxy, except for the locator cache timeout. + * + * @param newTimeout The new locator cache timeout (in seconds). + * + * @see Locator + **/ + ObjectPrx ice_locatorCacheTimeout(int newTimeout); + + /** + * Creates a new proxy that is identical to this proxy, except for the invocation timeout. + * + * @param newTimeout The new invocation timeout (in seconds). + * + **/ + ObjectPrx ice_invocationTimeout(int newTimeout); + + /** + * Returns whether this proxy caches connections. + * + * @return <code>true</code> if this proxy caches connections; <code>false</code>, otherwise. + **/ + boolean ice_isConnectionCached(); + + /** + * Creates a new proxy that is identical to this proxy, except for connection caching. + * + * @param newCache <code>true</code> if the new proxy should cache connections; <code>false</code>, otherwise. + * @return The new proxy with the specified caching policy. + **/ + ObjectPrx ice_connectionCached(boolean newCache); + + /** + * Returns how this proxy selects endpoints (randomly or ordered). + * + * @return The endpoint selection policy. + * + * @see EndpointSelectionType + **/ + EndpointSelectionType ice_getEndpointSelection(); + + /** + * Creates a new proxy that is identical to this proxy, except for the endpoint selection policy. + * + * @param newType The new endpoint selection policy. + * @return The new proxy with the specified endpoint selection policy. + * + * @see EndpointSelectionType + **/ + ObjectPrx ice_endpointSelection(EndpointSelectionType newType); + + /** + * Returns whether this proxy uses only secure endpoints. + * + * @return <code>True</code> if this proxy communicates only via secure endpoints; <code>false</code>, otherwise. + **/ + boolean ice_isSecure(); + + /** + * Creates a new proxy that is identical to this proxy, except for how it selects endpoints. + * + * @param b If <code>b</code> is <code>true</code>, only endpoints that use a secure transport are + * used by the new proxy. If <code>b</code> is false, the returned proxy uses both secure and insecure + * endpoints. + * @return The new proxy with the specified selection policy. + **/ + ObjectPrx ice_secure(boolean b); + + /** + * Creates a new proxy that is identical to this proxy, except for the encoding used to marshal + * parameters. + * + * @param e The encoding version to use to marshal requests parameters. + * @return The new proxy with the specified encoding version. + **/ + ObjectPrx ice_encodingVersion(Ice.EncodingVersion e); + + /** + * Returns the encoding version used to marshal requests parameters. + * + * @return The encoding version. + **/ + Ice.EncodingVersion ice_getEncodingVersion(); + + /** + * Returns whether this proxy prefers secure endpoints. + * + * @return <code>true</code> if the proxy always attempts to invoke via secure endpoints before it + * attempts to use insecure endpoints; <code>false</code>, otherwise. + **/ + boolean ice_isPreferSecure(); + + /** + * Creates a new proxy that is identical to this proxy, except for its endpoint selection policy. + * + * @param b If <code>b</code> is <code>true</code>, the new proxy will use secure endpoints for invocations + * and only use insecure endpoints if an invocation cannot be made via secure endpoints. If <code>b</code> is + * <code>false</code>, the proxy prefers insecure endpoints to secure ones. + * @return The new proxy with the new endpoint selection policy. + **/ + ObjectPrx ice_preferSecure(boolean b); + + /** + * Returns the router for this proxy. + * + * @return The router for the proxy. If no router is configured for the proxy, the return value + * is <code>null</code>. + **/ + Ice.RouterPrx ice_getRouter(); + + /** + * Creates a new proxy that is identical to this proxy, except for the router. + * + * @param router The router for the new proxy. + * @return The new proxy with the specified router. + **/ + ObjectPrx ice_router(Ice.RouterPrx router); + + /** + * Returns the locator for this proxy. + * + * @return The locator for this proxy. If no locator is configured, the return value is <code>null</code>. + **/ + Ice.LocatorPrx ice_getLocator(); + + /** + * Creates a new proxy that is identical to this proxy, except for the locator. + * + * @param locator The locator for the new proxy. + * @return The new proxy with the specified locator. + **/ + ObjectPrx ice_locator(Ice.LocatorPrx locator); + + /** + * Returns whether this proxy uses collocation optimization. + * + * @return <code>true</code> if the proxy uses collocation optimization; <code>false</code>, otherwise. + **/ + boolean ice_isCollocationOptimized(); + + /** + * Creates a new proxy that is identical to this proxy, except for collocation optimization. + * + * @param b <code>true</code> if the new proxy enables collocation optimization; <code>false</code>, otherwise. + * @return The new proxy the specified collocation optimization. + **/ + ObjectPrx ice_collocationOptimized(boolean b); + + /** + * Creates a new proxy that is identical to this proxy, but uses twoway invocations. + * + * @return A new proxy that uses twoway invocations. + **/ + ObjectPrx ice_twoway(); + + /** + * Returns whether this proxy uses twoway invocations. + * @return <code>true</code> if this proxy uses twoway invocations; <code>false</code>, otherwise. + **/ + boolean ice_isTwoway(); + + /** + * Creates a new proxy that is identical to this proxy, but uses oneway invocations. + * + * @return A new proxy that uses oneway invocations. + **/ + ObjectPrx ice_oneway(); + + /** + * Returns whether this proxy uses oneway invocations. + * @return <code>true</code> if this proxy uses oneway invocations; <code>false</code>, otherwise. + **/ + boolean ice_isOneway(); + + /** + * Creates a new proxy that is identical to this proxy, but uses batch oneway invocations. + * + * @return A new proxy that uses batch oneway invocations. + **/ + ObjectPrx ice_batchOneway(); + + /** + * Returns whether this proxy uses batch oneway invocations. + * @return <code>true</code> if this proxy uses batch oneway invocations; <code>false</code>, otherwise. + **/ + boolean ice_isBatchOneway(); + + /** + * Creates a new proxy that is identical to this proxy, but uses datagram invocations. + * + * @return A new proxy that uses datagram invocations. + **/ + ObjectPrx ice_datagram(); + + /** + * Returns whether this proxy uses datagram invocations. + * @return <code>true</code> if this proxy uses datagram invocations; <code>false</code>, otherwise. + **/ + boolean ice_isDatagram(); + + /** + * Creates a new proxy that is identical to this proxy, but uses batch datagram invocations. + * + * @return A new proxy that uses batch datagram invocations. + **/ + ObjectPrx ice_batchDatagram(); + + /** + * Returns whether this proxy uses batch datagram invocations. + * @return <code>true</code> if this proxy uses batch datagram invocations; <code>false</code>, otherwise. + **/ + boolean ice_isBatchDatagram(); + + /** + * Creates a new proxy that is identical to this proxy, except for compression. + * + * @param co <code>true</code> enables compression for the new proxy; <code>false</code> disables compression. + * @return A new proxy with the specified compression setting. + **/ + ObjectPrx ice_compress(boolean co); + + /** + * Creates a new proxy that is identical to this proxy, except for its timeout setting. + * + * @param t The timeout for the new proxy in milliseconds. + * @return A new proxy with the specified timeout. + **/ + ObjectPrx ice_timeout(int t); + + /** + * Creates a new proxy that is identical to this proxy, except for its connection ID. + * + * @param connectionId The connection ID for the new proxy. An empty string removes the + * connection ID. + * + * @return A new proxy with the specified connection ID. + **/ + ObjectPrx ice_connectionId(String connectionId); + + /** + * Returns the {@link Connection} for this proxy. If the proxy does not yet have an established connection, + * it first attempts to create a connection. + * + * @return The {@link Connection} for this proxy. + * @throws CollocationOptimizationException If the proxy uses collocation optimization and denotes a + * collocated object. + * + * @see Connection + **/ + Connection ice_getConnection(); + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_getConnection(); + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_getConnection(Callback __cb); + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @param __cb The callback object to notify the application when the operation is complete. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_getConnection(Callback_Object_ice_getConnection __cb); + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @param __responseCb The callback object to notify the application when there is a response available. + * @param __exceptionCb The callback object to notify the application when an exception occurs while getting + * the connection. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_getConnection(IceInternal.Functional_GenericCallback1<Ice.Connection> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb); + + /** + * Completes the asynchronous get connection. + * + * @param __result The asynchronous result. + **/ + Ice.Connection end_ice_getConnection(AsyncResult __result); + + /** + * Returns the cached {@link Connection} for this proxy. If the proxy does not yet have an established + * connection, it does not attempt to create a connection. + * + * @return The cached {@link Connection} for this proxy (<code>null</code> if the proxy does not have + * an established connection). + * @throws CollocationOptimizationException If the proxy uses collocation optimization and denotes a + * collocated object. + * + * @see Connection + **/ + Connection ice_getCachedConnection(); + + /** + * Flushes any pending batched requests for this communicator. The call blocks until the flush is complete. + **/ + void ice_flushBatchRequests(); + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_flushBatchRequests(); + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_flushBatchRequests(Callback __cb); + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @param __cb The callback object to notify the application when the flush is complete. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_flushBatchRequests(Callback_Object_ice_flushBatchRequests __cb); + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @param __responseCb The asynchronous completion callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + AsyncResult begin_ice_flushBatchRequests(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb); + + /** + * Completes the asynchronous flush request. + * + * @param __result The asynchronous result. + **/ + void end_ice_flushBatchRequests(AsyncResult __result); + + /** + * Returns whether this proxy equals the passed object. Two proxies are equal if they are equal in all respects, + * that is, if their object identity, endpoints timeout settings, and so on are all equal. + * + * @param r The object to compare this proxy with. + * @return <code>true</code> if this proxy is equal to <code>r</code>; <code>false</code>, otherwise. + **/ + @Override + boolean equals(java.lang.Object r); + + void __write(OutputStream os); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHelper.java b/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHelper.java new file mode 100644 index 00000000000..77c758ef68e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHelper.java @@ -0,0 +1,157 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for all proxy helpers. + **/ +public class ObjectPrxHelper extends ObjectPrxHelperBase +{ + /** + * Casts a proxy to {@link Ice.ObjectPrx}. This call contacts + * the server and will throw an Ice run-time exception if the target + * object does not exist or the server cannot be reached. + * + * @param b The proxy to cast to @{link Ice.ObjectPrx}. + * @return <code>b</code>. + **/ + public static ObjectPrx + checkedCast(Ice.ObjectPrx b) + { + return b; + } + + /** + * Casts a proxy to {@link Ice.ObjectPrx}. This call contacts + * the server and throws an Ice run-time exception if the target + * object does not exist or the server cannot be reached. + * + * @param b The proxy to cast to {@link Ice.ObjectPrx}. + * @param ctx The <code>Context</code> map for the invocation. + * @return <code>b</code>. + **/ + public static ObjectPrx + checkedCast(Ice.ObjectPrx b, java.util.Map<String, String> ctx) + { + return b; + } + + /** + * Creates a new proxy that is identical to the passed proxy, except + * for its facet. This call contacts + * the server and throws an Ice run-time exception if the target + * object does not exist, the specified facet does not exist, or the server cannot be reached. + * + * @param b The proxy to cast to {@link Ice.ObjectPrx}. + * @param f The facet for the new proxy. + * @return The new proxy with the specified facet. + **/ + public static ObjectPrx + checkedCast(Ice.ObjectPrx b, String f) + { + ObjectPrx d = null; + if(b != null) + { + Ice.ObjectPrx bb = b.ice_facet(f); + try + { + boolean ok = bb.ice_isA("::Ice::Object"); + assert(ok); + ObjectPrxHelper h = new ObjectPrxHelper(); + h.__copyFrom(bb); + d = h; + } + catch(Ice.FacetNotExistException ex) + { + } + } + return d; + } + + /** + * Creates a new proxy that is identical to the passed proxy, except + * for its facet. This call contacts + * the server and throws an Ice run-time exception if the target + * object does not exist, the specified facet does not exist, or the server cannot be reached. + * + * @param b The proxy to cast to {@link Ice.ObjectPrx}. + * @param f The facet for the new proxy. + * @param ctx The <code>Context</code> map for the invocation. + * @return The new proxy with the specified facet. + **/ + public static ObjectPrx + checkedCast(Ice.ObjectPrx b, String f, java.util.Map<String, String> ctx) + { + ObjectPrx d = null; + if(b != null) + { + Ice.ObjectPrx bb = b.ice_facet(f); + try + { + boolean ok = bb.ice_isA("::Ice::Object", ctx); + assert(ok); + ObjectPrxHelper h = new ObjectPrxHelper(); + h.__copyFrom(bb); + d = h; + } + catch(Ice.FacetNotExistException ex) + { + } + } + return d; + } + + /** + * Casts a proxy to {@link Ice.ObjectPrx}. This call does + * not contact the server and always succeeds. + * + * @param b The proxy to cast to {@link Ice.ObjectPrx}. + * @return <code>b</code>. + **/ + public static ObjectPrx + uncheckedCast(Ice.ObjectPrx b) + { + return b; + } + + /** + * Creates a new proxy that is identical to the passed proxy, except + * for its facet. This call does not contact the server and always succeeds. + * + * @param b The proxy to cast to {@link Ice.ObjectPrx}. + * @param f The facet for the new proxy. + * @return The new proxy with the specified facet. + **/ + public static ObjectPrx + uncheckedCast(Ice.ObjectPrx b, String f) + { + ObjectPrx d = null; + if(b != null) + { + Ice.ObjectPrx bb = b.ice_facet(f); + ObjectPrxHelper h = new ObjectPrxHelper(); + h.__copyFrom(bb); + d = h; + } + return d; + } + + /** + * Returns the Slice type id of the interface or class associated + * with this proxy class. + * + * @return the type id, "::Ice::Object" + **/ + public static String + ice_staticId() + { + return Ice.ObjectImpl.ice_staticId(); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHelperBase.java b/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHelperBase.java new file mode 100644 index 00000000000..fa60f0a62f2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHelperBase.java @@ -0,0 +1,3000 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +import java.util.LinkedList; +import java.util.List; + +import Ice.Instrumentation.InvocationObserver; +import IceInternal.RetryException; + +/** + * Base class for all proxies. + **/ +public class ObjectPrxHelperBase implements ObjectPrx, java.io.Serializable +{ + /** + * Returns a hash code for this proxy. + * + * @return The hash code. + **/ + @Override + public final int + hashCode() + { + return _reference.hashCode(); + } + + /** + * Returns the communicator that created this proxy. + * + * @return The communicator that created this proxy. + **/ + @Override + public final Communicator + ice_getCommunicator() + { + return _reference.getCommunicator(); + } + + /** + * Returns the stringified form of this proxy. + * + * @return The stringified proxy. + **/ + @Override + public final String + toString() + { + return _reference.toString(); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @return <code>true</code> if this proxy supports the specified interface; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isA(String __id) + { + return ice_isA(__id, null, false); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @return <code>true</code> if this proxy supports the specified interface; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isA(String __id, java.util.Map<String, String> __context) + { + return ice_isA(__id, __context, true); + } + + private static final String __ice_isA_name = "ice_isA"; + + private boolean + ice_isA(String __id, java.util.Map<String, String> __context, boolean __explicitCtx) + { + __checkTwowayOnly(__ice_isA_name); + return end_ice_isA(begin_ice_isA(__id, __context, __explicitCtx, true, null)); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id) + { + return begin_ice_isA(__id, null, false, false, null); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, java.util.Map<String, String> __context) + { + return begin_ice_isA(__id, __context, true, false, null); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, Callback __cb) + { + return begin_ice_isA(__id, null, false, false, __cb); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, java.util.Map<String, String> __context, Callback __cb) + { + return begin_ice_isA(__id, __context, true, false, __cb); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, Callback_Object_ice_isA __cb) + { + return begin_ice_isA(__id, null, false, false, __cb); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, java.util.Map<String, String> __context, Callback_Object_ice_isA __cb) + { + return begin_ice_isA(__id, __context, true, false, __cb); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_isA(__id, null, false, false, __responseCb, __exceptionCb, null); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_isA(__id, null, false, false, __responseCb, __exceptionCb, __sentCb); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, + java.util.Map<String, String> __context, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_isA(__id, __context, true, false, __responseCb, __exceptionCb, null); + } + + /** + * Tests whether this proxy supports a given interface. + * + * @param __id The Slice type ID of an interface. + * @param __context The <code>Context</code> map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_isA(String __id, + java.util.Map<String, String> __context, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_isA(__id, __context, true, false, __responseCb, __exceptionCb, __sentCb); + } + + private AsyncResult + begin_ice_isA(String __id, + java.util.Map<String, String> __context, + boolean __explicitCtx, + boolean __synchronous, + IceInternal.Functional_BoolCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_isA(__id, __context, __explicitCtx, __synchronous, + new IceInternal.Functional_TwowayCallbackBool(__responseCb, __exceptionCb, __sentCb) + { + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_isA_completed(this, __result); + } + }); + } + + private AsyncResult + begin_ice_isA(String __id, java.util.Map<String, String> __context, boolean __explicitCtx, + boolean __synchronous, IceInternal.CallbackBase __cb) + { + __checkAsyncTwowayOnly(__ice_isA_name); + IceInternal.OutgoingAsync __result = getOutgoingAsync(__ice_isA_name, __cb); + try + { + __result.prepare(__ice_isA_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); + OutputStream __os = __result.startWriteParams(Ice.FormatType.DefaultFormat); + __os.writeString(__id); + __result.endWriteParams(); + __result.invoke(); + } + catch(Exception __ex) + { + __result.abort(__ex); + } + return __result; + } + + /** + * Completes the asynchronous ice_isA request. + * + * @param __r The asynchronous result. + * @return <code>true</code> if this proxy supports the specified interface; <code>false</code>, otherwise. + **/ + @Override + public final boolean + end_ice_isA(AsyncResult __r) + { + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__r, this, __ice_isA_name); + try + { + if(!__result.__wait()) + { + try + { + __result.throwUserException(); + } + catch(UserException __ex) + { + throw new UnknownUserException(__ex.ice_id(), __ex); + } + } + boolean __ret; + InputStream __is = __result.startReadParams(); + __ret = __is.readBool(); + __result.endReadParams(); + return __ret; + } + finally + { + if(__result != null) + { + __result.cacheMessageBuffers(); + } + } + } + + static public void __ice_isA_completed(TwowayCallbackBool __cb, AsyncResult __result) + { + boolean __ret = false; + try + { + __ret = __result.getProxy().end_ice_isA(__result); + } + catch(LocalException __ex) + { + __cb.exception(__ex); + return; + } + catch(SystemException __ex) + { + __cb.exception(__ex); + return; + } + __cb.response(__ret); + } + + /** + * Tests whether the target object of this proxy can be reached. + **/ + @Override + public final void + ice_ping() + { + ice_ping(null, false); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The <code>Context</code> map for the invocation. + **/ + @Override + public final void + ice_ping(java.util.Map<String, String> __context) + { + ice_ping(__context, true); + } + + private static final String __ice_ping_name = "ice_ping"; + + private void + ice_ping(java.util.Map<String, String> __context, boolean __explicitCtx) + { + end_ice_ping(begin_ice_ping(__context, __explicitCtx, true, null)); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping() + { + return begin_ice_ping(null, false, false, null); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(java.util.Map<String, String> __context) + { + return begin_ice_ping(__context, true, false, null); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(Callback __cb) + { + return begin_ice_ping(null, false, false, __cb); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(java.util.Map<String, String> __context, Callback __cb) + { + return begin_ice_ping(__context, true, false, __cb); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(Callback_Object_ice_ping __cb) + { + return begin_ice_ping(null, false, false, __cb); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(java.util.Map<String, String> __context, Callback_Object_ice_ping __cb) + { + return begin_ice_ping(__context, true, false, __cb); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_ping(null, false, false, + new IceInternal.Functional_OnewayCallback(__responseCb, __exceptionCb, null)); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_ping(null, false, false, new IceInternal.Functional_OnewayCallback(__responseCb, + __exceptionCb, __sentCb)); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(java.util.Map<String, String> __context, + IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_ping(__context, true, false, new IceInternal.Functional_OnewayCallback(__responseCb, + __exceptionCb, null)); + } + + /** + * Tests whether the target object of this proxy can be reached. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ping(java.util.Map<String, String> __context, + IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_ping(__context, true, false, + new IceInternal.Functional_OnewayCallback(__responseCb, __exceptionCb, __sentCb)); + } + + private AsyncResult begin_ice_ping(java.util.Map<String, String> __context, boolean __explicitCtx, + boolean __synchronous, IceInternal.CallbackBase __cb) + { + IceInternal.OutgoingAsync __result = getOutgoingAsync(__ice_ping_name, __cb); + try + { + __result.prepare(__ice_ping_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); + __result.writeEmptyParams(); + __result.invoke(); + } + catch(Exception __ex) + { + __result.abort(__ex); + } + return __result; + } + + /** + * Completes the asynchronous ping request. + * + * @param __result The asynchronous result. + **/ + @Override + public final void + end_ice_ping(AsyncResult __result) + { + __end(__result, __ice_ping_name); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @return The Slice type IDs of the interfaces supported by the target object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + @Override + public final String[] + ice_ids() + { + return ice_ids(null, false); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The <code>Context</code> map for the invocation. + * @return The Slice type IDs of the interfaces supported by the target object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + @Override + public final String[] + ice_ids(java.util.Map<String, String> __context) + { + return ice_ids(__context, true); + } + + private static final String __ice_ids_name = "ice_ids"; + + private String[] + ice_ids(java.util.Map<String, String> __context, boolean __explicitCtx) + { + __checkTwowayOnly(__ice_id_name); + return end_ice_ids(begin_ice_ids(__context, __explicitCtx, true, null)); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids() + { + return begin_ice_ids(null, false, false, null); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(java.util.Map<String, String> __context) + { + return begin_ice_ids(__context, true, false, null); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(Callback __cb) + { + return begin_ice_ids(null, false, false,__cb); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(java.util.Map<String, String> __context, Callback __cb) + { + return begin_ice_ids(__context, true, false,__cb); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(Callback_Object_ice_ids __cb) + { + return begin_ice_ids(null, false, false,__cb); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(java.util.Map<String, String> __context, Callback_Object_ice_ids __cb) + { + return begin_ice_ids(__context, true, false,__cb); + } + + private class FunctionalCallback_Object_ice_ids extends IceInternal.Functional_TwowayCallbackArg1<String[]> + { + FunctionalCallback_Object_ice_ids(IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + super(__responseCb, __exceptionCb, __sentCb); + } + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_ids_completed(this, __result); + } + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_ids(null, false, false, new FunctionalCallback_Object_ice_ids(__responseCb, __exceptionCb, + null)); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_ids(null, false, false, new FunctionalCallback_Object_ice_ids(__responseCb, __exceptionCb, + __sentCb)); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_ids(__context, true, false, new FunctionalCallback_Object_ice_ids(__responseCb, __exceptionCb, + null)); + } + + /** + * Returns the Slice type IDs of the interfaces supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_ids(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String[]> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_ids(__context, true, false, + new FunctionalCallback_Object_ice_ids(__responseCb, __exceptionCb, __sentCb)); + } + + private AsyncResult begin_ice_ids(java.util.Map<String, String> __context, boolean __explicitCtx, + boolean __synchronous, IceInternal.CallbackBase __cb) + { + __checkAsyncTwowayOnly(__ice_ids_name); + IceInternal.OutgoingAsync __result = getOutgoingAsync(__ice_ids_name, __cb); + try + { + __result.prepare(__ice_ids_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); + __result.writeEmptyParams(); + __result.invoke(); + } + catch(Exception __ex) + { + __result.abort(__ex); + } + return __result; + } + + /** + * Completes the asynchronous ice_ids request. + * + * @param __r The asynchronous result. + * @return The Slice type IDs of the interfaces supported by the target object, in base-to-derived + * order. The first element of the returned array is always <code>::Ice::Object</code>. + **/ + @Override + public final String[] + end_ice_ids(AsyncResult __r) + { + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__r, this, __ice_ids_name); + try + { + if(!__result.__wait()) + { + try + { + __result.throwUserException(); + } + catch(UserException __ex) + { + throw new UnknownUserException(__ex.ice_id(), __ex); + } + } + String[] __ret = null; + InputStream __is = __result.startReadParams(); + __ret = StringSeqHelper.read(__is); + __result.endReadParams(); + return __ret; + } + finally + { + if(__result != null) + { + __result.cacheMessageBuffers(); + } + } + } + + static public void __ice_ids_completed(TwowayCallbackArg1<String[]> __cb, AsyncResult __result) + { + String[] __ret = null; + try + { + __ret = __result.getProxy().end_ice_ids(__result); + } + catch(LocalException __ex) + { + __cb.exception(__ex); + return; + } + catch(SystemException __ex) + { + __cb.exception(__ex); + return; + } + __cb.response(__ret); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @return The Slice type ID of the most-derived interface. + **/ + @Override + public final String + ice_id() + { + return ice_id(null, false); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The <code>Context</code> map for the invocation. + * @return The Slice type ID of the most-derived interface. + **/ + @Override + public final String + ice_id(java.util.Map<String, String> __context) + { + return ice_id(__context, true); + } + + private static final String __ice_id_name = "ice_id"; + + private String + ice_id(java.util.Map<String, String> __context, boolean __explicitCtx) + { + __checkTwowayOnly(__ice_id_name); + return end_ice_id(begin_ice_id(__context, __explicitCtx, true, null)); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id() + { + return begin_ice_id(null, false, false, null); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(java.util.Map<String, String> __context) + { + return begin_ice_id(__context, true, false, null); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(Callback __cb) + { + return begin_ice_id(null, false, false, __cb); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(java.util.Map<String, String> __context, Callback __cb) + { + return begin_ice_id(__context, true, false, __cb); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(Callback_Object_ice_id __cb) + { + return begin_ice_id(null, false, false, __cb); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(java.util.Map<String, String> __context, Callback_Object_ice_id __cb) + { + return begin_ice_id(__context, true, false, __cb); + } + + private class FunctionalCallback_Object_ice_id extends IceInternal.Functional_TwowayCallbackArg1<String> + { + FunctionalCallback_Object_ice_id(IceInternal.Functional_GenericCallback1<String> responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb, + IceInternal.Functional_BoolCallback sentCb) + { + super(responseCb, exceptionCb, sentCb); + } + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_id_completed(this, __result); + } + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_id(null, false, false, new FunctionalCallback_Object_ice_id(__responseCb, __exceptionCb, null)); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_id(null, false, false, new FunctionalCallback_Object_ice_id(__responseCb, __exceptionCb, __sentCb)); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_id(__context, true, false, new FunctionalCallback_Object_ice_id(__responseCb, __exceptionCb, null)); + } + + /** + * Returns the Slice type ID of the most-derived interface supported by the target object of this proxy. + * + * @param __context The context map for the invocation. + * @param __responseCb The asynchronous response callback object. + * @param __exceptionCb The asynchronous exception callback object. + * @param __sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + **/ + @Override + public final AsyncResult + begin_ice_id(java.util.Map<String, String> __context, + IceInternal.Functional_GenericCallback1<String> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_id(__context, true, false, + new FunctionalCallback_Object_ice_id(__responseCb, __exceptionCb, __sentCb)); + } + + private AsyncResult begin_ice_id(java.util.Map<String, String> __context, boolean __explicitCtx, + boolean __synchronous, IceInternal.CallbackBase __cb) + { + __checkAsyncTwowayOnly(__ice_id_name); + IceInternal.OutgoingAsync __result = getOutgoingAsync(__ice_id_name, __cb); + try + { + __result.prepare(__ice_id_name, OperationMode.Nonmutating, __context, __explicitCtx, __synchronous); + __result.writeEmptyParams(); + __result.invoke(); + } + catch(Exception __ex) + { + __result.abort(__ex); + } + return __result; + } + + /** + * Completes the asynchronous ice_id request. + * + * @param __r The asynchronous result. + * @return The Slice type ID of the most-derived interface. + **/ + @Override + public final String + end_ice_id(AsyncResult __r) + { + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__r, this, __ice_id_name); + try + { + if(!__result.__wait()) + { + try + { + __result.throwUserException(); + } + catch(UserException __ex) + { + throw new UnknownUserException(__ex.ice_id(), __ex); + } + } + String __ret = null; + InputStream __is = __result.startReadParams(); + __ret = __is.readString(); + __result.endReadParams(); + return __ret; + } + finally + { + if(__result != null) + { + __result.cacheMessageBuffers(); + } + } + } + + static public void __ice_id_completed(TwowayCallbackArg1<String> __cb, AsyncResult __result) + { + String __ret = null; + try + { + __ret = __result.getProxy().end_ice_id(__result); + } + catch(LocalException __ex) + { + __cb.exception(__ex); + return; + } + catch(SystemException __ex) + { + __cb.exception(__ex); + return; + } + __cb.response(__ret); + } + + /** + * Invoke an operation dynamically. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param outParams The encoded out-paramaters and return value + * for the operation. The return value follows any out-parameters. + * @return If the operation completed successfully, the return value + * is <code>true</code>. If the operation raises a user exception, + * the return value is <code>false</code>; in this case, <code>outParams</code> + * contains the encoded user exception. If the operation raised an + * it throws it directly. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final boolean + ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams) + { + return ice_invoke(operation, mode, inParams, outParams, null, false); + } + + /** + * Invoke an operation dynamically. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param outParams The encoded out-paramaters and return value + * for the operation. The return value follows any out-parameters. + * @param context The context map for the invocation. + * @return If the operation was invoked synchronously (because there + * was no need to queue the request), the return value is <code>true</code>; + * otherwise, if the invocation was queued, the return value is <code>false</code>. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final boolean + ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams, + java.util.Map<String, String> context) + { + return ice_invoke(operation, mode, inParams, outParams, context, true); + } + + private boolean + ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams, + java.util.Map<String, String> context, boolean explicitCtx) + { + return end_ice_invoke(outParams, begin_ice_invoke(operation, mode, inParams, context, explicitCtx, true, null)); + } + + private static final String __ice_invoke_name = "ice_invoke"; + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams) + { + return begin_ice_invoke(operation, mode, inParams, null, false, false, null); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context) + { + return begin_ice_invoke(operation, mode, inParams, __context, true, false, null); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, Callback __cb) + { + return begin_ice_invoke(operation, mode, inParams, null, false, false, __cb); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, java.util.Map<String, String> __context, + Callback __cb) + { + return begin_ice_invoke(operation, mode, inParams, __context, true, false, __cb); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, Callback_Object_ice_invoke __cb) + { + return begin_ice_invoke(operation, mode, inParams, null, false, false, __cb); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param __context The context map for the invocation. + * @param __cb The asynchronous callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, java.util.Map<String, String> __context, + Callback_Object_ice_invoke __cb) + { + return begin_ice_invoke(operation, mode, inParams, __context, true, false, __cb); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param responseCb The asynchronous response callback object. + * @param exceptionCb The asynchronous exception callback object. + * @param sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + FunctionalCallback_Object_ice_invoke_Response responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb, + IceInternal.Functional_BoolCallback sentCb) + { + return begin_ice_invoke(operation, mode, inParams, null, false, false, responseCb, exceptionCb, sentCb); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * for the operation. The return value follows any out-parameters. + * @param responseCb The asynchronous response callback object. + * @param exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + FunctionalCallback_Object_ice_invoke_Response responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb) + { + return begin_ice_invoke(operation, mode, inParams, null, false, false, responseCb, exceptionCb, null); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param context The context map for the invocation. + * for the operation. The return value follows any out-parameters. + * @param responseCb The asynchronous response callback object. + * @param exceptionCb The asynchronous exception callback object. + * @param sentCb The asynchronous sent callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> context, + FunctionalCallback_Object_ice_invoke_Response responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb, + IceInternal.Functional_BoolCallback sentCb) + { + return begin_ice_invoke(operation, mode, inParams, context, true, false, responseCb, exceptionCb, sentCb); + } + + /** + * Invokes an operation dynamically and asynchronously. + * + * @param operation The name of the operation to invoke. + * @param mode The operation mode (normal or idempotent). + * @param inParams The encoded in-parameters for the operation. + * @param context The context map for the invocation. + * for the operation. The return value follows any out-parameters. + * @param responseCb The asynchronous response callback object. + * @param exceptionCb The asynchronous exception callback object. + * @return The asynchronous result object. + * + * @see Blobject + * @see OperationMode + **/ + @Override + public final AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> context, + FunctionalCallback_Object_ice_invoke_Response responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb) + { + return begin_ice_invoke(operation, mode, inParams, context, true, false, responseCb, exceptionCb, null); + } + + private AsyncResult begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, + java.util.Map<String, String> __context, + boolean __explicitCtx, + boolean __synchronous, + FunctionalCallback_Object_ice_invoke_Response __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + class CB extends IceInternal.Functional_TwowayCallback implements _Callback_Object_ice_invoke + { + CB(FunctionalCallback_Object_ice_invoke_Response responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> exceptionCb, + IceInternal.Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + @Override + public void response(boolean __ret, byte[] outParams) + { + __responseCb.apply(__ret, outParams); + } + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_invoke_completed(this, __result); + } + + FunctionalCallback_Object_ice_invoke_Response __responseCb; + } + return begin_ice_invoke(operation, mode, inParams, __context, __explicitCtx, __synchronous, + new CB(__responseCb, __exceptionCb, __sentCb)); + } + + private AsyncResult + begin_ice_invoke(String operation, OperationMode mode, byte[] inParams, java.util.Map<String, String> __context, + boolean __explicitCtx, boolean __synchronous, IceInternal.CallbackBase __cb) + { + IceInternal.OutgoingAsync __result = getOutgoingAsync(__ice_invoke_name, __cb); + try + { + __result.prepare(operation, mode, __context, __explicitCtx, __synchronous); + __result.writeParamEncaps(inParams); + __result.invoke(); + } + catch(Exception __ex) + { + __result.abort(__ex); + } + return __result; + } + + /** + * Completes the asynchronous ice_invoke request. + * + * @param outParams The encoded out-paramaters and return value. + * @param __r The asynchronous result. + * @return If the operation completed successfully, the return value + * is <code>true</code>. If the operation raises a user exception, + * the return value is <code>false</code>; in this case, <code>outParams</code> + * contains the encoded user exception. If the operation raises a run-time exception, + * it throws it directly. + **/ + @Override + public final boolean + end_ice_invoke(ByteSeqHolder outParams, AsyncResult __r) + { + IceInternal.OutgoingAsync __result = IceInternal.OutgoingAsync.check(__r, this, __ice_invoke_name); + try + { + boolean ok = __result.__wait(); + if(_reference.getMode() == IceInternal.Reference.ModeTwoway) + { + if(outParams != null) + { + outParams.value = __result.readParamEncaps(); + } + } + return ok; + } + finally + { + if(__result != null) + { + __result.cacheMessageBuffers(); + } + } + } + + public static void __ice_invoke_completed(_Callback_Object_ice_invoke __cb, AsyncResult __result) + { + ByteSeqHolder outParams = new ByteSeqHolder(); + boolean __ret = false; + try + { + __ret = __result.getProxy().end_ice_invoke(outParams, __result); + } + catch(LocalException __ex) + { + __cb.exception(__ex); + return; + } + catch(SystemException __ex) + { + __cb.exception(__ex); + return; + } + __cb.response(__ret, outParams.value); + } + + /** + * Returns the identity embedded in this proxy. + * + * @return The identity of the target object. + **/ + @Override + public final Identity + ice_getIdentity() + { + return _reference.getIdentity().clone(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the identity. + * + * @param newIdentity The identity for the new proxy. + * @return The proxy with the new identity. + **/ + @Override + public final ObjectPrx + ice_identity(Identity newIdentity) + { + if(newIdentity.name.equals("")) + { + throw new IllegalIdentityException(); + } + if(newIdentity.equals(_reference.getIdentity())) + { + return this; + } + else + { + ObjectPrxHelperBase proxy = new ObjectPrxHelperBase(); + proxy.__setup(_reference.changeIdentity(newIdentity)); + return proxy; + } + } + + /** + * Returns the per-proxy context for this proxy. + * + * @return The per-proxy context. If the proxy does not have a per-proxy (implicit) context, the return value + * is <code>null</code>. + **/ + @Override + public final java.util.Map<String, String> + ice_getContext() + { + return new java.util.HashMap<String, String>(_reference.getContext()); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the per-proxy context. + * + * @param newContext The context for the new proxy. + * @return The proxy with the new per-proxy context. + **/ + @Override + public final ObjectPrx + ice_context(java.util.Map<String, String> newContext) + { + return newInstance(_reference.changeContext(newContext)); + } + + /** + * Returns the facet for this proxy. + * + * @return The facet for this proxy. If the proxy uses the default facet, the return value is the empty string. + **/ + @Override + public final String + ice_getFacet() + { + return _reference.getFacet(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the facet. + * + * @param newFacet The facet for the new proxy. + * @return The proxy with the new facet. + **/ + @Override + public final ObjectPrx + ice_facet(String newFacet) + { + if(newFacet == null) + { + newFacet = ""; + } + + if(newFacet.equals(_reference.getFacet())) + { + return this; + } + else + { + ObjectPrxHelperBase proxy = new ObjectPrxHelperBase(); + proxy.__setup(_reference.changeFacet(newFacet)); + return proxy; + } + } + + /** + * Returns the adapter ID for this proxy. + * + * @return The adapter ID. If the proxy does not have an adapter ID, the return value is the empty string. + **/ + @Override + public final String + ice_getAdapterId() + { + return _reference.getAdapterId(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the adapter ID. + * + * @param newAdapterId The adapter ID for the new proxy. + * @return The proxy with the new adapter ID. + **/ + @Override + public final ObjectPrx + ice_adapterId(String newAdapterId) + { + if(newAdapterId == null) + { + newAdapterId = ""; + } + + if(newAdapterId.equals(_reference.getAdapterId())) + { + return this; + } + else + { + return newInstance(_reference.changeAdapterId(newAdapterId)); + } + } + + /** + * Returns the endpoints used by this proxy. + * + * @return The endpoints used by this proxy. + * + * @see Endpoint + **/ + @Override + public final Endpoint[] + ice_getEndpoints() + { + return _reference.getEndpoints().clone(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the endpoints. + * + * @param newEndpoints The endpoints for the new proxy. + * @return The proxy with the new endpoints. + **/ + @Override + public final ObjectPrx + ice_endpoints(Endpoint[] newEndpoints) + { + if(java.util.Arrays.equals(newEndpoints, _reference.getEndpoints())) + { + return this; + } + else + { + IceInternal.EndpointI[] edpts = new IceInternal.EndpointI[newEndpoints.length]; + edpts = java.util.Arrays.asList(newEndpoints).toArray(edpts); + return newInstance(_reference.changeEndpoints(edpts)); + } + } + + /** + * Returns the locator cache timeout of this proxy. + * + * @return The locator cache timeout value (in seconds). + * + * @see Locator + **/ + @Override + public final int + ice_getLocatorCacheTimeout() + { + return _reference.getLocatorCacheTimeout(); + } + + /** + * Returns the invocation timeout of this proxy. + * + * @return The invocation timeout value (in seconds). + **/ + @Override + public final int + ice_getInvocationTimeout() + { + return _reference.getInvocationTimeout(); + } + + /** + * Returns the connection id of this proxy. + * + * @return The connection id. + * + **/ + @Override + public final String + ice_getConnectionId() + { + return _reference.getConnectionId(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the locator cache timeout. + * + * @param newTimeout The new locator cache timeout (in seconds). + * + * @see Locator + **/ + @Override + public final ObjectPrx + ice_locatorCacheTimeout(int newTimeout) + { + if(newTimeout < -1) + { + throw new IllegalArgumentException("invalid value passed to ice_locatorCacheTimeout: " + newTimeout); + } + if(newTimeout == _reference.getLocatorCacheTimeout()) + { + return this; + } + else + { + return newInstance(_reference.changeLocatorCacheTimeout(newTimeout)); + } + } + + /** + * Creates a new proxy that is identical to this proxy, except for the invocation timeout. + * + * @param newTimeout The new invocation timeout (in seconds). + **/ + @Override + public final ObjectPrx + ice_invocationTimeout(int newTimeout) + { + if(newTimeout < 1 && newTimeout != -1 && newTimeout != -2) + { + throw new IllegalArgumentException("invalid value passed to ice_invocationTimeout: " + newTimeout); + } + if(newTimeout == _reference.getInvocationTimeout()) + { + return this; + } + else + { + return newInstance(_reference.changeInvocationTimeout(newTimeout)); + } + } + + /** + * Returns whether this proxy caches connections. + * + * @return <code>true</code> if this proxy caches connections; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isConnectionCached() + { + return _reference.getCacheConnection(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for connection caching. + * + * @param newCache <code>true</code> if the new proxy should cache connections; <code>false</code>, otherwise. + * @return The new proxy with the specified caching policy. + **/ + @Override + public final ObjectPrx + ice_connectionCached(boolean newCache) + { + if(newCache == _reference.getCacheConnection()) + { + return this; + } + else + { + return newInstance(_reference.changeCacheConnection(newCache)); + } + } + + /** + * Returns how this proxy selects endpoints (randomly or ordered). + * + * @return The endpoint selection policy. + * + * @see EndpointSelectionType + **/ + @Override + public final Ice.EndpointSelectionType + ice_getEndpointSelection() + { + return _reference.getEndpointSelection(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for the endpoint selection policy. + * + * @param newType The new endpoint selection policy. + * @return The new proxy with the specified endpoint selection policy. + * + * @see EndpointSelectionType + **/ + @Override + public final ObjectPrx + ice_endpointSelection(Ice.EndpointSelectionType newType) + { + if(newType == _reference.getEndpointSelection()) + { + return this; + } + else + { + return newInstance(_reference.changeEndpointSelection(newType)); + } + } + + /** + * Returns whether this proxy uses only secure endpoints. + * + * @return <code>true</code> if all endpoints for this proxy are secure; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isSecure() + { + return _reference.getSecure(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for its endpoints. + * + * @param b If <code>b</code> is <code>true</code>, only endpoints that use a secure transport are + * retained for the new proxy. If <code>b</code> is false, the returned proxy is identical to this proxy. + * @return The new proxy with possible different endpoints.k + **/ + @Override + public final ObjectPrx + ice_secure(boolean b) + { + if(b == _reference.getSecure()) + { + return this; + } + else + { + return newInstance(_reference.changeSecure(b)); + } + } + + /** + * Creates a new proxy that is identical to this proxy, except for the encoding used to marshal + * parameters. + * + * @param e The encoding version to use to marshal requests parameters. + * @return The new proxy with the specified encoding version. + **/ + @Override + public final ObjectPrx + ice_encodingVersion(Ice.EncodingVersion e) + { + if(e.equals(_reference.getEncoding())) + { + return this; + } + else + { + return newInstance(_reference.changeEncoding(e)); + } + } + + /** + * Returns the encoding version used to marshal requests parameters. + * + * @return The encoding version. + **/ + @Override + public final Ice.EncodingVersion + ice_getEncodingVersion() + { + return _reference.getEncoding().clone(); + } + + /** + * Returns whether this proxy prefers secure endpoints. + * + * @return <code>true</code> if the proxy always attempts to invoke via secure endpoints before it + * attempts to use insecure endpoints; <code>false</code>, otherwise; + **/ + @Override + public final boolean + ice_isPreferSecure() + { + return _reference.getPreferSecure(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for its endpoint selection policy. + * + * @param b If <code>b</code> is <code>true</code>, the new proxy will use secure endpoints for invocations + * and only use insecure endpoints if an invocation cannot be made via secure endpoints. If <code>b</code> is + * <code>false</code>, the proxy prefers insecure endpoints to secure ones. + * @return The new proxy with the new endpoint selection policy. + **/ + @Override + public final ObjectPrx + ice_preferSecure(boolean b) + { + if(b == _reference.getPreferSecure()) + { + return this; + } + else + { + return newInstance(_reference.changePreferSecure(b)); + } + } + + /** + * Returns the router for this proxy. + * + * @return The router for the proxy. If no router is configured for the proxy, the return value + * is <code>null</code>. + **/ + @Override + public final Ice.RouterPrx + ice_getRouter() + { + IceInternal.RouterInfo ri = _reference.getRouterInfo(); + return ri != null ? ri.getRouter() : null; + } + + /** + * Creates a new proxy that is identical to this proxy, except for the router. + * + * @param router The router for the new proxy. + * @return The new proxy with the specified router. + **/ + @Override + public final ObjectPrx + ice_router(Ice.RouterPrx router) + { + IceInternal.Reference ref = _reference.changeRouter(router); + if(ref.equals(_reference)) + { + return this; + } + else + { + return newInstance(ref); + } + } + + /** + * Returns the locator for this proxy. + * + * @return The locator for this proxy. If no locator is configured, the return value is <code>null</code>. + **/ + @Override + public final Ice.LocatorPrx + ice_getLocator() + { + IceInternal.LocatorInfo ri = _reference.getLocatorInfo(); + return ri != null ? ri.getLocator() : null; + } + + /** + * Creates a new proxy that is identical to this proxy, except for the locator. + * + * @param locator The locator for the new proxy. + * @return The new proxy with the specified locator. + **/ + @Override + public final ObjectPrx + ice_locator(Ice.LocatorPrx locator) + { + IceInternal.Reference ref = _reference.changeLocator(locator); + if(ref.equals(_reference)) + { + return this; + } + else + { + return newInstance(ref); + } + } + + /** + * Returns whether this proxy uses collocation optimization. + * + * @return <code>true</code> if the proxy uses collocation optimization; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isCollocationOptimized() + { + return _reference.getCollocationOptimized(); + } + + /** + * Creates a new proxy that is identical to this proxy, except for collocation optimization. + * + * @param b <code>true</code> if the new proxy enables collocation optimization; <code>false</code>, otherwise. + * @return The new proxy the specified collocation optimization. + **/ + @Override + public final ObjectPrx + ice_collocationOptimized(boolean b) + { + if(b == _reference.getCollocationOptimized()) + { + return this; + } + else + { + return newInstance(_reference.changeCollocationOptimized(b)); + } + } + + /** + * Creates a new proxy that is identical to this proxy, but uses twoway invocations. + * + * @return A new proxy that uses twoway invocations. + **/ + @Override + public final ObjectPrx + ice_twoway() + { + if(_reference.getMode() == IceInternal.Reference.ModeTwoway) + { + return this; + } + else + { + return newInstance(_reference.changeMode(IceInternal.Reference.ModeTwoway)); + } + } + + /** + * Returns whether this proxy uses twoway invocations. + * @return <code>true</code> if this proxy uses twoway invocations; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isTwoway() + { + return _reference.getMode() == IceInternal.Reference.ModeTwoway; + } + + /** + * Creates a new proxy that is identical to this proxy, but uses oneway invocations. + * + * @return A new proxy that uses oneway invocations. + **/ + @Override + public final ObjectPrx + ice_oneway() + { + if(_reference.getMode() == IceInternal.Reference.ModeOneway) + { + return this; + } + else + { + return newInstance(_reference.changeMode(IceInternal.Reference.ModeOneway)); + } + } + + /** + * Returns whether this proxy uses oneway invocations. + * @return <code>true</code> if this proxy uses oneway invocations; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isOneway() + { + return _reference.getMode() == IceInternal.Reference.ModeOneway; + } + + /** + * Creates a new proxy that is identical to this proxy, but uses batch oneway invocations. + * + * @return A new proxy that uses batch oneway invocations. + **/ + @Override + public final ObjectPrx + ice_batchOneway() + { + if(_reference.getMode() == IceInternal.Reference.ModeBatchOneway) + { + return this; + } + else + { + return newInstance(_reference.changeMode(IceInternal.Reference.ModeBatchOneway)); + } + } + + /** + * Returns whether this proxy uses batch oneway invocations. + * @return <code>true</code> if this proxy uses batch oneway invocations; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isBatchOneway() + { + return _reference.getMode() == IceInternal.Reference.ModeBatchOneway; + } + + /** + * Creates a new proxy that is identical to this proxy, but uses datagram invocations. + * + * @return A new proxy that uses datagram invocations. + **/ + @Override + public final ObjectPrx + ice_datagram() + { + if(_reference.getMode() == IceInternal.Reference.ModeDatagram) + { + return this; + } + else + { + return newInstance(_reference.changeMode(IceInternal.Reference.ModeDatagram)); + } + } + + /** + * Returns whether this proxy uses datagram invocations. + * @return <code>true</code> if this proxy uses datagram invocations; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isDatagram() + { + return _reference.getMode() == IceInternal.Reference.ModeDatagram; + } + + /** + * Creates a new proxy that is identical to this proxy, but uses batch datagram invocations. + * + * @return A new proxy that uses batch datagram invocations. + **/ + @Override + public final ObjectPrx + ice_batchDatagram() + { + if(_reference.getMode() == IceInternal.Reference.ModeBatchDatagram) + { + return this; + } + else + { + return newInstance(_reference.changeMode(IceInternal.Reference.ModeBatchDatagram)); + } + } + + /** + * Returns whether this proxy uses batch datagram invocations. + * @return <code>true</code> if this proxy uses batch datagram invocations; <code>false</code>, otherwise. + **/ + @Override + public final boolean + ice_isBatchDatagram() + { + return _reference.getMode() == IceInternal.Reference.ModeBatchDatagram; + } + + /** + * Creates a new proxy that is identical to this proxy, except for compression. + * + * @param co <code>true</code> enables compression for the new proxy; <code>false</code>disables compression. + * @return A new proxy with the specified compression setting. + **/ + @Override + public final ObjectPrx + ice_compress(boolean co) + { + IceInternal.Reference ref = _reference.changeCompress(co); + if(ref.equals(_reference)) + { + return this; + } + else + { + return newInstance(ref); + } + } + + /** + * Creates a new proxy that is identical to this proxy, except for its timeout setting. + * + * @param t The timeout for the new proxy in milliseconds. + * @return A new proxy with the specified timeout. + **/ + @Override + public final ObjectPrx + ice_timeout(int t) + { + if(t < 1 && t != -1) + { + throw new IllegalArgumentException("invalid value passed to ice_timeout: " + t); + } + IceInternal.Reference ref = _reference.changeTimeout(t); + if(ref.equals(_reference)) + { + return this; + } + else + { + return newInstance(ref); + } + } + + /** + * Creates a new proxy that is identical to this proxy, except for its connection ID. + * + * @param id The connection ID for the new proxy. An empty string removes the + * connection ID. + * + * @return A new proxy with the specified connection ID. + **/ + @Override + public final ObjectPrx + ice_connectionId(String id) + { + IceInternal.Reference ref = _reference.changeConnectionId(id); + if(ref.equals(_reference)) + { + return this; + } + else + { + return newInstance(ref); + } + } + + /** + * Returns the {@link Connection} for this proxy. If the proxy does not yet have an established connection, + * it first attempts to create a connection. + * + * @return The {@link Connection} for this proxy. + * @throws CollocationOptimizationException If the proxy uses collocation optimization and denotes a + * collocated object. + * + * @see Connection + **/ + @Override + public final Connection + ice_getConnection() + { + return end_ice_getConnection(begin_ice_getConnection()); + } + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_getConnection() + { + return begin_ice_getConnectionInternal(null); + } + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @param __cb The callback object to notify the application when the flush is complete. + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_getConnection(Callback __cb) + { + return begin_ice_getConnectionInternal(__cb); + } + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @param __cb The callback object to notify the application when the flush is complete. + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_getConnection(Callback_Object_ice_getConnection __cb) + { + return begin_ice_getConnectionInternal(__cb); + } + + private class FunctionalCallback_Object_ice_getConnection + extends IceInternal.Functional_TwowayCallbackArg1<Ice.Connection> + { + FunctionalCallback_Object_ice_getConnection( + IceInternal.Functional_GenericCallback1<Ice.Connection> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + super(__responseCb, __exceptionCb, null); + } + + @Override + public final void __completed(AsyncResult __result) + { + ObjectPrxHelperBase.__ice_getConnection_completed(this, __result); + } + } + + /** + * Asynchronously gets the connection for this proxy. The call does not block. + * + * @param __responseCb The callback object to notify the application when the there is a response available. + * @param __exceptionCb The callback object to notify the application when the there is an exception getting + * connection. + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_getConnection(IceInternal.Functional_GenericCallback1<Ice.Connection> __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb) + { + return begin_ice_getConnectionInternal( + new FunctionalCallback_Object_ice_getConnection(__responseCb, __exceptionCb)); + } + + private static final String __ice_getConnection_name = "ice_getConnection"; + + private AsyncResult + begin_ice_getConnectionInternal(IceInternal.CallbackBase cb) + { + IceInternal.ProxyGetConnection result = new IceInternal.ProxyGetConnection(this, __ice_getConnection_name, cb); + try + { + result.invoke(); + } + catch(Exception ex) + { + result.abort(ex); + } + return result; + } + + @Override + public Ice.Connection + end_ice_getConnection(AsyncResult r) + { + IceInternal.ProxyGetConnection result = IceInternal.ProxyGetConnection.check(r, this, __ice_getConnection_name); + result.__wait(); + return result.getConnection(); + } + + static public void __ice_getConnection_completed(TwowayCallbackArg1<Ice.Connection> cb, AsyncResult result) + { + Ice.Connection ret = null; + try + { + ret = result.getProxy().end_ice_getConnection(result); + } + catch(LocalException ex) + { + cb.exception(ex); + return; + } + catch(SystemException ex) + { + cb.exception(ex); + return; + } + cb.response(ret); + } + + /** + * Returns the cached {@link Connection} for this proxy. If the proxy does not yet have an established + * connection, it does not attempt to create a connection. + * + * @return The cached {@link Connection} for this proxy (<code>null</code> if the proxy does not have + * an established connection). + * @throws CollocationOptimizationException If the proxy uses collocation optimization and denotes a + * collocated object. + * + * @see Connection + **/ + @Override + public final Connection + ice_getCachedConnection() + { + IceInternal.RequestHandler handler = null; + synchronized(this) + { + handler = _requestHandler; + } + + if(handler != null) + { + try + { + return handler.getConnection(); + } + catch(LocalException ex) + { + } + } + return null; + } + + /** + * Flushes any pending batched requests for this communicator. The call blocks until the flush is complete. + **/ + @Override + public void + ice_flushBatchRequests() + { + end_ice_flushBatchRequests(begin_ice_flushBatchRequests()); + } + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_flushBatchRequests() + { + return begin_ice_flushBatchRequestsInternal(null); + } + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @param __cb The callback object to notify the application when the flush is complete. + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_flushBatchRequests(Callback __cb) + { + return begin_ice_flushBatchRequestsInternal(__cb); + } + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @param __cb The callback object to notify the application when the flush is complete. + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_flushBatchRequests(Callback_Object_ice_flushBatchRequests __cb) + { + return begin_ice_flushBatchRequestsInternal(__cb); + } + + /** + * Asynchronously flushes any pending batched requests for this communicator. The call does not block. + * + * @param __exceptionCb The callback object to notify the application when the there is an exception flushing + * the requests. + * @param __sentCb The callback object to notify the application when the flush is complete. + * @return The asynchronous result object. + **/ + @Override + public AsyncResult + begin_ice_flushBatchRequests(IceInternal.Functional_VoidCallback __responseCb, + IceInternal.Functional_GenericCallback1<Ice.Exception> __exceptionCb, + IceInternal.Functional_BoolCallback __sentCb) + { + return begin_ice_flushBatchRequestsInternal( + new IceInternal.Functional_OnewayCallback(__responseCb, __exceptionCb, __sentCb)); + } + + private static final String __ice_flushBatchRequests_name = "ice_flushBatchRequests"; + + private AsyncResult + begin_ice_flushBatchRequestsInternal(IceInternal.CallbackBase cb) + { + IceInternal.ProxyFlushBatch result = new IceInternal.ProxyFlushBatch(this, __ice_flushBatchRequests_name, cb); + try + { + result.invoke(); + } + catch(Exception ex) + { + result.abort(ex); + } + return result; + } + + @Override + public void + end_ice_flushBatchRequests(AsyncResult r) + { + IceInternal.ProxyFlushBatch result = IceInternal.ProxyFlushBatch.check(r, this, __ice_flushBatchRequests_name); + result.__wait(); + } + + /** + * Returns whether this proxy equals the passed object. Two proxies are equal if they are equal in all respects, + * that is, if their object identity, endpoints timeout settings, and so on are all equal. + * + * @param r The object to compare this proxy with. + * @return <code>true</code> if this proxy is equal to <code>r</code>; <code>false</code>, otherwise. + **/ + @Override + public final boolean + equals(java.lang.Object r) + { + if(this == r) + { + return true; + } + + if(r instanceof ObjectPrxHelperBase) + { + return _reference.equals(((ObjectPrxHelperBase)r)._reference); + } + + return false; + } + + public void __write(OutputStream os) + { + _reference.getIdentity().__write(os); + _reference.streamWrite(os); + } + + public final IceInternal.Reference + __reference() + { + return _reference; + } + + public final void + __copyFrom(ObjectPrx from) + { + synchronized(from) + { + ObjectPrxHelperBase h = (ObjectPrxHelperBase)from; + _reference = h._reference; + _requestHandler = h._requestHandler; + } + } + + public final int + __handleException(Exception ex, IceInternal.RequestHandler handler, OperationMode mode, boolean sent, + Holder<Integer> interval, int cnt) + { + __updateRequestHandler(handler, null); // Clear the request handler + + // + // We only retry local exception, system exceptions aren't retried. + // + // A CloseConnectionException indicates graceful server shutdown, and is therefore + // always repeatable without violating "at-most-once". That's because by sending a + // close connection message, the server guarantees that all outstanding requests + // can safely be repeated. + // + // An ObjectNotExistException can always be retried as well without violating + // "at-most-once" (see the implementation of the checkRetryAfterException method + // of the ProxyFactory class for the reasons why it can be useful). + // + // If the request didn't get sent or if it's non-mutating or idempotent it can + // also always be retried if the retry count isn't reached. + // + if(ex instanceof LocalException && (!sent || + mode == OperationMode.Nonmutating || mode == OperationMode.Idempotent || + ex instanceof CloseConnectionException || + ex instanceof ObjectNotExistException)) + { + try + { + return _reference.getInstance().proxyFactory().checkRetryAfterException((LocalException)ex, + _reference, + interval, + cnt); + } + catch(CommunicatorDestroyedException exc) + { + // + // The communicator is already destroyed, so we cannot retry. + // + throw ex; + } + } + else + { + throw ex; // Retry could break at-most-once semantics, don't retry. + } + } + + public final void + __checkTwowayOnly(String name) + { + // + // No mutex lock necessary, there is nothing mutable in this + // operation. + // + + if(!ice_isTwoway()) + { + TwowayOnlyException ex = new TwowayOnlyException(); + ex.operation = name; + throw ex; + } + } + + public final void + __checkAsyncTwowayOnly(String name) + { + // + // No mutex lock necessary, there is nothing mutable in this + // operation. + // + + if(!ice_isTwoway()) + { + throw new java.lang.IllegalArgumentException("`" + name + "' can only be called with a twoway proxy"); + } + } + + public final void + __end(AsyncResult r, String operation) + { + IceInternal.ProxyOutgoingAsyncBase result = IceInternal.ProxyOutgoingAsyncBase.check(r, this, operation); + try + { + boolean ok = result.__wait(); + if(_reference.getMode() == IceInternal.Reference.ModeTwoway) + { + IceInternal.OutgoingAsync outAsync = (IceInternal.OutgoingAsync)result; + if(!ok) + { + try + { + outAsync.throwUserException(); + } + catch(UserException ex) + { + throw new UnknownUserException(ex.ice_id(), ex); + } + } + outAsync.readEmptyParams(); + } + } + finally + { + if(result != null) + { + result.cacheMessageBuffers(); + } + } + } + + public final IceInternal.RequestHandler + __getRequestHandler() + { + if(_reference.getCacheConnection()) + { + synchronized(this) + { + if(_requestHandler != null) + { + return _requestHandler; + } + } + } + return _reference.getRequestHandler(this); + } + + synchronized public final IceInternal.BatchRequestQueue + __getBatchRequestQueue() + { + if(_batchRequestQueue == null) + { + _batchRequestQueue = _reference.getBatchRequestQueue(); + } + return _batchRequestQueue; + } + + public IceInternal.RequestHandler + __setRequestHandler(IceInternal.RequestHandler handler) + { + if(_reference.getCacheConnection()) + { + synchronized(this) + { + if(_requestHandler == null) + { + _requestHandler = handler; + } + return _requestHandler; + } + } + return handler; + } + + public void + __updateRequestHandler(IceInternal.RequestHandler previous, IceInternal.RequestHandler handler) + { + if(_reference.getCacheConnection() && previous != null) + { + synchronized(this) + { + if(_requestHandler != null && _requestHandler != handler) + { + // + // Update the request handler only if "previous" is the same + // as the current request handler. This is called after + // connection binding by the connect request handler. We only + // replace the request handler if the current handler is the + // connect request handler. + // + _requestHandler = _requestHandler.update(previous, handler); + } + } + } + } + + public void + cacheMessageBuffers(InputStream is, OutputStream os) + { + synchronized(this) + { + if(_streamCache == null) + { + _streamCache = new LinkedList<StreamCacheEntry>(); + } + _streamCache.add(new StreamCacheEntry(is, os)); + } + } + + // + // Only for use by IceInternal.ProxyFactory + // + public final void + __setup(IceInternal.Reference ref) + { + // + // No need to synchronize, as this operation is only called + // upon initial initialization. + // + + assert(_reference == null); + assert(_requestHandler == null); + + _reference = ref; + } + + protected static <T> T checkedCastImpl(Ice.ObjectPrx obj, String id, Class<T> proxyCls, Class<?> helperCls) + { + return checkedCastImpl(obj, null, false, null, false, id, proxyCls, helperCls); + } + + protected static <T> T checkedCastImpl(Ice.ObjectPrx obj, java.util.Map<String, String> ctx, String id, + Class<T> proxyCls, Class<?> helperCls) + { + return checkedCastImpl(obj, ctx, true, null, false, id, proxyCls, helperCls); + } + + protected static <T> T checkedCastImpl(Ice.ObjectPrx obj, String facet, String id, Class<T> proxyCls, + Class<?> helperCls) + { + return checkedCastImpl(obj, null, false, facet, true, id, proxyCls, helperCls); + } + + protected static <T> T checkedCastImpl(Ice.ObjectPrx obj, String facet, java.util.Map<String, String> ctx, + String id, Class<T> proxyCls, Class<?> helperCls) + { + return checkedCastImpl(obj, ctx, true, facet, true, id, proxyCls, helperCls); + } + + protected static <T> T checkedCastImpl(Ice.ObjectPrx obj, java.util.Map<String, String> ctx, boolean explicitCtx, + String facet, boolean explicitFacet, String id, Class<T> proxyCls, + Class<?> helperCls) + { + T d = null; + if(obj != null) + { + if(explicitFacet) + { + obj = obj.ice_facet(facet); + } + if(proxyCls.isInstance(obj)) + { + d = proxyCls.cast(obj); + } + else + { + try + { + final boolean b = explicitCtx ? obj.ice_isA(id, ctx) : obj.ice_isA(id); + if(b) + { + ObjectPrxHelperBase h = null; + try + { + h = ObjectPrxHelperBase.class.cast(helperCls.newInstance()); + } + catch(InstantiationException ex) + { + throw new SyscallException(ex); + } + catch(IllegalAccessException ex) + { + throw new SyscallException(ex); + } + h.__copyFrom(obj); + d = proxyCls.cast(h); + } + } + catch(FacetNotExistException ex) + { + } + } + } + return d; + } + + protected static <T> T uncheckedCastImpl(Ice.ObjectPrx obj, Class<T> proxyCls, Class<?> helperCls) + { + return uncheckedCastImpl(obj, null, false, proxyCls, helperCls); + } + + protected static <T> T uncheckedCastImpl(Ice.ObjectPrx obj, String facet, Class<T> proxyCls, Class<?> helperCls) + { + return uncheckedCastImpl(obj, facet, true, proxyCls, helperCls); + } + + protected static <T> T uncheckedCastImpl(Ice.ObjectPrx obj, String facet, boolean explicitFacet, Class<T> proxyCls, + Class<?> helperCls) + { + T d = null; + if(obj != null) + { + try + { + if(explicitFacet) + { + ObjectPrxHelperBase h = ObjectPrxHelperBase.class.cast(helperCls.newInstance()); + h.__copyFrom(obj.ice_facet(facet)); + d = proxyCls.cast(h); + } + else + { + if(proxyCls.isInstance(obj)) + { + d = proxyCls.cast(obj); + } + else + { + ObjectPrxHelperBase h = ObjectPrxHelperBase.class.cast(helperCls.newInstance()); + h.__copyFrom(obj); + d = proxyCls.cast(h); + } + } + } + catch(InstantiationException ex) + { + throw new SyscallException(ex); + } + catch(IllegalAccessException ex) + { + throw new SyscallException(ex); + } + } + return d; + } + + protected IceInternal.OutgoingAsync + getOutgoingAsync(String operation, IceInternal.CallbackBase cb) + { + StreamCacheEntry cacheEntry = null; + if(_reference.getInstance().cacheMessageBuffers() > 0) + { + synchronized(this) + { + if(_streamCache != null && !_streamCache.isEmpty()) + { + cacheEntry = _streamCache.remove(0); + } + } + } + if(cacheEntry == null) + { + return new IceInternal.OutgoingAsync(this, operation, cb); + } + else + { + return new IceInternal.OutgoingAsync(this, operation, cb, cacheEntry.is, cacheEntry.os); + } + } + + private ObjectPrxHelperBase + newInstance(IceInternal.Reference ref) + { + try + { + ObjectPrxHelperBase proxy = getClass().newInstance(); + proxy.__setup(ref); + return proxy; + } + catch(InstantiationException e) + { + // + // Impossible + // + assert false; + return null; + } + catch(IllegalAccessException e) + { + // + // Impossible + // + assert false; + return null; + } + } + + private void + writeObject(java.io.ObjectOutputStream out) + throws java.io.IOException + { + out.writeUTF(toString()); + } + + private void + readObject(java.io.ObjectInputStream in) + throws java.io.IOException, ClassNotFoundException + { + String s = in.readUTF(); + try + { + Communicator communicator = ((Ice.ObjectInputStream)in).getCommunicator(); + if(communicator == null) + { + throw new java.io.IOException("Cannot deserialize proxy: no communicator provided"); + } + ObjectPrxHelperBase proxy = (ObjectPrxHelperBase)communicator.stringToProxy(s); + _reference = proxy._reference; + assert(proxy._requestHandler == null); + } + catch(ClassCastException ex) + { + java.io.IOException e = + new java.io.IOException("Cannot deserialize proxy: Ice.ObjectInputStream not found"); + e.initCause(ex); + throw e; + } + catch(LocalException ex) + { + java.io.IOException e = new java.io.IOException("Failure occurred while deserializing proxy"); + e.initCause(ex); + throw e; + } + } + + private static class StreamCacheEntry + { + StreamCacheEntry(InputStream is, OutputStream os) + { + this.is = is; + this.os = os; + } + + InputStream is; + OutputStream os; + } + + private transient IceInternal.Reference _reference; + private transient IceInternal.RequestHandler _requestHandler; + private transient IceInternal.BatchRequestQueue _batchRequestQueue; + private transient List<StreamCacheEntry> _streamCache; + public static final long serialVersionUID = 0L; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHolder.java b/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHolder.java new file mode 100644 index 00000000000..eb61958e123 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectPrxHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for proxies that are out- or inout-parameters. + **/ +public final class ObjectPrxHolder extends Holder<ObjectPrx> +{ + /** + * Instantiates the class with a <code>null</code> proxy. + **/ + public + ObjectPrxHolder() + { + } + + /** + * Instantiates the class with the passed proxy. + * + * @param value The proxy stored this holder. + **/ + public + ObjectPrxHolder(ObjectPrx value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectReader.java b/java-compat/src/Ice/src/main/java/Ice/ObjectReader.java new file mode 100644 index 00000000000..488986f98af --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectReader.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for extracting objects from an input stream. + **/ +public abstract class ObjectReader extends ObjectImpl +{ + /** + * Reads the state of this Slice class from an input stream. + * + * @param in The input stream to read from. + **/ + public abstract void read(InputStream in); + + @Override + public void __write(OutputStream os) + { + assert(false); + } + + @Override + public void __read(InputStream is) + { + read(is); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ObjectWriter.java b/java-compat/src/Ice/src/main/java/Ice/ObjectWriter.java new file mode 100644 index 00000000000..91e474477a7 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ObjectWriter.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for writing Slice classes to an output stream. + **/ +public abstract class ObjectWriter extends ObjectImpl +{ + /** + * Writes the state of this Slice class to an output stream. + * + * @param out The stream to write to. + **/ + public abstract void write(OutputStream out); + + @Override + public void __write(OutputStream os) + { + write(os); + } + + @Override + public void __read(Ice.InputStream is) + { + assert(false); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/OnewayCallback.java b/java-compat/src/Ice/src/main/java/Ice/OnewayCallback.java new file mode 100644 index 00000000000..76405d95605 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/OnewayCallback.java @@ -0,0 +1,77 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for generated oneway operation callback. + **/ +public abstract class OnewayCallback extends IceInternal.CallbackBase +{ + /** + * Called when the invocation response is received. + **/ + public abstract void response(); + + /** + * Called when the invocation raises an Ice run-time exception. + * + * @param ex The Ice run-time exception raised by the operation. + **/ + public abstract void exception(LocalException ex); + + /** + * Called when the invocation raises an Ice system exception. + * + * @param ex The Ice system exception raised by the operation. + **/ + public void exception(SystemException ex) + { + exception(new Ice.UnknownException(ex)); + } + + /** + * Called when a queued invocation is sent successfully. + **/ + public void sent(boolean sentSynchronously) + { + } + + @Override + public final void __sent(AsyncResult __result) + { + sent(__result.sentSynchronously()); + } + + @Override + public final boolean __hasSentCallback() + { + return true; + } + + @Override + public final void __completed(AsyncResult __result) + { + try + { + ((ObjectPrxHelperBase)__result.getProxy()).__end(__result, __result.getOperation()); + } + catch(LocalException __ex) + { + exception(__ex); + return; + } + catch(SystemException __ex) + { + exception(__ex); + return; + } + response(); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Optional.java b/java-compat/src/Ice/src/main/java/Ice/Optional.java new file mode 100644 index 00000000000..b906e31def0 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Optional.java @@ -0,0 +1,202 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Generic class for optional parameters. + **/ +public class Optional<T> +{ + /** + * The value defaults to unset. + **/ + public Optional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public Optional(T v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public Optional(Optional<T> opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public T get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(T v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(Optional<T> opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = null; + } + + /** + * Helper function for creating Optional instances. + * + * @param v The initial value of the Optional. + * + * @return A new Optional instance set to the given value. + **/ + public static <T> Optional<T> O(T v) + { + return new Optional<T>(v); + } + + /** + * Helper function for creating BooleanOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new BooleanOptional instance set to the given value. + **/ + public static BooleanOptional O(boolean v) + { + return new BooleanOptional(v); + } + + /** + * Helper function for creating ByteOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new ByteOptional instance set to the given value. + **/ + public static ByteOptional O(byte v) + { + return new ByteOptional(v); + } + + /** + * Helper function for creating ShortOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new ShortOptional instance set to the given value. + **/ + public static ShortOptional O(short v) + { + return new ShortOptional(v); + } + + /** + * Helper function for creating IntOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new IntOptional instance set to the given value. + **/ + public static IntOptional O(int v) + { + return new IntOptional(v); + } + + /** + * Helper function for creating LongOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new LongOptional instance set to the given value. + **/ + public static LongOptional O(long v) + { + return new LongOptional(v); + } + + /** + * Helper function for creating FloatOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new FloatOptional instance set to the given value. + **/ + public static FloatOptional O(float v) + { + return new FloatOptional(v); + } + + /** + * Helper function for creating DoubleOptional instances. + * + * @param v The initial value of the Optional. + * + * @return A new DoubleOptional instance set to the given value. + **/ + public static DoubleOptional O(double v) + { + return new DoubleOptional(v); + } + + private T _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/OptionalFormat.java b/java-compat/src/Ice/src/main/java/Ice/OptionalFormat.java new file mode 100644 index 00000000000..2c68b26ea4f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/OptionalFormat.java @@ -0,0 +1,70 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * The optional type. + * + * An optional value is encoded with a specific optional format. This optional + * format describes how the data is encoded and how it can be skipped by the + * unmarshaling code if the optional is not known to the receiver. + * + **/ +public enum OptionalFormat +{ + F1(0), + F2(1), + F4(2), + F8(3), + Size(4), + VSize(5), + FSize(6), + Class(7); + + private + OptionalFormat(int value) + { + _value = value; + } + + public int + value() + { + return _value; + } + + public static OptionalFormat + valueOf(int v) + { + switch(v) + { + case 0: + return F1; + case 1: + return F2; + case 2: + return F4; + case 3: + return F8; + case 4: + return Size; + case 5: + return VSize; + case 6: + return FSize; + case 7: + return Class; + default: + throw new IllegalArgumentException(); + } + } + + private int _value; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/OptionalObject.java b/java-compat/src/Ice/src/main/java/Ice/OptionalObject.java new file mode 100644 index 00000000000..cbb1c27384c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/OptionalObject.java @@ -0,0 +1,70 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Handles callbacks for an optional object parameter. + **/ +public class OptionalObject implements ReadValueCallback +{ + /** + * Instantiates the class with the given optional. + * + * @param opt The target optional. + * @param cls The formal type required for the unmarshaled object. + * @param type The Slice type ID corresponding to the formal type. + **/ + @SuppressWarnings("rawtypes") + public + OptionalObject(Optional opt, Class<?> cls, String type) + { + this.opt = opt; + this.cls = cls; + this.type = type; + } + + /** + * Sets the value of the optional to the passed instance. + * + * @param v The new value for the optional. + **/ + @SuppressWarnings("unchecked") + public void + valueReady(Ice.Object v) + { + if(v == null || cls.isInstance(v)) + { + // + // The line below would normally cause an "unchecked cast" warning. + // + opt.set(v); + } + else + { + IceInternal.Ex.throwUOE(type, v); + } + } + + /** + * The optional object. + **/ + @SuppressWarnings("rawtypes") + public Optional opt; + + /** + * The formal type of the target class. + **/ + public Class<?> cls; + + /** + * The Slice type ID of the target class. + **/ + public String type; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/OutputStream.java b/java-compat/src/Ice/src/main/java/Ice/OutputStream.java new file mode 100644 index 00000000000..c2a028d15a6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/OutputStream.java @@ -0,0 +1,2426 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public class OutputStream +{ + /** + * Constructing an OutputStream without providing a communicator means the stream will + * use the default encoding version, the default format for class encoding, and a + * non-direct buffer. You can supply a communicator later by calling initialize(). + **/ + public OutputStream() + { + this(false); + } + + /** + * Constructing an OutputStream without providing a communicator means the stream will + * use the default encoding version and the default format for class encoding. + * You can supply a communicator later by calling initialize(). + * + * @param direct Indicates whether to use a direct buffer. + **/ + public OutputStream(boolean direct) + { + _buf = new IceInternal.Buffer(direct); + _instance = null; + _closure = null; + _encoding = IceInternal.Protocol.currentEncoding; + _format = FormatType.CompactFormat; + } + + /** + * This constructor uses the communicator's default encoding version. + * + * @param communicator The communicator to use when initializing the stream. + **/ + public OutputStream(Communicator communicator) + { + assert(communicator != null); + final IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, instance.defaultsAndOverrides().defaultEncoding, instance.cacheMessageBuffers() > 1); + } + + /** + * This constructor uses the communicator's default encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param direct Indicates whether to use a direct buffer. + **/ + public OutputStream(Communicator communicator, boolean direct) + { + assert(communicator != null); + final IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, instance.defaultsAndOverrides().defaultEncoding, direct); + } + + /** + * This constructor uses the given communicator and encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired Ice encoding version. + **/ + public OutputStream(Communicator communicator, EncodingVersion encoding) + { + assert(communicator != null); + final IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, encoding, instance.cacheMessageBuffers() > 1); + } + + /** + * This constructor uses the given communicator and encoding version. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired Ice encoding version. + * @param direct Indicates whether to use a direct buffer. + **/ + public OutputStream(Communicator communicator, EncodingVersion encoding, boolean direct) + { + assert(communicator != null); + final IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, encoding, direct); + } + + public OutputStream(IceInternal.Instance instance, EncodingVersion encoding) + { + initialize(instance, encoding, instance.cacheMessageBuffers() > 1); + } + + public OutputStream(IceInternal.Instance instance, EncodingVersion encoding, boolean direct) + { + initialize(instance, encoding, direct); + } + + public OutputStream(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf, boolean adopt) + { + initialize(instance, encoding, new IceInternal.Buffer(buf, adopt)); + } + + /** + * Initializes the stream to use the communicator's default encoding version and class + * encoding format. + * + * @param communicator The communicator to use when initializing the stream. + **/ + public void initialize(Communicator communicator) + { + assert(communicator != null); + final IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, instance.defaultsAndOverrides().defaultEncoding, instance.cacheMessageBuffers() > 1); + } + + /** + * Initializes the stream to use the given encoding version and the communicator's + * default class encoding format. + * + * @param communicator The communicator to use when initializing the stream. + * @param encoding The desired Ice encoding version. + **/ + public void initialize(Communicator communicator, EncodingVersion encoding) + { + assert(communicator != null); + final IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + initialize(instance, encoding, instance.cacheMessageBuffers() > 1); + } + + private void initialize(IceInternal.Instance instance, EncodingVersion encoding, boolean direct) + { + initialize(instance, encoding, new IceInternal.Buffer(direct)); + } + + private void initialize(IceInternal.Instance instance, EncodingVersion encoding, IceInternal.Buffer buf) + { + assert(instance != null); + + _instance = instance; + _buf = buf; + _closure = null; + _encoding = encoding; + + _format = _instance.defaultsAndOverrides().defaultFormat; + + _encapsStack = null; + _encapsCache = null; + } + + /** + * Resets this output stream. This method allows the stream to be reused, to avoid creating + * unnecessary garbage. + **/ + public void reset() + { + _buf.reset(); + clear(); + } + + /** + * Releases any data retained by encapsulations. The {@link #reset} method internally calls </code>clear</code>. + **/ + public void clear() + { + if(_encapsStack != null) + { + assert(_encapsStack.next == null); + _encapsStack.next = _encapsCache; + _encapsCache = _encapsStack; + _encapsCache.reset(); + _encapsStack = null; + } + } + + public IceInternal.Instance instance() + { + return _instance; + } + + /** + * Sets the encoding format for class and exception instances. + * + * @param fmt The encoding format. + **/ + public void setFormat(FormatType fmt) + { + _format = fmt; + } + + /** + * Retrieves the closure object associated with this stream. + * + * @return The closure object. + **/ + public Object getClosure() + { + return _closure; + } + + /** + * Associates a closure object with this stream. + * + * @param p The new closure object. + * @return The previous closure object, or null. + **/ + public Object setClosure(Object p) + { + Object prev = _closure; + _closure = p; + return prev; + } + + /** + * Indicates that marshaling is finished. + * + * @return The byte sequence containing the encoded data. + **/ + public byte[] finished() + { + IceInternal.Buffer buf = prepareWrite(); + byte[] result = new byte[buf.b.limit()]; + buf.b.get(result); + return result; + } + + /** + * Swaps the contents of one stream with another. + * + * @param other The other stream. + **/ + public void swap(OutputStream other) + { + assert(_instance == other._instance); + + IceInternal.Buffer tmpBuf = other._buf; + other._buf = _buf; + _buf = tmpBuf; + + EncodingVersion tmpEncoding = other._encoding; + other._encoding = _encoding; + _encoding = tmpEncoding; + + Object tmpClosure = other._closure; + other._closure = _closure; + _closure = tmpClosure; + + // + // Swap is never called for streams that have encapsulations being written. However, + // encapsulations might still be set in case marshalling failed. We just + // reset the encapsulations if there are still some set. + // + resetEncapsulation(); + other.resetEncapsulation(); + } + + private void resetEncapsulation() + { + _encapsStack = null; + } + + /** + * Resizes the stream to a new size. + * + * @param sz The new size. + **/ + public void resize(int sz) + { + _buf.resize(sz, false); + _buf.b.position(sz); + } + + /** + * Prepares the internal data buffer to be written to a socket. + **/ + public IceInternal.Buffer prepareWrite() + { + _buf.b.limit(_buf.size()); + _buf.b.position(0); + return _buf; + } + + /** + * Retrieves the internal data buffer. + * + * @return The buffer. + **/ + public IceInternal.Buffer getBuffer() + { + return _buf; + } + + /** + * Marks the start of a class instance. + * + * @param data Preserved slices for this instance, or null. + **/ + public void startValue(SlicedData data) + { + assert(_encapsStack != null && _encapsStack.encoder != null); + _encapsStack.encoder.startInstance(SliceType.ValueSlice, data); + } + + /** + * Marks the end of a class instance. + **/ + public void endValue() + { + assert(_encapsStack != null && _encapsStack.encoder != null); + _encapsStack.encoder.endInstance(); + } + + /** + * Marks the start of a user exception. + * + * @param data Preserved slices for this exception, or null. + **/ + public void startException(SlicedData data) + { + assert(_encapsStack != null && _encapsStack.encoder != null); + _encapsStack.encoder.startInstance(SliceType.ExceptionSlice, data); + } + + /** + * Marks the end of a user exception. + **/ + public void endException() + { + assert(_encapsStack != null && _encapsStack.encoder != null); + _encapsStack.encoder.endInstance(); + } + + /** + * Writes the start of an encapsulation to the stream. + **/ + public void startEncapsulation() + { + // + // If no encoding version is specified, use the current write + // encapsulation encoding version if there's a current write + // encapsulation, otherwise, use the stream encoding version. + // + + if(_encapsStack != null) + { + startEncapsulation(_encapsStack.encoding, _encapsStack.format); + } + else + { + startEncapsulation(_encoding, FormatType.DefaultFormat); + } + } + + /** + * Writes the start of an encapsulation to the stream. + * + * @param encoding The encoding version of the encapsulation. + * + * @param format Specify the compact or sliced format. + * + **/ + public void startEncapsulation(EncodingVersion encoding, FormatType format) + { + IceInternal.Protocol.checkSupportedEncoding(encoding); + + Encaps curr = _encapsCache; + if(curr != null) + { + curr.reset(); + _encapsCache = _encapsCache.next; + } + else + { + curr = new Encaps(); + } + curr.next = _encapsStack; + _encapsStack = curr; + + _encapsStack.format = format; + _encapsStack.setEncoding(encoding); + _encapsStack.start = _buf.size(); + + writeInt(0); // Placeholder for the encapsulation length. + _encapsStack.encoding.__write(this); + } + + /** + * Ends the previous encapsulation. + **/ + public void endEncapsulation() + { + assert(_encapsStack != null); + + // Size includes size and version. + int start = _encapsStack.start; + int sz = _buf.size() - start; + _buf.b.putInt(start, sz); + + Encaps curr = _encapsStack; + _encapsStack = curr.next; + curr.next = _encapsCache; + _encapsCache = curr; + _encapsCache.reset(); + } + + /** + * Writes an empty encapsulation using the given encoding version. + * + * @param encoding The desired encoding version. + **/ + public void writeEmptyEncapsulation(EncodingVersion encoding) + { + IceInternal.Protocol.checkSupportedEncoding(encoding); + writeInt(6); // Size + encoding.__write(this); + } + + /** + * Writes a pre-encoded encapsulation. + * + * @param v The encapsulation data. + **/ + public void writeEncapsulation(byte[] v) + { + if(v.length < 6) + { + throw new EncapsulationException(); + } + expand(v.length); + _buf.b.put(v); + } + + /** + * Determines the current encoding version. + * + * @return The encoding version. + **/ + public EncodingVersion getEncoding() + { + return _encapsStack != null ? _encapsStack.encoding : _encoding; + } + + /** + * Marks the start of a new slice for a class instance or user exception. + * + * @param typeId The Slice type ID corresponding to this slice. + + * @param compactId The Slice compact type ID corresponding to + * this slice or -1 if no compact ID is defined for the + * type ID. + + * @param last True if this is the last slice, false otherwise. + **/ + public void startSlice(String typeId, int compactId, boolean last) + { + assert(_encapsStack != null && _encapsStack.encoder != null); + _encapsStack.encoder.startSlice(typeId, compactId, last); + } + + /** + * Marks the end of a slice for a class instance or user exception. + **/ + public void endSlice() + { + assert(_encapsStack != null && _encapsStack.encoder != null); + _encapsStack.encoder.endSlice(); + } + + /** + * Writes the state of Slice classes whose index was previously + * written with {@link #writeValue} to the stream. + **/ + public void writePendingValues() + { + if(_encapsStack != null && _encapsStack.encoder != null) + { + _encapsStack.encoder.writePendingValues(); + } + else if(_encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.equals(Util.Encoding_1_0)) + { + // + // If using the 1.0 encoding and no instances were written, we + // still write an empty sequence for pending instances if + // requested (i.e.: if this is called). + // + // This is required by the 1.0 encoding, even if no instances + // are written we do marshal an empty sequence if marshaled + // data types use classes. + // + writeSize(0); + } + } + + /** + * Writes a size to the stream. + * + * @param v The size to write. + **/ + public void writeSize(int v) + { + if(v > 254) + { + expand(5); + _buf.b.put((byte)-1); + _buf.b.putInt(v); + } + else + { + expand(1); + _buf.b.put((byte)v); + } + } + + /** + * Returns the current position and allocates four bytes for a fixed-length (32-bit) + * size value. + * + * @return The current position. + **/ + public int startSize() + { + int pos = _buf.b.position(); + writeInt(0); // Placeholder for 32-bit size + return pos; + } + + /** + * Computes the amount of data written since the previous call to startSize and + * writes that value at the saved position. + * + * @param pos The saved position. + **/ + public void endSize(int pos) + { + assert(pos >= 0); + rewriteInt(_buf.b.position() - pos - 4, pos); + } + + /** + * Writes a blob of bytes to the stream. + * + * @param v The byte array to be written. All of the bytes in the array are written. + **/ + public void writeBlob(byte[] v) + { + if(v == null) + { + return; + } + expand(v.length); + _buf.b.put(v); + } + + /** + * Writes a blob of bytes to the stream. + * + * @param v The byte array to be written. + * @param off The offset into the byte array from which to copy. + * @param len The number of bytes from the byte array to copy. + **/ + public void writeBlob(byte[] v, int off, int len) + { + if(v == null) + { + return; + } + expand(len); + _buf.b.put(v, off, len); + } + + /** + * Write the header information for an optional value. + * + * @param tag The numeric tag associated with the value. + * @param format The optional format of the value. + **/ + public boolean writeOptional(int tag, OptionalFormat format) + { + assert(_encapsStack != null); + if(_encapsStack.encoder != null) + { + return _encapsStack.encoder.writeOptional(tag, format); + } + else + { + return writeOptionalImpl(tag, format); + } + } + + /** + * Writes a byte to the stream. + * + * @param v The byte to write to the stream. + **/ + public void writeByte(byte v) + { + expand(1); + _buf.b.put(v); + } + + /** + * Writes an optional byte to the stream. + * + * @param tag The optional tag. + * @param v The optional byte to write to the stream. + **/ + public void writeByte(int tag, ByteOptional v) + { + if(v != null && v.isSet()) + { + writeByte(tag, v.get()); + } + } + + /** + * Writes an optional byte to the stream. + * + * @param tag The optional tag. + * @param v The byte to write to the stream. + **/ + public void writeByte(int tag, byte v) + { + if(writeOptional(tag, OptionalFormat.F1)) + { + writeByte(v); + } + } + + /** + * Writes a byte to the stream at the given position. The current position of the stream is not modified. + * + * @param v The byte to write to the stream. + * @param dest The position at which to store the byte in the buffer. + **/ + public void rewriteByte(byte v, int dest) + { + _buf.b.put(dest, v); + } + + /** + * Writes a byte sequence to the stream. + * + * @param v The byte sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeByteSeq(byte[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length); + _buf.b.put(v); + } + } + + /** + * Writes an optional byte sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional byte sequence to write to the stream. + **/ + public void writeByteSeq(int tag, Optional<byte[]> v) + { + if(v != null && v.isSet()) + { + writeByteSeq(tag, v.get()); + } + } + + /** + * Writes an optional byte sequence to the stream. + * + * @param tag The optional tag. + * @param v The byte sequence to write to the stream. + **/ + public void writeByteSeq(int tag, byte[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeByteSeq(v); + } + } + + /** + * Writes the remaining contents of the byte buffer as a byte sequence to the stream. + * + * @param v The byte buffer to write to the stream. + **/ + public void writeByteBuffer(java.nio.ByteBuffer v) + { + if(v == null || v.remaining() == 0) + { + writeSize(0); + } + else + { + writeSize(v.remaining()); + expand(v.remaining()); + _buf.b.put(v); + } + } + + /** + * Writes a serializable Java object to the stream. + * + * @param o The serializable object to write. + **/ + public void writeSerializable(java.io.Serializable o) + { + if(o == null) + { + writeSize(0); + return; + } + try + { + IceInternal.OutputStreamWrapper w = new IceInternal.OutputStreamWrapper(this); + java.io.ObjectOutputStream out = new java.io.ObjectOutputStream(w); + out.writeObject(o); + out.close(); + w.close(); + } + catch(java.lang.Exception ex) + { + throw new MarshalException("cannot serialize object: " + ex); + } + } + + /** + * Writes a boolean to the stream. + * + * @param v The boolean to write to the stream. + **/ + public void writeBool(boolean v) + { + expand(1); + _buf.b.put(v ? (byte)1 : (byte)0); + } + + /** + * Writes an optional boolean to the stream. + * + * @param tag The optional tag. + * @param v The optional boolean to write to the stream. + **/ + public void writeBool(int tag, BooleanOptional v) + { + if(v != null && v.isSet()) + { + writeBool(tag, v.get()); + } + } + + /** + * Writes an optional boolean to the stream. + * + * @param tag The optional tag. + * @param v The boolean to write to the stream. + **/ + public void writeBool(int tag, boolean v) + { + if(writeOptional(tag, OptionalFormat.F1)) + { + writeBool(v); + } + } + + /** + * Writes a boolean to the stream at the given position. The current position of the stream is not modified. + * + * @param v The boolean to write to the stream. + * @param dest The position at which to store the boolean in the buffer. + **/ + public void rewriteBool(boolean v, int dest) + { + _buf.b.put(dest, v ? (byte)1 : (byte)0); + } + + /** + * Writes a boolean sequence to the stream. + * + * @param v The boolean sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeBoolSeq(boolean[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length); + for(boolean b : v) + { + _buf.b.put(b ? (byte)1 : (byte)0); + } + } + } + + /** + * Writes an optional boolean sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional boolean sequence to write to the stream. + **/ + public void writeBoolSeq(int tag, Optional<boolean[]> v) + { + if(v != null && v.isSet()) + { + writeBoolSeq(tag, v.get()); + } + } + + /** + * Writes an optional boolean sequence to the stream. + * + * @param tag The optional tag. + * @param v The boolean sequence to write to the stream. + **/ + public void writeBoolSeq(int tag, boolean[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeBoolSeq(v); + } + } + + /** + * Writes a short to the stream. + * + * @param v The short to write to the stream. + **/ + public void writeShort(short v) + { + expand(2); + _buf.b.putShort(v); + } + + /** + * Writes an optional short to the stream. + * + * @param tag The optional tag. + * @param v The optional short to write to the stream. + **/ + public void writeShort(int tag, ShortOptional v) + { + if(v != null && v.isSet()) + { + writeShort(tag, v.get()); + } + } + + /** + * Writes an optional short to the stream. + * + * @param tag The optional tag. + * @param v The short to write to the stream. + **/ + public void writeShort(int tag, short v) + { + if(writeOptional(tag, OptionalFormat.F2)) + { + writeShort(v); + } + } + + /** + * Writes a short sequence to the stream. + * + * @param v The short sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeShortSeq(short[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length * 2); + java.nio.ShortBuffer shortBuf = _buf.b.asShortBuffer(); + shortBuf.put(v); + _buf.b.position(_buf.b.position() + v.length * 2); + } + } + + /** + * Writes an optional short sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional short sequence to write to the stream. + **/ + public void writeShortSeq(int tag, Optional<short[]> v) + { + if(v != null && v.isSet()) + { + writeShortSeq(tag, v.get()); + } + } + + /** + * Writes an optional short sequence to the stream. + * + * @param tag The optional tag. + * @param v The short sequence to write to the stream. + **/ + public void writeShortSeq(int tag, short[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeSize(v == null || v.length == 0 ? 1 : v.length * 2 + (v.length > 254 ? 5 : 1)); + writeShortSeq(v); + } + } + + /** + * Writes the remaining contents of the short buffer as a short sequence to the stream. + * + * @param v The short buffer to write to the stream. + **/ + public void writeShortBuffer(java.nio.ShortBuffer v) + { + if(v == null || v.remaining() == 0) + { + writeSize(0); + } + else + { + int sz = v.remaining(); + writeSize(sz); + expand(sz * 2); + + java.nio.ShortBuffer shortBuf = _buf.b.asShortBuffer(); + shortBuf.put(v); + _buf.b.position(_buf.b.position() + sz * 2); + } + } + + /** + * Writes an int to the stream. + * + * @param v The int to write to the stream. + **/ + public void writeInt(int v) + { + expand(4); + _buf.b.putInt(v); + } + + /** + * Writes an optional int to the stream. + * + * @param tag The optional tag. + * @param v The optional int to write to the stream. + **/ + public void writeInt(int tag, IntOptional v) + { + if(v != null && v.isSet()) + { + writeInt(tag, v.get()); + } + } + + /** + * Writes an optional int to the stream. + * + * @param tag The optional tag. + * @param v The int to write to the stream. + **/ + public void writeInt(int tag, int v) + { + if(writeOptional(tag, OptionalFormat.F4)) + { + writeInt(v); + } + } + + /** + * Writes an int to the stream at the given position. The current position of the stream is not modified. + * + * @param v The int to write to the stream. + * @param dest The position at which to store the int in the buffer. + **/ + public void rewriteInt(int v, int dest) + { + _buf.b.putInt(dest, v); + } + + /** + * Writes an int sequence to the stream. + * + * @param v The int sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeIntSeq(int[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length * 4); + java.nio.IntBuffer intBuf = _buf.b.asIntBuffer(); + intBuf.put(v); + _buf.b.position(_buf.b.position() + v.length * 4); + } + } + + /** + * Writes an optional int sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional int sequence to write to the stream. + **/ + public void writeIntSeq(int tag, Optional<int[]> v) + { + if(v != null && v.isSet()) + { + writeIntSeq(tag, v.get()); + } + } + + /** + * Writes an optional int sequence to the stream. + * + * @param tag The optional tag. + * @param v The int sequence to write to the stream. + **/ + public void writeIntSeq(int tag, int[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeSize(v == null || v.length == 0 ? 1 : v.length * 4 + (v.length > 254 ? 5 : 1)); + writeIntSeq(v); + } + } + + /** + * Writes the remaining contents of the int buffer as an int sequence to the stream. + * + * @param v The int buffer to write to the stream. + **/ + public void writeIntBuffer(java.nio.IntBuffer v) + { + if(v == null || v.remaining() == 0) + { + writeSize(0); + } + else + { + int sz = v.remaining(); + writeSize(sz); + expand(sz * 4); + + java.nio.IntBuffer intBuf = _buf.b.asIntBuffer(); + intBuf.put(v); + _buf.b.position(_buf.b.position() + sz * 4); + } + } + + /** + * Writes a long to the stream. + * + * @param v The long to write to the stream. + **/ + public void writeLong(long v) + { + expand(8); + _buf.b.putLong(v); + } + + /** + * Writes an optional long to the stream. + * + * @param tag The optional tag. + * @param v The optional long to write to the stream. + **/ + public void writeLong(int tag, LongOptional v) + { + if(v != null && v.isSet()) + { + writeLong(tag, v.get()); + } + } + + /** + * Writes an optional long to the stream. + * + * @param tag The optional tag. + * @param v The long to write to the stream. + **/ + public void writeLong(int tag, long v) + { + if(writeOptional(tag, OptionalFormat.F8)) + { + writeLong(v); + } + } + + /** + * Writes a long sequence to the stream. + * + * @param v The long sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeLongSeq(long[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length * 8); + java.nio.LongBuffer longBuf = _buf.b.asLongBuffer(); + longBuf.put(v); + _buf.b.position(_buf.b.position() + v.length * 8); + } + } + + /** + * Writes an optional long sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional long sequence to write to the stream. + **/ + public void writeLongSeq(int tag, Optional<long[]> v) + { + if(v != null && v.isSet()) + { + writeLongSeq(tag, v.get()); + } + } + + /** + * Writes an optional long sequence to the stream. + * + * @param tag The optional tag. + * @param v The long sequence to write to the stream. + **/ + public void writeLongSeq(int tag, long[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeSize(v == null || v.length == 0 ? 1 : v.length * 8 + (v.length > 254 ? 5 : 1)); + writeLongSeq(v); + } + } + + /** + * Writes the remaining contents of the long buffer as a long sequence to the stream. + * + * @param v The long buffer to write to the stream. + **/ + public void writeLongBuffer(java.nio.LongBuffer v) + { + if(v == null || v.remaining() == 0) + { + writeSize(0); + } + else + { + int sz = v.remaining(); + writeSize(sz); + expand(sz * 8); + + java.nio.LongBuffer longBuf = _buf.b.asLongBuffer(); + longBuf.put(v); + _buf.b.position(_buf.b.position() + sz * 8); + } + } + + /** + * Writes a float to the stream. + * + * @param v The float to write to the stream. + **/ + public void writeFloat(float v) + { + expand(4); + _buf.b.putFloat(v); + } + + /** + * Writes an optional float to the stream. + * + * @param tag The optional tag. + * @param v The optional float to write to the stream. + **/ + public void writeFloat(int tag, FloatOptional v) + { + if(v != null && v.isSet()) + { + writeFloat(tag, v.get()); + } + } + + /** + * Writes an optional float to the stream. + * + * @param tag The optional tag. + * @param v The float to write to the stream. + **/ + public void writeFloat(int tag, float v) + { + if(writeOptional(tag, OptionalFormat.F4)) + { + writeFloat(v); + } + } + + /** + * Writes a float sequence to the stream. + * + * @param v The float sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeFloatSeq(float[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length * 4); + java.nio.FloatBuffer floatBuf = _buf.b.asFloatBuffer(); + floatBuf.put(v); + _buf.b.position(_buf.b.position() + v.length * 4); + } + } + + /** + * Writes an optional float sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional float sequence to write to the stream. + **/ + public void writeFloatSeq(int tag, Optional<float[]> v) + { + if(v != null && v.isSet()) + { + writeFloatSeq(tag, v.get()); + } + } + + /** + * Writes an optional float sequence to the stream. + * + * @param tag The optional tag. + * @param v The float sequence to write to the stream. + **/ + public void writeFloatSeq(int tag, float[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeSize(v == null || v.length == 0 ? 1 : v.length * 4 + (v.length > 254 ? 5 : 1)); + writeFloatSeq(v); + } + } + + /** + * Writes the remaining contents of the float buffer as a float sequence to the stream. + * + * @param v The float buffer to write to the stream. + **/ + public void writeFloatBuffer(java.nio.FloatBuffer v) + { + if(v == null || v.remaining() == 0) + { + writeSize(0); + } + else + { + int sz = v.remaining(); + writeSize(sz); + expand(sz * 4); + + java.nio.FloatBuffer floatBuf = _buf.b.asFloatBuffer(); + floatBuf.put(v); + _buf.b.position(_buf.b.position() + sz * 4); + } + } + + /** + * Writes a double to the stream. + * + * @param v The double to write to the stream. + **/ + public void writeDouble(double v) + { + expand(8); + _buf.b.putDouble(v); + } + + /** + * Writes an optional double to the stream. + * + * @param tag The optional tag. + * @param v The optional double to write to the stream. + **/ + public void writeDouble(int tag, DoubleOptional v) + { + if(v != null && v.isSet()) + { + writeDouble(tag, v.get()); + } + } + + /** + * Writes an optional double to the stream. + * + * @param tag The optional tag. + * @param v The double to write to the stream. + **/ + public void writeDouble(int tag, double v) + { + if(writeOptional(tag, OptionalFormat.F8)) + { + writeDouble(v); + } + } + + /** + * Writes a double sequence to the stream. + * + * @param v The double sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeDoubleSeq(double[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + expand(v.length * 8); + java.nio.DoubleBuffer doubleBuf = _buf.b.asDoubleBuffer(); + doubleBuf.put(v); + _buf.b.position(_buf.b.position() + v.length * 8); + } + } + + /** + * Writes an optional double sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional double sequence to write to the stream. + **/ + public void writeDoubleSeq(int tag, Optional<double[]> v) + { + if(v != null && v.isSet()) + { + writeDoubleSeq(tag, v.get()); + } + } + + /** + * Writes an optional double sequence to the stream. + * + * @param tag The optional tag. + * @param v The double sequence to write to the stream. + **/ + public void writeDoubleSeq(int tag, double[] v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeSize(v == null || v.length == 0 ? 1 : v.length * 8 + (v.length > 254 ? 5 : 1)); + writeDoubleSeq(v); + } + } + + /** + * Writes the remaining contents of the double buffer as a double sequence to the stream. + * + * @param v The double buffer to write to the stream. + **/ + public void writeDoubleBuffer(java.nio.DoubleBuffer v) + { + if(v == null || v.remaining() == 0) + { + writeSize(0); + } + else + { + int sz = v.remaining(); + writeSize(sz); + expand(sz * 8); + + java.nio.DoubleBuffer doubleBuf = _buf.b.asDoubleBuffer(); + doubleBuf.put(v); + _buf.b.position(_buf.b.position() + sz * 8); + } + } + + final static java.nio.charset.Charset _utf8 = java.nio.charset.Charset.forName("UTF8"); + private java.nio.charset.CharsetEncoder _charEncoder = null; + + /** + * Writes a string to the stream. + * + * @param v The string to write to the stream. Passing <code>null</code> causes + * an empty string to be written to the stream. + **/ + public void writeString(String v) + { + if(v == null) + { + writeSize(0); + } + else + { + final int len = v.length(); + if(len > 0) + { + if(_stringBytes == null || len > _stringBytes.length) + { + _stringBytes = new byte[len]; + } + if(_stringChars == null || len > _stringChars.length) + { + _stringChars = new char[len]; + } + // + // If the string contains only 7-bit characters, it's more efficient + // to perform the conversion to UTF-8 manually. + // + v.getChars(0, len, _stringChars, 0); + for(int i = 0; i < len; ++i) + { + if(_stringChars[i] > (char)127) + { + // + // Found a multibyte character. + // + if(_charEncoder == null) + { + _charEncoder = _utf8.newEncoder(); + } + java.nio.ByteBuffer b = null; + try + { + b = _charEncoder.encode(java.nio.CharBuffer.wrap(_stringChars, 0, len)); + } + catch(java.nio.charset.CharacterCodingException ex) + { + throw new MarshalException(ex); + } + writeSize(b.limit()); + expand(b.limit()); + _buf.b.put(b); + return; + } + _stringBytes[i] = (byte)_stringChars[i]; + } + writeSize(len); + expand(len); + _buf.b.put(_stringBytes, 0, len); + } + else + { + writeSize(0); + } + } + } + + /** + * Writes an optional string to the stream. + * + * @param tag The optional tag. + * @param v The optional string to write to the stream. + **/ + public void writeString(int tag, Optional<String> v) + { + if(v != null && v.isSet()) + { + writeString(tag, v.get()); + } + } + + /** + * Writes an optional string to the stream. + * + * @param tag The optional tag. + * @param v The string to write to the stream. + **/ + public void writeString(int tag, String v) + { + if(writeOptional(tag, OptionalFormat.VSize)) + { + writeString(v); + } + } + + /** + * Writes a string sequence to the stream. + * + * @param v The string sequence to write to the stream. + * Passing <code>null</code> causes an empty sequence to be written to the stream. + **/ + public void writeStringSeq(String[] v) + { + if(v == null) + { + writeSize(0); + } + else + { + writeSize(v.length); + for(String e : v) + { + writeString(e); + } + } + } + + /** + * Writes an optional string sequence to the stream. + * + * @param tag The optional tag. + * @param v The optional string sequence to write to the stream. + **/ + public void writeStringSeq(int tag, Optional<String[]> v) + { + if(v != null && v.isSet()) + { + writeStringSeq(tag, v.get()); + } + } + + /** + * Writes an optional string sequence to the stream. + * + * @param tag The optional tag. + * @param v The string sequence to write to the stream. + **/ + public void writeStringSeq(int tag, String[] v) + { + if(writeOptional(tag, OptionalFormat.FSize)) + { + int pos = startSize(); + writeStringSeq(v); + endSize(pos); + } + } + + /** + * Writes a proxy to the stream. + * + * @param v The proxy to write. + **/ + public void writeProxy(ObjectPrx v) + { + if(v != null) + { + v.__write(this); + } + else + { + Identity ident = new Identity(); + ident.__write(this); + } + } + + /** + * Writes an optional proxy to the stream. + * + * @param tag The optional tag. + * @param v The optional proxy to write to the stream. + **/ + public void writeProxy(int tag, Optional<ObjectPrx> v) + { + if(v != null && v.isSet()) + { + writeProxy(tag, v.get()); + } + } + + /** + * Writes an optional proxy to the stream. + * + * @param tag The optional tag. + * @param v The proxy to write to the stream. + **/ + public void writeProxy(int tag, ObjectPrx v) + { + if(writeOptional(tag, OptionalFormat.FSize)) + { + int pos = startSize(); + writeProxy(v); + endSize(pos); + } + } + + /** + * Write an enumerated value. + * + * @param v The enumerator. + * @param maxValue The maximum enumerator value in the definition. + **/ + public void writeEnum(int v, int maxValue) + { + if(isEncoding_1_0()) + { + if(maxValue < 127) + { + writeByte((byte)v); + } + else if(maxValue < 32767) + { + writeShort((short)v); + } + else + { + writeInt(v); + } + } + else + { + writeSize(v); + } + } + + /** + * Writes a Slice value to the stream. + * + * @param v The value to write. This method writes the index of an instance; the state of the value is + * written once {@link #writePendingValues} is called. + **/ + public void writeValue(Ice.Object v) + { + initEncaps(); + _encapsStack.encoder.writeValue(v); + } + + /** + * Writes an optional value to the stream. + * + * @param tag The optional tag. + * @param v The optional value to write to the stream. + **/ + public <T extends Ice.Object> void writeValue(int tag, Optional<T> v) + { + if(v != null && v.isSet()) + { + writeValue(tag, v.get()); + } + } + + /** + * Writes an optional value to the stream. + * + * @param tag The optional tag. + * @param v The value to write to the stream. + **/ + public void writeValue(int tag, Ice.Object v) + { + if(writeOptional(tag, OptionalFormat.Class)) + { + writeValue(v); + } + } + + /** + * Writes a user exception to the stream. + * + * @param v The user exception to write. + **/ + public void writeException(UserException v) + { + initEncaps(); + _encapsStack.encoder.writeException(v); + } + + private boolean writeOptionalImpl(int tag, OptionalFormat format) + { + if(isEncoding_1_0()) + { + return false; // Optional members aren't supported with the 1.0 encoding. + } + + int v = format.value(); + if(tag < 30) + { + v |= tag << 3; + writeByte((byte)v); + } + else + { + v |= 0x0F0; // tag = 30 + writeByte((byte)v); + writeSize(tag); + } + return true; + } + + /** + * Determines the current position in the stream. + * + * @return The current position. + **/ + public int pos() + { + return _buf.b.position(); + } + + /** + * Sets the current position in the stream. + * + * @param n The new position. + **/ + public void pos(int n) + { + _buf.b.position(n); + } + + /** + * Determines the current size of the stream. + * + * @return The current size. + **/ + public int size() + { + return _buf.size(); + } + + /** + * Determines whether the stream is empty. + * + * @return True if no data has been written yet, false otherwise. + **/ + public boolean isEmpty() + { + return _buf.empty(); + } + + /** + * Expand the stream to accept more data. + * + * @param n The number of bytes to accommodate in the stream. + **/ + public void expand(int n) + { + _buf.expand(n); + } + + private IceInternal.Instance _instance; + private IceInternal.Buffer _buf; + private Object _closure; + private FormatType _format; + private byte[] _stringBytes; // Reusable array for string operations. + private char[] _stringChars; // Reusable array for string operations. + + private enum SliceType { NoSlice, ValueSlice, ExceptionSlice } + + abstract private static class EncapsEncoder + { + protected EncapsEncoder(OutputStream stream, Encaps encaps) + { + _stream = stream; + _encaps = encaps; + _typeIdIndex = 0; + _marshaledMap = new java.util.IdentityHashMap<Ice.Object, Integer>(); + } + + abstract void writeValue(Ice.Object v); + abstract void writeException(UserException v); + + abstract void startInstance(SliceType type, SlicedData data); + abstract void endInstance(); + abstract void startSlice(String typeId, int compactId, boolean last); + abstract void endSlice(); + + boolean writeOptional(int tag, OptionalFormat format) + { + return false; + } + + void writePendingValues() + { + } + + protected int registerTypeId(String typeId) + { + if(_typeIdMap == null) // Lazy initialization + { + _typeIdMap = new java.util.TreeMap<String, Integer>(); + } + + Integer p = _typeIdMap.get(typeId); + if(p != null) + { + return p; + } + else + { + _typeIdMap.put(typeId, ++_typeIdIndex); + return -1; + } + } + + final protected OutputStream _stream; + final protected Encaps _encaps; + + // Encapsulation attributes for instance marshaling. + final protected java.util.IdentityHashMap<Ice.Object, Integer> _marshaledMap; + private java.util.TreeMap<String, Integer> _typeIdMap; + private int _typeIdIndex; + } + + private static final class EncapsEncoder10 extends EncapsEncoder + { + EncapsEncoder10(OutputStream stream, Encaps encaps) + { + super(stream, encaps); + _sliceType = SliceType.NoSlice; + _valueIdIndex = 0; + _toBeMarshaledMap = new java.util.IdentityHashMap<Ice.Object, Integer>(); + } + + @Override + void writeValue(Ice.Object v) + { + // + // Object references are encoded as a negative integer in 1.0. + // + if(v != null) + { + _stream.writeInt(-registerValue(v)); + } + else + { + _stream.writeInt(0); + } + } + + @Override + void writeException(UserException v) + { + // + // User exception with the 1.0 encoding start with a boolean + // flag that indicates whether or not the exception uses + // classes. + // + // This allows reading the pending instances even if some part of + // the exception was sliced. + // + boolean usesClasses = v.__usesClasses(); + _stream.writeBool(usesClasses); + v.__write(_stream); + if(usesClasses) + { + writePendingValues(); + } + } + + @Override + void startInstance(SliceType sliceType, SlicedData sliceData) + { + _sliceType = sliceType; + } + + @Override + void endInstance() + { + if(_sliceType == SliceType.ValueSlice) + { + // + // Write the Object slice. + // + startSlice(ObjectImpl.ice_staticId(), -1, true); + _stream.writeSize(0); // For compatibility with the old AFM. + endSlice(); + } + _sliceType = SliceType.NoSlice; + } + + @Override + void startSlice(String typeId, int compactId, boolean last) + { + // + // For instance slices, encode a boolean to indicate how the type ID + // is encoded and the type ID either as a string or index. For + // exception slices, always encode the type ID as a string. + // + if(_sliceType == SliceType.ValueSlice) + { + int index = registerTypeId(typeId); + if(index < 0) + { + _stream.writeBool(false); + _stream.writeString(typeId); + } + else + { + _stream.writeBool(true); + _stream.writeSize(index); + } + } + else + { + _stream.writeString(typeId); + } + + _stream.writeInt(0); // Placeholder for the slice length. + + _writeSlice = _stream.pos(); + } + + @Override + void endSlice() + { + // + // Write the slice length. + // + final int sz = _stream.pos() - _writeSlice + 4; + _stream.rewriteInt(sz, _writeSlice - 4); + } + + @Override + void writePendingValues() + { + while(_toBeMarshaledMap.size() > 0) + { + // + // Consider the to be marshalled instances as marshaled now, + // this is necessary to avoid adding again the "to be + // marshaled instances" into _toBeMarshaledMap while writing + // instances. + // + _marshaledMap.putAll(_toBeMarshaledMap); + + java.util.IdentityHashMap<Ice.Object, Integer> savedMap = _toBeMarshaledMap; + _toBeMarshaledMap = new java.util.IdentityHashMap<Ice.Object, Integer>(); + _stream.writeSize(savedMap.size()); + for(java.util.Map.Entry<Ice.Object, Integer> p : savedMap.entrySet()) + { + // + // Ask the instance to marshal itself. Any new class + // instances that are triggered by the classes marshaled + // are added to toBeMarshaledMap. + // + _stream.writeInt(p.getValue().intValue()); + + try + { + p.getKey().ice_preMarshal(); + } + catch(java.lang.Exception ex) + { + String s = "exception raised by ice_preMarshal:\n" + IceInternal.Ex.toString(ex); + _stream.instance().initializationData().logger.warning(s); + } + + p.getKey().__write(_stream); + } + } + _stream.writeSize(0); // Zero marker indicates end of sequence of sequences of instances. + } + + private int registerValue(Ice.Object v) + { + assert(v != null); + + // + // Look for this instance in the to-be-marshaled map. + // + Integer p = _toBeMarshaledMap.get(v); + if(p != null) + { + return p.intValue(); + } + + // + // Didn't find it, try the marshaled map next. + // + p = _marshaledMap.get(v); + if(p != null) + { + return p.intValue(); + } + + // + // We haven't seen this instance previously, create a new + // index, and insert it into the to-be-marshaled map. + // + _toBeMarshaledMap.put(v, ++_valueIdIndex); + return _valueIdIndex; + } + + // Instance attributes + private SliceType _sliceType; + + // Slice attributes + private int _writeSlice; // Position of the slice data members + + // Encapsulation attributes for instance marshaling. + private int _valueIdIndex; + private java.util.IdentityHashMap<Ice.Object, Integer> _toBeMarshaledMap; + } + + private static final class EncapsEncoder11 extends EncapsEncoder + { + EncapsEncoder11(OutputStream stream, Encaps encaps) + { + super(stream, encaps); + _current = null; + _valueIdIndex = 1; + } + + @Override + void writeValue(Ice.Object v) + { + if(v == null) + { + _stream.writeSize(0); + } + else if(_current != null && _encaps.format == FormatType.SlicedFormat) + { + if(_current.indirectionTable == null) // Lazy initialization + { + _current.indirectionTable = new java.util.ArrayList<Ice.Object>(); + _current.indirectionMap = new java.util.IdentityHashMap<Ice.Object, Integer>(); + } + + // + // If writing an instance within a slice and using the sliced + // format, write an index from the instance indirection + // table. The indirect instance table is encoded at the end of + // each slice and is always read (even if the Slice is + // unknown). + // + Integer index = _current.indirectionMap.get(v); + if(index == null) + { + _current.indirectionTable.add(v); + final int idx = _current.indirectionTable.size(); // Position + 1 (0 is reserved for nil) + _current.indirectionMap.put(v, idx); + _stream.writeSize(idx); + } + else + { + _stream.writeSize(index.intValue()); + } + } + else + { + writeInstance(v); // Write the instance or a reference if already marshaled. + } + } + + @Override + void writeException(UserException v) + { + v.__write(_stream); + } + + @Override + void startInstance(SliceType sliceType, SlicedData data) + { + if(_current == null) + { + _current = new InstanceData(null); + } + else + { + _current = _current.next == null ? new InstanceData(_current) : _current.next; + } + _current.sliceType = sliceType; + _current.firstSlice = true; + + if(data != null) + { + writeSlicedData(data); + } + } + + @Override + void endInstance() + { + _current = _current.previous; + } + + @Override + void startSlice(String typeId, int compactId, boolean last) + { + assert((_current.indirectionTable == null || _current.indirectionTable.isEmpty()) && + (_current.indirectionMap == null || _current.indirectionMap.isEmpty())); + + _current.sliceFlagsPos = _stream.pos(); + + _current.sliceFlags = (byte)0; + if(_encaps.format == FormatType.SlicedFormat) + { + // Encode the slice size if using the sliced format. + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_SLICE_SIZE; + } + if(last) + { + _current.sliceFlags |= IceInternal.Protocol.FLAG_IS_LAST_SLICE; // This is the last slice. + } + + _stream.writeByte((byte)0); // Placeholder for the slice flags + + // + // For instance slices, encode the flag and the type ID either as a + // string or index. For exception slices, always encode the type + // ID a string. + // + if(_current.sliceType == SliceType.ValueSlice) + { + // + // Encode the type ID (only in the first slice for the compact + // encoding). + // + if(_encaps.format == FormatType.SlicedFormat || _current.firstSlice) + { + if(compactId >= 0) + { + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_TYPE_ID_COMPACT; + _stream.writeSize(compactId); + } + else + { + int index = registerTypeId(typeId); + if(index < 0) + { + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_TYPE_ID_STRING; + _stream.writeString(typeId); + } + else + { + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_TYPE_ID_INDEX; + _stream.writeSize(index); + } + } + } + } + else + { + _stream.writeString(typeId); + } + + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_SLICE_SIZE) != 0) + { + _stream.writeInt(0); // Placeholder for the slice length. + } + + _current.writeSlice = _stream.pos(); + _current.firstSlice = false; + } + + @Override + void endSlice() + { + // + // Write the optional member end marker if some optional members + // were encoded. Note that the optional members are encoded before + // the indirection table and are included in the slice size. + // + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS) != 0) + { + _stream.writeByte((byte)IceInternal.Protocol.OPTIONAL_END_MARKER); + } + + // + // Write the slice length if necessary. + // + if((_current.sliceFlags & IceInternal.Protocol.FLAG_HAS_SLICE_SIZE) != 0) + { + final int sz = _stream.pos() - _current.writeSlice + 4; + _stream.rewriteInt(sz, _current.writeSlice - 4); + } + + // + // Only write the indirection table if it contains entries. + // + if(_current.indirectionTable != null && !_current.indirectionTable.isEmpty()) + { + assert(_encaps.format == FormatType.SlicedFormat); + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_INDIRECTION_TABLE; + + // + // Write the indirection instance table. + // + _stream.writeSize(_current.indirectionTable.size()); + for(Ice.Object v : _current.indirectionTable) + { + writeInstance(v); + } + _current.indirectionTable.clear(); + _current.indirectionMap.clear(); + } + + // + // Finally, update the slice flags. + // + _stream.rewriteByte(_current.sliceFlags, _current.sliceFlagsPos); + } + + @Override + boolean writeOptional(int tag, OptionalFormat format) + { + if(_current == null) + { + return _stream.writeOptionalImpl(tag, format); + } + else + { + if(_stream.writeOptionalImpl(tag, format)) + { + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS; + return true; + } + else + { + return false; + } + } + } + + private void writeSlicedData(SlicedData slicedData) + { + assert(slicedData != null); + + // + // We only remarshal preserved slices if we are using the sliced + // format. Otherwise, we ignore the preserved slices, which + // essentially "slices" the instance into the most-derived type + // known by the sender. + // + if(_encaps.format != FormatType.SlicedFormat) + { + return; + } + + for(SliceInfo info : slicedData.slices) + { + startSlice(info.typeId, info.compactId, info.isLastSlice); + + // + // Write the bytes associated with this slice. + // + _stream.writeBlob(info.bytes); + + if(info.hasOptionalMembers) + { + _current.sliceFlags |= IceInternal.Protocol.FLAG_HAS_OPTIONAL_MEMBERS; + } + + // + // Make sure to also re-write the instance indirection table. + // + if(info.instances != null && info.instances.length > 0) + { + if(_current.indirectionTable == null) // Lazy initialization + { + _current.indirectionTable = new java.util.ArrayList<Ice.Object>(); + _current.indirectionMap = new java.util.IdentityHashMap<Ice.Object, Integer>(); + } + for(Ice.Object o : info.instances) + { + _current.indirectionTable.add(o); + } + } + + endSlice(); + } + } + + private void writeInstance(Ice.Object v) + { + assert(v != null); + + // + // If the instance was already marshaled, just write it's ID. + // + Integer p = _marshaledMap.get(v); + if(p != null) + { + _stream.writeSize(p); + return; + } + + // + // We haven't seen this instance previously, create a new ID, + // insert it into the marshaled map, and write the instance. + // + _marshaledMap.put(v, ++_valueIdIndex); + + try + { + v.ice_preMarshal(); + } + catch(java.lang.Exception ex) + { + String s = "exception raised by ice_preMarshal:\n" + IceInternal.Ex.toString(ex); + _stream.instance().initializationData().logger.warning(s); + } + + _stream.writeSize(1); // Class instance marker. + v.__write(_stream); + } + + private static final class InstanceData + { + InstanceData(InstanceData previous) + { + if(previous != null) + { + previous.next = this; + } + this.previous = previous; + this.next = null; + } + + // Instance attributes + SliceType sliceType; + boolean firstSlice; + + // Slice attributes + byte sliceFlags; + int writeSlice; // Position of the slice data members + int sliceFlagsPos; // Position of the slice flags + java.util.List<Ice.Object> indirectionTable; + java.util.IdentityHashMap<Ice.Object, Integer> indirectionMap; + + final InstanceData previous; + InstanceData next; + } + + private InstanceData _current; + + private int _valueIdIndex; // The ID of the next instance to marhsal + } + + private static final class Encaps + { + void reset() + { + encoder = null; + } + + void setEncoding(EncodingVersion encoding) + { + this.encoding = encoding; + encoding_1_0 = encoding.equals(Util.Encoding_1_0); + } + + int start; + FormatType format = FormatType.DefaultFormat; + EncodingVersion encoding; + boolean encoding_1_0; + + EncapsEncoder encoder; + + Encaps next; + } + + // + // The encoding version to use when there's no encapsulation to + // read from or write to. This is for example used to read message + // headers or when the user is using the streaming API with no + // encapsulation. + // + private EncodingVersion _encoding; + + private boolean isEncoding_1_0() + { + return _encapsStack != null ? _encapsStack.encoding_1_0 : _encoding.equals(Util.Encoding_1_0); + } + + private Encaps _encapsStack; + private Encaps _encapsCache; + + private void initEncaps() + { + if(_encapsStack == null) // Lazy initialization + { + _encapsStack = _encapsCache; + if(_encapsStack != null) + { + _encapsCache = _encapsCache.next; + } + else + { + _encapsStack = new Encaps(); + } + _encapsStack.setEncoding(_encoding); + } + + if(_encapsStack.format == FormatType.DefaultFormat) + { + _encapsStack.format = _format; + } + + if(_encapsStack.encoder == null) // Lazy initialization. + { + if(_encapsStack.encoding_1_0) + { + _encapsStack.encoder = new EncapsEncoder10(this, _encapsStack); + } + else + { + _encapsStack.encoder = new EncapsEncoder11(this, _encapsStack); + } + } + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/PluginFactory.java b/java-compat/src/Ice/src/main/java/Ice/PluginFactory.java new file mode 100644 index 00000000000..a92439a8d9e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/PluginFactory.java @@ -0,0 +1,27 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Applications implement this interface to provide a plug-in factory + * to the Ice run time. + **/ +public interface PluginFactory +{ + /** + * Called by the Ice run time to create a new plug-in. + * + * @param communicator The communicator that is in the process of being initialized. + * @param name The name of the plug-in. + * @param args The arguments that are specified in the plug-ins configuration. + * @return The plug-in that was created by this method. + **/ + Plugin create(Communicator communicator, String name, String[] args); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/PluginManagerI.java b/java-compat/src/Ice/src/main/java/Ice/PluginManagerI.java new file mode 100644 index 00000000000..6b40bb0f333 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/PluginManagerI.java @@ -0,0 +1,549 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +import java.net.URLEncoder; + +public final class PluginManagerI implements PluginManager +{ + private static String _kindOfObject = "plugin"; + + @Override + public synchronized void + initializePlugins() + { + if(_initialized) + { + InitializationException ex = new InitializationException(); + ex.reason = "plug-ins already initialized"; + throw ex; + } + + // + // Invoke initialize() on the plug-ins, in the order they were loaded. + // + java.util.List<Plugin> initializedPlugins = new java.util.ArrayList<Plugin>(); + try + { + for(PluginInfo p : _plugins) + { + try + { + p.plugin.initialize(); + } + catch(Ice.PluginInitializationException ex) + { + throw ex; + } + catch(RuntimeException ex) + { + PluginInitializationException e = new PluginInitializationException(); + e.reason = "plugin `" + p.name + "' initialization failed"; + e.initCause(ex); + throw e; + } + initializedPlugins.add(p.plugin); + } + } + catch(RuntimeException ex) + { + // + // Destroy the plug-ins that have been successfully initialized, in the + // reverse order. + // + java.util.ListIterator<Plugin> i = initializedPlugins.listIterator(initializedPlugins.size()); + while(i.hasPrevious()) + { + Plugin p = i.previous(); + try + { + p.destroy(); + } + catch(RuntimeException e) + { + // Ignore. + } + } + throw ex; + } + + _initialized = true; + } + + @Override + public synchronized String[] + getPlugins() + { + java.util.ArrayList<String> names = new java.util.ArrayList<String>(); + for(PluginInfo p : _plugins) + { + names.add(p.name); + } + return names.toArray(new String[0]); + } + + @Override + public synchronized Plugin + getPlugin(String name) + { + if(_communicator == null) + { + throw new CommunicatorDestroyedException(); + } + + Plugin p = findPlugin(name); + if(p != null) + { + return p; + } + + NotRegisteredException ex = new NotRegisteredException(); + ex.id = name; + ex.kindOfObject = _kindOfObject; + throw ex; + } + + @Override + public synchronized void + addPlugin(String name, Plugin plugin) + { + if(_communicator == null) + { + throw new CommunicatorDestroyedException(); + } + + if(findPlugin(name) != null) + { + AlreadyRegisteredException ex = new AlreadyRegisteredException(); + ex.id = name; + ex.kindOfObject = _kindOfObject; + throw ex; + } + + PluginInfo info = new PluginInfo(); + info.name = name; + info.plugin = plugin; + _plugins.add(info); + } + + @Override + public synchronized void + destroy() + { + if(_communicator != null) + { + if(_initialized) + { + java.util.ListIterator<PluginInfo> i = _plugins.listIterator(_plugins.size()); + while(i.hasPrevious()) + { + PluginInfo p = i.previous(); + try + { + p.plugin.destroy(); + } + catch(RuntimeException ex) + { + Ice.Util.getProcessLogger().warning("unexpected exception raised by plug-in `" + + p.name + "' destruction:\n" + ex.toString()); + } + } + } + + _communicator = null; + } + + _plugins.clear(); + + if(_classLoaders != null) + { + _classLoaders.clear(); + } + } + + public + PluginManagerI(Communicator communicator, IceInternal.Instance instance) + { + _communicator = communicator; + _instance = instance; + _initialized = false; + } + + public void + loadPlugins(StringSeqHolder cmdArgs) + { + assert(_communicator != null); + + // + // Load and initialize the plug-ins defined in the property set + // with the prefix "Ice.Plugin.". These properties should + // have the following format: + // + // Ice.Plugin.name[.<language>]=entry_point [args] + // + // If the Ice.PluginLoadOrder property is defined, load the + // specified plug-ins in the specified order, then load any + // remaining plug-ins. + // + final String prefix = "Ice.Plugin."; + Properties properties = _communicator.getProperties(); + java.util.Map<String, String> plugins = properties.getPropertiesForPrefix(prefix); + + final String[] loadOrder = properties.getPropertyAsList("Ice.PluginLoadOrder"); + for(String name : loadOrder) + { + if(findPlugin(name) != null) + { + PluginInitializationException ex = new PluginInitializationException(); + ex.reason = "plug-in `" + name + "' already loaded"; + throw ex; + } + + String key = "Ice.Plugin." + name + ".java"; + boolean hasKey = plugins.containsKey(key); + if(hasKey) + { + plugins.remove("Ice.Plugin." + name); + } + else + { + key = "Ice.Plugin." + name; + hasKey = plugins.containsKey(key); + } + + if(hasKey) + { + final String value = plugins.get(key); + loadPlugin(name, value, cmdArgs); + plugins.remove(key); + } + else + { + PluginInitializationException ex = new PluginInitializationException(); + ex.reason = "plug-in `" + name + "' not defined"; + throw ex; + } + } + + // + // Load any remaining plug-ins that weren't specified in PluginLoadOrder. + // + while(!plugins.isEmpty()) + { + java.util.Iterator<java.util.Map.Entry<String, String> > p = plugins.entrySet().iterator(); + java.util.Map.Entry<String, String> entry = p.next(); + + String name = entry.getKey().substring(prefix.length()); + + int dotPos = name.lastIndexOf('.'); + if(dotPos != -1) + { + String suffix = name.substring(dotPos + 1); + if(suffix.equals("cpp") || suffix.equals("clr")) + { + // + // Ignored + // + p.remove(); + } + else if(suffix.equals("java")) + { + name = name.substring(0, dotPos); + loadPlugin(name, entry.getValue(), cmdArgs); + p.remove(); + + // + // Don't want to load this one if it's there! + // + plugins.remove("Ice.Plugin." + name); + } + else + { + // + // Name is just a regular name that happens to contain a dot + // + dotPos = -1; + } + } + + if(dotPos == -1) + { + // + // Is there a .java entry? + // + String value = entry.getValue(); + p.remove(); + + String javaValue = plugins.remove("Ice.Plugin." + name + ".java"); + if(javaValue != null) + { + value = javaValue; + } + + loadPlugin(name, value, cmdArgs); + } + } + } + + private void + loadPlugin(String name, String pluginSpec, StringSeqHolder cmdArgs) + { + assert(_communicator != null); + + // + // We support the following formats: + // + // <class-name> [args] + // <jar-file>:<class-name> [args] + // <class-dir>:<class-name> [args] + // "<path with spaces>":<class-name> [args] + // "<path with spaces>:<class-name>" [args] + // + + String[] args; + try + { + args = IceUtilInternal.Options.split(pluginSpec); + } + catch(IceUtilInternal.Options.BadQuote ex) + { + throw new PluginInitializationException("invalid arguments for plug-in `" + name + "':\n" + + ex.getMessage()); + } + + assert(args.length > 0); + + final String entryPoint = args[0]; + + final boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + boolean absolutePath = false; + + // + // Find first ':' that isn't part of the file path. + // + int pos = entryPoint.indexOf(':'); + if(isWindows) + { + final String driveLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if(pos == 1 && entryPoint.length() > 2 && driveLetters.indexOf(entryPoint.charAt(0)) != -1 && + (entryPoint.charAt(2) == '\\' || entryPoint.charAt(2) == '/')) + { + absolutePath = true; + pos = entryPoint.indexOf(':', pos + 1); + } + if(!absolutePath) + { + absolutePath = entryPoint.startsWith("\\\\"); + } + } + else + { + absolutePath = entryPoint.startsWith("/"); + } + + if((pos == -1 && absolutePath) || (pos != -1 && entryPoint.length() <= pos + 1)) + { + // + // Class name is missing. + // + throw new PluginInitializationException("invalid entry point for plug-in `" + name + "':\n" + entryPoint); + } + + // + // Extract the JAR file or subdirectory, if any. + // + String classDir = null; // Path name of JAR file or subdirectory. + String className; + + if(pos == -1) + { + className = entryPoint; + } + else + { + classDir = entryPoint.substring(0, pos).trim(); + className = entryPoint.substring(pos + 1).trim(); + } + + // + // Shift the arguments. + // + String[] tmp = new String[args.length - 1]; + System.arraycopy(args, 1, tmp, 0, args.length - 1); + args = tmp; + + // + // Convert command-line options into properties. First we + // convert the options from the plug-in configuration, then + // we convert the options from the application command-line. + // + Properties properties = _communicator.getProperties(); + args = properties.parseCommandLineOptions(name, args); + cmdArgs.value = properties.parseCommandLineOptions(name, cmdArgs.value); + + // + // Instantiate the class. + // + PluginFactory pluginFactory = null; + try + { + Class<?> c = null; + + // + // Use a class loader if the user specified a JAR file or class directory. + // + if(classDir != null) + { + try + { + if(!absolutePath) + { + classDir = new java.io.File(System.getProperty("user.dir") + java.io.File.separator + + classDir).getCanonicalPath(); + } + + if(!classDir.endsWith(java.io.File.separator) && !classDir.toLowerCase().endsWith(".jar")) + { + classDir += java.io.File.separator; + } + classDir = URLEncoder.encode(classDir, "UTF-8"); + + // + // Reuse an existing class loader if we have already loaded a plug-in with + // the same value for classDir, otherwise create a new one. + // + ClassLoader cl = null; + + if(_classLoaders == null) + { + _classLoaders = new java.util.HashMap<String, ClassLoader>(); + } + else + { + cl = _classLoaders.get(classDir); + } + + if(cl == null) + { + final java.net.URL[] url = new java.net.URL[] { new java.net.URL("file", null, classDir) }; + + // + // Use the custom class loader (if any) as the parent. + // + if(_instance.initializationData().classLoader != null) + { + cl = new java.net.URLClassLoader(url, _instance.initializationData().classLoader); + } + else + { + cl = new java.net.URLClassLoader(url); + } + + _classLoaders.put(classDir, cl); + } + + c = cl.loadClass(className); + } + catch(java.net.MalformedURLException ex) + { + throw new PluginInitializationException("invalid entry point format `" + pluginSpec + "'", ex); + } + catch(java.io.IOException ex) + { + throw new PluginInitializationException("invalid path in entry point `" + pluginSpec + "'", ex); + } + catch(java.lang.ClassNotFoundException ex) + { + // Ignored + } + } + else + { + c = IceInternal.Util.getInstance(_communicator).findClass(className); + } + + if(c == null) + { + throw new PluginInitializationException("class " + className + " not found"); + } + + java.lang.Object obj = c.newInstance(); + try + { + pluginFactory = (PluginFactory)obj; + } + catch(ClassCastException ex) + { + throw new PluginInitializationException("class " + className + " does not implement Ice.PluginFactory", + ex); + } + } + catch(IllegalAccessException ex) + { + throw new PluginInitializationException("unable to access default constructor in class " + className, ex); + } + catch(InstantiationException ex) + { + throw new PluginInitializationException("unable to instantiate class " + className, ex); + } + + // + // Invoke the factory. + // + Plugin plugin = null; + try + { + plugin = pluginFactory.create(_communicator, name, args); + } + catch(PluginInitializationException ex) + { + throw ex; + } + catch(Throwable ex) + { + throw new PluginInitializationException("exception in factory " + className, ex); + } + + if(plugin == null) + { + throw new PluginInitializationException("failure in factory " + className); + } + + PluginInfo info = new PluginInfo(); + info.name = name; + info.plugin = plugin; + _plugins.add(info); + } + + private Plugin + findPlugin(String name) + { + for(PluginInfo p : _plugins) + { + if(name.equals(p.name)) + { + return p.plugin; + } + } + return null; + } + + static class PluginInfo + { + String name; + Plugin plugin; + } + + private Communicator _communicator; + private IceInternal.Instance _instance; + private java.util.List<PluginInfo> _plugins = new java.util.ArrayList<PluginInfo>(); + private boolean _initialized; + private java.util.Map<String, ClassLoader> _classLoaders; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/PropertiesAdminUpdateCallback.java b/java-compat/src/Ice/src/main/java/Ice/PropertiesAdminUpdateCallback.java new file mode 100644 index 00000000000..d07b0dab83a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/PropertiesAdminUpdateCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface PropertiesAdminUpdateCallback +{ + void updated(java.util.Map<String, String> changes); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/PropertiesI.java b/java-compat/src/Ice/src/main/java/Ice/PropertiesI.java new file mode 100644 index 00000000000..81cff7c62e5 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/PropertiesI.java @@ -0,0 +1,764 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public final class PropertiesI implements Properties +{ + static class PropertyValue + { + public PropertyValue(PropertyValue v) + { + value = v.value; + used = v.used; + } + + public PropertyValue(String v, boolean u) + { + value = v; + used = u; + } + + public String value; + public boolean used; + } + + @Override + public synchronized String + getProperty(String key) + { + PropertyValue pv = _properties.get(key); + if(pv != null) + { + pv.used = true; + return pv.value; + } + else + { + return ""; + } + } + + @Override + public synchronized String + getPropertyWithDefault(String key, String value) + { + PropertyValue pv = _properties.get(key); + if(pv != null) + { + pv.used = true; + return pv.value; + } + else + { + return value; + } + } + + @Override + public int + getPropertyAsInt(String key) + { + return getPropertyAsIntWithDefault(key, 0); + } + + @Override + public synchronized int + getPropertyAsIntWithDefault(String key, int value) + { + PropertyValue pv = _properties.get(key); + if(pv != null) + { + pv.used = true; + + try + { + return Integer.parseInt(pv.value); + } + catch(NumberFormatException ex) + { + Ice.Util.getProcessLogger().warning("numeric property " + key + + " set to non-numeric value, defaulting to " + value); + } + } + + return value; + } + + @Override + public String[] + getPropertyAsList(String key) + { + return getPropertyAsListWithDefault(key, null); + } + + @Override + public synchronized String[] + getPropertyAsListWithDefault(String key, String[] value) + { + if(value == null) + { + value = new String[0]; + } + + PropertyValue pv = _properties.get(key); + if(pv != null) + { + pv.used = true; + + String[] result = IceUtilInternal.StringUtil.splitString(pv.value, ", \t\r\n"); + if(result == null) + { + Ice.Util.getProcessLogger().warning("mismatched quotes in property " + key + + "'s value, returning default value"); + return value; + } + if(result.length == 0) + { + result = value; + } + return result; + } + else + { + return value; + } + } + + @Override + public synchronized java.util.Map<String, String> + getPropertiesForPrefix(String prefix) + { + java.util.HashMap<String, String> result = new java.util.HashMap<String, String>(); + for(java.util.Map.Entry<String, PropertyValue> p : _properties.entrySet()) + { + String key = p.getKey(); + if(prefix.length() == 0 || key.startsWith(prefix)) + { + PropertyValue pv = p.getValue(); + pv.used = true; + result.put(key, pv.value); + } + } + return result; + } + + @Override + public void + setProperty(String key, String value) + { + // + // Trim whitespace + // + if(key != null) + { + key = key.trim(); + } + + // + // Check if the property is legal. + // + Logger logger = Ice.Util.getProcessLogger(); + if(key == null || key.length() == 0) + { + throw new Ice.InitializationException("Attempt to set property with empty key"); + } + + int dotPos = key.indexOf('.'); + if(dotPos != -1) + { + String prefix = key.substring(0, dotPos); + for(int i = 0; IceInternal.PropertyNames.validProps[i] != null; ++i) + { + String pattern = IceInternal.PropertyNames.validProps[i][0].pattern(); + dotPos = pattern.indexOf('.'); + // + // Each top level prefix describes a non-empty namespace. Having a string without a + // prefix followed by a dot is an error. + // + assert(dotPos != -1); + String propPrefix = pattern.substring(0, dotPos - 1); + boolean mismatchCase = false; + String otherKey = ""; + if(!propPrefix.toUpperCase().equals(prefix.toUpperCase())) + { + continue; + } + + boolean found = false; + for(int j = 0; IceInternal.PropertyNames.validProps[i][j] != null && !found; ++j) + { + pattern = IceInternal.PropertyNames.validProps[i][j].pattern(); + java.util.regex.Pattern pComp = java.util.regex.Pattern.compile(pattern); + java.util.regex.Matcher m = pComp.matcher(key); + found = m.matches(); + + if(found && IceInternal.PropertyNames.validProps[i][j].deprecated()) + { + logger.warning("deprecated property: " + key); + if(IceInternal.PropertyNames.validProps[i][j].deprecatedBy() != null) + { + key = IceInternal.PropertyNames.validProps[i][j].deprecatedBy(); + } + } + + if(!found) + { + pComp = java.util.regex.Pattern.compile(pattern.toUpperCase()); + m = pComp.matcher(key.toUpperCase()); + if(m.matches()) + { + found = true; + mismatchCase = true; + otherKey = pattern.replaceAll("\\\\", ""); + break; + } + } + } + if(!found) + { + logger.warning("unknown property: " + key); + } + else if(mismatchCase) + { + logger.warning("unknown property: `" + key + "'; did you mean `" + otherKey + "'"); + } + } + } + + synchronized(this) + { + // + // Set or clear the property. + // + if(value != null && value.length() > 0) + { + PropertyValue pv = _properties.get(key); + if(pv != null) + { + pv.value = value; + } + else + { + pv = new PropertyValue(value, false); + } + _properties.put(key, pv); + } + else + { + _properties.remove(key); + } + } + } + + @Override + public synchronized String[] + getCommandLineOptions() + { + String[] result = new String[_properties.size()]; + int i = 0; + for(java.util.Map.Entry<String, PropertyValue> p : _properties.entrySet()) + { + result[i++] = "--" + p.getKey() + "=" + p.getValue().value; + } + assert(i == result.length); + return result; + } + + @Override + public String[] + parseCommandLineOptions(String pfx, String[] options) + { + if(pfx.length() > 0 && pfx.charAt(pfx.length() - 1) != '.') + { + pfx += '.'; + } + pfx = "--" + pfx; + + java.util.ArrayList<String> result = new java.util.ArrayList<String>(); + for(String opt : options) + { + if(opt.startsWith(pfx)) + { + if(opt.indexOf('=') == -1) + { + opt += "=1"; + } + + parseLine(opt.substring(2)); + } + else + { + result.add(opt); + } + } + return result.toArray(new String[0]); + } + + @Override + public String[] + parseIceCommandLineOptions(String[] options) + { + String[] args = options; + for(int i = 0; IceInternal.PropertyNames.clPropNames[i] != null; ++i) + { + args = parseCommandLineOptions(IceInternal.PropertyNames.clPropNames[i], args); + } + return args; + } + + @Override + public void + load(String file) + { + if(System.getProperty("os.name").startsWith("Windows") && file.startsWith("HKLM\\")) + { + String regQuery = "reg query " + file; + try + { + java.lang.Process process = Runtime.getRuntime().exec(regQuery); + process.waitFor(); + if(process.exitValue() != 0) + { + InitializationException ie = new InitializationException(); + ie.reason = "Could not read Windows registry key `" + file + "'"; + throw ie; + } + + java.io.InputStream is = process.getInputStream(); + java.io.StringWriter sw = new java.io.StringWriter(); + int c; + while((c = is.read()) != -1) + { + sw.write(c); + } + String[] result = sw.toString().split("\n"); + + for(String line : result) + { + int pos = line.indexOf("REG_SZ"); + if(pos != -1) + { + setProperty(line.substring(0, pos).trim(), line.substring(pos + 6, line.length()).trim()); + continue; + } + + pos = line.indexOf("REG_EXPAND_SZ"); + if(pos != -1) + { + String name = line.substring(0, pos).trim(); + line = line.substring(pos + 13, line.length()).trim(); + while(true) + { + int start = line.indexOf("%", 0); + int end = line.indexOf("%", start + 1); + + // + // If there isn't more %var% break the loop + // + if(start == -1 || end == -1) + { + break; + } + + String envKey = line.substring(start + 1, end); + String envValue = System.getenv(envKey); + if(envValue == null) + { + envValue = ""; + } + + envKey = "%" + envKey + "%"; + do + { + line = line.replace(envKey , envValue); + } + while(line.indexOf(envKey) != -1); + } + setProperty(name, line); + continue; + } + } + } + catch(Ice.LocalException ex) + { + throw ex; + } + catch(java.lang.Exception ex) + { + throw new InitializationException("Could not read Windows registry key `" + file + "'", ex); + } + } + else + { + java.io.PushbackInputStream is = null; + try + { + java.io.InputStream f = IceInternal.Util.openResource(getClass().getClassLoader(), file); + if(f == null) + { + FileException fe = new FileException(); + fe.path = file; + throw fe; + } + // + // Skip UTF-8 BOM if present. + // + byte[] bom = new byte[3]; + is = new java.io.PushbackInputStream(f, bom.length); + int read = is.read(bom, 0, bom.length); + if(read < 3 || bom[0] != (byte)0xEF || bom[1] != (byte)0xBB || bom[2] != (byte)0xBF) + { + if(read > 0) + { + is.unread(bom, 0, read); + } + } + + java.io.InputStreamReader isr = new java.io.InputStreamReader(is, "UTF-8"); + java.io.BufferedReader br = new java.io.BufferedReader(isr); + parse(br); + } + catch(java.io.IOException ex) + { + throw new FileException(0, file, ex); + } + finally + { + if(is != null) + { + try + { + is.close(); + } + catch(Throwable ex) + { + // Ignore. + } + } + } + } + } + + @Override + public synchronized Properties + _clone() + { + return new PropertiesI(this); + } + + public synchronized java.util.List<String> + getUnusedProperties() + { + java.util.List<String> unused = new java.util.ArrayList<String>(); + for(java.util.Map.Entry<String, PropertyValue> p : _properties.entrySet()) + { + PropertyValue pv = p.getValue(); + if(!pv.used) + { + unused.add(p.getKey()); + } + } + return unused; + } + + PropertiesI(PropertiesI props) + { + // + // NOTE: we can't just do a shallow copy of the map as the map values + // would otherwise be shared between the two PropertiesI object. + // + //_properties = new java.util.HashMap<String, PropertyValue>(props._properties); + for(java.util.Map.Entry<String, PropertyValue> p : props._properties.entrySet()) + { + _properties.put(p.getKey(), new PropertyValue(p.getValue())); + } + } + + PropertiesI() + { + } + + PropertiesI(StringSeqHolder args, Properties defaults) + { + if(defaults != null) + { + // + // NOTE: we can't just do a shallow copy of the map as the map values + // would otherwise be shared between the two PropertiesI object. + // + //_properties = new java.util.HashMap<String, PropertyValue>(((PropertiesI)defaults)._properties); + for(java.util.Map.Entry<String, PropertyValue> p : (((PropertiesI)defaults)._properties).entrySet()) + { + _properties.put(p.getKey(), new PropertyValue(p.getValue())); + } + } + + boolean loadConfigFiles = false; + + for(int i = 0; i < args.value.length; i++) + { + if(args.value[i].startsWith("--Ice.Config")) + { + String line = args.value[i]; + if(line.indexOf('=') == -1) + { + line += "=1"; + } + parseLine(line.substring(2)); + loadConfigFiles = true; + + String[] arr = new String[args.value.length - 1]; + System.arraycopy(args.value, 0, arr, 0, i); + if(i < args.value.length - 1) + { + System.arraycopy(args.value, i + 1, arr, i, args.value.length - i - 1); + } + args.value = arr; + } + } + + if(!loadConfigFiles) + { + // + // If Ice.Config is not set, load from ICE_CONFIG (if set) + // + loadConfigFiles = !_properties.containsKey("Ice.Config"); + } + + if(loadConfigFiles) + { + loadConfig(); + } + + args.value = parseIceCommandLineOptions(args.value); + } + + private void + parse(java.io.BufferedReader in) + { + try + { + String line; + while((line = in.readLine()) != null) + { + parseLine(line); + } + } + catch(java.io.IOException ex) + { + throw new SyscallException(ex); + } + } + + private static final int ParseStateKey = 0; + private static final int ParseStateValue = 1; + + private void + parseLine(String line) + { + String key = ""; + String value = ""; + + int state = ParseStateKey; + + String whitespace = ""; + String escapedspace = ""; + boolean finished = false; + for(int i = 0; i < line.length(); ++i) + { + char c = line.charAt(i); + switch(state) + { + case ParseStateKey: + { + switch(c) + { + case '\\': + if(i < line.length() - 1) + { + c = line.charAt(++i); + switch(c) + { + case '\\': + case '#': + case '=': + key += whitespace; + whitespace = ""; + key += c; + break; + + case ' ': + if(key.length() != 0) + { + whitespace += c; + } + break; + + default: + key += whitespace; + whitespace = ""; + key += '\\'; + key += c; + break; + } + } + else + { + key += whitespace; + key += c; + } + break; + + case ' ': + case '\t': + case '\r': + case '\n': + if(key.length() != 0) + { + whitespace += c; + } + break; + + case '=': + whitespace = ""; + state = ParseStateValue; + break; + + case '#': + finished = true; + break; + + default: + key += whitespace; + whitespace = ""; + key += c; + break; + } + break; + } + + case ParseStateValue: + { + switch(c) + { + case '\\': + if(i < line.length() - 1) + { + c = line.charAt(++i); + switch(c) + { + case '\\': + case '#': + case '=': + value += value.length() == 0 ? escapedspace : whitespace; + whitespace = ""; + escapedspace = ""; + value += c; + break; + + case ' ': + whitespace += c; + escapedspace += c; + break; + + default: + value += value.length() == 0 ? escapedspace : whitespace; + whitespace = ""; + escapedspace = ""; + value += '\\'; + value += c; + break; + } + } + else + { + value += value.length() == 0 ? escapedspace : whitespace; + value += c; + } + break; + + case ' ': + case '\t': + case '\r': + case '\n': + if(value.length() != 0) + { + whitespace += c; + } + break; + + case '#': + finished = true; + break; + + default: + value += value.length() == 0 ? escapedspace : whitespace; + whitespace = ""; + escapedspace = ""; + value += c; + break; + } + break; + } + } + if(finished) + { + break; + } + } + value += escapedspace; + + if((state == ParseStateKey && key.length() != 0) || (state == ParseStateValue && key.length() == 0)) + { + Ice.Util.getProcessLogger().warning("invalid config file entry: \"" + line + "\""); + return; + } + else if(key.length() == 0) + { + return; + } + + setProperty(key, value); + } + + private void + loadConfig() + { + String value = getProperty("Ice.Config"); + + if(value.length() == 0 || value.equals("1")) + { + try + { + value = System.getenv("ICE_CONFIG"); + if(value == null) + { + value = ""; + } + } + catch(java.lang.SecurityException ex) + { + value = ""; + } + } + + if(value.length() > 0) + { + for(String file : value.split(",")) + { + load(file.trim()); + } + + _properties.put("Ice.Config", new PropertyValue(value, true)); + } + } + + private java.util.HashMap<String, PropertyValue> _properties = new java.util.HashMap<String, PropertyValue>(); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ProxyIdentityFacetKey.java b/java-compat/src/Ice/src/main/java/Ice/ProxyIdentityFacetKey.java new file mode 100644 index 00000000000..21ff8089ba2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ProxyIdentityFacetKey.java @@ -0,0 +1,97 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * This class wraps a proxy to allow it to be used the key for a hashed collection. + * The <code>hashCode</code> and <code>equals</code> methods are based on the object identity and + * the facet of the proxy. + * + * @see Util#proxyIdentityAndFacetCompare + * @see Util#proxyIdentityCompare + * @see ProxyIdentityKey + * + **/ +public class ProxyIdentityFacetKey +{ + /** + * Initializes this class with the passed proxy. + * + * @param proxy The proxy for this instance. + **/ + public + ProxyIdentityFacetKey(Ice.ObjectPrx proxy) + { + _proxy = proxy; + + // + // Cache the identity and facet, and compute the hash code. + // + _identity = proxy.ice_getIdentity(); + _facet = proxy.ice_getFacet(); + int h = 5381; + h = IceInternal.HashUtil.hashAdd(h, _identity); + h = IceInternal.HashUtil.hashAdd(h, _facet); + _hashCode = h; + } + + /** + * Computes a hash value based on the object identity and the facet of the proxy. + * + * @return The hash value. + **/ + @Override + public int + hashCode() + { + return _hashCode; + } + + /** + * Compares this proxy with the passed object for equality. + * + * @param obj The object to compare this proxy with. + * @return <code>true</code> if the passed object is a proxy with the same object + * identity and facet as this proxy; <code>false</code>, otherwise. + **/ + @Override + public boolean + equals(java.lang.Object obj) + { + if(this == obj) + { + return true; + } + + if(obj instanceof ProxyIdentityFacetKey) + { + ProxyIdentityFacetKey other = (ProxyIdentityFacetKey)obj; + return (_hashCode == other._hashCode) && _identity.equals(other._identity) && _facet.equals(other._facet); + } + + return false; + } + + /** + * Returns the proxy stored by this class. + * + * @return The proxy stored by this class. + **/ + public Ice.ObjectPrx + getProxy() + { + return _proxy; + } + + final private Ice.ObjectPrx _proxy; + final private Ice.Identity _identity; + final private String _facet; + final private int _hashCode; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ProxyIdentityKey.java b/java-compat/src/Ice/src/main/java/Ice/ProxyIdentityKey.java new file mode 100644 index 00000000000..b8c85cf324b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ProxyIdentityKey.java @@ -0,0 +1,89 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * This class wraps a proxy to allow it to be used the key for a hashed collection. + * The <code>hashCode</code> and <code>equals</code> methods are based on the object identity + * of the proxy. + * + * @see Util#proxyIdentityCompare + * @see Util#proxyIdentityAndFacetCompare + * @see ProxyIdentityFacetKey + * + **/ +public class ProxyIdentityKey +{ + /** + * Initializes this class with the passed proxy. + * + * @param proxy The proxy for this instance. + **/ + public + ProxyIdentityKey(Ice.ObjectPrx proxy) + { + _proxy = proxy; + + // + // Cache the identity and its hash code. + // + _identity = proxy.ice_getIdentity(); + int h = 5381; + h = IceInternal.HashUtil.hashAdd(h, _identity); + _hashCode = h; + } + + /** + * Computes a hash value based on the object identity of the proxy. + * + * @return The hash value. + **/ + @Override + public int + hashCode() + { + return _hashCode; + } + + /** + * Compares this proxy with the passed object for equality. + * + * @param obj The object to compare this proxy with. + * @return <code>true</code> if the passed object is a proxy with the same object + * identity; <code>false</code>, otherwise. + **/ + @Override + public boolean + equals(java.lang.Object obj) + { + if(this == obj) + { + return true; + } + + if(obj instanceof ProxyIdentityKey) + { + ProxyIdentityKey other = (ProxyIdentityKey)obj; + return (_hashCode == other._hashCode) && _identity.equals(other._identity); + } + + return false; + } + + public Ice.ObjectPrx + getProxy() + { + return _proxy; + } + + final private Ice.ObjectPrx _proxy; + final private Ice.Identity _identity; + final private int _hashCode; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ReadValueCallback.java b/java-compat/src/Ice/src/main/java/Ice/ReadValueCallback.java new file mode 100644 index 00000000000..9a3132a9822 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ReadValueCallback.java @@ -0,0 +1,27 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback class to inform an application when an instance of a Slice class has been + * unmarshaled from an input stream. + * + * @see InputStream#readValue + **/ +public interface ReadValueCallback +{ + /** + * The Ice run time calls this method when it has fully unmarshaled the state + * of a Slice class instance. + * + * @param obj The unmarshaled Slice class instance. + **/ + void valueReady(Ice.Object obj); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Request.java b/java-compat/src/Ice/src/main/java/Ice/Request.java new file mode 100644 index 00000000000..1be2ec37fbf --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Request.java @@ -0,0 +1,23 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Interface for incoming requests. + **/ +public interface Request +{ + /** + * Returns the {@link Current} object for this the request. + * + * @return The {@link Current} object for this request. + **/ + Current getCurrent(); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ShortHolder.java b/java-compat/src/Ice/src/main/java/Ice/ShortHolder.java new file mode 100644 index 00000000000..f960536349d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ShortHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for shorts that are out- or inout-parameters. + **/ +public final class ShortHolder extends Holder<Short> +{ + /** + * Instantiates the class with the value zero. + **/ + public + ShortHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * The <code>short</code> value for this holder. + **/ + public + ShortHolder(short value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ShortOptional.java b/java-compat/src/Ice/src/main/java/Ice/ShortOptional.java new file mode 100644 index 00000000000..60b9228f1f0 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ShortOptional.java @@ -0,0 +1,106 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Manages an optional short parameter. + **/ +public class ShortOptional +{ + /** + * The value defaults to unset. + **/ + public ShortOptional() + { + _isSet = false; + } + + /** + * Sets the value to the given argument. + * + * @param v The initial value. + **/ + public ShortOptional(short v) + { + _value = v; + _isSet = true; + } + + /** + * Sets the value to a shallow copy of the given optional. + * + * @param opt The source value. + **/ + public ShortOptional(ShortOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Obtains the current value. + * + * @return The current value. + * @throws IllegalStateException If the value is not set. + **/ + public short get() + { + if(!_isSet) + { + throw new IllegalStateException("no value is set"); + } + return _value; + } + + /** + * Sets the value to the given argument. + * + * @param v The new value. + **/ + public void set(short v) + { + _value = v; + _isSet = true; + } + + /** + * If the given argument is set, this optional is set to a shallow copy of the argument, + * otherwise this optional is unset. + * + * @param opt The source value. + **/ + public void set(ShortOptional opt) + { + _value = opt._value; + _isSet = opt._isSet; + } + + /** + * Determines whether the value is set. + * + * @return True if the value is set, false otherwise. + **/ + public boolean isSet() + { + return _isSet; + } + + /** + * Unsets this value. + **/ + public void clear() + { + _isSet = false; + _value = 0; + } + + private short _value; + private boolean _isSet; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/SignalPolicy.java b/java-compat/src/Ice/src/main/java/Ice/SignalPolicy.java new file mode 100644 index 00000000000..b1bb328d199 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/SignalPolicy.java @@ -0,0 +1,31 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * The signal policy for Ice.Application signal handling. + * + * @see Ice.Application + **/ +public enum SignalPolicy +{ + /** + * If a signal is received, {@link Ice.Application} reacts to the signal + * by calling {@link Communicator#destroy} or {@link Communicator#shutdown}, + * or by calling a custom shutdown hook installed by the application. + **/ + HandleSignals, + + /** + * Any signal that is received is not intercepted and takes the default + * action. + **/ + NoSignalHandling +} diff --git a/java-compat/src/Ice/src/main/java/Ice/SliceInfo.java b/java-compat/src/Ice/src/main/java/Ice/SliceInfo.java new file mode 100644 index 00000000000..8297a4d447c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/SliceInfo.java @@ -0,0 +1,46 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * SliceInfo encapsulates the details of a slice for an unknown class or exception type. + **/ +public class SliceInfo +{ + /** + * The Slice type ID for this slice. + **/ + public String typeId; + + /** + * The Slice compact type ID for this slice. + **/ + public int compactId; + + /** + * The encoded bytes for this slice, including the leading size integer. + **/ + public byte[] bytes; + + /** + * The class instances referenced by this slice. + **/ + public Ice.Object[] instances; + + /** + * Whether or not the slice contains optional members. + **/ + public boolean hasOptionalMembers; + + /** + * Whether or not this is the last slice. + **/ + public boolean isLastSlice; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/SlicedData.java b/java-compat/src/Ice/src/main/java/Ice/SlicedData.java new file mode 100644 index 00000000000..b747689687a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/SlicedData.java @@ -0,0 +1,26 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * SlicedData holds the slices of unknown class or exception types. + **/ +public class SlicedData +{ + public SlicedData(SliceInfo[] slices) + { + this.slices = slices; + } + + /** + * The details of each slice, in order of most-derived to least-derived. + **/ + public SliceInfo[] slices; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/StringHolder.java b/java-compat/src/Ice/src/main/java/Ice/StringHolder.java new file mode 100644 index 00000000000..46095138097 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/StringHolder.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Holder class for strings that are out- or inout-parameters. + **/ +public final class StringHolder extends Holder<String> +{ + /** + * Instantiates the class with a <code>null</code> string. + **/ + public + StringHolder() + { + } + + /** + * Instantiates the class with the passed value. + * + * @param value The <code>String</code> value stored by this holder. + **/ + public + StringHolder(String value) + { + super(value); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/SysLoggerI.java b/java-compat/src/Ice/src/main/java/Ice/SysLoggerI.java new file mode 100644 index 00000000000..2938990276a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/SysLoggerI.java @@ -0,0 +1,244 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.io.IOException; + +public final class SysLoggerI implements Logger +{ + public + SysLoggerI(String prefix, String facilityString) + { + int facility; + if(facilityString.equals("LOG_KERN")) + { + facility = LOG_KERN; + } + else if(facilityString.equals("LOG_USER")) + { + facility = LOG_USER; + } + else if(facilityString.equals("LOG_MAIL")) + { + facility = LOG_MAIL; + } + else if(facilityString.equals("LOG_DAEMON")) + { + facility = LOG_DAEMON; + } + else if(facilityString.equals("LOG_AUTH")) + { + facility = LOG_AUTH; + } + else if(facilityString.equals("LOG_SYSLOG")) + { + facility = LOG_SYSLOG; + } + else if(facilityString.equals("LOG_LPR")) + { + facility = LOG_LPR; + } + else if(facilityString.equals("LOG_NEWS")) + { + facility = LOG_NEWS; + } + else if(facilityString.equals("LOG_UUCP")) + { + facility = LOG_UUCP; + } + else if(facilityString.equals("LOG_CRON")) + { + facility = LOG_CRON; + } + else if(facilityString.equals("LOG_AUTHPRIV")) + { + facility = LOG_AUTHPRIV; + } + else if(facilityString.equals("LOG_FTP")) + { + facility = LOG_FTP; + } + else if(facilityString.equals("LOG_LOCAL0")) + { + facility = LOG_LOCAL0; + } + else if(facilityString.equals("LOG_LOCAL1")) + { + facility = LOG_LOCAL1; + } + else if(facilityString.equals("LOG_LOCAL2")) + { + facility = LOG_LOCAL2; + } + else if(facilityString.equals("LOG_LOCAL3")) + { + facility = LOG_LOCAL3; + } + else if(facilityString.equals("LOG_LOCAL4")) + { + facility = LOG_LOCAL4; + } + else if(facilityString.equals("LOG_LOCAL5")) + { + facility = LOG_LOCAL5; + } + else if(facilityString.equals("LOG_LOCAL6")) + { + facility = LOG_LOCAL6; + } + else if(facilityString.equals("LOG_LOCAL7")) + { + facility = LOG_LOCAL7; + } + else + { + throw new Ice.InitializationException("Invalid value for Ice.SyslogFacility: " + facilityString); + } + initialize(prefix, facility); + } + + private + SysLoggerI(String prefix, int facility) + { + initialize(prefix, facility); + } + + private void + initialize(String prefix, int facility) + { + _prefix = prefix; + _facility = facility; + + // + // Open a datagram socket to communicate with the localhost + // syslog daemon. + // + try + { + _host = IceInternal.Network.getLocalAddress(IceInternal.Network.EnableBoth); + _socket = new DatagramSocket(); + _socket.connect(_host, _port); + } + catch(IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + @Override + public void + print(String message) + { + log(LOG_INFO, message); + } + + @Override + public void + trace(String category, String message) + { + log(LOG_INFO, category + ": " + message); + } + + @Override + public void + warning(String message) + { + log(LOG_WARNING, message); + } + + @Override + public void + error(String message) + { + log(LOG_ERR, message); + } + + + @Override + public String + getPrefix() + { + return _prefix; + } + + @Override + public Logger + cloneWithPrefix(String prefix) + { + return new SysLoggerI(prefix, _facility); + } + + private void + log(int severity, String message) + { + try + { + // + // Create a syslog message as defined by the RFC 3164: + // <PRI>HEADER MSG. PRI is the priority and is calculated + // from the facility and the severity. We don't specify + // the HEADER. MSG contains the identifier followed by a + // colon character and the message. + // + + int priority = (_facility << 3) | severity; + + String msg = '<' + Integer.toString(priority) + '>' + _prefix + ": " + message; + + byte buf[] = msg.getBytes(); + DatagramPacket p = new DatagramPacket(buf, buf.length, _host, _port); + _socket.send(p); + } + catch(IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + private String _prefix; + private int _facility; + private DatagramSocket _socket; + private InetAddress _host; + private static int _port = 514; + + // + // Syslog facilities (as defined in syslog.h) + // + private final static int LOG_KERN = 0; + private final static int LOG_USER = 1; + private final static int LOG_MAIL = 2; + private final static int LOG_DAEMON = 3; + private final static int LOG_AUTH = 4; + private final static int LOG_SYSLOG = 5; + private final static int LOG_LPR = 6; + private final static int LOG_NEWS = 7; + private final static int LOG_UUCP = 8; + private final static int LOG_CRON = 9; + private final static int LOG_AUTHPRIV = 10; + private final static int LOG_FTP = 11; + private final static int LOG_LOCAL0 = 16; + private final static int LOG_LOCAL1 = 17; + private final static int LOG_LOCAL2 = 18; + private final static int LOG_LOCAL3 = 19; + private final static int LOG_LOCAL4 = 20; + private final static int LOG_LOCAL5 = 21; + private final static int LOG_LOCAL6 = 22; + private final static int LOG_LOCAL7 = 23; + + // + // Syslog priorities (as defined in syslog.h) + // + private final static int LOG_ERR = 3; + private final static int LOG_WARNING = 4; + private final static int LOG_INFO = 6; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/SystemException.java b/java-compat/src/Ice/src/main/java/Ice/SystemException.java new file mode 100644 index 00000000000..c6f063adfb8 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/SystemException.java @@ -0,0 +1,25 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for all Ice system exceptions. + **/ +public abstract class SystemException extends Exception +{ + public SystemException() + { + } + + public SystemException(Throwable cause) + { + super(cause); + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ThreadHookPlugin.java b/java-compat/src/Ice/src/main/java/Ice/ThreadHookPlugin.java new file mode 100644 index 00000000000..8ce5943d638 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ThreadHookPlugin.java @@ -0,0 +1,64 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Class to support thread notification hooks. Applications using thread + * notifications hooks instantiate a <code>ThreadHookPlugin</code> with + * a thread notification hook and return the instance from their + * {@link PluginFactory} implementation. + * + * @see PluginFactory + * @see Plugin + **/ +public class ThreadHookPlugin implements Ice.Plugin +{ + /** + * Installs a thread notification hook for a communicator. + * + * @param communicator The communicator using the thread notification hook. + * @param threadHook The thread notification hook for the communicator. + **/ + public + ThreadHookPlugin(Communicator communicator, ThreadNotification threadHook) + { + if(communicator == null) + { + PluginInitializationException ex = new PluginInitializationException(); + ex.reason = "Communicator cannot be null"; + throw ex; + } + + IceInternal.Instance instance = IceInternal.Util.getInstance(communicator); + instance.setThreadHook(threadHook); + } + + /** + * Called by the Ice run time during communicator initialization. The derived class + * can override this method to perform any initialization that might be required + * by a custom thread notification hook. + **/ + @Override + public void + initialize() + { + } + + /** + * Called by the Ice run time when the communicator is destroyed. The derived class + * can override this method to perform any finalization that might be required + * by a custom thread notification hook. + **/ + @Override + public void + destroy() + { + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ThreadNotification.java b/java-compat/src/Ice/src/main/java/Ice/ThreadNotification.java new file mode 100644 index 00000000000..3fae6f8930e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ThreadNotification.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Interface for thread notification hooks. Applications can derive + * a class that implements the <code>start</code> and <code>stop</code> + * methods to intercept creation and destruction of threads created + * by the Ice run time. + * + * @see InitializationData + **/ +public interface ThreadNotification +{ + /** + * The Ice run time calls <code>start</code> for each new + * thread it creates. The call is made by the newly-started thread. + **/ + void start(); + + /** + * The Ice run time calls <code>stop</code> before it destroys + * a thread. The call is made by thread that is about to be + * destroyed. + **/ + void stop(); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TieBase.java b/java-compat/src/Ice/src/main/java/Ice/TieBase.java new file mode 100644 index 00000000000..0cbd8ff7c4e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TieBase.java @@ -0,0 +1,30 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Interface for servants using the tie mapping. + **/ +public interface TieBase +{ + /** + * Returns the delegate for this tie. + * + * @return The delegate. + **/ + java.lang.Object ice_delegate(); + + /** + * Sets the delegate for this tie. + * + * @param delegate The delegate. + **/ + void ice_delegate(java.lang.Object delegate); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallback.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallback.java new file mode 100644 index 00000000000..bedbe2970c6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallback.java @@ -0,0 +1,30 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base interface for generated twoway operation callback. + **/ +public interface TwowayCallback +{ + /** + * Called when the invocation raises an Ice run-time exception. + * + * @param __ex The Ice run-time exception raised by the operation. + **/ + public void exception(LocalException __ex); + + /** + * Called when the invocation raises an Ice system exception. + * + * @param __ex The Ice system exception raised by the operation. + **/ + public void exception(SystemException __ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackArg1.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackArg1.java new file mode 100644 index 00000000000..5149a2b4116 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackArg1.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackArg1<T> extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(T arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackArg1UE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackArg1UE.java new file mode 100644 index 00000000000..f1a8e57995d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackArg1UE.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackArg1UE<T> extends TwowayCallbackArg1<T> +{ + /** + * Called when the invocation raises an user exception. + * + * @param ex The user exception raised by the operation. + **/ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackBool.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackBool.java new file mode 100644 index 00000000000..bcbdb51971f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackBool.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackBool extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(boolean arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackBoolUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackBoolUE.java new file mode 100644 index 00000000000..5a6492e4b63 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackBoolUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackBoolUE extends TwowayCallbackBool +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackByte.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackByte.java new file mode 100644 index 00000000000..2c66deb95ab --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackByte.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackByte extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(byte arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackByteUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackByteUE.java new file mode 100644 index 00000000000..cccbd04fe42 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackByteUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackByteUE extends TwowayCallbackByte +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackDouble.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackDouble.java new file mode 100644 index 00000000000..042b35e2bc1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackDouble.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackDouble extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(double arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackDoubleUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackDoubleUE.java new file mode 100644 index 00000000000..3190a0b0d9b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackDoubleUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackDoubleUE extends TwowayCallbackDouble +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackFloat.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackFloat.java new file mode 100644 index 00000000000..37818f8e8c1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackFloat.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackFloat extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(float arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackFloatUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackFloatUE.java new file mode 100644 index 00000000000..26a14b83fe7 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackFloatUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackFloatUE extends TwowayCallbackFloat +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackInt.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackInt.java new file mode 100644 index 00000000000..3319fae792e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackInt.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackInt extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(int arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackIntUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackIntUE.java new file mode 100644 index 00000000000..7627bbb9ad6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackIntUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackIntUE extends TwowayCallbackInt +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackLong.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackLong.java new file mode 100644 index 00000000000..ea49ed2a7b4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackLong.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackLong extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(long arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackLongUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackLongUE.java new file mode 100644 index 00000000000..47ca9c303f3 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackLongUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackLongUE extends TwowayCallbackLong +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackShort.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackShort.java new file mode 100644 index 00000000000..8f613175c92 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackShort.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackShort extends TwowayCallback +{ + /** + * Called when the invocation response is received. + * + * @param arg The operation return value. + **/ + void response(short arg); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackShortUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackShortUE.java new file mode 100644 index 00000000000..142993b319a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackShortUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackShortUE extends TwowayCallbackShort +{ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackUE.java new file mode 100644 index 00000000000..ecd25e75edb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackUE.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackUE extends TwowayCallback +{ + public void exception(UserException __ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackVoidUE.java b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackVoidUE.java new file mode 100644 index 00000000000..24813fb7420 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/TwowayCallbackVoidUE.java @@ -0,0 +1,25 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public interface TwowayCallbackVoidUE extends TwowayCallback +{ + /** + * Called when the invocation response is received. + **/ + void response(); + + /** + * Called when the invocation raises an user exception. + * + * @param ex The user exception raised by the operation. + **/ + void exception(Ice.UserException ex); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/UnknownSlicedValue.java b/java-compat/src/Ice/src/main/java/Ice/UnknownSlicedValue.java new file mode 100644 index 00000000000..98d3d45260c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/UnknownSlicedValue.java @@ -0,0 +1,54 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Unknown sliced value holds an instance of an unknown Slice class type. + **/ +public final class UnknownSlicedValue extends ObjectImpl +{ + /** + * Represents an instance of a Slice class type having the given Slice type. + * + * @param unknownTypeId The Slice type ID of the unknown object. + **/ + public + UnknownSlicedValue(String unknownTypeId) + { + _unknownTypeId = unknownTypeId; + } + + /** + * Determine the Slice type ID associated with this object. + * + * @return The type ID. + **/ + public String getUnknownTypeId() + { + return _unknownTypeId; + } + + @Override + public void __write(OutputStream __os) + { + __os.startValue(_slicedData); + __os.endValue(); + } + + @Override + public void __read(InputStream __is) + { + __is.startValue(); + _slicedData = __is.endValue(true); + } + + private final String _unknownTypeId; + private SlicedData _slicedData; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/UserException.java b/java-compat/src/Ice/src/main/java/Ice/UserException.java new file mode 100644 index 00000000000..1d78d42c722 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/UserException.java @@ -0,0 +1,116 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Base class for Slice user exceptions. + **/ +public abstract class UserException extends java.lang.Exception implements Cloneable +{ + public UserException() + { + } + + public UserException(Throwable cause) + { + super(cause); + } + + /** + * Creates a copy of this exception. + * + * @return The copy of this exception. + **/ + @Override + public UserException clone() + { + UserException c = null; + + try + { + c = (UserException)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; + } + + /** + * Returns the name of this exception. + * + * @return The name of this exception. + * + * @deprecated ice_name() is deprecated, use ice_id() instead. + **/ + @Deprecated + public String + ice_name() + { + return ice_id().substring(2); + } + + /** + * Returns the type id of this exception. + * + * @return The type id of this exception. + **/ + public abstract String + ice_id(); + + /** + * Returns a string representation of this exception. + * + * @return A string representation of this exception. + **/ + @Override + public String + toString() + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + IceUtilInternal.OutputBase out = new IceUtilInternal.OutputBase(pw); + out.setUseTab(false); + out.print(getClass().getName()); + out.inc(); + IceInternal.ValueWriter.write(this, out); + pw.flush(); + return sw.toString(); + } + + public void + __write(OutputStream os) + { + os.startException(null); + __writeImpl(os); + os.endException(); + } + + public void + __read(InputStream is) + { + is.startException(); + __readImpl(is); + is.endException(false); + } + + public boolean + __usesClasses() + { + return false; + } + + protected abstract void + __writeImpl(OutputStream os); + + protected abstract void + __readImpl(InputStream is); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/UserExceptionFactory.java b/java-compat/src/Ice/src/main/java/Ice/UserExceptionFactory.java new file mode 100644 index 00000000000..9e899e813ec --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/UserExceptionFactory.java @@ -0,0 +1,26 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Instantiates user exceptions. + * + * @see InputStream#throwException + **/ +public interface UserExceptionFactory +{ + /** + * Instantiate a user exception with the given Slice type id (such as <code>::Module::MyException</code>) + * and throw it. If the implementation does not throw an exception, the Ice run time will fall back + * to using its default behavior for instantiating the user exception. + **/ + void createAndThrow(String typeId) + throws UserException; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/Util.java b/java-compat/src/Ice/src/main/java/Ice/Util.java new file mode 100644 index 00000000000..565dab3588a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/Util.java @@ -0,0 +1,715 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Utility methods for the Ice run time. + **/ +public final class Util +{ + /** + * Creates a new empty property set. + * + * @return A new empty property set. + **/ + public static Properties + createProperties() + { + return new PropertiesI(); + } + + /** + * Creates a property set initialized from an argument vector. + * + * @param args A command-line argument vector, possibly containing + * options to set properties. If the command-line options include + * a <code>--Ice.Config</code> option, the corresponding configuration + * files are parsed. If the same property is set in a configuration + * file and in the argument vector, the argument vector takes precedence. + * <p> + * This method modifies the argument vector by removing any Ice-related options. + * + * @return A property set initialized with the property settings + * that were removed from <code>args</code>. + **/ + public static Properties + createProperties(StringSeqHolder args) + { + return new PropertiesI(args, null); + } + + /** + * Creates a property set initialized from an argument vector. + * + * @param args A command-line argument vector, possibly containing + * options to set properties. If the command-line options include + * a <code>--Ice.Config</code> option, the corresponding configuration + * files are parsed. If the same property is set in a configuration + * file and in the argument vector, the argument vector takes precedence. + * <p> + * This method modifies the argument vector by removing any Ice-related options. + * @param defaults Default values for the property set. Settings in configuration + * files and <code>args</code> override these defaults. + * + * @return An initalized property set. + **/ + public static Properties + createProperties(StringSeqHolder args, Properties defaults) + { + return new PropertiesI(args, defaults); + } + + /** + * Creates a property set initialized from an argument vector. + * + * @param args A command-line argument vector, possibly containing + * options to set properties. If the command-line options include + * a <code>--Ice.Config</code> option, the corresponding configuration + * files are parsed. If the same property is set in a configuration + * file and in the argument vector, the argument vector takes precedence. + * + * @return A property set initialized with the property settings + * in <code>args</code>. + **/ + public static Properties + createProperties(String[] args) + { + StringSeqHolder argsH = new StringSeqHolder(args); + return createProperties(argsH); + } + + /** + * Creates a property set initialized from an argument vector. + * + * @param args A command-line argument vector, possibly containing + * options to set properties. If the command-line options include + * a <code>--Ice.Config</code> option, the corresponding configuration + * files are parsed. If the same property is set in a configuration + * file and in the argument vector, the argument vector takes precedence. + * @param defaults Default values for the property set. Settings in configuration + * files and <code>args</code> override these defaults. + * + * @return An initalized property set. + **/ + public static Properties + createProperties(String[] args, Properties defaults) + { + StringSeqHolder argsH = new StringSeqHolder(args); + return createProperties(argsH, defaults); + } + + /** + * Creates a communicator. + * + * @param args A command-line argument vector. Any Ice-related options + * in this vector are used to intialize the communicator. + * This method modifies the argument vector by removing any Ice-related options. + * + * @return The initialized communicator. + **/ + public static Communicator + initialize(StringSeqHolder args) + { + return initialize(args, null); + } + + /** + * Creates a communicator. + * + * @param args A command-line argument vector. Any Ice-related options + * in this vector are used to intialize the communicator. + * + * @return The initialized communicator. + **/ + public static Communicator + initialize(String[] args) + { + StringSeqHolder argsH = new StringSeqHolder(args); + return initialize(argsH); + } + + /** + * Creates a communicator. + * + * @param args A command-line argument vector. Any Ice-related options + * in this vector are used to intialize the communicator. + * This method modifies the argument vector by removing any Ice-related options. + * + * @param initData Additional intialization data. Property settings in <code>args</code> + * override property settings in <code>initData</code>. + * + * @return The initialized communicator. + * + * @see InitializationData + **/ + public static Communicator + initialize(StringSeqHolder args, InitializationData initData) + { + if(initData == null) + { + initData = new InitializationData(); + } + else + { + initData = initData.clone(); + } + initData.properties = createProperties(args, initData.properties); + + CommunicatorI result = new CommunicatorI(initData); + result.finishSetup(args); + return result; + } + + /** + * Creates a communicator. + * + * @param args A command-line argument vector. Any Ice-related options + * in this vector are used to intialize the communicator. + * + * @param initData Additional intialization data. Property settings in <code>args</code> + * override property settings in <code>initData</code>. + * + * @return The initialized communicator. + * + * @see InitializationData + **/ + public static Communicator + initialize(String[] args, InitializationData initData) + { + StringSeqHolder argsH = new StringSeqHolder(args); + return initialize(argsH, initData); + } + + /** + * Creates a communicator. + * + * @param initData Additional intialization data. + * + * @return The initialized communicator. + * + * @see InitializationData + **/ + public static Communicator + initialize(InitializationData initData) + { + if(initData == null) + { + initData = new InitializationData(); + } + else + { + initData = initData.clone(); + } + + CommunicatorI result = new CommunicatorI(initData); + result.finishSetup(new StringSeqHolder(new String[0])); + return result; + } + + /** + * Creates a communicator using a default configuration. + **/ + public static Communicator + initialize() + { + return initialize(new InitializationData()); + } + + /** + * Converts a string to an object identity. + * + * @param s The string to convert. + * + * @return The converted object identity. + **/ + public static Identity + stringToIdentity(String s) + { + Identity ident = new Identity(); + + // + // Find unescaped separator; note that the string may contain an escaped + // backslash before the separator. + // + int slash = -1, pos = 0; + while((pos = s.indexOf('/', pos)) != -1) + { + int escapes = 0; + while(pos - escapes > 0 && s.charAt(pos - escapes - 1) == '\\') + { + escapes++; + } + + // + // We ignore escaped escapes + // + if(escapes % 2 == 0) + { + if(slash == -1) + { + slash = pos; + } + else + { + // + // Extra unescaped slash found. + // + IdentityParseException ex = new IdentityParseException(); + ex.str = "unescaped backslash in identity `" + s + "'"; + throw ex; + } + } + pos++; + } + + if(slash == -1) + { + ident.category = ""; + try + { + ident.name = IceUtilInternal.StringUtil.unescapeString(s, 0, s.length()); + } + catch(IllegalArgumentException e) + { + IdentityParseException ex = new IdentityParseException(); + ex.str = "invalid identity name `" + s + "': " + e.getMessage(); + throw ex; + } + } + else + { + try + { + ident.category = IceUtilInternal.StringUtil.unescapeString(s, 0, slash); + } + catch(IllegalArgumentException e) + { + IdentityParseException ex = new IdentityParseException(); + ex.str = "invalid category in identity `" + s + "': " + e.getMessage(); + throw ex; + } + if(slash + 1 < s.length()) + { + try + { + ident.name = IceUtilInternal.StringUtil.unescapeString(s, slash + 1, s.length()); + } + catch(IllegalArgumentException e) + { + IdentityParseException ex = new IdentityParseException(); + ex.str = "invalid name in identity `" + s + "': " + e.getMessage(); + throw ex; + } + } + else + { + ident.name = ""; + } + } + + return ident; + } + + /** + * Converts an object identity to a string. + * + * @param ident The object identity to convert. + * + * @return The string representation of the object identity. + **/ + public static String + identityToString(Identity ident) + { + if(ident.category == null || ident.category.length() == 0) + { + return IceUtilInternal.StringUtil.escapeString(ident.name, "/"); + } + else + { + return IceUtilInternal.StringUtil.escapeString(ident.category, "/") + '/' + + IceUtilInternal.StringUtil.escapeString(ident.name, "/"); + } + } + + /** + * Compares the object identities of two proxies. + * + * @param lhs A proxy. + * @param rhs A proxy. + * @return -1 if the identity in <code>lhs</code> compares + * less than the identity in <code>rhs</code>; 0 if the identities + * compare equal; 1, otherwise. + * + * @see ProxyIdentityKey + * @see ProxyIdentityFacetKey + * @see #proxyIdentityAndFacetCompare + **/ + public static int + proxyIdentityCompare(ObjectPrx lhs, ObjectPrx rhs) + { + if(lhs == null && rhs == null) + { + return 0; + } + else if(lhs == null && rhs != null) + { + return -1; + } + else if(lhs != null && rhs == null) + { + return 1; + } + else + { + Identity lhsIdentity = lhs.ice_getIdentity(); + Identity rhsIdentity = rhs.ice_getIdentity(); + int n; + if((n = lhsIdentity.name.compareTo(rhsIdentity.name)) != 0) + { + return n; + } + return lhsIdentity.category.compareTo(rhsIdentity.category); + } + } + + /** + * Compares the object identities and facets of two proxies. + * + * @param lhs A proxy. + * @param rhs A proxy. + * @return -1 if the identity and facet in <code>lhs</code> compare + * less than the identity and facet in <code>rhs</code>; 0 if the identities + * and facets compare equal; 1, otherwise. + * + * @see ProxyIdentityFacetKey + * @see ProxyIdentityKey + * @see #proxyIdentityCompare + **/ + public static int + proxyIdentityAndFacetCompare(ObjectPrx lhs, ObjectPrx rhs) + { + if(lhs == null && rhs == null) + { + return 0; + } + else if(lhs == null && rhs != null) + { + return -1; + } + else if(lhs != null && rhs == null) + { + return 1; + } + else + { + Identity lhsIdentity = lhs.ice_getIdentity(); + Identity rhsIdentity = rhs.ice_getIdentity(); + int n; + if((n = lhsIdentity.name.compareTo(rhsIdentity.name)) != 0) + { + return n; + } + if((n = lhsIdentity.category.compareTo(rhsIdentity.category)) != 0) + { + return n; + } + + String lhsFacet = lhs.ice_getFacet(); + String rhsFacet = rhs.ice_getFacet(); + if(lhsFacet == null && rhsFacet == null) + { + return 0; + } + else if(lhsFacet == null) + { + return -1; + } + else if(rhsFacet == null) + { + return 1; + } + return lhsFacet.compareTo(rhsFacet); + } + } + + /** + * Returns the process-wide logger. + * + * @return The process-wide logger. + **/ + public static Logger + getProcessLogger() + { + synchronized(_processLoggerMutex) + { + if(_processLogger == null) + { + // + // TODO: Would be nice to be able to use process name as prefix by default. + // + _processLogger = new LoggerI("", ""); + } + + return _processLogger; + } + } + + /** + * Changes the process-wide logger. + * + * @param logger The new process-wide logger. + **/ + public static void + setProcessLogger(Logger logger) + { + synchronized(_processLoggerMutex) + { + _processLogger = logger; + } + } + + /** + * Returns the Ice version in the form <code>A.B.C</code>, where <code>A</code> indicates the + * major version, <code>B</code> indicates the minor version, and <code>C</code> indicates the + * patch level. + * + * @return The Ice version. + **/ + public static String + stringVersion() + { + return "3.7a3"; // "A.B.C", with A=major, B=minor, C=patch + } + + /** + * Returns the Ice version as an integer in the form <code>A.BB.CC</code>, where <code>A</code> + * indicates the major version, <code>BB</code> indicates the minor version, and <code>CC</code> + * indicates the patch level. For example, for Ice 3.3.1, the returned value is 30301. + * + * @return The Ice version. + **/ + public static int + intVersion() + { + return 30753; // AABBCC, with AA=major, BB=minor, CC=patch + } + + /** + * Converts a string to a protocol version. + * + * @param version The string to convert. + * + * @return The converted protocol version. + **/ + static public Ice.ProtocolVersion + stringToProtocolVersion(String version) + { + return new Ice.ProtocolVersion(stringToMajor(version), stringToMinor(version)); + } + + /** + * Converts a string to an encoding version. + * + * @param version The string to convert. + * + * @return The converted object identity. + **/ + static public Ice.EncodingVersion + stringToEncodingVersion(String version) + { + return new Ice.EncodingVersion(stringToMajor(version), stringToMinor(version)); + } + + /** + * Converts a protocol version to a string. + * + * @param v The protocol version to convert. + * + * @return The converted string. + **/ + static public String + protocolVersionToString(Ice.ProtocolVersion v) + { + return majorMinorToString(v.major, v.minor); + } + + /** + * Converts an encoding version to a string. + * + * @param v The encoding version to convert. + * + * @return The converted string. + **/ + static public String + encodingVersionToString(Ice.EncodingVersion v) + { + return majorMinorToString(v.major, v.minor); + } + + /** + * Returns the supported Ice protocol version. + * + * @return The Ice protocol version. + **/ + static public Ice.ProtocolVersion + currentProtocol() + { + return IceInternal.Protocol.currentProtocol.clone(); + } + + /** + * Returns the supported Ice encoding version. + * + * @return The Ice encoding version. + **/ + static public Ice.EncodingVersion + currentEncoding() + { + return IceInternal.Protocol.currentEncoding.clone(); + } + + /** + * Translates a Slice type id to a Java class name. + * + * @param id The Slice type id, such as <code>::Module::Type</code>. + * @return The equivalent Java class name, or null if the type id is malformed. + **/ + public static String typeIdToClass(String id) + { + if(!id.startsWith("::")) + { + return null; + } + + StringBuilder buf = new StringBuilder(id.length()); + + int start = 2; + boolean done = false; + while(!done) + { + int end = id.indexOf(':', start); + String s; + if(end != -1) + { + s = id.substring(start, end); + start = end + 2; + } + else + { + s = id.substring(start); + done = true; + } + if(buf.length() > 0) + { + buf.append('.'); + } + buf.append(fixKwd(s)); + } + + return buf.toString(); + } + + private static String fixKwd(String name) + { + // + // Keyword list. *Must* be kept in alphabetical order. Note that checkedCast and uncheckedCast + // are not Java keywords, but are in this list to prevent illegal code being generated if + // someone defines Slice operations with that name. + // + final String[] keywordList = + { + "abstract", "assert", "boolean", "break", "byte", "case", "catch", + "char", "checkedCast", "class", "clone", "const", "continue", "default", "do", + "double", "else", "enum", "equals", "extends", "false", "final", "finalize", + "finally", "float", "for", "getClass", "goto", "hashCode", "if", + "implements", "import", "instanceof", "int", "interface", "long", + "native", "new", "notify", "notifyAll", "null", "package", "private", + "protected", "public", "return", "short", "static", "strictfp", "super", "switch", + "synchronized", "this", "throw", "throws", "toString", "transient", + "true", "try", "uncheckedCast", "void", "volatile", "wait", "while" + }; + boolean found = java.util.Arrays.binarySearch(keywordList, name) >= 0; + return found ? "_" + name : name; + } + + static private byte + stringToMajor(String str) + { + int pos = str.indexOf('.'); + if(pos == -1) + { + throw new Ice.VersionParseException("malformed version value `" + str + "'"); + } + + String majStr = str.substring(0, pos); + int majVersion; + try + { + majVersion = Integer.parseInt(majStr); + } + catch(NumberFormatException ex) + { + throw new Ice.VersionParseException("invalid version value `" + str + "'"); + } + + if(majVersion < 1 || majVersion > 255) + { + throw new Ice.VersionParseException("range error in version `" + str + "'"); + } + + return (byte)majVersion; + } + + static private byte + stringToMinor(String str) + { + int pos = str.indexOf('.'); + if(pos == -1) + { + throw new Ice.VersionParseException("malformed version value `" + str + "'"); + } + + String minStr = str.substring(pos + 1, str.length()); + int minVersion; + try + { + minVersion = Integer.parseInt(minStr); + } + catch(NumberFormatException ex) + { + throw new Ice.VersionParseException("invalid version value `" + str + "'"); + } + + if(minVersion < 0 || minVersion > 255) + { + throw new Ice.VersionParseException("range error in version `" + str + "'"); + } + + return (byte)minVersion; + } + + static private String + majorMinorToString(byte major, byte minor) + { + StringBuilder str = new StringBuilder(); + str.append(major < 0 ? major + 255 : (int)major); + str.append("."); + str.append(minor < 0 ? minor + 255 : (int)minor); + return str.toString(); + } + + public final static Ice.ProtocolVersion Protocol_1_0 = new Ice.ProtocolVersion((byte)1, (byte)0); + + public final static Ice.EncodingVersion Encoding_1_0 = new Ice.EncodingVersion((byte)1, (byte)0); + public final static Ice.EncodingVersion Encoding_1_1 = new Ice.EncodingVersion((byte)1, (byte)1); + + private static java.lang.Object _processLoggerMutex = new java.lang.Object(); + private static Logger _processLogger = null; +} diff --git a/java-compat/src/Ice/src/main/java/Ice/ValueFactoryManagerI.java b/java-compat/src/Ice/src/main/java/Ice/ValueFactoryManagerI.java new file mode 100644 index 00000000000..13e968f5cae --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/ValueFactoryManagerI.java @@ -0,0 +1,30 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +public class ValueFactoryManagerI implements ValueFactoryManager +{ + public synchronized void add(ValueFactory factory, String id) + { + if(_factoryMap.containsKey(id)) + { + throw new AlreadyRegisteredException("value factory", id); + } + + _factoryMap.put(id, factory); + } + + public synchronized ValueFactory find(String id) + { + return _factoryMap.get(id); + } + + private java.util.HashMap<String, ValueFactory> _factoryMap = new java.util.HashMap<String, ValueFactory>(); +} diff --git a/java-compat/src/Ice/src/main/java/Ice/_AMD_Object_ice_invoke.java b/java-compat/src/Ice/src/main/java/Ice/_AMD_Object_ice_invoke.java new file mode 100644 index 00000000000..edc77cb14be --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/_AMD_Object_ice_invoke.java @@ -0,0 +1,38 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +final class _AMD_Object_ice_invoke extends IceInternal.IncomingAsync implements AMD_Object_ice_invoke +{ + public + _AMD_Object_ice_invoke(IceInternal.Incoming in) + { + super(in); + } + + @Override + public void + ice_response(boolean ok, byte[] outEncaps) + { + if(__validateResponse(ok)) + { + try + { + __writeParamEncaps(outEncaps, ok); + } + catch(Ice.LocalException ex) + { + __exception(ex); + return; + } + __response(); + } + } +} diff --git a/java-compat/src/Ice/src/main/java/Ice/_Callback_Object_ice_invoke.java b/java-compat/src/Ice/src/main/java/Ice/_Callback_Object_ice_invoke.java new file mode 100644 index 00000000000..6357f50555c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/Ice/_Callback_Object_ice_invoke.java @@ -0,0 +1,28 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Ice; + +/** + * Callback object for {@link ObjectPrx#begin_ice_invoke}. + **/ +public interface _Callback_Object_ice_invoke extends Ice.TwowayCallback +{ + /** + * The Ice run time calls <code>response</code> when an asynchronous operation invocation + * completes successfully or raises a user exception. + * + * @param ret Indicates the result of the invocation. If <code>true</code>, the operation + * completed succesfully; if <code>false</code>, the operation raised a user exception. + * @param outParams Contains the encoded out-parameters of the operation (if any) if <code>ok</code> + * is <code>true</code>; otherwise, if <code>ok</code> is <code>false</code>, contains the + * encoded user exception raised by the operation. + **/ + public void response(boolean ret, byte[] outParams); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ACMConfig.java b/java-compat/src/Ice/src/main/java/IceInternal/ACMConfig.java new file mode 100644 index 00000000000..291e9d1c59f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ACMConfig.java @@ -0,0 +1,82 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ACMConfig implements java.lang.Cloneable +{ + ACMConfig(boolean server) + { + timeout = 60 * 1000; + heartbeat = Ice.ACMHeartbeat.HeartbeatOnInvocation; + close = server ? Ice.ACMClose.CloseOnInvocation : Ice.ACMClose.CloseOnInvocationAndIdle; + } + + public ACMConfig(Ice.Properties p, Ice.Logger l, String prefix, ACMConfig dflt) + { + assert(prefix != null); + + String timeoutProperty; + if((prefix.equals("Ice.ACM.Client") || prefix.equals("Ice.ACM.Server")) && + p.getProperty(prefix + ".Timeout").isEmpty()) + { + timeoutProperty = prefix; // Deprecated property. + } + else + { + timeoutProperty = prefix + ".Timeout"; + } + + timeout = p.getPropertyAsIntWithDefault(timeoutProperty, dflt.timeout / 1000) * 1000; // To milliseconds + + int hb = p.getPropertyAsIntWithDefault(prefix + ".Heartbeat", dflt.heartbeat.ordinal()); + Ice.ACMHeartbeat[] heartbeatValues = Ice.ACMHeartbeat.values(); + if(hb >= 0 && hb < heartbeatValues.length) + { + heartbeat = heartbeatValues[hb]; + } + else + { + l.warning("invalid value for property `" + prefix + ".Heartbeat" + "', default value will be used instead"); + heartbeat = dflt.heartbeat; + } + + Ice.ACMClose[] closeValues = Ice.ACMClose.values(); + int cl = p.getPropertyAsIntWithDefault(prefix + ".Close", dflt.close.ordinal()); + if(cl >= 0 && cl < closeValues.length) + { + close = closeValues[cl]; + } + else + { + l.warning("invalid value for property `" + prefix + ".Close" + "', default value will be used instead"); + close = dflt.close; + } + } + + @Override + public ACMConfig + clone() + { + ACMConfig c = null; + try + { + c = (ACMConfig)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; // impossible + } + return c; + } + + public int timeout; + public Ice.ACMHeartbeat heartbeat; + public Ice.ACMClose close; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ACMMonitor.java b/java-compat/src/Ice/src/main/java/IceInternal/ACMMonitor.java new file mode 100644 index 00000000000..0265886b023 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ACMMonitor.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface ACMMonitor +{ + void add(Ice.ConnectionI con); + void remove(Ice.ConnectionI con); + void reap(Ice.ConnectionI con); + + ACMMonitor acm(Ice.IntOptional timeout, Ice.Optional<Ice.ACMClose> close, Ice.Optional<Ice.ACMHeartbeat> heartbeat); + Ice.ACM getACM(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Acceptor.java b/java-compat/src/Ice/src/main/java/IceInternal/Acceptor.java new file mode 100644 index 00000000000..628e147620a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Acceptor.java @@ -0,0 +1,23 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Acceptor +{ + java.nio.channels.ServerSocketChannel fd(); + void setReadyCallback(ReadyCallback callback); + void close(); + EndpointI listen(); + Transceiver accept(); + String protocol(); + @Override + String toString(); + String toDetailedString(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/AsyncResultI.java b/java-compat/src/Ice/src/main/java/IceInternal/AsyncResultI.java new file mode 100644 index 00000000000..41f49774a0e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/AsyncResultI.java @@ -0,0 +1,469 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import Ice.AsyncResult; +import Ice.Communicator; +import Ice.CommunicatorDestroyedException; +import Ice.Connection; + +public class AsyncResultI implements AsyncResult +{ + @Override + public void cancel() + { + cancel(new Ice.InvocationCanceledException()); + } + + @Override + public Communicator getCommunicator() + { + return _communicator; + } + + @Override + public Connection getConnection() + { + return null; + } + + @Override + public Ice.ObjectPrx getProxy() + { + return null; + } + + @Override + public final boolean isCompleted() + { + synchronized(this) + { + return (_state & StateDone) > 0; + } + } + + @Override + public final void waitForCompleted() + { + synchronized(this) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + while((_state & StateDone) == 0) + { + try + { + this.wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + } + } + + @Override + public final boolean isSent() + { + synchronized(this) + { + return (_state & StateSent) > 0; + } + } + + @Override + public final void waitForSent() + { + synchronized(this) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + while((_state & StateSent) == 0 && _exception == null) + { + try + { + this.wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + } + } + + @Override + public final void throwLocalException() + { + synchronized(this) + { + if(_exception != null) + { + throw _exception; + } + } + } + + @Override + public final boolean sentSynchronously() + { + return _sentSynchronously; // No lock needed, immutable + } + + @Override + public final String getOperation() + { + return _operation; + } + + public final void invokeSent() + { + assert(_callback != null); + + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(_callback.getClass().getClassLoader()); + } + + try + { + _callback.__sent(this); + } + catch(java.lang.RuntimeException ex) + { + warning(ex); + } + catch(java.lang.Error exc) + { + error(exc); + if(!(exc instanceof java.lang.AssertionError || exc instanceof java.lang.OutOfMemoryError)) + { + throw exc; + } + } + finally + { + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(null); + } + } + + if(_observer != null) + { + Ice.ObjectPrx proxy = getProxy(); + if(proxy == null || !proxy.ice_isTwoway()) + { + _observer.detach(); + _observer = null; + } + } + } + + public final void invokeCompleted() + { + assert(_callback != null); + + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(_callback.getClass().getClassLoader()); + } + + try + { + _callback.__completed(this); + } + catch(RuntimeException ex) + { + warning(ex); + } + catch(AssertionError exc) + { + error(exc); + } + catch(OutOfMemoryError exc) + { + error(exc); + } + finally + { + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(null); + } + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + } + + public final void invokeCompletedAsync() + { + // + // CommunicatorDestroyedCompleted is the only exception that can propagate directly + // from this method. + // + _instance.clientThreadPool().dispatch(new DispatchWorkItem(_cachedConnection) + { + @Override + public void run() + { + invokeCompleted(); + } + }); + } + + synchronized public void cancelable(final CancellationHandler handler) + { + if(_cancellationException != null) + { + try + { + throw _cancellationException; + } + finally + { + _cancellationException = null; + } + } + _cancellationHandler = handler; + } + + public final boolean __wait() + { + try + { + synchronized(this) + { + if((_state & StateEndCalled) > 0) + { + throw new IllegalArgumentException("end_ method called more than once"); + } + + _state |= StateEndCalled; + if(Thread.interrupted()) + { + throw new InterruptedException(); + } + while((_state & StateDone) == 0) + { + this.wait(); + } + + if(_exception != null) + { + throw (Ice.Exception)_exception.fillInStackTrace(); + } + + return (_state & StateOK) > 0; + } + } + catch(InterruptedException ex) + { + Ice.OperationInterruptedException exc = new Ice.OperationInterruptedException(); + cancel(exc); // Must be called outside the synchronization + throw exc; + } + } + + public void cacheMessageBuffers() + { + } + + protected AsyncResultI(Communicator communicator, Instance instance, String op, CallbackBase del) + { + _communicator = communicator; + _instance = instance; + _operation = op; + _state = 0; + _sentSynchronously = false; + _exception = null; + _callback = del; + } + + protected boolean sent(boolean done) + { + synchronized(this) + { + assert(_exception == null); + + boolean alreadySent = (_state & StateSent) != 0; + _state |= StateSent; + if(done) + { + _state |= StateDone | StateOK; + _cancellationHandler = null; + if(_observer != null && (_callback == null || !_callback.__hasSentCallback())) + { + _observer.detach(); + _observer = null; + } + + // + // For oneway requests after the data has been sent + // the buffers can be reused unless this is a + // collocated invocation. For collocated invocations + // the buffer won't be reused because it has already + // been marked as cached in invokeCollocated. + // + cacheMessageBuffers(); + } + this.notifyAll(); + return !alreadySent && _callback != null && _callback.__hasSentCallback(); + } + } + + protected boolean finished(boolean ok) + { + synchronized(this) + { + _state |= StateDone; + if(ok) + { + _state |= StateOK; + } + _cancellationHandler = null; + if(_callback == null) + { + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + } + this.notifyAll(); + return _callback != null; + } + } + + protected boolean finished(Ice.Exception ex) + { + synchronized(this) + { + _state |= StateDone; + _exception = ex; + _cancellationHandler = null; + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + if(_callback == null) + { + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + } + this.notifyAll(); + return _callback != null; + } + } + + protected final void invokeSentAsync() + { + // + // This is called when it's not safe to call the sent callback + // synchronously from this thread. Instead the exception callback + // is called asynchronously from the client thread pool. + // + try + { + _instance.clientThreadPool().dispatch(new DispatchWorkItem(_cachedConnection) + { + @Override + public void run() + { + invokeSent(); + } + }); + } + catch(CommunicatorDestroyedException exc) + { + } + } + + protected void cancel(Ice.LocalException ex) + { + CancellationHandler handler; + synchronized(this) + { + _cancellationException = ex; + if(_cancellationHandler == null) + { + return; + } + handler = _cancellationHandler; + } + handler.asyncRequestCanceled((OutgoingAsyncBase)this, ex); + } + + protected Ice.Instrumentation.InvocationObserver getObserver() + { + return _observer; + } + + protected static void check(AsyncResult r, String operation) + { + if(r == null) + { + throw new IllegalArgumentException("AsyncResult == null"); + } + else if(r.getOperation() != operation) // Do NOT use equals() here - we are comparing reference equality + { + throw new IllegalArgumentException("Incorrect operation for end_" + operation + " method: " + + r.getOperation()); + } + } + + private void warning(RuntimeException ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) + { + String s = "exception raised by AMI callback:\n" + Ex.toString(ex); + _instance.initializationData().logger.warning(s); + } + } + + private void error(Error error) + { + String s = "error raised by AMI callback:\n" + Ex.toString(error); + _instance.initializationData().logger.error(s); + } + + protected final Instance _instance; + protected Ice.Instrumentation.InvocationObserver _observer; + protected Connection _cachedConnection; + protected boolean _sentSynchronously; + + private final Communicator _communicator; + private final String _operation; + private final CallbackBase _callback; + + private Ice.Exception _exception; + + private CancellationHandler _cancellationHandler; + private Ice.LocalException _cancellationException; + + protected static final byte StateOK = 0x1; + protected static final byte StateDone = 0x2; + protected static final byte StateSent = 0x4; + protected static final byte StateEndCalled = 0x8; + protected static final byte StateCachedBuffers = 0x10; + protected byte _state; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/AsyncStatus.java b/java-compat/src/Ice/src/main/java/IceInternal/AsyncStatus.java new file mode 100644 index 00000000000..19fa9f28cb0 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/AsyncStatus.java @@ -0,0 +1,17 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class AsyncStatus +{ + public static final int Queued = 0; + public static final int Sent = 1; + public static final int InvokeSentCallback = 2; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/BZip2.java b/java-compat/src/Ice/src/main/java/IceInternal/BZip2.java new file mode 100644 index 00000000000..a29b7c30c32 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/BZip2.java @@ -0,0 +1,281 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class BZip2 +{ + public static Buffer compress(Buffer buf, int headerSize, int compressionLevel) + { + assert(supported()); + + int uncompressedLen = buf.size() - headerSize; + int compressedLen = (int)(uncompressedLen * 1.01 + 600); + byte[] compressed = new byte[compressedLen]; + + byte[] data = null; + int offset = 0; + try + { + // + // If the ByteBuffer is backed by an array then we can avoid + // an extra copy by using the array directly. + // + data = buf.b.array(); + offset = buf.b.arrayOffset(); + } + catch(Exception ex) + { + // + // Otherwise, allocate an array to hold a copy of the uncompressed data. + // + data = new byte[buf.size()]; + buf.b.position(0); + buf.b.get(data); + } + + try + { + // + // Compress the data using the class org.apache.tools.bzip2.CBZip2OutputStream. + // Its constructor requires an OutputStream argument, therefore we pass the + // compressed buffer in an OutputStream wrapper. + // + BufferedOutputStream bos = new BufferedOutputStream(compressed); + // + // For interoperability with the bzip2 C library, we insert the magic bytes + // 'B', 'Z' before invoking the Java implementation. + // + bos.write('B'); + bos.write('Z'); + java.lang.Object[] args = new java.lang.Object[]{ bos, Integer.valueOf(compressionLevel) }; + java.io.OutputStream os = (java.io.OutputStream)_bzOutputStreamCtor.newInstance(args); + os.write(data, offset + headerSize, uncompressedLen); + os.close(); + compressedLen = bos.pos(); + } + catch(Exception ex) + { + throw new Ice.CompressionException("bzip2 compression failure", ex); + } + + // + // Don't bother if the compressed data is larger than the + // uncompressed data. + // + if(compressedLen >= uncompressedLen) + { + return null; + } + + Buffer r = new Buffer(false); + r.resize(headerSize + 4 + compressedLen, false); + r.b.position(0); + + // + // Copy the header from the uncompressed stream to the compressed one. + // + r.b.put(data, offset, headerSize); + + // + // Add the size of the uncompressed stream before the message body. + // + r.b.putInt(buf.size()); + + // + // Add the compressed message body. + // + r.b.put(compressed, 0, compressedLen); + + return r; + } + + public static Buffer uncompress(Buffer buf, int headerSize, int messageSizeMax) + { + assert(supported()); + + buf.b.position(headerSize); + int uncompressedSize = buf.b.getInt(); + if(uncompressedSize <= headerSize) + { + throw new Ice.IllegalMessageSizeException(); + } + if(uncompressedSize > messageSizeMax) + { + IceInternal.Ex.throwMemoryLimitException(uncompressedSize, messageSizeMax); + } + + int compressedLen = buf.size() - headerSize - 4; + + byte[] compressed = null; + int offset = 0; + try + { + // + // If the ByteBuffer is backed by an array then we can avoid + // an extra copy by using the array directly. + // + compressed = buf.b.array(); + offset = buf.b.arrayOffset(); + } + catch(Exception ex) + { + // + // Otherwise, allocate an array to hold a copy of the compressed data. + // + compressed = new byte[buf.size()]; + buf.b.position(0); + buf.b.get(compressed); + } + + Buffer r = new Buffer(false); + r.resize(uncompressedSize, false); + + try + { + // + // Uncompress the data using the class org.apache.tools.bzip2.CBZip2InputStream. + // Its constructor requires an InputStream argument, therefore we pass the + // compressed data in a ByteArrayInputStream. + // + java.io.ByteArrayInputStream bais = + new java.io.ByteArrayInputStream(compressed, offset + headerSize + 4, compressedLen); + // + // For interoperability with the bzip2 C library, we insert the magic bytes + // 'B', 'Z' during compression and therefore must extract them before we + // invoke the Java implementation. + // + byte magicB = (byte)bais.read(); + byte magicZ = (byte)bais.read(); + if(magicB != (byte)'B' || magicZ != (byte)'Z') + { + Ice.CompressionException e = new Ice.CompressionException(); + e.reason = "bzip2 uncompression failure: invalid magic bytes"; + throw e; + } + java.lang.Object[] args = new java.lang.Object[]{ bais }; + java.io.InputStream is = (java.io.InputStream)_bzInputStreamCtor.newInstance(args); + r.b.position(headerSize); + byte[] arr = new byte[8 * 1024]; + int n; + while((n = is.read(arr)) != -1) + { + r.b.put(arr, 0, n); + } + is.close(); + } + catch(Exception ex) + { + throw new Ice.CompressionException("bzip2 uncompression failure", ex); + } + + // + // Copy the header from the compressed stream to the uncompressed one. + // + r.b.position(0); + r.b.put(compressed, offset, headerSize); + + return r; + } + + private static boolean _checked = false; + private static java.lang.reflect.Constructor<?> _bzInputStreamCtor; + private static java.lang.reflect.Constructor<?> _bzOutputStreamCtor; + + public synchronized static boolean supported() + { + // + // Use lazy initialization when determining whether support for bzip2 compression is available. + // + if(!_checked) + { + _checked = true; + try + { + Class<?> cls; + Class<?>[] types = new Class<?>[1]; + cls = IceInternal.Util.findClass("org.apache.tools.bzip2.CBZip2InputStream", null); + if(cls != null) + { + types[0] = java.io.InputStream.class; + _bzInputStreamCtor = cls.getDeclaredConstructor(types); + } + cls = IceInternal.Util.findClass("org.apache.tools.bzip2.CBZip2OutputStream", null); + if(cls != null) + { + types = new Class[2]; + types[0] = java.io.OutputStream.class; + types[1] = Integer.TYPE; + _bzOutputStreamCtor = cls.getDeclaredConstructor(types); + } + } + catch(Exception ex) + { + // Ignore - bzip2 compression not available. + } + } + return _bzInputStreamCtor != null && _bzOutputStreamCtor != null; + } + + private static class BufferedOutputStream extends java.io.OutputStream + { + BufferedOutputStream(byte[] data) + { + _data = data; + } + + @Override + public void close() + throws java.io.IOException + { + } + + @Override + public void flush() + throws java.io.IOException + { + } + + @Override + public void write(byte[] b) + throws java.io.IOException + { + assert(_data.length - _pos >= b.length); + System.arraycopy(b, 0, _data, _pos, b.length); + _pos += b.length; + } + + @Override + public void write(byte[] b, int off, int len) + throws java.io.IOException + { + assert(_data.length - _pos >= len); + System.arraycopy(b, off, _data, _pos, len); + _pos += len; + } + + @Override + public void write(int b) + throws java.io.IOException + { + assert(_data.length - _pos >= 1); + _data[_pos] = (byte)b; + ++_pos; + } + + int + pos() + { + return _pos; + } + + private byte[] _data; + private int _pos; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/BatchRequestQueue.java b/java-compat/src/Ice/src/main/java/IceInternal/BatchRequestQueue.java new file mode 100644 index 00000000000..3db2ac67177 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/BatchRequestQueue.java @@ -0,0 +1,239 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class BatchRequestQueue +{ + class BatchRequestI implements Ice.BatchRequest + { + public void reset(Ice.ObjectPrx proxy, String operation, int size) + { + _proxy = proxy; + _operation = operation; + _size = size; + } + + @Override + public void enqueue() + { + enqueueBatchRequest(); + } + + @Override + public Ice.ObjectPrx getProxy() + { + return _proxy; + } + + @Override + public String getOperation() + { + return _operation; + } + + @Override + public int getSize() + { + return _size; + } + + private Ice.ObjectPrx _proxy; + private String _operation; + private int _size; + } + + public + BatchRequestQueue(Instance instance, boolean datagram) + { + Ice.InitializationData initData = instance.initializationData(); + _interceptor = initData.batchRequestInterceptor; + _batchStreamInUse = false; + _batchRequestNum = 0; + _batchStream = new Ice.OutputStream(instance, Protocol.currentProtocolEncoding); + _batchStream.writeBlob(Protocol.requestBatchHdr); + _batchMarker = _batchStream.size(); + _request = new BatchRequestI(); + + _maxSize = instance.batchAutoFlushSize(); + if(_maxSize > 0 && datagram) + { + int udpSndSize = initData.properties.getPropertyAsIntWithDefault("Ice.UDP.SndSize", 65535 - _udpOverhead); + if(udpSndSize < _maxSize) + { + _maxSize = udpSndSize; + } + } + } + + synchronized public void + prepareBatchRequest(Ice.OutputStream os) + { + if(_exception != null) + { + throw (Ice.LocalException)_exception.fillInStackTrace(); + } + + waitStreamInUse(false); + _batchStreamInUse = true; + _batchStream.swap(os); + } + + public void + finishBatchRequest(Ice.OutputStream os, Ice.ObjectPrx proxy, String operation) + { + // + // No need for synchronization, no other threads are supposed + // to modify the queue since we set _batchStreamInUse to true. + // + assert(_batchStreamInUse); + _batchStream.swap(os); + + try + { + _batchStreamCanFlush = true; // Allow flush to proceed even if the stream is marked in use. + + if(_maxSize > 0 && _batchStream.size() >= _maxSize) + { + proxy.begin_ice_flushBatchRequests(); // Auto flush + } + + assert(_batchMarker < _batchStream.size()); + if(_interceptor != null) + { + _request.reset(proxy, operation, _batchStream.size() - _batchMarker); + _interceptor.enqueue(_request, _batchRequestNum, _batchMarker); + } + else + { + _batchMarker = _batchStream.size(); + ++_batchRequestNum; + } + } + finally + { + synchronized(this) + { + _batchStream.resize(_batchMarker); + _batchStreamInUse = false; + _batchStreamCanFlush = false; + notifyAll(); + } + } + } + + synchronized public void + abortBatchRequest(Ice.OutputStream os) + { + if(_batchStreamInUse) + { + _batchStream.swap(os); + _batchStream.resize(_batchMarker); + _batchStreamInUse = false; + notifyAll(); + } + } + + synchronized public int + swap(Ice.OutputStream os) + { + if(_batchRequestNum == 0) + { + return 0; + } + + waitStreamInUse(true); + + byte[] lastRequest = null; + if(_batchMarker < _batchStream.size()) + { + lastRequest = new byte[_batchStream.size() - _batchMarker]; + Buffer buffer = _batchStream.getBuffer(); + buffer.b.position(_batchMarker); + buffer.b.get(lastRequest); + _batchStream.resize(_batchMarker); + } + + int requestNum = _batchRequestNum; + _batchStream.swap(os); + + // + // Reset the batch. + // + _batchRequestNum = 0; + _batchStream.writeBlob(Protocol.requestBatchHdr); + _batchMarker = _batchStream.size(); + if(lastRequest != null) + { + _batchStream.writeBlob(lastRequest); + } + return requestNum; + } + + synchronized public void + destroy(Ice.LocalException ex) + { + _exception = ex; + } + + synchronized public boolean + isEmpty() + { + return _batchStream.size() == Protocol.requestBatchHdr.length; + } + + private void + waitStreamInUse(boolean flush) + { + // + // This is similar to a mutex lock in that the stream is + // only "locked" while marshaling. As such we don't permit the wait + // to be interrupted. Instead the interrupted status is saved and + // restored. + // + boolean interrupted = false; + while(_batchStreamInUse && !(flush && _batchStreamCanFlush)) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + interrupted = true; + } + } + // + // Restore the interrupted flag if we were interrupted. + // + if(interrupted) + { + Thread.currentThread().interrupt(); + } + } + + private void enqueueBatchRequest() + { + assert(_batchMarker < _batchStream.size()); + _batchMarker = _batchStream.size(); + ++_batchRequestNum; + } + + private Ice.BatchRequestInterceptor _interceptor; + private Ice.OutputStream _batchStream; + private boolean _batchStreamInUse; + private boolean _batchStreamCanFlush; + private int _batchRequestNum; + private int _batchMarker; + private BatchRequestI _request; + private Ice.LocalException _exception; + private int _maxSize; + + final private static int _udpOverhead = 20 + 8; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/BufSizeWarnInfo.java b/java-compat/src/Ice/src/main/java/IceInternal/BufSizeWarnInfo.java new file mode 100644 index 00000000000..67e84387319 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/BufSizeWarnInfo.java @@ -0,0 +1,25 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class BufSizeWarnInfo +{ + // Whether send size warning has been emitted + public boolean sndWarn; + + // The send size for which the warning wwas emitted + public int sndSize; + + // Whether receive size warning has been emitted + public boolean rcvWarn; + + // The receive size for which the warning wwas emitted + public int rcvSize; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Buffer.java b/java-compat/src/Ice/src/main/java/IceInternal/Buffer.java new file mode 100644 index 00000000000..911d8df76d4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Buffer.java @@ -0,0 +1,223 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// An instance of java.nio.ByteBuffer cannot grow beyond its initial capacity. +// This class wraps a ByteBuffer and supports reallocation. +// +public class Buffer +{ + public Buffer(boolean direct) + { + this(direct, java.nio.ByteOrder.LITTLE_ENDIAN); + } + + public Buffer(boolean direct, java.nio.ByteOrder order) + { + b = _emptyBuffer; + _size = 0; + _capacity = 0; + _direct = direct; + _order = order; + } + + public Buffer(byte[] data) + { + this(data, java.nio.ByteOrder.LITTLE_ENDIAN); + } + + public Buffer(byte[] data, java.nio.ByteOrder order) + { + b = java.nio.ByteBuffer.wrap(data); + b.order(order); + _size = data.length; + _capacity = 0; + _direct = false; + _order = order; + } + + public Buffer(java.nio.ByteBuffer data) + { + this(data, java.nio.ByteOrder.LITTLE_ENDIAN); + } + + public Buffer(java.nio.ByteBuffer data, java.nio.ByteOrder order) + { + b = data; + b.order(order); + _size = data.remaining(); + _capacity = 0; + _direct = false; + _order = order; + } + + public Buffer(Buffer buf, boolean adopt) + { + b = buf.b; + _size = buf._size; + _capacity = buf._capacity; + _direct = buf._direct; + _shrinkCounter = buf._shrinkCounter; + _order = buf._order; + + if(adopt) + { + buf.clear(); + } + } + + public int size() + { + return _size; + } + + public boolean empty() + { + return _size == 0; + } + + public void clear() + { + b = _emptyBuffer; + _size = 0; + _capacity = 0; + _shrinkCounter = 0; + } + + // + // Call expand(n) to add room for n additional bytes. Note that expand() + // examines the current position of the buffer first; we don't want to + // expand the buffer if the caller is writing to a location that is + // already in the buffer. + // + public void expand(int n) + { + final int sz = (b == _emptyBuffer) ? n : b.position() + n; + if(sz > _size) + { + resize(sz, false); + } + } + + public void resize(int n, boolean reading) + { + assert(b == _emptyBuffer || _capacity > 0); + + if(n == 0) + { + clear(); + } + else if(n > _capacity) + { + reserve(n); + } + _size = n; + + // + // When used for reading, we want to set the buffer's limit to the new size. + // + if(reading) + { + b.limit(_size); + } + } + + public void reset() + { + if(_size > 0 && _size * 2 < _capacity) + { + // + // If the current buffer size is smaller than the + // buffer capacity, we shrink the buffer memory to the + // current size. This is to avoid holding on to too much + // memory if it's not needed anymore. + // + if(++_shrinkCounter > 2) + { + reserve(_size); + _shrinkCounter = 0; + } + } + else + { + _shrinkCounter = 0; + } + _size = 0; + if(b != _emptyBuffer) + { + b.limit(b.capacity()); + b.position(0); + } + } + + private void reserve(int n) + { + if(n > _capacity) + { + _capacity = java.lang.Math.max(n, 2 * _capacity); + _capacity = java.lang.Math.max(240, _capacity); + } + else if(n < _capacity) + { + _capacity = n; + } + else + { + return; + } + + try + { + java.nio.ByteBuffer buf; + + if(_direct) + { + buf = java.nio.ByteBuffer.allocateDirect(_capacity); + } + else + { + buf = java.nio.ByteBuffer.allocate(_capacity); + } + + if(b == _emptyBuffer) + { + b = buf; + } + else + { + final int pos = b.position(); + b.position(0); + b.limit(java.lang.Math.min(_capacity, b.capacity())); + buf.put(b); + b = buf; + b.limit(b.capacity()); + b.position(pos); + } + + b.order(_order); // Preserve the original order. + } + catch(OutOfMemoryError ex) + { + _capacity = b.capacity(); // Restore the previous capacity. + throw ex; + } + } + + public java.nio.ByteBuffer b; + // Sentinel used for null buffer. + public java.nio.ByteBuffer _emptyBuffer = java.nio.ByteBuffer.allocate(0); + + private int _size; + private int _capacity; // Cache capacity to avoid excessive method calls. + private boolean _direct; // Use direct buffers? + private int _shrinkCounter; + private java.nio.ByteOrder _order; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CallbackBase.java b/java-compat/src/Ice/src/main/java/IceInternal/CallbackBase.java new file mode 100644 index 00000000000..b482e9a71cd --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/CallbackBase.java @@ -0,0 +1,25 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class CallbackBase +{ + public abstract void __completed(Ice.AsyncResult r); + public abstract void __sent(Ice.AsyncResult r); + public abstract boolean __hasSentCallback(); + + public static void check(boolean cb) + { + if(!cb) + { + throw new IllegalArgumentException("callback cannot be null"); + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CancellationHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/CancellationHandler.java new file mode 100644 index 00000000000..3085b41e3d0 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/CancellationHandler.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface CancellationHandler +{ + void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CollocatedObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/CollocatedObserverI.java new file mode 100644 index 00000000000..a29cc2ad237 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/CollocatedObserverI.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class CollocatedObserverI + extends IceMX.ObserverWithDelegate<IceMX.CollocatedMetrics, Ice.Instrumentation.CollocatedObserver> + implements Ice.Instrumentation.CollocatedObserver +{ + @Override + public void + reply(final int size) + { + forEach(new MetricsUpdate<IceMX.CollocatedMetrics>() + { + @Override + public void + update(IceMX.CollocatedMetrics v) + { + v.replySize += size; + } + }); + if(_delegate != null) + { + _delegate.reply(size); + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java new file mode 100644 index 00000000000..ad823f21319 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/CollocatedRequestHandler.java @@ -0,0 +1,436 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class CollocatedRequestHandler implements RequestHandler, ResponseHandler +{ + private class InvokeAllAsync extends DispatchWorkItem + { + private InvokeAllAsync(OutgoingAsyncBase outAsync, Ice.OutputStream os, int requestId, int batchRequestNum) + { + _outAsync = outAsync; + _os = os; + _requestId = requestId; + _batchRequestNum = batchRequestNum; + } + + @Override + public void run() + { + if(sentAsync(_outAsync)) + { + invokeAll(_os, _requestId, _batchRequestNum); + } + } + + private final OutgoingAsyncBase _outAsync; + private Ice.OutputStream _os; + private final int _requestId; + private final int _batchRequestNum; + } + + public + CollocatedRequestHandler(Reference ref, Ice.ObjectAdapter adapter) + { + _reference = ref; + _dispatcher = ref.getInstance().initializationData().dispatcher != null; + _adapter = (Ice.ObjectAdapterI)adapter; + _response = _reference.getMode() == Reference.ModeTwoway; + + _logger = _reference.getInstance().initializationData().logger; // Cached for better performance. + _traceLevels = _reference.getInstance().traceLevels(); // Cached for better performance. + _requestId = 0; + } + + @Override + public RequestHandler + update(RequestHandler previousHandler, RequestHandler newHandler) + { + return previousHandler == this ? newHandler : this; + } + + @Override + public int + sendAsyncRequest(ProxyOutgoingAsyncBase outAsync) + { + return outAsync.invokeCollocated(this); + } + + @Override + synchronized public void + asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) + { + Integer requestId = _sendAsyncRequests.remove(outAsync); + if(requestId != null) + { + if(requestId > 0) + { + _asyncRequests.remove(requestId); + } + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + _adapter.decDirectCount(); // invokeAll won't be called, decrease the direct count. + return; + } + + if(outAsync instanceof OutgoingAsync) + { + OutgoingAsync o = (OutgoingAsync)outAsync; + assert(o != null); + for(java.util.Map.Entry<Integer, OutgoingAsyncBase> e : _asyncRequests.entrySet()) + { + if(e.getValue() == o) + { + _asyncRequests.remove(e.getKey()); + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + return; + } + } + } + } + + @Override + public void + sendResponse(int requestId, final Ice.OutputStream os, byte status, boolean amd) + { + OutgoingAsyncBase outAsync = null; + synchronized(this) + { + assert(_response); + + if(_traceLevels.protocol >= 1) + { + fillInValue(os, 10, os.size()); + } + + // Adopt the OutputStream's buffer. + Ice.InputStream is = new Ice.InputStream(os.instance(), os.getEncoding(), os.getBuffer(), true); + + is.pos(Protocol.replyHdr.length + 4); + + if(_traceLevels.protocol >= 1) + { + TraceUtil.traceRecv(is, _logger, _traceLevels); + } + + outAsync = _asyncRequests.remove(requestId); + if(outAsync != null && !outAsync.completed(is)) + { + outAsync = null; + } + } + + if(outAsync != null) + { + // + // If called from an AMD dispatch, invoke asynchronously + // the completion callback since this might be called from + // the user code. + // + if(amd) + { + outAsync.invokeCompletedAsync(); + } + else + { + outAsync.invokeCompleted(); + } + } + _adapter.decDirectCount(); + } + + @Override + public void + sendNoResponse() + { + _adapter.decDirectCount(); + } + + @Override + public boolean + systemException(int requestId, Ice.SystemException ex, boolean amd) + { + handleException(requestId, ex, amd); + _adapter.decDirectCount(); + return true; + } + + @Override + public void + invokeException(int requestId, Ice.LocalException ex, int batchRequestNum, boolean amd) + { + handleException(requestId, ex, amd); + _adapter.decDirectCount(); + } + + @Override + public Reference + getReference() + { + return _reference; + } + + @Override + public Ice.ConnectionI + getConnection() + { + return null; + } + + int invokeAsyncRequest(OutgoingAsyncBase outAsync, int batchRequestNum, boolean sync) + { + // + // Increase the direct count to prevent the thread pool from being destroyed before + // invokeAll is called. This will also throw if the object adapter has been deactivated. + // + _adapter.incDirectCount(); + + int requestId = 0; + try + { + synchronized(this) + { + outAsync.cancelable(this); // This will throw if the request is canceled + + if(_response) + { + requestId = ++_requestId; + _asyncRequests.put(requestId, outAsync); + } + + _sendAsyncRequests.put(outAsync, requestId); + } + } + catch(Exception ex) + { + _adapter.decDirectCount(); + throw ex; + } + + outAsync.attachCollocatedObserver(_adapter, requestId); + + if(!sync || !_response || _reference.getInstance().queueRequests() || _reference.getInvocationTimeout() > 0) + { + _adapter.getThreadPool().dispatch(new InvokeAllAsync(outAsync, + outAsync.getOs(), + requestId, + batchRequestNum)); + } + else if(_dispatcher) + { + _adapter.getThreadPool().dispatchFromThisThread(new InvokeAllAsync(outAsync, + outAsync.getOs(), + requestId, + batchRequestNum)); + } + else // Optimization: directly call invokeAll if there's no dispatcher. + { + if(sentAsync(outAsync)) + { + invokeAll(outAsync.getOs(), requestId, batchRequestNum); + } + } + return AsyncStatus.Queued; + } + + private boolean + sentAsync(final OutgoingAsyncBase outAsync) + { + synchronized(this) + { + if(_sendAsyncRequests.remove(outAsync) == null) + { + return false; // The request timed-out. + } + + // + // This must be called within the synchronization to + // ensure completed(ex) can't be called concurrently if + // the request is canceled. + // + if(!outAsync.sent()) + { + return true; + } + } + + outAsync.invokeSent(); + return true; + } + + private void + invokeAll(Ice.OutputStream os, int requestId, int batchRequestNum) + { + if(_traceLevels.protocol >= 1) + { + fillInValue(os, 10, os.size()); + if(requestId > 0) + { + fillInValue(os, Protocol.headerSize, requestId); + } + else if(batchRequestNum > 0) + { + fillInValue(os, Protocol.headerSize, batchRequestNum); + } + TraceUtil.traceSend(os, _logger, _traceLevels); + } + + Ice.InputStream is = new Ice.InputStream(os.instance(), os.getEncoding(), os.getBuffer(), false); + + if(batchRequestNum > 0) + { + is.pos(Protocol.requestBatchHdr.length); + } + else + { + is.pos(Protocol.requestHdr.length); + } + + int invokeNum = batchRequestNum > 0 ? batchRequestNum : 1; + ServantManager servantManager = _adapter.getServantManager(); + try + { + while(invokeNum > 0) + { + // + // Increase the direct count for the dispatch. We increase it again here for + // each dispatch. It's important for the direct count to be > 0 until the last + // collocated request response is sent to make sure the thread pool isn't + // destroyed before. + // + try + { + _adapter.incDirectCount(); + } + catch(Ice.ObjectAdapterDeactivatedException ex) + { + handleException(requestId, ex, false); + break; + } + + Incoming in = new Incoming(_reference.getInstance(), this, null, _adapter, _response, (byte)0, + requestId); + in.invoke(servantManager, is); + --invokeNum; + } + } + catch(Ice.LocalException ex) + { + invokeException(requestId, ex, invokeNum, false); // Fatal invocation exception + } + catch(ServantError ex) + { + // + // ServantError is thrown when an Error has been raised by servant (or servant locator) + // code. We've already attempted to complete the invocation and send a response. + // + Throwable t = ex.getCause(); + // + // Suppress AssertionError and OutOfMemoryError, rethrow everything else. + // + if(!(t instanceof java.lang.AssertionError || t instanceof java.lang.OutOfMemoryError)) + { + throw (java.lang.Error)t; + } + } + catch(java.lang.Error ex) + { + // + // An Error was raised outside of servant code (i.e., by Ice code). + // Attempt to log the error and clean up. This may still fail + // depending on the severity of the error. + // + // Note that this does NOT send a response to the client. + // + Ice.UnknownException uex = new Ice.UnknownException(ex); + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + uex.unknown = sw.toString(); + _logger.error(uex.unknown); + invokeException(requestId, uex, invokeNum, false); + // + // Suppress AssertionError and OutOfMemoryError, rethrow everything else. + // + if(!(ex instanceof java.lang.AssertionError || ex instanceof java.lang.OutOfMemoryError)) + { + throw ex; + } + } + + _adapter.decDirectCount(); + } + + private void + handleException(int requestId, Ice.Exception ex, boolean amd) + { + if(requestId == 0) + { + return; // Ignore exception for oneway messages. + } + + OutgoingAsyncBase outAsync = null; + synchronized(this) + { + outAsync = _asyncRequests.remove(requestId); + if(outAsync != null && !outAsync.completed(ex)) + { + outAsync = null; + } + } + + if(outAsync != null) + { + // + // If called from an AMD dispatch, invoke asynchronously + // the completion callback since this might be called from + // the user code. + // + if(amd) + { + outAsync.invokeCompletedAsync(); + } + else + { + outAsync.invokeCompleted(); + } + } + } + + private void + fillInValue(Ice.OutputStream os, int pos, int value) + { + os.rewriteInt(value, pos); + } + + private final Reference _reference; + private final boolean _dispatcher; + private final boolean _response; + private final Ice.ObjectAdapterI _adapter; + private final Ice.Logger _logger; + private final TraceLevels _traceLevels; + + private int _requestId; + + // A map of outstanding requests that can be canceled. A request + // can be canceled if it has an invocation timeout, or we support + // interrupts. + private java.util.Map<OutgoingAsyncBase, Integer> _sendAsyncRequests = + new java.util.HashMap<OutgoingAsyncBase, Integer>(); + + private java.util.Map<Integer, OutgoingAsyncBase> _asyncRequests = + new java.util.HashMap<Integer, OutgoingAsyncBase>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorFlushBatch.java b/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorFlushBatch.java new file mode 100644 index 00000000000..309c9dd6a55 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorFlushBatch.java @@ -0,0 +1,164 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.Callable; + +public class CommunicatorFlushBatch extends IceInternal.AsyncResultI +{ + public static CommunicatorFlushBatch check(Ice.AsyncResult r, Ice.Communicator com, String operation) + { + check(r, operation); + if(!(r instanceof CommunicatorFlushBatch)) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + if(r.getCommunicator() != com) + { + throw new IllegalArgumentException("Communicator for call to end_" + operation + + " does not match communicator that was used to call corresponding " + + "begin_" + operation + " method"); + } + return (CommunicatorFlushBatch)r; + } + + public CommunicatorFlushBatch(Ice.Communicator communicator, Instance instance, String op, CallbackBase callback) + { + super(communicator, instance, op, callback); + + _observer = ObserverHelper.get(instance, op); + + // + // _useCount is initialized to 1 to prevent premature callbacks. + // The caller must invoke ready() after all flush requests have + // been initiated. + // + _useCount = 1; + } + + public void flushConnection(final Ice.ConnectionI con) + { + class FlushBatch extends OutgoingAsyncBase + { + public FlushBatch() + { + super(CommunicatorFlushBatch.this.getCommunicator(), + CommunicatorFlushBatch.this._instance, + CommunicatorFlushBatch.this.getOperation(), + null); + } + + @Override + public boolean sent() + { + if(_childObserver != null) + { + _childObserver.detach(); + _childObserver = null; + } + doCheck(false); + return false; + } + + // TODO: MJN: This is missing a test. + @Override + public boolean completed(Ice.Exception ex) + { + if(_childObserver != null) + { + _childObserver.failed(ex.ice_id()); + _childObserver.detach(); + _childObserver = null; + } + doCheck(false); + return false; + } + + @Override + protected Ice.Instrumentation.InvocationObserver getObserver() + { + return CommunicatorFlushBatch.this._observer; + } + } + + synchronized(this) + { + ++_useCount; + } + + try + { + final FlushBatch flushBatch = new FlushBatch(); + final int batchRequestNum = con.getBatchRequestQueue().swap(flushBatch.getOs()); + if(batchRequestNum == 0) + { + flushBatch.sent(); + } + else if(_instance.queueRequests()) + { + _instance.getQueueExecutor().executeNoThrow(new Callable<Void>() + { + @Override + public Void call() throws RetryException + { + con.sendAsyncRequest(flushBatch, false, false, batchRequestNum); + return null; + } + }); + } + else + { + con.sendAsyncRequest(flushBatch, false, false, batchRequestNum); + } + } + catch(RetryException ex) + { + doCheck(false); + throw ex.get(); + } + catch(Ice.LocalException ex) + { + doCheck(false); + throw ex; + } + } + + public void ready() + { + doCheck(true); + } + + private void doCheck(boolean userThread) + { + synchronized(this) + { + assert(_useCount > 0); + if(--_useCount > 0) + { + return; + } + } + + if(sent(true)) + { + if(userThread) + { + _sentSynchronously = true; + invokeSent(); + } + else + { + invokeSentAsync(); + } + } + } + + private int _useCount; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java new file mode 100644 index 00000000000..095948736e3 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/CommunicatorObserverI.java @@ -0,0 +1,840 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import IceMX.*; + +public class CommunicatorObserverI implements Ice.Instrumentation.CommunicatorObserver +{ + static void + addEndpointAttributes(MetricsHelper.AttributeResolver r, Class<?> cl) + throws Exception + { + r.add("endpoint", cl.getDeclaredMethod("getEndpoint")); + + Class<?> cli = Ice.EndpointInfo.class; + r.add("endpointType", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredMethod("type")); + r.add("endpointIsDatagram", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredMethod("datagram")); + r.add("endpointIsSecure", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredMethod("secure")); + r.add("endpointTimeout", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredField("timeout")); + r.add("endpointCompress", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredField("compress")); + + cli = Ice.IPEndpointInfo.class; + r.add("endpointHost", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredField("host")); + r.add("endpointPort", cl.getDeclaredMethod("getEndpointInfo"), cli.getDeclaredField("port")); + } + + static void + addConnectionAttributes(MetricsHelper.AttributeResolver r, Class<?> cl) + throws Exception + { + Class<?> cli = Ice.ConnectionInfo.class; + r.add("incoming", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("incoming")); + r.add("adapterName", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("adapterName")); + r.add("connectionId", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("connectionId")); + + cli = Ice.IPConnectionInfo.class; + r.add("localHost", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("localAddress")); + r.add("localPort", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("localPort")); + r.add("remoteHost", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("remoteAddress")); + r.add("remotePort", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("remotePort")); + + cli = Ice.UDPConnectionInfo.class; + r.add("mcastHost", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("mcastAddress")); + r.add("mcastPort", cl.getDeclaredMethod("getConnectionInfo"), cli.getDeclaredField("mcastPort")); + + addEndpointAttributes(r, cl); + } + + static public class ConnectionHelper extends MetricsHelper<ConnectionMetrics> + { + static private AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + add("parent", ConnectionHelper.class.getDeclaredMethod("getParent")); + add("id", ConnectionHelper.class.getDeclaredMethod("getId")); + add("state", ConnectionHelper.class.getDeclaredMethod("getState")); + addConnectionAttributes(this, ConnectionHelper.class); + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + } + } + }; + + ConnectionHelper(Ice.ConnectionInfo con, Ice.Endpoint endpt, Ice.Instrumentation.ConnectionState state) + { + super(_attributes); + _connectionInfo = con; + _endpoint = endpt; + _state = state; + } + + public String + getId() + { + if(_id == null) + { + StringBuilder os = new StringBuilder(); + Ice.IPConnectionInfo info = getIPConnectionInfo(); + if(info != null) + { + os.append(info.localAddress).append(':').append(info.localPort); + os.append(" -> "); + os.append(info.remoteAddress).append(':').append(info.remotePort); + } + else + { + os.append("connection-").append(_connectionInfo); + } + if(!_connectionInfo.connectionId.isEmpty()) + { + os.append(" [").append(_connectionInfo.connectionId).append("]"); + } + _id = os.toString(); + } + return _id; + } + + public String + getState() + { + switch(_state) + { + case ConnectionStateValidating: + return "validating"; + case ConnectionStateHolding: + return "holding"; + case ConnectionStateActive: + return "active"; + case ConnectionStateClosing: + return "closing"; + case ConnectionStateClosed: + return "closed"; + default: + assert(false); + return ""; + } + } + + public String + getParent() + { + if(_connectionInfo.adapterName != null && !_connectionInfo.adapterName.isEmpty()) + { + return _connectionInfo.adapterName; + } + else + { + return "Communicator"; + } + } + + public Ice.ConnectionInfo + getConnectionInfo() + { + return _connectionInfo; + } + + public Ice.Endpoint + getEndpoint() + { + return _endpoint; + } + + public Ice.EndpointInfo + getEndpointInfo() + { + if(_endpointInfo == null) + { + _endpointInfo = _endpoint.getInfo(); + } + return _endpointInfo; + } + + private Ice.IPConnectionInfo + getIPConnectionInfo() + { + for(Ice.ConnectionInfo p = _connectionInfo; p != null; p = p.underlying) + { + if(p instanceof Ice.IPConnectionInfo) + { + return (Ice.IPConnectionInfo)p; + } + } + return null; + } + + private final Ice.ConnectionInfo _connectionInfo; + private final Ice.Endpoint _endpoint; + private final Ice.Instrumentation.ConnectionState _state; + private String _id; + private Ice.EndpointInfo _endpointInfo; + } + + static public final class DispatchHelper extends MetricsHelper<DispatchMetrics> + { + static private final AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + Class<?> cl = DispatchHelper.class; + add("parent", cl.getDeclaredMethod("getParent")); + add("id", cl.getDeclaredMethod("getId")); + + addConnectionAttributes(this, cl); + + Class<?> clc = Ice.Current.class; + add("operation", cl.getDeclaredMethod("getCurrent"), clc.getDeclaredField("operation")); + add("identity", cl.getDeclaredMethod("getIdentity")); + add("facet", cl.getDeclaredMethod("getCurrent"), clc.getDeclaredField("facet")); + add("requestId", cl.getDeclaredMethod("getCurrent"), clc.getDeclaredField("requestId")); + add("mode", cl.getDeclaredMethod("getMode")); + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + } + } + }; + + DispatchHelper(Ice.Current current, int size) + { + super(_attributes); + _current = current; + _size = size; + } + + @Override + public void + initMetrics(DispatchMetrics v) + { + v.size += _size; + } + + @Override + protected String + defaultResolve(String attribute) + { + if(attribute.indexOf("context.", 0) == 0) + { + String v = _current.ctx.get(attribute.substring(8)); + if(v != null) + { + return v; + } + } + throw new IllegalArgumentException(attribute); + } + + public String + getMode() + { + return _current.requestId == 0 ? "oneway" : "twoway"; + } + + public String + getId() + { + if(_id == null) + { + StringBuilder os = new StringBuilder(); + if(_current.id.category != null && !_current.id.category.isEmpty()) + { + os.append(_current.id.category).append('/'); + } + os.append(_current.id.name).append(" [").append(_current.operation).append(']'); + _id = os.toString(); + } + return _id; + } + + public int + getRequestId() + { + return _current.requestId; + } + + public String + getParent() + { + return _current.adapter.getName(); + } + + public Ice.ConnectionInfo + getConnectionInfo() + { + if(_current.con != null) + { + return _current.con.getInfo(); + } + return null; + } + + public Ice.Endpoint + getEndpoint() + { + if(_current.con != null) + { + return _current.con.getEndpoint(); + } + return null; + } + + public Ice.Connection + getConnection() + { + return _current.con; + } + + public Ice.EndpointInfo + getEndpointInfo() + { + if(_current.con != null && _endpointInfo == null) + { + _endpointInfo = _current.con.getEndpoint().getInfo(); + } + return _endpointInfo; + } + + public Ice.Current + getCurrent() + { + return _current; + } + + public String + getIdentity() + { + return Ice.Util.identityToString(_current.id); + } + + final private Ice.Current _current; + final private int _size; + private String _id; + private Ice.EndpointInfo _endpointInfo; + } + + static public final class InvocationHelper extends MetricsHelper<InvocationMetrics> + { + static private final AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + Class<?> cl = InvocationHelper.class; + add("parent", cl.getDeclaredMethod("getParent")); + add("id", cl.getDeclaredMethod("getId")); + + add("operation", cl.getDeclaredMethod("getOperation")); + add("identity", cl.getDeclaredMethod("getIdentity")); + + Class<?> cli = Ice.ObjectPrx.class; + add("facet", cl.getDeclaredMethod("getProxy"), cli.getDeclaredMethod("ice_getFacet")); + add("encoding", cl.getDeclaredMethod("getEncodingVersion")); + add("mode", cl.getDeclaredMethod("getMode")); + add("proxy", cl.getDeclaredMethod("getProxy")); + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + } + } + }; + + InvocationHelper(Ice.ObjectPrx proxy, String op, java.util.Map<String, String> ctx) + { + super(_attributes); + _proxy = proxy; + _operation = op; + _context = ctx; + } + + @Override + protected String + defaultResolve(String attribute) + { + if(attribute.indexOf("context.", 0) == 0) + { + String v = _context.get(attribute.substring(8)); + if(v != null) + { + return v; + } + } + throw new IllegalArgumentException(attribute); + } + + public String + getMode() + { + if(_proxy == null) + { + throw new IllegalArgumentException("mode"); + } + + if(_proxy.ice_isTwoway()) + { + return "twoway"; + } + else if(_proxy.ice_isOneway()) + { + return "oneway"; + } + else if(_proxy.ice_isBatchOneway()) + { + return "batch-oneway"; + } + else if(_proxy.ice_isDatagram()) + { + return "datagram"; + } + else if(_proxy.ice_isBatchDatagram()) + { + return "batch-datagram"; + } + else + { + throw new IllegalArgumentException("mode"); + } + } + + public String + getId() + { + if(_id == null) + { + if(_proxy != null) + { + StringBuilder os = new StringBuilder(); + try + { + os.append(_proxy.ice_endpoints(emptyEndpoints)).append(" [").append(_operation).append(']'); + } + catch(Exception ex) + { + // Either a fixed proxy or the communicator is destroyed. + os.append(Ice.Util.identityToString(_proxy.ice_getIdentity())); + os.append(" [").append(_operation).append(']'); + } + _id = os.toString(); + } + else + { + _id = _operation; + } + } + return _id; + } + + public String + getParent() + { + return "Communicator"; + } + + public Ice.ObjectPrx + getProxy() + { + return _proxy; + } + + public String + getIdentity() + { + if(_proxy != null) + { + return Ice.Util.identityToString(_proxy.ice_getIdentity()); + } + else + { + return ""; + } + } + + public String + getOperation() + { + return _operation; + } + + public String + getEncodingVersion() + { + return Ice.Util.encodingVersionToString(_proxy.ice_getEncodingVersion()); + } + + final private Ice.ObjectPrx _proxy; + final private String _operation; + final private java.util.Map<String, String> _context; + private String _id; + + static final private Ice.Endpoint[] emptyEndpoints = new Ice.Endpoint[0]; + } + + static public final class ThreadHelper extends MetricsHelper<ThreadMetrics> + { + static private final AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + add("parent", ThreadHelper.class.getDeclaredField("_parent")); + add("id", ThreadHelper.class.getDeclaredField("_id")); + } + catch(Exception ex) + { + assert(false); + } + } + }; + + ThreadHelper(String parent, String id, Ice.Instrumentation.ThreadState state) + { + super(_attributes); + _parent = parent; + _id = id; + _state = state; + } + + @Override + public void + initMetrics(ThreadMetrics v) + { + switch(_state) + { + case ThreadStateInUseForIO: + ++v.inUseForIO; + break; + case ThreadStateInUseForUser: + ++v.inUseForUser; + break; + case ThreadStateInUseForOther: + ++v.inUseForOther; + break; + default: + break; + } + } + + final public String _parent; + final public String _id; + final private Ice.Instrumentation.ThreadState _state; + } + + static public final class EndpointHelper extends MetricsHelper<Metrics> + { + static private final AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + add("parent", EndpointHelper.class.getDeclaredMethod("getParent")); + add("id", EndpointHelper.class.getDeclaredMethod("getId")); + addEndpointAttributes(this, EndpointHelper.class); + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + } + } + }; + + EndpointHelper(Ice.Endpoint endpt, String id) + { + super(_attributes); + _endpoint = endpt; + _id = id; + } + + EndpointHelper(Ice.Endpoint endpt) + { + super(_attributes); + _endpoint = endpt; + } + + public Ice.EndpointInfo + getEndpointInfo() + { + if(_endpointInfo == null) + { + _endpointInfo = _endpoint.getInfo(); + } + return _endpointInfo; + } + + public String + getParent() + { + return "Communicator"; + } + + public String + getId() + { + if(_id == null) + { + _id = _endpoint.toString(); + } + return _id; + } + + public String + getEndpoint() + { + return _endpoint.toString(); + } + + final private Ice.Endpoint _endpoint; + private String _id; + private Ice.EndpointInfo _endpointInfo; + } + + public + CommunicatorObserverI(Ice.InitializationData initData) + { + _metrics = new MetricsAdminI(initData.properties, initData.logger); + _delegate = initData.observer; + + _connections = new ObserverFactoryWithDelegate<ConnectionMetrics, ConnectionObserverI, + Ice.Instrumentation.ConnectionObserver>(_metrics, "Connection", ConnectionMetrics.class); + _dispatch = new ObserverFactoryWithDelegate<DispatchMetrics, DispatchObserverI, + Ice.Instrumentation.DispatchObserver>(_metrics, "Dispatch", DispatchMetrics.class); + _invocations = new ObserverFactoryWithDelegate<InvocationMetrics, InvocationObserverI, + Ice.Instrumentation.InvocationObserver>(_metrics, "Invocation", InvocationMetrics.class); + _threads = new ObserverFactoryWithDelegate<ThreadMetrics, ThreadObserverI, + Ice.Instrumentation.ThreadObserver>(_metrics, "Thread", ThreadMetrics.class); + _connects = new ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI, + Ice.Instrumentation.Observer>(_metrics, "ConnectionEstablishment", Metrics.class); + _endpointLookups = new ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI, + Ice.Instrumentation.Observer>(_metrics, "EndpointLookup", Metrics.class); + + try + { + _invocations.registerSubMap("Remote", RemoteMetrics.class, + InvocationMetrics.class.getDeclaredField("remotes")); + _invocations.registerSubMap("Collocated", CollocatedMetrics.class, + InvocationMetrics.class.getDeclaredField("collocated")); + } + catch(Exception ex) + { + assert(false); + } + } + + @Override + public Ice.Instrumentation.Observer + getConnectionEstablishmentObserver(Ice.Endpoint endpt, String connector) + { + if(_connects.isEnabled()) + { + try + { + Ice.Instrumentation.Observer delegate = null; + if(_delegate != null) + { + delegate = _delegate.getConnectionEstablishmentObserver(endpt, connector); + } + return _connects.getObserver(new EndpointHelper(endpt, connector), ObserverWithDelegateI.class, + delegate); + } + catch(Exception ex) + { + _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + Ex.toString(ex)); + } + } + return null; + } + + @Override + public Ice.Instrumentation.Observer + getEndpointLookupObserver(Ice.Endpoint endpt) + { + if(_endpointLookups.isEnabled()) + { + try + { + Ice.Instrumentation.Observer delegate = null; + if(_delegate != null) + { + delegate = _delegate.getEndpointLookupObserver(endpt); + } + return _endpointLookups.getObserver(new EndpointHelper(endpt), ObserverWithDelegateI.class, delegate); + } + catch(Exception ex) + { + _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + Ex.toString(ex)); + } + + } + return null; + } + + @Override + public Ice.Instrumentation.ConnectionObserver + getConnectionObserver(Ice.ConnectionInfo c, Ice.Endpoint e, Ice.Instrumentation.ConnectionState s, + Ice.Instrumentation.ConnectionObserver observer) + { + if(_connections.isEnabled()) + { + try + { + Ice.Instrumentation.ConnectionObserver delegate = null; + ConnectionObserverI o = observer instanceof ConnectionObserverI ? (ConnectionObserverI)observer : null; + if(_delegate != null) + { + delegate = _delegate.getConnectionObserver(c, e, s, o != null ? o.getDelegate() : observer); + } + return _connections.getObserver(new ConnectionHelper(c, e, s), o, ConnectionObserverI.class, delegate); + } + catch(Exception ex) + { + _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + Ex.toString(ex)); + } + } + return null; + } + + @Override + public Ice.Instrumentation.ThreadObserver + getThreadObserver(String parent, String id, Ice.Instrumentation.ThreadState s, + Ice.Instrumentation.ThreadObserver observer) + { + if(_threads.isEnabled()) + { + try + { + Ice.Instrumentation.ThreadObserver delegate = null; + ThreadObserverI o = observer instanceof ThreadObserverI ? (ThreadObserverI)observer : null; + if(_delegate != null) + { + delegate = _delegate.getThreadObserver(parent, id, s, o != null ? o.getDelegate() : observer); + } + return _threads.getObserver(new ThreadHelper(parent, id, s), o, ThreadObserverI.class, delegate); + } + catch(Exception ex) + { + _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + Ex.toString(ex)); + } + } + return null; + } + + @Override + public Ice.Instrumentation.InvocationObserver + getInvocationObserver(Ice.ObjectPrx prx, String operation, java.util.Map<java.lang.String, java.lang.String> ctx) + { + if(_invocations.isEnabled()) + { + try + { + Ice.Instrumentation.InvocationObserver delegate = null; + if(_delegate != null) + { + delegate = _delegate.getInvocationObserver(prx, operation, ctx); + } + return _invocations.getObserver(new InvocationHelper(prx, operation, ctx), + InvocationObserverI.class, + delegate); + } + catch(Exception ex) + { + _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + Ex.toString(ex)); + } + } + return null; + } + + @Override + public Ice.Instrumentation.DispatchObserver + getDispatchObserver(Ice.Current c, int size) + { + if(_dispatch.isEnabled()) + { + try + { + Ice.Instrumentation.DispatchObserver delegate = null; + if(_delegate != null) + { + delegate = _delegate.getDispatchObserver(c, size); + } + return _dispatch.getObserver(new DispatchHelper(c, size), DispatchObserverI.class, delegate); + } + catch(Exception ex) + { + _metrics.getLogger().error("unexpected exception trying to obtain observer:\n" + Ex.toString(ex)); + } + } + return null; + } + + @Override + public void + setObserverUpdater(final Ice.Instrumentation.ObserverUpdater updater) + { + if(updater == null) + { + _connections.setUpdater(null); + _threads.setUpdater(null); + } + else + { + _connections.setUpdater(new Runnable() { + @Override + public void + run() + { + updater.updateConnectionObservers(); + } + }); + _threads.setUpdater(new Runnable() { + @Override + public void + run() + { + updater.updateThreadObservers(); + } + }); + } + + if(_delegate != null) + { + _delegate.setObserverUpdater(updater); + } + } + + public IceInternal.MetricsAdminI getFacet() + { + return _metrics; + } + + final private IceInternal.MetricsAdminI _metrics; + final private Ice.Instrumentation.CommunicatorObserver _delegate; + final private ObserverFactoryWithDelegate<ConnectionMetrics, ConnectionObserverI, + Ice.Instrumentation.ConnectionObserver> _connections; + final private ObserverFactoryWithDelegate<DispatchMetrics, DispatchObserverI, + Ice.Instrumentation.DispatchObserver> _dispatch; + final private ObserverFactoryWithDelegate<InvocationMetrics, InvocationObserverI, + Ice.Instrumentation.InvocationObserver> _invocations; + final private ObserverFactoryWithDelegate<ThreadMetrics, ThreadObserverI, + Ice.Instrumentation.ThreadObserver> _threads; + final private ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI, + Ice.Instrumentation.Observer> _connects; + final private ObserverFactoryWithDelegate<Metrics, ObserverWithDelegateI, + Ice.Instrumentation.Observer> _endpointLookups; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ConnectRequestHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/ConnectRequestHandler.java new file mode 100644 index 00000000000..4f50988102a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ConnectRequestHandler.java @@ -0,0 +1,385 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import Ice.ConnectionI; + +import java.util.concurrent.Callable; + +public class ConnectRequestHandler + implements RequestHandler, Reference.GetConnectionCallback, RouterInfo.AddProxyCallback +{ + synchronized public RequestHandler + connect(Ice.ObjectPrxHelperBase proxy) + { + if(!initialized()) + { + _proxies.add(proxy); + } + return _requestHandler; + } + + @Override + public RequestHandler + update(RequestHandler previousHandler, RequestHandler newHandler) + { + return previousHandler == this ? newHandler : this; + } + + @Override + public int + sendAsyncRequest(ProxyOutgoingAsyncBase out) + throws RetryException + { + synchronized(this) + { + if(!_initialized) + { + out.cancelable(this); // This will throw if the request is canceled + } + + if(!initialized()) + { + _requests.add(out); + return AsyncStatus.Queued; + } + } + return out.invokeRemote(_connection, _compress, _response); + } + + @Override + public void + asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) + { + synchronized(this) + { + if(_exception != null) + { + return; // The request has been notified of a failure already. + } + + if(!initialized()) + { + java.util.Iterator<ProxyOutgoingAsyncBase> it = _requests.iterator(); + while(it.hasNext()) + { + OutgoingAsyncBase request = it.next(); + if(request == outAsync) + { + it.remove(); + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + return; + } + } + assert(false); // The request has to be queued if it timed out and we're not initialized yet. + } + } + _connection.asyncRequestCanceled(outAsync, ex); + } + + @Override + public Reference + getReference() + { + return _reference; + } + + @Override + synchronized public ConnectionI + getConnection() + { + if(_exception != null) + { + throw (Ice.LocalException)_exception.fillInStackTrace(); + } + else + { + return _connection; + } + } + + // + // Implementation of Reference.GetConnectionCallback + // + + @Override + public void + setConnection(Ice.ConnectionI connection, boolean compress) + { + synchronized(this) + { + assert(_exception == null && _connection == null); + _connection = connection; + _compress = compress; + } + + // + // If this proxy is for a non-local object, and we are using a router, then + // add this proxy to the router info object. + // + RouterInfo ri = _reference.getRouterInfo(); + if(ri != null && !ri.addProxy(_proxy, this)) + { + return; // The request handler will be initialized once addProxy returns. + } + + // + // We can now send the queued requests. + // + flushRequests(); + } + + @Override + public synchronized void + setException(final Ice.LocalException ex) + { + assert(!_initialized && _exception == null); + _exception = ex; + _proxies.clear(); + _proxy = null; // Break cyclic reference count. + + // + // NOTE: remove the request handler *before* notifying the + // requests that the connection failed. It's important to ensure + // that future invocations will obtain a new connect request + // handler once invocations are notified. + // + try + { + _reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this); + } + catch(Ice.CommunicatorDestroyedException exc) + { + // Ignore + } + + for(OutgoingAsyncBase outAsync : _requests) + { + if(outAsync.completed(_exception)) + { + outAsync.invokeCompletedAsync(); + } + } + _requests.clear(); + notifyAll(); + } + + // + // Implementation of RouterInfo.AddProxyCallback + // + @Override + public void + addedProxy() + { + // + // The proxy was added to the router info, we're now ready to send the + // queued requests. + // + flushRequests(); + } + + public + ConnectRequestHandler(Reference ref, Ice.ObjectPrxHelperBase proxy) + { + _reference = ref; + _response = _reference.getMode() == Reference.ModeTwoway; + _proxy = (Ice.ObjectPrxHelperBase)proxy; + _initialized = false; + _flushing = false; + + if(_reference.getInstance().queueRequests()) + { + _requestHandler = new QueueRequestHandler(_reference.getInstance(), this); + } + else + { + _requestHandler = this; + } + } + + private boolean + initialized() + { + // Must be called with the mutex locked. + + if(_initialized) + { + assert(_connection != null); + return true; + } + else + { + // + // This is similar to a mutex lock in that the flag is + // only true for a short period of time. + // + boolean interrupted = false; + while(_flushing && _exception == null) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + interrupted = true; + } + } + // + // Restore the interrupted status. + // + if(interrupted) + { + Thread.currentThread().interrupt(); + } + + if(_exception != null) + { + if(_connection != null) + { + // + // Only throw if the connection didn't get established. If + // it died after being established, we allow the caller to + // retry the connection establishment by not throwing here + // (the connection will throw RetryException). + // + return true; + } + throw (Ice.LocalException)_exception.fillInStackTrace(); + } + else + { + return _initialized; + } + } + } + + private void + flushRequests() + { + if(_reference.getInstance().queueRequests()) + { + _reference.getInstance().getQueueExecutor().executeNoThrow(new Callable<Void>() + { + @Override + public Void call() throws Exception + { + flushRequestsImpl(); + return null; + } + }); + } + else + { + flushRequestsImpl(); + } + } + + private void + flushRequestsImpl() + { + synchronized(this) + { + assert(_connection != null && !_initialized); + + // + // We set the _flushing flag to true to prevent any additional queuing. Callers + // might block for a little while as the queued requests are being sent but this + // shouldn't be an issue as the request sends are non-blocking. + // + _flushing = true; + } + + Ice.LocalException exception = null; + for(ProxyOutgoingAsyncBase outAsync : _requests) + { + try + { + if((outAsync.invokeRemote(_connection, _compress, _response) & AsyncStatus.InvokeSentCallback) > 0) + { + outAsync.invokeSentAsync(); + } + } + catch(RetryException ex) + { + exception = ex.get(); + + // Remove the request handler before retrying. + _reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this); + outAsync.retryException(ex.get()); + } + catch(Ice.LocalException ex) + { + exception = ex; + if(outAsync.completed(ex)) + { + outAsync.invokeCompletedAsync(); + } + } + } + _requests.clear(); + + // + // If we aren't caching the connection, don't bother creating a + // connection request handler. Otherwise, update the proxies + // request handler to use the more efficient connection request + // handler. + // + if(_reference.getCacheConnection() && exception == null) + { + RequestHandler previous = _requestHandler; + _requestHandler = new ConnectionRequestHandler(_reference, _connection, _compress); + if(_reference.getInstance().queueRequests()) + { + _requestHandler = new QueueRequestHandler(_reference.getInstance(), _requestHandler); + } + for(Ice.ObjectPrxHelperBase proxy : _proxies) + { + proxy.__updateRequestHandler(previous, _requestHandler); + } + } + + synchronized(this) + { + assert(!_initialized); + _exception = exception; + _initialized = _exception == null; + _flushing = false; + + // + // Only remove once all the requests are flushed to + // guarantee serialization. + // + _reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this); + + _proxies.clear(); + _proxy = null; // Break cyclic reference count. + notifyAll(); + } + } + + private final Reference _reference; + private boolean _response; + + private Ice.ObjectPrxHelperBase _proxy; + private java.util.Set<Ice.ObjectPrxHelperBase> _proxies = new java.util.HashSet<Ice.ObjectPrxHelperBase>(); + + private Ice.ConnectionI _connection; + private boolean _compress; + private Ice.LocalException _exception; + private boolean _initialized; + private boolean _flushing; + + private java.util.List<ProxyOutgoingAsyncBase> _requests = new java.util.LinkedList<ProxyOutgoingAsyncBase>(); + private RequestHandler _requestHandler; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ConnectionACMMonitor.java b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionACMMonitor.java new file mode 100644 index 00000000000..7e4b1427c1f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionACMMonitor.java @@ -0,0 +1,126 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class ConnectionACMMonitor implements ACMMonitor +{ + ConnectionACMMonitor(FactoryACMMonitor parent, java.util.concurrent.ScheduledExecutorService timer, + ACMConfig config) + { + _parent = parent; + _timer = timer; + _config = config; + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_connection == null); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + @Override + public synchronized void + add(Ice.ConnectionI connection) + { + assert(_connection == null); + _connection = connection; + if(_config.timeout > 0) + { + _future = _timer.scheduleAtFixedRate(new Runnable() { + @Override + public void run() + { + monitorConnection(); + } + }, + _config.timeout / 2, _config.timeout / 2, java.util.concurrent.TimeUnit.MILLISECONDS); + } + } + + @Override + public synchronized void + remove(Ice.ConnectionI connection) + { + assert(_connection == connection); + _connection = null; + if(_config.timeout > 0) + { + _future.cancel(false); + _future = null; + } + } + + @Override + public void + reap(Ice.ConnectionI connection) + { + _parent.reap(connection); + } + + @Override + public ACMMonitor + acm(Ice.IntOptional timeout, Ice.Optional<Ice.ACMClose> close, Ice.Optional<Ice.ACMHeartbeat> heartbeat) + { + return _parent.acm(timeout, close, heartbeat); + } + + @Override + public Ice.ACM + getACM() + { + Ice.ACM acm = new Ice.ACM(); + acm.timeout = _config.timeout / 1000; + acm.close = _config.close; + acm.heartbeat = _config.heartbeat; + return acm; + } + + private void + monitorConnection() + { + Ice.ConnectionI connection; + synchronized(this) + { + if(_connection == null) + { + return; + } + connection = _connection; + } + + try + { + connection.monitor(Time.currentMonotonicTimeMillis(), _config); + } + catch(Exception ex) + { + _parent.handleException(ex); + } + } + + final private FactoryACMMonitor _parent; + final private java.util.concurrent.ScheduledExecutorService _timer; + private java.util.concurrent.Future<?> _future; + final private ACMConfig _config; + + private Ice.ConnectionI _connection; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ConnectionFlushBatch.java b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionFlushBatch.java new file mode 100644 index 00000000000..7824d3154c1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionFlushBatch.java @@ -0,0 +1,102 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.Callable; + +public class ConnectionFlushBatch extends OutgoingAsyncBase +{ + public static ConnectionFlushBatch check(Ice.AsyncResult r, Ice.Connection con, String operation) + { + check(r, operation); + if(!(r instanceof ConnectionFlushBatch)) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + if(r.getConnection() != con) + { + throw new IllegalArgumentException("Connection for call to end_" + operation + + " does not match connection that was used to call corresponding " + + "begin_" + operation + " method"); + } + return (ConnectionFlushBatch)r; + } + + public ConnectionFlushBatch(Ice.ConnectionI con, Ice.Communicator communicator, Instance instance, + String operation, CallbackBase callback) + { + super(communicator, instance, operation, callback); + _connection = con; + } + + @Override + public Ice.Connection getConnection() + { + return _connection; + } + + public void invoke() + { + try + { + final int batchRequestNum = _connection.getBatchRequestQueue().swap(_os); + + int status; + if(batchRequestNum == 0) + { + status = IceInternal.AsyncStatus.Sent; + if(sent()) + { + status |= IceInternal.AsyncStatus.InvokeSentCallback; + } + } + else if(_instance.queueRequests()) + { + status = _instance.getQueueExecutor().execute(new Callable<Integer>() + { + @Override + public Integer call() throws RetryException + { + return _connection.sendAsyncRequest(ConnectionFlushBatch.this, false, false, batchRequestNum); + } + }); + } + else + { + status = _connection.sendAsyncRequest(this, false, false, batchRequestNum); + } + + if((status & AsyncStatus.Sent) > 0) + { + _sentSynchronously = true; + if((status & AsyncStatus.InvokeSentCallback) > 0) + { + invokeSent(); + } + } + } + catch(RetryException ex) + { + if(completed(ex.get())) + { + invokeCompletedAsync(); + } + } + catch(Ice.Exception ex) + { + if(completed(ex)) + { + invokeCompletedAsync(); + } + } + } + + private Ice.ConnectionI _connection; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ConnectionObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionObserverI.java new file mode 100644 index 00000000000..ebbf963aba9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionObserverI.java @@ -0,0 +1,62 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ConnectionObserverI + extends IceMX.ObserverWithDelegate<IceMX.ConnectionMetrics, Ice.Instrumentation.ConnectionObserver> + implements Ice.Instrumentation.ConnectionObserver +{ + @Override + public void + sentBytes(final int num) + { + _sentBytes = num; + forEach(_sentBytesUpdate); + if(_delegate != null) + { + _delegate.sentBytes(num); + } + } + + @Override + public void + receivedBytes(int num) + { + _receivedBytes = num; + forEach(_receivedBytesUpdate); + if(_delegate != null) + { + _delegate.receivedBytes(num); + } + } + + private MetricsUpdate<IceMX.ConnectionMetrics> _sentBytesUpdate = new MetricsUpdate<IceMX.ConnectionMetrics>() + { + @Override + public void + update(IceMX.ConnectionMetrics v) + { + v.sentBytes += _sentBytes; + } + }; + + private MetricsUpdate<IceMX.ConnectionMetrics> _receivedBytesUpdate = new MetricsUpdate<IceMX.ConnectionMetrics>() + { + @Override + public void + update(IceMX.ConnectionMetrics v) + { + v.receivedBytes += _receivedBytes; + } + }; + + private int _sentBytes; + private int _receivedBytes; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ConnectionRequestHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionRequestHandler.java new file mode 100644 index 00000000000..6e098e1c6a4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ConnectionRequestHandler.java @@ -0,0 +1,82 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ConnectionRequestHandler implements RequestHandler +{ + @Override + public RequestHandler + update(RequestHandler previousHandler, RequestHandler newHandler) + { + try + { + if(previousHandler == this) + { + return newHandler; + } + else if(previousHandler.getConnection() == _connection) + { + // + // If both request handlers point to the same connection, we also + // update the request handler. See bug ICE-5489 for reasons why + // this can be useful. + // + return newHandler; + } + } + catch(Ice.Exception ex) + { + // Ignore + } + return this; + } + + @Override + public int sendAsyncRequest(ProxyOutgoingAsyncBase out) + throws RetryException + { + return out.invokeRemote(_connection, _compress, _response); + } + + @Override + public void + asyncRequestCanceled(OutgoingAsyncBase outgoingAsync, Ice.LocalException ex) + { + _connection.asyncRequestCanceled(outgoingAsync, ex); + } + + @Override + public Reference + getReference() + { + return _reference; + } + + @Override + public Ice.ConnectionI + getConnection() + { + return _connection; + } + + public ConnectionRequestHandler(Reference ref, Ice.ConnectionI connection, boolean compress) + { + _reference = ref; + _response = _reference.getMode() == Reference.ModeTwoway; + _connection = connection; + _compress = compress; + } + + private final Reference _reference; + private final boolean _response; + private final Ice.ConnectionI _connection; + private final boolean _compress; + +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Connector.java b/java-compat/src/Ice/src/main/java/IceInternal/Connector.java new file mode 100644 index 00000000000..29638f0f138 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Connector.java @@ -0,0 +1,25 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Connector +{ + Transceiver connect(); + + short type(); + @Override + String toString(); + + // + // Compare connectors for sorting process. + // + @Override + boolean equals(java.lang.Object obj); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/DefaultsAndOverrides.java b/java-compat/src/Ice/src/main/java/IceInternal/DefaultsAndOverrides.java new file mode 100644 index 00000000000..b1b7fc5687d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/DefaultsAndOverrides.java @@ -0,0 +1,242 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class DefaultsAndOverrides +{ + DefaultsAndOverrides(Ice.Properties properties, Ice.Logger logger) + { + String value; + int intValue; + + defaultProtocol = properties.getPropertyWithDefault("Ice.Default.Protocol", "tcp"); + + value = properties.getProperty("Ice.Default.Host"); + if(!value.isEmpty()) + { + defaultHost = value; + } + else + { + defaultHost = null; + } + + value = properties.getProperty("Ice.Default.SourceAddress"); + if(!value.isEmpty()) + { + defaultSourceAddress = Network.getNumericAddress(value); + if(defaultSourceAddress == null) + { + throw new Ice.InitializationException("invalid IP address set for Ice.Default.SourceAddress: `" + + value + "'"); + } + } + else + { + defaultSourceAddress = null; + } + + value = properties.getProperty("Ice.Override.Timeout"); + if(!value.isEmpty()) + { + overrideTimeout = true; + intValue = properties.getPropertyAsInt("Ice.Override.Timeout"); + if(intValue < 0 && intValue != -1) + { + overrideTimeoutValue = -1; + StringBuffer msg = new StringBuffer("invalid value for Ice.Override.Timeout `"); + msg.append(properties.getProperty("Ice.Override.Timeout")); + msg.append("': defaulting to -1"); + logger.warning(msg.toString()); + } + else + { + overrideTimeoutValue = intValue; + } + } + else + { + overrideTimeout = false; + overrideTimeoutValue = -1; + } + + value = properties.getProperty("Ice.Override.ConnectTimeout"); + if(!value.isEmpty()) + { + overrideConnectTimeout = true; + intValue = properties.getPropertyAsInt("Ice.Override.ConnectTimeout"); + if(intValue < 0 && intValue != -1) + { + overrideConnectTimeoutValue = -1; + StringBuffer msg = new StringBuffer("invalid value for Ice.Override.ConnectTimeout `"); + msg.append(properties.getProperty("Ice.Override.ConnectTimeout")); + msg.append("': defaulting to -1"); + logger.warning(msg.toString()); + } + else + { + overrideConnectTimeoutValue = intValue; + } + } + else + { + overrideConnectTimeout = false; + overrideConnectTimeoutValue = -1; + } + + value = properties.getProperty("Ice.Override.CloseTimeout"); + if(!value.isEmpty()) + { + overrideCloseTimeout = true; + intValue = properties.getPropertyAsInt("Ice.Override.CloseTimeout"); + if(intValue < 0 && intValue != -1) + { + overrideCloseTimeoutValue = -1; + StringBuffer msg = new StringBuffer("invalid value for Ice.Override.CloseTimeout `"); + msg.append(properties.getProperty("Ice.Override.CloseTimeout")); + msg.append("': defaulting to -1"); + logger.warning(msg.toString()); + } + else + { + overrideCloseTimeoutValue = intValue; + } + } + else + { + overrideCloseTimeout = false; + overrideCloseTimeoutValue = -1; + } + + value = properties.getProperty("Ice.Override.Compress"); + if(!value.isEmpty()) + { + overrideCompress = true; + boolean b = properties.getPropertyAsInt("Ice.Override.Compress") > 0; + if(b && !BZip2.supported()) + { + System.err.println("warning: bzip2 support not available, Ice.Override.Compress ignored"); + b = false; + } + overrideCompressValue = b; + } + else + { + overrideCompress = false; + overrideCompressValue = false; + } + + value = properties.getProperty("Ice.Override.Secure"); + if(!value.isEmpty()) + { + overrideSecure = true; + overrideSecureValue = properties.getPropertyAsInt("Ice.Override.Secure") > 0; + } + else + { + overrideSecure = false; + overrideSecureValue = false; + } + + defaultCollocationOptimization = + properties.getPropertyAsIntWithDefault("Ice.Default.CollocationOptimized", 1) > 0; + + value = properties.getPropertyWithDefault("Ice.Default.EndpointSelection", "Random"); + if(value.equals("Random")) + { + defaultEndpointSelection = Ice.EndpointSelectionType.Random; + } + else if(value.equals("Ordered")) + { + defaultEndpointSelection = Ice.EndpointSelectionType.Ordered; + } + else + { + Ice.EndpointSelectionTypeParseException ex = new Ice.EndpointSelectionTypeParseException(); + ex.str = "illegal value `" + value + "'; expected `Random' or `Ordered'"; + throw ex; + } + + intValue = properties.getPropertyAsIntWithDefault("Ice.Default.Timeout", 60000); + if(intValue < 1 && intValue != -1) + { + defaultTimeout = 60000; + StringBuffer msg = new StringBuffer("invalid value for Ice.Default.Timeout `"); + msg.append(properties.getProperty("Ice.Default.Timeout")); + msg.append("': defaulting to 60000"); + logger.warning(msg.toString()); + } + else + { + defaultTimeout = intValue; + } + + intValue = properties.getPropertyAsIntWithDefault("Ice.Default.LocatorCacheTimeout", -1); + if(intValue < -1) + { + defaultLocatorCacheTimeout = -1; + StringBuffer msg = new StringBuffer("invalid value for Ice.Default.LocatorCacheTimeout `"); + msg.append(properties.getProperty("Ice.Default.LocatorCacheTimeout")); + msg.append("': defaulting to -1"); + logger.warning(msg.toString()); + } + else + { + defaultLocatorCacheTimeout = intValue; + } + + intValue = properties.getPropertyAsIntWithDefault("Ice.Default.InvocationTimeout", -1); + if(intValue < 1 && intValue != -1 && intValue != -2) + { + defaultInvocationTimeout = -1; + StringBuffer msg = new StringBuffer("invalid value for Ice.Default.InvocationTimeout `"); + msg.append(properties.getProperty("Ice.Default.InvocationTimeout")); + msg.append("': defaulting to -1"); + logger.warning(msg.toString()); + } + else + { + defaultInvocationTimeout = intValue; + } + + defaultPreferSecure = properties.getPropertyAsIntWithDefault("Ice.Default.PreferSecure", 0) > 0; + + value = properties.getPropertyWithDefault("Ice.Default.EncodingVersion", + Ice.Util.encodingVersionToString(Protocol.currentEncoding)); + defaultEncoding = Ice.Util.stringToEncodingVersion(value); + Protocol.checkSupportedEncoding(defaultEncoding); + + boolean slicedFormat = properties.getPropertyAsIntWithDefault("Ice.Default.SlicedFormat", 0) > 0; + defaultFormat = slicedFormat ? Ice.FormatType.SlicedFormat : Ice.FormatType.CompactFormat; + } + + final public String defaultHost; + final public java.net.InetSocketAddress defaultSourceAddress; + final public String defaultProtocol; + final public boolean defaultCollocationOptimization; + final public Ice.EndpointSelectionType defaultEndpointSelection; + final public int defaultTimeout; + final public int defaultLocatorCacheTimeout; + final public int defaultInvocationTimeout; + final public boolean defaultPreferSecure; + final public Ice.EncodingVersion defaultEncoding; + final public Ice.FormatType defaultFormat; + + final public boolean overrideTimeout; + final public int overrideTimeoutValue; + final public boolean overrideConnectTimeout; + final public int overrideConnectTimeoutValue; + final public boolean overrideCloseTimeout; + final public int overrideCloseTimeoutValue; + final public boolean overrideCompress; + final public boolean overrideCompressValue; + final public boolean overrideSecure; + final public boolean overrideSecureValue; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/DictionaryPatcher.java b/java-compat/src/Ice/src/main/java/IceInternal/DictionaryPatcher.java new file mode 100644 index 00000000000..2f426ac4fa1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/DictionaryPatcher.java @@ -0,0 +1,41 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class DictionaryPatcher<K, V> implements Ice.ReadValueCallback +{ + public DictionaryPatcher(java.util.Map<K, V> dict, Class<V> cls, K key) + { + _dict = dict; + _cls = cls; + _key = key; + } + + public void valueReady(Ice.Object v) + { + if(v != null) + { + // + // Raise ClassCastException if the element doesn't match the expected type. + // + if(!_cls.isInstance(v)) + { + throw new ClassCastException("expected element of type " + _cls.getName() + " but received " + + v.getClass().getName()); + } + } + + _dict.put(_key, _cls.cast(v)); + } + + private java.util.Map<K, V> _dict; + private Class<V> _cls; + private K _key; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/DispatchObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/DispatchObserverI.java new file mode 100644 index 00000000000..1d4ce8be34e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/DispatchObserverI.java @@ -0,0 +1,55 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class DispatchObserverI + extends IceMX.ObserverWithDelegate<IceMX.DispatchMetrics, Ice.Instrumentation.DispatchObserver> + implements Ice.Instrumentation.DispatchObserver +{ + @Override + public void + userException() + { + forEach(_userException); + if(_delegate != null) + { + _delegate.userException(); + } + } + + @Override + public void + reply(final int size) + { + forEach(new MetricsUpdate<IceMX.DispatchMetrics>() + { + @Override + public void + update(IceMX.DispatchMetrics v) + { + v.replySize += size; + } + }); + if(_delegate != null) + { + _delegate.reply(size); + } + } + + final private MetricsUpdate<IceMX.DispatchMetrics> _userException = new MetricsUpdate<IceMX.DispatchMetrics>() + { + @Override + public void + update(IceMX.DispatchMetrics v) + { + ++v.userException; + } + }; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/DispatchWorkItem.java b/java-compat/src/Ice/src/main/java/IceInternal/DispatchWorkItem.java new file mode 100644 index 00000000000..157cf841f78 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/DispatchWorkItem.java @@ -0,0 +1,44 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// A helper class for thread pool work items that only need to call user +// callbacks. If a dispatcher is installed with the communicator, the +// thread pool work item is executed with the dispatcher, otherwise it's +// executed by a thread pool thread (after promoting a follower thread). +// +abstract public class DispatchWorkItem implements ThreadPoolWorkItem, Runnable +{ + public DispatchWorkItem() + { + } + + public DispatchWorkItem(Ice.Connection connection) + { + _connection = connection; + } + + @Override + final public void + execute(ThreadPoolCurrent current) + { + current.ioCompleted(); // Promote a follower + current.dispatchFromThisThread(this); + } + + public Ice.Connection + getConnection() + { + return _connection; + } + + private Ice.Connection _connection; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EndpointFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/EndpointFactory.java new file mode 100644 index 00000000000..350a9aa7e15 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EndpointFactory.java @@ -0,0 +1,21 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface EndpointFactory +{ + short type(); + String protocol(); + EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint); + EndpointI read(Ice.InputStream s); + void destroy(); + + EndpointFactory clone(ProtocolInstance instance, EndpointFactory delegate); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EndpointFactoryManager.java b/java-compat/src/Ice/src/main/java/IceInternal/EndpointFactoryManager.java new file mode 100644 index 00000000000..252baa39baf --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EndpointFactoryManager.java @@ -0,0 +1,183 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class EndpointFactoryManager +{ + EndpointFactoryManager(Instance instance) + { + _instance = instance; + } + + public synchronized void add(EndpointFactory factory) + { + for(int i = 0; i < _factories.size(); i++) + { + EndpointFactory f = _factories.get(i); + if(f.type() == factory.type()) + { + assert(false); + } + } + _factories.add(factory); + } + + public synchronized EndpointFactory get(short type) + { + for(int i = 0; i < _factories.size(); i++) + { + EndpointFactory f = _factories.get(i); + if(f.type() == type) + { + return f; + } + } + return null; + } + + public synchronized EndpointI create(String str, boolean oaEndpoint) + { + String[] arr = IceUtilInternal.StringUtil.splitString(str, " \t\r\n"); + if(arr == null) + { + Ice.EndpointParseException e = new Ice.EndpointParseException(); + e.str = "mismatched quote"; + throw e; + } + + if(arr.length == 0) + { + Ice.EndpointParseException e = new Ice.EndpointParseException(); + e.str = "value has no non-whitespace characters"; + throw e; + } + + java.util.ArrayList<String> v = new java.util.ArrayList<String>(java.util.Arrays.asList(arr)); + String protocol = v.get(0); + v.remove(0); + + if(protocol.equals("default")) + { + protocol = _instance.defaultsAndOverrides().defaultProtocol; + } + + EndpointFactory factory = null; + + for(int i = 0; i < _factories.size(); i++) + { + EndpointFactory f = _factories.get(i); + if(f.protocol().equals(protocol)) + { + factory = f; + } + } + + if(factory != null) + { + EndpointI e = factory.create(v, oaEndpoint); + if(!v.isEmpty()) + { + Ice.EndpointParseException ex = new Ice.EndpointParseException(); + ex.str = "unrecognized argument `" + v.get(0) + "' in endpoint `" + str + "'"; + throw ex; + } + return e; + + // Code below left in place for debugging. + + /* + EndpointI e = f.create(s.substring(m.end()), oaEndpoint); + BasicStream bs = new BasicStream(_instance, true, false); + e.streamWrite(bs); + java.nio.ByteBuffer buf = bs.getBuffer(); + buf.position(0); + short type = bs.readShort(); + EndpointI ue = new IceInternal.OpaqueEndpointI(type, bs); + System.err.println("Normal: " + e); + System.err.println("Opaque: " + ue); + return e; + */ + } + + // + // If the stringified endpoint is opaque, create an unknown endpoint, + // then see whether the type matches one of the known endpoints. + // + if(protocol.equals("opaque")) + { + EndpointI ue = new OpaqueEndpointI(v); + if(!v.isEmpty()) + { + Ice.EndpointParseException ex = new Ice.EndpointParseException(); + ex.str = "unrecognized argument `" + v.get(0) + "' in endpoint `" + str + "'"; + throw ex; + } + factory = get(ue.type()); + if(factory != null) + { + // + // Make a temporary stream, write the opaque endpoint data into the stream, + // and ask the factory to read the endpoint data from that stream to create + // the actual endpoint. + // + Ice.OutputStream os = new Ice.OutputStream(_instance, Protocol.currentProtocolEncoding, false); + os.writeShort(ue.type()); + ue.streamWrite(os); + Ice.InputStream is = + new Ice.InputStream(_instance, Protocol.currentProtocolEncoding, os.getBuffer(), true); + is.pos(0); + is.readShort(); // type + is.startEncapsulation(); + EndpointI e = factory.read(is); + is.endEncapsulation(); + return e; + } + return ue; // Endpoint is opaque, but we don't have a factory for its type. + } + + return null; + } + + public synchronized EndpointI read(Ice.InputStream s) + { + short type = s.readShort(); + + EndpointFactory factory = get(type); + EndpointI e = null; + + s.startEncapsulation(); + + if(factory != null) + { + e = factory.read(s); + } + else + { + e = new OpaqueEndpointI(type, s); + } + + s.endEncapsulation(); + + return e; + } + + void destroy() + { + for(int i = 0; i < _factories.size(); i++) + { + EndpointFactory f = _factories.get(i); + f.destroy(); + } + _factories.clear(); + } + + private Instance _instance; + private java.util.List<EndpointFactory> _factories = new java.util.ArrayList<EndpointFactory>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EndpointHostResolver.java b/java-compat/src/Ice/src/main/java/IceInternal/EndpointHostResolver.java new file mode 100644 index 00000000000..89cc00f4a3a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EndpointHostResolver.java @@ -0,0 +1,202 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class EndpointHostResolver +{ + EndpointHostResolver(Instance instance) + { + _instance = instance; + _protocol = instance.protocolSupport(); + _preferIPv6 = instance.preferIPv6(); + try + { + _threadName = Util.createThreadName(_instance.initializationData().properties, "Ice.HostResolver"); + _executor = java.util.concurrent.Executors.newFixedThreadPool(1, + Util.createThreadFactory(_instance.initializationData().properties, _threadName)); + updateObserver(); + } + catch(RuntimeException ex) + { + String s = "cannot create thread for endpoint host resolver thread:\n" + Ex.toString(ex); + _instance.initializationData().logger.error(s); + throw ex; + } + } + + synchronized void resolve(final String host, final int port, final Ice.EndpointSelectionType selType, + final IPEndpointI endpoint, final EndpointI_connectors callback) + { + // + // TODO: Optimize to avoid the lookup if the given host is a textual IPv4 or IPv6 + // address. This requires implementing parsing of IPv4/IPv6 addresses (Java does + // not provide such methods). + // + + assert(!_destroyed); + + NetworkProxy networkProxy = _instance.networkProxy(); + if(networkProxy == null) + { + java.util.List<java.net.InetSocketAddress> addrs = Network.getAddresses(host, port, _protocol, selType, + _preferIPv6, false); + if(addrs != null) + { + callback.connectors(endpoint.connectors(addrs, networkProxy)); + return; + } + } + + final Ice.Instrumentation.ThreadObserver threadObserver = _observer; + final Ice.Instrumentation.Observer observer = getObserver(endpoint); + if(observer != null) + { + observer.attach(); + } + + _executor.execute(new Runnable() + { + @Override + public void run() + { + synchronized(EndpointHostResolver.this) + { + if(_destroyed) + { + Ice.CommunicatorDestroyedException ex = new Ice.CommunicatorDestroyedException(); + if(observer != null) + { + observer.failed(ex.ice_id()); + observer.detach(); + } + callback.exception(ex); + return; + } + } + + if(threadObserver != null) + { + threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle, + Ice.Instrumentation.ThreadState.ThreadStateInUseForOther); + } + + try + { + int protocol = _protocol; + NetworkProxy networkProxy = _instance.networkProxy(); + if(networkProxy != null) + { + networkProxy = networkProxy.resolveHost(_protocol); + if(networkProxy != null) + { + protocol = networkProxy.getProtocolSupport(); + } + } + + callback.connectors(endpoint.connectors(Network.getAddresses(host, + port, + protocol, + selType, + _preferIPv6, + true), + networkProxy)); + } + catch(Ice.LocalException ex) + { + if(observer != null) + { + observer.failed(ex.ice_id()); + } + callback.exception(ex); + } + finally + { + if(threadObserver != null) + { + threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther, + Ice.Instrumentation.ThreadState.ThreadStateIdle); + } + if(observer != null) + { + observer.detach(); + } + } + } + }); + } + + synchronized void destroy() + { + assert(!_destroyed); + _destroyed = true; + + // + // Shutdown the executor. No new tasks will be accepted. + // Existing tasks will execute. + // + _executor.shutdown(); + } + + void joinWithThread() + throws InterruptedException + { + // Wait for the executor to terminate. + try + { + while(!_executor.isTerminated()) + { + // A very long time. + _executor.awaitTermination(100000, java.util.concurrent.TimeUnit.SECONDS); + } + + } + finally + { + if(_observer != null) + { + _observer.detach(); + } + } + } + + synchronized void updateObserver() + { + Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer; + if(obsv != null) + { + _observer = obsv.getThreadObserver("Communicator", _threadName, + Ice.Instrumentation.ThreadState.ThreadStateIdle, + _observer); + if(_observer != null) + { + _observer.attach(); + } + } + } + + private Ice.Instrumentation.Observer + getObserver(IPEndpointI endpoint) + { + Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer; + if(obsv != null) + { + return obsv.getEndpointLookupObserver(endpoint); + } + return null; + } + + private final Instance _instance; + private final int _protocol; + private final boolean _preferIPv6; + private boolean _destroyed; + private Ice.Instrumentation.ThreadObserver _observer; + private String _threadName; + private java.util.concurrent.ExecutorService _executor; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EndpointI.java b/java-compat/src/Ice/src/main/java/IceInternal/EndpointI.java new file mode 100644 index 00000000000..d393916472d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EndpointI.java @@ -0,0 +1,197 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<EndpointI> +{ + public void streamWrite(Ice.OutputStream s) + { + s.startEncapsulation(); + streamWriteImpl(s); + s.endEncapsulation(); + } + + @Override + public String toString() + { + return _toString(); + } + + @Override + public String _toString() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + return protocol() + options(); + } + + // + // Marshal the endpoint. + // + public abstract void streamWriteImpl(Ice.OutputStream s); + + // + // Return the endpoint type. + // + public abstract short type(); + + // + // Return the protocol name. + // + public abstract String protocol(); + + // + // Return the timeout for the endpoint in milliseconds. 0 means + // non-blocking, -1 means no timeout. + // + public abstract int timeout(); + + // + // Return a new endpoint with a different timeout value, provided + // that timeouts are supported by the endpoint. Otherwise the same + // endpoint is returned. + // + public abstract EndpointI timeout(int t); + + // + // Return the connection ID + // + public abstract String connectionId(); + + // + // Return a new endpoint with a different connection id. + // + public abstract EndpointI connectionId(String connectionId); + + // + // Return true if the endpoints support bzip2 compress, or false + // otherwise. + // + public abstract boolean compress(); + + // + // Return a new endpoint with a different compression value, + // provided that compression is supported by the + // endpoint. Otherwise the same endpoint is returned. + // + public abstract EndpointI compress(boolean co); + + // + // Return true if the endpoint is datagram-based. + // + public abstract boolean datagram(); + + // + // Return true if the endpoint is secure. + // + public abstract boolean secure(); + + // + // Return a server side transceiver for this endpoint, or null if a + // transceiver can only be created by an acceptor. + // + public abstract Transceiver transceiver(); + + // + // Return connectors for this endpoint, or empty list if no connector + // is available. + // + public abstract void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback); + + // + // Return an acceptor for this endpoint, or null if no acceptors + // is available. + // + public abstract Acceptor acceptor(String adapterName); + + // + // Expand endpoint out in to separate endpoints for each local + // host if listening on INADDR_ANY. + // + public abstract java.util.List<EndpointI> expand(); + + // + // Check whether the endpoint is equivalent to another one. + // + public abstract boolean equivalent(EndpointI endpoint); + + public abstract String options(); + + public void initWithOptions(java.util.ArrayList<String> args) + { + java.util.ArrayList<String> unknown = new java.util.ArrayList<String>(); + + String str = "`" + protocol() + " "; + for(String p : args) + { + if(IceUtilInternal.StringUtil.findFirstOf(p, " \t\n\r") != -1) + { + str += " \"" + p + "\""; + } + else + { + str += " " + p; + } + } + str += "'"; + + for(int n = 0; n < args.size(); ++n) + { + String option = args.get(n); + if(option.length() < 2 || option.charAt(0) != '-') + { + unknown.add(option); + continue; + } + + String argument = null; + if(n + 1 < args.size() && args.get(n + 1).charAt(0) != '-') + { + argument = args.get(++n); + } + + if(!checkOption(option, argument, str)) + { + unknown.add(option); + if(argument != null) + { + unknown.add(argument); + } + } + } + + args.clear(); + args.addAll(unknown); + } + + // + // Compare endpoints for sorting purposes. + // + @Override + public boolean equals(java.lang.Object obj) + { + if(!(obj instanceof EndpointI)) + { + return false; + } + return compareTo((EndpointI)obj) == 0; + } + + protected boolean checkOption(String option, String argument, String endpoint) + { + // Must be overridden to check for options. + return false; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EndpointIHolder.java b/java-compat/src/Ice/src/main/java/IceInternal/EndpointIHolder.java new file mode 100644 index 00000000000..226664113f1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EndpointIHolder.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class EndpointIHolder +{ + public EndpointI value; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EndpointI_connectors.java b/java-compat/src/Ice/src/main/java/IceInternal/EndpointI_connectors.java new file mode 100644 index 00000000000..dfcdb479645 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EndpointI_connectors.java @@ -0,0 +1,16 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface EndpointI_connectors +{ + void connectors(java.util.List<Connector> connectors); + void exception(Ice.LocalException ex); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EventHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/EventHandler.java new file mode 100644 index 00000000000..06fab81e580 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EventHandler.java @@ -0,0 +1,44 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class EventHandler +{ + // + // Called when there's a message ready to be processed. + // + abstract public void message(ThreadPoolCurrent current); + + // + // Called when the event handler is unregistered. + // + abstract public void finished(ThreadPoolCurrent current, boolean close); + + // + // Get a textual representation of the event handler. + // + @Override + abstract public String toString(); + + // + // Get the native information of the handler, this is used by the selector. + // + abstract public java.nio.channels.SelectableChannel fd(); + + // + // Set the ready callback + // + abstract public void setReadyCallback(ReadyCallback callback); + + public int _disabled = 0; + public int _registered = 0; + public int _ready = 0; + public java.nio.channels.SelectionKey _key = null; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/EventHandlerOpPair.java b/java-compat/src/Ice/src/main/java/IceInternal/EventHandlerOpPair.java new file mode 100644 index 00000000000..37deadd0ff4 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/EventHandlerOpPair.java @@ -0,0 +1,22 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class EventHandlerOpPair +{ + EventHandlerOpPair(EventHandler handler, int op) + { + this.handler = handler; + this.op = op; + } + + EventHandler handler; + int op; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Ex.java b/java-compat/src/Ice/src/main/java/IceInternal/Ex.java new file mode 100644 index 00000000000..dcffe92be76 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Ex.java @@ -0,0 +1,49 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class Ex +{ + public static void throwUOE(String expectedType, Ice.Object v) + { + // + // If the object is an unknown sliced object, we didn't find an + // value factory, in this case raise a NoValueFactoryException + // instead. + // + if(v instanceof Ice.UnknownSlicedValue) + { + Ice.UnknownSlicedValue usv = (Ice.UnknownSlicedValue)v; + throw new Ice.NoValueFactoryException("", usv.getUnknownTypeId()); + } + + String type = v.ice_id(); + throw new Ice.UnexpectedObjectException("expected element of type `" + expectedType + "' but received '" + + type, type, expectedType); + } + + public static void throwMemoryLimitException(int requested, int maximum) + { + throw new Ice.MemoryLimitException("requested " + requested + " bytes, maximum allowed is " + maximum + + " bytes (see Ice.MessageSizeMax)"); + } + + // + // A small utility to get the strack trace of the exception (which also includes toString()). + // + public static String toString(java.lang.Throwable ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + return sw.toString(); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/FactoryACMMonitor.java b/java-compat/src/Ice/src/main/java/IceInternal/FactoryACMMonitor.java new file mode 100644 index 00000000000..1944656bcfa --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/FactoryACMMonitor.java @@ -0,0 +1,232 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class FactoryACMMonitor implements ACMMonitor +{ + static class Change + { + Change(Ice.ConnectionI connection, boolean remove) + { + this.connection = connection; + this.remove = remove; + } + + final Ice.ConnectionI connection; + final boolean remove; + } + + FactoryACMMonitor(Instance instance, ACMConfig config) + { + _instance = instance; + _config = config; + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_instance == null); + IceUtilInternal.Assert.FinalizerAssert(_connections.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_changes.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_reapedConnections.isEmpty()); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + synchronized void + destroy() + { + if(_instance == null) + { + return; + } + _instance = null; + _connections.clear(); + _changes.clear(); + } + + @Override + public void + add(Ice.ConnectionI connection) + { + if(_config.timeout == 0) + { + return; + } + + synchronized(this) + { + if(_connections.isEmpty()) + { + _connections.add(connection); + assert _future == null; + _future = _instance.timer().scheduleAtFixedRate(new Runnable() { + @Override + public void run() + { + monitorConnections(); + } + }, + _config.timeout / 2, _config.timeout / 2, java.util.concurrent.TimeUnit.MILLISECONDS); + } + else + { + _changes.add(new Change(connection, false)); + } + } + } + + @Override + public void + remove(Ice.ConnectionI connection) + { + if(_config.timeout == 0) + { + return; + } + + synchronized(this) + { + assert(_instance != null); + _changes.add(new Change(connection, true)); + } + } + + @Override + public synchronized void + reap(Ice.ConnectionI connection) + { + _reapedConnections.add(connection); + } + + @Override + public synchronized ACMMonitor + acm(Ice.IntOptional timeout, Ice.Optional<Ice.ACMClose> close, Ice.Optional<Ice.ACMHeartbeat> heartbeat) + { + assert(_instance != null); + + ACMConfig config = _config.clone(); + if(timeout != null && timeout.isSet()) + { + config.timeout = timeout.get() * 1000; // To milliseconds + } + if(close != null && close.isSet()) + { + config.close = close.get(); + } + if(heartbeat != null && heartbeat.isSet()) + { + config.heartbeat = heartbeat.get(); + } + return new ConnectionACMMonitor(this, _instance.timer(), config); + } + + @Override + public Ice.ACM + getACM() + { + Ice.ACM acm = new Ice.ACM(); + acm.timeout = _config.timeout / 1000; + acm.close = _config.close; + acm.heartbeat = _config.heartbeat; + return acm; + } + + synchronized java.util.List<Ice.ConnectionI> + swapReapedConnections() + { + if(_reapedConnections.isEmpty()) + { + return null; + } + java.util.List<Ice.ConnectionI> connections = _reapedConnections; + _reapedConnections = new java.util.ArrayList<Ice.ConnectionI>(); + return connections; + } + + private void + monitorConnections() + { + synchronized(this) + { + if(_instance == null) + { + return; + } + + for(Change change : _changes) + { + if(change.remove) + { + _connections.remove(change.connection); + } + else + { + _connections.add(change.connection); + } + } + _changes.clear(); + + if(_connections.isEmpty()) + { + _future.cancel(false); + _future = null; + return; + } + } + + + // + // Monitor connections outside the thread synchronization, so + // that connections can be added or removed during monitoring. + // + long now = Time.currentMonotonicTimeMillis(); + for(Ice.ConnectionI connection : _connections) + { + try + { + connection.monitor(now, _config); + } + catch(Exception ex) + { + handleException(ex); + } + } + } + + synchronized void + handleException(Exception ex) + { + if(_instance == null) + { + return; + } + _instance.initializationData().logger.error("exception in connection monitor:\n" + ex); + } + + private Instance _instance; + final private ACMConfig _config; + + private java.util.Set<Ice.ConnectionI> _connections = new java.util.HashSet<Ice.ConnectionI>(); + private java.util.List<Change> _changes = new java.util.ArrayList<Change>(); + private java.util.List<Ice.ConnectionI> _reapedConnections = new java.util.ArrayList<Ice.ConnectionI>(); + private java.util.concurrent.Future<?> _future; +} + diff --git a/java-compat/src/Ice/src/main/java/IceInternal/FixedReference.java b/java-compat/src/Ice/src/main/java/IceInternal/FixedReference.java new file mode 100644 index 00000000000..6ae5fe1b4c2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/FixedReference.java @@ -0,0 +1,319 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class FixedReference extends Reference +{ + public + FixedReference(Instance instance, + Ice.Communicator communicator, + Ice.Identity identity, + String facet, + int mode, + boolean secure, + Ice.EncodingVersion encoding, + Ice.ConnectionI connection) + { + super(instance, communicator, identity, facet, mode, secure, Ice.Util.Protocol_1_0, encoding, -1, null); + _fixedConnection = connection; + } + + @Override + public EndpointI[] + getEndpoints() + { + return _emptyEndpoints; + } + + @Override + public String + getAdapterId() + { + return ""; + } + + @Override + public LocatorInfo + getLocatorInfo() + { + return null; + } + + @Override + public RouterInfo + getRouterInfo() + { + return null; + } + + @Override + public boolean + getCollocationOptimized() + { + return false; + } + + @Override + public final boolean + getCacheConnection() + { + return true; + } + + @Override + public boolean + getPreferSecure() + { + return false; + } + + @Override + public final Ice.EndpointSelectionType + getEndpointSelection() + { + return Ice.EndpointSelectionType.Random; + } + + @Override + public int + getLocatorCacheTimeout() + { + return 0; + } + + @Override + public String + getConnectionId() + { + return ""; + } + + @Override + public Reference + changeEndpoints(EndpointI[] newEndpoints) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeAdapterId(String newAdapterId) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeLocator(Ice.LocatorPrx newLocator) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeRouter(Ice.RouterPrx newRouter) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeCollocationOptimized(boolean newCollocationOptimized) + { + throw new Ice.FixedProxyException(); + } + + @Override + public final Reference + changeCacheConnection(boolean newCache) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changePreferSecure(boolean prefSec) + { + throw new Ice.FixedProxyException(); + } + + @Override + public final Reference + changeEndpointSelection(Ice.EndpointSelectionType newType) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeLocatorCacheTimeout(int newTimeout) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeTimeout(int newTimeout) + { + throw new Ice.FixedProxyException(); + } + + @Override + public Reference + changeConnectionId(String connectionId) + { + throw new Ice.FixedProxyException(); + } + + @Override + public boolean + isIndirect() + { + return false; + } + + @Override + public boolean + isWellKnown() + { + return false; + } + + @Override + public void + streamWrite(Ice.OutputStream s) + throws Ice.MarshalException + { + throw new Ice.FixedProxyException(); + } + + @Override + public String + toString() + throws Ice.MarshalException + { + throw new Ice.FixedProxyException(); + } + + @Override + public java.util.Map<String, String> + toProperty(String prefix) + { + throw new Ice.FixedProxyException(); + } + + @Override + public RequestHandler + getRequestHandler(Ice.ObjectPrxHelperBase proxy) + { + switch(getMode()) + { + case Reference.ModeTwoway: + case Reference.ModeOneway: + case Reference.ModeBatchOneway: + { + if(_fixedConnection.endpoint().datagram()) + { + throw new Ice.NoEndpointException(""); + } + break; + } + + case Reference.ModeDatagram: + case Reference.ModeBatchDatagram: + { + if(!_fixedConnection.endpoint().datagram()) + { + throw new Ice.NoEndpointException(""); + } + break; + } + } + + // + // If a secure connection is requested or secure overrides is set, + // check if the connection is secure. + // + boolean secure; + DefaultsAndOverrides defaultsAndOverrides = getInstance().defaultsAndOverrides(); + if(defaultsAndOverrides.overrideSecure) + { + secure = defaultsAndOverrides.overrideSecureValue; + } + else + { + secure = getSecure(); + } + if(secure && !_fixedConnection.endpoint().secure()) + { + throw new Ice.NoEndpointException(""); + } + + _fixedConnection.throwException(); // Throw in case our connection is already destroyed. + + boolean compress; + if(defaultsAndOverrides.overrideCompress) + { + compress = defaultsAndOverrides.overrideCompressValue; + } + else if(_overrideCompress) + { + compress = _compress; + } + else + { + compress = _fixedConnection.endpoint().compress(); + } + + RequestHandler handler = new ConnectionRequestHandler(this, _fixedConnection, compress); + if(getInstance().queueRequests()) + { + handler = new QueueRequestHandler(getInstance(), handler); + } + return proxy.__setRequestHandler(handler); + } + + @Override + public BatchRequestQueue + getBatchRequestQueue() + { + return _fixedConnection.getBatchRequestQueue(); + } + + @Override + public boolean + equals(java.lang.Object obj) + { + if(this == obj) + { + return true; + } + if(!(obj instanceof FixedReference)) + { + return false; + } + FixedReference rhs = (FixedReference)obj; + if(!super.equals(rhs)) + { + return false; + } + return _fixedConnection.equals(rhs._fixedConnection); + } + + @Override + public int + hashCode() + { + return super.hashCode(); + } + + private Ice.ConnectionI _fixedConnection; + private static EndpointI[] _emptyEndpoints = new EndpointI[0]; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_BoolCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_BoolCallback.java new file mode 100644 index 00000000000..71954017a36 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_BoolCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_BoolCallback +{ + void apply(boolean arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_ByteCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_ByteCallback.java new file mode 100644 index 00000000000..06d44618159 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_ByteCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_ByteCallback +{ + void apply(byte arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_CallbackBase.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_CallbackBase.java new file mode 100644 index 00000000000..dc200518c10 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_CallbackBase.java @@ -0,0 +1,50 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_CallbackBase extends IceInternal.CallbackBase +{ + public Functional_CallbackBase(boolean responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + CallbackBase.check(responseCb || exceptionCb != null); + __exceptionCb = exceptionCb; + __sentCb = sentCb; + } + + protected Functional_CallbackBase(Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + __exceptionCb = exceptionCb; + __sentCb = sentCb; + } + + @Override + public final void __sent(Ice.AsyncResult __result) + { + if(__sentCb != null) + { + __sentCb.apply(__result.sentSynchronously()); + } + } + + @Override + public final boolean __hasSentCallback() + { + return __sentCb != null; + } + + @Override + public abstract void __completed(Ice.AsyncResult __result); + + protected final Functional_GenericCallback1<Ice.Exception> __exceptionCb; + protected final Functional_BoolCallback __sentCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_DoubleCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_DoubleCallback.java new file mode 100644 index 00000000000..8aba3931756 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_DoubleCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_DoubleCallback +{ + void apply(double arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_FloatCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_FloatCallback.java new file mode 100644 index 00000000000..69deb3ff76d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_FloatCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_FloatCallback +{ + void apply(float arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_GenericCallback1.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_GenericCallback1.java new file mode 100644 index 00000000000..aae63a7e35b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_GenericCallback1.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_GenericCallback1<T> +{ + void apply(T arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_IntCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_IntCallback.java new file mode 100644 index 00000000000..ab901b9cad8 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_IntCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_IntCallback +{ + void apply(int arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_LongCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_LongCallback.java new file mode 100644 index 00000000000..ff64e28b35e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_LongCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_LongCallback +{ + void apply(long arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_OnewayCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_OnewayCallback.java new file mode 100644 index 00000000000..7962cd4e336 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_OnewayCallback.java @@ -0,0 +1,44 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class Functional_OnewayCallback extends IceInternal.Functional_CallbackBase +{ + public Functional_OnewayCallback(Functional_VoidCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || exceptionCb != null); + __responseCb = responseCb; + } + + @Override + public final void __completed(Ice.AsyncResult __result) + { + try + { + ((Ice.ObjectPrxHelperBase)__result.getProxy()).__end(__result, __result.getOperation()); + if(__responseCb != null) + { + __responseCb.apply(); + } + } + catch(Ice.Exception __ex) + { + if(__exceptionCb != null) + { + __exceptionCb.apply(__ex); + } + } + } + + private final Functional_VoidCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_ShortCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_ShortCallback.java new file mode 100644 index 00000000000..32a1d925ce6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_ShortCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_ShortCallback +{ + void apply(short arg); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallback.java new file mode 100644 index 00000000000..f88b2d64ca6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallback.java @@ -0,0 +1,44 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallback extends IceInternal.Functional_CallbackBase implements Ice.TwowayCallback +{ + public Functional_TwowayCallback(boolean responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb, exceptionCb, sentCb); + } + + protected Functional_TwowayCallback(Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + } + + @Override + public void exception(Ice.SystemException ex) + { + if(__exceptionCb != null) + { + __exceptionCb.apply(ex); + } + } + + @Override + public final void exception(Ice.LocalException ex) + { + if(__exceptionCb != null) + { + __exceptionCb.apply(ex); + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackArg1.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackArg1.java new file mode 100644 index 00000000000..c7b52ea9c52 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackArg1.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackArg1<T> extends Functional_TwowayCallback + implements Ice.TwowayCallbackArg1<T> +{ + public Functional_TwowayCallbackArg1(Functional_GenericCallback1<T> responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackArg1(boolean userExceptionCb, + Functional_GenericCallback1<T> responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + @Override + public void response(T arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_GenericCallback1<T> __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackArg1UE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackArg1UE.java new file mode 100644 index 00000000000..ed810994d8e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackArg1UE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackArg1UE<T> + extends Functional_TwowayCallbackArg1<T> implements Ice.TwowayCallbackArg1UE<T> +{ + public Functional_TwowayCallbackArg1UE( + Functional_GenericCallback1<T> responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(userExceptionCb != null, responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackBool.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackBool.java new file mode 100644 index 00000000000..973b107f1ff --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackBool.java @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackBool extends Functional_TwowayCallback implements Ice.TwowayCallbackBool +{ + public Functional_TwowayCallbackBool(Functional_BoolCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + this.__responseCb = responseCb; + } + + protected Functional_TwowayCallbackBool(boolean userExceptionCb, + Functional_BoolCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + this.__responseCb = responseCb; + } + + @Override + public void response(boolean arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_BoolCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackBoolUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackBoolUE.java new file mode 100644 index 00000000000..28d2a92777f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackBoolUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackBoolUE + extends Functional_TwowayCallbackBool implements Ice.TwowayCallbackBoolUE +{ + public Functional_TwowayCallbackBoolUE( + Functional_BoolCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(userExceptionCb != null, responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackByte.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackByte.java new file mode 100644 index 00000000000..986163e8d80 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackByte.java @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackByte extends Functional_TwowayCallback implements Ice.TwowayCallbackByte +{ + public Functional_TwowayCallbackByte(Functional_ByteCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackByte(boolean userExceptionCb, + Functional_ByteCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + @Override + public void response(byte arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_ByteCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackByteUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackByteUE.java new file mode 100644 index 00000000000..1c0fb9bb8bc --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackByteUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackByteUE + extends Functional_TwowayCallbackByte implements Ice.TwowayCallbackByteUE +{ + public Functional_TwowayCallbackByteUE( + Functional_ByteCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(userExceptionCb != null, responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackDouble.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackDouble.java new file mode 100644 index 00000000000..879014d73e5 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackDouble.java @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackDouble + extends Functional_TwowayCallback implements Ice.TwowayCallbackDouble +{ + public Functional_TwowayCallbackDouble(Functional_DoubleCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackDouble(boolean userExceptionCb, + Functional_DoubleCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + public void response(double arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_DoubleCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackDoubleUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackDoubleUE.java new file mode 100644 index 00000000000..a8d28cf12fe --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackDoubleUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackDoubleUE + extends Functional_TwowayCallbackDouble implements Ice.TwowayCallbackDoubleUE +{ + public Functional_TwowayCallbackDoubleUE( + Functional_DoubleCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(userExceptionCb != null, responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackFloat.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackFloat.java new file mode 100644 index 00000000000..7ea9b1f9753 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackFloat.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackFloat + extends Functional_TwowayCallback implements Ice.TwowayCallbackFloat +{ + public Functional_TwowayCallbackFloat(Functional_FloatCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackFloat(boolean userExceptionCb, + Functional_FloatCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + @Override + public void response(float arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_FloatCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackFloatUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackFloatUE.java new file mode 100644 index 00000000000..d5dc8141064 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackFloatUE.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackFloatUE + extends Functional_TwowayCallbackFloat implements Ice.TwowayCallbackFloatUE +{ + public Functional_TwowayCallbackFloatUE(Functional_FloatCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(userExceptionCb != null, responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackInt.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackInt.java new file mode 100644 index 00000000000..8c6fea2818e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackInt.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackInt + extends Functional_TwowayCallback implements Ice.TwowayCallbackInt +{ + public Functional_TwowayCallbackInt(Functional_IntCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackInt(boolean userExceptionCb, + Functional_IntCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + @Override + public void response(int arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_IntCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackIntUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackIntUE.java new file mode 100644 index 00000000000..b749b44b1ad --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackIntUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackIntUE + extends Functional_TwowayCallbackInt implements Ice.TwowayCallbackIntUE +{ + public Functional_TwowayCallbackIntUE( + Functional_IntCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(userExceptionCb != null, responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackLong.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackLong.java new file mode 100644 index 00000000000..bc6c654643e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackLong.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackLong + extends Functional_TwowayCallback implements Ice.TwowayCallbackLong +{ + public Functional_TwowayCallbackLong(Functional_LongCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackLong(boolean userExceptionCb, + Functional_LongCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + @Override + public void response(long arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_LongCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackLongUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackLongUE.java new file mode 100644 index 00000000000..2eb6985fcb8 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackLongUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackLongUE + extends Functional_TwowayCallbackLong implements Ice.TwowayCallbackLongUE +{ + public Functional_TwowayCallbackLongUE( + Functional_LongCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackShort.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackShort.java new file mode 100644 index 00000000000..f6c835f0721 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackShort.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackShort + extends Functional_TwowayCallback implements Ice.TwowayCallbackShort +{ + public Functional_TwowayCallbackShort(Functional_ShortCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, exceptionCb, sentCb); + __responseCb = responseCb; + } + + protected Functional_TwowayCallbackShort(boolean userExceptionCb, + Functional_ShortCallback responseCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb != null || (userExceptionCb && exceptionCb != null)); + __responseCb = responseCb; + } + + @Override + public void response(short arg) + { + if(__responseCb != null) + { + __responseCb.apply(arg); + } + } + + final private Functional_ShortCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackShortUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackShortUE.java new file mode 100644 index 00000000000..47ff52de87c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackShortUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackShortUE + extends Functional_TwowayCallbackShort implements Ice.TwowayCallbackShortUE +{ + public Functional_TwowayCallbackShortUE( + Functional_ShortCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb, exceptionCb, sentCb); + __userExceptionCb = userExceptionCb; + } + + @Override + public void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + private final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackUE.java new file mode 100644 index 00000000000..5ae5d838274 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackUE.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackUE extends Functional_TwowayCallback implements Ice.TwowayCallbackUE +{ + public Functional_TwowayCallbackUE(boolean responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(exceptionCb, sentCb); + CallbackBase.check(responseCb || (userExceptionCb != null && exceptionCb != null)); + __userExceptionCb = userExceptionCb; + } + + @Override + public final void exception(Ice.UserException ex) + { + if(__userExceptionCb != null) + { + __userExceptionCb.apply(ex); + } + } + + protected final Functional_GenericCallback1<Ice.UserException> __userExceptionCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackVoidUE.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackVoidUE.java new file mode 100644 index 00000000000..080b4ad863a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_TwowayCallbackVoidUE.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Functional_TwowayCallbackVoidUE + extends Functional_TwowayCallbackUE implements Ice.TwowayCallbackVoidUE +{ + public Functional_TwowayCallbackVoidUE( + Functional_VoidCallback responseCb, + Functional_GenericCallback1<Ice.UserException> userExceptionCb, + Functional_GenericCallback1<Ice.Exception> exceptionCb, + Functional_BoolCallback sentCb) + { + super(responseCb != null, userExceptionCb, exceptionCb, sentCb); + __responseCb = responseCb; + } + + @Override + public void response() + { + if(__responseCb != null) + { + __responseCb.apply(); + } + } + + private final Functional_VoidCallback __responseCb; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Functional_VoidCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/Functional_VoidCallback.java new file mode 100644 index 00000000000..ca40c37cd7c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Functional_VoidCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Functional_VoidCallback +{ + void apply(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/HTTPNetworkProxy.java b/java-compat/src/Ice/src/main/java/IceInternal/HTTPNetworkProxy.java new file mode 100644 index 00000000000..1214731fbea --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/HTTPNetworkProxy.java @@ -0,0 +1,135 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class HTTPNetworkProxy implements NetworkProxy +{ + public HTTPNetworkProxy(String host, int port) + { + _host = host; + _port = port; + _protocolSupport = Network.EnableBoth; + } + + private HTTPNetworkProxy(java.net.InetSocketAddress address, int protocolSupport) + { + _address = address; + _protocolSupport = protocolSupport; + } + + @Override + public void beginWrite(java.net.InetSocketAddress endpoint, Buffer buf) + { + String addr = Network.addrToString(endpoint); + StringBuilder str = new StringBuilder(); + str.append("CONNECT "); + str.append(addr); + str.append(" HTTP/1.1\r\nHost: "); + str.append(addr); + str.append("\r\n\r\n"); + + byte[] b = str.toString().getBytes(java.nio.charset.StandardCharsets.US_ASCII); + + // + // HTTP connect request + // + buf.resize(b.length, false); + buf.b.position(0); + buf.b.put(b); + buf.b.position(0); + buf.b.limit(buf.size()); + } + + @Override + public int endWrite(Buffer buf) + { + // Once the request is sent, read the response + return buf.b.hasRemaining() ? SocketOperation.Write : SocketOperation.Read; + } + + @Override + public void beginRead(Buffer buf) + { + // + // Read the HTTP response + // + buf.resize(7, true); // Enough space for reading at least HTTP1.1 + buf.b.position(0); + } + + @Override + public int endRead(Buffer buf) + { + // + // Check if we received the full HTTP response, if not, continue + // reading otherwise we're done. + // + int end = new HttpParser().isCompleteMessage(buf.b, 0, buf.b.position()); + if(end < 0 && !buf.b.hasRemaining()) + { + // + // Read one more byte, we can't easily read bytes in advance + // since the transport implenentation might be be able to read + // the data from the memory instead of the socket. + // + buf.resize(buf.size() + 1, true); + return SocketOperation.Read; + } + return SocketOperation.None; + } + + @Override + public void finish(Buffer readBuffer, Buffer writeBuffer) + { + HttpParser parser = new HttpParser(); + parser.parse(readBuffer.b, 0, readBuffer.b.position()); + if(parser.status() != 200) + { + throw new Ice.ConnectFailedException(); + } + } + + @Override + public NetworkProxy resolveHost(int protocol) + { + assert(_host != null); + return new HTTPNetworkProxy(Network.getAddresses(_host, + _port, + protocol, + Ice.EndpointSelectionType.Random, + false, + true).get(0), + protocol); + } + + @Override + public java.net.InetSocketAddress getAddress() + { + assert(_address != null); // Host must be resolved. + return _address; + } + + @Override + public String getName() + { + return "HTTP"; + } + + @Override + public int getProtocolSupport() + { + return _protocolSupport; + } + + private String _host; + private int _port; + private java.net.InetSocketAddress _address; + private int _protocolSupport; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/HashUtil.java b/java-compat/src/Ice/src/main/java/IceInternal/HashUtil.java new file mode 100644 index 00000000000..fc931e8294f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/HashUtil.java @@ -0,0 +1,120 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class HashUtil +{ + public static int + hashAdd(int hashCode, boolean value) + { + return ((hashCode << 5) + hashCode) ^ (value ? 0 : 1); + } + + public static int + hashAdd(int hashCode, short value) + { + return ((hashCode << 5) + hashCode) ^ (int)(2654435761l * value); + } + + public static int + hashAdd(int hashCode, byte value) + { + return ((hashCode << 5) + hashCode) ^ (int)(2654435761l * value); + } + + public static int + hashAdd(int hashCode, int value) + { + return ((hashCode << 5) + hashCode) ^ (int)(2654435761l * value); + } + + public static int + hashAdd(int hashCode, long value) + { + return ((hashCode << 5) + hashCode) ^ (int)(value ^ (value >>> 32)); + } + + public static int + hashAdd(int hashCode, float value) + { + return ((hashCode << 5) + hashCode) ^ Float.floatToIntBits(value); + } + + public static int + hashAdd(int hashCode, double value) + { + long v = Double.doubleToLongBits(value); + return ((hashCode << 5) + hashCode) ^ (int)(v ^ (v >>> 32)); + } + + public static int + hashAdd(int hashCode, java.lang.Object value) + { + if(value != null) + { + hashCode = ((hashCode << 5) + hashCode) ^ value.hashCode(); + } + return hashCode; + } + + public static int + hashAdd(int hashCode, boolean[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, byte[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, char[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, double[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, float[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, int[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, long[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, Object[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } + + public static int + hashAdd(int hashCode, short[] arr) + { + return ((hashCode << 5) + hashCode) ^ java.util.Arrays.hashCode(arr); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/HttpParser.java b/java-compat/src/Ice/src/main/java/IceInternal/HttpParser.java new file mode 100644 index 00000000000..999b2a62430 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/HttpParser.java @@ -0,0 +1,732 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class HttpParser +{ + HttpParser() + { + _type = Type.Unknown; + _versionMajor = 0; + _versionMinor = 0; + _status = 0; + _state = State.Init; + } + + private enum Type + { + Unknown, + Request, + Response + } + + int isCompleteMessage(java.nio.ByteBuffer buf, int begin, int end) + { + int p = begin; + + // + // Skip any leading CR-LF characters. + // + while(p < end) + { + byte ch = buf.get(p); + if(ch != (byte)'\r' && ch != (byte)'\n') + { + break; + } + ++p; + } + + // + // Look for adjacent CR-LF/CR-LF or LF/LF. + // + boolean seenFirst = false; + while(p < end) + { + byte ch = buf.get(p++); + if(ch == (byte)'\n') + { + if(seenFirst) + { + return p; + } + else + { + seenFirst = true; + } + } + else if(ch != (byte)'\r') + { + seenFirst = false; + } + } + + return -1; + } + + boolean parse(java.nio.ByteBuffer buf, int begin, int end) + { + int p = begin; + int start = 0; + final char CR = '\r'; + final char LF = '\n'; + + if(_state == State.Complete) + { + _state = State.Init; + } + + while(p != end && _state != State.Complete) + { + char c = (char)buf.get(p); + + switch(_state) + { + case Init: + { + _method.setLength(0); + _uri.setLength(0); + _versionMajor = -1; + _versionMinor = -1; + _status = -1; + _reason = ""; + _headers.clear(); + _state = State.Type; + continue; + } + case Type: + { + if(c == CR || c == LF) + { + break; + } + else if(c == 'H') + { + // + // Could be the start of "HTTP/1.1" or "HEAD". + // + _state = State.TypeCheck; + break; + } + else + { + _state = State.Request; + continue; + } + } + case TypeCheck: + { + if(c == 'T') // Continuing "H_T_TP/1.1" + { + _state = State.Response; + } + else if(c == 'E') // Expecting "HEAD" + { + _state = State.Request; + _method.append('H'); + _method.append('E'); + } + else + { + throw new WebSocketException("malformed request or response"); + } + break; + } + case Request: + { + _type = Type.Request; + _state = State.RequestMethod; + continue; + } + case RequestMethod: + { + if(c == ' ' || c == CR || c == LF) + { + _state = State.RequestMethodSP; + continue; + } + _method.append(c); + break; + } + case RequestMethodSP: + { + if(c == ' ') + { + break; + } + else if(c == CR || c == LF) + { + throw new WebSocketException("malformed request"); + } + _state = State.RequestURI; + continue; + } + case RequestURI: + { + if(c == ' ' || c == CR || c == LF) + { + _state = State.RequestURISP; + continue; + } + _uri.append(c); + break; + } + case RequestURISP: + { + if(c == ' ') + { + break; + } + else if(c == CR || c == LF) + { + throw new WebSocketException("malformed request"); + } + _state = State.Version; + continue; + } + case RequestLF: + { + if(c != LF) + { + throw new WebSocketException("malformed request"); + } + _state = State.HeaderFieldStart; + break; + } + case HeaderFieldStart: + { + // + // We've already seen a LF to reach this state. + // + // Another CR or LF indicates the end of the header fields. + // + if(c == CR) + { + _state = State.HeaderFieldEndLF; + break; + } + else if(c == LF) + { + _state = State.Complete; + break; + } + else if(c == ' ') + { + // + // Could be a continuation line. + // + _state = State.HeaderFieldContStart; + break; + } + + _state = State.HeaderFieldNameStart; + continue; + } + case HeaderFieldContStart: + { + if(c == ' ') + { + break; + } + + _state = State.HeaderFieldCont; + start = p; + continue; + } + case HeaderFieldCont: + { + if(c == CR || c == LF) + { + if(p > start) + { + if(_headerName.isEmpty()) + { + throw new WebSocketException("malformed header"); + } + String s = _headers.get(_headerName); + assert(s != null); + StringBuffer newValue = new StringBuffer(s); + newValue.append(' '); + for(int i = start; i < p; ++i) + { + newValue.append((char)buf.get(i)); + } + _headers.put(_headerName, newValue.toString()); + _state = c == CR ? State.HeaderFieldLF : State.HeaderFieldStart; + } + else + { + // + // Could mark the end of the header fields. + // + _state = c == CR ? State.HeaderFieldEndLF : State.Complete; + } + } + + break; + } + case HeaderFieldNameStart: + { + assert(c != ' '); + start = p; + _headerName = ""; + _state = State.HeaderFieldName; + continue; + } + case HeaderFieldName: + { + if(c == ' ' || c == ':') + { + _state = State.HeaderFieldNameEnd; + continue; + } + else if(c == CR || c == LF) + { + throw new WebSocketException("malformed header"); + } + break; + } + case HeaderFieldNameEnd: + { + if(_headerName.isEmpty()) + { + StringBuffer str = new StringBuffer(); + for(int i = start; i < p; ++i) + { + str.append((char)buf.get(i)); + } + _headerName = str.toString().toLowerCase(); + // + // Add a placeholder entry if necessary. + // + if(!_headers.containsKey(_headerName)) + { + _headers.put(_headerName, ""); + _headerNames.put(_headerName, str.toString()); + } + } + + if(c == ' ') + { + break; + } + else if(c != ':' || p == start) + { + throw new WebSocketException("malformed header"); + } + + _state = State.HeaderFieldValueStart; + break; + } + case HeaderFieldValueStart: + { + if(c == ' ') + { + break; + } + + // + // Check for "Name:\r\n" + // + if(c == CR) + { + _state = State.HeaderFieldLF; + break; + } + else if(c == LF) + { + _state = State.HeaderFieldStart; + break; + } + + start = p; + _state = State.HeaderFieldValue; + continue; + } + case HeaderFieldValue: + { + if(c == CR || c == LF) + { + _state = State.HeaderFieldValueEnd; + continue; + } + break; + } + case HeaderFieldValueEnd: + { + assert(c == CR || c == LF); + if(p > start) + { + StringBuffer str = new StringBuffer(); + for(int i = start; i < p; ++i) + { + str.append((char)buf.get(i)); + } + String s = _headers.get(_headerName); + if(s == null || s.length() == 0) + { + _headers.put(_headerName, str.toString()); + } + else + { + _headers.put(_headerName, s + ", " + str.toString()); + } + } + + if(c == CR) + { + _state = State.HeaderFieldLF; + } + else + { + _state = State.HeaderFieldStart; + } + break; + } + case HeaderFieldLF: + { + if(c != LF) + { + throw new WebSocketException("malformed header"); + } + _state = State.HeaderFieldStart; + break; + } + case HeaderFieldEndLF: + { + if(c != LF) + { + throw new WebSocketException("malformed header"); + } + _state = State.Complete; + break; + } + case Version: + { + if(c != 'H') + { + throw new WebSocketException("malformed version"); + } + _state = State.VersionH; + break; + } + case VersionH: + { + if(c != 'T') + { + throw new WebSocketException("malformed version"); + } + _state = State.VersionHT; + break; + } + case VersionHT: + { + if(c != 'T') + { + throw new WebSocketException("malformed version"); + } + _state = State.VersionHTT; + break; + } + case VersionHTT: + { + if(c != 'P') + { + throw new WebSocketException("malformed version"); + } + _state = State.VersionHTTP; + break; + } + case VersionHTTP: + { + if(c != '/') + { + throw new WebSocketException("malformed version"); + } + _state = State.VersionMajor; + break; + } + case VersionMajor: + { + if(c == '.') + { + if(_versionMajor == -1) + { + throw new WebSocketException("malformed version"); + } + _state = State.VersionMinor; + break; + } + else if(c < '0' || c > '9') + { + throw new WebSocketException("malformed version"); + } + if(_versionMajor == -1) + { + _versionMajor = 0; + } + _versionMajor *= 10; + _versionMajor += c - '0'; + break; + } + case VersionMinor: + { + if(c == CR) + { + if(_versionMinor == -1 || _type != Type.Request) + { + throw new WebSocketException("malformed version"); + } + _state = State.RequestLF; + break; + } + else if(c == LF) + { + if(_versionMinor == -1 || _type != Type.Request) + { + throw new WebSocketException("malformed version"); + } + _state = State.HeaderFieldStart; + break; + } + else if(c == ' ') + { + if(_versionMinor == -1 || _type != Type.Response) + { + throw new WebSocketException("malformed version"); + } + _state = State.ResponseVersionSP; + break; + } + else if(c < '0' || c > '9') + { + throw new WebSocketException("malformed version"); + } + if(_versionMinor == -1) + { + _versionMinor = 0; + } + _versionMinor *= 10; + _versionMinor += c - '0'; + break; + } + case Response: + { + _type = Type.Response; + _state = State.VersionHT; + continue; + } + case ResponseVersionSP: + { + if(c == ' ') + { + break; + } + + _state = State.ResponseStatus; + continue; + } + case ResponseStatus: + { + // TODO: Is reason string optional? + if(c == CR) + { + if(_status == -1) + { + throw new WebSocketException("malformed response status"); + } + _state = State.ResponseLF; + break; + } + else if(c == LF) + { + if(_status == -1) + { + throw new WebSocketException("malformed response status"); + } + _state = State.HeaderFieldStart; + break; + } + else if(c == ' ') + { + if(_status == -1) + { + throw new WebSocketException("malformed response status"); + } + _state = State.ResponseReasonStart; + break; + } + else if(c < '0' || c > '9') + { + throw new WebSocketException("malformed response status"); + } + if(_status == -1) + { + _status = 0; + } + _status *= 10; + _status += c - '0'; + break; + } + case ResponseReasonStart: + { + // + // Skip leading spaces. + // + if(c == ' ') + { + break; + } + + _state = State.ResponseReason; + start = p; + continue; + } + case ResponseReason: + { + if(c == CR || c == LF) + { + if(p > start) + { + StringBuffer str = new StringBuffer(); + for(int i = start; i < p; ++i) + { + str.append((char)buf.get(i)); + } + _reason = str.toString(); + } + _state = c == CR ? State.ResponseLF : State.HeaderFieldStart; + } + + break; + } + case ResponseLF: + { + if(c != LF) + { + throw new WebSocketException("malformed status line"); + } + _state = State.HeaderFieldStart; + break; + } + case Complete: + { + assert(false); // Shouldn't reach + } + } + + ++p; + } + + return _state == State.Complete; + } + + String uri() + { + assert(_type == Type.Request); + return _uri.toString(); + } + + int versionMajor() + { + return _versionMajor; + } + + int versionMinor() + { + return _versionMinor; + } + + int status() + { + return _status; + } + + String reason() + { + return _reason; + } + + String getHeader(String name, boolean toLower) + { + String s = _headers.get(name.toLowerCase()); + if(s != null) + { + return toLower ? s.trim().toLowerCase() : s.trim(); + } + + return null; + } + + java.util.Map<String, String> getHeaders() + { + java.util.Map<String, String> headers = new java.util.HashMap<String, String>(); + for(java.util.Map.Entry<String, String> entry : _headers.entrySet()) + { + headers.put(_headerNames.get(entry.getKey()), entry.getValue().trim()); // Return original header name. + } + return headers; + } + + private Type _type; + + private StringBuffer _method = new StringBuffer(); + private StringBuffer _uri = new StringBuffer(); + + private java.util.Map<String, String> _headers = new java.util.HashMap<String, String>(); + private java.util.Map<String, String> _headerNames = new java.util.HashMap<String, String>(); + private String _headerName = ""; + + private int _versionMajor; + private int _versionMinor; + + private int _status; + private String _reason; + + private enum State + { + Init, + Type, + TypeCheck, + Request, + RequestMethod, + RequestMethodSP, + RequestURI, + RequestURISP, + RequestLF, + HeaderFieldStart, + HeaderFieldContStart, + HeaderFieldCont, + HeaderFieldNameStart, + HeaderFieldName, + HeaderFieldNameEnd, + HeaderFieldValueStart, + HeaderFieldValue, + HeaderFieldValueEnd, + HeaderFieldLF, + HeaderFieldEndLF, + Version, + VersionH, + VersionHT, + VersionHTT, + VersionHTTP, + VersionMajor, + VersionMinor, + Response, + ResponseVersionSP, + ResponseStatus, + ResponseReasonStart, + ResponseReason, + ResponseLF, + Complete + } + + private State _state; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/IPEndpointI.java b/java-compat/src/Ice/src/main/java/IceInternal/IPEndpointI.java new file mode 100644 index 00000000000..7a6057800c6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/IPEndpointI.java @@ -0,0 +1,377 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class IPEndpointI extends EndpointI +{ + protected IPEndpointI(ProtocolInstance instance, String host, int port, java.net.InetSocketAddress sourceAddr, + String connectionId) + { + _instance = instance; + _host = host; + _port = port; + _sourceAddr = sourceAddr; + _connectionId = connectionId; + _hashInitialized = false; + } + + protected IPEndpointI(ProtocolInstance instance) + { + _instance = instance; + _host = null; + _port = 0; + _sourceAddr = null; + _connectionId = ""; + _hashInitialized = false; + } + + protected IPEndpointI(ProtocolInstance instance, Ice.InputStream s) + { + _instance = instance; + _host = s.readString(); + _port = s.readInt(); + _sourceAddr = null; + _connectionId = ""; + _hashInitialized = false; + } + + @Override + public Ice.EndpointInfo getInfo() + { + Ice.IPEndpointInfo info = new Ice.IPEndpointInfo() + { + @Override + public short type() + { + return IPEndpointI.this.type(); + } + + @Override + public boolean datagram() + { + return IPEndpointI.this.datagram(); + } + + @Override + public boolean secure() + { + return IPEndpointI.this.secure(); + } + }; + fillEndpointInfo(info); + return info; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public boolean secure() + { + return _instance.secure(); + } + + @Override + public String connectionId() + { + return _connectionId; + } + + @Override + public EndpointI connectionId(String connectionId) + { + if(connectionId.equals(_connectionId)) + { + return this; + } + else + { + return createEndpoint(_host, _port, connectionId); + } + } + + @Override + public void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) + { + _instance.resolve(_host, _port, selType, this, callback); + } + + @Override + public java.util.List<EndpointI> expand() + { + java.util.List<EndpointI> endps = new java.util.ArrayList<EndpointI>(); + java.util.List<String> hosts = Network.getHostsForEndpointExpand(_host, _instance.protocolSupport(), false); + if(hosts == null || hosts.isEmpty()) + { + endps.add(this); + } + else + { + for(String h : hosts) + { + endps.add(createEndpoint(h, _port, _connectionId)); + } + } + return endps; + } + + @Override + public boolean equivalent(EndpointI endpoint) + { + if(!(endpoint instanceof IPEndpointI)) + { + return false; + } + IPEndpointI ipEndpointI = (IPEndpointI)endpoint; + return ipEndpointI.type() == type() && ipEndpointI._host.equals(_host) && ipEndpointI._port == _port && + Network.compareAddress(ipEndpointI._sourceAddr, _sourceAddr) == 0; + } + + public java.util.List<Connector> connectors(java.util.List<java.net.InetSocketAddress> addresses, + NetworkProxy proxy) + { + java.util.List<Connector> connectors = new java.util.ArrayList<Connector>(); + for(java.net.InetSocketAddress p : addresses) + { + connectors.add(createConnector(p, proxy)); + } + return connectors; + } + + @Override + synchronized public int hashCode() + { + if(!_hashInitialized) + { + _hashValue = 5381; + _hashValue = HashUtil.hashAdd(_hashValue, type()); + _hashValue = hashInit(_hashValue); + _hashInitialized = true; + } + return _hashValue; + } + + @Override + public String options() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = ""; + + if(_host != null && _host.length() > 0) + { + s += " -h "; + boolean addQuote = _host.indexOf(':') != -1; + if(addQuote) + { + s += "\""; + } + s += _host; + if(addQuote) + { + s += "\""; + } + } + + s += " -p " + _port; + + if(_sourceAddr != null) + { + s += " --sourceAddress " + _sourceAddr.getAddress().getHostAddress(); + } + + return s; + } + + @Override + public int compareTo(EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof IPEndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + IPEndpointI p = (IPEndpointI)obj; + if(this == p) + { + return 0; + } + + int v = _host.compareTo(p._host); + if(v != 0) + { + return v; + } + + if(_port < p._port) + { + return -1; + } + else if(p._port < _port) + { + return 1; + } + + int rc = Network.compareAddress(_sourceAddr, p._sourceAddr); + if(rc != 0) + { + return rc; + } + + return _connectionId.compareTo(p._connectionId); + } + + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + s.writeString(_host); + s.writeInt(_port); + } + + public int hashInit(int h) + { + h = HashUtil.hashAdd(h, _host); + h = HashUtil.hashAdd(h, _port); + if(_sourceAddr != null) + { + h = HashUtil.hashAdd(h, _sourceAddr.getAddress().getHostAddress()); + } + h = HashUtil.hashAdd(h, _connectionId); + return h; + } + + public void fillEndpointInfo(Ice.IPEndpointInfo info) + { + info.timeout = timeout(); + info.compress = compress(); + info.host = _host; + info.port = _port; + info.sourceAddress = _sourceAddr == null ? "" : _sourceAddr.getAddress().getHostAddress(); + } + + public void initWithOptions(java.util.ArrayList<String> args, boolean oaEndpoint) + { + super.initWithOptions(args); + + if(_host == null || _host.length() == 0) + { + _host = _instance.defaultHost(); + } + else if(_host.equals("*")) + { + if(oaEndpoint) + { + _host = ""; + } + else + { + throw new Ice.EndpointParseException("`-h *' not valid for proxy endpoint `" + toString() + "'"); + } + } + + if(_host == null) + { + _host = ""; + } + + if(_sourceAddr == null) + { + if (!oaEndpoint) + { + _sourceAddr = _instance.defaultSourceAddress(); + } + } + else if(oaEndpoint) + { + throw new Ice.EndpointParseException("`--sourceAddress' not valid for object adapter endpoint `" + + toString() + "'"); + } + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + if(option.equals("-h")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -h option in endpoint " + endpoint); + } + _host = argument; + } + else if(option.equals("-p")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -p option in endpoint " + endpoint); + } + + try + { + _port = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid port value `" + argument + + "' in endpoint " + endpoint); + } + + if(_port < 0 || _port > 65535) + { + throw new Ice.EndpointParseException("port value `" + argument + + "' out of range in endpoint " + endpoint); + } + } + else if(option.equals("--sourceAddress")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for --sourceAddress option in endpoint " + + endpoint); + } + _sourceAddr = Network.getNumericAddress(argument); + if(_sourceAddr == null) + { + throw new Ice.EndpointParseException( + "invalid IP address provided for --sourceAddress option in endpoint " + endpoint); + } + } + else + { + return false; + } + return true; + } + + protected abstract Connector createConnector(java.net.InetSocketAddress addr, NetworkProxy proxy); + protected abstract IPEndpointI createEndpoint(String host, int port, String connectionId); + + protected ProtocolInstance _instance; + protected String _host; + protected int _port; + protected java.net.InetSocketAddress _sourceAddr; + protected String _connectionId; + private boolean _hashInitialized; + private int _hashValue; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Incoming.java b/java-compat/src/Ice/src/main/java/IceInternal/Incoming.java new file mode 100644 index 00000000000..6a7babc0c36 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Incoming.java @@ -0,0 +1,415 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import Ice.Instrumentation.CommunicatorObserver; + +final public class Incoming extends IncomingBase implements Ice.Request +{ + public + Incoming(Instance instance, ResponseHandler responseHandler, Ice.ConnectionI connection, Ice.ObjectAdapter adapter, + boolean response, byte compress, int requestId) + { + super(instance, responseHandler, connection, adapter, response, compress, requestId); + + // + // Prepare the response if necessary. + // + if(response) + { + _os.writeBlob(IceInternal.Protocol.replyHdr); + + // + // Add the request ID. + // + _os.writeInt(requestId); + } + } + + @Override + public Ice.Current + getCurrent() + { + return _current; + } + + // + // These functions allow this object to be reused, rather than reallocated. + // + @Override + public void + reset(Instance instance, ResponseHandler handler, Ice.ConnectionI connection, Ice.ObjectAdapter adapter, + boolean response, byte compress, int requestId) + { + _cb = null; + _inParamPos = -1; + + super.reset(instance, handler, connection, adapter, response, compress, requestId); + + // + // Prepare the response if necessary. + // + if(response) + { + _os.writeBlob(IceInternal.Protocol.replyHdr); + + // + // Add the request ID. + // + _os.writeInt(requestId); + } + } + + @Override + public void + reclaim() + { + _cb = null; + _inParamPos = -1; + + super.reclaim(); + } + + public void + invoke(ServantManager servantManager, Ice.InputStream stream) + { + _is = stream; + + int start = _is.pos(); + + // + // Read the current. + // + _current.id.__read(_is); + + // + // For compatibility with the old FacetPath. + // + String[] facetPath = _is.readStringSeq(); + if(facetPath.length > 0) + { + if(facetPath.length > 1) + { + throw new Ice.MarshalException(); + } + _current.facet = facetPath[0]; + } + else + { + _current.facet = ""; + } + + _current.operation = _is.readString(); + _current.mode = Ice.OperationMode.values()[_is.readByte()]; + _current.ctx = new java.util.HashMap<String, String>(); + int sz = _is.readSize(); + while(sz-- > 0) + { + String first = _is.readString(); + String second = _is.readString(); + _current.ctx.put(first, second); + } + + CommunicatorObserver obsv = _instance.initializationData().observer; + if(obsv != null) + { + // Read the parameter encapsulation size. + int size = _is.readInt(); + _is.pos(_is.pos() - 4); + + _observer = obsv.getDispatchObserver(_current, _is.pos() - start + size); + if(_observer != null) + { + _observer.attach(); + } + } + + // + // Don't put the code above into the try block below. Exceptions + // in the code above are considered fatal, and must propagate to + // the caller of this operation. + // + + if(servantManager != null) + { + _servant = servantManager.findServant(_current.id, _current.facet); + if(_servant == null) + { + _locator = servantManager.findServantLocator(_current.id.category); + if(_locator == null && _current.id.category.length() > 0) + { + _locator = servantManager.findServantLocator(""); + } + + if(_locator != null) + { + try + { + _servant = _locator.locate(_current, _cookie); + } + catch(Ice.UserException ex) + { + Ice.EncodingVersion encoding = _is.skipEncapsulation(); // Required for batch requests. + + if(_observer != null) + { + _observer.userException(); + } + + if(_response) + { + _os.writeByte(ReplyStatus.replyUserException); + _os.startEncapsulation(encoding, Ice.FormatType.DefaultFormat); + _os.writeException(ex); + _os.endEncapsulation(); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, false); + } + else + { + _responseHandler.sendNoResponse(); + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + _responseHandler = null; + return; + } + catch(java.lang.Exception ex) + { + _is.skipEncapsulation(); // Required for batch requests. + __handleException(ex, false); + return; + } + catch(java.lang.Error ex) + { + _is.skipEncapsulation(); // Required for batch requests. + __handleError(ex, false); // Always throws. + } + } + } + } + + try + { + if(_servant != null) + { + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(_servant.getClass().getClassLoader()); + } + + try + { + // + // DispatchAsync is a "pseudo dispatch status", used internally only + // to indicate async dispatch. + // + if(_servant.__dispatch(this, _current) == Ice.DispatchStatus.DispatchAsync) + { + // + // If this was an asynchronous dispatch, we're done here. + // + return; + } + } + finally + { + if(_instance.useApplicationClassLoader()) + { + Thread.currentThread().setContextClassLoader(null); + } + } + + if(_locator != null && !__servantLocatorFinished(false)) + { + return; + } + } + else + { + // + // Skip the input parameters, this is required for reading + // the next batch request if dispatching batch requests. + // + _is.skipEncapsulation(); + + if(servantManager != null && servantManager.hasServant(_current.id)) + { + throw new Ice.FacetNotExistException(_current.id, _current.facet, _current.operation); + } + else + { + throw new Ice.ObjectNotExistException(_current.id, _current.facet, _current.operation); + } + } + } + catch(java.lang.Exception ex) + { + if(_servant != null && _locator != null && !__servantLocatorFinished(false)) + { + return; + } + __handleException(ex, false); + return; + } + catch(java.lang.Error ex) + { + if(_servant != null && _locator != null && !__servantLocatorFinished(false)) + { + return; + } + __handleError(ex, false); // Always throws. + } + + // + // Don't put the code below into the try block above. Exceptions + // in the code below are considered fatal, and must propagate to + // the caller of this operation. + // + + assert(_responseHandler != null); + + if(_response) + { + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, false); + } + else + { + _responseHandler.sendNoResponse(); + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + _responseHandler = null; + } + + public final void + push(Ice.DispatchInterceptorAsyncCallback cb) + { + if(_interceptorAsyncCallbackList == null) + { + _interceptorAsyncCallbackList = new java.util.LinkedList<Ice.DispatchInterceptorAsyncCallback>(); + } + + _interceptorAsyncCallbackList.addFirst(cb); + } + + public final void + pop() + { + assert _interceptorAsyncCallbackList != null; + _interceptorAsyncCallbackList.removeFirst(); + } + + public final void + startOver() + { + if(_inParamPos == -1) + { + // + // That's the first startOver, so almost nothing to do + // + _inParamPos = _is.pos(); + } + else + { + killAsync(); + + // + // Let's rewind _is and clean-up _os + // + _is.pos(_inParamPos); + if(_response) + { + _os.resize(Protocol.headerSize + 4); + } + } + } + + public final void + killAsync() + { + // + // Always runs in the dispatch thread + // + if(_cb != null) + { + // + // May raise ResponseSentException + // + _cb.__deactivate(this); + _cb = null; + } + } + + public final Ice.InputStream + startReadParams() + { + // + // Remember the encoding used by the input parameters, we'll + // encode the response parameters with the same encoding. + // + _current.encoding = _is.startEncapsulation(); + return _is; + } + + public final void + endReadParams() + { + _is.endEncapsulation(); + } + + public final void + readEmptyParams() + { + _current.encoding = _is.skipEmptyEncapsulation(); + } + + public final byte[] + readParamEncaps() + { + _current.encoding = new Ice.EncodingVersion(); + return _is.readEncapsulation(_current.encoding); + } + + final void + setActive(IncomingAsync cb) + { + assert _cb == null; + _cb = cb; + } + + final boolean + isRetriable() + { + return _inParamPos != -1; + } + + public Incoming next; // For use by ConnectionI. + + private Ice.InputStream _is; + + private IncomingAsync _cb; + private int _inParamPos = -1; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/IncomingAsync.java b/java-compat/src/Ice/src/main/java/IceInternal/IncomingAsync.java new file mode 100644 index 00000000000..7abed77651d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/IncomingAsync.java @@ -0,0 +1,204 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class IncomingAsync extends IncomingBase implements Ice.AMDCallback +{ + public + IncomingAsync(Incoming in) // Adopts the argument. It must not be used afterwards. + { + super(in); + _retriable = in.isRetriable(); + + if(_retriable) + { + in.setActive(this); + _active = true; + } + } + + @Override + public void + ice_exception(java.lang.Exception ex) + { + // + // Only call __exception if this incoming is not retriable or if + // all the interceptors return true and no response has been sent + // yet. + // + + if(_retriable) + { + try + { + if(_interceptorAsyncCallbackList != null) + { + for(Ice.DispatchInterceptorAsyncCallback cb : _interceptorAsyncCallbackList) + { + if(!cb.exception(ex)) + { + return; + } + } + } + } + catch(java.lang.RuntimeException exc) + { + return; + } + + synchronized(this) + { + if(!_active) + { + return; + } + _active = false; + } + } + + if(_responseHandler != null) + { + __exception(ex); + } + else + { + // + // Response has already been sent. + // + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + } + } + + final void + __deactivate(Incoming in) + { + assert _retriable; + + synchronized(this) + { + if(!_active) + { + // + // Since _deactivate can only be called on an active object, + // this means the response has already been sent (see __validateXXX below) + // + throw new Ice.ResponseSentException(); + } + _active = false; + } + + in.adopt(this); + } + + final protected void + __response() + { + try + { + if(_locator != null && !__servantLocatorFinished(true)) + { + return; + } + + assert(_responseHandler != null); + + if(_response) + { + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, true); + } + else + { + _responseHandler.sendNoResponse(); + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + _responseHandler = null; + } + catch(Ice.LocalException ex) + { + _responseHandler.invokeException(_current.requestId, ex, 1, true); + } + } + + final protected void + __exception(java.lang.Exception exc) + { + try + { + if(_locator != null && !__servantLocatorFinished(true)) + { + return; + } + + __handleException(exc, true); + } + catch(Ice.LocalException ex) + { + _responseHandler.invokeException(_current.requestId, ex, 1, true); + } + } + + final protected boolean + __validateResponse(boolean ok) + { + // + // Only returns true if this incoming is not retriable or if all + // the interceptors return true and no response has been sent + // yet. Upon getting a true return value, the caller should send + // the response. + // + + if(_retriable) + { + try + { + if(_interceptorAsyncCallbackList != null) + { + for(Ice.DispatchInterceptorAsyncCallback cb : _interceptorAsyncCallbackList) + { + if(!cb.response(ok)) + { + return false; + } + } + } + } + catch(java.lang.RuntimeException ex) + { + return false; + } + + synchronized(this) + { + if(!_active) + { + return false; + } + _active = false; + } + } + return true; + } + + private final boolean _retriable; + private boolean _active = false; // only meaningful when _retriable == true +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java b/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java new file mode 100644 index 00000000000..93c853c9853 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/IncomingBase.java @@ -0,0 +1,663 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class IncomingBase +{ + protected + IncomingBase(Instance instance, ResponseHandler handler, Ice.ConnectionI connection, Ice.ObjectAdapter adapter, + boolean response, byte compress, int requestId) + { + _instance = instance; + _responseHandler = handler; + _response = response; + _compress = compress; + if(_response) + { + _os = new Ice.OutputStream(instance, Protocol.currentProtocolEncoding); + } + + _current = new Ice.Current(); + _current.id = new Ice.Identity(); + _current.adapter = adapter; + _current.con = connection; + _current.requestId = requestId; + + _cookie = new Ice.LocalObjectHolder(); + } + + protected + IncomingBase(IncomingBase in) // Adopts the argument. It must not be used afterwards. + { + // + // We don't change _current as it's exposed by Ice::Request + // + _current = in._current; + + // + // Deep copy + // + if(in._interceptorAsyncCallbackList != null) + { + // + // Copy, not just reference + // + _interceptorAsyncCallbackList = + new java.util.LinkedList<Ice.DispatchInterceptorAsyncCallback>(in._interceptorAsyncCallbackList); + } + + adopt(in); + } + + protected void + adopt(IncomingBase other) + { + _instance = other._instance; + //other._instance = null; // Don't reset _instance. + + _observer = other._observer; + other._observer = null; + + _servant = other._servant; + other._servant = null; + + _locator = other._locator; + other._locator = null; + + _cookie = other._cookie; + other._cookie = null; + + _response = other._response; + other._response = false; + + _compress = other._compress; + other._compress = 0; + + // + // Adopt the stream - it creates less garbage. + // + _os = other._os; + other._os = null; + + _responseHandler = other._responseHandler; + other._responseHandler = null; + } + + public Ice.OutputStream + __startWriteParams(Ice.FormatType format) + { + if(!_response) + { + throw new Ice.MarshalException("can't marshal out parameters for oneway dispatch"); + } + + assert(_os.size() == Protocol.headerSize + 4); // Reply status position. + assert(_current.encoding != null); // Encoding for reply is known. + _os.writeByte((byte)0); + _os.startEncapsulation(_current.encoding, format); + return _os; + } + + public void + __endWriteParams(boolean ok) + { + if(!ok && _observer != null) + { + _observer.userException(); + } + + assert(_response); + + int save = _os.pos(); + _os.pos(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ok ? ReplyStatus.replyOK : ReplyStatus.replyUserException); + _os.pos(save); + _os.endEncapsulation(); + } + + public void + __writeEmptyParams() + { + if(_response) + { + assert(_os.size() == Protocol.headerSize + 4); // Reply status position. + assert(_current.encoding != null); // Encoding for reply is known. + _os.writeByte(ReplyStatus.replyOK); + _os.writeEmptyEncapsulation(_current.encoding); + } + } + + public void + __writeParamEncaps(byte[] v, boolean ok) + { + if(!ok && _observer != null) + { + _observer.userException(); + } + + if(_response) + { + assert(_os.size() == Protocol.headerSize + 4); // Reply status position. + assert(_current.encoding != null); // Encoding for reply is known. + _os.writeByte(ok ? ReplyStatus.replyOK : ReplyStatus.replyUserException); + if(v == null || v.length == 0) + { + _os.writeEmptyEncapsulation(_current.encoding); + } + else + { + _os.writeEncapsulation(v); + } + } + } + + public void + __writeUserException(Ice.UserException ex, Ice.FormatType format) + { + Ice.OutputStream __os = __startWriteParams(format); + __os.writeException(ex); + __endWriteParams(false); + } + + // + // These functions allow this object to be reused, rather than reallocated. + // + public void + reset(Instance instance, ResponseHandler handler, Ice.ConnectionI connection, Ice.ObjectAdapter adapter, + boolean response, byte compress, int requestId) + { + _instance = instance; + + // + // Don't recycle the Current object, because servants may keep a reference to it. + // + _current = new Ice.Current(); + _current.id = new Ice.Identity(); + _current.adapter = adapter; + _current.con = connection; + _current.requestId = requestId; + + if(_cookie == null) + { + _cookie = new Ice.LocalObjectHolder(); + } + + _response = response; + + _compress = compress; + + if(_response && _os == null) + { + _os = new Ice.OutputStream(instance, Protocol.currentProtocolEncoding); + } + + _responseHandler = handler; + + _interceptorAsyncCallbackList = null; + } + + public void + reclaim() + { + _servant = null; + + _locator = null; + + if(_cookie != null) + { + _cookie.value = null; + } + + _observer = null; + + if(_os != null) + { + _os.reset(); + } + + _interceptorAsyncCallbackList = null; + } + + final protected void + __warning(java.lang.Exception ex) + { + assert(_instance != null); + + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + IceUtilInternal.OutputBase out = new IceUtilInternal.OutputBase(pw); + out.setUseTab(false); + out.print("dispatch exception:"); + out.print("\nidentity: " + Ice.Util.identityToString(_current.id)); + out.print("\nfacet: " + IceUtilInternal.StringUtil.escapeString(_current.facet, "")); + out.print("\noperation: " + _current.operation); + if(_current.con != null) + { + for(Ice.ConnectionInfo connInfo = _current.con.getInfo(); connInfo != null; connInfo = connInfo.underlying) + { + if(connInfo instanceof Ice.IPConnectionInfo) + { + Ice.IPConnectionInfo ipConnInfo = (Ice.IPConnectionInfo)connInfo; + out.print("\nremote host: " + ipConnInfo.remoteAddress + " remote port: " + ipConnInfo.remotePort); + } + } + } + out.print("\n"); + ex.printStackTrace(pw); + pw.flush(); + _instance.initializationData().logger.warning(sw.toString()); + } + + final protected boolean + __servantLocatorFinished(boolean amd) + { + assert(_locator != null && _servant != null); + try + { + _locator.finished(_current, _servant, _cookie.value); + return true; + } + catch(Ice.UserException ex) + { + assert(_responseHandler != null); + + if(_observer != null) + { + _observer.userException(); + } + + // + // The operation may have already marshaled a reply; we must overwrite that reply. + // + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUserException); + _os.startEncapsulation(_current.encoding, Ice.FormatType.DefaultFormat); + _os.writeException(ex); + _os.endEncapsulation(); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + _responseHandler = null; + } + catch(java.lang.Exception ex) + { + __handleException(ex, amd); + } + catch(java.lang.Error ex) + { + __handleError(ex, amd); // Always throws. + } + return false; + } + + final protected void + __handleException(java.lang.Exception exc, boolean amd) + { + assert(_responseHandler != null); + + try + { + throw exc; + } + catch(Ice.RequestFailedException ex) + { + if(ex.id == null || ex.id.name == null || ex.id.name.isEmpty()) + { + ex.id = _current.id; + } + + if(ex.facet == null || ex.facet.isEmpty()) + { + ex.facet = _current.facet; + } + + if(ex.operation == null || ex.operation.length() == 0) + { + ex.operation = _current.operation; + } + + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + if(ex instanceof Ice.ObjectNotExistException) + { + _os.writeByte(ReplyStatus.replyObjectNotExist); + } + else if(ex instanceof Ice.FacetNotExistException) + { + _os.writeByte(ReplyStatus.replyFacetNotExist); + } + else if(ex instanceof Ice.OperationNotExistException) + { + _os.writeByte(ReplyStatus.replyOperationNotExist); + } + else + { + assert(false); + } + ex.id.__write(_os); + + // + // For compatibility with the old FacetPath. + // + if(ex.facet == null || ex.facet.length() == 0) + { + _os.writeStringSeq(null); + } + else + { + String[] facetPath2 = { ex.facet }; + _os.writeStringSeq(facetPath2); + } + + _os.writeString(ex.operation); + + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + catch(Ice.UnknownLocalException ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownLocalException); + _os.writeString(ex.unknown); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + catch(Ice.UnknownUserException ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownUserException); + _os.writeString(ex.unknown); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + catch(Ice.UnknownException ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownException); + _os.writeString(ex.unknown); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + catch(Ice.Exception ex) + { + if(ex instanceof Ice.SystemException) + { + if(_responseHandler.systemException(_current.requestId, (Ice.SystemException)ex, amd)) + { + return; + } + } + + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownLocalException); + //_os.writeString(ex.toString()); + java.io.StringWriter sw = new java.io.StringWriter(); + sw.write(ex.ice_id() + "\n"); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _os.writeString(sw.toString()); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + catch(Ice.UserException ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownUserException); + //_os.writeString(ex.toString()); + java.io.StringWriter sw = new java.io.StringWriter(); + sw.write(ex.ice_id() + "\n"); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _os.writeString(sw.toString()); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + catch(java.lang.Exception ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(ex); + } + + if(_observer != null) + { + _observer.failed(ex.getClass().getName()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownException); + //_os.writeString(ex.toString()); + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _os.writeString(sw.toString()); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + _responseHandler = null; + } + + final protected void + __handleError(java.lang.Error exc, boolean amd) + { + assert(_responseHandler != null); + + Ice.UnknownException uex = new Ice.UnknownException(exc); + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + exc.printStackTrace(pw); + pw.flush(); + uex.unknown = sw.toString(); + + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 0) + { + __warning(uex); + } + + if(_observer != null) + { + _observer.failed(uex.ice_id()); + } + + if(_response) + { + _os.resize(Protocol.headerSize + 4); // Reply status position. + _os.writeByte(ReplyStatus.replyUnknownException); + _os.writeString(uex.unknown); + if(_observer != null) + { + _observer.reply(_os.size() - Protocol.headerSize - 4); + } + _responseHandler.sendResponse(_current.requestId, _os, _compress, amd); + } + else + { + _responseHandler.sendNoResponse(); + } + + if(_observer != null) + { + _observer.detach(); + _observer = null; + } + _responseHandler = null; + + throw new ServantError(exc); + } + + protected Instance _instance; + protected Ice.Current _current; + protected Ice.Object _servant; + protected Ice.ServantLocator _locator; + protected Ice.LocalObjectHolder _cookie; + protected Ice.Instrumentation.DispatchObserver _observer; + + protected boolean _response; + protected byte _compress; + + protected Ice.OutputStream _os; + + protected ResponseHandler _responseHandler; + + protected java.util.LinkedList<Ice.DispatchInterceptorAsyncCallback> _interceptorAsyncCallbackList; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java new file mode 100644 index 00000000000..2a6b69935a3 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/IncomingConnectionFactory.java @@ -0,0 +1,658 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class IncomingConnectionFactory extends EventHandler implements Ice.ConnectionI.StartCallback +{ + public synchronized void + activate() + { + setState(StateActive); + } + + public synchronized void + hold() + { + setState(StateHolding); + } + + public synchronized void + destroy() + { + setState(StateClosed); + } + + public synchronized void + updateConnectionObservers() + { + for(Ice.ConnectionI connection : _connections) + { + connection.updateObserver(); + } + } + + public void + waitUntilHolding() + throws InterruptedException + { + java.util.LinkedList<Ice.ConnectionI> connections; + + synchronized(this) + { + // + // First we wait until the connection factory itself is in holding + // state. + // + while(_state < StateHolding) + { + wait(); + } + + // + // We want to wait until all connections are in holding state + // outside the thread synchronization. + // + connections = new java.util.LinkedList<Ice.ConnectionI>(_connections); + } + + // + // Now we wait until each connection is in holding state. + // + for(Ice.ConnectionI connection : connections) + { + connection.waitUntilHolding(); + } + } + + public void + waitUntilFinished() + throws InterruptedException + { + java.util.LinkedList<Ice.ConnectionI> connections = null; + + synchronized(this) + { + // + // First we wait until the factory is destroyed. If we are using + // an acceptor, we also wait for it to be closed. + // + while(_state != StateFinished) + { + wait(); + } + + // + // Clear the OA. See bug 1673 for the details of why this is necessary. + // + _adapter = null; + + // + // We want to wait until all connections are finished outside the + // thread synchronization. + // + connections = new java.util.LinkedList<Ice.ConnectionI>(_connections); + } + + if(connections != null) + { + for(Ice.ConnectionI connection : connections) + { + try + { + connection.waitUntilFinished(); + } + catch(InterruptedException e) + { + // + // Force close all of the connections. + // + for(Ice.ConnectionI c : connections) + { + c.close(true); + } + throw e; + } + } + } + + synchronized(this) + { + if(_transceiver != null) + { + assert(_connections.size() <= 1); // The connection isn't monitored or reaped. + } + else + { + // Ensure all the connections are finished and reapable at this point. + java.util.List<Ice.ConnectionI> cons = _monitor.swapReapedConnections(); + assert((cons == null ? 0 : cons.size()) == _connections.size()); + if(cons != null) + { + cons.clear(); + } + } + _connections.clear(); + _monitor.destroy(); + } + } + + public EndpointI + endpoint() + { + // No mutex protection necessary, _endpoint is immutable. + return _endpoint; + } + + public synchronized java.util.LinkedList<Ice.ConnectionI> + connections() + { + java.util.LinkedList<Ice.ConnectionI> connections = new java.util.LinkedList<Ice.ConnectionI>(); + + // + // Only copy connections which have not been destroyed. + // + for(Ice.ConnectionI connection : _connections) + { + if(connection.isActiveOrHolding()) + { + connections.add(connection); + } + } + + return connections; + } + + public void + flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) + { + for(Ice.ConnectionI c : connections()) // connections() is synchronized, no need to synchronize here. + { + try + { + outAsync.flushConnection(c); + } + catch(Ice.LocalException ex) + { + // Ignore. + } + } + } + + // + // Operations from EventHandler. + // + + @Override + public void + message(ThreadPoolCurrent current) + { + Ice.ConnectionI connection = null; + synchronized(this) + { + if(_state >= StateClosed) + { + return; + } + else if(_state == StateHolding) + { + Thread.yield(); + return; + } + + // + // Reap closed connections. + // + java.util.List<Ice.ConnectionI> cons = _monitor.swapReapedConnections(); + if(cons != null) + { + for(Ice.ConnectionI c : cons) + { + _connections.remove(c); + } + } + + // + // Now accept a new connection. + // + Transceiver transceiver = null; + try + { + transceiver = _acceptor.accept(); + + if(_instance.traceLevels().network >= 2) + { + StringBuffer s = new StringBuffer("trying to accept "); + s.append(_endpoint.protocol()); + s.append(" connection\n"); + s.append(transceiver.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + } + catch(Ice.SocketException ex) + { + if(Network.noMoreFds(ex.getCause())) + { + try + { + String s = "fatal error: can't accept more connections:\n" + ex.getCause().getMessage(); + s += '\n' + _acceptor.toString(); + _instance.initializationData().logger.error(s); + } + finally + { + Runtime.getRuntime().halt(1); + } + } + + // Ignore socket exceptions. + return; + } + catch(Ice.LocalException ex) + { + // Warn about other Ice local exceptions. + if(_warn) + { + warning(ex); + } + return; + } + + assert(transceiver != null); + + try + { + connection = new Ice.ConnectionI(_adapter.getCommunicator(), _instance, _monitor, transceiver, null, + _endpoint, _adapter); + } + catch(Ice.LocalException ex) + { + try + { + transceiver.close(); + } + catch(Ice.LocalException exc) + { + // Ignore + } + + if(_warn) + { + warning(ex); + } + return; + } + + _connections.add(connection); + } + + assert(connection != null); + connection.start(this); + } + + @Override + public synchronized void + finished(ThreadPoolCurrent current, boolean close) + { + assert(_state == StateClosed); + setState(StateFinished); + + if(close) + { + closeAcceptor(); + } + } + + @Override + public synchronized String + toString() + { + if(_transceiver != null) + { + return _transceiver.toString(); + } + return _acceptor.toString(); + } + + @Override + public java.nio.channels.SelectableChannel + fd() + { + assert(_acceptor != null); + return _acceptor.fd(); + } + + @Override + public void setReadyCallback(ReadyCallback readyCallback) + { + if(_acceptor != null) + { + _acceptor.setReadyCallback(readyCallback); + } + } + + // + // Operations from ConnectionI.StartCallback + // + @Override + public synchronized void + connectionStartCompleted(Ice.ConnectionI connection) + { + // + // Initially, connections are in the holding state. If the factory is active + // we activate the connection. + // + if(_state == StateActive) + { + connection.activate(); + } + } + + @Override + public synchronized void + connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex) + { + if(_state >= StateClosed) + { + return; + } + // + // Do not warn about connection exceptions here. The connection is not yet validated. + // + } + + public + IncomingConnectionFactory(Instance instance, EndpointI endpoint, Ice.ObjectAdapterI adapter) + { + _instance = instance; + _endpoint = endpoint; + _adapter = adapter; + _warn = _instance.initializationData().properties.getPropertyAsInt("Ice.Warn.Connections") > 0 ? true : false; + _state = StateHolding; + _monitor = new FactoryACMMonitor(instance, adapter.getACM()); + + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideTimeout) + { + _endpoint = _endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue); + } + + if(defaultsAndOverrides.overrideCompress) + { + _endpoint = _endpoint.compress(defaultsAndOverrides.overrideCompressValue); + } + + try + { + _transceiver = _endpoint.transceiver(); + if(_transceiver != null) + { + if(_instance.traceLevels().network >= 2) + { + StringBuffer s = new StringBuffer("attempting to bind to "); + s.append(_endpoint.protocol()); + s.append(" socket\n"); + s.append(_transceiver.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + _endpoint = _transceiver.bind(); + + Ice.ConnectionI connection = + new Ice.ConnectionI(_adapter.getCommunicator(), _instance, null, _transceiver, null, _endpoint, + _adapter); + connection.startAndWait(); + + _connections.add(connection); + } + else + { + createAcceptor(); + } + } + catch(java.lang.Exception ex) + { + // + // Clean up for finalizer. + // + if(_transceiver != null) + { + try + { + _transceiver.close(); + } + catch(Ice.LocalException e) + { + // Here we ignore any exceptions in close(). + } + } + + _state = StateFinished; + _monitor.destroy(); + _connections.clear(); + + if(ex instanceof Ice.LocalException) + { + throw (Ice.LocalException)ex; + } + else if(ex instanceof InterruptedException) + { + throw new Ice.OperationInterruptedException(); + } + else + { + throw new Ice.SyscallException(ex); + } + } + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_state == StateFinished); + IceUtilInternal.Assert.FinalizerAssert(_connections.isEmpty()); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private static final int StateActive = 0; + private static final int StateHolding = 1; + private static final int StateClosed = 2; + private static final int StateFinished = 3; + + private void + setState(int state) + { + if(_state == state) // Don't switch twice. + { + return; + } + + switch(state) + { + case StateActive: + { + if(_state != StateHolding) // Can only switch from holding to active. + { + return; + } + if(_acceptor != null) + { + if(_instance.traceLevels().network >= 1) + { + StringBuffer s = new StringBuffer("accepting "); + s.append(_endpoint.protocol()); + s.append(" connections at "); + s.append(_acceptor.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + _adapter.getThreadPool().register(this, SocketOperation.Read); + } + + for(Ice.ConnectionI connection : _connections) + { + connection.activate(); + } + break; + } + + case StateHolding: + { + if(_state != StateActive) // Can only switch from active to holding. + { + return; + } + if(_acceptor != null) + { + if(_instance.traceLevels().network >= 1) + { + StringBuffer s = new StringBuffer("holding "); + s.append(_endpoint.protocol()); + s.append(" connections at "); + s.append(_acceptor.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + _adapter.getThreadPool().unregister(this, SocketOperation.Read); + } + + for(Ice.ConnectionI connection : _connections) + { + connection.hold(); + } + break; + } + + case StateClosed: + { + if(_acceptor != null) + { + // + // If possible, close the acceptor now to prevent new connections from + // being accepted while we are deactivating. This is especially useful + // if there are no more threads in the thread pool available to dispatch + // the finish() call. + // + if(_adapter.getThreadPool().finish(this, true)) + { + closeAcceptor(); + } + } + else + { + state = StateFinished; + } + + for(Ice.ConnectionI connection : _connections) + { + connection.destroy(Ice.ConnectionI.ObjectAdapterDeactivated); + } + break; + } + + case StateFinished: + { + assert(_state == StateClosed); + break; + } + } + + _state = state; + notifyAll(); + } + + private void + createAcceptor() + { + try + { + _acceptor = _endpoint.acceptor(_adapter.getName()); + assert(_acceptor != null); + + if(_instance.traceLevels().network >= 2) + { + StringBuffer s = new StringBuffer("attempting to bind to "); + s.append(_endpoint.protocol()); + s.append(" socket "); + s.append(_acceptor.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + + _endpoint = _acceptor.listen(); + + if(_instance.traceLevels().network >= 1) + { + StringBuffer s = new StringBuffer("listening for "); + s.append(_endpoint.protocol()); + s.append(" connections\n"); + s.append(_acceptor.toDetailedString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + + _adapter.getThreadPool().initialize(this); + + if(_state == StateActive) + { + _adapter.getThreadPool().register(this, SocketOperation.Read); + } + } + catch(Exception ex) + { + if(_acceptor != null) + { + _acceptor.close(); + } + throw ex; + } + } + + private void + closeAcceptor() + { + if(_instance.traceLevels().network >= 1) + { + StringBuffer s = new StringBuffer("stopping to accept "); + s.append(_endpoint.protocol()); + s.append(" connections at "); + s.append(_acceptor.toString()); + _instance.initializationData().logger.trace(_instance.traceLevels().networkCat, s.toString()); + } + _acceptor.close(); + } + + private void + warning(Ice.LocalException ex) + { + String s = "connection exception:\n" + Ex.toString(ex) + '\n' + _acceptor.toString(); + _instance.initializationData().logger.warning(s); + } + + private final Instance _instance; + private final FactoryACMMonitor _monitor; + + private Acceptor _acceptor; + private Transceiver _transceiver; + private EndpointI _endpoint; + + private Ice.ObjectAdapterI _adapter; + + private final boolean _warn; + + private java.util.Set<Ice.ConnectionI> _connections = new java.util.HashSet<Ice.ConnectionI>(); + + private int _state; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/InputStreamWrapper.java b/java-compat/src/Ice/src/main/java/IceInternal/InputStreamWrapper.java new file mode 100644 index 00000000000..8359235b692 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/InputStreamWrapper.java @@ -0,0 +1,96 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// Class to provide a java.io.InputStream on top of a ByteBuffer. +// We use this to deserialize arbitrary Java serializable classes from +// a Slice byte sequence. This class is a wrapper around a Buffer +// that passes all methods through. +// + +public class InputStreamWrapper extends java.io.InputStream +{ + public InputStreamWrapper(int size, java.nio.ByteBuffer buf) + { + _buf = buf; + _markPos = 0; + } + + @Override + public int read() + throws java.io.IOException + { + try + { + return _buf.get(); + } + catch(java.lang.Exception ex) + { + throw new java.io.IOException(ex.toString()); + } + } + + @Override + public int read(byte[] b) + throws java.io.IOException + { + return read(b, 0, b.length); + } + + @Override + public int read(byte[] b, int offset, int count) + throws java.io.IOException + { + try + { + _buf.get(b, offset, count); + } + catch(java.lang.Exception ex) + { + throw new java.io.IOException(ex.toString()); + } + return count; + } + + @Override + public int available() + { + return _buf.remaining(); + } + + @Override + public void mark(int readlimit) + { + _markPos = _buf.position(); + } + + @Override + public void reset() + throws java.io.IOException + { + _buf.position(_markPos); + } + + @Override + public boolean markSupported() + { + return true; + } + + @Override + public void close() + throws java.io.IOException + { + } + + private java.nio.ByteBuffer _buf; + private int _markPos; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Instance.java b/java-compat/src/Ice/src/main/java/IceInternal/Instance.java new file mode 100644 index 00000000000..30b78609ca8 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Instance.java @@ -0,0 +1,1863 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.TimeUnit; + +public final class Instance implements Ice.ClassResolver +{ + static private class ThreadObserverHelper + { + ThreadObserverHelper(String threadName) + { + _threadName = threadName; + } + + synchronized public void updateObserver(Ice.Instrumentation.CommunicatorObserver obsv) + { + assert(obsv != null); + + _observer = obsv.getThreadObserver("Communicator", + _threadName, + Ice.Instrumentation.ThreadState.ThreadStateIdle, + _observer); + if(_observer != null) + { + _observer.attach(); + } + } + + protected void beforeExecute() + { + _threadObserver = _observer; + if(_threadObserver != null) + { + _threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle, + Ice.Instrumentation.ThreadState.ThreadStateInUseForOther); + } + } + + protected void afterExecute() + { + if(_threadObserver != null) + { + _threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther, + Ice.Instrumentation.ThreadState.ThreadStateIdle); + _threadObserver = null; + } + } + + final private String _threadName; + // + // We use a volatile to avoid synchronization when reading + // _observer. Reference assignement is atomic in Java so it + // also doesn't need to be synchronized. + // + private volatile Ice.Instrumentation.ThreadObserver _observer; + private Ice.Instrumentation.ThreadObserver _threadObserver; + } + + static private class Timer extends java.util.concurrent.ScheduledThreadPoolExecutor + { + Timer(Ice.Properties props, String threadName) + { + super(1, Util.createThreadFactory(props, threadName)); // Single thread executor + if(!Util.isAndroid()) + { + // This API doesn't exist on Android up to API level 20. + setRemoveOnCancelPolicy(true); + } + setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + _observerHelper = new ThreadObserverHelper(threadName); + } + + public void updateObserver(Ice.Instrumentation.CommunicatorObserver obsv) + { + _observerHelper.updateObserver(obsv); + } + + @Override + protected void beforeExecute(Thread t, Runnable r) + { + _observerHelper.beforeExecute(); + } + + @Override + protected void afterExecute(Runnable t, Throwable e) + { + _observerHelper.afterExecute(); + } + + private final ThreadObserverHelper _observerHelper; + } + + static private class QueueExecutor extends java.util.concurrent.ThreadPoolExecutor + { + QueueExecutor(Ice.Properties props, String threadName) + { + super(1, 1, 0, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue<Runnable>(), + Util.createThreadFactory(props, threadName)); + _observerHelper = new ThreadObserverHelper(threadName); + } + + public void updateObserver(Ice.Instrumentation.CommunicatorObserver obsv) + { + _observerHelper.updateObserver(obsv); + } + + @Override + protected void beforeExecute(Thread t, Runnable r) + { + _observerHelper.beforeExecute(); + } + + @Override + protected void afterExecute(Runnable t, Throwable e) + { + _observerHelper.afterExecute(); + } + + public void destroy() + throws InterruptedException + { + shutdown(); + while(!isTerminated()) + { + // A very long time. + awaitTermination(100000, java.util.concurrent.TimeUnit.SECONDS); + } + } + + private final ThreadObserverHelper _observerHelper; + } + + private class ObserverUpdaterI implements Ice.Instrumentation.ObserverUpdater + { + @Override + public void + updateConnectionObservers() + { + Instance.this.updateConnectionObservers(); + } + + @Override + public void + updateThreadObservers() + { + Instance.this.updateThreadObservers(); + } + } + + public Ice.InitializationData + initializationData() + { + // + // No check for destruction. It must be possible to access the + // initialization data after destruction. + // + // No mutex lock, immutable. + // + return _initData; + } + + public TraceLevels + traceLevels() + { + // No mutex lock, immutable. + assert(_traceLevels != null); + return _traceLevels; + } + + public DefaultsAndOverrides + defaultsAndOverrides() + { + // No mutex lock, immutable. + assert(_defaultsAndOverrides != null); + return _defaultsAndOverrides; + } + + public synchronized RouterManager + routerManager() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_routerManager != null); + return _routerManager; + } + + public synchronized LocatorManager + locatorManager() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_locatorManager != null); + return _locatorManager; + } + + public synchronized ReferenceFactory + referenceFactory() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_referenceFactory != null); + return _referenceFactory; + } + + public synchronized RequestHandlerFactory + requestHandlerFactory() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_requestHandlerFactory != null); + return _requestHandlerFactory; + } + + public synchronized ProxyFactory + proxyFactory() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_proxyFactory != null); + return _proxyFactory; + } + + public synchronized OutgoingConnectionFactory + outgoingConnectionFactory() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_outgoingConnectionFactory != null); + return _outgoingConnectionFactory; + } + + public synchronized ObjectAdapterFactory + objectAdapterFactory() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_objectAdapterFactory != null); + return _objectAdapterFactory; + } + + public int + protocolSupport() + { + return _protocolSupport; + } + + public boolean + preferIPv6() + { + return _preferIPv6; + } + + public NetworkProxy + networkProxy() + { + return _networkProxy; + } + + public synchronized ThreadPool + clientThreadPool() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_clientThreadPool != null); + return _clientThreadPool; + } + + public synchronized ThreadPool + serverThreadPool() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + if(_serverThreadPool == null) // Lazy initialization. + { + if(_state == StateDestroyInProgress) + { + throw new Ice.CommunicatorDestroyedException(); + } + + int timeout = _initData.properties.getPropertyAsInt("Ice.ServerIdleTime"); + _serverThreadPool = new ThreadPool(this, "Ice.ThreadPool.Server", timeout); + } + + return _serverThreadPool; + } + + public synchronized EndpointHostResolver + endpointHostResolver() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_endpointHostResolver != null); + return _endpointHostResolver; + } + + synchronized public RetryQueue + retryQueue() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_retryQueue != null); + return _retryQueue; + } + + synchronized public java.util.concurrent.ScheduledExecutorService + timer() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_timer != null); + return _timer; + } + + public synchronized EndpointFactoryManager + endpointFactoryManager() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_endpointFactoryManager != null); + return _endpointFactoryManager; + } + + public synchronized Ice.PluginManager + pluginManager() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(_pluginManager != null); + return _pluginManager; + } + + public int + messageSizeMax() + { + // No mutex lock, immutable. + return _messageSizeMax; + } + + public int + batchAutoFlushSize() + { + // No mutex lock, immutable. + return _batchAutoFlushSize; + } + + public int + cacheMessageBuffers() + { + // No mutex lock, immutable. + return _cacheMessageBuffers; + } + + public ACMConfig + clientACM() + { + // No mutex lock, immutable. + return _clientACM; + } + + public ACMConfig + serverACM() + { + // No mutex lock, immutable. + return _serverACM; + } + + public Ice.ImplicitContextI + getImplicitContext() + { + return _implicitContext; + } + + public synchronized Ice.ObjectPrx + createAdmin(Ice.ObjectAdapter adminAdapter, Ice.Identity adminIdentity) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + boolean createAdapter = (adminAdapter == null); + + synchronized(this) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + if(adminIdentity == null || adminIdentity.name == null || adminIdentity.name.isEmpty()) + { + throw new Ice.IllegalIdentityException(adminIdentity); + } + + if(_adminAdapter != null) + { + throw new Ice.InitializationException("Admin already created"); + } + + if(!_adminEnabled) + { + throw new Ice.InitializationException("Admin is disabled"); + } + + if(createAdapter) + { + if(!_initData.properties.getProperty("Ice.Admin.Endpoints").isEmpty()) + { + adminAdapter = _objectAdapterFactory.createObjectAdapter("Ice.Admin", null); + } + else + { + throw new Ice.InitializationException("Ice.Admin.Endpoints is not set"); + } + } + + _adminIdentity = adminIdentity; + _adminAdapter = adminAdapter; + addAllAdminFacets(); + } + + if(createAdapter) + { + try + { + adminAdapter.activate(); + } + catch(Ice.LocalException ex) + { + // + // We cleanup _adminAdapter, however this error is not recoverable + // (can't call again getAdmin() after fixing the problem) + // since all the facets (servants) in the adapter are lost + // + adminAdapter.destroy(); + synchronized(this) + { + _adminAdapter = null; + } + throw ex; + } + } + setServerProcessProxy(adminAdapter, adminIdentity); + return adminAdapter.createProxy(adminIdentity); + } + + public Ice.ObjectPrx + getAdmin() + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + Ice.ObjectAdapter adminAdapter; + Ice.Identity adminIdentity; + + synchronized(this) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + if(_adminAdapter != null) + { + return _adminAdapter.createProxy(_adminIdentity); + } + else if(_adminEnabled) + { + if(!_initData.properties.getProperty("Ice.Admin.Endpoints").isEmpty()) + { + adminAdapter = _objectAdapterFactory.createObjectAdapter("Ice.Admin", null); + } + else + { + return null; + } + adminIdentity = new Ice.Identity("admin", _initData.properties.getProperty("Ice.Admin.InstanceName")); + if(adminIdentity.category.isEmpty()) + { + adminIdentity.category = java.util.UUID.randomUUID().toString(); + } + + _adminIdentity = adminIdentity; + _adminAdapter = adminAdapter; + addAllAdminFacets(); + // continue below outside synchronization + } + else + { + return null; + } + } + + try + { + adminAdapter.activate(); + } + catch(Ice.LocalException ex) + { + // + // We cleanup _adminAdapter, however this error is not recoverable + // (can't call again getAdmin() after fixing the problem) + // since all the facets (servants) in the adapter are lost + // + adminAdapter.destroy(); + synchronized(this) + { + _adminAdapter = null; + } + throw ex; + } + + setServerProcessProxy(adminAdapter, adminIdentity); + return adminAdapter.createProxy(adminIdentity); + } + + public synchronized void + addAdminFacet(Ice.Object servant, String facet) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + if(_adminAdapter == null || (!_adminFacetFilter.isEmpty() && !_adminFacetFilter.contains(facet))) + { + if(_adminFacets.get(facet) != null) + { + throw new Ice.AlreadyRegisteredException("facet", facet); + } + _adminFacets.put(facet, servant); + } + else + { + _adminAdapter.addFacet(servant, _adminIdentity, facet); + } + } + + public synchronized Ice.Object + removeAdminFacet(String facet) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + Ice.Object result; + + if(_adminAdapter == null || (!_adminFacetFilter.isEmpty() && !_adminFacetFilter.contains(facet))) + { + result = _adminFacets.remove(facet); + if(result == null) + { + throw new Ice.NotRegisteredException("facet", facet); + } + } + else + { + result = _adminAdapter.removeFacet(_adminIdentity, facet); + } + + return result; + } + + public synchronized Ice.Object + findAdminFacet(String facet) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + Ice.Object result = null; + + if(_adminAdapter == null || (!_adminFacetFilter.isEmpty() && !_adminFacetFilter.contains(facet))) + { + result = _adminFacets.get(facet); + } + else + { + result = _adminAdapter.findFacet(_adminIdentity, facet); + } + + return result; + } + + public synchronized java.util.Map<String, Ice.Object> + findAllAdminFacets() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + if(_adminAdapter == null) + { + return new java.util.HashMap<String, Ice.Object>(_adminFacets); + } + else + { + java.util.Map<String, Ice.Object> result = _adminAdapter.findAllFacets(_adminIdentity); + if(!_adminFacets.isEmpty()) + { + // Also returns filtered facets + result.putAll(_adminFacets); + } + return result; + } + } + + public synchronized void + setDefaultLocator(Ice.LocatorPrx locator) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + _referenceFactory = _referenceFactory.setDefaultLocator(locator); + } + + public synchronized void + setDefaultRouter(Ice.RouterPrx router) + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + _referenceFactory = _referenceFactory.setDefaultRouter(router); + } + + public void + setLogger(Ice.Logger logger) + { + // + // No locking, as it can only be called during plug-in loading + // + _initData.logger = logger; + } + + public void + setThreadHook(Ice.ThreadNotification threadHook) + { + // + // No locking, as it can only be called during plug-in loading + // + _initData.threadHook = threadHook; + } + + public Class<?> + findClass(String className) + { + return Util.findClass(className, _initData.classLoader); + } + + public ClassLoader + getClassLoader() + { + return _initData.classLoader; + } + + // + // From Ice.ClassResolver. + // + public Class<?> resolveClass(String typeId) + throws LinkageError + { + Class<?> c = null; + + // + // To convert a Slice type id into a Java class, we do the following: + // + // 1. Convert the Slice type id into a classname (e.g., ::M::X -> M.X). + // 2. If that fails, extract the top-level module (if any) from the type id + // and check for an Package property. If found, prepend the property + // value to the classname. + // 3. If that fails, check for an Default.Package property. If found, + // prepend the property value to the classname. + // + String className; + boolean addClass = false; + + synchronized(this) + { + className = _typeToClassMap.get(typeId); + } + + if(className == null) + { + className = Ice.Util.typeIdToClass(typeId); + addClass = true; + } + + c = getConcreteClass(className); + + if(c == null) + { + int pos = typeId.indexOf(':', 2); + if(pos != -1) + { + String topLevelModule = typeId.substring(2, pos); + String pkg = _initData.properties.getProperty("Ice.Package." + topLevelModule); + if(pkg.length() > 0) + { + c = getConcreteClass(pkg + "." + className); + } + } + } + + if(c == null) + { + String pkg = _initData.properties.getProperty("Ice.Default.Package"); + if(pkg.length() > 0) + { + c = getConcreteClass(pkg + "." + className); + } + } + + if(c != null && addClass) + { + synchronized(this) + { + className = c.getName(); + if(_typeToClassMap.containsKey(typeId)) + { + assert(_typeToClassMap.get(typeId).equals(className)); + } + else + { + _typeToClassMap.put(typeId, className); + } + } + } + + return c; + } + + public String resolveCompactId(int compactId) + { + String className = "IceCompactId.TypeId_" + Integer.toString(compactId); + Class<?> c = getConcreteClass(className); + if(c == null) + { + for(String pkg : _packages) + { + c = getConcreteClass(pkg + "." + className); + if(c != null) + { + break; + } + } + } + if(c != null) + { + try + { + return (String)c.getField("typeId").get(null); + } + catch(Exception ex) + { + assert(false); + } + } + return ""; + } + + public Class<?> getConcreteClass(String className) + throws LinkageError + { + Class<?> c = findClass(className); + + if(c != null) + { + // + // Ensure the class is instantiable. The constants are + // defined in the JVM specification (0x200 = interface, + // 0x400 = abstract). + // + final int modifiers = c.getModifiers(); + if((modifiers & 0x200) == 0 && (modifiers & 0x400) == 0) + { + return c; + } + } + + return null; + } + + public boolean + useApplicationClassLoader() + { + return _useApplicationClassLoader; + } + + public boolean + queueRequests() + { + return _queueExecutorService != null; + } + + synchronized public QueueExecutorService + getQueueExecutor() + { + if(_state == StateDestroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + return _queueExecutorService; + } + + // + // Only for use by Ice.CommunicatorI + // + public + Instance(Ice.Communicator communicator, Ice.InitializationData initData) + { + _state = StateActive; + _initData = initData; + + try + { + if(_initData.properties == null) + { + _initData.properties = Ice.Util.createProperties(); + } + + synchronized(Instance.class) + { + if(!_oneOffDone) + { + String stdOut = _initData.properties.getProperty("Ice.StdOut"); + String stdErr = _initData.properties.getProperty("Ice.StdErr"); + + java.io.PrintStream outStream = null; + + if(stdOut.length() > 0) + { + // + // We need to close the existing stdout for JVM thread dump to go + // to the new file + // + System.out.close(); + + try + { + outStream = new java.io.PrintStream(new java.io.FileOutputStream(stdOut, true)); + } + catch(java.io.FileNotFoundException ex) + { + throw new Ice.FileException(0, stdOut, ex); + } + + System.setOut(outStream); + } + if(stdErr.length() > 0) + { + // + // close for consistency with stdout + // + System.err.close(); + + if(stdErr.equals(stdOut)) + { + System.setErr(outStream); + } + else + { + try + { + System.setErr(new java.io.PrintStream(new java.io.FileOutputStream(stdErr, true))); + } + catch(java.io.FileNotFoundException ex) + { + throw new Ice.FileException(0, stdErr, ex); + } + + } + } + _oneOffDone = true; + } + } + + if(_initData.logger == null) + { + String logfile = _initData.properties.getProperty("Ice.LogFile"); + if(_initData.properties.getPropertyAsInt("Ice.UseSyslog") > 0 && + !System.getProperty("os.name").startsWith("Windows")) + { + if(logfile.length() != 0) + { + throw new Ice.InitializationException("Both syslog and file logger cannot be enabled."); + } + _initData.logger = new Ice.SysLoggerI(_initData.properties.getProperty("Ice.ProgramName"), + _initData.properties.getPropertyWithDefault("Ice.SyslogFacility", "LOG_USER")); + } + else if(logfile.length() != 0) + { + _initData.logger = new Ice.LoggerI(_initData.properties.getProperty("Ice.ProgramName"), logfile); + } + else + { + _initData.logger = Ice.Util.getProcessLogger(); + } + } + + _packages = validatePackages(); + + _useApplicationClassLoader = _initData.properties.getPropertyAsInt("Ice.UseApplicationClassLoader") > 0; + + _traceLevels = new TraceLevels(_initData.properties); + + _defaultsAndOverrides = new DefaultsAndOverrides(_initData.properties, _initData.logger); + + _clientACM = new ACMConfig(_initData.properties, + _initData.logger, + "Ice.ACM.Client", + new ACMConfig(_initData.properties, _initData.logger, "Ice.ACM", + new ACMConfig(false))); + + _serverACM = new ACMConfig(_initData.properties, + _initData.logger, + "Ice.ACM.Server", + new ACMConfig(_initData.properties, _initData.logger, "Ice.ACM", + new ACMConfig(true))); + + { + final int defaultMessageSizeMax = 1024; + int num = _initData.properties.getPropertyAsIntWithDefault("Ice.MessageSizeMax", defaultMessageSizeMax); + if(num < 1 || num > 0x7fffffff / 1024) + { + _messageSizeMax = 0x7fffffff; + } + else + { + _messageSizeMax = num * 1024; // Property is in kilobytes, _messageSizeMax in bytes + } + } + + if(_initData.properties.getProperty("Ice.BatchAutoFlushSize").isEmpty() && + !_initData.properties.getProperty("Ice.BatchAutoFlush").isEmpty()) + { + if(_initData.properties.getPropertyAsInt("Ice.BatchAutoFlush") > 0) + { + _batchAutoFlushSize = _messageSizeMax; + } + else + { + _batchAutoFlushSize = 0; + } + } + else + { + int num = _initData.properties.getPropertyAsIntWithDefault("Ice.BatchAutoFlushSize", 1024); // 1MB + if(num < 1) + { + _batchAutoFlushSize = num; + } + else if(num > 0x7fffffff / 1024) + { + _batchAutoFlushSize = 0x7fffffff; + } + else + { + _batchAutoFlushSize = num * 1024; // Property is in kilobytes, _batchAutoFlushSize in bytes + } + } + + _implicitContext = Ice.ImplicitContextI.create(_initData.properties.getProperty("Ice.ImplicitContext")); + + _routerManager = new RouterManager(); + + _locatorManager = new LocatorManager(_initData.properties); + + _referenceFactory = new ReferenceFactory(this, communicator); + + _requestHandlerFactory = new RequestHandlerFactory(this); + + _proxyFactory = new ProxyFactory(this); + + boolean isIPv6Supported = Network.isIPv6Supported(); + boolean ipv4 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0; + boolean ipv6 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv6", isIPv6Supported ? 1 : 0) > 0; + if(!ipv4 && !ipv6) + { + throw new Ice.InitializationException("Both IPV4 and IPv6 support cannot be disabled."); + } + else if(ipv4 && ipv6) + { + _protocolSupport = Network.EnableBoth; + } + else if(ipv4) + { + _protocolSupport = Network.EnableIPv4; + } + else + { + _protocolSupport = Network.EnableIPv6; + } + _preferIPv6 = _initData.properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0; + + _networkProxy = createNetworkProxy(_initData.properties, _protocolSupport); + + _endpointFactoryManager = new EndpointFactoryManager(this); + + ProtocolInstance tcpProtocolInstance = new ProtocolInstance(this, Ice.TCPEndpointType.value, "tcp", false); + _endpointFactoryManager.add(new TcpEndpointFactory(tcpProtocolInstance)); + + ProtocolInstance udpProtocolInstance = new ProtocolInstance(this, Ice.UDPEndpointType.value, "udp", false); + _endpointFactoryManager.add(new UdpEndpointFactory(udpProtocolInstance)); + + _pluginManager = new Ice.PluginManagerI(communicator, this); + + if(_initData.valueFactoryManager == null) + { + _initData.valueFactoryManager = new ValueFactoryManagerI(); + } + + _outgoingConnectionFactory = new OutgoingConnectionFactory(communicator, this); + + _objectAdapterFactory = new ObjectAdapterFactory(this, communicator); + + _retryQueue = new RetryQueue(this); + + // + // If Ice.ThreadInterruptSafe is set or we're running on Android all + // IO is done on the background thread. For Android we use the queue + // executor as Android doesn't allow any network invocations on the main + // thread even if the call is non-blocking. + // + if(_initData.properties.getPropertyAsInt("Ice.ThreadInterruptSafe") > 0 || Util.isAndroid()) + { + _queueExecutor = new QueueExecutor(_initData.properties, + Util.createThreadName(_initData.properties, "Ice.BackgroundIO")); + _queueExecutorService = new QueueExecutorService(_queueExecutor); + + // Caching message buffers is not supported with background IO. + _cacheMessageBuffers = 0; + } + else + { + _cacheMessageBuffers = _initData.properties.getPropertyAsIntWithDefault("Ice.CacheMessageBuffers", 2); + } + } + catch(Ice.LocalException ex) + { + destroy(); + throw ex; + } + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_state == StateDestroyed); + IceUtilInternal.Assert.FinalizerAssert(_referenceFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_requestHandlerFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_proxyFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_outgoingConnectionFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_objectAdapterFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_clientThreadPool == null); + IceUtilInternal.Assert.FinalizerAssert(_serverThreadPool == null); + IceUtilInternal.Assert.FinalizerAssert(_endpointHostResolver == null); + IceUtilInternal.Assert.FinalizerAssert(_timer == null); + IceUtilInternal.Assert.FinalizerAssert(_routerManager == null); + IceUtilInternal.Assert.FinalizerAssert(_locatorManager == null); + IceUtilInternal.Assert.FinalizerAssert(_endpointFactoryManager == null); + IceUtilInternal.Assert.FinalizerAssert(_pluginManager == null); + IceUtilInternal.Assert.FinalizerAssert(_retryQueue == null); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + public void + finishSetup(Ice.StringSeqHolder args, Ice.Communicator communicator) + { + // + // Load plug-ins. + // + assert(_serverThreadPool == null); + Ice.PluginManagerI pluginManagerImpl = (Ice.PluginManagerI)_pluginManager; + pluginManagerImpl.loadPlugins(args); + + // + // Add WS and WSS endpoint factories if TCP/SSL factories are installed. + // + final EndpointFactory tcpFactory = _endpointFactoryManager.get(Ice.TCPEndpointType.value); + if(tcpFactory != null) + { + final ProtocolInstance instance = new ProtocolInstance(this, Ice.WSEndpointType.value, "ws", false); + _endpointFactoryManager.add(new WSEndpointFactory(instance, tcpFactory.clone(instance, null))); + } + final EndpointFactory sslFactory = _endpointFactoryManager.get(Ice.SSLEndpointType.value); + if(sslFactory != null) + { + final ProtocolInstance instance = new ProtocolInstance(this, Ice.WSSEndpointType.value, "wss", true); + _endpointFactoryManager.add(new WSEndpointFactory(instance, sslFactory.clone(instance, null))); + } + + // + // Create Admin facets, if enabled. + // + // Note that any logger-dependent admin facet must be created after we load all plugins, + // since one of these plugins can be a Logger plugin that sets a new logger during loading + // + + if(_initData.properties.getProperty("Ice.Admin.Enabled").isEmpty()) + { + _adminEnabled = !_initData.properties.getProperty("Ice.Admin.Endpoints").isEmpty(); + } + else + { + _adminEnabled = _initData.properties.getPropertyAsInt("Ice.Admin.Enabled") > 0; + } + + String[] facetFilter = _initData.properties.getPropertyAsList("Ice.Admin.Facets"); + if(facetFilter.length > 0) + { + _adminFacetFilter.addAll(java.util.Arrays.asList(facetFilter)); + } + + if(_adminEnabled) + { + // + // Process facet + // + String processFacetName = "Process"; + if(_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(processFacetName)) + { + _adminFacets.put(processFacetName, new ProcessI(communicator)); + } + + // + // Logger facet + // + String loggerFacetName = "Logger"; + if(_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(loggerFacetName)) + { + LoggerAdminLogger logger = new LoggerAdminLoggerI(_initData.properties, _initData.logger); + setLogger(logger); + _adminFacets.put(loggerFacetName, logger.getFacet()); + } + + // + // Properties facet + // + String propertiesFacetName = "Properties"; + PropertiesAdminI propsAdmin = null; + if(_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(propertiesFacetName)) + { + propsAdmin = new PropertiesAdminI(this); + _adminFacets.put(propertiesFacetName, propsAdmin); + } + + // + // Metrics facet + // + String metricsFacetName = "Metrics"; + if(_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(metricsFacetName)) + { + CommunicatorObserverI observer = new CommunicatorObserverI(_initData); + _initData.observer = observer; + _adminFacets.put(metricsFacetName, observer.getFacet()); + + // + // Make sure the admin plugin receives property updates. + // + if(propsAdmin != null) + { + propsAdmin.addUpdateCallback(observer.getFacet()); + } + } + } + + // + // Set observer updater + // + if(_initData.observer != null) + { + _initData.observer.setObserverUpdater(new ObserverUpdaterI()); + } + + // + // Create threads. + // + try + { + _timer = new Timer(_initData.properties, Util.createThreadName(_initData.properties, "Ice.Timer")); + } + catch(RuntimeException ex) + { + String s = "cannot create thread for timer:\n" + Ex.toString(ex); + _initData.logger.error(s); + throw ex; + } + + try + { + _endpointHostResolver = new EndpointHostResolver(this); + } + catch(RuntimeException ex) + { + String s = "cannot create thread for endpoint host resolver:\n" + Ex.toString(ex); + _initData.logger.error(s); + throw ex; + } + + _clientThreadPool = new ThreadPool(this, "Ice.ThreadPool.Client", 0); + + // + // The default router/locator may have been set during the loading of plugins. + // Therefore we make sure it is not already set before checking the property. + // + if(_referenceFactory.getDefaultRouter() == null) + { + Ice.RouterPrx router = + Ice.RouterPrxHelper.uncheckedCast(_proxyFactory.propertyToProxy("Ice.Default.Router")); + if(router != null) + { + _referenceFactory = _referenceFactory.setDefaultRouter(router); + } + } + + if(_referenceFactory.getDefaultLocator() == null) + { + Ice.LocatorPrx loc = + Ice.LocatorPrxHelper.uncheckedCast(_proxyFactory.propertyToProxy("Ice.Default.Locator")); + if(loc != null) + { + _referenceFactory = _referenceFactory.setDefaultLocator(loc); + } + } + + // + // Server thread pool initialization is lazy in serverThreadPool(). + // + + // + // An application can set Ice.InitPlugins=0 if it wants to postpone + // initialization until after it has interacted directly with the + // plug-ins. + // + if(_initData.properties.getPropertyAsIntWithDefault("Ice.InitPlugins", 1) > 0) + { + pluginManagerImpl.initializePlugins(); + } + + // + // This must be done last as this call creates the Ice.Admin object adapter + // and eventually registers a process proxy with the Ice locator (allowing + // remote clients to invoke on Ice.Admin facets as soon as it's registered). + // + if(_initData.properties.getPropertyAsIntWithDefault("Ice.Admin.DelayCreation", 0) <= 0) + { + getAdmin(); + } + } + + // + // Only for use by Ice.CommunicatorI + // + @SuppressWarnings("deprecation") + public void + destroy() + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + synchronized(this) + { + // + // If destroy is in progress, wait for it to be done. This + // is necessary in case destroy() is called concurrently + // by multiple threads. + // + while(_state == StateDestroyInProgress) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + + if(_state == StateDestroyed) + { + return; + } + _state = StateDestroyInProgress; + } + + try + { + // + // Shutdown and destroy all the incoming and outgoing Ice + // connections and wait for the connections to be finished. + // + if(_objectAdapterFactory != null) + { + _objectAdapterFactory.shutdown(); + } + + if(_outgoingConnectionFactory != null) + { + _outgoingConnectionFactory.destroy(); + } + + if(_objectAdapterFactory != null) + { + _objectAdapterFactory.destroy(); + } + + if(_outgoingConnectionFactory != null) + { + _outgoingConnectionFactory.waitUntilFinished(); + } + + if(_retryQueue != null) + { + _retryQueue.destroy(); // Must be called before destroying thread pools. + } + + if(_initData.observer != null) + { + _initData.observer.setObserverUpdater(null); + } + + if(_initData.logger instanceof LoggerAdminLogger) + { + // + // This only disables the remote logging; we don't set or reset _initData.logger + // + ((LoggerAdminLogger)_initData.logger).destroy(); + } + + // + // Now, destroy the thread pools. This must be done *only* after + // all the connections are finished (the connections destruction + // can require invoking callbacks with the thread pools). + // + if(_serverThreadPool != null) + { + _serverThreadPool.destroy(); + } + if(_clientThreadPool != null) + { + _clientThreadPool.destroy(); + } + if(_endpointHostResolver != null) + { + _endpointHostResolver.destroy(); + } + if(_timer != null) + { + _timer.shutdown(); // Don't use shutdownNow(), timers don't support interrupts + } + + // + // Wait for all the threads to be finished. + // + try + { + if(_clientThreadPool != null) + { + _clientThreadPool.joinWithAllThreads(); + } + if(_serverThreadPool != null) + { + _serverThreadPool.joinWithAllThreads(); + } + if(_endpointHostResolver != null) + { + _endpointHostResolver.joinWithThread(); + } + if(_queueExecutor != null) + { + _queueExecutor.destroy(); + } + if(_timer != null) + { + while(!_timer.isTerminated()) + { + // A very long time. + _timer.awaitTermination(100000, java.util.concurrent.TimeUnit.SECONDS); + } + } + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + + // + // NOTE: at this point destroy() can't be interrupted + // anymore. The calls below are therefore guaranteed to be + // called once. + // + + for(Ice.ObjectFactory f : _objectFactoryMap.values()) + { + f.destroy(); + } + _objectFactoryMap.clear(); + + if(_routerManager != null) + { + _routerManager.destroy(); + } + + if(_locatorManager != null) + { + _locatorManager.destroy(); + } + + if(_endpointFactoryManager != null) + { + _endpointFactoryManager.destroy(); + } + + if(_initData.properties.getPropertyAsInt("Ice.Warn.UnusedProperties") > 0) + { + java.util.List<String> unusedProperties = ((Ice.PropertiesI)_initData.properties).getUnusedProperties(); + if(unusedProperties.size() != 0) + { + StringBuilder message = new StringBuilder("The following properties were set but never read:"); + for(String p : unusedProperties) + { + message.append("\n "); + message.append(p); + } + _initData.logger.warning(message.toString()); + } + } + + // + // Destroy last so that a Logger plugin can receive all log/traces before its destruction. + // + if(_pluginManager != null) + { + _pluginManager.destroy(); + } + + synchronized(this) + { + _objectAdapterFactory = null; + _outgoingConnectionFactory = null; + _retryQueue = null; + + _serverThreadPool = null; + _clientThreadPool = null; + _endpointHostResolver = null; + _timer = null; + + _referenceFactory = null; + _requestHandlerFactory = null; + _proxyFactory = null; + _routerManager = null; + _locatorManager = null; + _endpointFactoryManager = null; + + _pluginManager = null; + + _adminAdapter = null; + _adminFacets.clear(); + + _queueExecutor = null; + _queueExecutorService = null; + + _typeToClassMap.clear(); + + _state = StateDestroyed; + notifyAll(); + } + } + finally + { + synchronized(this) + { + if(_state == StateDestroyInProgress) + { + _state = StateActive; + notifyAll(); + } + } + } + } + + public BufSizeWarnInfo getBufSizeWarn(short type) + { + synchronized(_setBufSizeWarn) + { + BufSizeWarnInfo info; + if(!_setBufSizeWarn.containsKey(type)) + { + info = new BufSizeWarnInfo(); + info.sndWarn = false; + info.sndSize = -1; + info.rcvWarn = false; + info.rcvSize = -1; + _setBufSizeWarn.put(type, info); + } + else + { + info = _setBufSizeWarn.get(type); + } + return info; + } + } + + public void setSndBufSizeWarn(short type, int size) + { + synchronized(_setBufSizeWarn) + { + BufSizeWarnInfo info = getBufSizeWarn(type); + info.sndWarn = true; + info.sndSize = size; + _setBufSizeWarn.put(type, info); + } + } + + public void setRcvBufSizeWarn(short type, int size) + { + synchronized(_setBufSizeWarn) + { + BufSizeWarnInfo info = getBufSizeWarn(type); + info.rcvWarn = true; + info.rcvSize = size; + _setBufSizeWarn.put(type, info); + } + } + + @SuppressWarnings("deprecation") + public synchronized void addObjectFactory(final Ice.ObjectFactory factory, String id) + { + // + // Create a ValueFactory wrapper around the given ObjectFactory and register the wrapper + // with the value factory manager. This may raise AlreadyRegisteredException. + // + _initData.valueFactoryManager.add( + new Ice.ValueFactory() + { + public Ice.Object create(String id) + { + return factory.create(id); + } + }, id); + + _objectFactoryMap.put(id, factory); + } + + @SuppressWarnings("deprecation") + public synchronized Ice.ObjectFactory findObjectFactory(String id) + { + return _objectFactoryMap.get(id); + } + + private void + updateConnectionObservers() + { + try + { + assert(_outgoingConnectionFactory != null); + _outgoingConnectionFactory.updateConnectionObservers(); + assert(_objectAdapterFactory != null); + _objectAdapterFactory.updateConnectionObservers(); + } + catch(Ice.CommunicatorDestroyedException ex) + { + } + } + + private void + updateThreadObservers() + { + try + { + if(_clientThreadPool != null) + { + _clientThreadPool.updateObservers(); + } + if(_serverThreadPool != null) + { + _serverThreadPool.updateObservers(); + } + assert(_objectAdapterFactory != null); + _objectAdapterFactory.updateThreadObservers(); + if(_endpointHostResolver != null) + { + _endpointHostResolver.updateObserver(); + } + if(_timer != null) + { + _timer.updateObserver(_initData.observer); + } + if(_queueExecutor != null) + { + _queueExecutor.updateObserver(_initData.observer); + } + } + catch(Ice.CommunicatorDestroyedException ex) + { + } + } + + private String[] + validatePackages() + { + final String prefix = "Ice.Package."; + java.util.Map<String, String> map = _initData.properties.getPropertiesForPrefix(prefix); + java.util.List<String> packages = new java.util.ArrayList<String>(); + for(java.util.Map.Entry<String, String> p : map.entrySet()) + { + String key = p.getKey(); + String pkg = p.getValue(); + if(key.length() == prefix.length()) + { + _initData.logger.warning("ignoring invalid property: " + key + "=" + pkg); + } + String module = key.substring(prefix.length()); + String className = pkg + "." + module + "._Marker"; + Class<?> cls = null; + try + { + cls = findClass(className); + } + catch(java.lang.Exception ex) + { + } + if(cls == null) + { + _initData.logger.warning("unable to validate package: " + key + "=" + pkg); + } + else + { + packages.add(pkg); + } + } + + String pkg = _initData.properties.getProperty("Ice.Default.Package"); + if(pkg.length() > 0) + { + packages.add(pkg); + } + return packages.toArray(new String[packages.size()]); + } + + private synchronized void + addAllAdminFacets() + { + java.util.Map<String, Ice.Object> filteredFacets = new java.util.HashMap<String, Ice.Object>(); + for(java.util.Map.Entry<String, Ice.Object> p : _adminFacets.entrySet()) + { + if(_adminFacetFilter.isEmpty() || _adminFacetFilter.contains(p.getKey())) + { + _adminAdapter.addFacet(p.getValue(), _adminIdentity, p.getKey()); + } + else + { + filteredFacets.put(p.getKey(), p.getValue()); + } + } + _adminFacets = filteredFacets; + } + + private void + setServerProcessProxy(Ice.ObjectAdapter adminAdapter, Ice.Identity adminIdentity) + { + Ice.ObjectPrx admin = adminAdapter.createProxy(adminIdentity); + Ice.LocatorPrx locator = adminAdapter.getLocator(); + String serverId = _initData.properties.getProperty("Ice.Admin.ServerId"); + + if(locator != null && !serverId.isEmpty()) + { + Ice.ProcessPrx process = Ice.ProcessPrxHelper.uncheckedCast(admin.ice_facet("Process")); + try + { + // + // Note that as soon as the process proxy is registered, the communicator might be + // shutdown by a remote client and admin facets might start receiving calls. + // + locator.getRegistry().setServerProcessProxy(serverId, process); + } + catch(Ice.ServerNotFoundException ex) + { + if(_traceLevels.location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't register server `"); + s.append(serverId); + s.append("' with the locator registry:\n"); + s.append("the server is not known to the locator registry"); + _initData.logger.trace(_traceLevels.locationCat, s.toString()); + } + + throw new Ice.InitializationException("Locator knows nothing about server `" + serverId + "'"); + } + catch(Ice.LocalException ex) + { + if(_traceLevels.location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't register server `"); + s.append(serverId); + s.append("' with the locator registry:\n"); + s.append(ex.toString()); + _initData.logger.trace(_traceLevels.locationCat, s.toString()); + } + throw ex; + } + + if(_traceLevels.location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("registered server `"); + s.append(serverId); + s.append("' with the locator registry"); + _initData.logger.trace(_traceLevels.locationCat, s.toString()); + } + } + } + + private NetworkProxy createNetworkProxy(Ice.Properties properties, int protocolSupport) + { + String proxyHost; + + proxyHost = properties.getProperty("Ice.SOCKSProxyHost"); + if(!proxyHost.isEmpty()) + { + if(protocolSupport == Network.EnableIPv6) + { + throw new Ice.InitializationException("IPv6 only is not supported with SOCKS4 proxies"); + } + int proxyPort = properties.getPropertyAsIntWithDefault("Ice.SOCKSProxyPort", 1080); + return new SOCKSNetworkProxy(proxyHost, proxyPort); + } + + proxyHost = properties.getProperty("Ice.HTTPProxyHost"); + if(!proxyHost.isEmpty()) + { + return new HTTPNetworkProxy(proxyHost, properties.getPropertyAsIntWithDefault("Ice.HTTPProxyPort", 1080)); + } + + return null; + } + + private static final int StateActive = 0; + private static final int StateDestroyInProgress = 1; + private static final int StateDestroyed = 2; + private int _state; + + private final Ice.InitializationData _initData; // Immutable, not reset by destroy(). + private final TraceLevels _traceLevels; // Immutable, not reset by destroy(). + private final DefaultsAndOverrides _defaultsAndOverrides; // Immutable, not reset by destroy(). + private final int _messageSizeMax; // Immutable, not reset by destroy(). + private final int _batchAutoFlushSize; // Immutable, not reset by destroy(). + private final int _cacheMessageBuffers; // Immutable, not reset by destroy(). + private final ACMConfig _clientACM; // Immutable, not reset by destroy(). + private final ACMConfig _serverACM; // Immutable, not reset by destroy(). + private final Ice.ImplicitContextI _implicitContext; + private RouterManager _routerManager; + private LocatorManager _locatorManager; + private ReferenceFactory _referenceFactory; + private RequestHandlerFactory _requestHandlerFactory; + private ProxyFactory _proxyFactory; + private OutgoingConnectionFactory _outgoingConnectionFactory; + private ObjectAdapterFactory _objectAdapterFactory; + private int _protocolSupport; + private boolean _preferIPv6; + private NetworkProxy _networkProxy; + private ThreadPool _clientThreadPool; + private ThreadPool _serverThreadPool; + private EndpointHostResolver _endpointHostResolver; + private RetryQueue _retryQueue; + private Timer _timer; + private EndpointFactoryManager _endpointFactoryManager; + private Ice.PluginManager _pluginManager; + + private boolean _adminEnabled = false; + private Ice.ObjectAdapter _adminAdapter; + private java.util.Map<String, Ice.Object> _adminFacets = new java.util.HashMap<String, Ice.Object>(); + private java.util.Set<String> _adminFacetFilter = new java.util.HashSet<String>(); + private Ice.Identity _adminIdentity; + private java.util.Map<Short, BufSizeWarnInfo> _setBufSizeWarn = new java.util.HashMap<Short, BufSizeWarnInfo>(); + + private java.util.Map<String, String> _typeToClassMap = new java.util.HashMap<String, String>(); + final private String[] _packages; + final private boolean _useApplicationClassLoader; + + private static boolean _oneOffDone = false; + private QueueExecutorService _queueExecutorService; + private QueueExecutor _queueExecutor; + + @SuppressWarnings("deprecation") + private java.util.HashMap<String, Ice.ObjectFactory> _objectFactoryMap = + new java.util.HashMap<String, Ice.ObjectFactory>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/InvocationObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/InvocationObserverI.java new file mode 100644 index 00000000000..93cb2fb906a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/InvocationObserverI.java @@ -0,0 +1,249 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import IceMX.*; + +public class InvocationObserverI + extends IceMX.ObserverWithDelegate<IceMX.InvocationMetrics, Ice.Instrumentation.InvocationObserver> + implements Ice.Instrumentation.InvocationObserver +{ + static public final class RemoteInvocationHelper extends MetricsHelper<RemoteMetrics> + { + static private final AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + Class<?> cl = RemoteInvocationHelper.class; + add("parent", cl.getDeclaredMethod("getParent")); + add("id", cl.getDeclaredMethod("getId")); + add("requestId", cl.getDeclaredMethod("getRequestId")); + CommunicatorObserverI.addConnectionAttributes(this, RemoteInvocationHelper.class); + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + } + } + }; + + RemoteInvocationHelper(Ice.ConnectionInfo con, Ice.Endpoint endpt, int requestId, int size) + { + super(_attributes); + _connectionInfo = con; + _endpoint = endpt; + _requestId = requestId; + _size = size; + } + + @Override + public void + initMetrics(RemoteMetrics v) + { + v.size += _size; + } + + public String + getId() + { + if(_id == null) + { + _id = _endpoint.toString(); + if(_connectionInfo.connectionId != null && !_connectionInfo.connectionId.isEmpty()) + { + _id += " [" + _connectionInfo.connectionId + "]"; + } + } + return _id; + } + + int + getRequestId() + { + return _requestId; + } + + public String + getParent() + { + if(_connectionInfo.adapterName != null && !_connectionInfo.adapterName.isEmpty()) + { + return _connectionInfo.adapterName; + } + else + { + return "Communicator"; + } + } + + public Ice.ConnectionInfo + getConnectionInfo() + { + return _connectionInfo; + } + + public Ice.Endpoint + getEndpoint() + { + return _endpoint; + } + + public Ice.EndpointInfo + getEndpointInfo() + { + if(_endpointInfo == null) + { + _endpointInfo = _endpoint.getInfo(); + } + return _endpointInfo; + } + + final private Ice.ConnectionInfo _connectionInfo; + final private Ice.Endpoint _endpoint; + final private int _requestId; + final private int _size; + private String _id; + private Ice.EndpointInfo _endpointInfo; + } + + static public final class CollocatedInvocationHelper extends MetricsHelper<CollocatedMetrics> + { + static private final AttributeResolver _attributes = new AttributeResolver() + { + { + try + { + Class<?> cl = CollocatedInvocationHelper.class; + add("parent", cl.getDeclaredMethod("getParent")); + add("id", cl.getDeclaredMethod("getId")); + add("requestId", cl.getDeclaredMethod("getRequestId")); + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + } + } + }; + + CollocatedInvocationHelper(Ice.ObjectAdapter adapter, int requestId, int size) + { + super(_attributes); + _id = adapter.getName(); + _requestId = requestId; + _size = size; + } + + @Override + public void + initMetrics(CollocatedMetrics v) + { + v.size += _size; + } + + public String + getId() + { + return _id; + } + + int + getRequestId() + { + return _requestId; + } + + public String + getParent() + { + return "Communicator"; + } + + final private int _requestId; + final private int _size; + final private String _id; + } + + @Override + public void + userException() + { + forEach(_userException); + if(_delegate != null) + { + _delegate.userException(); + } + } + + @Override + public void + retried() + { + forEach(_incrementRetry); + if(_delegate != null) + { + _delegate.retried(); + } + } + + @Override + public Ice.Instrumentation.RemoteObserver + getRemoteObserver(Ice.ConnectionInfo con, Ice.Endpoint edpt, int requestId, int sz) + { + Ice.Instrumentation.RemoteObserver delegate = null; + if(_delegate != null) + { + delegate = _delegate.getRemoteObserver(con, edpt, requestId, sz); + } + return getObserver("Remote", + new RemoteInvocationHelper(con, edpt, requestId, sz), + RemoteMetrics.class, + RemoteObserverI.class, + delegate); + } + + @Override + public Ice.Instrumentation.CollocatedObserver + getCollocatedObserver(Ice.ObjectAdapter adapter, int requestId, int sz) + { + Ice.Instrumentation.CollocatedObserver delegate = null; + if(_delegate != null) + { + delegate = _delegate.getCollocatedObserver(adapter, requestId, sz); + } + return getObserver("Collocated", + new CollocatedInvocationHelper(adapter, requestId, sz), + CollocatedMetrics.class, + CollocatedObserverI.class, + delegate); + } + + final MetricsUpdate<InvocationMetrics> _incrementRetry = new MetricsUpdate<InvocationMetrics>() + { + @Override + public void + update(InvocationMetrics v) + { + ++v.retry; + } + }; + + final MetricsUpdate<InvocationMetrics> _userException = new MetricsUpdate<InvocationMetrics>() + { + @Override + public void + update(InvocationMetrics v) + { + ++v.userException; + } + }; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ListPatcher.java b/java-compat/src/Ice/src/main/java/IceInternal/ListPatcher.java new file mode 100644 index 00000000000..56f3472d567 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ListPatcher.java @@ -0,0 +1,46 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ListPatcher<T> implements Ice.ReadValueCallback +{ + public ListPatcher(java.util.List<T> list, Class<T> cls, int index) + { + _list = list; + _cls = cls; + _index = index; + } + + public void valueReady(Ice.Object v) + { + if(v != null) + { + // + // Raise ClassCastException if the element doesn't match the expected type. + // + if(!_cls.isInstance(v)) + { + throw new ClassCastException("expected element of type " + _cls.getName() + " but received " + + v.getClass().getName()); + } + } + + // + // This isn't very efficient for sequentially-accessed lists, but there + // isn't much we can do about it as long as a new patcher instance is + // created for each element. + // + _list.set(_index, _cls.cast(v)); + } + + private java.util.List<T> _list; + private Class<T> _cls; + private int _index; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java b/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java new file mode 100644 index 00000000000..82c4dea0e25 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/LocatorInfo.java @@ -0,0 +1,708 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class LocatorInfo +{ + interface GetEndpointsCallback + { + void setEndpoints(EndpointI[] endpoints, boolean cached); + void setException(Ice.LocalException ex); + } + + private static class RequestCallback + { + public void + response(LocatorInfo locatorInfo, Ice.ObjectPrx proxy) + { + EndpointI[] endpoints = null; + if(proxy != null) + { + Reference r = ((Ice.ObjectPrxHelperBase)proxy).__reference(); + if(_ref.isWellKnown() && !Protocol.isSupported(_ref.getEncoding(), r.getEncoding())) + { + // + // If a well-known proxy and the returned proxy + // encoding isn't supported, we're done: there's + // no compatible endpoint we can use. + // + } + else if(!r.isIndirect()) + { + endpoints = r.getEndpoints(); + } + else if(_ref.isWellKnown() && !r.isWellKnown()) + { + // + // We're resolving the endpoints of a well-known object and the proxy returned + // by the locator is an indirect proxy. We now need to resolve the endpoints + // of this indirect proxy. + // + locatorInfo.getEndpoints(r, _ref, _ttl, _callback); + return; + } + } + + if(_ref.getInstance().traceLevels().location >= 1) + { + locatorInfo.getEndpointsTrace(_ref, endpoints, false); + } + if(_callback != null) + { + _callback.setEndpoints(endpoints == null ? new EndpointI[0] : endpoints, false); + } + } + + public void + exception(LocatorInfo locatorInfo, Exception exc) + { + try + { + locatorInfo.getEndpointsException(_ref, exc); // This throws. + } + catch(Ice.LocalException ex) + { + if(_callback != null) + { + _callback.setException(ex); + } + } + } + + RequestCallback(Reference ref, int ttl, GetEndpointsCallback cb) + { + _ref = ref; + _ttl = ttl; + _callback = cb; + } + + final Reference _ref; + final int _ttl; + final GetEndpointsCallback _callback; + } + + private abstract class Request + { + public void + addCallback(Reference ref, Reference wellKnownRef, int ttl, GetEndpointsCallback cb) + { + RequestCallback callback = new RequestCallback(ref, ttl, cb); + synchronized(this) + { + if(!_response && _exception == null) + { + _callbacks.add(callback); + if(wellKnownRef != null) // This request is to resolve the endpoints of a cached well-known object ref + { + _wellKnownRefs.add(wellKnownRef); + } + if(!_sent) + { + _sent = true; + send(); + } + return; + } + } + + if(_response) + { + callback.response(_locatorInfo, _proxy); + } + else + { + assert(_exception != null); + callback.exception(_locatorInfo, _exception); + } + } + + Request(LocatorInfo locatorInfo, Reference ref) + { + _locatorInfo = locatorInfo; + _ref = ref; + _sent = false; + _response = false; + } + + protected void + response(Ice.ObjectPrx proxy) + { + synchronized(this) + { + _locatorInfo.finishRequest(_ref, _wellKnownRefs, proxy, false); + _response = true; + _proxy = proxy; + notifyAll(); + } + for(RequestCallback callback : _callbacks) + { + callback.response(_locatorInfo, proxy); + } + } + + protected void + exception(Exception ex) + { + synchronized(this) + { + _locatorInfo.finishRequest(_ref, _wellKnownRefs, null, ex instanceof Ice.UserException); + _exception = ex; + notifyAll(); + } + for(RequestCallback callback : _callbacks) + { + callback.exception(_locatorInfo, ex); + } + } + + protected abstract void send(); + + final protected LocatorInfo _locatorInfo; + final protected Reference _ref; + + private java.util.List<RequestCallback> _callbacks = new java.util.ArrayList<RequestCallback>(); + private java.util.List<Reference> _wellKnownRefs = new java.util.ArrayList<Reference>(); + private boolean _sent; + private boolean _response; + private Ice.ObjectPrx _proxy; + private Exception _exception; + } + + private class ObjectRequest extends Request + { + public ObjectRequest(LocatorInfo locatorInfo, Reference reference) + { + super(locatorInfo, reference); + assert(reference.isWellKnown()); + } + + @Override + protected void + send() + { + try + { + _locatorInfo.getLocator().begin_findObjectById( + _ref.getIdentity(), + new Ice.Callback_Locator_findObjectById() + { + @Override + public void + response(Ice.ObjectPrx proxy) + { + ObjectRequest.this.response(proxy); + } + + @Override + public void + exception(Ice.UserException ex) + { + ObjectRequest.this.exception(ex); + } + + @Override + public void + exception(Ice.LocalException ex) + { + ObjectRequest.this.exception(ex); + } + }); + } + catch(Exception ex) + { + exception(ex); + } + } + } + + private class AdapterRequest extends Request + { + public AdapterRequest(LocatorInfo locatorInfo, Reference reference) + { + super(locatorInfo, reference); + assert(reference.isIndirect()); + } + + @Override + protected void + send() + { + try + { + _locatorInfo.getLocator().begin_findAdapterById( + _ref.getAdapterId(), + new Ice.Callback_Locator_findAdapterById() + { + @Override + public void + response(Ice.ObjectPrx proxy) + { + AdapterRequest.this.response(proxy); + } + + @Override + public void + exception(Ice.UserException ex) + { + AdapterRequest.this.exception(ex); + } + + @Override + public void + exception(Ice.LocalException ex) + { + AdapterRequest.this.exception(ex); + } + }); + } + catch(Exception ex) + { + exception(ex); + } + } + } + + LocatorInfo(Ice.LocatorPrx locator, LocatorTable table, boolean background) + { + _locator = locator; + _table = table; + _background = background; + } + + synchronized public void + destroy() + { + _locatorRegistry = null; + _table.clear(); + } + + @Override + public boolean + equals(java.lang.Object obj) + { + if(this == obj) + { + return true; + } + + if(obj instanceof LocatorInfo) + { + return _locator.equals(((LocatorInfo)obj)._locator); + } + + return false; + } + + @Override + public int + hashCode() + { + return _locator.hashCode(); + } + + public Ice.LocatorPrx + getLocator() + { + // + // No synchronization necessary, _locator is immutable. + // + return _locator; + } + + public Ice.LocatorRegistryPrx + getLocatorRegistry() + { + synchronized(this) + { + if(_locatorRegistry != null) + { + return _locatorRegistry; + } + } + + // + // Do not make locator calls from within sync. + // + Ice.LocatorRegistryPrx locatorRegistry = _locator.getRegistry(); + if(locatorRegistry == null) + { + return null; + } + + synchronized(this) + { + // + // The locator registry can't be located. We use ordered + // endpoint selection in case the locator returned a proxy + // with some endpoints which are prefered to be tried first. + // + _locatorRegistry = (Ice.LocatorRegistryPrx)locatorRegistry.ice_locator(null).ice_endpointSelection( + Ice.EndpointSelectionType.Ordered); + return _locatorRegistry; + } + } + + public void + getEndpoints(Reference ref, int ttl, GetEndpointsCallback callback) + { + getEndpoints(ref, null, ttl, callback); + } + + public void + getEndpoints(Reference ref, Reference wellKnownRef, int ttl, GetEndpointsCallback callback) + { + assert(ref.isIndirect()); + EndpointI[] endpoints = null; + Ice.Holder<Boolean> cached = new Ice.Holder<Boolean>(); + if(!ref.isWellKnown()) + { + endpoints = _table.getAdapterEndpoints(ref.getAdapterId(), ttl, cached); + if(!cached.value) + { + if(_background && endpoints != null) + { + getAdapterRequest(ref).addCallback(ref, wellKnownRef, ttl, null); + } + else + { + getAdapterRequest(ref).addCallback(ref, wellKnownRef, ttl, callback); + return; + } + } + } + else + { + Reference r = _table.getObjectReference(ref.getIdentity(), ttl, cached); + if(!cached.value) + { + if(_background && r != null) + { + getObjectRequest(ref).addCallback(ref, null, ttl, null); + } + else + { + getObjectRequest(ref).addCallback(ref, null, ttl, callback); + return; + } + } + + if(!r.isIndirect()) + { + endpoints = r.getEndpoints(); + } + else if(!r.isWellKnown()) + { + getEndpoints(r, ref, ttl, callback); + return; + } + } + + assert(endpoints != null); + if(ref.getInstance().traceLevels().location >= 1) + { + getEndpointsTrace(ref, endpoints, true); + } + if(callback != null) + { + callback.setEndpoints(endpoints, true); + } + } + + public void + clearCache(Reference ref) + { + assert(ref.isIndirect()); + + if(!ref.isWellKnown()) + { + EndpointI[] endpoints = _table.removeAdapterEndpoints(ref.getAdapterId()); + + if(endpoints != null && ref.getInstance().traceLevels().location >= 2) + { + trace("removed endpoints from locator table\n", ref, endpoints); + } + } + else + { + Reference r = _table.removeObjectReference(ref.getIdentity()); + if(r != null) + { + if(!r.isIndirect()) + { + if(ref.getInstance().traceLevels().location >= 2) + { + trace("removed endpoints from locator table", ref, r.getEndpoints()); + } + } + else if(!r.isWellKnown()) + { + clearCache(r); + } + } + } + } + + private void + trace(String msg, Reference ref, EndpointI[] endpoints) + { + assert(ref.isIndirect()); + + StringBuilder s = new StringBuilder(128); + s.append(msg); + s.append("\n"); + if(!ref.isWellKnown()) + { + s.append("adapter = "); + s.append(ref.getAdapterId()); + s.append("\n"); + } + else + { + s.append("object = "); + s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append("\n"); + } + + s.append("endpoints = "); + final int sz = endpoints.length; + for(int i = 0; i < sz; i++) + { + s.append(endpoints[i].toString()); + if(i + 1 < sz) + { + s.append(":"); + } + } + + ref.getInstance().initializationData().logger.trace(ref.getInstance().traceLevels().locationCat, s.toString()); + } + + private void + getEndpointsException(Reference ref, Exception exc) + { + assert(ref.isIndirect()); + + try + { + throw exc; + } + catch(Ice.AdapterNotFoundException ex) + { + final Instance instance = ref.getInstance(); + if(instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("adapter not found\n"); + s.append("adapter = "); + s.append(ref.getAdapterId()); + instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); + } + + Ice.NotRegisteredException e = new Ice.NotRegisteredException(); + e.kindOfObject = "object adapter"; + e.id = ref.getAdapterId(); + throw e; + } + catch(Ice.ObjectNotFoundException ex) + { + final Instance instance = ref.getInstance(); + if(instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("object not found\n"); + s.append("object = "); + s.append(Ice.Util.identityToString(ref.getIdentity())); + instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); + } + + Ice.NotRegisteredException e = new Ice.NotRegisteredException(); + e.kindOfObject = "object"; + e.id = Ice.Util.identityToString(ref.getIdentity()); + throw e; + } + catch(Ice.NotRegisteredException ex) + { + throw ex; + } + catch(Ice.LocalException ex) + { + final Instance instance = ref.getInstance(); + if(instance.traceLevels().location >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't contact the locator to retrieve adapter endpoints\n"); + if(ref.getAdapterId().length() > 0) + { + s.append("adapter = "); + s.append(ref.getAdapterId()); + s.append("\n"); + } + else + { + s.append("object = "); + s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append("\n"); + } + s.append("reason = " + ex); + instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); + } + throw ex; + } + catch(Exception ex) + { + assert(false); + } + } + + private void + getEndpointsTrace(Reference ref, EndpointI[] endpoints, boolean cached) + { + if(endpoints != null && endpoints.length > 0) + { + if(cached) + { + trace("found endpoints in locator table", ref, endpoints); + } + else + { + trace("retrieved endpoints from locator, adding to locator table", ref, endpoints); + } + } + else + { + final Instance instance = ref.getInstance(); + StringBuilder s = new StringBuilder(128); + s.append("no endpoints configured for "); + if(ref.getAdapterId().length() > 0) + { + s.append("adapter\n"); + s.append("adapter = "); + s.append(ref.getAdapterId()); + s.append("\n"); + } + else + { + s.append("object\n"); + s.append("object = "); + s.append(Ice.Util.identityToString(ref.getIdentity())); + s.append("\n"); + } + instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); + } + } + + synchronized private Request + getAdapterRequest(Reference ref) + { + if(ref.getInstance().traceLevels().location >= 1) + { + Instance instance = ref.getInstance(); + StringBuilder s = new StringBuilder(128); + s.append("searching for adapter by id\n"); + s.append("adapter = "); + s.append(ref.getAdapterId()); + instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); + } + + Request request = _adapterRequests.get(ref.getAdapterId()); + if(request != null) + { + return request; + } + request = new AdapterRequest(this, ref); + _adapterRequests.put(ref.getAdapterId(), request); + return request; + } + + synchronized private Request + getObjectRequest(Reference ref) + { + if(ref.getInstance().traceLevels().location >= 1) + { + Instance instance = ref.getInstance(); + StringBuilder s = new StringBuilder(128); + s.append("searching for object by id\n"); + s.append("object = "); + s.append(Ice.Util.identityToString(ref.getIdentity())); + instance.initializationData().logger.trace(instance.traceLevels().locationCat, s.toString()); + } + + Request request = _objectRequests.get(ref.getIdentity()); + if(request != null) + { + return request; + } + request = new ObjectRequest(this, ref); + _objectRequests.put(ref.getIdentity(), request); + return request; + } + + private void + finishRequest(Reference ref, java.util.List<Reference> wellKnownRefs, Ice.ObjectPrx proxy, boolean notRegistered) + { + if(proxy == null || ((Ice.ObjectPrxHelperBase)proxy).__reference().isIndirect()) + { + // + // Remove the cached references of well-known objects for which we tried + // to resolved the endpoints if these endpoints are empty. + // + for(Reference r : wellKnownRefs) + { + _table.removeObjectReference(r.getIdentity()); + } + } + + if(!ref.isWellKnown()) + { + if(proxy != null && !((Ice.ObjectPrxHelperBase)proxy).__reference().isIndirect()) + { + // Cache the adapter endpoints. + _table.addAdapterEndpoints(ref.getAdapterId(), + ((Ice.ObjectPrxHelperBase)proxy).__reference().getEndpoints()); + } + else if(notRegistered) // If the adapter isn't registered anymore, remove it from the cache. + { + _table.removeAdapterEndpoints(ref.getAdapterId()); + } + + synchronized(this) + { + assert(_adapterRequests.get(ref.getAdapterId()) != null); + _adapterRequests.remove(ref.getAdapterId()); + } + } + else + { + if(proxy != null && !((Ice.ObjectPrxHelperBase)proxy).__reference().isWellKnown()) + { + // Cache the well-known object reference. + _table.addObjectReference(ref.getIdentity(), ((Ice.ObjectPrxHelperBase)proxy).__reference()); + } + else if(notRegistered) // If the well-known object isn't registered anymore, remove it from the cache. + { + _table.removeObjectReference(ref.getIdentity()); + } + + synchronized(this) + { + assert(_objectRequests.get(ref.getIdentity()) != null); + _objectRequests.remove(ref.getIdentity()); + } + } + } + + private final Ice.LocatorPrx _locator; + private Ice.LocatorRegistryPrx _locatorRegistry; + private final LocatorTable _table; + private final boolean _background; + + private java.util.Map<String, Request> _adapterRequests = new java.util.HashMap<String, Request>(); + private java.util.Map<Ice.Identity, Request> _objectRequests = new java.util.HashMap<Ice.Identity, Request>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LocatorManager.java b/java-compat/src/Ice/src/main/java/IceInternal/LocatorManager.java new file mode 100644 index 00000000000..201dacf41b2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/LocatorManager.java @@ -0,0 +1,140 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class LocatorManager +{ + static private final class LocatorKey implements Cloneable + { + @Override + public boolean + equals(Object o) + { + assert(o instanceof LocatorKey); + LocatorKey k = (LocatorKey)o; + if(!k._id.equals(_id)) + { + return false; + } + if(!k._encoding.equals(_encoding)) + { + return false; + } + return true; + } + + @Override + public int + hashCode() + { + int h = 5381; + h = IceInternal.HashUtil.hashAdd(h, _id); + h = IceInternal.HashUtil.hashAdd(h, _encoding); + return h; + } + + @Override + public LocatorKey + clone() + { + LocatorKey c = null; + try + { + c = (LocatorKey)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; // impossible + } + return c; + } + + LocatorKey set(Ice.LocatorPrx locator) + { + Reference r = ((Ice.ObjectPrxHelperBase)locator).__reference(); + _id = r.getIdentity(); + _encoding = r.getEncoding(); + return this; + } + + private Ice.Identity _id; + private Ice.EncodingVersion _encoding; + } + + LocatorManager(Ice.Properties properties) + { + _background = properties.getPropertyAsInt("Ice.BackgroundLocatorCacheUpdates") > 0; + } + + synchronized void + destroy() + { + for(LocatorInfo info : _table.values()) + { + info.destroy(); + } + _table.clear(); + _locatorTables.clear(); + } + + // + // Returns locator info for a given locator. Automatically creates + // the locator info if it doesn't exist yet. + // + public LocatorInfo + get(Ice.LocatorPrx loc) + { + if(loc == null) + { + return null; + } + + // + // The locator can't be located. + // + Ice.LocatorPrx locator = Ice.LocatorPrxHelper.uncheckedCast(loc.ice_locator(null)); + + // + // TODO: reap unused locator info objects? + // + + synchronized(this) + { + LocatorInfo info = _table.get(locator); + if(info == null) + { + // + // Rely on locator identity for the adapter table. We want to + // have only one table per locator (not one per locator + // proxy). + // + LocatorTable table = _locatorTables.get(_lookupKey.set(locator)); + if(table == null) + { + table = new LocatorTable(); + _locatorTables.put(_lookupKey.clone(), table); + } + + info = new LocatorInfo(locator, table, _background); + _table.put(locator, info); + } + + return info; + } + } + + final private boolean _background; + + private java.util.HashMap<Ice.LocatorPrx, LocatorInfo> _table = + new java.util.HashMap<Ice.LocatorPrx, LocatorInfo>(); + private java.util.HashMap<LocatorKey, LocatorTable> _locatorTables = + new java.util.HashMap<LocatorKey, LocatorTable>(); + private LocatorKey _lookupKey = new LocatorKey(); // A key used for the lookup +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LocatorTable.java b/java-compat/src/Ice/src/main/java/IceInternal/LocatorTable.java new file mode 100644 index 00000000000..0f2a13bda37 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/LocatorTable.java @@ -0,0 +1,132 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class LocatorTable +{ + LocatorTable() + { + } + + synchronized void + clear() + { + _adapterEndpointsTable.clear(); + _objectTable.clear(); + } + + synchronized IceInternal.EndpointI[] + getAdapterEndpoints(String adapter, int ttl, Ice.Holder<Boolean> cached) + { + if(ttl == 0) // Locator cache disabled. + { + cached.value = false; + return null; + } + + EndpointTableEntry entry = _adapterEndpointsTable.get(adapter); + if(entry != null) + { + cached.value = checkTTL(entry.time, ttl); + return entry.endpoints; + } + cached.value = false; + return null; + } + + synchronized void + addAdapterEndpoints(String adapter, IceInternal.EndpointI[] endpoints) + { + _adapterEndpointsTable.put(adapter, + new EndpointTableEntry(IceInternal.Time.currentMonotonicTimeMillis(), endpoints)); + } + + synchronized IceInternal.EndpointI[] + removeAdapterEndpoints(String adapter) + { + EndpointTableEntry entry = _adapterEndpointsTable.remove(adapter); + return entry != null ? entry.endpoints : null; + } + + synchronized Reference + getObjectReference(Ice.Identity id, int ttl, Ice.Holder<Boolean> cached) + { + if(ttl == 0) // Locator cache disabled. + { + cached.value = false; + return null; + } + + ReferenceTableEntry entry = _objectTable.get(id); + if(entry != null) + { + cached.value = checkTTL(entry.time, ttl); + return entry.reference; + } + cached.value = false; + return null; + } + + synchronized void + addObjectReference(Ice.Identity id, Reference ref) + { + _objectTable.put(id, new ReferenceTableEntry(IceInternal.Time.currentMonotonicTimeMillis(), ref)); + } + + synchronized Reference + removeObjectReference(Ice.Identity id) + { + ReferenceTableEntry entry = _objectTable.remove(id); + return entry != null ? entry.reference : null; + } + + private boolean + checkTTL(long time, int ttl) + { + assert(ttl != 0); + if(ttl < 0) // TTL = infinite + { + return true; + } + else + { + return IceInternal.Time.currentMonotonicTimeMillis() - time <= ((long)ttl * 1000); + } + } + + private static final class EndpointTableEntry + { + public EndpointTableEntry(long time, IceInternal.EndpointI[] endpoints) + { + this.time = time; + this.endpoints = endpoints; + } + + final public long time; + final public IceInternal.EndpointI[] endpoints; + } + + private static final class ReferenceTableEntry + { + public ReferenceTableEntry(long time, Reference reference) + { + this.time = time; + this.reference = reference; + } + + final public long time; + final public Reference reference; + } + + private java.util.Map<String, EndpointTableEntry> _adapterEndpointsTable = + new java.util.HashMap<String, EndpointTableEntry>(); + private java.util.Map<Ice.Identity, ReferenceTableEntry> _objectTable = + new java.util.HashMap<Ice.Identity, ReferenceTableEntry>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminI.java b/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminI.java new file mode 100644 index 00000000000..4a322318fad --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminI.java @@ -0,0 +1,465 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class LoggerAdminI extends Ice._LoggerAdminDisp +{ + @Override + public void attachRemoteLogger(Ice.RemoteLoggerPrx prx, Ice.LogMessageType[] messageTypes, String[] categories, + int messageMax, Ice.Current current) + throws Ice.RemoteLoggerAlreadyAttachedException + { + if(prx == null) + { + return; // can't send this null RemoteLogger anything! + } + + Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(prx.ice_twoway()); + + Filters filters = new Filters(messageTypes, categories); + java.util.List<Ice.LogMessage> initLogMessages = null; + + synchronized(this) + { + if(_sendLogCommunicator == null) + { + if(_destroyed) + { + throw new Ice.ObjectNotExistException(); + } + + _sendLogCommunicator = + createSendLogCommunicator(current.adapter.getCommunicator(), _logger.getLocalLogger()); + } + + Ice.Identity remoteLoggerId = remoteLogger.ice_getIdentity(); + + if(_remoteLoggerMap.containsKey(remoteLoggerId)) + { + if(_traceLevel > 0) + { + _logger.trace(_traceCategory, "rejecting `" + remoteLogger.toString() + + "' with RemoteLoggerAlreadyAttachedException"); + } + + throw new Ice.RemoteLoggerAlreadyAttachedException(); + } + + _remoteLoggerMap.put(remoteLoggerId, + new RemoteLoggerData(changeCommunicator(remoteLogger, _sendLogCommunicator), filters)); + + if(messageMax != 0) + { + initLogMessages = new java.util.LinkedList<Ice.LogMessage>(_queue); // copy + } + else + { + initLogMessages = new java.util.LinkedList<Ice.LogMessage>(); + } + } + + if(_traceLevel > 0) + { + _logger.trace(_traceCategory, "attached `" + remoteLogger.toString() + "'"); + } + + if(!initLogMessages.isEmpty()) + { + filterLogMessages(initLogMessages, filters.messageTypes, filters.traceCategories, messageMax); + } + + final Ice.Callback initCompletedCb = new Ice.Callback() + { + @Override + public void completed(Ice.AsyncResult r) + { + Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(r.getProxy()); + + try + { + remoteLogger.end_init(r); + + if(_traceLevel > 1) + { + _logger.trace(_traceCategory, r.getOperation() + " on `" + remoteLogger.toString() + + "' completed successfully"); + } + } + catch(Ice.LocalException ex) + { + deadRemoteLogger(remoteLogger, _logger, ex, r.getOperation()); + } + } + }; + + try + { + remoteLogger.begin_init(_logger.getPrefix(), initLogMessages.toArray(new Ice.LogMessage[0]), + initCompletedCb); + } + catch(Ice.LocalException ex) + { + deadRemoteLogger(remoteLogger, _logger, ex, "init"); + throw ex; + } + } + + @Override + public boolean detachRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Current current) + { + if(remoteLogger == null) + { + return false; + } + + // + // No need to convert the proxy as we only use its identity + // + boolean found = removeRemoteLogger(remoteLogger); + + if(_traceLevel > 0) + { + if(found) + { + _logger.trace(_traceCategory, "detached `" + remoteLogger.toString() + "'"); + } + else + { + _logger.trace(_traceCategory, "cannot detach `" + remoteLogger.toString() + "': not found"); + } + } + + return found; + } + + @Override + public Ice.LogMessage[] getLog(Ice.LogMessageType[] messageTypes, String[] categories, int messageMax, + Ice.StringHolder prefix, Ice.Current current) + { + java.util.List<Ice.LogMessage> logMessages = null; + synchronized(this) + { + if(messageMax != 0) + { + logMessages = new java.util.LinkedList<Ice.LogMessage>(_queue); + } + else + { + logMessages = new java.util.LinkedList<Ice.LogMessage>(); + } + } + + prefix.value = _logger.getPrefix(); + + if(!logMessages.isEmpty()) + { + Filters filters = new Filters(messageTypes, categories); + filterLogMessages(logMessages, filters.messageTypes, filters.traceCategories, messageMax); + } + return logMessages.toArray(new Ice.LogMessage[0]); + } + + + LoggerAdminI(Ice.Properties props, LoggerAdminLoggerI logger) + { + _maxLogCount = props.getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepLogs", 100); + _maxTraceCount = props.getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepTraces", 100); + _traceLevel = props.getPropertyAsInt("Ice.Trace.Admin.Logger"); + _logger = logger; + } + + void destroy() + { + Ice.Communicator sendLogCommunicator = null; + + synchronized(this) + { + if(!_destroyed) + { + _destroyed = true; + sendLogCommunicator = _sendLogCommunicator; + _sendLogCommunicator = null; + } + } + + // + // Destroy outside lock to avoid deadlock when there are outstanding two-way log calls sent to + // remote logggers + // + if(sendLogCommunicator != null) + { + sendLogCommunicator.destroy(); + } + } + + synchronized java.util.List<Ice.RemoteLoggerPrx> log(Ice.LogMessage logMessage) + { + java.util.List<Ice.RemoteLoggerPrx> remoteLoggers = null; + + // + // Put message in _queue + // + if((logMessage.type != Ice.LogMessageType.TraceMessage && _maxLogCount > 0) || + (logMessage.type == Ice.LogMessageType.TraceMessage && _maxTraceCount > 0)) + { + _queue.add(logMessage); // add at the end + + if(logMessage.type != Ice.LogMessageType.TraceMessage) + { + assert(_maxLogCount > 0); + if(_logCount == _maxLogCount) + { + // + // Need to remove the oldest log from the queue + // + assert(_oldestLog != -1); + _queue.remove(_oldestLog); + int qs = _queue.size(); + + while(_oldestLog < qs && _queue.get(_oldestLog).type == Ice.LogMessageType.TraceMessage) + { + _oldestLog++; + } + assert(_oldestLog < qs); // remember: we just added a log message at end + } + else + { + assert(_logCount < _maxLogCount); + _logCount++; + if(_oldestLog == -1) + { + _oldestLog = _queue.size() - 1; + } + } + } + else + { + assert(_maxTraceCount > 0); + if(_traceCount == _maxTraceCount) + { + // + // Need to remove the oldest trace from the queue + // + assert(_oldestTrace != -1); + _queue.remove(_oldestTrace); + int qs = _queue.size(); + while(_oldestTrace < qs && _queue.get(_oldestTrace).type != Ice.LogMessageType.TraceMessage) + { + _oldestTrace++; + } + assert(_oldestTrace < qs); // remember: we just added a trace message at end + } + else + { + assert(_traceCount < _maxTraceCount); + _traceCount++; + if(_oldestTrace == -1) + { + _oldestTrace = _queue.size() - 1; + } + } + } + + // + // Queue updated, now find which remote loggers want this message + // + for(RemoteLoggerData p : _remoteLoggerMap.values()) + { + Filters filters = p.filters; + + if(filters.messageTypes.isEmpty() || filters.messageTypes.contains(logMessage.type)) + { + if(logMessage.type != Ice.LogMessageType.TraceMessage || filters.traceCategories.isEmpty() || + filters.traceCategories.contains(logMessage.traceCategory)) + { + if(remoteLoggers == null) + { + remoteLoggers = new java.util.ArrayList<Ice.RemoteLoggerPrx>(); + } + remoteLoggers.add(p.remoteLogger); + } + } + } + } + + return remoteLoggers; + } + + void deadRemoteLogger(Ice.RemoteLoggerPrx remoteLogger, Ice.Logger logger, Ice.LocalException ex, String operation) + { + // + // No need to convert remoteLogger as we only use its identity + // + if(removeRemoteLogger(remoteLogger)) + { + if(_traceLevel > 0) + { + logger.trace(_traceCategory, "detached `" + remoteLogger.toString() + "' because " + + operation + " raised:\n" + ex.toString()); + } + } + } + + int getTraceLevel() + { + return _traceLevel; + } + + private synchronized boolean removeRemoteLogger(Ice.RemoteLoggerPrx remoteLogger) + { + return _remoteLoggerMap.remove(remoteLogger.ice_getIdentity()) != null; + } + + private static void filterLogMessages(java.util.List<Ice.LogMessage> logMessages, + java.util.Set<Ice.LogMessageType> messageTypes, + java.util.Set<String> traceCategories, int messageMax) + { + assert(!logMessages.isEmpty() && messageMax != 0); + + // + // Filter only if one of the 3 filters is set; messageMax < 0 means "give me all" + // that match the other filters, if any. + // + if(!messageTypes.isEmpty() || !traceCategories.isEmpty() || messageMax > 0) + { + int count = 0; + java.util.ListIterator<Ice.LogMessage> p = logMessages.listIterator(logMessages.size()); + while(p.hasPrevious()) + { + boolean keepIt = false; + Ice.LogMessage msg = p.previous(); + if(messageTypes.isEmpty() || messageTypes.contains(msg.type)) + { + if(msg.type != Ice.LogMessageType.TraceMessage || traceCategories.isEmpty() || + traceCategories.contains(msg.traceCategory)) + { + keepIt = true; + } + } + + if(keepIt) + { + ++count; + if(messageMax > 0 && count >= messageMax) + { + if(p.hasPrevious()) + { + int removeCount = p.previousIndex() + 1; + for(int i = 0; i < removeCount; ++i) + { + logMessages.remove(0); + } + } + break; // while + } + } + else + { + p.remove(); + } + } + } + // else, don't need any filtering + } + + // + // Change this proxy's communicator, while keeping its invocation timeout + // + private static Ice.RemoteLoggerPrx changeCommunicator(Ice.RemoteLoggerPrx prx, Ice.Communicator communicator) + { + if(prx == null) + { + return null; + } + + Ice.ObjectPrx result = communicator.stringToProxy(prx.toString()); + return Ice.RemoteLoggerPrxHelper.uncheckedCast(result.ice_invocationTimeout(prx.ice_getInvocationTimeout())); + } + + private static void copyProperties(String prefix, Ice.Properties from, Ice.Properties to) + { + for(java.util.Map.Entry<String, String> p : from.getPropertiesForPrefix(prefix).entrySet()) + { + to.setProperty(p.getKey(), p.getValue()); + } + } + + private static Ice.Communicator createSendLogCommunicator(Ice.Communicator communicator, Ice.Logger logger) + { + Ice.InitializationData initData = new Ice.InitializationData(); + initData.logger = logger; + initData.properties = Ice.Util.createProperties(); + + Ice.Properties mainProps = communicator.getProperties(); + + copyProperties("Ice.Default.Locator", mainProps, initData.properties); + copyProperties("Ice.Plugin.IceSSL", mainProps, initData.properties); + copyProperties("IceSSL.", mainProps, initData.properties); + + String[] extraProps = mainProps.getPropertyAsList("Ice.Admin.Logger.Properties"); + + if(extraProps.length > 0) + { + for(int i = 0; i < extraProps.length; ++i) + { + String p = extraProps[i]; + if(!p.startsWith("--")) + { + extraProps[i] = "--" + p; + } + } + initData.properties.parseCommandLineOptions("", extraProps); + } + return Ice.Util.initialize(initData); + } + + + private final java.util.List<Ice.LogMessage> _queue = new java.util.LinkedList<Ice.LogMessage>(); + private int _logCount = 0; // non-trace messages + private final int _maxLogCount; + private int _traceCount = 0; + private final int _maxTraceCount; + private final int _traceLevel; + + private int _oldestTrace = -1; + private int _oldestLog = -1; + + private static class Filters + { + Filters(Ice.LogMessageType[] m, String[] c) + { + messageTypes = new java.util.HashSet<Ice.LogMessageType>(java.util.Arrays.asList(m)); + traceCategories = new java.util.HashSet<String>(java.util.Arrays.asList(c)); + } + + final java.util.Set<Ice.LogMessageType> messageTypes; + final java.util.Set<String> traceCategories; + } + + private static class RemoteLoggerData + { + RemoteLoggerData(Ice.RemoteLoggerPrx prx, Filters f) + { + remoteLogger = prx; + filters = f; + } + + final Ice.RemoteLoggerPrx remoteLogger; + final Filters filters; + } + + private final java.util.Map<Ice.Identity, RemoteLoggerData> _remoteLoggerMap + = new java.util.HashMap<Ice.Identity, RemoteLoggerData>(); + + private final LoggerAdminLoggerI _logger; + private Ice.Communicator _sendLogCommunicator = null; + private boolean _destroyed = false; + static private final String _traceCategory = "Admin.Logger"; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminLogger.java b/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminLogger.java new file mode 100644 index 00000000000..1ae9f52faf1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminLogger.java @@ -0,0 +1,16 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +interface LoggerAdminLogger extends Ice.Logger +{ + Ice.Object getFacet(); + void destroy(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminLoggerI.java b/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminLoggerI.java new file mode 100644 index 00000000000..b5743d72873 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/LoggerAdminLoggerI.java @@ -0,0 +1,254 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class LoggerAdminLoggerI implements LoggerAdminLogger, Runnable +{ + @Override + public void print(String message) + { + Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.PrintMessage, now(), "", message); + _localLogger.print(message); + log(logMessage); + } + + @Override + public void trace(String category, String message) + { + Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.TraceMessage, now(), category, message); + _localLogger.trace(category, message); + log(logMessage); + } + + @Override + public void warning(String message) + { + Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.WarningMessage, now(), "", message); + _localLogger.warning(message); + log(logMessage); + } + + @Override + public void error(String message) + { + Ice.LogMessage logMessage = new Ice.LogMessage(Ice.LogMessageType.ErrorMessage, now(), "", message); + _localLogger.error(message); + log(logMessage); + } + + @Override + public String getPrefix() + { + return _localLogger.getPrefix(); + } + + @Override + public Ice.Logger cloneWithPrefix(String prefix) + { + return _localLogger.cloneWithPrefix(prefix); + } + + @Override + public Ice.Object getFacet() + { + return _loggerAdmin; + } + + @Override + public void destroy() + { + Thread thread = null; + synchronized(this) + { + if(_sendLogThread != null) + { + thread = _sendLogThread; + _sendLogThread = null; + _destroyed = true; + notifyAll(); + } + } + + if(thread != null) + { + try + { + thread.join(); + } + catch(InterruptedException e) + { + synchronized(this) + { + _sendLogThread = thread; + } + throw new Ice.OperationInterruptedException(); + } + } + + _loggerAdmin.destroy(); + } + + @Override + public void run() + { + if(_loggerAdmin.getTraceLevel() > 1) + { + _localLogger.trace(_traceCategory, "send log thread started"); + } + + final Ice.Callback logCompletedCb = new Ice.Callback() + { + + @Override + public void completed(Ice.AsyncResult r) + { + Ice.RemoteLoggerPrx remoteLogger = Ice.RemoteLoggerPrxHelper.uncheckedCast(r.getProxy()); + + try + { + remoteLogger.end_log(r); + + if(_loggerAdmin.getTraceLevel() > 1) + { + _localLogger.trace(_traceCategory, r.getOperation() + " on `" + remoteLogger.toString() + + "' completed successfully"); + } + } + catch(Ice.CommunicatorDestroyedException ex) + { + // expected if there are outstanding calls during + // communicator destruction + } + catch(Ice.LocalException ex) + { + _loggerAdmin.deadRemoteLogger(remoteLogger, _localLogger, ex, r.getOperation()); + } + } + }; + + for(;;) + { + Job job = null; + synchronized(this) + { + while(!_destroyed && _jobQueue.isEmpty()) + { + try + { + wait(); + } + catch(InterruptedException e) + { + // Ignored, this should never occur + } + } + + if(_destroyed) + { + break; // for(;;) + } + + assert(!_jobQueue.isEmpty()); + job = _jobQueue.removeFirst(); + } + + for(Ice.RemoteLoggerPrx p : job.remoteLoggers) + { + if(_loggerAdmin.getTraceLevel() > 1) + { + _localLogger.trace(_traceCategory, "sending log message to `" + p.toString() + "'"); + } + + try + { + // + // p is a proxy associated with the _sendLogCommunicator + // + p.begin_log(job.logMessage, logCompletedCb); + } + catch(Ice.LocalException ex) + { + _loggerAdmin.deadRemoteLogger(p, _localLogger, ex, "log"); + } + } + } + + if(_loggerAdmin.getTraceLevel() > 1) + { + _localLogger.trace(_traceCategory, "send log thread completed"); + } + } + + LoggerAdminLoggerI(Ice.Properties props, Ice.Logger localLogger) + { + if(localLogger instanceof LoggerAdminLoggerI) + { + _localLogger = ((LoggerAdminLoggerI)localLogger).getLocalLogger(); + } + else + { + _localLogger = localLogger; + } + + _loggerAdmin = new LoggerAdminI(props, this); + } + + Ice.Logger getLocalLogger() + { + return _localLogger; + } + + void log(Ice.LogMessage logMessage) + { + java.util.List<Ice.RemoteLoggerPrx> remoteLoggers = _loggerAdmin.log(logMessage); + + if(remoteLoggers != null) + { + assert(!remoteLoggers.isEmpty()); + + synchronized(this) + { + if(_sendLogThread == null) + { + _sendLogThread = new Thread(this, "Ice.SendLogThread"); + _sendLogThread.start(); + } + + _jobQueue.addLast(new Job(remoteLoggers, logMessage)); + notifyAll(); + } + } + } + + static private long now() + { + return java.util.Calendar.getInstance().getTimeInMillis() * 1000; + } + + private static class Job + { + Job(java.util.List<Ice.RemoteLoggerPrx> r, Ice.LogMessage l) + { + remoteLoggers = r; + logMessage = l; + } + + final java.util.List<Ice.RemoteLoggerPrx> remoteLoggers; + final Ice.LogMessage logMessage; + } + + private final Ice.Logger _localLogger; + private final LoggerAdminI _loggerAdmin; + private boolean _destroyed = false; + private Thread _sendLogThread; + private final java.util.Deque<Job> _jobQueue = new java.util.ArrayDeque<Job>(); + + static private final String _traceCategory = "Admin.Logger"; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/MetricsAdminI.java b/java-compat/src/Ice/src/main/java/IceInternal/MetricsAdminI.java new file mode 100644 index 00000000000..92b0cb139a6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/MetricsAdminI.java @@ -0,0 +1,400 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class MetricsAdminI extends IceMX._MetricsAdminDisp implements Ice.PropertiesAdminUpdateCallback +{ + final static private String[] suffixes = + { + "Disabled", + "GroupBy", + "Accept.*", + "Reject.*", + "RetainDetached", + "Map.*", + }; + + static void + validateProperties(String prefix, Ice.Properties properties) + { + java.util.Map<String, String> props = properties.getPropertiesForPrefix(prefix); + java.util.List<String> unknownProps = new java.util.ArrayList<String>(); + for(String prop : props.keySet()) + { + boolean valid = false; + for(String suffix : suffixes) + { + if(IceUtilInternal.StringUtil.match(prop, prefix + suffix, false)) + { + valid = true; + break; + } + } + + if(!valid) + { + unknownProps.add(prop); + } + } + + if(unknownProps.size() != 0 && properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0) + { + StringBuffer message = new StringBuffer("found unknown IceMX properties for `"); + message.append(prefix.substring(0, prefix.length() - 1)); + message.append("':"); + for(String p : unknownProps) + { + message.append("\n "); + message.append(p); + } + Ice.Util.getProcessLogger().warning(message.toString()); + } + } + + static class MetricsMapFactory<T extends IceMX.Metrics> + { + public MetricsMapFactory(Runnable updater, Class<T> cl) + { + _updater = updater; + _class = cl; + } + + public void + update() + { + assert(_updater != null); + _updater.run(); + } + + public MetricsMap<T> + create(String mapPrefix, Ice.Properties properties) + { + return new MetricsMap<T>(mapPrefix, _class, properties, _subMaps); + } + + public <S extends IceMX.Metrics> void + registerSubMap(String subMap, Class<S> cl, java.lang.reflect.Field field) + { + _subMaps.put(subMap, new MetricsMap.SubMapFactory<S>(cl, field)); + } + + final private Runnable _updater; + final private Class<T> _class; + final private java.util.Map<String, MetricsMap.SubMapFactory<?>> _subMaps = + new java.util.HashMap<String, MetricsMap.SubMapFactory<?>>(); + } + + public MetricsAdminI(Ice.Properties properties, Ice.Logger logger) + { + _logger = logger; + _properties = properties; + updateViews(); + } + + public void updateViews() + { + java.util.Set<MetricsMapFactory<?> > updatedMaps = new java.util.HashSet<MetricsMapFactory<?> >(); + synchronized(this) + { + String viewsPrefix = "IceMX.Metrics."; + java.util.Map<String, String> viewsProps = _properties.getPropertiesForPrefix(viewsPrefix); + java.util.Map<String, MetricsViewI> views = new java.util.HashMap<String, MetricsViewI>(); + _disabledViews.clear(); + for(java.util.Map.Entry<String, String> e : viewsProps.entrySet()) + { + String viewName = e.getKey().substring(viewsPrefix.length()); + int dotPos = viewName.indexOf('.'); + if(dotPos > 0) + { + viewName = viewName.substring(0, dotPos); + } + + if(views.containsKey(viewName) || _disabledViews.contains(viewName)) + { + continue; // View already configured. + } + + validateProperties(viewsPrefix + viewName + ".", _properties); + + if(_properties.getPropertyAsIntWithDefault(viewsPrefix + viewName + ".Disabled", 0) > 0) + { + _disabledViews.add(viewName); + continue; // The view is disabled + } + + // + // Create the view or update it. + // + MetricsViewI v = _views.get(viewName); + if(v == null) + { + v = new MetricsViewI(viewName); + } + views.put(viewName, v); + + for(java.util.Map.Entry<String, MetricsMapFactory<?>> f : _factories.entrySet()) + { + if(v.addOrUpdateMap(_properties, f.getKey(), f.getValue(), _logger)) + { + updatedMaps.add(f.getValue()); + } + } + } + java.util.Map<String, MetricsViewI> tmp = _views; + _views = views; + views = tmp; + + // + // Go through removed views to collect maps to update. + // + for(java.util.Map.Entry<String, MetricsViewI> v : views.entrySet()) + { + if(!_views.containsKey(v.getKey())) + { + for(String n : v.getValue().getMaps()) + { + updatedMaps.add(_factories.get(n)); + } + } + } + } + + // + // Call the updaters to update the maps. + // + for(MetricsMapFactory<?> f : updatedMaps) + { + f.update(); + } + } + + @Override + synchronized public String[] + getMetricsViewNames(Ice.StringSeqHolder holder, Ice.Current current) + { + holder.value = _disabledViews.toArray(new String[_disabledViews.size()]); + return _views.keySet().toArray(new String[_views.size()]); + } + + @Override + public void + enableMetricsView(String name, Ice.Current current) + throws IceMX.UnknownMetricsView + { + synchronized(this) + { + getMetricsView(name); // Throws if unknown view. + _properties.setProperty("IceMX.Metrics." + name + ".Disabled", "0"); + } + updateViews(); + } + + @Override + public void + disableMetricsView(String name, Ice.Current current) + throws IceMX.UnknownMetricsView + { + synchronized(this) + { + getMetricsView(name); // Throws if unknown view. + _properties.setProperty("IceMX.Metrics." + name + ".Disabled", "1"); + } + updateViews(); + } + + @Override + synchronized public java.util.Map<String, IceMX.Metrics[]> + getMetricsView(String viewName, Ice.LongHolder holder, Ice.Current current) + throws IceMX.UnknownMetricsView + { + MetricsViewI view = getMetricsView(viewName); + holder.value = IceInternal.Time.currentMonotonicTimeMillis(); + if(view != null) + { + return view.getMetrics(); + } + return new java.util.HashMap<String, IceMX.Metrics[]>(); + } + + @Override + synchronized public IceMX.MetricsFailures[] + getMapMetricsFailures(String viewName, String mapName, Ice.Current current) + throws IceMX.UnknownMetricsView + { + MetricsViewI view = getMetricsView(viewName); + if(view != null) + { + return view.getFailures(mapName); + } + return new IceMX.MetricsFailures[0]; + } + + @Override + synchronized public IceMX.MetricsFailures + getMetricsFailures(String viewName, String mapName, String id, Ice.Current current) + throws IceMX.UnknownMetricsView + { + MetricsViewI view = getMetricsView(viewName); + if(view != null) + { + return view.getFailures(mapName, id); + } + return new IceMX.MetricsFailures(); + } + + public <T extends IceMX.Metrics> void + registerMap(String map, Class<T> cl, Runnable updater) + { + boolean updated; + MetricsMapFactory<T> factory; + synchronized(this) + { + factory = new MetricsMapFactory<T>(updater, cl); + _factories.put(map, factory); + updated = addOrUpdateMap(map, factory); + } + if(updated) + { + factory.update(); + } + } + + synchronized public <S extends IceMX.Metrics> void + registerSubMap(String map, String subMap, Class<S> cl, java.lang.reflect.Field field) + { + boolean updated; + MetricsMapFactory<?> factory; + synchronized(this) + { + factory = _factories.get(map); + if(factory == null) + { + return; + } + factory.registerSubMap(subMap, cl, field); + removeMap(map); + updated = addOrUpdateMap(map, factory); + } + if(updated) + { + factory.update(); + } + } + + public void + unregisterMap(String mapName) + { + boolean updated; + MetricsMapFactory<?> factory; + synchronized(this) + { + factory = _factories.remove(mapName); + if(factory == null) + { + return; + } + updated = removeMap(mapName); + } + if(updated) + { + factory.update(); + } + } + + public <T extends IceMX.Metrics> java.util.List<MetricsMap<T>> + getMaps(String mapName, Class<T> cl) + { + java.util.List<MetricsMap<T>> maps = new java.util.ArrayList<MetricsMap<T>>(); + for(MetricsViewI v : _views.values()) + { + MetricsMap<T> map = v.getMap(mapName, cl); + if(map != null) + { + maps.add(map); + } + } + return maps; + } + + public Ice.Logger + getLogger() + { + return _logger; + } + + @Override + public void + updated(java.util.Map<String, String> props) + { + for(java.util.Map.Entry<String, String> e : props.entrySet()) + { + if(e.getKey().indexOf("IceMX.") == 0) + { + // Udpate the metrics views using the new configuration. + try + { + updateViews(); + } + catch(Exception ex) + { + _logger.warning("unexpected exception while updating metrics view configuration:\n" + + ex.toString()); + } + return; + } + } + } + + private MetricsViewI + getMetricsView(String name) + throws IceMX.UnknownMetricsView + { + MetricsViewI view = _views.get(name); + if(view == null) + { + if(!_disabledViews.contains(name)) + { + throw new IceMX.UnknownMetricsView(); + } + return null; + } + return view; + } + + private boolean + addOrUpdateMap(String mapName, MetricsMapFactory<?> factory) + { + boolean updated = false; + for(MetricsViewI v : _views.values()) + { + updated |= v.addOrUpdateMap(_properties, mapName, factory, _logger); + } + return updated; + } + + private boolean + removeMap(String mapName) + { + boolean updated = false; + for(MetricsViewI v : _views.values()) + { + updated |= v.removeMap(mapName); + } + return updated; + } + + private Ice.Properties _properties; + final private Ice.Logger _logger; + final private java.util.Map<String, MetricsMapFactory<?>> _factories = + new java.util.HashMap<String, MetricsMapFactory<?>>(); + + private java.util.Map<String, MetricsViewI> _views = new java.util.HashMap<String, MetricsViewI>(); + private java.util.Set<String> _disabledViews = new java.util.HashSet<String>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/MetricsMap.java b/java-compat/src/Ice/src/main/java/IceInternal/MetricsMap.java new file mode 100644 index 00000000000..b4d6dfb10c2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/MetricsMap.java @@ -0,0 +1,517 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class MetricsMap<T extends IceMX.Metrics> +{ + public class Entry + { + Entry(T obj) + { + _object = obj; + } + + public void + failed(String exceptionName) + { + synchronized(MetricsMap.this) + { + ++_object.failures; + if(_failures == null) + { + _failures = new java.util.HashMap<String, Integer>(); + } + Integer count = _failures.get(exceptionName); + _failures.put(exceptionName, new Integer(count == null ? 1 : count + 1)); + } + } + + @SuppressWarnings("unchecked") + public <S extends IceMX.Metrics> MetricsMap<S>.Entry + getMatching(String mapName, IceMX.MetricsHelper<S> helper, Class<S> cl) + { + SubMap<S> m; + synchronized(MetricsMap.this) + { + m = _subMaps != null ? (SubMap<S>)_subMaps.get(mapName) : null; + if(m == null) + { + m = createSubMap(mapName, cl); + if(m == null) + { + return null; + } + if(_subMaps == null) + { + _subMaps = new java.util.HashMap<String, SubMap<?>>(); + } + _subMaps.put(mapName, m); + } + } + return m.getMatching(helper); + } + + public void + detach(long lifetime) + { + synchronized(MetricsMap.this) + { + _object.totalLifetime += lifetime; + if(--_object.current == 0) + { + detached(this); + } + } + } + + public void + execute(IceMX.Observer.MetricsUpdate<T> func) + { + synchronized(MetricsMap.this) + { + func.update(_object); + } + } + + public MetricsMap<?> + getMap() + { + return MetricsMap.this; + } + + private IceMX.MetricsFailures + getFailures() + { + if(_failures == null) + { + return null; + } + IceMX.MetricsFailures f = new IceMX.MetricsFailures(); + f.id = _object.id; + f.failures = new java.util.HashMap<String, Integer>(_failures); + return f; + } + + private void + attach(IceMX.MetricsHelper<T> helper) + { + ++_object.total; + ++_object.current; + helper.initMetrics(_object); + } + + private boolean + isDetached() + { + return _object.current == 0; + } + + @Override + @SuppressWarnings("unchecked") + public IceMX.Metrics + clone() + { + T metrics = (T)_object.clone(); + if(_subMaps != null) + { + for(SubMap<?> s : _subMaps.values()) + { + s.addSubMapToMetrics(metrics); + } + } + return metrics; + } + + private T _object; + private java.util.Map<String, Integer> _failures; + private java.util.Map<String, SubMap<?>> _subMaps; + } + + static class SubMap<S extends IceMX.Metrics> + { + public + SubMap(MetricsMap<S> map, java.lang.reflect.Field field) + { + _map = map; + _field = field; + } + + public MetricsMap<S>.Entry + getMatching(IceMX.MetricsHelper<S> helper) + { + return _map.getMatching(helper, null); + } + + public void + addSubMapToMetrics(IceMX.Metrics metrics) + { + try + { + _field.set(metrics, _map.getMetrics()); + } + catch(Exception ex) + { + assert(false); + } + } + + final private MetricsMap<S> _map; + final private java.lang.reflect.Field _field; + } + + static class SubMapCloneFactory<S extends IceMX.Metrics> + { + public SubMapCloneFactory(MetricsMap<S> map, java.lang.reflect.Field field) + { + _map = map; + _field = field; + } + + public SubMap<S> + create() + { + return new SubMap<S>(new MetricsMap<S>(_map), _field); + } + + final private MetricsMap<S> _map; + final private java.lang.reflect.Field _field; + } + + static class SubMapFactory<S extends IceMX.Metrics> + { + SubMapFactory(Class<S> cl, java.lang.reflect.Field field) + { + _class = cl; + _field = field; + } + + SubMapCloneFactory<S> + createCloneFactory(String subMapPrefix, Ice.Properties properties) + { + return new SubMapCloneFactory<S>(new MetricsMap<S>(subMapPrefix, _class, properties, null), _field); + } + + final private Class<S> _class; + final private java.lang.reflect.Field _field; + } + + MetricsMap(String mapPrefix, Class<T> cl, Ice.Properties props, java.util.Map<String, SubMapFactory<?>> subMaps) + { + MetricsAdminI.validateProperties(mapPrefix, props); + _properties = props.getPropertiesForPrefix(mapPrefix); + + _retain = props.getPropertyAsIntWithDefault(mapPrefix + "RetainDetached", 10); + _accept = parseRule(props, mapPrefix + "Accept"); + _reject = parseRule(props, mapPrefix + "Reject"); + _groupByAttributes = new java.util.ArrayList<String>(); + _groupBySeparators = new java.util.ArrayList<String>(); + _class = cl; + + String groupBy = props.getPropertyWithDefault(mapPrefix + "GroupBy", "id"); + if(!groupBy.isEmpty()) + { + String v = ""; + boolean attribute = Character.isLetter(groupBy.charAt(0)) || Character.isDigit(groupBy.charAt(0)); + if(!attribute) + { + _groupByAttributes.add(""); + } + + for(char p : groupBy.toCharArray()) + { + boolean isAlphaNum = Character.isLetter(p) || Character.isDigit(p) || p == '.'; + if(attribute && !isAlphaNum) + { + _groupByAttributes.add(v); + v = "" + p; + attribute = false; + } + else if(!attribute && isAlphaNum) + { + _groupBySeparators.add(v); + v = "" + p; + attribute = true; + } + else + { + v += p; + } + } + + if(attribute) + { + _groupByAttributes.add(v); + } + else + { + _groupBySeparators.add(v); + } + } + + if(subMaps != null && !subMaps.isEmpty()) + { + _subMaps = new java.util.HashMap<String, SubMapCloneFactory<?>>(); + + java.util.List<String> subMapNames = new java.util.ArrayList<String>(); + for(java.util.Map.Entry<String, SubMapFactory<?>> e : subMaps.entrySet()) + { + subMapNames.add(e.getKey()); + String subMapsPrefix = mapPrefix + "Map."; + String subMapPrefix = subMapsPrefix + e.getKey() + '.'; + if(props.getPropertiesForPrefix(subMapPrefix).isEmpty()) + { + if(props.getPropertiesForPrefix(subMapsPrefix).isEmpty()) + { + subMapPrefix = mapPrefix; + } + else + { + continue; // This sub-map isn't configured. + } + } + + _subMaps.put(e.getKey(), e.getValue().createCloneFactory(subMapPrefix, props)); + } + } + else + { + _subMaps = null; + } + } + + MetricsMap(MetricsMap<T> map) + { + _properties = map._properties; + _groupByAttributes = map._groupByAttributes; + _groupBySeparators = map._groupBySeparators; + _retain = map._retain; + _accept = map._accept; + _reject = map._reject; + _class = map._class; + _subMaps = map._subMaps; + } + + java.util.Map<String, String> + getProperties() + { + return _properties; + } + + synchronized IceMX.Metrics[] + getMetrics() + { + IceMX.Metrics[] metrics = new IceMX.Metrics[_objects.size()]; + int i = 0; + for(Entry e : _objects.values()) + { + metrics[i++] = e.clone(); + } + return metrics; + } + + synchronized IceMX.MetricsFailures[] + getFailures() + { + java.util.List<IceMX.MetricsFailures> failures = new java.util.ArrayList<IceMX.MetricsFailures>(); + for(Entry e : _objects.values()) + { + IceMX.MetricsFailures f = e.getFailures(); + if(f != null) + { + failures.add(f); + } + } + return failures.toArray(new IceMX.MetricsFailures[failures.size()]); + } + + synchronized IceMX.MetricsFailures + getFailures(String id) + { + Entry e = _objects.get(id); + if(e != null) + { + return e.getFailures(); + } + return null; + } + + @SuppressWarnings("unchecked") + public <S extends IceMX.Metrics> SubMap<S> + createSubMap(String subMapName, Class<S> cl) + { + if(_subMaps == null) + { + return null; + } + SubMapCloneFactory<S> factory = (SubMapCloneFactory<S>)_subMaps.get(subMapName); + if(factory != null) + { + return factory.create(); + } + return null; + } + + public Entry + getMatching(IceMX.MetricsHelper<T> helper, Entry previous) + { + // + // Check the accept and reject filters. + // + for(java.util.Map.Entry<String, java.util.regex.Pattern> e : _accept.entrySet()) + { + if(!match(e.getKey(), e.getValue(), helper, false)) + { + return null; + } + } + + for(java.util.Map.Entry<String, java.util.regex.Pattern> e : _reject.entrySet()) + { + if(match(e.getKey(), e.getValue(), helper, true)) + { + return null; + } + } + + // + // Compute the key from the GroupBy property. + // + String key; + try + { + if(_groupByAttributes.size() == 1) + { + key = helper.resolve(_groupByAttributes.get(0)); + } + else + { + StringBuilder os = new StringBuilder(); + java.util.Iterator<String> q = _groupBySeparators.iterator(); + for(String p : _groupByAttributes) + { + os.append(helper.resolve(p)); + if(q.hasNext()) + { + os.append(q.next()); + } + } + key = os.toString(); + } + } + catch(Exception ex) + { + return null; + } + + // + // Lookup the metrics object. + // + synchronized(this) + { + if(previous != null && previous._object.id.equals(key)) + { + assert(_objects.get(key) == previous); + return previous; + } + + Entry e = _objects.get(key); + if(e == null) + { + try + { + T t = _class.newInstance(); + t.id = key; + e = new Entry(t); + _objects.put(key, e); + } + catch(Exception ex) + { + assert(false); + } + } + e.attach(helper); + return e; + } + } + + private void + detached(Entry entry) + { + if(_retain == 0) + { + return; + } + + if(_detachedQueue == null) + { + _detachedQueue = new java.util.LinkedList<Entry>(); + } + assert(_detachedQueue.size() <= _retain); + + // Compress the queue by removing entries which are no longer detached. + java.util.Iterator<Entry> p = _detachedQueue.iterator(); + while(p.hasNext()) + { + Entry e = p.next(); + if(e == entry || !e.isDetached()) + { + p.remove(); + } + } + + // If there's still no room, remove the oldest entry (at the front). + if(_detachedQueue.size() == _retain) + { + _objects.remove(_detachedQueue.pollFirst()._object.id); + } + + // Add the entry at the back of the queue. + _detachedQueue.add(entry); + } + + private java.util.Map<String, java.util.regex.Pattern> + parseRule(Ice.Properties properties, String name) + { + java.util.Map<String, java.util.regex.Pattern> pats = new java.util.HashMap<String, java.util.regex.Pattern>(); + java.util.Map<String, String> rules = properties.getPropertiesForPrefix(name + '.'); + for(java.util.Map.Entry<String,String> e : rules.entrySet()) + { + pats.put(e.getKey().substring(name.length() + 1), java.util.regex.Pattern.compile(e.getValue())); + } + return pats; + } + + private boolean + match(String attribute, java.util.regex.Pattern regex, IceMX.MetricsHelper<T> helper, boolean reject) + { + String value; + try + { + value = helper.resolve(attribute); + } + catch(Exception ex) + { + return !reject; + } + return regex.matcher(value).matches(); + } + + final private java.util.Map<String, String> _properties; + final private java.util.List<String> _groupByAttributes; + final private java.util.List<String> _groupBySeparators; + final private int _retain; + final private java.util.Map<String, java.util.regex.Pattern> _accept; + final private java.util.Map<String, java.util.regex.Pattern> _reject; + final private Class<T> _class; + + final private java.util.Map<String, Entry> _objects = new java.util.HashMap<String, Entry>(); + final private java.util.Map<String, SubMapCloneFactory<?>> _subMaps; + private java.util.Deque<Entry> _detachedQueue; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/MetricsViewI.java b/java-compat/src/Ice/src/main/java/IceInternal/MetricsViewI.java new file mode 100644 index 00000000000..c45aedff457 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/MetricsViewI.java @@ -0,0 +1,126 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class MetricsViewI +{ + MetricsViewI(String name) + { + _name = name; + } + + public boolean + addOrUpdateMap(Ice.Properties properties, String mapName, MetricsAdminI.MetricsMapFactory<?> factory, + Ice.Logger logger) + { + // + // Add maps to views configured with the given map. + // + String viewPrefix = "IceMX.Metrics." + _name + "."; + String mapsPrefix = viewPrefix + "Map."; + java.util.Map<String, String> mapsProps = properties.getPropertiesForPrefix(mapsPrefix); + + String mapPrefix; + java.util.Map<String, String> mapProps = new java.util.HashMap<String, String>(); + if(!mapsProps.isEmpty()) + { + mapPrefix = mapsPrefix + mapName + "."; + mapProps = properties.getPropertiesForPrefix(mapPrefix); + if(mapProps.isEmpty()) + { + // This map isn't configured for this view. + return _maps.remove(mapName) != null; + } + } + else + { + mapPrefix = viewPrefix; + mapProps = properties.getPropertiesForPrefix(mapPrefix); + } + + if(properties.getPropertyAsInt(mapPrefix + "Disabled") > 0) + { + // This map is disabled for this view. + return _maps.remove(mapName) != null; + } + + MetricsMap<?> m = _maps.get(mapName); + if(m != null && m.getProperties().equals(mapProps)) + { + return false; // The map configuration didn't change, no need to re-create. + } + + try + { + _maps.put(mapName, factory.create(mapPrefix, properties)); + } + catch(Exception ex) + { + logger.warning("unexpected exception while creating metrics map:\n" + ex); + _maps.remove(mapName); + } + return true; + } + + public boolean + removeMap(String mapName) + { + return _maps.remove(mapName) != null; + } + + public java.util.Map<String, IceMX.Metrics[]> + getMetrics() + { + java.util.Map<String, IceMX.Metrics[]> metrics = new java.util.HashMap<String, IceMX.Metrics[]>(); + for(java.util.Map.Entry<String, MetricsMap<?>> e : _maps.entrySet()) + { + metrics.put(e.getKey(), e.getValue().getMetrics()); + } + return metrics; + } + + public IceMX.MetricsFailures[] + getFailures(String mapName) + { + MetricsMap<?> m = _maps.get(mapName); + if(m != null) + { + return m.getFailures(); + } + return null; + } + + public IceMX.MetricsFailures + getFailures(String mapName, String id) + { + MetricsMap<?> m = _maps.get(mapName); + if(m != null) + { + return m.getFailures(id); + } + return null; + } + + public java.util.Collection<String> + getMaps() + { + return _maps.keySet(); + } + + @SuppressWarnings("unchecked") + public <T extends IceMX.Metrics> MetricsMap<T> + getMap(String mapName, Class<T> cl) + { + return (MetricsMap<T>)_maps.get(mapName); + } + + final private String _name; + final private java.util.Map<String, MetricsMap<?>> _maps = new java.util.HashMap<String, MetricsMap<?>>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Network.java b/java-compat/src/Ice/src/main/java/IceInternal/Network.java new file mode 100644 index 00000000000..0e19cf0e0b0 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Network.java @@ -0,0 +1,1353 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class Network +{ + // ProtocolSupport + public final static int EnableIPv4 = 0; + public final static int EnableIPv6 = 1; + public final static int EnableBoth = 2; + + private static java.util.regex.Pattern IPV4_PATTERN = null; + private static java.util.regex.Pattern IPV6_PATTERN = null; + private final static String ipv4Pattern = + "(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])"; + private final static String ipv6Pattern = + "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-" + + "fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1" + + ",4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1," + + "4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-" + + "F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" + + "\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}" + + "[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"; + + static + { + try + { + IPV4_PATTERN = + java.util.regex.Pattern.compile(ipv4Pattern, java.util.regex.Pattern.CASE_INSENSITIVE); + IPV6_PATTERN = + java.util.regex.Pattern.compile(ipv6Pattern, java.util.regex.Pattern.CASE_INSENSITIVE); + } + catch (java.util.regex.PatternSyntaxException ex) + { + assert(false); + } + } + + public static boolean + isNumericAddress(String ipAddress) + { + java.util.regex.Matcher ipv4 = IPV4_PATTERN.matcher(ipAddress); + if(ipv4.matches()) + { + return true; + } + java.util.regex.Matcher ipv6 = IPV6_PATTERN.matcher(ipAddress); + return ipv6.matches(); + } + + public static boolean + connectionRefused(java.net.ConnectException ex) + { + // + // The JDK raises a generic ConnectException when the server + // actively refuses a connection. Unfortunately, our only + // choice is to search the exception message for + // distinguishing phrases. + // + + String msg = ex.getMessage(); + + if(msg != null) + { + msg = msg.toLowerCase(); + + final String[] msgs = + { + "connection refused", // ECONNREFUSED + "remote host refused an attempted connect operation" // ECONNREFUSED (AIX JDK 1.4.2) + }; + + for(String m : msgs) + { + if(msg.indexOf(m) != -1) + { + return true; + } + } + } + + return false; + } + + public static boolean + noMoreFds(java.lang.Throwable ex) + { + String msg = ex.getMessage(); + if(msg != null) + { + msg = msg.toLowerCase(); + + final String[] msgs = + { + "too many open files", // EMFILE + "file table overflow", // ENFILE + "too many open files in system" // ENFILE + }; + + for(String m : msgs) + { + if(msg.indexOf(m) != -1) + { + return true; + } + } + } + + return false; + } + + public static boolean + isIPv6Supported() + { + try + { + java.net.Socket socket = new java.net.Socket(); + socket.bind(new java.net.InetSocketAddress(java.net.InetAddress.getByName("::1"), 0)); + socket.close(); + return true; + } + catch(java.io.IOException ex) + { + return false; + } + } + + public static java.nio.channels.SocketChannel + createTcpSocket() + { + try + { + java.nio.channels.SocketChannel fd = java.nio.channels.SocketChannel.open(); + java.net.Socket socket = fd.socket(); + socket.setTcpNoDelay(true); + socket.setKeepAlive(true); + return fd; + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + public static java.nio.channels.ServerSocketChannel + createTcpServerSocket() + { + try + { + java.nio.channels.ServerSocketChannel fd = java.nio.channels.ServerSocketChannel.open(); + // + // It's not possible to set TCP_NODELAY or KEEP_ALIVE + // on a server socket in Java + // + //java.net.Socket socket = fd.socket(); + //socket.setTcpNoDelay(true); + //socket.setKeepAlive(true); + return fd; + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + public static java.nio.channels.DatagramChannel + createUdpSocket(java.net.InetSocketAddress addr) + { + try + { + // + // Use reflection so this code still compiles with older JDK versions. + // java.net.StandardProtocolFamily is new in JDK 1.7 + // + Class<?> c = Util.findClass("java.net.StandardProtocolFamily", null); + if(addr.getAddress().isMulticastAddress() && c != null) + { + // + // For multicast sockets with JDK 7 we must use the open overload that accepts + // ProtocolFamily and specify the ProtocolFamily that corresponds to the address + // type of the multicast groups that the channel will join. + // + String family = "INET"; + if(addr.getAddress() instanceof java.net.Inet6Address) + { + family = "INET6"; + } + java.lang.reflect.Method valueOf = c.getDeclaredMethod("valueOf", new Class<?>[]{String.class}); + + Object[] args = new Object[]{valueOf.invoke(null, new Object[]{family})}; + + java.lang.reflect.Method open = java.nio.channels.DatagramChannel.class.getDeclaredMethod( + "open", new Class<?>[]{Util.findClass("java.net.ProtocolFamily", null)}); + return (java.nio.channels.DatagramChannel)open.invoke(null, args); + } + else + { + return java.nio.channels.DatagramChannel.open(); + } + } + catch(IllegalAccessException ex) + { + throw new Ice.SocketException(ex); + } + catch(java.lang.reflect.InvocationTargetException ex) + { + throw new Ice.SocketException(ex); + } + catch(NoSuchMethodException ex) + { + throw new Ice.SocketException(ex); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + public static void + closeSocketNoThrow(java.nio.channels.SelectableChannel fd) + { + try + { + fd.close(); + } + catch(java.io.IOException ex) + { + // Ignore + } + } + + public static void + closeSocket(java.nio.channels.SelectableChannel fd) + { + try + { + fd.close(); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + public static void + setBlock(java.nio.channels.SelectableChannel fd, boolean block) + { + try + { + fd.configureBlocking(block); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static void + setReuseAddress(java.nio.channels.DatagramChannel fd, boolean reuse) + { + try + { + fd.socket().setReuseAddress(reuse); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static void + setReuseAddress(java.nio.channels.ServerSocketChannel fd, boolean reuse) + { + try + { + fd.socket().setReuseAddress(reuse); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static java.net.InetSocketAddress + doBind(java.nio.channels.ServerSocketChannel fd, java.net.InetSocketAddress addr, int backlog) + { + try + { + java.net.ServerSocket sock = fd.socket(); + sock.bind(addr, backlog); + return (java.net.InetSocketAddress)sock.getLocalSocketAddress(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static java.net.InetSocketAddress + doBind(java.nio.channels.DatagramChannel fd, java.net.InetSocketAddress addr) + { + try + { + java.net.DatagramSocket sock = fd.socket(); + sock.bind(addr); + return (java.net.InetSocketAddress)sock.getLocalSocketAddress(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static java.nio.channels.SocketChannel + doAccept(java.nio.channels.ServerSocketChannel afd) + { + java.nio.channels.SocketChannel fd = null; + while(true) + { + try + { + fd = afd.accept(); + break; + } + catch(java.io.IOException ex) + { + if(interrupted(ex)) + { + continue; + } + + throw new Ice.SocketException(ex); + } + } + + try + { + java.net.Socket socket = fd.socket(); + socket.setTcpNoDelay(true); + socket.setKeepAlive(true); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + + return fd; + } + + public static boolean + doConnect(java.nio.channels.SocketChannel fd, java.net.InetSocketAddress addr, + java.net.InetSocketAddress sourceAddr) + { + if(sourceAddr != null) + { + try + { + fd.bind(sourceAddr); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + try + { + if(!fd.connect(addr)) + { + return false; + } + } + catch(java.net.ConnectException ex) + { + closeSocketNoThrow(fd); + + if(connectionRefused(ex)) + { + throw new Ice.ConnectionRefusedException(ex); + } + else + { + throw new Ice.ConnectFailedException(ex); + } + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + catch(java.lang.SecurityException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + + if(System.getProperty("os.name").equals("Linux")) + { + // + // Prevent self connect (self connect happens on Linux when a client tries to connect to + // a server which was just deactivated if the client socket re-uses the same ephemeral + // port as the server). + // + if(addr.equals(fd.socket().getLocalSocketAddress())) + { + closeSocketNoThrow(fd); + throw new Ice.ConnectionRefusedException(); + } + } + return true; + } + + public static void + doFinishConnect(java.nio.channels.SocketChannel fd) + { + // + // Note: we don't close the socket if there's an exception. It's the responsibility + // of the caller to do so. + // + + try + { + if(!fd.finishConnect()) + { + throw new Ice.ConnectFailedException(); + } + + if(System.getProperty("os.name").equals("Linux")) + { + // + // Prevent self connect (self connect happens on Linux when a client tries to connect to + // a server which was just deactivated if the client socket re-uses the same ephemeral + // port as the server). + // + java.net.SocketAddress addr = fd.socket().getRemoteSocketAddress(); + if(addr != null && addr.equals(fd.socket().getLocalSocketAddress())) + { + throw new Ice.ConnectionRefusedException(); + } + } + } + catch(java.net.ConnectException ex) + { + if(connectionRefused(ex)) + { + throw new Ice.ConnectionRefusedException(ex); + } + else + { + throw new Ice.ConnectFailedException(ex); + } + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + public static void + doConnect(java.nio.channels.DatagramChannel fd, java.net.InetSocketAddress addr, + java.net.InetSocketAddress sourceAddr) + { + if(sourceAddr != null) + { + doBind(fd, sourceAddr); + } + + try + { + fd.connect(addr); + } + catch(java.net.ConnectException ex) + { + closeSocketNoThrow(fd); + + if(connectionRefused(ex)) + { + throw new Ice.ConnectionRefusedException(ex); + } + else + { + throw new Ice.ConnectFailedException(ex); + } + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static void + setSendBufferSize(java.nio.channels.SocketChannel fd, int size) + { + try + { + java.net.Socket socket = fd.socket(); + socket.setSendBufferSize(size); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static int + getSendBufferSize(java.nio.channels.SocketChannel fd) + { + int size; + try + { + java.net.Socket socket = fd.socket(); + size = socket.getSendBufferSize(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + return size; + } + + public static void + setRecvBufferSize(java.nio.channels.SocketChannel fd, int size) + { + try + { + java.net.Socket socket = fd.socket(); + socket.setReceiveBufferSize(size); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static int + getRecvBufferSize(java.nio.channels.SocketChannel fd) + { + int size; + try + { + java.net.Socket socket = fd.socket(); + size = socket.getReceiveBufferSize(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + return size; + } + + public static void + setRecvBufferSize(java.nio.channels.ServerSocketChannel fd, int size) + { + try + { + java.net.ServerSocket socket = fd.socket(); + socket.setReceiveBufferSize(size); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static int + getRecvBufferSize(java.nio.channels.ServerSocketChannel fd) + { + int size; + try + { + java.net.ServerSocket socket = fd.socket(); + size = socket.getReceiveBufferSize(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + return size; + } + + public static void + setSendBufferSize(java.nio.channels.DatagramChannel fd, int size) + { + try + { + java.net.DatagramSocket socket = fd.socket(); + socket.setSendBufferSize(size); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static int + getSendBufferSize(java.nio.channels.DatagramChannel fd) + { + int size; + try + { + java.net.DatagramSocket socket = fd.socket(); + size = socket.getSendBufferSize(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + return size; + } + + public static void + setRecvBufferSize(java.nio.channels.DatagramChannel fd, int size) + { + try + { + java.net.DatagramSocket socket = fd.socket(); + socket.setReceiveBufferSize(size); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + } + + public static int + getRecvBufferSize(java.nio.channels.DatagramChannel fd) + { + int size; + try + { + java.net.DatagramSocket socket = fd.socket(); + size = socket.getReceiveBufferSize(); + } + catch(java.io.IOException ex) + { + closeSocketNoThrow(fd); + throw new Ice.SocketException(ex); + } + return size; + } + + public static java.net.InetSocketAddress + getAddressForServer(String host, int port, int protocol, boolean preferIPv6) + { + if(host == null || host.length() == 0) + { + try + { + if(protocol != EnableIPv4) + { + return new java.net.InetSocketAddress(java.net.InetAddress.getByName("::0"), port); + } + else + { + return new java.net.InetSocketAddress(java.net.InetAddress.getByName("0.0.0.0"), port); + } + } + catch(java.net.UnknownHostException ex) + { + assert(false); + return null; + } + catch(java.lang.SecurityException ex) + { + throw new Ice.SocketException(ex); + } + } + return getAddresses(host, port, protocol, Ice.EndpointSelectionType.Ordered, preferIPv6, true).get(0); + } + + public static int + compareAddress(java.net.InetSocketAddress addr1, java.net.InetSocketAddress addr2) + { + if(addr1 == null) + { + if(addr2 == null) + { + return 0; + } + else + { + return -1; + } + } + else if(addr2 == null) + { + return 1; + } + + if(addr1.getPort() < addr2.getPort()) + { + return -1; + } + else if(addr2.getPort() < addr1.getPort()) + { + return 1; + } + + byte[] larr = addr1.getAddress().getAddress(); + byte[] rarr = addr2.getAddress().getAddress(); + if(larr.length < rarr.length) + { + return -1; + } + else if(rarr.length < larr.length) + { + return 1; + } + assert(larr.length == rarr.length); + + for(int i = 0; i < larr.length; i++) + { + if(larr[i] < rarr[i]) + { + return -1; + } + else if(rarr[i] < larr[i]) + { + return 1; + } + } + + return 0; + } + + public static java.net.InetAddress + getLocalAddress(int protocol) + { + java.net.InetAddress addr = null; + + try + { + addr = java.net.InetAddress.getLocalHost(); + } + catch(java.net.UnknownHostException ex) + { + // + // May be raised on DHCP systems. + // + } + catch(NullPointerException ex) + { + // + // Workaround for bug in JDK. + // + } + + if(addr == null || !isValidAddr(addr, protocol)) + { + // + // Iterate over the network interfaces and pick an IP + // address (preferably not the loopback address). + // + java.util.ArrayList<java.net.InetAddress> addrs = getLocalAddresses(protocol); + java.util.Iterator<java.net.InetAddress> iter = addrs.iterator(); + while(addr == null && iter.hasNext()) + { + java.net.InetAddress a = iter.next(); + if(protocol == EnableBoth || isValidAddr(a, protocol)) + { + addr = a; + } + } + + if(addr == null) + { + addr = getLoopbackAddresses(protocol)[0]; // Use the loopback address as the last resort. + } + } + + assert(addr != null); + return addr; + } + + public static java.util.List<java.net.InetSocketAddress> + getAddresses(String host, int port, int protocol, Ice.EndpointSelectionType selType, boolean preferIPv6, + boolean blocking) + { + if(!blocking) + { + if(!isNumericAddress(host)) + { + return null; // Can't get the address without blocking. + } + + java.util.List<java.net.InetSocketAddress> addrs = new java.util.ArrayList<java.net.InetSocketAddress>(); + try + { + addrs.add(new java.net.InetSocketAddress(java.net.InetAddress.getByName(host), port)); + } + catch(java.net.UnknownHostException ex) + { + assert(false); + } + return addrs; + } + + java.util.List<java.net.InetSocketAddress> addresses = new java.util.ArrayList<java.net.InetSocketAddress>(); + try + { + java.net.InetAddress[] addrs; + if(host == null || host.length() == 0) + { + addrs = getLoopbackAddresses(protocol); + } + else + { + addrs = java.net.InetAddress.getAllByName(host); + } + + for(java.net.InetAddress addr : addrs) + { + if(protocol == EnableBoth || isValidAddr(addr, protocol)) + { + addresses.add(new java.net.InetSocketAddress(addr, port)); + } + } + + if(selType == Ice.EndpointSelectionType.Random) + { + java.util.Collections.shuffle(addresses); + } + + if(protocol == EnableBoth) + { + if(preferIPv6) + { + java.util.Collections.sort(addresses, _preferIPv6Comparator); + } + else + { + java.util.Collections.sort(addresses, _preferIPv4Comparator); + } + } + } + catch(java.net.UnknownHostException ex) + { + throw new Ice.DNSException(0, host, ex); + } + catch(java.lang.SecurityException ex) + { + throw new Ice.SocketException(ex); + } + + // + // No Inet4Address/Inet6Address available. + // + if(addresses.isEmpty()) + { + throw new Ice.DNSException(0, host); + } + + return addresses; + } + + public static java.util.ArrayList<java.net.InetAddress> + getLocalAddresses(int protocol) + { + java.util.ArrayList<java.net.InetAddress> result = new java.util.ArrayList<java.net.InetAddress>(); + try + { + java.util.Enumeration<java.net.NetworkInterface> ifaces = java.net.NetworkInterface.getNetworkInterfaces(); + while(ifaces.hasMoreElements()) + { + java.net.NetworkInterface iface = ifaces.nextElement(); + java.util.Enumeration<java.net.InetAddress> addrs = iface.getInetAddresses(); + while(addrs.hasMoreElements()) + { + java.net.InetAddress addr = addrs.nextElement(); + if(!addr.isLoopbackAddress()) + { + if(protocol == EnableBoth || isValidAddr(addr, protocol)) + { + result.add(addr); + } + } + } + } + } + catch(java.net.SocketException ex) + { + throw new Ice.SocketException(ex); + } + catch(java.lang.SecurityException ex) + { + throw new Ice.SocketException(ex); + } + + return result; + } + + public static final class SocketPair + { + public java.nio.channels.spi.AbstractSelectableChannel source; + public java.nio.channels.WritableByteChannel sink; + } + + public static SocketPair + createPipe() + { + SocketPair fds = new SocketPair(); + try + { + java.nio.channels.Pipe pipe = java.nio.channels.Pipe.open(); + fds.sink = pipe.sink(); + fds.source = pipe.source(); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + return fds; + } + + public static java.util.ArrayList<String> + getHostsForEndpointExpand(String host, int protocolSupport, boolean includeLoopback) + { + boolean wildcard = (host == null || host.length() == 0); + if(!wildcard) + { + try + { + wildcard = java.net.InetAddress.getByName(host).isAnyLocalAddress(); + } + catch(java.net.UnknownHostException ex) + { + } + catch(java.lang.SecurityException ex) + { + throw new Ice.SocketException(ex); + } + } + + java.util.ArrayList<String> hosts = new java.util.ArrayList<String>(); + if(wildcard) + { + java.util.ArrayList<java.net.InetAddress> addrs = getLocalAddresses(protocolSupport); + for(java.net.InetAddress addr : addrs) + { + // + // NOTE: We don't publish link-local IPv6 addresses as these addresses can only + // be accessed in general with a scope-id. + // + if(!addr.isLinkLocalAddress()) + { + hosts.add(addr.getHostAddress()); + } + } + + if(includeLoopback || hosts.isEmpty()) + { + if(protocolSupport != EnableIPv6) + { + hosts.add("127.0.0.1"); + } + + if(protocolSupport != EnableIPv4) + { + hosts.add("0:0:0:0:0:0:0:1"); + } + } + } + return hosts; + } + + public static void + setTcpBufSize(java.nio.channels.SocketChannel socket, ProtocolInstance instance) + { + // + // By default, on Windows we use a 128KB buffer size. On Unix + // platforms, we use the system defaults. + // + int dfltBufSize = 0; + if(System.getProperty("os.name").startsWith("Windows")) + { + dfltBufSize = 128 * 1024; + } + + int rcvSize = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize); + int sndSize = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.SndSize", dfltBufSize); + + setTcpBufSize(socket, rcvSize, sndSize, instance); + } + + public static void + setTcpBufSize(java.nio.channels.SocketChannel socket, int rcvSize, int sndSize, ProtocolInstance instance) + { + if(rcvSize > 0) + { + // + // Try to set the buffer size. The kernel will silently adjust + // the size to an acceptable value. Then read the size back to + // get the size that was actually set. + // + setRecvBufferSize(socket, rcvSize); + int size = getRecvBufferSize(socket); + if(size < rcvSize) + { + // Warn if the size that was set is less than the requested size and + // we have not already warned. + BufSizeWarnInfo winfo = instance.getBufSizeWarn(Ice.TCPEndpointType.value); + if(!winfo.rcvWarn || rcvSize != winfo.rcvSize) + { + instance.logger().warning("TCP receive buffer size: requested size of " + rcvSize + + " adjusted to " + size); + instance.setRcvBufSizeWarn(Ice.TCPEndpointType.value, rcvSize); + } + } + } + + if(sndSize > 0) + { + // + // Try to set the buffer size. The kernel will silently adjust + // the size to an acceptable value. Then read the size back to + // get the size that was actually set. + // + setSendBufferSize(socket, sndSize); + int size = getSendBufferSize(socket); + if(size < sndSize) + { + // Warn if the size that was set is less than the requested size and + // we have not already warned. + BufSizeWarnInfo winfo = instance.getBufSizeWarn(Ice.TCPEndpointType.value); + if(!winfo.sndWarn || sndSize != winfo.sndSize) + { + instance.logger().warning("TCP send buffer size: requested size of " + sndSize + + " adjusted to " + size); + instance.setSndBufSizeWarn(Ice.TCPEndpointType.value, sndSize); + } + } + } + } + + public static void + setTcpBufSize(java.nio.channels.ServerSocketChannel socket, ProtocolInstance instance) + { + // + // By default, on Windows we use a 128KB buffer size. On Unix + // platforms, we use the system defaults. + // + int dfltBufSize = 0; + if(System.getProperty("os.name").startsWith("Windows")) + { + dfltBufSize = 128 * 1024; + } + + // + // Get property for buffer size. + // + int sizeRequested = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize); + if(sizeRequested > 0) + { + // + // Try to set the buffer size. The kernel will silently adjust + // the size to an acceptable value. Then read the size back to + // get the size that was actually set. + // + setRecvBufferSize(socket, sizeRequested); + int size = getRecvBufferSize(socket); + if(size < sizeRequested) + { + // Warn if the size that was set is less than the requested size and + // we have not already warned. + BufSizeWarnInfo winfo = instance.getBufSizeWarn(Ice.TCPEndpointType.value); + if(!winfo.rcvWarn || sizeRequested != winfo.rcvSize) + { + instance.logger().warning("TCP receive buffer size: requested size of " + sizeRequested + + " adjusted to " + size); + instance.setRcvBufSizeWarn(Ice.TCPEndpointType.value, sizeRequested); + } + } + } + } + + public static String + fdToString(java.nio.channels.SelectableChannel fd, NetworkProxy proxy, java.net.InetSocketAddress target) + { + if(fd == null) + { + return "<closed>"; + } + + java.net.InetAddress localAddr = null, remoteAddr = null; + int localPort = -1, remotePort = -1; + + if(fd instanceof java.nio.channels.SocketChannel) + { + java.net.Socket socket = ((java.nio.channels.SocketChannel)fd).socket(); + localAddr = socket.getLocalAddress(); + localPort = socket.getLocalPort(); + remoteAddr = socket.getInetAddress(); + remotePort = socket.getPort(); + } + else if(fd instanceof java.nio.channels.DatagramChannel) + { + java.net.DatagramSocket socket = ((java.nio.channels.DatagramChannel)fd).socket(); + localAddr = socket.getLocalAddress(); + localPort = socket.getLocalPort(); + remoteAddr = socket.getInetAddress(); + remotePort = socket.getPort(); + } + else + { + assert(false); + } + + return addressesToString(localAddr, localPort, remoteAddr, remotePort, proxy, target); + } + + public static String + fdToString(java.nio.channels.SelectableChannel fd) + { + if(fd == null) + { + return "<closed>"; + } + + java.net.InetAddress localAddr = null, remoteAddr = null; + int localPort = -1, remotePort = -1; + + if(fd instanceof java.nio.channels.SocketChannel) + { + java.net.Socket socket = ((java.nio.channels.SocketChannel)fd).socket(); + localAddr = socket.getLocalAddress(); + localPort = socket.getLocalPort(); + remoteAddr = socket.getInetAddress(); + remotePort = socket.getPort(); + } + else if(fd instanceof java.nio.channels.DatagramChannel) + { + java.net.DatagramSocket socket = ((java.nio.channels.DatagramChannel)fd).socket(); + localAddr = socket.getLocalAddress(); + localPort = socket.getLocalPort(); + remoteAddr = socket.getInetAddress(); + remotePort = socket.getPort(); + } + else + { + assert(false); + } + + return addressesToString(localAddr, localPort, remoteAddr, remotePort); + } + + public static String + addressesToString(java.net.InetAddress localAddr, int localPort, java.net.InetAddress remoteAddr, int remotePort, + NetworkProxy proxy, java.net.InetSocketAddress target) + { + StringBuilder s = new StringBuilder(128); + s.append("local address = "); + s.append(addrToString(localAddr, localPort)); + + if(proxy != null) + { + if(remoteAddr == null) + { + java.net.InetSocketAddress addr = proxy.getAddress(); + remoteAddr = addr.getAddress(); + remotePort = addr.getPort(); + } + s.append("\n"); + s.append(proxy.getName()); + s.append(" proxy address = "); + s.append(addrToString(remoteAddr, remotePort)); + s.append("\nremote address = "); + s.append(addrToString(target.getAddress(), target.getPort())); + } + else + { + if(remoteAddr == null && target != null) + { + remoteAddr = target.getAddress(); + remotePort = target.getPort(); + } + + if(remoteAddr == null) + { + s.append("\nremote address = <not connected>"); + } + else + { + s.append("\nremote address = "); + s.append(addrToString(remoteAddr, remotePort)); + } + } + + return s.toString(); + } + + public static String + addressesToString(java.net.InetAddress localAddr, int localPort, java.net.InetAddress remoteAddr, int remotePort) + { + return addressesToString(localAddr, localPort, remoteAddr, remotePort, null, null); + } + + public static String + addrToString(java.net.InetSocketAddress addr) + { + StringBuilder s = new StringBuilder(128); + s.append(addr.getAddress().getHostAddress()); + s.append(':'); + s.append(addr.getPort()); + return s.toString(); + } + + public static boolean + interrupted(java.io.IOException ex) + { + return ex instanceof java.io.InterruptedIOException; + } + + private static boolean + isValidAddr(java.net.InetAddress addr, int protocol) + { + byte[] bytes = null; + if(addr != null) + { + bytes = addr.getAddress(); + } + return bytes != null && + ((bytes.length == 16 && protocol == EnableIPv6) || + (bytes.length == 4 && protocol == EnableIPv4)); + } + + public static String + addrToString(java.net.InetAddress addr, int port) + { + StringBuffer s = new StringBuffer(); + + // + // In early Android releases, sockets don't correctly report their address and + // port information. + // + + if(addr == null || addr.isAnyLocalAddress()) + { + s.append("<not available>"); + } + else + { + s.append(addr.getHostAddress()); + } + + if(port > 0) + { + s.append(':'); + s.append(port); + } + + return s.toString(); + } + + private static java.net.InetAddress[] + getLoopbackAddresses(int protocol) + { + try + { + java.net.InetAddress[] addrs = new java.net.InetAddress[protocol == EnableBoth ? 2 : 1]; + int i = 0; + if(protocol != EnableIPv6) + { + addrs[i++] = java.net.InetAddress.getByName("127.0.0.1"); + } + if(protocol != EnableIPv4) + { + addrs[i++] = java.net.InetAddress.getByName("::1"); + } + return addrs; + } + catch(java.net.UnknownHostException ex) + { + assert(false); + return null; + } + catch(java.lang.SecurityException ex) + { + throw new Ice.SocketException(ex); + } + } + + public static java.net.InetSocketAddress + getNumericAddress(String address) + { + java.net.InetSocketAddress addr = null; + if(!address.isEmpty() && isNumericAddress(address)) + { + try + { + addr = new java.net.InetSocketAddress(java.net.InetAddress.getByName(address), 0); + } + catch(java.net.UnknownHostException ex) + { + } + } + return addr; + } + + static class IPAddressComparator implements java.util.Comparator<java.net.InetSocketAddress> + { + IPAddressComparator(boolean ipv6) + { + _ipv6 = ipv6; + } + + @Override + public int + compare(java.net.InetSocketAddress lhs, java.net.InetSocketAddress rhs) + { + if(lhs.getAddress().getAddress().length < rhs.getAddress().getAddress().length) + { + return _ipv6 ? 1 : -1; + } + else if(lhs.getAddress().getAddress().length > rhs.getAddress().getAddress().length) + { + return _ipv6 ? -1 : 1; + } + else + { + return 0; + } + } + + final private boolean _ipv6; + } + + private static IPAddressComparator _preferIPv4Comparator = new IPAddressComparator(false); + private static IPAddressComparator _preferIPv6Comparator = new IPAddressComparator(true); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/NetworkProxy.java b/java-compat/src/Ice/src/main/java/IceInternal/NetworkProxy.java new file mode 100644 index 00000000000..80dcce87d3e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/NetworkProxy.java @@ -0,0 +1,60 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface NetworkProxy +{ + // + // Write the connection request on the connection established + // with the network proxy server. This is called right after + // the connection establishment succeeds. + // + void beginWrite(java.net.InetSocketAddress endpoint, Buffer buf); + int endWrite(Buffer buf); + + // + // Once the connection request has been sent, this is called + // to prepare and read the response from the proxy server. + // + void beginRead(Buffer buf); + int endRead(Buffer buf); + + // + // This is called when the response from the proxy has been + // read. The proxy should copy the extra read data (if any) in the + // given byte vector. + // + void finish(Buffer readBuffer, Buffer writeBuffer); + + // + // If the proxy host needs to be resolved, this should return + // a new NetworkProxy containing the IP address of the proxy. + // This is called from the endpoint host resolver thread, so + // it's safe if this this method blocks. + // + NetworkProxy resolveHost(int protocolSupport); + + // + // Returns the IP address of the network proxy. This method + // must not block. It's only called on a network proxy object + // returned by resolveHost(). + // + java.net.InetSocketAddress getAddress(); + + // + // Returns the name of the proxy, used for tracing purposes. + // + String getName(); + + // + // Returns the protocols supported by the proxy. + // + int getProtocolSupport(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ObjectAdapterFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/ObjectAdapterFactory.java new file mode 100644 index 00000000000..bfec67de6a6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ObjectAdapterFactory.java @@ -0,0 +1,268 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ObjectAdapterFactory +{ + public void + shutdown() + { + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + // + // Ignore shutdown requests if the object adapter factory has + // already been shut down. + // + if(_instance == null) + { + return; + } + + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + // + // Deactivate outside the thread synchronization, to avoid + // deadlocks. + // + for(Ice.ObjectAdapterI adapter : adapters) + { + adapter.deactivate(); + } + + synchronized(this) + { + _instance = null; + _communicator = null; + notifyAll(); + } + } + + + public void + waitForShutdown() + { + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + // + // First we wait for the shutdown of the factory itself. + // + while(_instance != null) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + // + // Now we wait for deactivation of each object adapter. + // + for(Ice.ObjectAdapterI adapter : adapters) + { + adapter.waitForDeactivate(); + } + } + + public synchronized boolean + isShutdown() + { + return _instance == null; + } + + public void + destroy() + { + // + // First wait for shutdown to finish. + // + waitForShutdown(); + + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + for(Ice.ObjectAdapterI adapter : adapters) + { + adapter.destroy(); + } + + synchronized(this) + { + _adapters.clear(); + } + } + + public void + updateConnectionObservers() + { + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + for(Ice.ObjectAdapterI adapter : adapters) + { + adapter.updateConnectionObservers(); + } + } + + public void + updateThreadObservers() + { + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + for(Ice.ObjectAdapterI adapter : adapters) + { + adapter.updateThreadObservers(); + } + } + + public synchronized Ice.ObjectAdapter + createObjectAdapter(String name, Ice.RouterPrx router) + { + if(Thread.interrupted()) + { + throw new Ice.OperationInterruptedException(); + } + + if(_instance == null) + { + throw new Ice.CommunicatorDestroyedException(); + } + + Ice.ObjectAdapterI adapter = null; + if(name.length() == 0) + { + String uuid = java.util.UUID.randomUUID().toString(); + adapter = new Ice.ObjectAdapterI(_instance, _communicator, this, uuid, null, true); + } + else + { + if(_adapterNamesInUse.contains(name)) + { + throw new Ice.AlreadyRegisteredException("object adapter", name); + } + adapter = new Ice.ObjectAdapterI(_instance, _communicator, this, name, router, false); + _adapterNamesInUse.add(name); + } + _adapters.add(adapter); + return adapter; + } + + public Ice.ObjectAdapter + findObjectAdapter(Ice.ObjectPrx proxy) + { + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + if(_instance == null) + { + return null; + } + + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + for(Ice.ObjectAdapterI adapter : adapters) + { + try + { + if(adapter.isLocal(proxy)) + { + return adapter; + } + } + catch(Ice.ObjectAdapterDeactivatedException ex) + { + // Ignore. + } + } + + return null; + } + + public synchronized void + removeObjectAdapter(Ice.ObjectAdapter adapter) + { + if(_instance == null) + { + return; + } + + _adapters.remove(adapter); + _adapterNamesInUse.remove(adapter.getName()); + } + + public void + flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) + { + java.util.List<Ice.ObjectAdapterI> adapters; + synchronized(this) + { + adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(_adapters); + } + + for(Ice.ObjectAdapterI adapter : adapters) + { + adapter.flushAsyncBatchRequests(outAsync); + } + } + + // + // Only for use by Instance. + // + ObjectAdapterFactory(Instance instance, Ice.Communicator communicator) + { + _instance = instance; + _communicator = communicator; + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_instance == null); + IceUtilInternal.Assert.FinalizerAssert(_communicator == null); + IceUtilInternal.Assert.FinalizerAssert(_adapters.isEmpty()); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private Instance _instance; + private Ice.Communicator _communicator; + private java.util.Set<String> _adapterNamesInUse = new java.util.HashSet<String>(); + private java.util.List<Ice.ObjectAdapterI> _adapters = new java.util.LinkedList<Ice.ObjectAdapterI>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ObjectInputStream.java b/java-compat/src/Ice/src/main/java/IceInternal/ObjectInputStream.java new file mode 100644 index 00000000000..ea1e7167f4c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ObjectInputStream.java @@ -0,0 +1,52 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// We need to override the resolveClass method of ObjectInputStream so +// that we can use the same class-lookup mechanism as elsewhere in the +// Ice run time. +// + +public class ObjectInputStream extends java.io.ObjectInputStream +{ + public ObjectInputStream(Instance instance, java.io.InputStream in) + throws java.io.IOException + { + super(in); + _instance = instance; + } + + @Override + protected Class<?> resolveClass(java.io.ObjectStreamClass cls) + throws java.io.IOException, ClassNotFoundException + { + if(_instance == null) + { + throw new Ice.MarshalException("cannot unmarshal a serializable without a communicator"); + } + + try + { + Class<?> c = _instance.findClass(cls.getName()); + if(c != null) + { + return c; + } + throw new ClassNotFoundException("unable to resolve class" + cls.getName()); + } + catch(Exception ex) + { + throw new ClassNotFoundException("unable to resolve class " + cls.getName(), ex); + } + } + + private Instance _instance; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ObserverHelper.java b/java-compat/src/Ice/src/main/java/IceInternal/ObserverHelper.java new file mode 100644 index 00000000000..290be728304 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ObserverHelper.java @@ -0,0 +1,65 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import Ice.Instrumentation.CommunicatorObserver; +import Ice.Instrumentation.InvocationObserver; + +public final class ObserverHelper +{ + static public InvocationObserver + get(Instance instance, String op) + { + CommunicatorObserver obsv = instance.initializationData().observer; + if(obsv != null) + { + InvocationObserver observer = obsv.getInvocationObserver(null, op, _emptyContext); + if(observer != null) + { + observer.attach(); + } + return observer; + } + return null; + } + + static public InvocationObserver + get(Ice.ObjectPrx proxy, String op) + { + return get(proxy, op, null); + } + + static public InvocationObserver + get(Ice.ObjectPrx proxy, String op, java.util.Map<String, String> context) + { + CommunicatorObserver obsv = + ((Ice.ObjectPrxHelperBase)proxy).__reference().getInstance().initializationData().observer; + if(obsv != null) + { + InvocationObserver observer; + if(context == null) + { + observer = obsv.getInvocationObserver(proxy, op, _emptyContext); + } + else + { + observer = obsv.getInvocationObserver(proxy, op, context); + } + if(observer != null) + { + observer.attach(); + } + return observer; + } + return null; + } + + private static final java.util.Map<String, String> _emptyContext = new java.util.HashMap<String, String>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/OpaqueEndpointI.java b/java-compat/src/Ice/src/main/java/IceInternal/OpaqueEndpointI.java new file mode 100644 index 00000000000..c6c6b849ba5 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/OpaqueEndpointI.java @@ -0,0 +1,422 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class OpaqueEndpointI extends EndpointI +{ + public OpaqueEndpointI(java.util.ArrayList<String> args) + { + _type = -1; + _rawEncoding = Ice.Util.Encoding_1_0; + _rawBytes = new byte[0]; + + initWithOptions(args); + + if(_type < 0) + { + throw new Ice.EndpointParseException("no -t option in endpoint " + toString()); + } + if(_rawBytes.length == 0) + { + throw new Ice.EndpointParseException("no -v option in endpoint " + toString()); + } + + calcHashValue(); + } + + public OpaqueEndpointI(short type, Ice.InputStream s) + { + _type = type; + _rawEncoding = s.getEncoding(); + int sz = s.getEncapsulationSize(); + _rawBytes = s.readBlob(sz); + + calcHashValue(); + } + + // + // Marshal the endpoint + // + @Override + public void streamWrite(Ice.OutputStream s) + { + s.startEncapsulation(_rawEncoding, Ice.FormatType.DefaultFormat); + s.writeBlob(_rawBytes); + s.endEncapsulation(); + } + + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + assert(false); + } + + // + // Return the endpoint information. + // + @Override + public Ice.EndpointInfo getInfo() + { + return new Ice.OpaqueEndpointInfo(null, -1, false, _rawEncoding, _rawBytes) + { + @Override + public short type() + { + return _type; + } + + @Override + public boolean datagram() + { + return false; + } + + @Override + public boolean secure() + { + return false; + } + }; + } + + // + // Return the endpoint type + // + @Override + public short type() + { + return _type; + } + + // + // Return the protocol name + // + @Override + public String protocol() + { + return "opaque"; + } + + // + // Return the timeout for the endpoint in milliseconds. 0 means + // non-blocking, -1 means no timeout. + // + @Override + public int timeout() + { + return -1; + } + + // + // Return a new endpoint with a different timeout value, provided + // that timeouts are supported by the endpoint. Otherwise the same + // endpoint is returned. + // + @Override + public EndpointI timeout(int t) + { + return this; + } + + @Override + public String connectionId() + { + return ""; + } + + // + // Return a new endpoint with a different connection id. + // + @Override + public EndpointI connectionId(String connectionId) + { + return this; + } + + // + // Return true if the endpoints support bzip2 compress, or false + // otherwise. + // + @Override + public boolean compress() + { + return false; + } + + // + // Return a new endpoint with a different compression value, + // provided that compression is supported by the + // endpoint. Otherwise the same endpoint is returned. + // + @Override + public EndpointI compress(boolean compress) + { + return this; + } + + // + // Return true if the endpoint is datagram-based. + // + @Override + public boolean datagram() + { + return false; + } + + // + // Return true if the endpoint is secure. + // + @Override + public boolean secure() + { + return false; + } + + // + // Return a server side transceiver for this endpoint, or null if a + // transceiver can only be created by an acceptor.d. + // + @Override + public Transceiver transceiver() + { + return null; + } + + // + // Return connectors for this endpoint, or empty list if no connector + // is available. + // + @Override + public void connectors_async(Ice.EndpointSelectionType selType, EndpointI_connectors callback) + { + callback.connectors(new java.util.ArrayList<Connector>()); + } + + // + // Return an acceptor for this endpoint, or null if no acceptors + // is available. + // + @Override + public Acceptor acceptor(String adapterName) + { + return null; + } + + // + // Expand endpoint out in to separate endpoints for each local + // host if listening on INADDR_ANY on server side or if no host + // was specified on client side. + // + @Override + public java.util.List<EndpointI> expand() + { + java.util.List<EndpointI> endps = new java.util.ArrayList<EndpointI>(); + endps.add(this); + return endps; + } + + // + // Check whether the endpoint is equivalent to another one. + // + @Override + public boolean equivalent(EndpointI endpoint) + { + return false; + } + + @Override + public int hashCode() + { + return _hashCode; + } + + @Override + public String options() + { + String s = ""; + if(_type > -1) + { + s += " -t " + _type; + } + s += " -e " + Ice.Util.encodingVersionToString(_rawEncoding); + if(_rawBytes.length > 0) + { + s += " -v " + IceUtilInternal.Base64.encode(_rawBytes); + } + return s; + } + + // + // Compare endpoints for sorting purposes + // + @Override + public int compareTo(EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof OpaqueEndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + OpaqueEndpointI p = (OpaqueEndpointI)obj; + if(this == p) + { + return 0; + } + + if(_type < p._type) + { + return -1; + } + else if(p._type < _type) + { + return 1; + } + + if(_rawEncoding.major < p._rawEncoding.major) + { + return -1; + } + else if(p._rawEncoding.major < _rawEncoding.major) + { + return 1; + } + + if(_rawEncoding.minor < p._rawEncoding.minor) + { + return -1; + } + else if(p._rawEncoding.minor < _rawEncoding.minor) + { + return 1; + } + + if(_rawBytes.length < p._rawBytes.length) + { + return -1; + } + else if(p._rawBytes.length < _rawBytes.length) + { + return 1; + } + for(int i = 0; i < _rawBytes.length; i++) + { + if(_rawBytes[i] < p._rawBytes[i]) + { + return -1; + } + else if(p._rawBytes[i] < _rawBytes[i]) + { + return 1; + } + } + + return 0; + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + switch(option.charAt(1)) + { + case 't': + { + if(_type > -1) + { + throw new Ice.EndpointParseException("multiple -t options in endpoint " + endpoint); + } + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint); + } + + int t; + try + { + t = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid type value `" + argument + "' in endpoint " + endpoint); + } + + if(t < 0 || t > 65535) + { + throw new Ice.EndpointParseException("type value `" + argument + "' out of range in endpoint " + + endpoint); + } + + _type = (short)t; + return true; + } + + case 'v': + { + if(_rawBytes.length > 0) + { + throw new Ice.EndpointParseException("multiple -v options in endpoint " + endpoint); + } + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -v option in endpoint " + endpoint); + } + + for(int j = 0; j < argument.length(); ++j) + { + if(!IceUtilInternal.Base64.isBase64(argument.charAt(j))) + { + throw new Ice.EndpointParseException("invalid base64 character `" + argument.charAt(j) + + "' (ordinal " + ((int)argument.charAt(j)) + + ") in endpoint " + endpoint); + } + } + _rawBytes = IceUtilInternal.Base64.decode(argument); + return true; + } + + case 'e': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -e option in endpoint " + endpoint); + } + + try + { + _rawEncoding = Ice.Util.stringToEncodingVersion(argument); + } + catch(Ice.VersionParseException e) + { + throw new Ice.EndpointParseException("invalid encoding version `" + argument + + "' in endpoint " + endpoint + ":\n" + e.str); + } + return true; + } + + default: + { + return false; + } + } + } + + private void calcHashValue() + { + int h = 5381; + h = IceInternal.HashUtil.hashAdd(h, _type); + h = IceInternal.HashUtil.hashAdd(h, _rawEncoding); + h = IceInternal.HashUtil.hashAdd(h, _rawBytes); + _hashCode = h; + } + + private short _type; + private Ice.EncodingVersion _rawEncoding; + private byte[] _rawBytes; + private int _hashCode; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/OutgoingAsync.java b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingAsync.java new file mode 100644 index 00000000000..85e5522be77 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingAsync.java @@ -0,0 +1,444 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class OutgoingAsync extends ProxyOutgoingAsyncBase +{ + public static OutgoingAsync check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (OutgoingAsync)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + public OutgoingAsync(Ice.ObjectPrx prx, String operation, CallbackBase cb) + { + super((Ice.ObjectPrxHelperBase)prx, operation, cb); + _encoding = Protocol.getCompatibleEncoding(_proxy.__reference().getEncoding()); + _is = null; + } + + public OutgoingAsync(Ice.ObjectPrx prx, String operation, CallbackBase cb, Ice.InputStream is, Ice.OutputStream os) + { + super((Ice.ObjectPrxHelperBase)prx, operation, cb, os); + _encoding = Protocol.getCompatibleEncoding(_proxy.__reference().getEncoding()); + _is = is; + } + + public void prepare(String operation, Ice.OperationMode mode, java.util.Map<String, String> ctx, + boolean explicitCtx, boolean synchronous) + { + Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(_proxy.__reference().getProtocol())); + + _mode = mode; + _synchronous = synchronous; + + if(explicitCtx && ctx == null) + { + ctx = _emptyContext; + } + _observer = ObserverHelper.get(_proxy, operation, ctx); + + switch(_proxy.__reference().getMode()) + { + case Reference.ModeTwoway: + case Reference.ModeOneway: + case Reference.ModeDatagram: + { + _os.writeBlob(IceInternal.Protocol.requestHdr); + break; + } + + case Reference.ModeBatchOneway: + case Reference.ModeBatchDatagram: + { + _proxy.__getBatchRequestQueue().prepareBatchRequest(_os); + break; + } + } + + Reference ref = _proxy.__reference(); + + ref.getIdentity().__write(_os); + + // + // For compatibility with the old FacetPath. + // + String facet = ref.getFacet(); + if(facet == null || facet.length() == 0) + { + _os.writeStringSeq(null); + } + else + { + String[] facetPath = { facet }; + _os.writeStringSeq(facetPath); + } + + _os.writeString(operation); + + _os.writeByte((byte) mode.value()); + + if(ctx != null) + { + // + // Explicit context + // + Ice.ContextHelper.write(_os, ctx); + } + else + { + // + // Implicit context + // + Ice.ImplicitContextI implicitContext = ref.getInstance().getImplicitContext(); + java.util.Map<String, String> prxContext = ref.getContext(); + + if(implicitContext == null) + { + Ice.ContextHelper.write(_os, prxContext); + } + else + { + implicitContext.write(prxContext, _os); + } + } + } + + @Override + public boolean sent() + { + return sent(!_proxy.ice_isTwoway()); // done = true if not a two-way proxy (no response expected) + } + + @Override + public int invokeRemote(Ice.ConnectionI connection, boolean compress, boolean response) throws RetryException + { + _cachedConnection = connection; + return connection.sendAsyncRequest(this, compress, response, 0); + } + + @Override + public int invokeCollocated(CollocatedRequestHandler handler) + { + // The stream cannot be cached if the proxy is not a twoway or there is an invocation timeout set. + if(!_proxy.ice_isTwoway() || _proxy.__reference().getInvocationTimeout() > 0) + { + // Disable caching by marking the streams as cached! + _state |= StateCachedBuffers; + } + return handler.invokeAsyncRequest(this, 0, _synchronous); + } + + @Override + public void abort(Ice.Exception ex) + { + int mode = _proxy.__reference().getMode(); + if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram) + { + // + // If we didn't finish a batch oneway or datagram request, we + // must notify the connection about that we give up ownership + // of the batch stream. + // + _proxy.__getBatchRequestQueue().abortBatchRequest(_os); + } + + super.abort(ex); + } + + public void invoke() + { + int mode = _proxy.__reference().getMode(); + if(mode == Reference.ModeBatchOneway || mode == Reference.ModeBatchDatagram) + { + // + // NOTE: we don't call sent/completed callbacks for batch AMI requests + // + _sentSynchronously = true; + _proxy.__getBatchRequestQueue().finishBatchRequest(_os, _proxy, getOperation()); + finished(true); + } + else + { + // + // NOTE: invokeImpl doesn't throw so this can be called from the + // try block with the catch block calling abort() in case of an + // exception. + // + invokeImpl(true); // userThread = true + } + } + + @Override + public final boolean completed(Ice.InputStream is) + { + // + // NOTE: this method is called from ConnectionI.parseMessage + // with the connection locked. Therefore, it must not invoke + // any user callbacks. + // + + assert(_proxy.ice_isTwoway()); // Can only be called for twoways. + + if(_childObserver != null) + { + _childObserver.reply(is.size() - Protocol.headerSize - 4); + _childObserver.detach(); + _childObserver = null; + } + + byte replyStatus; + try + { + // _is can already be initialized if the invocation is retried + if(_is == null) + { + _is = new Ice.InputStream(_instance, IceInternal.Protocol.currentProtocolEncoding); + } + _is.swap(is); + replyStatus = _is.readByte(); + + switch(replyStatus) + { + case ReplyStatus.replyOK: + { + break; + } + + case ReplyStatus.replyUserException: + { + if(_observer != null) + { + _observer.userException(); + } + break; + } + + case ReplyStatus.replyObjectNotExist: + case ReplyStatus.replyFacetNotExist: + case ReplyStatus.replyOperationNotExist: + { + Ice.Identity id = new Ice.Identity(); + id.__read(_is); + + // + // For compatibility with the old FacetPath. + // + String[] facetPath = _is.readStringSeq(); + String facet; + if(facetPath.length > 0) + { + if(facetPath.length > 1) + { + throw new Ice.MarshalException(); + } + facet = facetPath[0]; + } + else + { + facet = ""; + } + + String operation = _is.readString(); + + Ice.RequestFailedException ex = null; + switch(replyStatus) + { + case ReplyStatus.replyObjectNotExist: + { + ex = new Ice.ObjectNotExistException(); + break; + } + + case ReplyStatus.replyFacetNotExist: + { + ex = new Ice.FacetNotExistException(); + break; + } + + case ReplyStatus.replyOperationNotExist: + { + ex = new Ice.OperationNotExistException(); + break; + } + + default: + { + assert(false); + break; + } + } + + ex.id = id; + ex.facet = facet; + ex.operation = operation; + throw ex; + } + + case ReplyStatus.replyUnknownException: + case ReplyStatus.replyUnknownLocalException: + case ReplyStatus.replyUnknownUserException: + { + String unknown = _is.readString(); + + Ice.UnknownException ex = null; + switch(replyStatus) + { + case ReplyStatus.replyUnknownException: + { + ex = new Ice.UnknownException(); + break; + } + + case ReplyStatus.replyUnknownLocalException: + { + ex = new Ice.UnknownLocalException(); + break; + } + + case ReplyStatus.replyUnknownUserException: + { + ex = new Ice.UnknownUserException(); + break; + } + + default: + { + assert(false); + break; + } + } + + ex.unknown = unknown; + throw ex; + } + + default: + { + throw new Ice.UnknownReplyStatusException(); + } + } + + return finished(replyStatus == ReplyStatus.replyOK); + } + catch(Ice.Exception ex) + { + return completed(ex); + } + } + + public Ice.OutputStream startWriteParams(Ice.FormatType format) + { + _os.startEncapsulation(_encoding, format); + return _os; + } + + public void endWriteParams() + { + _os.endEncapsulation(); + } + + public void writeEmptyParams() + { + _os.writeEmptyEncapsulation(_encoding); + } + + public void writeParamEncaps(byte[] encaps) + { + if(encaps == null || encaps.length == 0) + { + _os.writeEmptyEncapsulation(_encoding); + } + else + { + _os.writeEncapsulation(encaps); + } + } + + public Ice.InputStream startReadParams() + { + _is.startEncapsulation(); + return _is; + } + + public void endReadParams() + { + _is.endEncapsulation(); + } + + public void readEmptyParams() + { + _is.skipEmptyEncapsulation(); + } + + public byte[] readParamEncaps() + { + return _is.readEncapsulation(null); + } + + public final void throwUserException() + throws Ice.UserException + { + try + { + _is.startEncapsulation(); + _is.throwException(null); + } + catch(Ice.UserException ex) + { + _is.endEncapsulation(); + throw ex; + } + } + + @Override + public void cacheMessageBuffers() + { + if(_proxy.__reference().getInstance().cacheMessageBuffers() > 0) + { + synchronized(this) + { + if((_state & StateCachedBuffers) > 0) + { + return; + } + _state |= StateCachedBuffers; + } + + if(_is != null) + { + _is.reset(); + } + _os.reset(); + + _proxy.cacheMessageBuffers(_is, _os); + + _is = null; + _os = null; + } + } + + final private Ice.EncodingVersion _encoding; + private Ice.InputStream _is; + + // + // If true this AMI request is being used for a generated synchronous invocation. + // + private boolean _synchronous; + + private static final java.util.Map<String, String> _emptyContext = new java.util.HashMap<String, String>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/OutgoingAsyncBase.java b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingAsyncBase.java new file mode 100644 index 00000000000..7af12ad2912 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingAsyncBase.java @@ -0,0 +1,107 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// Base class for handling asynchronous invocations. This class is +// responsible for the handling of the output stream and the child +// invocation observer. +// +public abstract class OutgoingAsyncBase extends IceInternal.AsyncResultI +{ + public boolean sent() + { + return sent(true); + } + + public boolean completed(Ice.InputStream is) + { + assert(false); // Must be implemented by classes that handle responses + return false; + } + + public boolean completed(Ice.Exception ex) + { + return finished(ex); + } + + public final void attachRemoteObserver(Ice.ConnectionInfo info, Ice.Endpoint endpt, int requestId) + { + if(_observer != null) + { + final int size = _os.size() - IceInternal.Protocol.headerSize - 4; + _childObserver = getObserver().getRemoteObserver(info, endpt, requestId, size); + if(_childObserver != null) + { + _childObserver.attach(); + } + } + } + + public final void attachCollocatedObserver(Ice.ObjectAdapter adapter, int requestId) + { + if(_observer != null) + { + final int size = _os.size() - IceInternal.Protocol.headerSize - 4; + _childObserver = getObserver().getCollocatedObserver(adapter, requestId, size); + if(_childObserver != null) + { + _childObserver.attach(); + } + } + } + + public final Ice.OutputStream getOs() + { + return _os; + } + + protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, String op, CallbackBase del) + { + super(com, instance, op, del); + _os = new Ice.OutputStream(instance, Protocol.currentProtocolEncoding); + } + + protected OutgoingAsyncBase(Ice.Communicator com, Instance instance, String op, CallbackBase del, + Ice.OutputStream os) + { + super(com, instance, op, del); + _os = os; + } + + @Override + protected boolean sent(boolean done) + { + if(done) + { + if(_childObserver != null) + { + _childObserver.detach(); + _childObserver = null; + } + } + return super.sent(done); + } + + @Override + protected boolean finished(Ice.Exception ex) + { + if(_childObserver != null) + { + _childObserver.failed(ex.ice_id()); + _childObserver.detach(); + _childObserver = null; + } + return super.finished(ex); + } + + protected Ice.OutputStream _os; + protected Ice.Instrumentation.ChildInvocationObserver _childObserver; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java new file mode 100644 index 00000000000..94b80c0e2fb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/OutgoingConnectionFactory.java @@ -0,0 +1,1149 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class OutgoingConnectionFactory +{ + // + // Helper class to multi hash map. + // + private static class MultiHashMap<K, V> extends java.util.HashMap<K, java.util.List<V>> + { + public void + putOne(K key, V value) + { + java.util.List<V> list = this.get(key); + if(list == null) + { + list = new java.util.LinkedList<V>(); + this.put(key, list); + } + list.add(value); + } + + public boolean + removeElementWithValue(K key, V value) + { + java.util.List<V> list = this.get(key); + assert(list != null); + boolean v = list.remove(value); + if(list.isEmpty()) + { + this.remove(key); + } + return v; + } + } + + interface CreateConnectionCallback + { + void setConnection(Ice.ConnectionI connection, boolean compress); + void setException(Ice.LocalException ex); + } + + public synchronized void + destroy() + { + if(_destroyed) + { + return; + } + + for(java.util.List<Ice.ConnectionI> connectionList : _connections.values()) + { + for(Ice.ConnectionI connection : connectionList) + { + connection.destroy(Ice.ConnectionI.CommunicatorDestroyed); + } + } + + _destroyed = true; + _communicator = null; + notifyAll(); + } + + public synchronized void + updateConnectionObservers() + { + for(java.util.List<Ice.ConnectionI> connectionList : _connections.values()) + { + for(Ice.ConnectionI connection : connectionList) + { + connection.updateObserver(); + } + } + } + + // Called from Instance.destroy(). + public void + waitUntilFinished() + { + java.util.Map<Connector, java.util.List<Ice.ConnectionI> > connections = null; + synchronized(this) + { + // + // First we wait until the factory is destroyed. We also + // wait until there are no pending connections + // anymore. Only then we can be sure the _connections + // contains all connections. + // + while(!_destroyed || !_pending.isEmpty() || _pendingConnectCount > 0) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + throw new Ice.OperationInterruptedException(); + } + } + + // + // We want to wait until all connections are finished outside the + // thread synchronization. + // + connections = new java.util.HashMap<Connector, java.util.List<Ice.ConnectionI> >(_connections); + } + + // + // Now we wait until the destruction of each connection is finished. + // + for(java.util.List<Ice.ConnectionI> connectionList : connections.values()) + { + for(Ice.ConnectionI connection : connectionList) + { + try + { + connection.waitUntilFinished(); + } + catch(InterruptedException e) + { + // + // Force close all of the connections. + // + for(java.util.List<Ice.ConnectionI> l : connections.values()) + { + for(Ice.ConnectionI c : l) + { + c.close(true); + } + } + throw new Ice.OperationInterruptedException(); + } + } + } + + synchronized(this) + { + // Ensure all the connections are finished and reapable at this point. + java.util.List<Ice.ConnectionI> cons = _monitor.swapReapedConnections(); + if(cons != null) + { + int size = 0; + for(java.util.List<Ice.ConnectionI> connectionList : _connections.values()) + { + size += connectionList.size(); + } + assert(cons.size() == size); + _connections.clear(); + _connectionsByEndpoint.clear(); + } + else + { + assert(_connections.isEmpty()); + assert(_connectionsByEndpoint.isEmpty()); + } + _monitor.destroy(); + } + } + + public void + create(EndpointI[] endpts, boolean hasMore, Ice.EndpointSelectionType selType, CreateConnectionCallback callback) + { + assert(endpts.length > 0); + + // + // Apply the overrides. + // + java.util.List<EndpointI> endpoints = applyOverrides(endpts); + + // + // Try to find a connection to one of the given endpoints. + // + try + { + Ice.Holder<Boolean> compress = new Ice.Holder<Boolean>(); + Ice.ConnectionI connection = findConnectionByEndpoint(endpoints, compress); + if(connection != null) + { + callback.setConnection(connection, compress.value); + return; + } + } + catch(Ice.LocalException ex) + { + callback.setException(ex); + return; + } + + ConnectCallback cb = new ConnectCallback(this, endpoints, hasMore, callback, selType); + cb.getConnectors(); + } + + public synchronized void + setRouterInfo(IceInternal.RouterInfo routerInfo) + { + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + assert(routerInfo != null); + + // + // Search for connections to the router's client proxy + // endpoints, and update the object adapter for such + // connections, so that callbacks from the router can be + // received over such connections. + // + Ice.ObjectAdapter adapter = routerInfo.getAdapter(); + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + for(EndpointI endpoint : routerInfo.getClientEndpoints()) + { + // + // Modify endpoints with overrides. + // + if(defaultsAndOverrides.overrideTimeout) + { + endpoint = endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue); + } + + // + // The Connection object does not take the compression flag of + // endpoints into account, but instead gets the information + // about whether messages should be compressed or not from + // other sources. In order to allow connection sharing for + // endpoints that differ in the value of the compression flag + // only, we always set the compression flag to false here in + // this connection factory. + // + endpoint = endpoint.compress(false); + + for(java.util.List<Ice.ConnectionI> connectionList : _connections.values()) + { + for(Ice.ConnectionI connection : connectionList) + { + if(connection.endpoint() == endpoint) + { + connection.setAdapter(adapter); + } + } + } + } + } + + public synchronized void + removeAdapter(Ice.ObjectAdapter adapter) + { + if(_destroyed) + { + return; + } + + for(java.util.List<Ice.ConnectionI> connectionList : _connections.values()) + { + for(Ice.ConnectionI connection : connectionList) + { + if(connection.getAdapter() == adapter) + { + connection.setAdapter(null); + } + } + } + } + + public void + flushAsyncBatchRequests(CommunicatorFlushBatch outAsync) + { + java.util.List<Ice.ConnectionI> c = new java.util.LinkedList<Ice.ConnectionI>(); + + synchronized(this) + { + if(!_destroyed) + { + for(java.util.List<Ice.ConnectionI> connectionList : _connections.values()) + { + for(Ice.ConnectionI connection : connectionList) + { + if(connection.isActiveOrHolding()) + { + c.add(connection); + } + } + } + } + } + + for(Ice.ConnectionI conn : c) + { + try + { + outAsync.flushConnection(conn); + } + catch(Ice.LocalException ex) + { + // Ignore. + } + } + } + + // + // Only for use by Instance. + // + OutgoingConnectionFactory(Ice.Communicator communicator, Instance instance) + { + _communicator = communicator; + _instance = instance; + _monitor = new FactoryACMMonitor(instance, instance.clientACM()); + _destroyed = false; + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_destroyed); + IceUtilInternal.Assert.FinalizerAssert(_connections.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_connectionsByEndpoint.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_pendingConnectCount == 0); + IceUtilInternal.Assert.FinalizerAssert(_pending.isEmpty()); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private java.util.List<EndpointI> + applyOverrides(EndpointI[] endpts) + { + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + java.util.List<EndpointI> endpoints = new java.util.ArrayList<EndpointI>(); + for(EndpointI endpoint : endpts) + { + // + // Modify endpoints with overrides. + // + if(defaultsAndOverrides.overrideTimeout) + { + endpoints.add(endpoint.timeout(defaultsAndOverrides.overrideTimeoutValue)); + } + else + { + endpoints.add(endpoint); + } + } + + return endpoints; + } + + synchronized private Ice.ConnectionI + findConnectionByEndpoint(java.util.List<EndpointI> endpoints, Ice.Holder<Boolean> compress) + { + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + assert(!endpoints.isEmpty()); + + for(EndpointI endpoint : endpoints) + { + java.util.List<Ice.ConnectionI> connectionList = _connectionsByEndpoint.get(endpoint); + if(connectionList == null) + { + continue; + } + + for(Ice.ConnectionI connection : connectionList) + { + if(connection.isActiveOrHolding()) // Don't return destroyed or un-validated connections + { + if(defaultsAndOverrides.overrideCompress) + { + compress.value = defaultsAndOverrides.overrideCompressValue; + } + else + { + compress.value = endpoint.compress(); + } + return connection; + } + } + } + + return null; + } + + // + // Must be called while synchronized. + // + private Ice.ConnectionI + findConnection(java.util.List<ConnectorInfo> connectors, Ice.Holder<Boolean> compress) + { + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + for(ConnectorInfo ci : connectors) + { + if(_pending.containsKey(ci.connector)) + { + continue; + } + + java.util.List<Ice.ConnectionI> connectionList = _connections.get(ci.connector); + if(connectionList == null) + { + continue; + } + + for(Ice.ConnectionI connection : connectionList) + { + if(connection.isActiveOrHolding()) // Don't return destroyed or un-validated connections + { + if(defaultsAndOverrides.overrideCompress) + { + compress.value = defaultsAndOverrides.overrideCompressValue; + } + else + { + compress.value = ci.endpoint.compress(); + } + return connection; + } + } + } + + return null; + } + + synchronized private void + incPendingConnectCount() + { + // + // Keep track of the number of pending connects. The outgoing connection factory + // waitUntilFinished() method waits for all the pending connects to terminate before + // to return. This ensures that the communicator client thread pool isn't destroyed + // too soon and will still be available to execute the ice_exception() callbacks for + // the asynchronous requests waiting on a connection to be established. + // + + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + ++_pendingConnectCount; + } + + synchronized private void + decPendingConnectCount() + { + --_pendingConnectCount; + assert(_pendingConnectCount >= 0); + if(_destroyed && _pendingConnectCount == 0) + { + notifyAll(); + } + } + + private Ice.ConnectionI + getConnection(java.util.List<ConnectorInfo> connectors, ConnectCallback cb, Ice.Holder<Boolean> compress) + { + assert(cb != null); + synchronized(this) + { + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + // + // Reap closed connections + // + java.util.List<Ice.ConnectionI> cons = _monitor.swapReapedConnections(); + if(cons != null) + { + for(Ice.ConnectionI c : cons) + { + _connections.removeElementWithValue(c.connector(), c); + _connectionsByEndpoint.removeElementWithValue(c.endpoint(), c); + _connectionsByEndpoint.removeElementWithValue(c.endpoint().compress(true), c); + } + } + + // + // Try to get the connection. We may need to wait for other threads to + // finish if one of them is currently establishing a connection to one + // of our connectors. + // + while(true) + { + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + // + // Search for a matching connection. If we find one, we're done. + // + Ice.ConnectionI connection = findConnection(connectors, compress); + if(connection != null) + { + return connection; + } + + if(addToPending(cb, connectors)) + { + return null; + } + else + { + // + // If no thread is currently establishing a connection to one of our connectors, + // we get out of this loop and start the connection establishment to one of the + // given connectors. + // + break; + } + } + } + + // + // At this point, we're responsible for establishing the connection to one of + // the given connectors. If it's a non-blocking connect, calling nextConnector + // will start the connection establishment. Otherwise, we return null to get + // the caller to establish the connection. + // + if(cb != null) + { + cb.nextConnector(); + } + + return null; + } + + private synchronized Ice.ConnectionI + createConnection(Transceiver transceiver, ConnectorInfo ci) + { + assert(_pending.containsKey(ci.connector) && transceiver != null); + + // + // Create and add the connection to the connection map. Adding the connection to the map + // is necessary to support the interruption of the connection initialization and validation + // in case the communicator is destroyed. + // + Ice.ConnectionI connection = null; + try + { + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + + connection = new Ice.ConnectionI(_communicator, _instance, _monitor, transceiver, ci.connector, + ci.endpoint.compress(false), null); + } + catch(Ice.LocalException ex) + { + try + { + transceiver.close(); + } + catch(Ice.LocalException exc) + { + // Ignore + } + throw ex; + } + + _connections.putOne(ci.connector, connection); + _connectionsByEndpoint.putOne(connection.endpoint(), connection); + _connectionsByEndpoint.putOne(connection.endpoint().compress(true), connection); + return connection; + } + + private void + finishGetConnection(java.util.List<ConnectorInfo> connectors, + ConnectorInfo ci, + Ice.ConnectionI connection, + ConnectCallback cb) + { + java.util.Set<ConnectCallback> connectionCallbacks = new java.util.HashSet<ConnectCallback>(); + if(cb != null) + { + connectionCallbacks.add(cb); + } + + java.util.Set<ConnectCallback> callbacks = new java.util.HashSet<ConnectCallback>(); + synchronized(this) + { + for(ConnectorInfo c : connectors) + { + java.util.Set<ConnectCallback> cbs = _pending.remove(c.connector); + if(cbs != null) + { + for(ConnectCallback cc : cbs) + { + if(cc.hasConnector(ci)) + { + connectionCallbacks.add(cc); + } + else + { + callbacks.add(cc); + } + } + } + } + + for(ConnectCallback cc : connectionCallbacks) + { + cc.removeFromPending(); + callbacks.remove(cc); + } + for(ConnectCallback cc : callbacks) + { + cc.removeFromPending(); + } + notifyAll(); + } + + boolean compress; + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + if(defaultsAndOverrides.overrideCompress) + { + compress = defaultsAndOverrides.overrideCompressValue; + } + else + { + compress = ci.endpoint.compress(); + } + + for(ConnectCallback cc : callbacks) + { + cc.getConnection(); + } + for(ConnectCallback cc : connectionCallbacks) + { + cc.setConnection(connection, compress); + } + } + + private void + finishGetConnection(java.util.List<ConnectorInfo> connectors, Ice.LocalException ex, ConnectCallback cb) + { + java.util.Set<ConnectCallback> failedCallbacks = new java.util.HashSet<ConnectCallback>(); + if(cb != null) + { + failedCallbacks.add(cb); + } + + java.util.Set<ConnectCallback> callbacks = new java.util.HashSet<ConnectCallback>(); + synchronized(this) + { + for(ConnectorInfo c : connectors) + { + java.util.Set<ConnectCallback> cbs = _pending.remove(c.connector); + if(cbs != null) + { + for(ConnectCallback cc : cbs) + { + if(cc.removeConnectors(connectors)) + { + failedCallbacks.add(cc); + } + else + { + callbacks.add(cc); + } + } + } + } + + for(ConnectCallback cc : callbacks) + { + assert(!failedCallbacks.contains(cc)); + cc.removeFromPending(); + } + notifyAll(); + } + + for(ConnectCallback cc : callbacks) + { + cc.getConnection(); + } + for(ConnectCallback cc : failedCallbacks) + { + cc.setException(ex); + } + } + + private boolean + addToPending(ConnectCallback cb, java.util.List<ConnectorInfo> connectors) + { + // + // Add the callback to each connector pending list. + // + boolean found = false; + for(ConnectorInfo p : connectors) + { + java.util.Set<ConnectCallback> cbs = _pending.get(p.connector); + if(cbs != null) + { + found = true; + if(cb != null) + { + cbs.add(cb); // Add the callback to each pending connector. + } + } + } + + if(found) + { + return true; + } + + // + // If there's no pending connection for the given connectors, we're + // responsible for its establishment. We add empty pending lists, + // other callbacks to the same connectors will be queued. + // + for(ConnectorInfo p : connectors) + { + if(!_pending.containsKey(p.connector)) + { + _pending.put(p.connector, new java.util.HashSet<ConnectCallback>()); + } + } + + return false; + } + + private void + removeFromPending(ConnectCallback cb, java.util.List<ConnectorInfo> connectors) + { + for(ConnectorInfo p : connectors) + { + java.util.Set<ConnectCallback> cbs = _pending.get(p.connector); + if(cbs != null) + { + cbs.remove(cb); + } + } + } + + private void + handleConnectionException(Ice.LocalException ex, boolean hasMore) + { + TraceLevels traceLevels = _instance.traceLevels(); + if(traceLevels.retry >= 2) + { + StringBuilder s = new StringBuilder(128); + s.append("connection to endpoint failed"); + if(ex instanceof Ice.CommunicatorDestroyedException) + { + s.append("\n"); + } + else + { + if(hasMore) + { + s.append(", trying next endpoint\n"); + } + else + { + s.append(" and no more endpoints to try\n"); + } + } + s.append(ex.toString()); + _instance.initializationData().logger.trace(traceLevels.retryCat, s.toString()); + } + } + + private void + handleException(Ice.LocalException ex, boolean hasMore) + { + TraceLevels traceLevels = _instance.traceLevels(); + if(traceLevels.retry >= 2) + { + StringBuilder s = new StringBuilder(128); + s.append("couldn't resolve endpoint host"); + if(ex instanceof Ice.CommunicatorDestroyedException) + { + s.append("\n"); + } + else + { + if(hasMore) + { + s.append(", trying next endpoint\n"); + } + else + { + s.append(" and no more endpoints to try\n"); + } + } + s.append(ex.toString()); + _instance.initializationData().logger.trace(traceLevels.retryCat, s.toString()); + } + } + + private static class ConnectorInfo + { + public ConnectorInfo(Connector c, EndpointI e) + { + connector = c; + endpoint = e; + } + + @Override + public boolean + equals(Object obj) + { + ConnectorInfo r = (ConnectorInfo)obj; + return connector.equals(r.connector); + } + + @Override + public int + hashCode() + { + return connector.hashCode(); + } + + public Connector connector; + public EndpointI endpoint; + } + + private static class ConnectCallback implements Ice.ConnectionI.StartCallback, EndpointI_connectors + { + ConnectCallback(OutgoingConnectionFactory f, java.util.List<EndpointI> endpoints, boolean more, + CreateConnectionCallback cb, Ice.EndpointSelectionType selType) + { + _factory = f; + _endpoints = endpoints; + _hasMore = more; + _callback = cb; + _selType = selType; + _endpointsIter = _endpoints.iterator(); + } + + // + // Methods from ConnectionI.StartCallback + // + @Override + public void + connectionStartCompleted(Ice.ConnectionI connection) + { + if(_observer != null) + { + _observer.detach(); + } + connection.activate(); + _factory.finishGetConnection(_connectors, _current, connection, this); + } + + @Override + public void + connectionStartFailed(Ice.ConnectionI connection, Ice.LocalException ex) + { + assert(_current != null); + if(connectionStartFailedImpl(ex)) + { + nextConnector(); + } + } + + // + // Methods from EndpointI_connectors + // + @Override + public void + connectors(java.util.List<Connector> cons) + { + for(Connector p : cons) + { + _connectors.add(new ConnectorInfo(p, _currentEndpoint)); + } + + if(_endpointsIter.hasNext()) + { + nextEndpoint(); + } + else + { + assert(!_connectors.isEmpty()); + + // + // We now have all the connectors for the given endpoints. We can try to obtain the + // connection. + // + _iter = _connectors.iterator(); + getConnection(); + } + } + + @Override + public void + exception(Ice.LocalException ex) + { + _factory.handleException(ex, _hasMore || _endpointsIter.hasNext()); + if(_endpointsIter.hasNext()) + { + nextEndpoint(); + } + else if(!_connectors.isEmpty()) + { + // + // We now have all the connectors for the given endpoints. We can try to obtain the + // connection. + // + _iter = _connectors.iterator(); + getConnection(); + } + else + { + _callback.setException(ex); + _factory.decPendingConnectCount(); // Must be called last. + } + } + + void + setConnection(Ice.ConnectionI connection, boolean compress) + { + // + // Callback from the factory: the connection to one of the callback + // connectors has been established. + // + _callback.setConnection(connection, compress); + _factory.decPendingConnectCount(); // Must be called last. + } + + void + setException(Ice.LocalException ex) + { + // + // Callback from the factory: connection establishment failed. + // + _callback.setException(ex); + _factory.decPendingConnectCount(); // Must be called last. + } + + boolean + hasConnector(ConnectorInfo ci) + { + return _connectors.contains(ci); + } + + boolean + removeConnectors(java.util.List<ConnectorInfo> connectors) + { + _connectors.removeAll(connectors); + _iter = _connectors.iterator(); + return _connectors.isEmpty(); + } + + void + removeFromPending() + { + _factory.removeFromPending(this, _connectors); + } + + private void + getConnectors() + { + try + { + // + // Notify the factory that there's an async connect pending. This is necessary + // to prevent the outgoing connection factory to be destroyed before all the + // pending asynchronous connects are finished. + // + _factory.incPendingConnectCount(); + } + catch(Ice.LocalException ex) + { + _callback.setException(ex); + return; + } + + nextEndpoint(); + } + + private void + nextEndpoint() + { + try + { + assert(_endpointsIter.hasNext()); + _currentEndpoint = _endpointsIter.next(); + _currentEndpoint.connectors_async(_selType, this); + } + catch(Ice.LocalException ex) + { + exception(ex); + } + } + + private void + getConnection() + { + try + { + // + // If all the connectors have been created, we ask the factory to get a + // connection. + // + Ice.Holder<Boolean> compress = new Ice.Holder<Boolean>(); + Ice.ConnectionI connection = _factory.getConnection(_connectors, this, compress); + if(connection == null) + { + // + // A null return value from getConnection indicates that the connection + // is being established and that everything has been done to ensure that + // the callback will be notified when the connection establishment is + // done. + // + return; + } + + _callback.setConnection(connection, compress.value); + _factory.decPendingConnectCount(); // Must be called last. + } + catch(Ice.LocalException ex) + { + _callback.setException(ex); + _factory.decPendingConnectCount(); // Must be called last. + } + } + + private void + nextConnector() + { + while(true) + { + try + { + assert(_iter.hasNext()); + _current = _iter.next(); + + Ice.Instrumentation.CommunicatorObserver obsv = _factory._instance.initializationData().observer; + if(obsv != null) + { + _observer = obsv.getConnectionEstablishmentObserver(_current.endpoint, + _current.connector.toString()); + if(_observer != null) + { + _observer.attach(); + } + } + + if(_factory._instance.traceLevels().network >= 2) + { + StringBuffer s = new StringBuffer("trying to establish "); + s.append(_current.endpoint.protocol()); + s.append(" connection to "); + s.append(_current.connector.toString()); + _factory._instance.initializationData().logger.trace(_factory._instance.traceLevels().networkCat, + s.toString()); + } + + Ice.ConnectionI connection = _factory.createConnection(_current.connector.connect(), _current); + connection.start(this); + } + catch(Ice.LocalException ex) + { + if(_factory._instance.traceLevels().network >= 2) + { + StringBuffer s = new StringBuffer("failed to establish "); + s.append(_current.endpoint.protocol()); + s.append(" connection to "); + s.append(_current.connector.toString()); + s.append("\n"); + s.append(ex); + _factory._instance.initializationData().logger.trace(_factory._instance.traceLevels().networkCat, + s.toString()); + } + + if(connectionStartFailedImpl(ex)) + { + continue; + } + } + break; + } + } + + private boolean + connectionStartFailedImpl(Ice.LocalException ex) + { + if(_observer != null) + { + _observer.failed(ex.ice_id()); + _observer.detach(); + } + + _factory.handleConnectionException(ex, _hasMore || _iter.hasNext()); + if(ex instanceof Ice.CommunicatorDestroyedException) // No need to continue. + { + _factory.finishGetConnection(_connectors, ex, this); + } + else if(_iter.hasNext()) // Try the next connector. + { + return true; + } + else + { + _factory.finishGetConnection(_connectors, ex, this); + } + return false; + } + + private final OutgoingConnectionFactory _factory; + private final boolean _hasMore; + private final CreateConnectionCallback _callback; + private final java.util.List<EndpointI> _endpoints; + private final Ice.EndpointSelectionType _selType; + private java.util.Iterator<EndpointI> _endpointsIter; + private EndpointI _currentEndpoint; + private java.util.List<ConnectorInfo> _connectors = new java.util.ArrayList<ConnectorInfo>(); + private java.util.Iterator<ConnectorInfo> _iter; + private ConnectorInfo _current; + private Ice.Instrumentation.Observer _observer; + } + + private Ice.Communicator _communicator; + private final Instance _instance; + private final FactoryACMMonitor _monitor; + private boolean _destroyed; + + private MultiHashMap<Connector, Ice.ConnectionI> _connections = new MultiHashMap<Connector, Ice.ConnectionI>(); + private MultiHashMap<EndpointI, Ice.ConnectionI> _connectionsByEndpoint = + new MultiHashMap<EndpointI, Ice.ConnectionI>(); + private java.util.Map<Connector, java.util.HashSet<ConnectCallback> > _pending = + new java.util.HashMap<Connector, java.util.HashSet<ConnectCallback> >(); + private int _pendingConnectCount = 0; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/OutputStreamWrapper.java b/java-compat/src/Ice/src/main/java/IceInternal/OutputStreamWrapper.java new file mode 100644 index 00000000000..6f9e2f9a9d6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/OutputStreamWrapper.java @@ -0,0 +1,178 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.io.*; + +// +// Class to provide a java.io.OutputStream on top of our stream. +// We use this to serialize arbitrary Java serializable classes into +// +// Slice sequences are encoded on the wire as a count of elements, followed +// by the sequence contents. For arbitrary Java classes, we do not know how +// big the sequence that is eventually written will be. To avoid excessive +// data copying, this class mantains a private _bytes array of 254 bytes and, +// initially, writes data into that array. If more than 254 bytes end up being +// written, we write a dummy sequence size of 255 (which occupies five bytes +// on the wire) into the stream and, once this stream is closed, patch +// that size to match the actual size. Otherwise, if the _bytes buffer contains +// fewer than 255 bytes when this stream is closed, we write the sequence size +// as a single byte, followed by the contents of the _bytes buffer. +// + +public class OutputStreamWrapper extends java.io.OutputStream +{ + public + OutputStreamWrapper(Ice.OutputStream s) + { + _s = s; + _spos = s.pos(); + _bytes = new byte[254]; + _pos = 0; + } + + @Override + public void + write(int b) throws IOException + { + try + { + if(_bytes != null) + { + // + // If we can fit the data into the first 254 bytes, write it to _bytes. + // + if(_pos < _bytes.length) + { + _bytes[_pos++] = (byte)b; + return; + } + + _s.writeSize(255); // Dummy size, until we know how big the stream + // really is and can patch the size. + + if(_pos > 0) + { + // + // Write the current contents of _bytes. + // + _s.expand(_pos); + _s.getBuffer().b.put(_bytes, 0, _pos); + } + _bytes = null; + } + + // + // Write data passed by caller. + // + _s.expand(1); + _s.getBuffer().b.put((byte)b); + _pos += 1; + } + catch(java.lang.Exception ex) + { + throw new IOException(ex.toString()); + } + } + + @Override + public void + write(byte[] b) throws IOException + { + write(b, 0, b.length); + } + + @Override + public void + write(byte[] bytes, int offset, int count) throws IOException + { + try + { + if(_bytes != null) + { + // + // If we can fit the data into the first 254 bytes, write it to _bytes. + // + if(count <= _bytes.length - _pos) + { + System.arraycopy(bytes, offset, _bytes, _pos, count); + _pos += count; + return; + } + + _s.writeSize(255); // Dummy size, until we know how big the stream + // really is and can patch the size. + + if(_pos > 0) + { + // + // Write the current contents of _bytes. + // + _s.expand(_pos); + _s.getBuffer().b.put(_bytes, 0, _pos); + } + _bytes = null; + } + + // + // Write data passed by caller. + // + _s.expand(count); + _s.getBuffer().b.put(bytes, offset, count); + _pos += count; + } + catch(java.lang.Exception ex) + { + throw new IOException(ex.toString()); + } + } + + @Override + public void + flush() throws IOException + { + // This does nothing because we do not know the final size of a writable stream until it is closed, + // and we cannot write to the stream until we know whether the final size is < 255 or not. + } + + @Override + public void + close() throws IOException + { + try + { + if(_bytes != null) + { + assert(_pos <= _bytes.length); + _s.pos(_spos); + _s.writeSize(_pos); + _s.expand(_pos); + _s.getBuffer().b.put(_bytes, 0, _pos); + _bytes = null; + } + else + { + int currentPos = _s.pos(); + _s.pos(_spos); + _s.writeSize(_pos); // Patch previously-written dummy value. + _s.pos(currentPos); + } + } + catch(java.lang.Exception ex) + { + throw new IOException(ex.toString()); + } + } + + private Ice.OutputStream _s; + private int _spos; + private byte[] _bytes; + private int _pos; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProcessI.java b/java-compat/src/Ice/src/main/java/IceInternal/ProcessI.java new file mode 100644 index 00000000000..516d5f03aa9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProcessI.java @@ -0,0 +1,46 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProcessI extends Ice._ProcessDisp +{ + public ProcessI(Ice.Communicator communicator) + { + _communicator = communicator; + } + + @Override + public void + shutdown(Ice.Current current) + { + _communicator.shutdown(); + } + + @Override + public void + writeMessage(String message, int fd, Ice.Current current) + { + switch(fd) + { + case 1: + { + System.out.println(message); + break; + } + case 2: + { + System.err.println(message); + break; + } + } + } + + private Ice.Communicator _communicator; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/PropertiesAdminI.java b/java-compat/src/Ice/src/main/java/IceInternal/PropertiesAdminI.java new file mode 100644 index 00000000000..b6041ba4fd6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/PropertiesAdminI.java @@ -0,0 +1,214 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class PropertiesAdminI extends Ice._PropertiesAdminDisp implements Ice.NativePropertiesAdmin +{ + public PropertiesAdminI(Instance instance) + { + _properties = instance.initializationData().properties; + _logger = instance.initializationData().logger; + } + + @Override + public synchronized String + getProperty(String name, Ice.Current current) + { + return _properties.getProperty(name); + } + + @Override + public synchronized java.util.TreeMap<String, String> + getPropertiesForPrefix(String name, Ice.Current current) + { + return new java.util.TreeMap<String, String>(_properties.getPropertiesForPrefix(name)); + } + + @Override + synchronized public void setProperties(java.util.Map<String, String> props, Ice.Current current) + { + java.util.Map<String, String> old = _properties.getPropertiesForPrefix(""); + final int traceLevel = _properties.getPropertyAsInt("Ice.Trace.Admin.Properties"); + + // + // Compute the difference between the new property set and the existing property set: + // + // 1) Any properties in the new set that were not defined in the existing set. + // + // 2) Any properties that appear in both sets but with different values. + // + // 3) Any properties not present in the new set but present in the existing set. + // In other words, the property has been removed. + // + java.util.Map<String, String> added = new java.util.HashMap<String, String>(); + java.util.Map<String, String> changed = new java.util.HashMap<String, String>(); + java.util.Map<String, String> removed = new java.util.HashMap<String, String>(); + for(java.util.Map.Entry<String, String> e : props.entrySet()) + { + final String key = e.getKey(); + final String value = e.getValue(); + if(!old.containsKey(key)) + { + if(value.length() > 0) + { + // + // This property is new. + // + added.put(key, value); + } + } + else + { + if(!value.equals(old.get(key))) + { + if(value.length() == 0) + { + // + // This property was removed. + // + removed.put(key, value); + } + else + { + // + // This property has changed. + // + changed.put(key, value); + } + } + + old.remove(key); + } + } + + if(traceLevel > 0 && (!added.isEmpty() || !changed.isEmpty() || !removed.isEmpty())) + { + StringBuilder out = new StringBuilder(128); + out.append("Summary of property changes"); + + if(!added.isEmpty()) + { + out.append("\nNew properties:"); + for(java.util.Map.Entry<String, String> e : added.entrySet()) + { + out.append("\n "); + out.append(e.getKey()); + if(traceLevel > 1) + { + out.append(" = "); + out.append(e.getValue()); + } + } + } + + if(!changed.isEmpty()) + { + out.append("\nChanged properties:"); + for(java.util.Map.Entry<String, String> e : changed.entrySet()) + { + out.append("\n "); + out.append(e.getKey()); + if(traceLevel > 1) + { + out.append(" = "); + out.append(e.getValue()); + out.append(" (old value = "); + out.append(_properties.getProperty(e.getKey())); + out.append(")"); + } + } + } + + if(!removed.isEmpty()) + { + out.append("\nRemoved properties:"); + for(java.util.Map.Entry<String, String> e : removed.entrySet()) + { + out.append("\n "); + out.append(e.getKey()); + } + } + + _logger.trace(_traceCategory, out.toString()); + } + + // + // Update the property set. + // + + for(java.util.Map.Entry<String, String> e : added.entrySet()) + { + _properties.setProperty(e.getKey(), e.getValue()); + } + + for(java.util.Map.Entry<String, String> e : changed.entrySet()) + { + _properties.setProperty(e.getKey(), e.getValue()); + } + + for(java.util.Map.Entry<String, String> e : removed.entrySet()) + { + _properties.setProperty(e.getKey(), ""); + } + + if(!_updateCallbacks.isEmpty()) + { + java.util.Map<String, String> changes = new java.util.HashMap<String, String>(added); + changes.putAll(changed); + changes.putAll(removed); + + // + // Copy the callbacks to allow callbacks to update the callbacks. + // + java.util.List<Ice.PropertiesAdminUpdateCallback> callbacks = + new java.util.ArrayList<Ice.PropertiesAdminUpdateCallback>(_updateCallbacks); + for(Ice.PropertiesAdminUpdateCallback callback : callbacks) + { + try + { + callback.updated(changes); + } + catch(java.lang.Exception ex) + { + if(_properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _logger.warning("properties admin update callback raised unexpected exception:\n" + + sw.toString()); + } + } + } + } + } + + @Override + public synchronized void + addUpdateCallback (Ice.PropertiesAdminUpdateCallback cb) + { + _updateCallbacks.add(cb); + } + + @Override + public synchronized void + removeUpdateCallback(Ice.PropertiesAdminUpdateCallback cb) + { + _updateCallbacks.remove(cb); + } + + private final Ice.Properties _properties; + private final Ice.Logger _logger; + private java.util.List<Ice.PropertiesAdminUpdateCallback> _updateCallbacks = + new java.util.ArrayList<Ice.PropertiesAdminUpdateCallback>(); + + static private final String _traceCategory = "Admin.Properties"; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Property.java b/java-compat/src/Ice/src/main/java/IceInternal/Property.java new file mode 100644 index 00000000000..3d8395c0289 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Property.java @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class Property +{ + public Property(String pattern, boolean deprecated, String deprecatedBy) + { + _pattern = pattern; + _deprecated = deprecated; + _deprecatedBy = deprecatedBy; + } + + public String + pattern() + { + return _pattern; + } + + public boolean + deprecated() + { + return _deprecated; + } + + public String + deprecatedBy() + { + return _deprecatedBy; + } + + private String _pattern; + private boolean _deprecated; + private String _deprecatedBy; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java b/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java new file mode 100644 index 00000000000..78fca903d04 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/PropertyNames.java @@ -0,0 +1,1254 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** +// Generated by makeprops.py from file ./config/PropertyNames.xml, Thu Aug 18 20:28:56 2016 + +// IMPORTANT: Do not edit this file -- any edits made here will be lost! + +package IceInternal; + +public final class PropertyNames +{ + public static final Property IceProps[] = + { + new Property("Ice\\.ACM\\.Client", true, null), + new Property("Ice\\.ACM\\.Server", true, null), + new Property("Ice\\.ACM\\.Timeout", false, null), + new Property("Ice\\.ACM\\.Heartbeat", false, null), + new Property("Ice\\.ACM\\.Close", false, null), + new Property("Ice\\.ACM", false, null), + new Property("Ice\\.ACM\\.Client\\.Timeout", false, null), + new Property("Ice\\.ACM\\.Client\\.Heartbeat", false, null), + new Property("Ice\\.ACM\\.Client\\.Close", false, null), + new Property("Ice\\.ACM\\.Client", false, null), + new Property("Ice\\.ACM\\.Server\\.Timeout", false, null), + new Property("Ice\\.ACM\\.Server\\.Heartbeat", false, null), + new Property("Ice\\.ACM\\.Server\\.Close", false, null), + new Property("Ice\\.ACM\\.Server", false, null), + new Property("Ice\\.Admin\\.ACM\\.Timeout", false, null), + new Property("Ice\\.Admin\\.ACM\\.Heartbeat", false, null), + new Property("Ice\\.Admin\\.ACM\\.Close", false, null), + new Property("Ice\\.Admin\\.ACM", false, null), + new Property("Ice\\.Admin\\.AdapterId", false, null), + new Property("Ice\\.Admin\\.Endpoints", false, null), + new Property("Ice\\.Admin\\.Locator\\.EndpointSelection", false, null), + new Property("Ice\\.Admin\\.Locator\\.ConnectionCached", false, null), + new Property("Ice\\.Admin\\.Locator\\.PreferSecure", false, null), + new Property("Ice\\.Admin\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("Ice\\.Admin\\.Locator\\.InvocationTimeout", false, null), + new Property("Ice\\.Admin\\.Locator\\.Locator", false, null), + new Property("Ice\\.Admin\\.Locator\\.Router", false, null), + new Property("Ice\\.Admin\\.Locator\\.CollocationOptimized", false, null), + new Property("Ice\\.Admin\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("Ice\\.Admin\\.Locator", false, null), + new Property("Ice\\.Admin\\.PublishedEndpoints", false, null), + new Property("Ice\\.Admin\\.ReplicaGroupId", false, null), + new Property("Ice\\.Admin\\.Router\\.EndpointSelection", false, null), + new Property("Ice\\.Admin\\.Router\\.ConnectionCached", false, null), + new Property("Ice\\.Admin\\.Router\\.PreferSecure", false, null), + new Property("Ice\\.Admin\\.Router\\.LocatorCacheTimeout", false, null), + new Property("Ice\\.Admin\\.Router\\.InvocationTimeout", false, null), + new Property("Ice\\.Admin\\.Router\\.Locator", false, null), + new Property("Ice\\.Admin\\.Router\\.Router", false, null), + new Property("Ice\\.Admin\\.Router\\.CollocationOptimized", false, null), + new Property("Ice\\.Admin\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("Ice\\.Admin\\.Router", false, null), + new Property("Ice\\.Admin\\.ProxyOptions", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.Size", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.SizeMax", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.SizeWarn", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.StackSize", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.Serialize", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("Ice\\.Admin\\.ThreadPool\\.ThreadPriority", false, null), + new Property("Ice\\.Admin\\.MessageSizeMax", false, null), + new Property("Ice\\.Admin\\.DelayCreation", false, null), + new Property("Ice\\.Admin\\.Enabled", false, null), + new Property("Ice\\.Admin\\.Facets", false, null), + new Property("Ice\\.Admin\\.InstanceName", false, null), + new Property("Ice\\.Admin\\.Logger\\.KeepLogs", false, null), + new Property("Ice\\.Admin\\.Logger\\.KeepTraces", false, null), + new Property("Ice\\.Admin\\.Logger\\.Properties", false, null), + new Property("Ice\\.Admin\\.ServerId", false, null), + new Property("Ice\\.BackgroundLocatorCacheUpdates", false, null), + new Property("Ice\\.BatchAutoFlush", true, null), + new Property("Ice\\.BatchAutoFlushSize", false, null), + new Property("Ice\\.ChangeUser", false, null), + new Property("Ice\\.ClientAccessPolicyProtocol", false, null), + new Property("Ice\\.Compression\\.Level", false, null), + new Property("Ice\\.CollectObjects", false, null), + new Property("Ice\\.Config", false, null), + new Property("Ice\\.ConsoleListener", false, null), + new Property("Ice\\.Default\\.CollocationOptimized", false, null), + new Property("Ice\\.Default\\.EncodingVersion", false, null), + new Property("Ice\\.Default\\.EndpointSelection", false, null), + new Property("Ice\\.Default\\.Host", false, null), + new Property("Ice\\.Default\\.Locator\\.EndpointSelection", false, null), + new Property("Ice\\.Default\\.Locator\\.ConnectionCached", false, null), + new Property("Ice\\.Default\\.Locator\\.PreferSecure", false, null), + new Property("Ice\\.Default\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("Ice\\.Default\\.Locator\\.InvocationTimeout", false, null), + new Property("Ice\\.Default\\.Locator\\.Locator", false, null), + new Property("Ice\\.Default\\.Locator\\.Router", false, null), + new Property("Ice\\.Default\\.Locator\\.CollocationOptimized", false, null), + new Property("Ice\\.Default\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("Ice\\.Default\\.Locator", false, null), + new Property("Ice\\.Default\\.LocatorCacheTimeout", false, null), + new Property("Ice\\.Default\\.InvocationTimeout", false, null), + new Property("Ice\\.Default\\.Package", false, null), + new Property("Ice\\.Default\\.PreferSecure", false, null), + new Property("Ice\\.Default\\.Protocol", false, null), + new Property("Ice\\.Default\\.Router\\.EndpointSelection", false, null), + new Property("Ice\\.Default\\.Router\\.ConnectionCached", false, null), + new Property("Ice\\.Default\\.Router\\.PreferSecure", false, null), + new Property("Ice\\.Default\\.Router\\.LocatorCacheTimeout", false, null), + new Property("Ice\\.Default\\.Router\\.InvocationTimeout", false, null), + new Property("Ice\\.Default\\.Router\\.Locator", false, null), + new Property("Ice\\.Default\\.Router\\.Router", false, null), + new Property("Ice\\.Default\\.Router\\.CollocationOptimized", false, null), + new Property("Ice\\.Default\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("Ice\\.Default\\.Router", false, null), + new Property("Ice\\.Default\\.SlicedFormat", false, null), + new Property("Ice\\.Default\\.SourceAddress", false, null), + new Property("Ice\\.Default\\.Timeout", false, null), + new Property("Ice\\.EventLog\\.Source", false, null), + new Property("Ice\\.FactoryAssemblies", false, null), + new Property("Ice\\.HTTPProxyHost", false, null), + new Property("Ice\\.HTTPProxyPort", false, null), + new Property("Ice\\.ImplicitContext", false, null), + new Property("Ice\\.InitPlugins", false, null), + new Property("Ice\\.IPv4", false, null), + new Property("Ice\\.IPv6", false, null), + new Property("Ice\\.LogFile", false, null), + new Property("Ice\\.LogFile\\.SizeMax", false, null), + new Property("Ice\\.LogStdErr\\.Convert", false, null), + new Property("Ice\\.MessageSizeMax", false, null), + new Property("Ice\\.Nohup", false, null), + new Property("Ice\\.NullHandleAbort", false, null), + new Property("Ice\\.Override\\.CloseTimeout", false, null), + new Property("Ice\\.Override\\.Compress", false, null), + new Property("Ice\\.Override\\.ConnectTimeout", false, null), + new Property("Ice\\.Override\\.Timeout", false, null), + new Property("Ice\\.Override\\.Secure", false, null), + new Property("Ice\\.Package\\.[^\\s]+", false, null), + new Property("Ice\\.Plugin\\.[^\\s]+", false, null), + new Property("Ice\\.PluginLoadOrder", false, null), + new Property("Ice\\.PreferIPv6Address", false, null), + new Property("Ice\\.PrintAdapterReady", false, null), + new Property("Ice\\.PrintProcessId", false, null), + new Property("Ice\\.PrintStackTraces", false, null), + new Property("Ice\\.ProgramName", false, null), + new Property("Ice\\.RetryIntervals", false, null), + new Property("Ice\\.ServerIdleTime", false, null), + new Property("Ice\\.SOCKSProxyHost", false, null), + new Property("Ice\\.SOCKSProxyPort", false, null), + new Property("Ice\\.StdErr", false, null), + new Property("Ice\\.StdOut", false, null), + new Property("Ice\\.SyslogFacility", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.Size", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.SizeMax", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.SizeWarn", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.StackSize", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.Serialize", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.ThreadIdleTime", false, null), + new Property("Ice\\.ThreadPool\\.Client\\.ThreadPriority", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.Size", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.SizeMax", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.SizeWarn", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.StackSize", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.Serialize", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.ThreadIdleTime", false, null), + new Property("Ice\\.ThreadPool\\.Server\\.ThreadPriority", false, null), + new Property("Ice\\.ThreadPriority", false, null), + new Property("Ice\\.Trace\\.Admin\\.Properties", false, null), + new Property("Ice\\.Trace\\.Admin\\.Logger", false, null), + new Property("Ice\\.Trace\\.Locator", false, null), + new Property("Ice\\.Trace\\.Network", false, null), + new Property("Ice\\.Trace\\.Protocol", false, null), + new Property("Ice\\.Trace\\.Retry", false, null), + new Property("Ice\\.Trace\\.Slicing", false, null), + new Property("Ice\\.Trace\\.ThreadPool", false, null), + new Property("Ice\\.UDP\\.RcvSize", false, null), + new Property("Ice\\.UDP\\.SndSize", false, null), + new Property("Ice\\.TCP\\.Backlog", false, null), + new Property("Ice\\.TCP\\.RcvSize", false, null), + new Property("Ice\\.TCP\\.SndSize", false, null), + new Property("Ice\\.UseApplicationClassLoader", false, null), + new Property("Ice\\.UseSyslog", false, null), + new Property("Ice\\.Warn\\.AMICallback", false, null), + new Property("Ice\\.Warn\\.Connections", false, null), + new Property("Ice\\.Warn\\.Datagrams", false, null), + new Property("Ice\\.Warn\\.Dispatch", false, null), + new Property("Ice\\.Warn\\.Endpoints", false, null), + new Property("Ice\\.Warn\\.UnknownProperties", false, null), + new Property("Ice\\.Warn\\.UnusedProperties", false, null), + new Property("Ice\\.CacheMessageBuffers", false, null), + new Property("Ice\\.ThreadInterruptSafe", false, null), + new Property("Ice\\.Voip", false, null), + null + }; + + public static final Property IceMXProps[] = + { + new Property("IceMX\\.Metrics\\.[^\\s]+\\.GroupBy", false, null), + new Property("IceMX\\.Metrics\\.[^\\s]+\\.Map", false, null), + new Property("IceMX\\.Metrics\\.[^\\s]+\\.RetainDetached", false, null), + new Property("IceMX\\.Metrics\\.[^\\s]+\\.Accept", false, null), + new Property("IceMX\\.Metrics\\.[^\\s]+\\.Reject", false, null), + new Property("IceMX\\.Metrics\\.[^\\s]+", false, null), + null + }; + + public static final Property IceDiscoveryProps[] = + { + new Property("IceDiscovery\\.Multicast\\.ACM\\.Timeout", false, null), + new Property("IceDiscovery\\.Multicast\\.ACM\\.Heartbeat", false, null), + new Property("IceDiscovery\\.Multicast\\.ACM\\.Close", false, null), + new Property("IceDiscovery\\.Multicast\\.ACM", false, null), + new Property("IceDiscovery\\.Multicast\\.AdapterId", false, null), + new Property("IceDiscovery\\.Multicast\\.Endpoints", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.EndpointSelection", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.ConnectionCached", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.PreferSecure", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.InvocationTimeout", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.Locator", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.Router", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.CollocationOptimized", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceDiscovery\\.Multicast\\.Locator", false, null), + new Property("IceDiscovery\\.Multicast\\.PublishedEndpoints", false, null), + new Property("IceDiscovery\\.Multicast\\.ReplicaGroupId", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.EndpointSelection", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.ConnectionCached", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.PreferSecure", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.InvocationTimeout", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.Locator", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.Router", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.CollocationOptimized", false, null), + new Property("IceDiscovery\\.Multicast\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceDiscovery\\.Multicast\\.Router", false, null), + new Property("IceDiscovery\\.Multicast\\.ProxyOptions", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.Size", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.SizeMax", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.StackSize", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.Serialize", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceDiscovery\\.Multicast\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceDiscovery\\.Multicast\\.MessageSizeMax", false, null), + new Property("IceDiscovery\\.Reply\\.ACM\\.Timeout", false, null), + new Property("IceDiscovery\\.Reply\\.ACM\\.Heartbeat", false, null), + new Property("IceDiscovery\\.Reply\\.ACM\\.Close", false, null), + new Property("IceDiscovery\\.Reply\\.ACM", false, null), + new Property("IceDiscovery\\.Reply\\.AdapterId", false, null), + new Property("IceDiscovery\\.Reply\\.Endpoints", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.EndpointSelection", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.ConnectionCached", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.PreferSecure", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.InvocationTimeout", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.Locator", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.Router", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.CollocationOptimized", false, null), + new Property("IceDiscovery\\.Reply\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceDiscovery\\.Reply\\.Locator", false, null), + new Property("IceDiscovery\\.Reply\\.PublishedEndpoints", false, null), + new Property("IceDiscovery\\.Reply\\.ReplicaGroupId", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.EndpointSelection", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.ConnectionCached", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.PreferSecure", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.InvocationTimeout", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.Locator", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.Router", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.CollocationOptimized", false, null), + new Property("IceDiscovery\\.Reply\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceDiscovery\\.Reply\\.Router", false, null), + new Property("IceDiscovery\\.Reply\\.ProxyOptions", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.Size", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.SizeMax", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.StackSize", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.Serialize", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceDiscovery\\.Reply\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceDiscovery\\.Reply\\.MessageSizeMax", false, null), + new Property("IceDiscovery\\.Locator\\.ACM\\.Timeout", false, null), + new Property("IceDiscovery\\.Locator\\.ACM\\.Heartbeat", false, null), + new Property("IceDiscovery\\.Locator\\.ACM\\.Close", false, null), + new Property("IceDiscovery\\.Locator\\.ACM", false, null), + new Property("IceDiscovery\\.Locator\\.AdapterId", false, null), + new Property("IceDiscovery\\.Locator\\.Endpoints", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.EndpointSelection", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.ConnectionCached", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.PreferSecure", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.InvocationTimeout", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.Locator", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.Router", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.CollocationOptimized", false, null), + new Property("IceDiscovery\\.Locator\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceDiscovery\\.Locator\\.Locator", false, null), + new Property("IceDiscovery\\.Locator\\.PublishedEndpoints", false, null), + new Property("IceDiscovery\\.Locator\\.ReplicaGroupId", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.EndpointSelection", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.ConnectionCached", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.PreferSecure", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.InvocationTimeout", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.Locator", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.Router", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.CollocationOptimized", false, null), + new Property("IceDiscovery\\.Locator\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceDiscovery\\.Locator\\.Router", false, null), + new Property("IceDiscovery\\.Locator\\.ProxyOptions", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.Size", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.SizeMax", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.StackSize", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.Serialize", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceDiscovery\\.Locator\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceDiscovery\\.Locator\\.MessageSizeMax", false, null), + new Property("IceDiscovery\\.Lookup", false, null), + new Property("IceDiscovery\\.Timeout", false, null), + new Property("IceDiscovery\\.RetryCount", false, null), + new Property("IceDiscovery\\.LatencyMultiplier", false, null), + new Property("IceDiscovery\\.Address", false, null), + new Property("IceDiscovery\\.Port", false, null), + new Property("IceDiscovery\\.Interface", false, null), + new Property("IceDiscovery\\.DomainId", false, null), + null + }; + + public static final Property IceGridDiscoveryProps[] = + { + new Property("IceGridDiscovery\\.Reply\\.ACM\\.Timeout", false, null), + new Property("IceGridDiscovery\\.Reply\\.ACM\\.Heartbeat", false, null), + new Property("IceGridDiscovery\\.Reply\\.ACM\\.Close", false, null), + new Property("IceGridDiscovery\\.Reply\\.ACM", false, null), + new Property("IceGridDiscovery\\.Reply\\.AdapterId", false, null), + new Property("IceGridDiscovery\\.Reply\\.Endpoints", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.EndpointSelection", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.ConnectionCached", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.PreferSecure", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.Locator", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.Router", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGridDiscovery\\.Reply\\.Locator", false, null), + new Property("IceGridDiscovery\\.Reply\\.PublishedEndpoints", false, null), + new Property("IceGridDiscovery\\.Reply\\.ReplicaGroupId", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.EndpointSelection", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.ConnectionCached", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.PreferSecure", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.InvocationTimeout", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.Locator", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.Router", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.CollocationOptimized", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGridDiscovery\\.Reply\\.Router", false, null), + new Property("IceGridDiscovery\\.Reply\\.ProxyOptions", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.Size", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.StackSize", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.Serialize", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGridDiscovery\\.Reply\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGridDiscovery\\.Reply\\.MessageSizeMax", false, null), + new Property("IceGridDiscovery\\.Locator\\.ACM\\.Timeout", false, null), + new Property("IceGridDiscovery\\.Locator\\.ACM\\.Heartbeat", false, null), + new Property("IceGridDiscovery\\.Locator\\.ACM\\.Close", false, null), + new Property("IceGridDiscovery\\.Locator\\.ACM", false, null), + new Property("IceGridDiscovery\\.Locator\\.AdapterId", false, null), + new Property("IceGridDiscovery\\.Locator\\.Endpoints", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.EndpointSelection", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.ConnectionCached", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.PreferSecure", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.Locator", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.Router", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGridDiscovery\\.Locator\\.Locator", false, null), + new Property("IceGridDiscovery\\.Locator\\.PublishedEndpoints", false, null), + new Property("IceGridDiscovery\\.Locator\\.ReplicaGroupId", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.EndpointSelection", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.ConnectionCached", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.PreferSecure", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.InvocationTimeout", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.Locator", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.Router", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.CollocationOptimized", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGridDiscovery\\.Locator\\.Router", false, null), + new Property("IceGridDiscovery\\.Locator\\.ProxyOptions", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.Size", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.StackSize", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.Serialize", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGridDiscovery\\.Locator\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGridDiscovery\\.Locator\\.MessageSizeMax", false, null), + new Property("IceGridDiscovery\\.Lookup", false, null), + new Property("IceGridDiscovery\\.Timeout", false, null), + new Property("IceGridDiscovery\\.RetryCount", false, null), + new Property("IceGridDiscovery\\.RetryDelay", false, null), + new Property("IceGridDiscovery\\.Address", false, null), + new Property("IceGridDiscovery\\.Port", false, null), + new Property("IceGridDiscovery\\.Interface", false, null), + new Property("IceGridDiscovery\\.InstanceName", false, null), + null + }; + + public static final Property IceBoxProps[] = + { + new Property("IceBox\\.InheritProperties", false, null), + new Property("IceBox\\.InstanceName", true, null), + new Property("IceBox\\.LoadOrder", false, null), + new Property("IceBox\\.PrintServicesReady", false, null), + new Property("IceBox\\.Service\\.[^\\s]+", false, null), + new Property("IceBox\\.ServiceManager\\.AdapterId", true, null), + new Property("IceBox\\.ServiceManager\\.Endpoints", true, null), + new Property("IceBox\\.ServiceManager\\.Locator", true, null), + new Property("IceBox\\.ServiceManager\\.PublishedEndpoints", true, null), + new Property("IceBox\\.ServiceManager\\.ReplicaGroupId", true, null), + new Property("IceBox\\.ServiceManager\\.Router", true, null), + new Property("IceBox\\.ServiceManager\\.ThreadPool\\.Size", true, null), + new Property("IceBox\\.ServiceManager\\.ThreadPool\\.SizeMax", true, null), + new Property("IceBox\\.ServiceManager\\.ThreadPool\\.SizeWarn", true, null), + new Property("IceBox\\.ServiceManager\\.ThreadPool\\.StackSize", true, null), + new Property("IceBox\\.Trace\\.ServiceObserver", false, null), + new Property("IceBox\\.UseSharedCommunicator\\.[^\\s]+", false, null), + null + }; + + public static final Property IceBoxAdminProps[] = + { + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.EndpointSelection", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.ConnectionCached", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.PreferSecure", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.LocatorCacheTimeout", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.InvocationTimeout", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.Locator", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.Router", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.CollocationOptimized", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy\\.Context\\.[^\\s]+", false, null), + new Property("IceBoxAdmin\\.ServiceManager\\.Proxy", false, null), + null + }; + + public static final Property IceGridAdminProps[] = + { + new Property("IceGridAdmin\\.AuthenticateUsingSSL", false, null), + new Property("IceGridAdmin\\.MetricsConfig", false, null), + new Property("IceGridAdmin\\.Username", false, null), + new Property("IceGridAdmin\\.Password", false, null), + new Property("IceGridAdmin\\.Replica", false, null), + new Property("IceGridAdmin\\.Host", false, null), + new Property("IceGridAdmin\\.Port", false, null), + new Property("IceGridAdmin\\.InstanceName", false, null), + new Property("IceGridAdmin\\.Discovery\\.Address", false, null), + new Property("IceGridAdmin\\.Discovery\\.Interface", false, null), + new Property("IceGridAdmin\\.Discovery\\.Lookup", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ACM\\.Timeout", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ACM\\.Heartbeat", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ACM\\.Close", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ACM", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.AdapterId", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Endpoints", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.EndpointSelection", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.ConnectionCached", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.PreferSecure", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.Locator", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.Router", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Locator", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.PublishedEndpoints", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ReplicaGroupId", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.EndpointSelection", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.ConnectionCached", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.PreferSecure", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.InvocationTimeout", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.Locator", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.Router", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.CollocationOptimized", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.Router", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ProxyOptions", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.Size", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.StackSize", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.Serialize", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGridAdmin\\.Discovery\\.Reply\\.MessageSizeMax", false, null), + new Property("IceGridAdmin\\.Trace\\.Observers", false, null), + new Property("IceGridAdmin\\.Trace\\.SaveToRegistry", false, null), + null + }; + + public static final Property IceGridProps[] = + { + new Property("IceGrid\\.AdminRouter\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.AdminRouter\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.AdminRouter\\.ACM\\.Close", false, null), + new Property("IceGrid\\.AdminRouter\\.ACM", false, null), + new Property("IceGrid\\.AdminRouter\\.AdapterId", false, null), + new Property("IceGrid\\.AdminRouter\\.Endpoints", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.Router", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.AdminRouter\\.Locator", false, null), + new Property("IceGrid\\.AdminRouter\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.AdminRouter\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.Locator", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.Router", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.AdminRouter\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.AdminRouter\\.Router", false, null), + new Property("IceGrid\\.AdminRouter\\.ProxyOptions", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.AdminRouter\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.AdminRouter\\.MessageSizeMax", false, null), + new Property("IceGrid\\.InstanceName", false, null), + new Property("IceGrid\\.Node\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Node\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Node\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Node\\.ACM", false, null), + new Property("IceGrid\\.Node\\.AdapterId", false, null), + new Property("IceGrid\\.Node\\.Endpoints", false, null), + new Property("IceGrid\\.Node\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Node\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Node\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Node\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Node\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Node\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Node\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Node\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Node\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Node\\.Locator", false, null), + new Property("IceGrid\\.Node\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Node\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Node\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Node\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Node\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Node\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Node\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Node\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Node\\.Router\\.Router", false, null), + new Property("IceGrid\\.Node\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Node\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Node\\.Router", false, null), + new Property("IceGrid\\.Node\\.ProxyOptions", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Node\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Node\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Node\\.AllowRunningServersAsRoot", false, null), + new Property("IceGrid\\.Node\\.AllowEndpointsOverride", false, null), + new Property("IceGrid\\.Node\\.CollocateRegistry", false, null), + new Property("IceGrid\\.Node\\.Data", false, null), + new Property("IceGrid\\.Node\\.DisableOnFailure", false, null), + new Property("IceGrid\\.Node\\.Name", false, null), + new Property("IceGrid\\.Node\\.Output", false, null), + new Property("IceGrid\\.Node\\.ProcessorSocketCount", false, null), + new Property("IceGrid\\.Node\\.PrintServersReady", false, null), + new Property("IceGrid\\.Node\\.PropertiesOverride", false, null), + new Property("IceGrid\\.Node\\.RedirectErrToOut", false, null), + new Property("IceGrid\\.Node\\.Trace\\.Activator", false, null), + new Property("IceGrid\\.Node\\.Trace\\.Adapter", false, null), + new Property("IceGrid\\.Node\\.Trace\\.Patch", false, null), + new Property("IceGrid\\.Node\\.Trace\\.Replica", false, null), + new Property("IceGrid\\.Node\\.Trace\\.Server", false, null), + new Property("IceGrid\\.Node\\.UserAccounts", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.EndpointSelection", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.ConnectionCached", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.PreferSecure", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.Locator", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.Router", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Node\\.UserAccountMapper", false, null), + new Property("IceGrid\\.Node\\.WaitTime", false, null), + new Property("IceGrid\\.Registry\\.AdminCryptPasswords", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.Router", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.AdminPermissionsVerifier", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionFilters", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ACM", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.AdapterId", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Endpoints", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.Router", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.Router", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ProxyOptions", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Registry\\.AdminSessionManager\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.Router", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.AdminSSLPermissionsVerifier", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ACM", false, null), + new Property("IceGrid\\.Registry\\.Client\\.AdapterId", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Endpoints", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Client\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Client\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ProxyOptions", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Registry\\.Client\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Registry\\.Client\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Registry\\.CryptPasswords", false, null), + new Property("IceGrid\\.Registry\\.DefaultTemplates", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ACM", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.AdapterId", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Endpoints", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ProxyOptions", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Enabled", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Address", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Port", false, null), + new Property("IceGrid\\.Registry\\.Discovery\\.Interface", false, null), + new Property("IceGrid\\.Registry\\.DynamicRegistration", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ACM", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.AdapterId", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Endpoints", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ProxyOptions", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Registry\\.Internal\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Registry\\.LMDB\\.MapSize", false, null), + new Property("IceGrid\\.Registry\\.LMDB\\.Path", false, null), + new Property("IceGrid\\.Registry\\.NodeSessionTimeout", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.Router", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.PermissionsVerifier", false, null), + new Property("IceGrid\\.Registry\\.ReplicaName", false, null), + new Property("IceGrid\\.Registry\\.ReplicaSessionTimeout", false, null), + new Property("IceGrid\\.Registry\\.RequireNodeCertCN", false, null), + new Property("IceGrid\\.Registry\\.RequireReplicaCertCN", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ACM", false, null), + new Property("IceGrid\\.Registry\\.Server\\.AdapterId", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Endpoints", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Server\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.Server\\.Router", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ProxyOptions", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Registry\\.Server\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Registry\\.Server\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Registry\\.SessionFilters", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ACM\\.Timeout", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ACM\\.Heartbeat", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ACM\\.Close", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ACM", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.AdapterId", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Endpoints", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.Router", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.PublishedEndpoints", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ReplicaGroupId", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.Router", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.Router", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ProxyOptions", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.Size", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.SizeMax", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.SizeWarn", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.StackSize", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.Serialize", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IceGrid\\.Registry\\.SessionManager\\.MessageSizeMax", false, null), + new Property("IceGrid\\.Registry\\.SessionTimeout", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.EndpointSelection", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.ConnectionCached", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.PreferSecure", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.LocatorCacheTimeout", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.InvocationTimeout", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.Router", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.CollocationOptimized", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier\\.Context\\.[^\\s]+", false, null), + new Property("IceGrid\\.Registry\\.SSLPermissionsVerifier", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Application", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Adapter", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Locator", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Node", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Object", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Patch", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Replica", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Server", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Session", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Subscriber", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.Topic", false, null), + new Property("IceGrid\\.Registry\\.Trace\\.TopicManager", false, null), + new Property("IceGrid\\.Registry\\.UserAccounts", false, null), + null + }; + + public static final Property IcePatch2Props[] = + { + new Property("IcePatch2\\.ACM\\.Timeout", false, null), + new Property("IcePatch2\\.ACM\\.Heartbeat", false, null), + new Property("IcePatch2\\.ACM\\.Close", false, null), + new Property("IcePatch2\\.ACM", false, null), + new Property("IcePatch2\\.AdapterId", false, null), + new Property("IcePatch2\\.Endpoints", false, null), + new Property("IcePatch2\\.Locator\\.EndpointSelection", false, null), + new Property("IcePatch2\\.Locator\\.ConnectionCached", false, null), + new Property("IcePatch2\\.Locator\\.PreferSecure", false, null), + new Property("IcePatch2\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("IcePatch2\\.Locator\\.InvocationTimeout", false, null), + new Property("IcePatch2\\.Locator\\.Locator", false, null), + new Property("IcePatch2\\.Locator\\.Router", false, null), + new Property("IcePatch2\\.Locator\\.CollocationOptimized", false, null), + new Property("IcePatch2\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("IcePatch2\\.Locator", false, null), + new Property("IcePatch2\\.PublishedEndpoints", false, null), + new Property("IcePatch2\\.ReplicaGroupId", false, null), + new Property("IcePatch2\\.Router\\.EndpointSelection", false, null), + new Property("IcePatch2\\.Router\\.ConnectionCached", false, null), + new Property("IcePatch2\\.Router\\.PreferSecure", false, null), + new Property("IcePatch2\\.Router\\.LocatorCacheTimeout", false, null), + new Property("IcePatch2\\.Router\\.InvocationTimeout", false, null), + new Property("IcePatch2\\.Router\\.Locator", false, null), + new Property("IcePatch2\\.Router\\.Router", false, null), + new Property("IcePatch2\\.Router\\.CollocationOptimized", false, null), + new Property("IcePatch2\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("IcePatch2\\.Router", false, null), + new Property("IcePatch2\\.ProxyOptions", false, null), + new Property("IcePatch2\\.ThreadPool\\.Size", false, null), + new Property("IcePatch2\\.ThreadPool\\.SizeMax", false, null), + new Property("IcePatch2\\.ThreadPool\\.SizeWarn", false, null), + new Property("IcePatch2\\.ThreadPool\\.StackSize", false, null), + new Property("IcePatch2\\.ThreadPool\\.Serialize", false, null), + new Property("IcePatch2\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("IcePatch2\\.ThreadPool\\.ThreadPriority", false, null), + new Property("IcePatch2\\.MessageSizeMax", false, null), + new Property("IcePatch2\\.Directory", false, null), + new Property("IcePatch2\\.InstanceName", false, null), + null + }; + + public static final Property IcePatch2ClientProps[] = + { + new Property("IcePatch2Client\\.ChunkSize", false, null), + new Property("IcePatch2Client\\.Directory", false, null), + new Property("IcePatch2Client\\.Proxy", false, null), + new Property("IcePatch2Client\\.Remove", false, null), + new Property("IcePatch2Client\\.Thorough", false, null), + null + }; + + public static final Property IceSSLProps[] = + { + new Property("IceSSL\\.Alias", false, null), + new Property("IceSSL\\.CAs", false, null), + new Property("IceSSL\\.CertAuthDir", true, "IceSSL.CAs"), + new Property("IceSSL\\.CertAuthFile", true, "IceSSL.CAs"), + new Property("IceSSL\\.CertStore", false, null), + new Property("IceSSL\\.CertStoreLocation", false, null), + new Property("IceSSL\\.CertFile", false, null), + new Property("IceSSL\\.CertVerifier", false, null), + new Property("IceSSL\\.CheckCertName", false, null), + new Property("IceSSL\\.CheckCRL", false, null), + new Property("IceSSL\\.Ciphers", false, null), + new Property("IceSSL\\.DefaultDir", false, null), + new Property("IceSSL\\.DH\\.[^\\s]+", false, null), + new Property("IceSSL\\.DHParams", false, null), + new Property("IceSSL\\.EntropyDaemon", false, null), + new Property("IceSSL\\.FindCert", false, null), + new Property("IceSSL\\.FindCert\\.[^\\s]+", true, "IceSSL.FindCert"), + new Property("IceSSL\\.InitOpenSSL", false, null), + new Property("IceSSL\\.KeyFile", true, null), + new Property("IceSSL\\.Keychain", false, null), + new Property("IceSSL\\.KeychainPassword", false, null), + new Property("IceSSL\\.Keystore", false, null), + new Property("IceSSL\\.KeystorePassword", false, null), + new Property("IceSSL\\.KeystoreType", false, null), + new Property("IceSSL\\.Password", false, null), + new Property("IceSSL\\.PasswordCallback", false, null), + new Property("IceSSL\\.PasswordRetryMax", false, null), + new Property("IceSSL\\.Protocols", false, null), + new Property("IceSSL\\.ProtocolVersionMax", false, null), + new Property("IceSSL\\.ProtocolVersionMin", false, null), + new Property("IceSSL\\.Random", false, null), + new Property("IceSSL\\.Trace\\.Security", false, null), + new Property("IceSSL\\.TrustOnly", false, null), + new Property("IceSSL\\.TrustOnly\\.Client", false, null), + new Property("IceSSL\\.TrustOnly\\.Server", false, null), + new Property("IceSSL\\.TrustOnly\\.Server\\.[^\\s]+", false, null), + new Property("IceSSL\\.Truststore", false, null), + new Property("IceSSL\\.TruststorePassword", false, null), + new Property("IceSSL\\.TruststoreType", false, null), + new Property("IceSSL\\.UsePlatformCAs", false, null), + new Property("IceSSL\\.VerifyDepthMax", false, null), + new Property("IceSSL\\.VerifyPeer", false, null), + null + }; + + public static final Property IceStormAdminProps[] = + { + new Property("IceStormAdmin\\.TopicManager\\.[^\\s]+", false, null), + new Property("IceStormAdmin\\.Host", false, null), + new Property("IceStormAdmin\\.Port", false, null), + null + }; + + public static final Property IceBTProps[] = + { + new Property("IceBT\\.RcvSize", false, null), + new Property("IceBT\\.SndSize", false, null), + null + }; + + public static final Property Glacier2Props[] = + { + new Property("Glacier2\\.AddConnectionContext", false, null), + new Property("Glacier2\\.Client\\.ACM\\.Timeout", false, null), + new Property("Glacier2\\.Client\\.ACM\\.Heartbeat", false, null), + new Property("Glacier2\\.Client\\.ACM\\.Close", false, null), + new Property("Glacier2\\.Client\\.ACM", false, null), + new Property("Glacier2\\.Client\\.AdapterId", false, null), + new Property("Glacier2\\.Client\\.Endpoints", false, null), + new Property("Glacier2\\.Client\\.Locator\\.EndpointSelection", false, null), + new Property("Glacier2\\.Client\\.Locator\\.ConnectionCached", false, null), + new Property("Glacier2\\.Client\\.Locator\\.PreferSecure", false, null), + new Property("Glacier2\\.Client\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.Client\\.Locator\\.InvocationTimeout", false, null), + new Property("Glacier2\\.Client\\.Locator\\.Locator", false, null), + new Property("Glacier2\\.Client\\.Locator\\.Router", false, null), + new Property("Glacier2\\.Client\\.Locator\\.CollocationOptimized", false, null), + new Property("Glacier2\\.Client\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.Client\\.Locator", false, null), + new Property("Glacier2\\.Client\\.PublishedEndpoints", false, null), + new Property("Glacier2\\.Client\\.ReplicaGroupId", false, null), + new Property("Glacier2\\.Client\\.Router\\.EndpointSelection", false, null), + new Property("Glacier2\\.Client\\.Router\\.ConnectionCached", false, null), + new Property("Glacier2\\.Client\\.Router\\.PreferSecure", false, null), + new Property("Glacier2\\.Client\\.Router\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.Client\\.Router\\.InvocationTimeout", false, null), + new Property("Glacier2\\.Client\\.Router\\.Locator", false, null), + new Property("Glacier2\\.Client\\.Router\\.Router", false, null), + new Property("Glacier2\\.Client\\.Router\\.CollocationOptimized", false, null), + new Property("Glacier2\\.Client\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.Client\\.Router", false, null), + new Property("Glacier2\\.Client\\.ProxyOptions", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.Size", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.SizeMax", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.SizeWarn", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.StackSize", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.Serialize", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("Glacier2\\.Client\\.ThreadPool\\.ThreadPriority", false, null), + new Property("Glacier2\\.Client\\.MessageSizeMax", false, null), + new Property("Glacier2\\.Client\\.AlwaysBatch", false, null), + new Property("Glacier2\\.Client\\.Buffered", false, null), + new Property("Glacier2\\.Client\\.ForwardContext", false, null), + new Property("Glacier2\\.Client\\.SleepTime", false, null), + new Property("Glacier2\\.Client\\.Trace\\.Override", false, null), + new Property("Glacier2\\.Client\\.Trace\\.Reject", false, null), + new Property("Glacier2\\.Client\\.Trace\\.Request", false, null), + new Property("Glacier2\\.CryptPasswords", false, null), + new Property("Glacier2\\.Filter\\.Address\\.Reject", false, null), + new Property("Glacier2\\.Filter\\.Address\\.Accept", false, null), + new Property("Glacier2\\.Filter\\.ProxySizeMax", false, null), + new Property("Glacier2\\.Filter\\.Category\\.Accept", false, null), + new Property("Glacier2\\.Filter\\.Category\\.AcceptUser", false, null), + new Property("Glacier2\\.Filter\\.AdapterId\\.Accept", false, null), + new Property("Glacier2\\.Filter\\.Identity\\.Accept", false, null), + new Property("Glacier2\\.InstanceName", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.EndpointSelection", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.ConnectionCached", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.PreferSecure", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.InvocationTimeout", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.Locator", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.Router", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.CollocationOptimized", false, null), + new Property("Glacier2\\.PermissionsVerifier\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.PermissionsVerifier", false, null), + new Property("Glacier2\\.ReturnClientProxy", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.EndpointSelection", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.ConnectionCached", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.PreferSecure", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.InvocationTimeout", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.Locator", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.Router", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.CollocationOptimized", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.SSLPermissionsVerifier", false, null), + new Property("Glacier2\\.RoutingTable\\.MaxSize", false, null), + new Property("Glacier2\\.Server\\.ACM\\.Timeout", false, null), + new Property("Glacier2\\.Server\\.ACM\\.Heartbeat", false, null), + new Property("Glacier2\\.Server\\.ACM\\.Close", false, null), + new Property("Glacier2\\.Server\\.ACM", false, null), + new Property("Glacier2\\.Server\\.AdapterId", false, null), + new Property("Glacier2\\.Server\\.Endpoints", false, null), + new Property("Glacier2\\.Server\\.Locator\\.EndpointSelection", false, null), + new Property("Glacier2\\.Server\\.Locator\\.ConnectionCached", false, null), + new Property("Glacier2\\.Server\\.Locator\\.PreferSecure", false, null), + new Property("Glacier2\\.Server\\.Locator\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.Server\\.Locator\\.InvocationTimeout", false, null), + new Property("Glacier2\\.Server\\.Locator\\.Locator", false, null), + new Property("Glacier2\\.Server\\.Locator\\.Router", false, null), + new Property("Glacier2\\.Server\\.Locator\\.CollocationOptimized", false, null), + new Property("Glacier2\\.Server\\.Locator\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.Server\\.Locator", false, null), + new Property("Glacier2\\.Server\\.PublishedEndpoints", false, null), + new Property("Glacier2\\.Server\\.ReplicaGroupId", false, null), + new Property("Glacier2\\.Server\\.Router\\.EndpointSelection", false, null), + new Property("Glacier2\\.Server\\.Router\\.ConnectionCached", false, null), + new Property("Glacier2\\.Server\\.Router\\.PreferSecure", false, null), + new Property("Glacier2\\.Server\\.Router\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.Server\\.Router\\.InvocationTimeout", false, null), + new Property("Glacier2\\.Server\\.Router\\.Locator", false, null), + new Property("Glacier2\\.Server\\.Router\\.Router", false, null), + new Property("Glacier2\\.Server\\.Router\\.CollocationOptimized", false, null), + new Property("Glacier2\\.Server\\.Router\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.Server\\.Router", false, null), + new Property("Glacier2\\.Server\\.ProxyOptions", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.Size", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.SizeMax", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.SizeWarn", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.StackSize", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.Serialize", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.ThreadIdleTime", false, null), + new Property("Glacier2\\.Server\\.ThreadPool\\.ThreadPriority", false, null), + new Property("Glacier2\\.Server\\.MessageSizeMax", false, null), + new Property("Glacier2\\.Server\\.AlwaysBatch", false, null), + new Property("Glacier2\\.Server\\.Buffered", false, null), + new Property("Glacier2\\.Server\\.ForwardContext", false, null), + new Property("Glacier2\\.Server\\.SleepTime", false, null), + new Property("Glacier2\\.Server\\.Trace\\.Override", false, null), + new Property("Glacier2\\.Server\\.Trace\\.Request", false, null), + new Property("Glacier2\\.SessionManager\\.EndpointSelection", false, null), + new Property("Glacier2\\.SessionManager\\.ConnectionCached", false, null), + new Property("Glacier2\\.SessionManager\\.PreferSecure", false, null), + new Property("Glacier2\\.SessionManager\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.SessionManager\\.InvocationTimeout", false, null), + new Property("Glacier2\\.SessionManager\\.Locator", false, null), + new Property("Glacier2\\.SessionManager\\.Router", false, null), + new Property("Glacier2\\.SessionManager\\.CollocationOptimized", false, null), + new Property("Glacier2\\.SessionManager\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.SessionManager", false, null), + new Property("Glacier2\\.SSLSessionManager\\.EndpointSelection", false, null), + new Property("Glacier2\\.SSLSessionManager\\.ConnectionCached", false, null), + new Property("Glacier2\\.SSLSessionManager\\.PreferSecure", false, null), + new Property("Glacier2\\.SSLSessionManager\\.LocatorCacheTimeout", false, null), + new Property("Glacier2\\.SSLSessionManager\\.InvocationTimeout", false, null), + new Property("Glacier2\\.SSLSessionManager\\.Locator", false, null), + new Property("Glacier2\\.SSLSessionManager\\.Router", false, null), + new Property("Glacier2\\.SSLSessionManager\\.CollocationOptimized", false, null), + new Property("Glacier2\\.SSLSessionManager\\.Context\\.[^\\s]+", false, null), + new Property("Glacier2\\.SSLSessionManager", false, null), + new Property("Glacier2\\.SessionTimeout", false, null), + new Property("Glacier2\\.Trace\\.RoutingTable", false, null), + new Property("Glacier2\\.Trace\\.Session", false, null), + null + }; + + public static final Property Glacier2CryptPermissionsVerifierProps[] = + { + new Property("Glacier2CryptPermissionsVerifier\\.[^\\s]+\\.PermissionsVerifier", false, null), + new Property("Glacier2CryptPermissionsVerifier\\.[^\\s]+\\.AdminPermissionsVerifier", false, null), + null + }; + + public static final Property FreezeProps[] = + { + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.CheckpointPeriod", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.DbHome", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.DbPrivate", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.DbRecoverFatal", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.EncodingVersion", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.LockFile", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.OldLogsAutoDelete", false, null), + new Property("Freeze\\.DbEnv\\.[^\\s]+\\.PeriodicCheckpointMinSize", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.BtreeMinKey", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.Checksum", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.MaxTxSize", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.PageSize", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.PopulateEmptyIndices", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.RollbackOnUserException", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.SavePeriod", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.SaveSizeTrigger", false, null), + new Property("Freeze\\.Evictor\\.[^\\s]+\\.StreamTimeout", false, null), + new Property("Freeze\\.Map\\.[^\\s]+\\.BtreeMinKey", false, null), + new Property("Freeze\\.Map\\.[^\\s]+\\.Checksum", false, null), + new Property("Freeze\\.Map\\.[^\\s]+\\.PageSize", false, null), + new Property("Freeze\\.Trace\\.DbEnv", false, null), + new Property("Freeze\\.Trace\\.Evictor", false, null), + new Property("Freeze\\.Trace\\.Map", false, null), + new Property("Freeze\\.Trace\\.Transaction", false, null), + new Property("Freeze\\.Warn\\.Deadlocks", false, null), + new Property("Freeze\\.Warn\\.Rollback", false, null), + null + }; + + + public static final Property[] validProps[] = + { + IceProps, + IceMXProps, + IceDiscoveryProps, + IceGridDiscoveryProps, + IceBoxProps, + IceBoxAdminProps, + IceGridAdminProps, + IceGridProps, + IcePatch2Props, + IcePatch2ClientProps, + IceSSLProps, + IceStormAdminProps, + IceBTProps, + Glacier2Props, + Glacier2CryptPermissionsVerifierProps, + FreezeProps, + null + }; + + public static final String clPropNames[] = + { + "Ice", + "IceMX", + "IceDiscovery", + "IceGridDiscovery", + "IceBox", + "IceBoxAdmin", + "IceGridAdmin", + "IceGrid", + "IcePatch2", + "IcePatch2Client", + "IceSSL", + "IceStormAdmin", + "IceBT", + "Glacier2", + "Glacier2CryptPermissionsVerifier", + "Freeze", + null + }; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Protocol.java b/java-compat/src/Ice/src/main/java/IceInternal/Protocol.java new file mode 100644 index 00000000000..01b9a460b42 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Protocol.java @@ -0,0 +1,198 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final public class Protocol +{ + // + // Size of the Ice protocol header + // + // Magic number (4 bytes) + // Protocol version major (Byte) + // Protocol version minor (Byte) + // Encoding version major (Byte) + // Encoding version minor (Byte) + // Message type (Byte) + // Compression status (Byte) + // Message size (Int) + // + public final static int headerSize = 14; + + // + // The magic number at the front of each message + // + public final static byte magic[] = { 0x49, 0x63, 0x65, 0x50 }; // 'I', 'c', 'e', 'P' + + // + // The current Ice protocol and encoding version + // + public final static byte protocolMajor = 1; + public final static byte protocolMinor = 0; + public final static byte protocolEncodingMajor = 1; + public final static byte protocolEncodingMinor = 0; + + public final static byte encodingMajor = 1; + public final static byte encodingMinor = 1; + + // + // The Ice protocol message types + // + public final static byte requestMsg = 0; + public final static byte requestBatchMsg = 1; + public final static byte replyMsg = 2; + public final static byte validateConnectionMsg = 3; + public final static byte closeConnectionMsg = 4; + + public final static byte[] requestHdr = + { + IceInternal.Protocol.magic[0], + IceInternal.Protocol.magic[1], + IceInternal.Protocol.magic[2], + IceInternal.Protocol.magic[3], + IceInternal.Protocol.protocolMajor, + IceInternal.Protocol.protocolMinor, + IceInternal.Protocol.protocolEncodingMajor, + IceInternal.Protocol.protocolEncodingMinor, + IceInternal.Protocol.requestMsg, + (byte)0, // Compression status. + (byte)0, (byte)0, (byte)0, (byte)0, // Message size (placeholder). + (byte)0, (byte)0, (byte)0, (byte)0 // Request ID (placeholder). + }; + + public final static byte[] requestBatchHdr = + { + IceInternal.Protocol.magic[0], + IceInternal.Protocol.magic[1], + IceInternal.Protocol.magic[2], + IceInternal.Protocol.magic[3], + IceInternal.Protocol.protocolMajor, + IceInternal.Protocol.protocolMinor, + IceInternal.Protocol.protocolEncodingMajor, + IceInternal.Protocol.protocolEncodingMinor, + IceInternal.Protocol.requestBatchMsg, + 0, // Compression status. + (byte)0, (byte)0, (byte)0, (byte)0, // Message size (placeholder). + (byte)0, (byte)0, (byte)0, (byte)0 // Number of requests in batch (placeholder). + }; + + public final static byte[] replyHdr = + { + IceInternal.Protocol.magic[0], + IceInternal.Protocol.magic[1], + IceInternal.Protocol.magic[2], + IceInternal.Protocol.magic[3], + IceInternal.Protocol.protocolMajor, + IceInternal.Protocol.protocolMinor, + IceInternal.Protocol.protocolEncodingMajor, + IceInternal.Protocol.protocolEncodingMinor, + IceInternal.Protocol.replyMsg, + (byte)0, // Compression status. + (byte)0, (byte)0, (byte)0, (byte)0 // Message size (placeholder). + }; + + static final public Ice.ProtocolVersion currentProtocol = new Ice.ProtocolVersion(protocolMajor, protocolMinor); + static final public Ice.EncodingVersion currentProtocolEncoding = new Ice.EncodingVersion(protocolEncodingMajor, + protocolEncodingMinor); + + static final public Ice.EncodingVersion currentEncoding = new Ice.EncodingVersion(encodingMajor, encodingMinor); + + static public void + checkSupportedProtocol(Ice.ProtocolVersion v) + { + if(v.major != currentProtocol.major || v.minor > currentProtocol.minor) + { + throw new Ice.UnsupportedProtocolException("", v, currentProtocol); + } + } + + static public void + checkSupportedProtocolEncoding(Ice.EncodingVersion v) + { + if(v.major != currentProtocolEncoding.major || v.minor > currentProtocolEncoding.minor) + { + throw new Ice.UnsupportedEncodingException("", v, currentProtocolEncoding); + } + } + + static public void + checkSupportedEncoding(Ice.EncodingVersion v) + { + if(v.major != currentEncoding.major || v.minor > currentEncoding.minor) + { + throw new Ice.UnsupportedEncodingException("", v, currentEncoding); + } + } + + // + // Either return the given protocol if not compatible, or the greatest + // supported protocol otherwise. + // + static public Ice.ProtocolVersion + getCompatibleProtocol(Ice.ProtocolVersion v) + { + if(v.major != currentProtocol.major) + { + return v; // Unsupported protocol, return as is. + } + else if(v.minor < currentProtocol.minor) + { + return v; // Supported protocol. + } + else + { + // + // Unsupported but compatible, use the currently supported + // protocol, that's the best we can do. + // + return currentProtocol; + } + } + + // + // Either return the given encoding if not compatible, or the greatest + // supported encoding otherwise. + // + static public Ice.EncodingVersion + getCompatibleEncoding(Ice.EncodingVersion v) + { + if(v.major != currentEncoding.major) + { + return v; // Unsupported encoding, return as is. + } + else if(v.minor < currentEncoding.minor) + { + return v; // Supported encoding. + } + else + { + // + // Unsupported but compatible, use the currently supported + // encoding, that's the best we can do. + // + return currentEncoding; + } + } + + static public boolean + isSupported(Ice.EncodingVersion version, Ice.EncodingVersion supported) + { + return version.major == supported.major && version.minor <= supported.minor; + } + + public static final int OPTIONAL_END_MARKER = 0xFF; + + public static final byte FLAG_HAS_TYPE_ID_STRING = (byte)(1<<0); + public static final byte FLAG_HAS_TYPE_ID_INDEX = (byte)(1<<1); + public static final byte FLAG_HAS_TYPE_ID_COMPACT = (byte)(1<<1 | 1<<0); + public static final byte FLAG_HAS_OPTIONAL_MEMBERS = (byte)(1<<2); + public static final byte FLAG_HAS_INDIRECTION_TABLE = (byte)(1<<3); + public static final byte FLAG_HAS_SLICE_SIZE = (byte)(1<<4); + public static final byte FLAG_IS_LAST_SLICE = (byte)(1<<5); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProtocolInstance.java b/java-compat/src/Ice/src/main/java/IceInternal/ProtocolInstance.java new file mode 100644 index 00000000000..e88ec007887 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProtocolInstance.java @@ -0,0 +1,142 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProtocolInstance +{ + public ProtocolInstance(Ice.Communicator communicator, short type, String protocol, boolean secure) + { + _instance = Util.getInstance(communicator); + _traceLevel = _instance.traceLevels().network; + _traceCategory = _instance.traceLevels().networkCat; + _logger = _instance.initializationData().logger; + _properties = _instance.initializationData().properties; + _type = type; + _protocol = protocol; + _secure = secure; + } + + public int traceLevel() + { + return _traceLevel; + } + + public String traceCategory() + { + return _traceCategory; + } + + public Ice.Logger logger() + { + return _logger; + } + + public String protocol() + { + return _protocol; + } + + public short type() + { + return _type; + } + + public boolean secure() + { + return _secure; + } + + public Ice.Properties properties() + { + return _properties; + } + + public boolean preferIPv6() + { + return _instance.preferIPv6(); + } + + public int protocolSupport() + { + return _instance.protocolSupport(); + } + + public String defaultHost() + { + return _instance.defaultsAndOverrides().defaultHost; + } + + public java.net.InetSocketAddress defaultSourceAddress() + { + return _instance.defaultsAndOverrides().defaultSourceAddress; + } + + public Ice.EncodingVersion defaultEncoding() + { + return _instance.defaultsAndOverrides().defaultEncoding; + } + + public int defaultTimeout() + { + return _instance.defaultsAndOverrides().defaultTimeout; + } + + public NetworkProxy networkProxy() + { + return _instance.networkProxy(); + } + + public int messageSizeMax() + { + return _instance.messageSizeMax(); + } + + public void resolve(String host, int port, Ice.EndpointSelectionType type, IPEndpointI endpt, + EndpointI_connectors callback) + { + _instance.endpointHostResolver().resolve(host, port, type, endpt, callback); + } + + public BufSizeWarnInfo getBufSizeWarn(short type) + { + return _instance.getBufSizeWarn(type); + } + + public void setSndBufSizeWarn(short type, int size) + { + _instance.setSndBufSizeWarn(type, size); + } + + public void setRcvBufSizeWarn(short type, int size) + { + _instance.setRcvBufSizeWarn(type, size); + } + + ProtocolInstance(Instance instance, short type, String protocol, boolean secure) + { + _instance = instance; + _traceLevel = _instance.traceLevels().network; + _traceCategory = _instance.traceLevels().networkCat; + _logger = _instance.initializationData().logger; + _properties = _instance.initializationData().properties; + _type = type; + _protocol = protocol; + _secure = secure; + } + + protected Instance _instance; + protected int _traceLevel; + protected String _traceCategory; + protected Ice.Logger _logger; + protected Ice.Properties _properties; + protected String _protocol; + protected short _type; + protected boolean _secure; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProtocolPluginFacade.java b/java-compat/src/Ice/src/main/java/IceInternal/ProtocolPluginFacade.java new file mode 100644 index 00000000000..7bfb91f3e04 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProtocolPluginFacade.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface ProtocolPluginFacade +{ + // + // Get the Communicator instance with which this facade is + // associated. + // + Ice.Communicator getCommunicator(); + + // + // Register an EndpointFactory. + // + void addEndpointFactory(EndpointFactory factory); + + // + // Get an EndpointFactory. + // + EndpointFactory getEndpointFactory(short type); + + // + // Look up a Java class by name. + // + Class<?> findClass(String className); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProtocolPluginFacadeI.java b/java-compat/src/Ice/src/main/java/IceInternal/ProtocolPluginFacadeI.java new file mode 100644 index 00000000000..fa510e2e6f9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProtocolPluginFacadeI.java @@ -0,0 +1,59 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProtocolPluginFacadeI implements ProtocolPluginFacade +{ + public ProtocolPluginFacadeI(Ice.Communicator communicator) + { + _communicator = communicator; + _instance = Util.getInstance(communicator); + } + + // + // Get the Communicator instance with which this facade is + // associated. + // + @Override + public Ice.Communicator getCommunicator() + { + return _communicator; + } + + // + // Register an EndpointFactory. + // + @Override + public void addEndpointFactory(EndpointFactory factory) + { + _instance.endpointFactoryManager().add(factory); + } + + // + // Register an EndpointFactory. + // + @Override + public EndpointFactory getEndpointFactory(short type) + { + return _instance.endpointFactoryManager().get(type); + } + + // + // Look up a Java class by name. + // + @Override + public Class<?> findClass(String className) + { + return _instance.findClass(className); + } + + private Instance _instance; + private Ice.Communicator _communicator; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProxyFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/ProxyFactory.java new file mode 100644 index 00000000000..ed3f1b81bd6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProxyFactory.java @@ -0,0 +1,302 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import Ice.OperationInterruptedException; + +public final class ProxyFactory +{ + public Ice.ObjectPrx + stringToProxy(String str) + { + Reference ref = _instance.referenceFactory().create(str, null); + return referenceToProxy(ref); + } + + public String + proxyToString(Ice.ObjectPrx proxy) + { + if(proxy != null) + { + Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)proxy; + return h.__reference().toString(); + } + else + { + return ""; + } + } + + public Ice.ObjectPrx + propertyToProxy(String prefix) + { + String proxy = _instance.initializationData().properties.getProperty(prefix); + Reference ref = _instance.referenceFactory().create(proxy, prefix); + return referenceToProxy(ref); + } + + public java.util.Map<String, String> + proxyToProperty(Ice.ObjectPrx proxy, String prefix) + { + if(proxy != null) + { + Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)proxy; + return h.__reference().toProperty(prefix); + } + else + { + return new java.util.HashMap<String, String>(); + } + } + + public Ice.ObjectPrx + streamToProxy(Ice.InputStream s) + { + Ice.Identity ident = new Ice.Identity(); + ident.__read(s); + + Reference ref = _instance.referenceFactory().create(ident, s); + return referenceToProxy(ref); + } + + public Ice.ObjectPrx + referenceToProxy(Reference ref) + { + if(ref != null) + { + Ice.ObjectPrxHelperBase proxy = new Ice.ObjectPrxHelperBase(); + proxy.__setup(ref); + return proxy; + } + else + { + return null; + } + } + + public int + checkRetryAfterException(Ice.LocalException ex, Reference ref, Ice.Holder<Integer> sleepInterval, int cnt) + { + TraceLevels traceLevels = _instance.traceLevels(); + Ice.Logger logger = _instance.initializationData().logger; + + // + // We don't retry batch requests because the exception might have caused + // the all the requests batched with the connection to be aborted and we + // want the application to be notified. + // + if(ref.getMode() == IceInternal.Reference.ModeBatchOneway || + ref.getMode() == IceInternal.Reference.ModeBatchDatagram) + { + throw ex; + } + + if(ex instanceof Ice.ObjectNotExistException) + { + Ice.ObjectNotExistException one = (Ice.ObjectNotExistException)ex; + + if(ref.getRouterInfo() != null && one.operation.equals("ice_add_proxy")) + { + // + // If we have a router, an ObjectNotExistException with an + // operation name "ice_add_proxy" indicates to the client + // that the router isn't aware of the proxy (for example, + // because it was evicted by the router). In this case, we + // must *always* retry, so that the missing proxy is added + // to the router. + // + + ref.getRouterInfo().clearCache(ref); + + if(traceLevels.retry >= 1) + { + String s = "retrying operation call to add proxy to router\n" + ex.toString(); + logger.trace(traceLevels.retryCat, s); + } + + if(sleepInterval != null) + { + sleepInterval.value = 0; + } + return cnt; // We must always retry, so we don't look at the retry count. + } + else if(ref.isIndirect()) + { + // + // We retry ObjectNotExistException if the reference is + // indirect. + // + + if(ref.isWellKnown()) + { + LocatorInfo li = ref.getLocatorInfo(); + if(li != null) + { + li.clearCache(ref); + } + } + } + else + { + // + // For all other cases, we don't retry ObjectNotExistException. + // + throw ex; + } + } + else if(ex instanceof Ice.RequestFailedException) + { + // + // For all other cases, we don't retry ObjectNotExistException + // + throw ex; + } + + // + // There is no point in retrying an operation that resulted in a + // MarshalException. This must have been raised locally (because + // if it happened in a server it would result in an + // UnknownLocalException instead), which means there was a problem + // in this process that will not change if we try again. + // + // The most likely cause for a MarshalException is exceeding the + // maximum message size, which is represented by the subclass + // MemoryLimitException. For example, a client can attempt to send + // a message that exceeds the maximum memory size, or accumulate + // enough batch requests without flushing that the maximum size is + // reached. + // + // This latter case is especially problematic, because if we were + // to retry a batch request after a MarshalException, we would in + // fact silently discard the accumulated requests and allow new + // batch requests to accumulate. If the subsequent batched + // requests do not exceed the maximum message size, it appears to + // the client that all of the batched requests were accepted, when + // in reality only the last few are actually sent. + // + if(ex instanceof Ice.MarshalException) + { + throw ex; + } + + // + // Don't retry if the communicator is destroyed or object adapter + // deactivated. + // + if(ex instanceof Ice.CommunicatorDestroyedException || ex instanceof Ice.ObjectAdapterDeactivatedException) + { + throw ex; + } + + // + // Don't retry invocation timeouts. + // + if(ex instanceof Ice.InvocationTimeoutException || ex instanceof Ice.InvocationCanceledException) + { + throw ex; + } + + // + // Don't retry on OperationInterruptedException. + // + if(ex instanceof OperationInterruptedException) + { + throw ex; + } + + ++cnt; + assert(cnt > 0); + + int interval; + if(cnt == (_retryIntervals.length + 1) && ex instanceof Ice.CloseConnectionException) + { + // + // A close connection exception is always retried at least once, even if the retry + // limit is reached. + // + interval = 0; + } + else if(cnt > _retryIntervals.length) + { + if(traceLevels.retry >= 1) + { + String s = "cannot retry operation call because retry limit has been exceeded\n" + ex.toString(); + logger.trace(traceLevels.retryCat, s); + } + throw ex; + } + else + { + interval = _retryIntervals[cnt - 1]; + } + + if(traceLevels.retry >= 1) + { + String s = "retrying operation call"; + if(interval > 0) + { + s += " in " + interval + "ms"; + } + s += " because of exception\n" + ex; + logger.trace(traceLevels.retryCat, s); + } + + sleepInterval.value = interval; + return cnt; + } + + // + // Only for use by Instance. + // + ProxyFactory(Instance instance) + { + _instance = instance; + + String[] arr = _instance.initializationData().properties.getPropertyAsList("Ice.RetryIntervals"); + + if(arr.length > 0) + { + _retryIntervals = new int[arr.length]; + + for(int i = 0; i < arr.length; i++) + { + int v; + + try + { + v = Integer.parseInt(arr[i]); + } + catch(NumberFormatException ex) + { + v = 0; + } + + // + // If -1 is the first value, no retry and wait intervals. + // + if(i == 0 && v == -1) + { + _retryIntervals = new int[0]; + break; + } + + _retryIntervals[i] = v > 0 ? v : 0; + } + } + else + { + _retryIntervals = new int[1]; + _retryIntervals[0] = 0; + } + } + + private Instance _instance; + private int[] _retryIntervals; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProxyFlushBatch.java b/java-compat/src/Ice/src/main/java/IceInternal/ProxyFlushBatch.java new file mode 100644 index 00000000000..eb49b24c6f1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProxyFlushBatch.java @@ -0,0 +1,62 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProxyFlushBatch extends ProxyOutgoingAsyncBase +{ + public static ProxyFlushBatch check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (ProxyFlushBatch)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + public ProxyFlushBatch(Ice.ObjectPrxHelperBase prx, String operation, CallbackBase callback) + { + super(prx, operation, callback); + _observer = ObserverHelper.get(prx, operation); + _batchRequestNum = prx.__getBatchRequestQueue().swap(_os); + } + + @Override + public int invokeRemote(Ice.ConnectionI connection, boolean compress, boolean response) throws RetryException + { + if(_batchRequestNum == 0) + { + return sent() ? AsyncStatus.Sent | AsyncStatus.InvokeSentCallback : AsyncStatus.Sent; + } + _cachedConnection = connection; + return connection.sendAsyncRequest(this, compress, false, _batchRequestNum); + } + + @Override + public int invokeCollocated(CollocatedRequestHandler handler) + { + if(_batchRequestNum == 0) + { + return sent() ? AsyncStatus.Sent | AsyncStatus.InvokeSentCallback : AsyncStatus.Sent; + } + return handler.invokeAsyncRequest(this, _batchRequestNum, false); + } + + public void invoke() + { + Protocol.checkSupportedProtocol(Protocol.getCompatibleProtocol(_proxy.__reference().getProtocol())); + invokeImpl(true); // userThread = true + } + + protected int _batchRequestNum; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProxyGetConnection.java b/java-compat/src/Ice/src/main/java/IceInternal/ProxyGetConnection.java new file mode 100644 index 00000000000..f4da8e83e12 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProxyGetConnection.java @@ -0,0 +1,65 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ProxyGetConnection extends ProxyOutgoingAsyncBase +{ + public static ProxyGetConnection check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (ProxyGetConnection)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + public ProxyGetConnection(Ice.ObjectPrxHelperBase prx, String operation, CallbackBase cb) + { + super(prx, operation, cb); + _observer = ObserverHelper.get(prx, operation); + } + + @Override + public int invokeRemote(Ice.ConnectionI connection, boolean compress, boolean response) + throws RetryException + { + _cachedConnection = connection; + if(finished(true)) + { + invokeCompletedAsync(); + } + return AsyncStatus.Sent; + } + + @Override + public int invokeCollocated(CollocatedRequestHandler handler) + { + if(finished(true)) + { + invokeCompletedAsync(); + } + return AsyncStatus.Sent; + } + + @Override + public Ice.Connection getConnection() + { + return _cachedConnection; + } + + public void invoke() + { + invokeImpl(true); // userThread = true + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ProxyOutgoingAsyncBase.java b/java-compat/src/Ice/src/main/java/IceInternal/ProxyOutgoingAsyncBase.java new file mode 100644 index 00000000000..a38c6c28c7a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ProxyOutgoingAsyncBase.java @@ -0,0 +1,318 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +// +// Base class for proxy based invocations. This class handles the +// retry for proxy invocations. It also ensures the child observer is +// correct notified of failures and make sure the retry task is +// correctly canceled when the invocation completes. +// +public abstract class ProxyOutgoingAsyncBase extends OutgoingAsyncBase +{ + public static ProxyOutgoingAsyncBase check(Ice.AsyncResult r, Ice.ObjectPrx prx, String operation) + { + ProxyOutgoingAsyncBase.checkImpl(r, prx, operation); + try + { + return (ProxyOutgoingAsyncBase)r; + } + catch(ClassCastException ex) + { + throw new IllegalArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); + } + } + + public abstract int invokeRemote(Ice.ConnectionI con, boolean compress, boolean response) throws RetryException; + + public abstract int invokeCollocated(CollocatedRequestHandler handler); + + @Override + public Ice.ObjectPrx getProxy() + { + return _proxy; + } + + @Override + public boolean completed(Ice.Exception exc) + { + if(_childObserver != null) + { + _childObserver.failed(exc.ice_id()); + _childObserver.detach(); + _childObserver = null; + } + + // + // NOTE: at this point, synchronization isn't needed, no other threads should be + // calling on the callback. + // + try + { + // + // It's important to let the retry queue do the retry even if + // the retry interval is 0. This method can be called with the + // connection locked so we can't just retry here. + // + _instance.retryQueue().add(this, handleException(exc)); + return false; + } + catch(Ice.Exception ex) + { + return finished(ex); // No retries, we're done + } + } + + public void retryException(Ice.Exception ex) + { + try + { + // + // It's important to let the retry queue do the retry. This is + // called from the connect request handler and the retry might + // require could end up waiting for the flush of the + // connection to be done. + // + _proxy.__updateRequestHandler(_handler, null); // Clear request handler and always retry. + _instance.retryQueue().add(this, 0); + } + catch(Ice.Exception exc) + { + if(completed(exc)) + { + invokeCompletedAsync(); + } + } + } + + public void retry() + { + invokeImpl(false); + } + + public void cancelable(final CancellationHandler handler) + { + if(_proxy.__reference().getInvocationTimeout() == -2 && _cachedConnection != null) + { + final int timeout = _cachedConnection.timeout(); + if(timeout > 0) + { + _future = _instance.timer().schedule( + new Runnable() + { + @Override + public void run() + { + cancel(new Ice.ConnectionTimeoutException()); + } + }, timeout, java.util.concurrent.TimeUnit.MILLISECONDS); + } + } + super.cancelable(handler); + } + + public void abort(Ice.Exception ex) + { + assert(_childObserver == null); + if(finished(ex)) + { + invokeCompletedAsync(); + } + else if(ex instanceof Ice.CommunicatorDestroyedException) + { + // + // If it's a communicator destroyed exception, don't swallow + // it but instead notify the user thread. Even if no callback + // was provided. + // + throw ex; + } + } + + protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, String op, CallbackBase delegate) + { + super(prx.ice_getCommunicator(), prx.__reference().getInstance(), op, delegate); + _proxy = prx; + _mode = Ice.OperationMode.Normal; + _cnt = 0; + _sent = false; + } + + protected ProxyOutgoingAsyncBase(Ice.ObjectPrxHelperBase prx, String op, CallbackBase delegate, Ice.OutputStream os) + { + super(prx.ice_getCommunicator(), prx.__reference().getInstance(), op, delegate, os); + _proxy = prx; + _mode = Ice.OperationMode.Normal; + _cnt = 0; + _sent = false; + } + + protected static Ice.AsyncResult checkImpl(Ice.AsyncResult r, Ice.ObjectPrx p, String operation) + { + check(r, operation); + if(r.getProxy() != p) + { + throw new IllegalArgumentException("Proxy for call to end_" + operation + + " does not match proxy that was used to call corresponding " + + "begin_" + operation + " method"); + } + return r; + } + + protected void invokeImpl(boolean userThread) + { + try + { + if(userThread) + { + int invocationTimeout = _proxy.__reference().getInvocationTimeout(); + if(invocationTimeout > 0) + { + _future = _instance.timer().schedule( + new Runnable() + { + @Override + public void run() + { + cancel(new Ice.InvocationTimeoutException()); + } + }, invocationTimeout, java.util.concurrent.TimeUnit.MILLISECONDS); + } + } + else // If not called from the user thread, it's called from the retry queue + { + if(_observer != null) + { + _observer.retried(); + } + } + + while(true) + { + try + { + _sent = false; + _handler = null; + _handler = _proxy.__getRequestHandler(); + int status = _handler.sendAsyncRequest(this); + if((status & AsyncStatus.Sent) > 0) + { + if(userThread) + { + _sentSynchronously = true; + if((status & AsyncStatus.InvokeSentCallback) > 0) + { + invokeSent(); // Call the sent callback from the user thread. + } + } + else + { + if((status & AsyncStatus.InvokeSentCallback) > 0) + { + invokeSentAsync(); // Call the sent callback from a client thread pool thread. + } + } + } + return; // We're done! + } + catch(RetryException ex) + { + _proxy.__updateRequestHandler(_handler, null); // Clear request handler and always retry. + } + catch(Ice.Exception ex) + { + if(_childObserver != null) + { + _childObserver.failed(ex.ice_id()); + _childObserver.detach(); + _childObserver = null; + } + final int interval = handleException(ex); + if(interval > 0) + { + _instance.retryQueue().add(this, interval); + return; + } + else if(_observer != null) + { + _observer.retried(); + } + } + } + } + catch(Ice.Exception ex) + { + // + // If called from the user thread we re-throw, the exception + // will be catch by the caller and abort() will be called. + // + if(userThread) + { + throw ex; + } + else if(finished(ex)) // No retries, we're done + { + invokeCompletedAsync(); + } + } + } + + @Override + protected boolean sent(boolean done) + { + _sent = true; + if(done) + { + if(_future != null) + { + _future.cancel(false); + _future = null; + } + } + return super.sent(done); + } + + @Override + protected boolean finished(Ice.Exception ex) + { + if(_future != null) + { + _future.cancel(false); + _future = null; + } + return super.finished(ex); + } + + @Override + protected boolean finished(boolean ok) + { + if(_future != null) + { + _future.cancel(false); + _future = null; + } + return super.finished(ok); + } + + protected int handleException(Ice.Exception exc) + { + Ice.Holder<Integer> interval = new Ice.Holder<Integer>(); + _cnt = _proxy.__handleException(exc, _handler, _mode, _sent, interval, _cnt); + return interval.value; + } + + final protected Ice.ObjectPrxHelperBase _proxy; + protected RequestHandler _handler; + protected Ice.OperationMode _mode; + + private java.util.concurrent.Future<?> _future; + private int _cnt; + private boolean _sent; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/QueueExecutorService.java b/java-compat/src/Ice/src/main/java/IceInternal/QueueExecutorService.java new file mode 100644 index 00000000000..cb46d5dfe0b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/QueueExecutorService.java @@ -0,0 +1,118 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +public final class QueueExecutorService +{ + QueueExecutorService(ExecutorService executor) + { + _executor = executor; + _thread = executeNoThrow(new Callable<Thread>() + { + @Override + public Thread call() + { + return Thread.currentThread(); + } + }); + } + + public <T> T executeNoThrow(Callable<T> callable) + { + try + { + return execute(callable); + } + catch(RetryException ex) + { + assert(false); + return null; + } + } + + public <T> T execute(Callable<T> callable) + throws RetryException + { + if(_thread == Thread.currentThread()) + { + try + { + return callable.call(); + } + catch(RuntimeException ex) + { + throw ex; + } + catch(Exception ex) + { + // RetryException is the only checked exception that + // can be raised by Ice internals. + assert(ex instanceof RetryException); + throw (RetryException)ex; + } + } + + boolean interrupted = false; + try + { + Future<T> future = _executor.submit(callable); + while(true) + { + try + { + T value = future.get(); + return value; + } + catch(InterruptedException ex) + { + interrupted = true; + } + } + } + catch(RejectedExecutionException e) + { + throw new Ice.CommunicatorDestroyedException(); + } + catch(ExecutionException e) + { + try + { + throw e.getCause(); + } + catch(RuntimeException ex) + { + throw ex; + } + catch(Throwable ex) + { + // RetryException is the only checked exception that + // can be raised by Ice internals. + assert(ex instanceof RetryException); + throw (RetryException)ex; + } + } + finally + { + if(interrupted) + { + Thread.currentThread().interrupt(); + } + } + } + + final ExecutorService _executor; + final Thread _thread; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/QueueRequestHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/QueueRequestHandler.java new file mode 100644 index 00000000000..a77e67c0f9f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/QueueRequestHandler.java @@ -0,0 +1,96 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.Callable; + +import Ice.ConnectionI; + +public class QueueRequestHandler implements RequestHandler +{ + public + QueueRequestHandler(Instance instance, RequestHandler delegate) + { + _executor = instance.getQueueExecutor(); + assert(delegate != null); + _delegate = delegate; + } + + @Override + public RequestHandler + update(RequestHandler previousHandler, RequestHandler newHandler) + { + // + // Only update to new handler if the previous handler matches this one. + // + try + { + if(previousHandler == this || previousHandler == _delegate) + { + return newHandler; + } + else if(previousHandler.getConnection() == _delegate.getConnection()) + { + return newHandler; + } + } + catch(Ice.Exception ex) + { + // Ignore + } + return this; + } + + @Override + public int + sendAsyncRequest(final ProxyOutgoingAsyncBase out) throws RetryException + { + return _executor.execute(new Callable<Integer>() + { + @Override + public Integer call() throws RetryException + { + return _delegate.sendAsyncRequest(out); + } + }); + } + + @Override + public void + asyncRequestCanceled(final OutgoingAsyncBase outAsync, final Ice.LocalException ex) + { + _executor.executeNoThrow(new Callable<Void>() + { + @Override + public Void call() + { + _delegate.asyncRequestCanceled(outAsync, ex); + return null; + } + }); + } + + @Override + public Reference + getReference() + { + return _delegate.getReference(); + } + + @Override + public ConnectionI + getConnection() + { + return _delegate.getConnection(); + } + + private final RequestHandler _delegate; + private final QueueExecutorService _executor; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ReadyCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/ReadyCallback.java new file mode 100644 index 00000000000..e4c1482c5fb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ReadyCallback.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface ReadyCallback +{ + void ready(int op, boolean value); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Reference.java b/java-compat/src/Ice/src/main/java/IceInternal/Reference.java new file mode 100644 index 00000000000..b7ea1dd2f32 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Reference.java @@ -0,0 +1,547 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class Reference implements Cloneable +{ + public final static int ModeTwoway = 0; + public final static int ModeOneway = 1; + public final static int ModeBatchOneway = 2; + public final static int ModeDatagram = 3; + public final static int ModeBatchDatagram = 4; + public final static int ModeLast = ModeBatchDatagram; + + public interface GetConnectionCallback + { + void setConnection(Ice.ConnectionI connection, boolean compress); + void setException(Ice.LocalException ex); + } + + public final int + getMode() + { + return _mode; + } + + public final boolean + getSecure() + { + return _secure; + } + + public final Ice.ProtocolVersion + getProtocol() + { + return _protocol; + } + + public final Ice.EncodingVersion + getEncoding() + { + return _encoding; + } + + public final Ice.Identity + getIdentity() + { + return _identity; + } + + public final String + getFacet() + { + return _facet; + } + + public final Instance + getInstance() + { + return _instance; + } + + public final java.util.Map<String, String> + getContext() + { + return _context; + } + + public int + getInvocationTimeout() + { + return _invocationTimeout; + } + + public final Ice.Communicator + getCommunicator() + { + return _communicator; + } + + public abstract EndpointI[] getEndpoints(); + public abstract String getAdapterId(); + public abstract RouterInfo getRouterInfo(); + public abstract LocatorInfo getLocatorInfo(); + public abstract boolean getCollocationOptimized(); + public abstract boolean getCacheConnection(); + public abstract boolean getPreferSecure(); + public abstract Ice.EndpointSelectionType getEndpointSelection(); + public abstract int getLocatorCacheTimeout(); + public abstract String getConnectionId(); + + // + // The change* methods (here and in derived classes) create + // a new reference based on the existing one, with the + // corresponding value changed. + // + public final Reference + changeContext(java.util.Map<String, String> newContext) + { + if(newContext == null) + { + newContext = _emptyContext; + } + Reference r = _instance.referenceFactory().copy(this); + if(newContext.isEmpty()) + { + r._context = _emptyContext; + } + else + { + r._context = new java.util.HashMap<String, String>(newContext); + } + return r; + } + + public final Reference + changeMode(int newMode) + { + if(newMode == _mode) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._mode = newMode; + return r; + } + + public Reference + changeSecure(boolean newSecure) + { + if(newSecure == _secure) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._secure = newSecure; + return r; + } + + public final Reference + changeIdentity(Ice.Identity newIdentity) + { + if(newIdentity.equals(_identity)) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._identity = newIdentity.clone(); + return r; + } + + public final Reference + changeFacet(String newFacet) + { + if(newFacet.equals(_facet)) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._facet = newFacet; + return r; + } + + public final Reference + changeInvocationTimeout(int newTimeout) + { + if(newTimeout == _invocationTimeout) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._invocationTimeout = newTimeout; + return r; + } + + public Reference + changeEncoding(Ice.EncodingVersion newEncoding) + { + if(newEncoding.equals(_encoding)) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._encoding = newEncoding; + return r; + } + + public Reference + changeCompress(boolean newCompress) + { + if(_overrideCompress && _compress == newCompress) + { + return this; + } + Reference r = _instance.referenceFactory().copy(this); + r._compress = newCompress; + r._overrideCompress = true; + return r; + } + + public abstract Reference changeAdapterId(String newAdapterId); + public abstract Reference changeEndpoints(EndpointI[] newEndpoints); + public abstract Reference changeLocator(Ice.LocatorPrx newLocator); + public abstract Reference changeRouter(Ice.RouterPrx newRouter); + public abstract Reference changeCollocationOptimized(boolean newCollocationOptimized); + public abstract Reference changeCacheConnection(boolean newCache); + public abstract Reference changePreferSecure(boolean newPreferSecure); + public abstract Reference changeEndpointSelection(Ice.EndpointSelectionType newType); + public abstract Reference changeLocatorCacheTimeout(int newTimeout); + + public abstract Reference changeTimeout(int newTimeout); + public abstract Reference changeConnectionId(String connectionId); + + @Override + public synchronized int + hashCode() + { + if(_hashInitialized) + { + return _hashValue; + } + + int h = 5381; + h = IceInternal.HashUtil.hashAdd(h, _mode); + h = IceInternal.HashUtil.hashAdd(h, _secure); + h = IceInternal.HashUtil.hashAdd(h, _identity); + h = IceInternal.HashUtil.hashAdd(h, _context); + h = IceInternal.HashUtil.hashAdd(h, _facet); + h = IceInternal.HashUtil.hashAdd(h, _overrideCompress); + if(_overrideCompress) + { + h = IceInternal.HashUtil.hashAdd(h, _compress); + } + h = IceInternal.HashUtil.hashAdd(h, _protocol); + h = IceInternal.HashUtil.hashAdd(h, _encoding); + h = IceInternal.HashUtil.hashAdd(h, _invocationTimeout); + + _hashValue = h; + _hashInitialized = true; + + return _hashValue; + } + + // + // Utility methods + // + public abstract boolean isIndirect(); + public abstract boolean isWellKnown(); + + // + // Marshal the reference. + // + public void + streamWrite(Ice.OutputStream s) + { + // + // Don't write the identity here. Operations calling streamWrite + // write the identity. + // + + // + // For compatibility with the old FacetPath. + // + if(_facet.length() == 0) + { + s.writeStringSeq(null); + } + else + { + String[] facetPath = { _facet }; + s.writeStringSeq(facetPath); + } + + s.writeByte((byte)_mode); + + s.writeBool(_secure); + + if(!s.getEncoding().equals(Ice.Util.Encoding_1_0)) + { + _protocol.__write(s); + _encoding.__write(s); + } + + // Derived class writes the remainder of the reference. + } + + // + // Convert the reference to its string form. + // + @Override + public String + toString() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + StringBuilder s = new StringBuilder(128); + + // + // If the encoded identity string contains characters which + // the reference parser uses as separators, then we enclose + // the identity string in quotes. + // + String id = Ice.Util.identityToString(_identity); + if(IceUtilInternal.StringUtil.findFirstOf(id, " :@") != -1) + { + s.append('"'); + s.append(id); + s.append('"'); + } + else + { + s.append(id); + } + + if(_facet.length() > 0) + { + // + // If the encoded facet string contains characters which + // the reference parser uses as separators, then we enclose + // the facet string in quotes. + // + s.append(" -f "); + String fs = IceUtilInternal.StringUtil.escapeString(_facet, ""); + if(IceUtilInternal.StringUtil.findFirstOf(fs, " :@") != -1) + { + s.append('"'); + s.append(fs); + s.append('"'); + } + else + { + s.append(fs); + } + } + + switch(_mode) + { + case ModeTwoway: + { + s.append(" -t"); + break; + } + + case ModeOneway: + { + s.append(" -o"); + break; + } + + case ModeBatchOneway: + { + s.append(" -O"); + break; + } + + case ModeDatagram: + { + s.append(" -d"); + break; + } + + case ModeBatchDatagram: + { + s.append(" -D"); + break; + } + } + + if(_secure) + { + s.append(" -s"); + } + + if(!_protocol.equals(Ice.Util.Protocol_1_0)) + { + // + // We only print the protocol if it's not 1.0. It's fine as + // long as we don't add Ice.Default.ProtocolVersion, a + // stringified proxy will convert back to the same proxy with + // stringToProxy. + // + s.append(" -p "); + s.append(Ice.Util.protocolVersionToString(_protocol)); + } + + // + // Always print the encoding version to ensure a stringified proxy + // will convert back to a proxy with the same encoding with + // stringToProxy (and won't use Ice.Default.EncodingVersion). + // + s.append(" -e "); + s.append(Ice.Util.encodingVersionToString(_encoding)); + + return s.toString(); + + // Derived class writes the remainder of the string. + } + + // + // Convert the reference to its property form. + // + public abstract java.util.Map<String, String> toProperty(String prefix); + + public abstract RequestHandler getRequestHandler(Ice.ObjectPrxHelperBase proxy); + + public abstract BatchRequestQueue getBatchRequestQueue(); + + @Override + public boolean + equals(java.lang.Object obj) + { + // + // Note: if(this == obj) and type test are performed by each non-abstract derived class. + // + + Reference r = (Reference)obj; // Guaranteed to succeed. + + if(_mode != r._mode) + { + return false; + } + + if(_secure != r._secure) + { + return false; + } + + if(!_identity.equals(r._identity)) + { + return false; + } + + if(!_context.equals(r._context)) + { + return false; + } + + if(!_facet.equals(r._facet)) + { + return false; + } + + if(_overrideCompress != r._overrideCompress) + { + return false; + } + if(_overrideCompress && _compress != r._compress) + { + return false; + } + + if(!_protocol.equals(r._protocol)) + { + return false; + } + + if(!_encoding.equals(r._encoding)) + { + return false; + } + + if(_invocationTimeout != r._invocationTimeout) + { + return false; + } + + return true; + } + + @Override + public Reference clone() + { + Reference c = null; + try + { + c = (Reference)super.clone(); + } + catch(CloneNotSupportedException ex) + { + assert false; + } + return c; + } + + protected int _hashValue; + protected boolean _hashInitialized; + private static java.util.Map<String, String> _emptyContext = new java.util.HashMap<String, String>(); + + final private Instance _instance; + final private Ice.Communicator _communicator; + + private int _mode; + private boolean _secure; + private Ice.Identity _identity; + private java.util.Map<String, String> _context; + private String _facet; + private Ice.ProtocolVersion _protocol; + private Ice.EncodingVersion _encoding; + private int _invocationTimeout; + protected boolean _overrideCompress; + protected boolean _compress; // Only used if _overrideCompress == true + + protected + Reference(Instance instance, + Ice.Communicator communicator, + Ice.Identity identity, + String facet, + int mode, + boolean secure, + Ice.ProtocolVersion protocol, + Ice.EncodingVersion encoding, + int invocationTimeout, + java.util.Map<String, String> context) + { + // + // Validate string arguments. + // + assert(identity.name != null); + assert(identity.category != null); + assert(facet != null); + + _instance = instance; + _communicator = communicator; + _mode = mode; + _secure = secure; + _identity = identity; + _context = context != null ? new java.util.HashMap<String, String>(context) : _emptyContext; + _facet = facet; + _protocol = protocol; + _encoding = encoding; + _invocationTimeout = invocationTimeout; + _hashInitialized = false; + _overrideCompress = false; + _compress = false; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ReferenceFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/ReferenceFactory.java new file mode 100644 index 00000000000..ed36537017e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ReferenceFactory.java @@ -0,0 +1,916 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ReferenceFactory +{ + public Reference + create(Ice.Identity ident, String facet, Reference tmpl, EndpointI[] endpoints) + { + if(ident.name.length() == 0 && ident.category.length() == 0) + { + return null; + } + + return create(ident, facet, tmpl.getMode(), tmpl.getSecure(), tmpl.getProtocol(), tmpl.getEncoding(), + endpoints, null, null); + } + + public Reference + create(Ice.Identity ident, String facet, Reference tmpl, String adapterId) + { + if(ident.name.length() == 0 && ident.category.length() == 0) + { + return null; + } + + return create(ident, facet, tmpl.getMode(), tmpl.getSecure(), tmpl.getProtocol(), tmpl.getEncoding(), null, + adapterId, null); + } + + public Reference + create(Ice.Identity ident, Ice.ConnectionI fixedConnection) + { + if(ident.name.length() == 0 && ident.category.length() == 0) + { + return null; + } + + // + // Create new reference + // + return new FixedReference( + _instance, + _communicator, + ident, + "", // Facet + fixedConnection.endpoint().datagram() ? Reference.ModeDatagram : Reference.ModeTwoway, + fixedConnection.endpoint().secure(), + _instance.defaultsAndOverrides().defaultEncoding, + fixedConnection); + } + + public Reference + copy(Reference r) + { + Ice.Identity ident = r.getIdentity(); + if(ident.name.length() == 0 && ident.category.length() == 0) + { + return null; + } + return r.clone(); + } + + public Reference + create(String s, String propertyPrefix) + { + if(s == null || s.length() == 0) + { + return null; + } + + final String delim = " \t\n\r"; + + int beg; + int end = 0; + + beg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end); + if(beg == -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "no non-whitespace characters found in `" + s + "'"; + throw e; + } + + // + // Extract the identity, which may be enclosed in single + // or double quotation marks. + // + String idstr = null; + end = IceUtilInternal.StringUtil.checkQuote(s, beg); + if(end == -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "mismatched quotes around identity in `" + s + "'"; + throw e; + } + else if(end == 0) + { + end = IceUtilInternal.StringUtil.findFirstOf(s, delim + ":@", beg); + if(end == -1) + { + end = s.length(); + } + idstr = s.substring(beg, end); + } + else + { + beg++; // Skip leading quote + idstr = s.substring(beg, end); + end++; // Skip trailing quote + } + + if(beg == end) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "no identity in `" + s + "'"; + throw e; + } + + // + // Parsing the identity may raise IdentityParseException. + // + Ice.Identity ident = Ice.Util.stringToIdentity(idstr); + + if(ident.name.length() == 0) + { + // + // An identity with an empty name and a non-empty + // category is illegal. + // + if(ident.category.length() > 0) + { + Ice.IllegalIdentityException e = new Ice.IllegalIdentityException(); + e.id = ident; + throw e; + } + // + // Treat a stringified proxy containing two double + // quotes ("") the same as an empty string, i.e., + // a null proxy, but only if nothing follows the + // quotes. + // + else if(IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end) != -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "invalid characters after identity in `" + s + "'"; + throw e; + } + else + { + return null; + } + } + + String facet = ""; + int mode = Reference.ModeTwoway; + boolean secure = false; + Ice.EncodingVersion encoding = _instance.defaultsAndOverrides().defaultEncoding; + Ice.ProtocolVersion protocol = Ice.Util.Protocol_1_0; + String adapter = ""; + + while(true) + { + beg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end); + if(beg == -1) + { + break; + } + + if(s.charAt(beg) == ':' || s.charAt(beg) == '@') + { + break; + } + + end = IceUtilInternal.StringUtil.findFirstOf(s, delim + ":@", beg); + if(end == -1) + { + end = s.length(); + } + + if(beg == end) + { + break; + } + + String option = s.substring(beg, end); + if(option.length() != 2 || option.charAt(0) != '-') + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "expected a proxy option but found `" + option + "' in `" + s + "'"; + throw e; + } + + // + // Check for the presence of an option argument. The + // argument may be enclosed in single or double + // quotation marks. + // + String argument = null; + int argumentBeg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end); + if(argumentBeg != -1) + { + final char ch = s.charAt(argumentBeg); + if(ch != '@' && ch != ':' && ch != '-') + { + beg = argumentBeg; + end = IceUtilInternal.StringUtil.checkQuote(s, beg); + if(end == -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "mismatched quotes around value for " + option + " option in `" + s + "'"; + throw e; + } + else if(end == 0) + { + end = IceUtilInternal.StringUtil.findFirstOf(s, delim + ":@", beg); + if(end == -1) + { + end = s.length(); + } + argument = s.substring(beg, end); + } + else + { + beg++; // Skip leading quote + argument = s.substring(beg, end); + end++; // Skip trailing quote + } + } + } + + // + // If any new options are added here, + // IceInternal::Reference::toString() and its derived classes must be updated as well. + // + switch(option.charAt(1)) + { + case 'f': + { + if(argument == null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "no argument provided for -f option in `" + s + "'"; + throw e; + } + + try + { + facet = IceUtilInternal.StringUtil.unescapeString(argument, 0, argument.length()); + } + catch(IllegalArgumentException ex) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "invalid facet in `" + s + "': " + ex.getMessage(); + throw e; + } + + break; + } + + case 't': + { + if(argument != null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unexpected argument `" + argument + "' provided for -t option in `" + s + "'"; + throw e; + } + mode = Reference.ModeTwoway; + break; + } + + case 'o': + { + if(argument != null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unexpected argument `" + argument + "' provided for -o option in `" + s + "'"; + throw e; + } + mode = Reference.ModeOneway; + break; + } + + case 'O': + { + if(argument != null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unexpected argument `" + argument + "' provided for -O option in `" + s + "'"; + throw e; + } + mode = Reference.ModeBatchOneway; + break; + } + + case 'd': + { + if(argument != null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unexpected argument `" + argument + "' provided for -d option in `" + s + "'"; + throw e; + } + mode = Reference.ModeDatagram; + break; + } + + case 'D': + { + if(argument != null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unexpected argument `" + argument + "' provided for -D option in `" + s + "'"; + throw e; + } + mode = Reference.ModeBatchDatagram; + break; + } + + case 's': + { + if(argument != null) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unexpected argument `" + argument + "' provided for -s option in `" + s + "'"; + throw e; + } + secure = true; + break; + } + + case 'e': + { + if(argument == null) + { + throw new Ice.ProxyParseException("no argument provided for -e option in `" + s + "'"); + } + + try + { + encoding = Ice.Util.stringToEncodingVersion(argument); + } + catch(Ice.VersionParseException e) + { + throw new Ice.ProxyParseException("invalid encoding version `" + argument + "' in `" + s + + "':\n" + e.str); + } + break; + } + + case 'p': + { + if(argument == null) + { + throw new Ice.ProxyParseException("no argument provided for -p option in `" + s + "'"); + } + + try + { + protocol = Ice.Util.stringToProtocolVersion(argument); + } + catch(Ice.VersionParseException e) + { + throw new Ice.ProxyParseException("invalid protocol version `" + argument + "' in `" + s + + "':\n" + e.str); + } + break; + } + + default: + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "unknown option `" + option + "' in `" + s + "'"; + throw e; + } + } + } + + if(beg == -1) + { + return create(ident, facet, mode, secure, protocol, encoding, null, null, propertyPrefix); + } + + java.util.ArrayList<EndpointI> endpoints = new java.util.ArrayList<EndpointI>(); + + if(s.charAt(beg) == ':') + { + java.util.ArrayList<String> unknownEndpoints = new java.util.ArrayList<String>(); + end = beg; + + while(end < s.length() && s.charAt(end) == ':') + { + beg = end + 1; + + end = beg; + while(true) + { + end = s.indexOf(':', end); + if(end == -1) + { + end = s.length(); + break; + } + else + { + boolean quoted = false; + int quote = beg; + while(true) + { + quote = s.indexOf('\"', quote); + if(quote == -1 || end < quote) + { + break; + } + else + { + quote = s.indexOf('\"', ++quote); + if(quote == -1) + { + break; + } + else if(end < quote) + { + quoted = true; + break; + } + ++quote; + } + } + if(!quoted) + { + break; + } + ++end; + } + } + + String es = s.substring(beg, end); + EndpointI endp = _instance.endpointFactoryManager().create(es, false); + if(endp != null) + { + endpoints.add(endp); + } + else + { + unknownEndpoints.add(es); + } + } + if(endpoints.size() == 0) + { + assert(!unknownEndpoints.isEmpty()); + Ice.EndpointParseException e = new Ice.EndpointParseException(); + e.str = "invalid endpoint `" + unknownEndpoints.get(0) + "' in `" + s + "'"; + throw e; + } + else if(unknownEndpoints.size() != 0 && + _instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Endpoints", 1) > 0) + { + StringBuffer msg = new StringBuffer("Proxy contains unknown endpoints:"); + for(String e : unknownEndpoints) + { + msg.append(" `"); + msg.append(e); + msg.append("'"); + } + _instance.initializationData().logger.warning(msg.toString()); + } + + EndpointI[] endp = new EndpointI[endpoints.size()]; + endpoints.toArray(endp); + return create(ident, facet, mode, secure, protocol, encoding, endp, null, propertyPrefix); + } + else if(s.charAt(beg) == '@') + { + beg = IceUtilInternal.StringUtil.findFirstNotOf(s, delim, beg + 1); + if(beg == -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "missing adapter id in `" + s + "'"; + throw e; + } + + String adapterstr = null; + end = IceUtilInternal.StringUtil.checkQuote(s, beg); + if(end == -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "mismatched quotes around adapter id in `" + s + "'"; + throw e; + } + else if(end == 0) + { + end = IceUtilInternal.StringUtil.findFirstOf(s, delim, beg); + if(end == -1) + { + end = s.length(); + } + adapterstr = s.substring(beg, end); + } + else + { + beg++; // Skip leading quote + adapterstr = s.substring(beg, end); + end++; // Skip trailing quote + } + + if(end != s.length() && IceUtilInternal.StringUtil.findFirstNotOf(s, delim, end) != -1) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "invalid trailing characters after `" + s.substring(0, end + 1) + "' in `" + s + "'"; + throw e; + } + + try + { + adapter = IceUtilInternal.StringUtil.unescapeString(adapterstr, 0, adapterstr.length()); + } + catch(IllegalArgumentException ex) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "invalid adapter id in `" + s + "': " + ex.getMessage(); + throw e; + } + if(adapter.length() == 0) + { + Ice.ProxyParseException e = new Ice.ProxyParseException(); + e.str = "empty adapter id in `" + s + "'"; + throw e; + } + return create(ident, facet, mode, secure, protocol, encoding, null, adapter, propertyPrefix); + } + + Ice.ProxyParseException ex = new Ice.ProxyParseException(); + ex.str = "malformed proxy `" + s + "'"; + throw ex; + } + + public Reference + create(Ice.Identity ident, Ice.InputStream s) + { + // + // Don't read the identity here. Operations calling this + // constructor read the identity, and pass it as a parameter. + // + + if(ident.name.length() == 0 && ident.category.length() == 0) + { + return null; + } + + // + // For compatibility with the old FacetPath. + // + String[] facetPath = s.readStringSeq(); + String facet; + if(facetPath.length > 0) + { + if(facetPath.length > 1) + { + throw new Ice.ProxyUnmarshalException(); + } + facet = facetPath[0]; + } + else + { + facet = ""; + } + + int mode = s.readByte(); + if(mode < 0 || mode > Reference.ModeLast) + { + throw new Ice.ProxyUnmarshalException(); + } + + boolean secure = s.readBool(); + + Ice.ProtocolVersion protocol; + Ice.EncodingVersion encoding; + if(!s.getEncoding().equals(Ice.Util.Encoding_1_0)) + { + protocol = new Ice.ProtocolVersion(); + protocol.__read(s); + encoding = new Ice.EncodingVersion(); + encoding.__read(s); + } + else + { + protocol = Ice.Util.Protocol_1_0; + encoding = Ice.Util.Encoding_1_0; + } + + EndpointI[] endpoints = null; + String adapterId = null; + + int sz = s.readSize(); + if(sz > 0) + { + endpoints = new EndpointI[sz]; + for(int i = 0; i < sz; i++) + { + endpoints[i] = _instance.endpointFactoryManager().read(s); + } + } + else + { + adapterId = s.readString(); + } + + return create(ident, facet, mode, secure, protocol, encoding, endpoints, adapterId, null); + } + + public ReferenceFactory + setDefaultRouter(Ice.RouterPrx defaultRouter) + { + if(_defaultRouter == null ? defaultRouter == null : _defaultRouter.equals(defaultRouter)) + { + return this; + } + + ReferenceFactory factory = new ReferenceFactory(_instance, _communicator); + factory._defaultLocator = _defaultLocator; + factory._defaultRouter = defaultRouter; + return factory; + } + + public Ice.RouterPrx + getDefaultRouter() + { + return _defaultRouter; + } + + public ReferenceFactory + setDefaultLocator(Ice.LocatorPrx defaultLocator) + { + if(_defaultLocator == null ? defaultLocator == null : _defaultLocator.equals(defaultLocator)) + { + return this; + } + + ReferenceFactory factory = new ReferenceFactory(_instance, _communicator); + factory._defaultRouter = _defaultRouter; + factory._defaultLocator = defaultLocator; + return factory; + } + + public Ice.LocatorPrx + getDefaultLocator() + { + return _defaultLocator; + } + + // + // Only for use by Instance + // + ReferenceFactory(Instance instance, Ice.Communicator communicator) + { + _instance = instance; + _communicator = communicator; + } + + static private String[] _suffixes = + { + "EndpointSelection", + "ConnectionCached", + "PreferSecure", + "LocatorCacheTimeout", + "InvocationTimeout", + "Locator", + "Router", + "CollocationOptimized", + "Context\\..*" + }; + + private void + checkForUnknownProperties(String prefix) + { + // + // Do not warn about unknown properties if Ice prefix, ie Ice, Glacier2, etc + // + for(int i = 0; IceInternal.PropertyNames.clPropNames[i] != null; ++i) + { + if(prefix.startsWith(IceInternal.PropertyNames.clPropNames[i] + ".")) + { + return; + } + } + + java.util.ArrayList<String> unknownProps = new java.util.ArrayList<String>(); + java.util.Map<String, String> props = + _instance.initializationData().properties.getPropertiesForPrefix(prefix + "."); + for(java.util.Map.Entry<String, String> p : props.entrySet()) + { + String prop = p.getKey(); + + boolean valid = false; + for(String suffix : _suffixes) + { + String pattern = java.util.regex.Pattern.quote(prefix + ".") + suffix; + if(java.util.regex.Pattern.compile(pattern).matcher(prop).matches()) + { + valid = true; + break; + } + } + + if(!valid) + { + unknownProps.add(prop); + } + } + + if(unknownProps.size() != 0) + { + StringBuffer message = new StringBuffer("found unknown properties for proxy '"); + message.append(prefix); + message.append("':"); + for(String s : unknownProps) + { + message.append("\n "); + message.append(s); + } + _instance.initializationData().logger.warning(message.toString()); + } + } + + private Reference + create(Ice.Identity ident, String facet, int mode, boolean secure, Ice.ProtocolVersion protocol, + Ice.EncodingVersion encoding, EndpointI[] endpoints, String adapterId, String propertyPrefix) + { + DefaultsAndOverrides defaultsAndOverrides = _instance.defaultsAndOverrides(); + + // + // Default local proxy options. + // + LocatorInfo locatorInfo = null; + if(_defaultLocator != null) + { + if(!((Ice.ObjectPrxHelperBase)_defaultLocator).__reference().getEncoding().equals(encoding)) + { + locatorInfo = _instance.locatorManager().get( + (Ice.LocatorPrx)_defaultLocator.ice_encodingVersion(encoding)); + } + else + { + locatorInfo = _instance.locatorManager().get(_defaultLocator); + } + } + RouterInfo routerInfo = _instance.routerManager().get(_defaultRouter); + boolean collocationOptimized = defaultsAndOverrides.defaultCollocationOptimization; + boolean cacheConnection = true; + boolean preferSecure = defaultsAndOverrides.defaultPreferSecure; + Ice.EndpointSelectionType endpointSelection = defaultsAndOverrides.defaultEndpointSelection; + int locatorCacheTimeout = defaultsAndOverrides.defaultLocatorCacheTimeout; + int invocationTimeout = defaultsAndOverrides.defaultInvocationTimeout; + java.util.Map<String, String> context = null; + + // + // Override the defaults with the proxy properties if a property prefix is defined. + // + if(propertyPrefix != null && propertyPrefix.length() > 0) + { + Ice.Properties properties = _instance.initializationData().properties; + + // + // Warn about unknown properties. + // + if(properties.getPropertyAsIntWithDefault("Ice.Warn.UnknownProperties", 1) > 0) + { + checkForUnknownProperties(propertyPrefix); + } + + String property; + + property = propertyPrefix + ".Locator"; + Ice.LocatorPrx locator = Ice.LocatorPrxHelper.uncheckedCast(_communicator.propertyToProxy(property)); + if(locator != null) + { + if(!((Ice.ObjectPrxHelperBase)locator).__reference().getEncoding().equals(encoding)) + { + locatorInfo = _instance.locatorManager().get((Ice.LocatorPrx)locator.ice_encodingVersion(encoding)); + } + else + { + locatorInfo = _instance.locatorManager().get(locator); + } + } + + property = propertyPrefix + ".Router"; + Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(_communicator.propertyToProxy(property)); + if(router != null) + { + if(propertyPrefix.endsWith(".Router")) + { + String s = "`" + property + "=" + properties.getProperty(property) + + "': cannot set a router on a router; setting ignored"; + _instance.initializationData().logger.warning(s); + } + else + { + routerInfo = _instance.routerManager().get(router); + } + } + + property = propertyPrefix + ".CollocationOptimized"; + collocationOptimized = properties.getPropertyAsIntWithDefault(property, collocationOptimized ? 1 : 0) > 0; + + property = propertyPrefix + ".ConnectionCached"; + cacheConnection = properties.getPropertyAsIntWithDefault(property, cacheConnection ? 1 : 0) > 0; + + property = propertyPrefix + ".PreferSecure"; + preferSecure = properties.getPropertyAsIntWithDefault(property, preferSecure ? 1 : 0) > 0; + + property = propertyPrefix + ".EndpointSelection"; + if(properties.getProperty(property).length() > 0) + { + String type = properties.getProperty(property); + if(type.equals("Random")) + { + endpointSelection = Ice.EndpointSelectionType.Random; + } + else if(type.equals("Ordered")) + { + endpointSelection = Ice.EndpointSelectionType.Ordered; + } + else + { + throw new Ice.EndpointSelectionTypeParseException("illegal value `" + type + + "'; expected `Random' or `Ordered'"); + } + } + + property = propertyPrefix + ".LocatorCacheTimeout"; + String value = properties.getProperty(property); + if(!value.isEmpty()) + { + locatorCacheTimeout = properties.getPropertyAsIntWithDefault(property, locatorCacheTimeout); + if(locatorCacheTimeout < -1) + { + locatorCacheTimeout = -1; + + StringBuffer msg = new StringBuffer("invalid value for "); + msg.append(property); + msg.append(" '"); + msg.append(properties.getProperty(property)); + msg.append("': defaulting to -1"); + _instance.initializationData().logger.warning(msg.toString()); + } + } + + property = propertyPrefix + ".InvocationTimeout"; + value = properties.getProperty(property); + if(!value.isEmpty()) + { + invocationTimeout = properties.getPropertyAsIntWithDefault(property, locatorCacheTimeout); + if(invocationTimeout < 1 && invocationTimeout != -1) + { + invocationTimeout = -1; + + StringBuffer msg = new StringBuffer("invalid value for "); + msg.append(property); + msg.append(" '"); + msg.append(properties.getProperty(property)); + msg.append("': defaulting to -1"); + _instance.initializationData().logger.warning(msg.toString()); + } + } + + property = propertyPrefix + ".Context."; + java.util.Map<String, String> contexts = properties.getPropertiesForPrefix(property); + if(!contexts.isEmpty()) + { + context = new java.util.HashMap<String, String>(); + for(java.util.Map.Entry<String, String> e : contexts.entrySet()) + { + context.put(e.getKey().substring(property.length()), e.getValue()); + } + } + } + + // + // Create new reference + // + return new RoutableReference(_instance, + _communicator, + ident, + facet, + mode, + secure, + protocol, + encoding, + endpoints, + adapterId, + locatorInfo, + routerInfo, + collocationOptimized, + cacheConnection, + preferSecure, + endpointSelection, + locatorCacheTimeout, + invocationTimeout, + context); + } + + final private Instance _instance; + final private Ice.Communicator _communicator; + private Ice.RouterPrx _defaultRouter; + private Ice.LocatorPrx _defaultLocator; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RemoteObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/RemoteObserverI.java new file mode 100644 index 00000000000..f7c35f706eb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RemoteObserverI.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class RemoteObserverI + extends IceMX.ObserverWithDelegate<IceMX.RemoteMetrics, Ice.Instrumentation.RemoteObserver> + implements Ice.Instrumentation.RemoteObserver +{ + @Override + public void + reply(final int size) + { + forEach(new MetricsUpdate<IceMX.RemoteMetrics>() + { + @Override + public void + update(IceMX.RemoteMetrics v) + { + v.replySize += size; + } + }); + if(_delegate != null) + { + _delegate.reply(size); + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ReplyStatus.java b/java-compat/src/Ice/src/main/java/IceInternal/ReplyStatus.java new file mode 100644 index 00000000000..20b2cc32dd1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ReplyStatus.java @@ -0,0 +1,22 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +interface ReplyStatus +{ + static final byte replyOK = 0; + static final byte replyUserException = 1; + static final byte replyObjectNotExist = 2; + static final byte replyFacetNotExist = 3; + static final byte replyOperationNotExist = 4; + static final byte replyUnknownLocalException = 5; + static final byte replyUnknownUserException = 6; + static final byte replyUnknownException = 7; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RequestHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/RequestHandler.java new file mode 100644 index 00000000000..5fa3485400d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RequestHandler.java @@ -0,0 +1,22 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface RequestHandler extends CancellationHandler +{ + RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler); + + int sendAsyncRequest(ProxyOutgoingAsyncBase out) + throws RetryException; + + Reference getReference(); + + Ice.ConnectionI getConnection(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RequestHandlerFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/RequestHandlerFactory.java new file mode 100644 index 00000000000..ff4022724a9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RequestHandlerFactory.java @@ -0,0 +1,96 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.Callable; + +public final class RequestHandlerFactory +{ + RequestHandlerFactory(Instance instance) + { + _instance = instance; + } + + public RequestHandler + getRequestHandler(final RoutableReference ref, Ice.ObjectPrxHelperBase proxy) + { + if(ref.getCollocationOptimized()) + { + Ice.ObjectAdapter adapter = _instance.objectAdapterFactory().findObjectAdapter(proxy); + if(adapter != null) + { + return proxy.__setRequestHandler(new CollocatedRequestHandler(ref, adapter)); + } + } + + ConnectRequestHandler handler = null; + boolean connect = false; + if(ref.getCacheConnection()) + { + synchronized(this) + { + handler = _handlers.get(ref); + if(handler == null) + { + handler = new ConnectRequestHandler(ref, proxy); + _handlers.put(ref, handler); + connect = true; + } + } + } + else + { + handler = new ConnectRequestHandler(ref, proxy); + connect = true; + } + + if(connect) + { + if(_instance.queueRequests()) + { + final ConnectRequestHandler h = handler; + _instance.getQueueExecutor().executeNoThrow(new Callable<Void>() + { + @Override + public Void call() + { + ref.getConnection(h); + return null; + } + }); + } + else + { + ref.getConnection(handler); + } + } + return proxy.__setRequestHandler(handler.connect(proxy)); + } + + void + removeRequestHandler(Reference ref, RequestHandler handler) + { + if(ref.getCacheConnection()) + { + synchronized(this) + { + if(_handlers.get(ref) == handler) + { + _handlers.remove(ref); + } + } + } + } + + private final Instance _instance; + private final Map<Reference, ConnectRequestHandler> _handlers = new HashMap<Reference, ConnectRequestHandler>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ResponseHandler.java b/java-compat/src/Ice/src/main/java/IceInternal/ResponseHandler.java new file mode 100644 index 00000000000..401d80e5451 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ResponseHandler.java @@ -0,0 +1,18 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface ResponseHandler +{ + void sendResponse(int requestId, Ice.OutputStream os, byte status, boolean amd); + void sendNoResponse(); + boolean systemException(int requestId, Ice.SystemException ex, boolean amd); + void invokeException(int requestId, Ice.LocalException ex, int invokeNum, boolean amd); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RetryException.java b/java-compat/src/Ice/src/main/java/IceInternal/RetryException.java new file mode 100644 index 00000000000..463a675b24a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RetryException.java @@ -0,0 +1,27 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class RetryException extends Exception +{ + public + RetryException(Ice.LocalException ex) + { + _ex = ex; + } + + public Ice.LocalException + get() + { + return _ex; + } + + private Ice.LocalException _ex; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RetryQueue.java b/java-compat/src/Ice/src/main/java/IceInternal/RetryQueue.java new file mode 100644 index 00000000000..f495e6ecbcc --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RetryQueue.java @@ -0,0 +1,84 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class RetryQueue +{ + RetryQueue(Instance instance) + { + _instance = instance; + } + + synchronized public void add(ProxyOutgoingAsyncBase outAsync, int interval) + { + if(_instance == null) + { + throw new Ice.CommunicatorDestroyedException(); + } + RetryTask task = new RetryTask(_instance, this, outAsync); + outAsync.cancelable(task); // This will throw if the request is canceled + task.setFuture(_instance.timer().schedule(task, interval, java.util.concurrent.TimeUnit.MILLISECONDS)); + _requests.add(task); + } + + synchronized public void destroy() + { + if(_instance == null) + { + return; // Already destroyed. + } + + java.util.HashSet<RetryTask> keep = new java.util.HashSet<RetryTask>(); + for(RetryTask task : _requests) + { + if(!task.destroy()) + { + keep.add(task); + } + } + _requests = keep; + _instance = null; + + // + // Wait for the tasks to be executed, it shouldn't take long + // since they couldn't be canceled. If interrupted, we + // preserve the interrupt. + // + boolean interrupted = false; + while(!_requests.isEmpty()) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + interrupted = true; + } + } + if(interrupted) + { + Thread.currentThread().interrupt(); + } + } + + synchronized boolean remove(RetryTask task) + { + boolean removed = _requests.remove(task); + if(_instance == null && _requests.isEmpty()) + { + notify(); + } + return removed; + } + + private Instance _instance; + private java.util.HashSet<RetryTask> _requests = new java.util.HashSet<RetryTask>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RetryTask.java b/java-compat/src/Ice/src/main/java/IceInternal/RetryTask.java new file mode 100644 index 00000000000..a9b4b1d1119 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RetryTask.java @@ -0,0 +1,80 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class RetryTask implements Runnable, CancellationHandler +{ + RetryTask(Instance instance, RetryQueue queue, ProxyOutgoingAsyncBase outAsync) + { + _instance = instance; + _queue = queue; + _outAsync = outAsync; + } + + @Override + public void run() + { + _outAsync.retry(); + + // + // NOTE: this must be called last, destroy() blocks until all task + // are removed to prevent the client thread pool to be destroyed + // (we still need the client thread pool at this point to call + // exception callbacks with CommunicatorDestroyedException). + // + _queue.remove(this); + } + + @Override + public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) + { + if(_queue.remove(this) && _future.cancel(false)) + { + if(_instance.traceLevels().retry >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("operation retry canceled\n"); + s.append(Ex.toString(ex)); + _instance.initializationData().logger.trace(_instance.traceLevels().retryCat, s.toString()); + } + if(_outAsync.completed(ex)) + { + _outAsync.invokeCompletedAsync(); + } + } + } + + public boolean destroy() + { + if(_future.cancel(false)) + { + try + { + _outAsync.abort(new Ice.CommunicatorDestroyedException()); + } + catch(Ice.CommunicatorDestroyedException ex) + { + // Abort can throw if there's no callback, just ignore in this case + } + return true; + } + return false; + } + + public void setFuture(java.util.concurrent.Future<?> future) + { + _future = future; + } + + private final Instance _instance; + private final RetryQueue _queue; + private final ProxyOutgoingAsyncBase _outAsync; + private java.util.concurrent.Future<?> _future; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java b/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java new file mode 100644 index 00000000000..688b2ca9935 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RoutableReference.java @@ -0,0 +1,974 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class RoutableReference extends Reference +{ + @Override + public final EndpointI[] + getEndpoints() + { + return _endpoints; + } + + @Override + public final String + getAdapterId() + { + return _adapterId; + } + + @Override + public final LocatorInfo + getLocatorInfo() + { + return _locatorInfo; + } + + @Override + public final RouterInfo + getRouterInfo() + { + return _routerInfo; + } + + @Override + public final boolean + getCollocationOptimized() + { + return _collocationOptimized; + } + + @Override + public final boolean + getCacheConnection() + { + return _cacheConnection; + } + + @Override + public final boolean + getPreferSecure() + { + return _preferSecure; + } + + @Override + public final Ice.EndpointSelectionType + getEndpointSelection() + { + return _endpointSelection; + } + + @Override + public final int + getLocatorCacheTimeout() + { + return _locatorCacheTimeout; + } + + @Override + public final String + getConnectionId() + { + return _connectionId; + } + + @Override + public Reference + changeEncoding(Ice.EncodingVersion newEncoding) + { + RoutableReference r = (RoutableReference)super.changeEncoding(newEncoding); + if(r != this) + { + LocatorInfo locInfo = r._locatorInfo; + if(locInfo != null && !locInfo.getLocator().ice_getEncodingVersion().equals(newEncoding)) + { + r._locatorInfo = getInstance().locatorManager().get( + (Ice.LocatorPrx)locInfo.getLocator().ice_encodingVersion(newEncoding)); + } + } + return r; + } + + @Override + public Reference + changeCompress(boolean newCompress) + { + RoutableReference r = (RoutableReference)super.changeCompress(newCompress); + if(r != this && _endpoints.length > 0) // Also override the compress flag on the endpoints if it was updated. + { + EndpointI[] newEndpoints = new EndpointI[_endpoints.length]; + for(int i = 0; i < _endpoints.length; i++) + { + newEndpoints[i] = _endpoints[i].compress(newCompress); + } + r._endpoints = newEndpoints; + } + return r; + } + + @Override + public Reference + changeEndpoints(EndpointI[] newEndpoints) + { + if(java.util.Arrays.equals(newEndpoints, _endpoints)) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._endpoints = newEndpoints; + r._adapterId = ""; + r.applyOverrides(r._endpoints); + return r; + } + + @Override + public Reference + changeAdapterId(String newAdapterId) + { + if(_adapterId.equals(newAdapterId)) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._adapterId = newAdapterId; + r._endpoints = _emptyEndpoints; + return r; + } + + @Override + public Reference + changeLocator(Ice.LocatorPrx newLocator) + { + LocatorInfo newLocatorInfo = getInstance().locatorManager().get(newLocator); + if(newLocatorInfo != null && _locatorInfo != null && newLocatorInfo.equals(_locatorInfo)) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._locatorInfo = newLocatorInfo; + return r; + } + + @Override + public Reference + changeRouter(Ice.RouterPrx newRouter) + { + RouterInfo newRouterInfo = getInstance().routerManager().get(newRouter); + if(newRouterInfo != null && _routerInfo != null && newRouterInfo.equals(_routerInfo)) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._routerInfo = newRouterInfo; + return r; + } + + @Override + public Reference + changeCollocationOptimized(boolean newCollocationOptimized) + { + if(newCollocationOptimized == _collocationOptimized) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._collocationOptimized = newCollocationOptimized; + return r; + } + + @Override + public final Reference + changeCacheConnection(boolean newCache) + { + if(newCache == _cacheConnection) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._cacheConnection = newCache; + return r; + } + + @Override + public Reference + changePreferSecure(boolean newPreferSecure) + { + if(newPreferSecure == _preferSecure) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._preferSecure = newPreferSecure; + return r; + } + + @Override + public final Reference + changeEndpointSelection(Ice.EndpointSelectionType newType) + { + if(newType == _endpointSelection) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._endpointSelection = newType; + return r; + } + + @Override + public Reference + changeLocatorCacheTimeout(int newTimeout) + { + if(_locatorCacheTimeout == newTimeout) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._locatorCacheTimeout = newTimeout; + return r; + } + + @Override + public Reference + changeTimeout(int newTimeout) + { + if(_overrideTimeout && _timeout == newTimeout) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._timeout = newTimeout; + r._overrideTimeout = true; + if(_endpoints.length > 0) + { + EndpointI[] newEndpoints = new EndpointI[_endpoints.length]; + for(int i = 0; i < _endpoints.length; i++) + { + newEndpoints[i] = _endpoints[i].timeout(newTimeout); + } + r._endpoints = newEndpoints; + } + return r; + } + + @Override + public Reference + changeConnectionId(String id) + { + if(_connectionId.equals(id)) + { + return this; + } + RoutableReference r = (RoutableReference)getInstance().referenceFactory().copy(this); + r._connectionId = id; + if(_endpoints.length > 0) + { + EndpointI[] newEndpoints = new EndpointI[_endpoints.length]; + for(int i = 0; i < _endpoints.length; i++) + { + newEndpoints[i] = _endpoints[i].connectionId(id); + } + r._endpoints = newEndpoints; + } + return r; + } + + @Override + public boolean + isIndirect() + { + return _endpoints.length == 0; + } + + @Override + public boolean + isWellKnown() + { + return _endpoints.length == 0 && _adapterId.length() == 0; + } + + @Override + public void + streamWrite(Ice.OutputStream s) + throws Ice.MarshalException + { + super.streamWrite(s); + + s.writeSize(_endpoints.length); + if(_endpoints.length > 0) + { + assert(_adapterId.length() == 0); + for(EndpointI endpoint : _endpoints) + { + s.writeShort(endpoint.type()); + endpoint.streamWrite(s); + } + } + else + { + s.writeString(_adapterId); // Adapter id. + } + } + + @Override + public String + toString() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + StringBuilder s = new StringBuilder(128); + s.append(super.toString()); + if(_endpoints.length > 0) + { + for(EndpointI endpoint : _endpoints) + { + String endp = endpoint.toString(); + if(endp != null && endp.length() > 0) + { + s.append(':'); + s.append(endp); + } + } + } + else if(_adapterId.length() > 0) + { + s.append(" @ "); + + // + // If the encoded adapter id string contains characters which + // the reference parser uses as separators, then we enclose + // the adapter id string in quotes. + // + String a = IceUtilInternal.StringUtil.escapeString(_adapterId, null); + if(IceUtilInternal.StringUtil.findFirstOf(a, " :@") != -1) + { + s.append('"'); + s.append(a); + s.append('"'); + } + else + { + s.append(a); + } + } + return s.toString(); + } + + @Override + public java.util.Map<String, String> toProperty(String prefix) + { + java.util.Map<String, String> properties = new java.util.HashMap<String, String>(); + + properties.put(prefix, toString()); + properties.put(prefix + ".CollocationOptimized", _collocationOptimized ? "1" : "0"); + properties.put(prefix + ".ConnectionCached", _cacheConnection ? "1" : "0"); + properties.put(prefix + ".PreferSecure", _preferSecure ? "1" : "0"); + properties.put(prefix + ".EndpointSelection", + _endpointSelection == Ice.EndpointSelectionType.Random ? "Random" : "Ordered"); + + { + StringBuffer s = new StringBuffer(); + s.append(getInvocationTimeout()); + properties.put(prefix + ".InvocationTimeout", s.toString()); + } + { + StringBuffer s = new StringBuffer(); + s.append(_locatorCacheTimeout); + properties.put(prefix + ".LocatorCacheTimeout", s.toString()); + } + + if(_routerInfo != null) + { + Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)_routerInfo.getRouter(); + java.util.Map<String, String> routerProperties = h.__reference().toProperty(prefix + ".Router"); + for(java.util.Map.Entry<String, String> p : routerProperties.entrySet()) + { + properties.put(p.getKey(), p.getValue()); + } + } + + if(_locatorInfo != null) + { + Ice.ObjectPrxHelperBase h = (Ice.ObjectPrxHelperBase)_locatorInfo.getLocator(); + java.util.Map<String, String> locatorProperties = h.__reference().toProperty(prefix + ".Locator"); + for(java.util.Map.Entry<String, String> p : locatorProperties.entrySet()) + { + properties.put(p.getKey(), p.getValue()); + } + } + + return properties; + } + + @Override + public synchronized int + hashCode() + { + if(!_hashInitialized) + { + super.hashCode(); // Initializes _hashValue. + _hashValue = IceInternal.HashUtil.hashAdd(_hashValue, _adapterId); + } + return _hashValue; + } + + @Override + public boolean + equals(java.lang.Object obj) + { + if(this == obj) + { + return true; + } + if(!(obj instanceof RoutableReference)) + { + return false; + } + + if(!super.equals(obj)) + { + return false; + } + RoutableReference rhs = (RoutableReference)obj; // Guaranteed to succeed. + if(_locatorInfo == null ? rhs._locatorInfo != null : !_locatorInfo.equals(rhs._locatorInfo)) + { + return false; + } + if(_routerInfo == null ? rhs._routerInfo != null : !_routerInfo.equals(rhs._routerInfo)) + { + return false; + } + if(_collocationOptimized != rhs._collocationOptimized) + { + return false; + } + if(_cacheConnection != rhs._cacheConnection) + { + return false; + } + if(_preferSecure != rhs._preferSecure) + { + return false; + } + if(_endpointSelection != rhs._endpointSelection) + { + return false; + } + if(_locatorCacheTimeout != rhs._locatorCacheTimeout) + { + return false; + } + if(!_connectionId.equals(rhs._connectionId)) + { + return false; + } + if(_overrideTimeout != rhs._overrideTimeout) + { + return false; + } + if(_overrideTimeout && _timeout != rhs._timeout) + { + return false; + } + if(!java.util.Arrays.equals(_endpoints, rhs._endpoints)) + { + return false; + } + if(!_adapterId.equals(rhs._adapterId)) + { + return false; + } + return true; + } + + @Override + public RequestHandler + getRequestHandler(Ice.ObjectPrxHelperBase proxy) + { + return getInstance().requestHandlerFactory().getRequestHandler(this, proxy); + } + + @Override + public BatchRequestQueue + getBatchRequestQueue() + { + return new BatchRequestQueue(getInstance(), getMode() == Reference.ModeBatchDatagram); + } + + public void + getConnection(final GetConnectionCallback callback) + { + if(_routerInfo != null) + { + // + // If we route, we send everything to the router's client + // proxy endpoints. + // + _routerInfo.getClientEndpoints(new RouterInfo.GetClientEndpointsCallback() + { + @Override + public void + setEndpoints(EndpointI[] endpts) + { + if(endpts.length > 0) + { + applyOverrides(endpts); + createConnection(endpts, callback); + } + else + { + getConnectionNoRouterInfo(callback); + } + } + + @Override + public void + setException(Ice.LocalException ex) + { + callback.setException(ex); + } + }); + } + else + { + getConnectionNoRouterInfo(callback); + } + } + + public void + getConnectionNoRouterInfo(final GetConnectionCallback callback) + { + if(_endpoints.length > 0) + { + createConnection(_endpoints, callback); + return; + } + + final RoutableReference self = this; + if(_locatorInfo != null) + { + _locatorInfo.getEndpoints(this, _locatorCacheTimeout, new LocatorInfo.GetEndpointsCallback() + { + @Override + public void + setEndpoints(EndpointI[] endpoints, final boolean cached) + { + if(endpoints.length == 0) + { + callback.setException(new Ice.NoEndpointException(self.toString())); + return; + } + + applyOverrides(endpoints); + createConnection(endpoints, new GetConnectionCallback() + { + @Override + public void + setConnection(Ice.ConnectionI connection, boolean compress) + { + callback.setConnection(connection, compress); + } + + @Override + public void + setException(Ice.LocalException exc) + { + try + { + throw exc; + } + catch(Ice.NoEndpointException ex) + { + callback.setException(ex); // No need to retry if there's no endpoints. + } + catch(Ice.LocalException ex) + { + assert(_locatorInfo != null); + _locatorInfo.clearCache(self); + if(cached) + { + TraceLevels traceLvls = getInstance().traceLevels(); + if(traceLvls.retry >= 2) + { + String s = "connection to cached endpoints failed\n" + + "removing endpoints from cache and trying one more time\n" + ex; + getInstance().initializationData().logger.trace(traceLvls.retryCat, s); + } + getConnectionNoRouterInfo(callback); // Retry. + return; + } + callback.setException(ex); + } + } + }); + } + + @Override + public void + setException(Ice.LocalException ex) + { + callback.setException(ex); + } + }); + } + else + { + callback.setException(new Ice.NoEndpointException(toString())); + } + } + + protected + RoutableReference(Instance instance, + Ice.Communicator communicator, + Ice.Identity identity, + String facet, + int mode, + boolean secure, + Ice.ProtocolVersion protocol, + Ice.EncodingVersion encoding, + EndpointI[] endpoints, + String adapterId, + LocatorInfo locatorInfo, + RouterInfo routerInfo, + boolean collocationOptimized, + boolean cacheConnection, + boolean prefereSecure, + Ice.EndpointSelectionType endpointSelection, + int locatorCacheTimeout, + int invocationTimeout, + java.util.Map<String, String> context) + { + super(instance, communicator, identity, facet, mode, secure, protocol, encoding, invocationTimeout, context); + _endpoints = endpoints; + _adapterId = adapterId; + _locatorInfo = locatorInfo; + _routerInfo = routerInfo; + _collocationOptimized = collocationOptimized; + _cacheConnection = cacheConnection; + _preferSecure = prefereSecure; + _endpointSelection = endpointSelection; + _locatorCacheTimeout = locatorCacheTimeout; + _overrideTimeout = false; + _timeout = -1; + + if(_endpoints == null) + { + _endpoints = _emptyEndpoints; + } + if(_adapterId == null) + { + _adapterId = ""; + } + assert(_adapterId.length() == 0 || _endpoints.length == 0); + } + + protected void + applyOverrides(EndpointI[] endpts) + { + // + // Apply the endpoint overrides to each endpoint. + // + for(int i = 0; i < endpts.length; ++i) + { + endpts[i] = endpts[i].connectionId(_connectionId); + if(_overrideCompress) + { + endpts[i] = endpts[i].compress(_compress); + } + if(_overrideTimeout) + { + endpts[i] = endpts[i].timeout(_timeout); + } + } + } + + private EndpointI[] + filterEndpoints(EndpointI[] allEndpoints) + { + java.util.List<EndpointI> endpoints = new java.util.ArrayList<EndpointI>(); + + // + // Filter out opaque endpoints. + // + for(EndpointI endpoint : allEndpoints) + { + if(!(endpoint instanceof IceInternal.OpaqueEndpointI)) + { + endpoints.add(endpoint); + } + } + + // + // Filter out endpoints according to the mode of the reference. + // + switch(getMode()) + { + case Reference.ModeTwoway: + case Reference.ModeOneway: + case Reference.ModeBatchOneway: + { + // + // Filter out datagram endpoints. + // + java.util.Iterator<EndpointI> i = endpoints.iterator(); + while(i.hasNext()) + { + EndpointI endpoint = i.next(); + if(endpoint.datagram()) + { + i.remove(); + } + } + break; + } + + case Reference.ModeDatagram: + case Reference.ModeBatchDatagram: + { + // + // Filter out non-datagram endpoints. + // + java.util.Iterator<EndpointI> i = endpoints.iterator(); + while(i.hasNext()) + { + EndpointI endpoint = i.next(); + if(!endpoint.datagram()) + { + i.remove(); + } + } + break; + } + } + + // + // Sort the endpoints according to the endpoint selection type. + // + switch(getEndpointSelection()) + { + case Random: + { + java.util.Collections.shuffle(endpoints); + break; + } + case Ordered: + { + // Nothing to do. + break; + } + default: + { + assert(false); + break; + } + } + + // + // If a secure connection is requested or secure overrides is + // set, remove all non-secure endpoints. Otherwise if preferSecure is set + // make secure endpoints prefered. By default make non-secure + // endpoints preferred over secure endpoints. + // + DefaultsAndOverrides overrides = getInstance().defaultsAndOverrides(); + if(overrides.overrideSecure ? overrides.overrideSecureValue : getSecure()) + { + java.util.Iterator<EndpointI> i = endpoints.iterator(); + while(i.hasNext()) + { + EndpointI endpoint = i.next(); + if(!endpoint.secure()) + { + i.remove(); + } + } + } + else if(getPreferSecure()) + { + java.util.Collections.sort(endpoints, _preferSecureEndpointComparator); + } + else + { + java.util.Collections.sort(endpoints, _preferNonSecureEndpointComparator); + } + + return endpoints.toArray(new EndpointI[endpoints.size()]); + } + + protected void + createConnection(EndpointI[] allEndpoints, final GetConnectionCallback callback) + { + final EndpointI[] endpoints = filterEndpoints(allEndpoints); + if(endpoints.length == 0) + { + callback.setException(new Ice.NoEndpointException(toString())); + return; + } + + // + // Finally, create the connection. + // + final OutgoingConnectionFactory factory = getInstance().outgoingConnectionFactory(); + if(getCacheConnection() || endpoints.length == 1) + { + // + // Get an existing connection or create one if there's no + // existing connection to one of the given endpoints. + // + factory.create(endpoints, false, getEndpointSelection(), + new OutgoingConnectionFactory.CreateConnectionCallback() + { + @Override + public void + setConnection(Ice.ConnectionI connection, boolean compress) + { + // + // If we have a router, set the object adapter for this router + // (if any) to the new connection, so that callbacks from the + // router can be received over this new connection. + // + if(_routerInfo != null && _routerInfo.getAdapter() != null) + { + connection.setAdapter(_routerInfo.getAdapter()); + } + callback.setConnection(connection, compress); + } + + @Override + public void + setException(Ice.LocalException ex) + { + callback.setException(ex); + } + }); + } + else + { + // + // Go through the list of endpoints and try to create the + // connection until it succeeds. This is different from just + // calling create() with the given endpoints since this might + // create a new connection even if there's an existing + // connection for one of the endpoints. + // + + factory.create(new EndpointI[]{ endpoints[0] }, true, getEndpointSelection(), + new OutgoingConnectionFactory.CreateConnectionCallback() + { + @Override + public void + setConnection(Ice.ConnectionI connection, boolean compress) + { + // + // If we have a router, set the object adapter for this router + // (if any) to the new connection, so that callbacks from the + // router can be received over this new connection. + // + if(_routerInfo != null && _routerInfo.getAdapter() != null) + { + connection.setAdapter(_routerInfo.getAdapter()); + } + callback.setConnection(connection, compress); + } + + @Override + public void + setException(final Ice.LocalException ex) + { + if(_exception == null) + { + _exception = ex; + } + + if(++_i == endpoints.length) + { + callback.setException(_exception); + return; + } + + final boolean more = _i != endpoints.length - 1; + final EndpointI[] endpoint = new EndpointI[]{ endpoints[_i] }; + factory.create(endpoint, more, getEndpointSelection(), this); + } + + private int _i = 0; + private Ice.LocalException _exception = null; + }); + } + } + + static class EndpointComparator implements java.util.Comparator<EndpointI> + { + EndpointComparator(boolean preferSecure) + { + _preferSecure = preferSecure; + } + + @Override + public int + compare(EndpointI le, EndpointI re) + { + boolean ls = le.secure(); + boolean rs = re.secure(); + if((ls && rs) || (!ls && !rs)) + { + return 0; + } + else if(!ls && rs) + { + if(_preferSecure) + { + return 1; + } + else + { + return -1; + } + } + else + { + if(_preferSecure) + { + return -1; + } + else + { + return 1; + } + } + } + + private boolean _preferSecure; + } + + private static EndpointComparator _preferNonSecureEndpointComparator = new EndpointComparator(false); + private static EndpointComparator _preferSecureEndpointComparator = new EndpointComparator(true); + private static EndpointI[] _emptyEndpoints = new EndpointI[0]; + + private EndpointI[] _endpoints; + private String _adapterId; + private LocatorInfo _locatorInfo; // Null if no router is used. + private RouterInfo _routerInfo; // Null if no router is used. + private boolean _collocationOptimized; + private boolean _cacheConnection; + private boolean _preferSecure; + private Ice.EndpointSelectionType _endpointSelection; + private int _locatorCacheTimeout; + + private boolean _overrideTimeout; + private int _timeout; // Only used if _overrideTimeout == true + private String _connectionId = ""; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RouterInfo.java b/java-compat/src/Ice/src/main/java/IceInternal/RouterInfo.java new file mode 100644 index 00000000000..1de08e756fe --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RouterInfo.java @@ -0,0 +1,280 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class RouterInfo +{ + interface GetClientEndpointsCallback + { + void setEndpoints(EndpointI[] endpoints); + void setException(Ice.LocalException ex); + } + + interface AddProxyCallback + { + void addedProxy(); + void setException(Ice.LocalException ex); + } + + RouterInfo(Ice.RouterPrx router) + { + _router = router; + + assert(_router != null); + } + + synchronized public void + destroy() + { + _clientEndpoints = new EndpointI[0]; + _serverEndpoints = new EndpointI[0]; + _adapter = null; + _identities.clear(); + } + + @Override + public boolean + equals(java.lang.Object obj) + { + if(this == obj) + { + return true; + } + + if(obj instanceof RouterInfo) + { + return _router.equals(((RouterInfo)obj)._router); + } + + return false; + } + + @Override + public int + hashCode() + { + return _router.hashCode(); + } + + public Ice.RouterPrx + getRouter() + { + // + // No mutex lock necessary, _router is immutable. + // + return _router; + } + + public EndpointI[] + getClientEndpoints() + { + synchronized(this) + { + if(_clientEndpoints != null) // Lazy initialization. + { + return _clientEndpoints; + } + } + + return setClientEndpoints(_router.getClientProxy()); + } + + public void + getClientEndpoints(final GetClientEndpointsCallback callback) + { + EndpointI[] clientEndpoints = null; + synchronized(this) + { + clientEndpoints = _clientEndpoints; + } + + if(clientEndpoints != null) + { + callback.setEndpoints(clientEndpoints); + return; + } + + _router.begin_getClientProxy(new Ice.Callback_Router_getClientProxy() + { + @Override + public void + response(Ice.ObjectPrx clientProxy) + { + callback.setEndpoints(setClientEndpoints(clientProxy)); + } + + @Override + public void + exception(Ice.LocalException ex) + { + callback.setException(ex); + } + }); + } + + public EndpointI[] + getServerEndpoints() + { + synchronized(this) + { + if(_serverEndpoints != null) // Lazy initialization. + { + return _serverEndpoints; + } + } + + return setServerEndpoints(_router.getServerProxy()); + } + + public boolean + addProxy(final Ice.ObjectPrx proxy, final AddProxyCallback callback) + { + assert(proxy != null); + synchronized(this) + { + if(_identities.contains(proxy.ice_getIdentity())) + { + // + // Only add the proxy to the router if it's not already in our local map. + // + return true; + } + } + + _router.begin_addProxies(new Ice.ObjectPrx[] { proxy }, + new Ice.Callback_Router_addProxies() + { + @Override + public void + response(Ice.ObjectPrx[] evictedProxies) + { + addAndEvictProxies(proxy, evictedProxies); + callback.addedProxy(); + } + + @Override + public void + exception(Ice.LocalException ex) + { + callback.setException(ex); + } + }); + + return false; + } + + public synchronized void + setAdapter(Ice.ObjectAdapter adapter) + { + _adapter = adapter; + } + + public synchronized Ice.ObjectAdapter + getAdapter() + { + return _adapter; + } + + public synchronized void clearCache(Reference ref) + { + _identities.remove(ref.getIdentity()); + } + + private synchronized EndpointI[] + setClientEndpoints(Ice.ObjectPrx clientProxy) + { + if(_clientEndpoints == null) + { + if(clientProxy == null) + { + // + // If getClientProxy() return nil, use router endpoints. + // + _clientEndpoints = ((Ice.ObjectPrxHelperBase)_router).__reference().getEndpoints(); + } + else + { + clientProxy = clientProxy.ice_router(null); // The client proxy cannot be routed. + + // + // In order to avoid creating a new connection to the + // router, we must use the same timeout as the already + // existing connection. + // + if(_router.ice_getConnection() != null) + { + clientProxy = clientProxy.ice_timeout(_router.ice_getConnection().timeout()); + } + + _clientEndpoints = ((Ice.ObjectPrxHelperBase)clientProxy).__reference().getEndpoints(); + } + } + return _clientEndpoints; + } + + private synchronized EndpointI[] + setServerEndpoints(Ice.ObjectPrx serverProxy) + { + if(serverProxy == null) + { + throw new Ice.NoEndpointException(); + } + + serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed. + _serverEndpoints = ((Ice.ObjectPrxHelperBase)serverProxy).__reference().getEndpoints(); + return _serverEndpoints; + } + + private synchronized void + addAndEvictProxies(Ice.ObjectPrx proxy, Ice.ObjectPrx[] evictedProxies) + { + // + // Check if the proxy hasn't already been evicted by a + // concurrent addProxies call. If it's the case, don't + // add it to our local map. + // + int index = _evictedIdentities.indexOf(proxy.ice_getIdentity()); + if(index >= 0) + { + _evictedIdentities.remove(index); + } + else + { + // + // If we successfully added the proxy to the router, + // we add it to our local map. + // + _identities.add(proxy.ice_getIdentity()); + } + + // + // We also must remove whatever proxies the router evicted. + // + for(Ice.ObjectPrx p : evictedProxies) + { + if(!_identities.remove(p.ice_getIdentity())) + { + // + // It's possible for the proxy to not have been + // added yet in the local map if two threads + // concurrently call addProxies. + // + _evictedIdentities.add(p.ice_getIdentity()); + } + } + } + + private final Ice.RouterPrx _router; + private EndpointI[] _clientEndpoints; + private EndpointI[] _serverEndpoints; + private Ice.ObjectAdapter _adapter; + private java.util.Set<Ice.Identity> _identities = new java.util.HashSet<Ice.Identity>(); + private java.util.List<Ice.Identity> _evictedIdentities = new java.util.ArrayList<Ice.Identity>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/RouterManager.java b/java-compat/src/Ice/src/main/java/IceInternal/RouterManager.java new file mode 100644 index 00000000000..217c5d86d5d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/RouterManager.java @@ -0,0 +1,76 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class RouterManager +{ + RouterManager() + { + } + + synchronized void + destroy() + { + for(RouterInfo info : _table.values()) + { + info.destroy(); + } + _table.clear(); + } + + // + // Returns router info for a given router. Automatically creates + // the router info if it doesn't exist yet. + // + public RouterInfo + get(Ice.RouterPrx rtr) + { + if(rtr == null) + { + return null; + } + + // + // The router cannot be routed. + // + Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null)); + + synchronized(this) + { + RouterInfo info = _table.get(router); + if(info == null) + { + info = new RouterInfo(router); + _table.put(router, info); + } + + return info; + } + } + + public RouterInfo + erase(Ice.RouterPrx rtr) + { + RouterInfo info = null; + if(rtr != null) + { + // The router cannot be routed. + Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null)); + + synchronized(this) + { + info = _table.remove(router); + } + } + return info; + } + + private java.util.HashMap<Ice.RouterPrx, RouterInfo> _table = new java.util.HashMap<Ice.RouterPrx, RouterInfo>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/SOCKSNetworkProxy.java b/java-compat/src/Ice/src/main/java/IceInternal/SOCKSNetworkProxy.java new file mode 100644 index 00000000000..c2843bdbf6e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/SOCKSNetworkProxy.java @@ -0,0 +1,128 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class SOCKSNetworkProxy implements NetworkProxy +{ + public SOCKSNetworkProxy(String host, int port) + { + _host = host; + _port = port; + } + + private SOCKSNetworkProxy(java.net.InetSocketAddress address) + { + _address = address; + } + + @Override + public void beginWrite(java.net.InetSocketAddress endpoint, Buffer buf) + { + final java.net.InetAddress addr = endpoint.getAddress(); + if(addr == null) + { + throw new Ice.FeatureNotSupportedException("SOCKS4 does not support domain names"); + } + else if(!(addr instanceof java.net.Inet4Address)) + { + throw new Ice.FeatureNotSupportedException("SOCKS4 only supports IPv4 addresses"); + } + + // + // SOCKS connect request + // + buf.resize(9, false); + final java.nio.ByteOrder order = buf.b.order(); + buf.b.order(java.nio.ByteOrder.BIG_ENDIAN); // Network byte order. + buf.b.position(0); + buf.b.put((byte)0x04); // SOCKS version 4. + buf.b.put((byte)0x01); // Command, establish a TCP/IP stream connection + buf.b.putShort((short)endpoint.getPort()); // Port + buf.b.put(addr.getAddress()); // IPv4 address + buf.b.put((byte)0x00); // User ID. + buf.b.position(0); + buf.b.limit(buf.size()); + buf.b.order(order); + } + + @Override + public int endWrite(Buffer buf) + { + // Once the request is sent, read the response + return buf.b.hasRemaining() ? SocketOperation.Write : SocketOperation.Read; + } + + @Override + public void beginRead(Buffer buf) + { + // + // Read the SOCKS4 response whose size is 8 bytes. + // + if(!buf.b.hasRemaining()) + { + buf.resize(8, true); + buf.b.position(0); + } + } + + @Override + public int endRead(Buffer buf) + { + // We're done once we read the response + return buf.b.hasRemaining() ? SocketOperation.Read : SocketOperation.None; + } + + @Override + public void finish(Buffer readBuffer, Buffer writeBuffer) + { + readBuffer.b.position(0); + byte b1 = readBuffer.b.get(); + byte b2 = readBuffer.b.get(); + if(b1 != 0x00 || b2 != 0x5a) + { + throw new Ice.ConnectFailedException(); + } + } + + @Override + public NetworkProxy resolveHost(int protocolSupport) + { + assert(_host != null); + return new SOCKSNetworkProxy(Network.getAddresses(_host, + _port, + protocolSupport, + Ice.EndpointSelectionType.Random, + false, + true).get(0)); + } + + @Override + public java.net.InetSocketAddress getAddress() + { + assert(_address != null); // Host must be resolved. + return _address; + } + + @Override + public String getName() + { + return "SOCKS"; + } + + @Override + public int getProtocolSupport() + { + return Network.EnableIPv4; + } + + private String _host; + private int _port; + private java.net.InetSocketAddress _address; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Selector.java b/java-compat/src/Ice/src/main/java/IceInternal/Selector.java new file mode 100644 index 00000000000..ecc4529845e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Selector.java @@ -0,0 +1,408 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class Selector +{ + static final class TimeoutException extends Exception + { + } + + Selector(Instance instance) + { + _instance = instance; + _selecting = false; + _interrupted = false; + + try + { + _selector = java.nio.channels.Selector.open(); + } + catch(java.io.IOException ex) + { + throw new Ice.SyscallException(ex); + } + + // + // The Selector holds a Set representing the selected keys. The + // Set reference doesn't change, so we obtain it once here. + // + _keys = _selector.selectedKeys(); + } + + void destroy() + { + try + { + _selector.close(); + } + catch(java.io.IOException ex) + { + } + _selector = null; + } + + void initialize(EventHandler handler) + { + if(handler.fd() != null) + { + updateImpl(handler); + } + } + + void update(EventHandler handler, int remove, int add) + { + int previous = handler._registered; + handler._registered = handler._registered & ~remove; + handler._registered = handler._registered | add; + if(previous == handler._registered) + { + return; + } + + if(handler.fd() == null) + { + return; + } + + updateImpl(handler); + checkReady(handler); + } + + void enable(EventHandler handler, int status) + { + if(handler.fd() == null || (handler._disabled & status) == 0) + { + return; + } + handler._disabled = handler._disabled & ~status; + + if(handler.fd() == null) + { + return; + } + + if(handler._key != null && (handler._registered & status) != 0) + { + updateImpl(handler); // If registered with the selector, update the registration. + } + checkReady(handler); + } + + void disable(EventHandler handler, int status) + { + if(handler.fd() == null || (handler._disabled & status) != 0) + { + return; + } + handler._disabled = handler._disabled | status; + + if(handler._key != null && (handler._registered & status) != 0) + { + updateImpl(handler); // If registered with the selector, update the registration. + } + checkReady(handler); + } + + boolean finish(EventHandler handler, boolean closeNow) + { + handler._registered = 0; + if(handler._key != null) + { + handler._key.cancel(); + handler._key = null; + } + _changes.remove(handler); + checkReady(handler); + return closeNow; + } + + void ready(EventHandler handler, int status, boolean value) + { + if(((handler._ready & status) != 0) == value) + { + return; // Nothing to do if ready state already correctly set. + } + + if(value) + { + handler._ready |= status; + } + else + { + handler._ready &= ~status; + } + checkReady(handler); + } + + void startSelect() + { + if(!_changes.isEmpty()) + { + updateSelector(); + } + _selecting = true; + + // + // If there are ready handlers, don't block in select, just do a non-blocking + // select to retrieve new ready handlers from the Java selector. + // + _selectNow = !_readyHandlers.isEmpty(); + } + + void finishSelect(java.util.List<EventHandlerOpPair> handlers) + { + assert(handlers.isEmpty()); + + if(_keys.isEmpty() && _readyHandlers.isEmpty() && !_interrupted) // If key set is empty and we weren't woken up. + { + // + // This is necessary to prevent a busy loop in case of a spurious wake-up which + // sometime occurs in the client thread pool when the communicator is destroyed. + // If there are too many successive spurious wake-ups, we log an error. + // + try + { + Thread.sleep(1); + } + catch(InterruptedException ex) + { + // + // Eat the InterruptedException (as we do in ThreadPool.promoteFollower). + // + } + + if(++_spuriousWakeUp > 100) + { + _spuriousWakeUp = 0; + _instance.initializationData().logger.warning("spurious selector wake up"); + } + return; + } + _interrupted = false; + _spuriousWakeUp = 0; + + for(java.nio.channels.SelectionKey key : _keys) + { + EventHandler handler = (EventHandler)key.attachment(); + try + { + // + // Use the intersection of readyOps and interestOps because we only want to + // report the operations in which the handler is still interested. + // + final int op = fromJavaOps(key.readyOps() & key.interestOps()); + if(!_readyHandlers.contains(handler)) // Handler will be added by the loop below + { + handlers.add(new EventHandlerOpPair(handler, op)); + } + } + catch(java.nio.channels.CancelledKeyException ex) + { + assert(handler._registered == 0); + } + } + + for(EventHandler handler : _readyHandlers) + { + int op = handler._ready & ~handler._disabled & handler._registered; + if(handler._key != null && _keys.contains(handler._key)) + { + op |= fromJavaOps(handler._key.readyOps() & handler._key.interestOps()); + } + if(op > 0) + { + handlers.add(new EventHandlerOpPair(handler, op)); + } + } + + _keys.clear(); + _selecting = false; + } + + void select(long timeout) + throws TimeoutException + { + while(true) + { + try + { + if(_selectNow) + { + _selector.selectNow(); + } + else if(timeout > 0) + { + // + // NOTE: On some platforms, select() sometime returns slightly before + // the timeout (at least according to our monotonic time). To make sure + // timeouts are correctly detected, we wait for a little longer than + // the configured timeout (10ms). + // + long before = IceInternal.Time.currentMonotonicTimeMillis(); + if(_selector.select(timeout * 1000 + 10) == 0) + { + if(IceInternal.Time.currentMonotonicTimeMillis() - before >= timeout * 1000) + { + throw new TimeoutException(); + } + } + } + else + { + _selector.select(); + } + } + catch(java.nio.channels.CancelledKeyException ex) + { + // This sometime occurs on OS X, ignore. + continue; + } + catch(java.io.IOException ex) + { + // + // Pressing Ctrl-C causes select() to raise an + // IOException, which seems like a JDK bug. We trap + // for that special case here and ignore it. + // Hopefully we're not masking something important! + // + if(Network.interrupted(ex)) + { + continue; + } + + try + { + String s = "fatal error: selector failed:\n" + ex.getCause().getMessage(); + _instance.initializationData().logger.error(s); + } + finally + { + Runtime.getRuntime().halt(1); + } + } + + break; + } + } + + private void updateImpl(EventHandler handler) + { + _changes.add(handler); + wakeup(); + } + + private void updateSelector() + { + for(EventHandler handler : _changes) + { + int status = handler._registered & ~handler._disabled; + int ops = toJavaOps(handler, status); + if(handler._key == null) + { + if(handler._registered != 0) + { + try + { + handler._key = handler.fd().register(_selector, ops, handler); + } + catch(java.nio.channels.ClosedChannelException ex) + { + assert(false); + } + } + } + else + { + handler._key.interestOps(ops); + } + } + _changes.clear(); + } + + private void checkReady(EventHandler handler) + { + if((handler._ready & ~handler._disabled & handler._registered) != 0) + { + _readyHandlers.add(handler); + if(_selecting) + { + wakeup(); + } + } + else + { + _readyHandlers.remove(handler); + } + } + + private void wakeup() + { + if(_selecting && !_interrupted) + { + _selector.wakeup(); + _interrupted = true; + } + } + + private int toJavaOps(EventHandler handler, int o) + { + int op = 0; + if((o & SocketOperation.Read) != 0) + { + if((handler.fd().validOps() & java.nio.channels.SelectionKey.OP_READ) != 0) + { + op |= java.nio.channels.SelectionKey.OP_READ; + } + else + { + op |= java.nio.channels.SelectionKey.OP_ACCEPT; + } + } + if((o & SocketOperation.Write) != 0) + { + op |= java.nio.channels.SelectionKey.OP_WRITE; + } + if((o & SocketOperation.Connect) != 0) + { + op |= java.nio.channels.SelectionKey.OP_CONNECT; + } + return op; + } + + private int fromJavaOps(int o) + { + int op = 0; + if((o & (java.nio.channels.SelectionKey.OP_READ | java.nio.channels.SelectionKey.OP_ACCEPT)) != 0) + { + op |= SocketOperation.Read; + } + if((o & java.nio.channels.SelectionKey.OP_WRITE) != 0) + { + op |= SocketOperation.Write; + } + if((o & java.nio.channels.SelectionKey.OP_CONNECT) != 0) + { + op |= SocketOperation.Connect; + } + return op; + } + + final private Instance _instance; + + private java.nio.channels.Selector _selector; + private java.util.Set<java.nio.channels.SelectionKey> _keys; + private java.util.HashSet<EventHandler> _changes = new java.util.HashSet<EventHandler>(); + private java.util.HashSet<EventHandler> _readyHandlers = new java.util.HashSet<EventHandler>(); + private boolean _selecting; + private boolean _selectNow; + private boolean _interrupted; + private int _spuriousWakeUp; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/SequencePatcher.java b/java-compat/src/Ice/src/main/java/IceInternal/SequencePatcher.java new file mode 100644 index 00000000000..ca11b14d21c --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/SequencePatcher.java @@ -0,0 +1,41 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class SequencePatcher implements Ice.ReadValueCallback +{ + public SequencePatcher(java.lang.Object[] seq, Class<?> cls, int index) + { + _seq = seq; + _cls = cls; + _index = index; + } + + public void valueReady(Ice.Object v) + { + if(v != null) + { + // + // Raise ClassCastException if the element doesn't match the expected type. + // + if(!_cls.isInstance(v)) + { + throw new ClassCastException("expected element of type " + _cls.getName() + " but received " + + v.getClass().getName()); + } + } + + _seq[_index] = v; + } + + private java.lang.Object[] _seq; + private Class<?> _cls; + private int _index; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ServantError.java b/java-compat/src/Ice/src/main/java/IceInternal/ServantError.java new file mode 100644 index 00000000000..8823aae9ea9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ServantError.java @@ -0,0 +1,28 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final public class ServantError extends java.lang.Error +{ + public ServantError(String reason) + { + super(reason); + } + + public ServantError(String reason, Throwable cause) + { + super(reason, cause); + } + + public ServantError(Throwable cause) + { + super(cause); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java b/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java new file mode 100644 index 00000000000..2789304f276 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ServantManager.java @@ -0,0 +1,322 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ServantManager +{ + public synchronized void + addServant(Ice.Object servant, Ice.Identity ident, String facet) + { + assert(_instance != null); // Must not be called after destruction. + + if(facet == null) + { + facet = ""; + } + + java.util.Map<String, Ice.Object> m = _servantMapMap.get(ident); + if(m == null) + { + m = new java.util.HashMap<String, Ice.Object>(); + _servantMapMap.put(ident, m); + } + else + { + if(m.containsKey(facet)) + { + Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); + ex.id = Ice.Util.identityToString(ident); + ex.kindOfObject = "servant"; + if(facet.length() > 0) + { + ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, ""); + } + throw ex; + } + } + + m.put(facet, servant); + } + + public synchronized void + addDefaultServant(Ice.Object servant, String category) + { + assert(_instance != null); // Must not be called after destruction + + Ice.Object obj = _defaultServantMap.get(category); + if(obj != null) + { + Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); + ex.kindOfObject = "default servant"; + ex.id = category; + throw ex; + } + + _defaultServantMap.put(category, servant); + } + + public synchronized Ice.Object + removeServant(Ice.Identity ident, String facet) + { + assert(_instance != null); // Must not be called after destruction. + + if(facet == null) + { + facet = ""; + } + + java.util.Map<String, Ice.Object> m = _servantMapMap.get(ident); + Ice.Object obj = null; + if(m == null || (obj = m.remove(facet)) == null) + { + Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); + ex.id = Ice.Util.identityToString(ident); + ex.kindOfObject = "servant"; + if(facet.length() > 0) + { + ex.id += " -f " + IceUtilInternal.StringUtil.escapeString(facet, ""); + } + throw ex; + } + + if(m.isEmpty()) + { + _servantMapMap.remove(ident); + } + return obj; + } + + public synchronized Ice.Object + removeDefaultServant(String category) + { + assert(_instance != null); // Must not be called after destruction. + + Ice.Object obj = _defaultServantMap.get(category); + if(obj == null) + { + Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); + ex.kindOfObject = "default servant"; + ex.id = category; + throw ex; + } + + _defaultServantMap.remove(category); + return obj; + } + + public synchronized java.util.Map<String, Ice.Object> + removeAllFacets(Ice.Identity ident) + { + assert(_instance != null); // Must not be called after destruction. + + java.util.Map<String, Ice.Object> m = _servantMapMap.get(ident); + if(m == null) + { + Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); + ex.id = Ice.Util.identityToString(ident); + ex.kindOfObject = "servant"; + throw ex; + } + + _servantMapMap.remove(ident); + + return m; + } + + public synchronized Ice.Object + findServant(Ice.Identity ident, String facet) + { + // + // This assert is not valid if the adapter dispatch incoming + // requests from bidir connections. This method might be called if + // requests are received over the bidir connection after the + // adapter was deactivated. + // + //assert(_instance != null); // Must not be called after destruction. + + if(facet == null) + { + facet = ""; + } + + java.util.Map<String, Ice.Object> m = _servantMapMap.get(ident); + Ice.Object obj = null; + if(m == null) + { + obj = _defaultServantMap.get(ident.category); + if(obj == null) + { + obj = _defaultServantMap.get(""); + } + } + else + { + obj = m.get(facet); + } + + return obj; + } + + public synchronized Ice.Object + findDefaultServant(String category) + { + assert(_instance != null); // Must not be called after destruction. + + return _defaultServantMap.get(category); + } + + public synchronized java.util.Map<String, Ice.Object> + findAllFacets(Ice.Identity ident) + { + assert(_instance != null); // Must not be called after destruction. + + java.util.Map<String, Ice.Object> m = _servantMapMap.get(ident); + if(m != null) + { + return new java.util.HashMap<String, Ice.Object>(m); + } + + return new java.util.HashMap<String, Ice.Object>(); + } + + public synchronized boolean + hasServant(Ice.Identity ident) + { + // + // This assert is not valid if the adapter dispatch incoming + // requests from bidir connections. This method might be called if + // requests are received over the bidir connection after the + // adapter was deactivated. + // + //assert(_instance != null); // Must not be called after destruction. + + java.util.Map<String, Ice.Object> m = _servantMapMap.get(ident); + if(m == null) + { + return false; + } + else + { + assert(!m.isEmpty()); + return true; + } + } + + public synchronized void + addServantLocator(Ice.ServantLocator locator, String category) + { + assert(_instance != null); // Must not be called after destruction. + + Ice.ServantLocator l = _locatorMap.get(category); + if(l != null) + { + Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); + ex.id = IceUtilInternal.StringUtil.escapeString(category, ""); + ex.kindOfObject = "servant locator"; + throw ex; + } + + _locatorMap.put(category, locator); + } + + public synchronized Ice.ServantLocator + removeServantLocator(String category) + { + Ice.ServantLocator l = null; + assert(_instance != null); // Must not be called after destruction. + + l = _locatorMap.remove(category); + if(l == null) + { + Ice.NotRegisteredException ex = new Ice.NotRegisteredException(); + ex.id = IceUtilInternal.StringUtil.escapeString(category, ""); + ex.kindOfObject = "servant locator"; + throw ex; + } + return l; + } + + public synchronized Ice.ServantLocator + findServantLocator(String category) + { + // + // This assert is not valid if the adapter dispatch incoming + // requests from bidir connections. This method might be called if + // requests are received over the bidir connection after the + // adapter was deactivated. + // + //assert(_instance != null); // Must not be called after destruction. + + return _locatorMap.get(category); + } + + // + // Only for use by Ice.ObjectAdatperI. + // + public + ServantManager(Instance instance, String adapterName) + { + _instance = instance; + _adapterName = adapterName; + } + + // + // Only for use by Ice.ObjectAdapterI. + // + public void + destroy() + { + java.util.Map<String, Ice.ServantLocator> locatorMap = new java.util.HashMap<String, Ice.ServantLocator>(); + Ice.Logger logger = null; + synchronized(this) + { + // + // If the ServantManager has already been destroyed, we're done. + // + if(_instance == null) + { + return; + } + + logger = _instance.initializationData().logger; + + _servantMapMap.clear(); + + _defaultServantMap.clear(); + + locatorMap.putAll(_locatorMap); + _locatorMap.clear(); + + _instance = null; + } + + for(java.util.Map.Entry<String, Ice.ServantLocator> p : locatorMap.entrySet()) + { + Ice.ServantLocator locator = p.getValue(); + try + { + locator.deactivate(p.getKey()); + } + catch(java.lang.Exception ex) + { + String s = "exception during locator deactivation:\n" + "object adapter: `" + _adapterName + "'\n" + + "locator category: `" + p.getKey() + "'\n" + Ex.toString(ex); + logger.error(s); + } + } + } + + private Instance _instance; + final private String _adapterName; + private java.util.Map<Ice.Identity, java.util.Map<String, Ice.Object> > _servantMapMap = + new java.util.HashMap<Ice.Identity, java.util.Map<String, Ice.Object> >(); + private java.util.Map<String, Ice.Object> _defaultServantMap = new java.util.HashMap<String, Ice.Object>(); + private java.util.Map<String, Ice.ServantLocator> _locatorMap = new java.util.HashMap<String, Ice.ServantLocator>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/SocketOperation.java b/java-compat/src/Ice/src/main/java/IceInternal/SocketOperation.java new file mode 100644 index 00000000000..030d5d32bfd --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/SocketOperation.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.nio.channels.SelectionKey; + +public class SocketOperation +{ + public static final int None = 0; + public static final int Read = SelectionKey.OP_READ; + public static final int Write = SelectionKey.OP_WRITE; + public static final int Connect = SelectionKey.OP_CONNECT; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/StreamSocket.java b/java-compat/src/Ice/src/main/java/IceInternal/StreamSocket.java new file mode 100644 index 00000000000..03cd265e0e6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/StreamSocket.java @@ -0,0 +1,329 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class StreamSocket +{ + public StreamSocket(ProtocolInstance instance, + NetworkProxy proxy, + java.net.InetSocketAddress addr, + java.net.InetSocketAddress sourceAddr) + { + _instance = instance; + _proxy = proxy; + _addr = addr; + _fd = Network.createTcpSocket(); + _state = StateNeedConnect; + + try + { + init(); + if(Network.doConnect(_fd, _proxy != null ? _proxy.getAddress() : _addr, sourceAddr)) + { + _state = _proxy != null ? StateProxyWrite : StateConnected; + } + } + catch(Ice.LocalException ex) + { + assert(!_fd.isOpen()); + _fd = null; // Necessary for the finalizer + throw ex; + } + + _desc = Network.fdToString(_fd, _proxy, _addr); + } + + public StreamSocket(ProtocolInstance instance, java.nio.channels.SocketChannel fd) + { + _instance = instance; + _proxy = null; + _addr = null; + _fd = fd; + _state = StateConnected; + + try + { + init(); + } + catch(Ice.LocalException ex) + { + assert(!_fd.isOpen()); + _fd = null; // Necessary for the finalizer + throw ex; + } + + _desc = Network.fdToString(_fd); + } + + @Override + protected synchronized void finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + public void setBufferSize(int rcvSize, int sndSize) + { + Network.setTcpBufSize(_fd, rcvSize, sndSize, _instance); + } + + public int connect(Buffer readBuffer, Buffer writeBuffer) + { + if(_state == StateNeedConnect) + { + _state = StateConnectPending; + return SocketOperation.Connect; + } + else if(_state <= StateConnectPending) + { + Network.doFinishConnect(_fd); + _desc = Network.fdToString(_fd, _proxy, _addr); + _state = _proxy != null ? StateProxyWrite : StateConnected; + } + + if(_state == StateProxyWrite) + { + _proxy.beginWrite(_addr, writeBuffer); + return SocketOperation.Write; + } + else if(_state == StateProxyRead) + { + _proxy.beginRead(readBuffer); + return SocketOperation.Read; + } + else if(_state == StateProxyConnected) + { + _proxy.finish(readBuffer, writeBuffer); + + readBuffer.clear(); + writeBuffer.clear(); + + _state = StateConnected; + } + + assert(_state == StateConnected); + return SocketOperation.None; + } + + public boolean isConnected() + { + return _state == StateConnected; + } + + public java.nio.channels.SocketChannel fd() + { + return _fd; + } + + public int read(Buffer buf) + { + if(_state == StateProxyRead) + { + while(true) + { + int ret = read(buf.b); + if(ret == 0) + { + return SocketOperation.Read; + } + _state = toState(_proxy.endRead(buf)); + if(_state != StateProxyRead) + { + return SocketOperation.None; + } + } + } + read(buf.b); + return buf.b.hasRemaining() ? SocketOperation.Read : SocketOperation.None; + } + + public int write(Buffer buf) + { + if(_state == StateProxyWrite) + { + while(true) + { + int ret = write(buf.b); + if(ret == 0) + { + return SocketOperation.Write; + } + _state = toState(_proxy.endWrite(buf)); + if(_state != StateProxyWrite) + { + return SocketOperation.None; + } + } + } + write(buf.b); + return buf.b.hasRemaining() ? SocketOperation.Write : SocketOperation.None; + } + + public int read(java.nio.ByteBuffer buf) + { + assert(_fd != null); + + int read = 0; + + while(buf.hasRemaining()) + { + try + { + int ret = _fd.read(buf); + if(ret == -1) + { + throw new Ice.ConnectionLostException(); + } + else if(ret == 0) + { + return read; + } + + read += ret; + } + catch(java.io.InterruptedIOException ex) + { + continue; + } + catch(java.io.IOException ex) + { + throw new Ice.ConnectionLostException(ex); + } + } + return read; + } + + public int write(java.nio.ByteBuffer buf) + { + assert(_fd != null); + + int sent = 0; + while(buf.hasRemaining()) + { + try + { + int ret; + if(_maxSendPacketSize > 0 && buf.remaining() > _maxSendPacketSize) + { + int previous = buf.limit(); + buf.limit(buf.position() + _maxSendPacketSize); + ret = _fd.write(buf); + buf.limit(previous); + } + else + { + ret = _fd.write(buf); + } + + if(ret == -1) + { + throw new Ice.ConnectionLostException(); + } + else if(ret == 0) + { + return sent; + } + sent += ret; + } + catch(java.io.InterruptedIOException ex) + { + continue; + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + return sent; + } + + public void close() + { + assert(_fd != null); + try + { + _fd.close(); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + finally + { + _fd = null; + } + } + + @Override + public String toString() + { + return _desc; + } + + private void init() + { + Network.setBlock(_fd, false); + Network.setTcpBufSize(_fd, _instance); + + if(System.getProperty("os.name").startsWith("Windows")) + { + // + // On Windows, limiting the buffer size is important to prevent + // poor throughput performances when sending large amount of + // data. See Microsoft KB article KB823764. + // + _maxSendPacketSize = java.lang.Math.max(512, Network.getSendBufferSize(_fd) / 2); + } + else + { + _maxSendPacketSize = 0; + } + } + + private int toState(int operation) + { + switch(operation) + { + case SocketOperation.Read: + return StateProxyRead; + case SocketOperation.Write: + return StateProxyWrite; + default: + return StateProxyConnected; + } + } + + private final ProtocolInstance _instance; + + final private NetworkProxy _proxy; + final private java.net.InetSocketAddress _addr; + + private java.nio.channels.SocketChannel _fd; + private int _maxSendPacketSize; + private int _state; + private String _desc; + + private static final int StateNeedConnect = 0; + private static final int StateConnectPending = 1; + private static final int StateProxyRead = 2; + private static final int StateProxyWrite = 3; + private static final int StateProxyConnected = 4; + private static final int StateConnected = 5; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TcpAcceptor.java b/java-compat/src/Ice/src/main/java/IceInternal/TcpAcceptor.java new file mode 100644 index 00000000000..27418ca2bad --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TcpAcceptor.java @@ -0,0 +1,150 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +class TcpAcceptor implements Acceptor +{ + @Override + public java.nio.channels.ServerSocketChannel fd() + { + return _fd; + } + + @Override + public void setReadyCallback(ReadyCallback callback) + { + // No need to for the ready callback. + } + + @Override + public void close() + { + if(_fd != null) + { + Network.closeSocketNoThrow(_fd); + _fd = null; + } + } + + @Override + public EndpointI listen() + { + try + { + _addr = Network.doBind(_fd, _addr, _backlog); + } + catch(Ice.Exception ex) + { + _fd = null; + throw ex; + } + _endpoint = _endpoint.endpoint(this); + return _endpoint; + } + + @Override + public Transceiver accept() + { + return new TcpTransceiver(_instance, new StreamSocket(_instance, Network.doAccept(_fd))); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public String toString() + { + return Network.addrToString(_addr); + } + + @Override + public String toDetailedString() + { + StringBuffer s = new StringBuffer("local address = "); + s.append(toString()); + + java.util.List<String> intfs = + Network.getHostsForEndpointExpand(_addr.getAddress().getHostAddress(), _instance.protocolSupport(), true); + if(!intfs.isEmpty()) + { + s.append("\nlocal interfaces = "); + s.append(IceUtilInternal.StringUtil.joinString(intfs, ", ")); + } + return s.toString(); + } + + int effectivePort() + { + return _addr.getPort(); + } + + TcpAcceptor(TcpEndpointI endpoint, ProtocolInstance instance, String host, int port) + { + _endpoint = endpoint; + _instance = instance; + _backlog = instance.properties().getPropertyAsIntWithDefault("Ice.TCP.Backlog", 511); + + try + { + _fd = Network.createTcpServerSocket(); + Network.setBlock(_fd, false); + Network.setTcpBufSize(_fd, instance); + if(!System.getProperty("os.name").startsWith("Windows")) + { + // + // Enable SO_REUSEADDR on Unix platforms to allow re-using the + // socket even if it's in the TIME_WAIT state. On Windows, + // this doesn't appear to be necessary and enabling + // SO_REUSEADDR would actually not be a good thing since it + // allows a second process to bind to an address even it's + // already bound by another process. + // + // TODO: using SO_EXCLUSIVEADDRUSE on Windows would probably + // be better but it's only supported by recent Windows + // versions (XP SP2, Windows Server 2003). + // + Network.setReuseAddress(_fd, true); + } + + _addr = Network.getAddressForServer(host, port, instance.protocolSupport(), instance.preferIPv6()); + } + catch(RuntimeException ex) + { + _fd = null; + throw ex; + } + } + + @Override + protected synchronized void finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private TcpEndpointI _endpoint; + private ProtocolInstance _instance; + private java.nio.channels.ServerSocketChannel _fd; + private int _backlog; + private java.net.InetSocketAddress _addr; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TcpConnector.java b/java-compat/src/Ice/src/main/java/IceInternal/TcpConnector.java new file mode 100644 index 00000000000..64ab2c3b515 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TcpConnector.java @@ -0,0 +1,101 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class TcpConnector implements Connector +{ + @Override + public Transceiver connect() + { + return new TcpTransceiver(_instance, new StreamSocket(_instance, _proxy, _addr, _sourceAddr)); + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String toString() + { + return Network.addrToString(_proxy == null ? _addr : _proxy.getAddress()); + } + + @Override + public int hashCode() + { + return _hashCode; + } + + // + // Only for use by TcpEndpoint + // + TcpConnector(ProtocolInstance instance, java.net.InetSocketAddress addr, NetworkProxy proxy, + java.net.InetSocketAddress sourceAddr, int timeout, String connectionId) + { + _instance = instance; + _addr = addr; + _proxy = proxy; + _sourceAddr = sourceAddr; + _timeout = timeout; + _connectionId = connectionId; + + _hashCode = 5381; + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _addr.getAddress().getHostAddress()); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _addr.getPort()); + if(_sourceAddr != null) + { + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _sourceAddr.getAddress().getHostAddress()); + } + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _timeout); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _connectionId); + } + + @Override + public boolean equals(java.lang.Object obj) + { + if(!(obj instanceof TcpConnector)) + { + return false; + } + + if(this == obj) + { + return true; + } + + TcpConnector p = (TcpConnector)obj; + if(_timeout != p._timeout) + { + return false; + } + + if(!_connectionId.equals(p._connectionId)) + { + return false; + } + + if(Network.compareAddress(_sourceAddr, p._sourceAddr) != 0) + { + return false; + } + + return Network.compareAddress(_addr, p._addr) == 0; + } + + private ProtocolInstance _instance; + private java.net.InetSocketAddress _addr; + private NetworkProxy _proxy; + private java.net.InetSocketAddress _sourceAddr; + private int _timeout; + private String _connectionId = ""; + private int _hashCode; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TcpEndpointFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/TcpEndpointFactory.java new file mode 100644 index 00000000000..9211951ca59 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TcpEndpointFactory.java @@ -0,0 +1,58 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class TcpEndpointFactory implements EndpointFactory +{ + TcpEndpointFactory(ProtocolInstance instance) + { + _instance = instance; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) + { + IPEndpointI endpt = new TcpEndpointI(_instance); + endpt.initWithOptions(args, oaEndpoint); + return endpt; + } + + @Override + public EndpointI read(Ice.InputStream s) + { + return new TcpEndpointI(_instance, s); + } + + @Override + public void destroy() + { + _instance = null; + } + + @Override + public EndpointFactory clone(ProtocolInstance instance, EndpointFactory delegate) + { + return new TcpEndpointFactory(instance); + } + + private ProtocolInstance _instance; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TcpEndpointI.java b/java-compat/src/Ice/src/main/java/IceInternal/TcpEndpointI.java new file mode 100644 index 00000000000..f038da63a2d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TcpEndpointI.java @@ -0,0 +1,317 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class TcpEndpointI extends IPEndpointI +{ + public TcpEndpointI(ProtocolInstance instance, String ho, int po, java.net.InetSocketAddress sourceAddr, int ti, + String conId, boolean co) + { + super(instance, ho, po, sourceAddr, conId); + _timeout = ti; + _compress = co; + } + + public TcpEndpointI(ProtocolInstance instance) + { + super(instance); + _timeout = _instance.defaultTimeout(); + _compress = false; + } + + public TcpEndpointI(ProtocolInstance instance, Ice.InputStream s) + { + super(instance, s); + _timeout = s.readInt(); + _compress = s.readBool(); + } + + // + // Return the endpoint information. + // + @Override + public Ice.EndpointInfo getInfo() + { + Ice.TCPEndpointInfo info = new Ice.TCPEndpointInfo() + { + @Override + public short type() + { + return TcpEndpointI.this.type(); + } + + @Override + public boolean datagram() + { + return TcpEndpointI.this.datagram(); + } + + @Override + public boolean secure() + { + return TcpEndpointI.this.secure(); + } + }; + fillEndpointInfo(info); + return info; + } + + // + // Return the timeout for the endpoint in milliseconds. 0 means + // non-blocking, -1 means no timeout. + // + @Override + public int timeout() + { + return _timeout; + } + + // + // Return a new endpoint with a different timeout value, provided + // that timeouts are supported by the endpoint. Otherwise the same + // endpoint is returned. + // + @Override + public EndpointI timeout(int timeout) + { + if(timeout == _timeout) + { + return this; + } + else + { + return new TcpEndpointI(_instance, _host, _port, _sourceAddr, timeout, _connectionId, _compress); + } + } + + // + // Return true if the endpoints support bzip2 compress, or false + // otherwise. + // + @Override + public boolean compress() + { + return _compress; + } + + // + // Return a new endpoint with a different compression value, + // provided that compression is supported by the + // endpoint. Otherwise the same endpoint is returned. + // + @Override + public EndpointI compress(boolean compress) + { + if(compress == _compress) + { + return this; + } + else + { + return new TcpEndpointI(_instance, _host, _port, _sourceAddr, _timeout, _connectionId, compress); + } + } + + // + // Return true if the endpoint is datagram-based. + // + @Override + public boolean datagram() + { + return false; + } + + // + // Return a server side transceiver for this endpoint, or null if a + // transceiver can only be created by an acceptor. + // + @Override + public Transceiver transceiver() + { + return null; + } + + // + // Return an acceptor for this endpoint, or null if no acceptors + // is available. + // + @Override + public Acceptor acceptor(String adapterName) + { + return new TcpAcceptor(this, _instance, _host, _port); + } + + public TcpEndpointI endpoint(TcpAcceptor acceptor) + { + return new TcpEndpointI(_instance, _host, acceptor.effectivePort(), _sourceAddr, _timeout, + _connectionId, _compress); + } + + @Override + public String options() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = super.options(); + + if(_timeout == -1) + { + s += " -t infinite"; + } + else + { + s += " -t " + _timeout; + } + + if(_compress) + { + s += " -z"; + } + + return s; + } + + // + // Compare endpoints for sorting purposes + // + @Override + public int compareTo(EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof TcpEndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + TcpEndpointI p = (TcpEndpointI)obj; + if(this == p) + { + return 0; + } + + if(_timeout < p._timeout) + { + return -1; + } + else if(p._timeout < _timeout) + { + return 1; + } + + if(!_compress && p._compress) + { + return -1; + } + else if(!p._compress && _compress) + { + return 1; + } + + return super.compareTo(obj); + } + + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + super.streamWriteImpl(s); + s.writeInt(_timeout); + s.writeBool(_compress); + } + + @Override + public int hashInit(int h) + { + h = super.hashInit(h); + h = IceInternal.HashUtil.hashAdd(h, _timeout); + h = IceInternal.HashUtil.hashAdd(h, _compress); + return h; + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + if(super.checkOption(option, argument, endpoint)) + { + return true; + } + + switch(option.charAt(1)) + { + case 't': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint); + } + + if(argument.equals("infinite")) + { + _timeout = -1; + } + else + { + try + { + _timeout = Integer.parseInt(argument); + if(_timeout < 1) + { + throw new Ice.EndpointParseException("invalid timeout value `" + argument + + "' in endpoint " + endpoint); + } + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid timeout value `" + argument + + "' in endpoint " + endpoint); + } + } + + return true; + } + + case 'z': + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -z option in " + endpoint); + } + + _compress = true; + + return true; + } + + default: + { + return false; + } + } + } + + @Override + protected Connector createConnector(java.net.InetSocketAddress addr, NetworkProxy proxy) + { + return new TcpConnector(_instance, addr, proxy, _sourceAddr, _timeout, _connectionId); + } + + @Override + protected IPEndpointI createEndpoint(String host, int port, String connectionId) + { + return new TcpEndpointI(_instance, host, port, _sourceAddr, _timeout, connectionId, _compress); + } + + private int _timeout; + private boolean _compress; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TcpTransceiver.java b/java-compat/src/Ice/src/main/java/IceInternal/TcpTransceiver.java new file mode 100644 index 00000000000..069e79a3408 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TcpTransceiver.java @@ -0,0 +1,126 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class TcpTransceiver implements Transceiver +{ + @Override + public java.nio.channels.SelectableChannel fd() + { + assert(_stream != null); + return _stream.fd(); + } + + @Override + public void setReadyCallback(ReadyCallback callback) + { + // No need of the callback + } + + @Override + public int initialize(Buffer readBuffer, Buffer writeBuffer) + { + return _stream.connect(readBuffer, writeBuffer); + } + + @Override + public int closing(boolean initiator, Ice.LocalException ex) + { + // If we are initiating the connection closure, wait for the peer + // to close the TCP/IP connection. Otherwise, close immediately. + return initiator ? SocketOperation.Read : SocketOperation.None; + } + + @Override + public void close() + { + _stream.close(); + } + + @Override + public EndpointI bind() + { + assert(false); + return null; + } + + @Override + public int write(Buffer buf) + { + return _stream.write(buf); + } + + @Override + public int read(Buffer buf) + { + return _stream.read(buf); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public String toString() + { + return _stream.toString(); + } + + @Override + public String toDetailedString() + { + return toString(); + } + + @Override + public Ice.ConnectionInfo getInfo() + { + Ice.TCPConnectionInfo info = new Ice.TCPConnectionInfo(); + if(_stream.fd() != null) + { + java.net.Socket socket = _stream.fd().socket(); + info.localAddress = socket.getLocalAddress().getHostAddress(); + info.localPort = socket.getLocalPort(); + if(socket.getInetAddress() != null) + { + info.remoteAddress = socket.getInetAddress().getHostAddress(); + info.remotePort = socket.getPort(); + } + if(!socket.isClosed()) + { + info.rcvSize = Network.getRecvBufferSize(_stream.fd()); + info.sndSize = Network.getSendBufferSize(_stream.fd()); + } + } + return info; + } + + @Override + public void checkSendSize(Buffer buf) + { + } + + @Override + public void setBufferSize(int rcvSize, int sndSize) + { + _stream.setBufferSize(rcvSize, sndSize); + } + + TcpTransceiver(ProtocolInstance instance, StreamSocket stream) + { + _instance = instance; + _stream = stream; + } + + final private ProtocolInstance _instance; + final private StreamSocket _stream; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ThreadObserverI.java b/java-compat/src/Ice/src/main/java/IceInternal/ThreadObserverI.java new file mode 100644 index 00000000000..553e46840bf --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ThreadObserverI.java @@ -0,0 +1,68 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public class ThreadObserverI + extends IceMX.ObserverWithDelegate<IceMX.ThreadMetrics, Ice.Instrumentation.ThreadObserver> + implements Ice.Instrumentation.ThreadObserver +{ + @Override + public void + stateChanged(final Ice.Instrumentation.ThreadState oldState, final Ice.Instrumentation.ThreadState newState) + { + _oldState = oldState; + _newState = newState; + forEach(_threadStateUpdate); + if(_delegate != null) + { + _delegate.stateChanged(oldState, newState); + } + } + + private MetricsUpdate<IceMX.ThreadMetrics> _threadStateUpdate = new MetricsUpdate<IceMX.ThreadMetrics>() + { + @Override + public void + update(IceMX.ThreadMetrics v) + { + switch(_oldState) + { + case ThreadStateInUseForIO: + --v.inUseForIO; + break; + case ThreadStateInUseForUser: + --v.inUseForUser; + break; + case ThreadStateInUseForOther: + --v.inUseForOther; + break; + default: + break; + } + switch(_newState) + { + case ThreadStateInUseForIO: + ++v.inUseForIO; + break; + case ThreadStateInUseForUser: + ++v.inUseForUser; + break; + case ThreadStateInUseForOther: + ++v.inUseForOther; + break; + default: + break; + } + } + }; + + private Ice.Instrumentation.ThreadState _oldState; + private Ice.Instrumentation.ThreadState _newState; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ThreadPool.java b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPool.java new file mode 100644 index 00000000000..9dc5f1ec92a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPool.java @@ -0,0 +1,823 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ThreadPool +{ + final class ShutdownWorkItem implements ThreadPoolWorkItem + { + @Override + public void execute(ThreadPoolCurrent current) + { + current.ioCompleted(); + try + { + _instance.objectAdapterFactory().shutdown(); + } + catch(Ice.CommunicatorDestroyedException ex) + { + } + } + } + + static final class FinishedWorkItem implements ThreadPoolWorkItem + { + public + FinishedWorkItem(EventHandler handler, boolean close) + { + _handler = handler; + _close = close; + } + + @Override + public void execute(ThreadPoolCurrent current) + { + _handler.finished(current, _close); + } + + private final EventHandler _handler; + private final boolean _close; + } + + static final class JoinThreadWorkItem implements ThreadPoolWorkItem + { + public + JoinThreadWorkItem(EventHandlerThread thread) + { + _thread = thread; + } + + @Override + public void execute(ThreadPoolCurrent current) + { + // No call to ioCompleted, this shouldn't block (and we don't want to cause + // a new thread to be started). + try + { + _thread.join(); + } + catch (InterruptedException e) + { + // Ignore. + } + } + + private final EventHandlerThread _thread; + } + + static final class InterruptWorkItem implements ThreadPoolWorkItem + { + @Override + public void execute(ThreadPoolCurrent current) + { + // Nothing to do, this is just used to interrupt the thread pool selector. + } + } + + private static ThreadPoolWorkItem _interruptWorkItem = new InterruptWorkItem(); + + // + // Exception raised by the thread pool work queue when the thread pool + // is destroyed. + // + static final class DestroyedException extends RuntimeException + { + } + + public + ThreadPool(Instance instance, String prefix, int timeout) + { + Ice.Properties properties = instance.initializationData().properties; + + _instance = instance; + _dispatcher = instance.initializationData().dispatcher; + _destroyed = false; + _prefix = prefix; + _selector = new Selector(instance); + _threadIndex = 0; + _inUse = 0; + _inUseIO = 0; + _promote = true; + _serialize = properties.getPropertyAsInt(_prefix + ".Serialize") > 0; + _serverIdleTime = timeout; + _threadPrefix = Util.createThreadName(properties, _prefix); + + int nProcessors = Runtime.getRuntime().availableProcessors(); + + // + // We use just one thread as the default. This is the fastest + // possible setting, still allows one level of nesting, and + // doesn't require to make the servants thread safe. + // + int size = properties.getPropertyAsIntWithDefault(_prefix + ".Size", 1); + if(size < 1) + { + String s = _prefix + ".Size < 1; Size adjusted to 1"; + _instance.initializationData().logger.warning(s); + size = 1; + } + + int sizeMax = properties.getPropertyAsIntWithDefault(_prefix + ".SizeMax", size); + if(sizeMax == -1) + { + sizeMax = nProcessors; + } + if(sizeMax < size) + { + String s = _prefix + ".SizeMax < " + _prefix + ".Size; SizeMax adjusted to Size (" + size + ")"; + _instance.initializationData().logger.warning(s); + sizeMax = size; + } + + int sizeWarn = properties.getPropertyAsInt(_prefix + ".SizeWarn"); + if(sizeWarn != 0 && sizeWarn < size) + { + String s = _prefix + ".SizeWarn < " + _prefix + ".Size; adjusted SizeWarn to Size (" + size + ")"; + _instance.initializationData().logger.warning(s); + sizeWarn = size; + } + else if(sizeWarn > sizeMax) + { + String s = _prefix + ".SizeWarn > " + _prefix + ".SizeMax; adjusted SizeWarn to SizeMax (" + sizeMax + ")"; + _instance.initializationData().logger.warning(s); + sizeWarn = sizeMax; + } + + int threadIdleTime = properties.getPropertyAsIntWithDefault(_prefix + ".ThreadIdleTime", 60); + if(threadIdleTime < 0) + { + String s = _prefix + ".ThreadIdleTime < 0; ThreadIdleTime adjusted to 0"; + _instance.initializationData().logger.warning(s); + threadIdleTime = 0; + } + + _size = size; + _sizeMax = sizeMax; + _sizeWarn = sizeWarn; + _sizeIO = Math.min(sizeMax, nProcessors); + _threadIdleTime = threadIdleTime; + + int stackSize = properties.getPropertyAsInt( _prefix + ".StackSize"); + if(stackSize < 0) + { + String s = _prefix + ".StackSize < 0; Size adjusted to JRE default"; + _instance.initializationData().logger.warning(s); + stackSize = 0; + } + _stackSize = stackSize; + + boolean hasPriority = properties.getProperty(_prefix + ".ThreadPriority").length() > 0; + int priority = properties.getPropertyAsInt(_prefix + ".ThreadPriority"); + if(!hasPriority) + { + hasPriority = properties.getProperty("Ice.ThreadPriority").length() > 0; + priority = properties.getPropertyAsInt("Ice.ThreadPriority"); + } + _hasPriority = hasPriority; + _priority = priority; + + _workQueue = new ThreadPoolWorkQueue(_instance, this, _selector); + _nextHandler = _handlers.iterator(); + + if(_instance.traceLevels().threadPool >= 1) + { + String s = "creating " + _prefix + ": Size = " + _size + ", SizeMax = " + _sizeMax + ", SizeWarn = " + + _sizeWarn; + _instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s); + } + + try + { + for(int i = 0; i < _size; i++) + { + EventHandlerThread thread = new EventHandlerThread(_threadPrefix + "-" + _threadIndex++); + if(_hasPriority) + { + thread.start(_priority); + } + else + { + thread.start(java.lang.Thread.NORM_PRIORITY); + } + _threads.add(thread); + } + } + catch(RuntimeException ex) + { + String s = "cannot create thread for `" + _prefix + "':\n" + Ex.toString(ex); + _instance.initializationData().logger.error(s); + + destroy(); + try + { + joinWithAllThreads(); + } + catch (InterruptedException e) + { + throw new Ice.OperationInterruptedException(); + } + throw ex; + } + } + + @Override + protected synchronized void + finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_destroyed); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + public synchronized void + destroy() + { + if(_destroyed) + { + return; + } + + _destroyed = true; + _workQueue.destroy(); + } + + public synchronized void + updateObservers() + { + for(EventHandlerThread thread : _threads) + { + thread.updateObserver(); + } + } + + public synchronized void + initialize(final EventHandler handler) + { + assert(!_destroyed); + _selector.initialize(handler); + + handler.setReadyCallback( + new ReadyCallback() + { + public void ready(int op, boolean value) + { + synchronized(ThreadPool.this) + { + if(_destroyed) + { + return; + } + _selector.ready(handler, op, value); + } + } + }); + } + + public void + register(EventHandler handler, int op) + { + update(handler, SocketOperation.None, op); + } + + public synchronized void + update(EventHandler handler, int remove, int add) + { + assert(!_destroyed); + + // Don't remove what needs to be added + remove &= ~add; + + // Don't remove/add if already un-registered or registered + remove = handler._registered & remove; + add = ~handler._registered & add; + if(remove == add) + { + return; + } + _selector.update(handler, remove, add); + } + + public void + unregister(EventHandler handler, int op) + { + update(handler, op, SocketOperation.None); + } + + public synchronized boolean + finish(EventHandler handler, boolean closeNow) + { + assert(!_destroyed); + closeNow = _selector.finish(handler, closeNow); + _workQueue.queue(new FinishedWorkItem(handler, !closeNow)); + return closeNow; + } + + public void + dispatchFromThisThread(DispatchWorkItem workItem) + { + if(_dispatcher != null) + { + try + { + _dispatcher.dispatch(workItem, workItem.getConnection()); + } + catch(java.lang.Exception ex) + { + if(_instance.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.Dispatch", 1) > 1) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _instance.initializationData().logger.warning("dispatch exception:\n" + sw.toString()); + } + } + } + else + { + workItem.run(); + } + } + + synchronized public void + dispatch(DispatchWorkItem workItem) + { + if(_destroyed) + { + throw new Ice.CommunicatorDestroyedException(); + } + _workQueue.queue(workItem); + } + + public void + joinWithAllThreads() + throws InterruptedException + { + // + // _threads is immutable after destroy() has been called, + // therefore no synchronization is needed. (Synchronization + // wouldn't be possible here anyway, because otherwise the + // other threads would never terminate.) + // + for(EventHandlerThread thread : _threads) + { + thread.join(); + } + + // + // Destroy the selector + // + _selector.destroy(); + } + + private void + run(EventHandlerThread thread) + { + ThreadPoolCurrent current = new ThreadPoolCurrent(_instance, this, thread); + boolean select = false; + while(true) + { + if(current._handler != null) + { + try + { + current._handler.message(current); + } + catch(DestroyedException ex) + { + return; + } + catch(java.lang.Exception ex) + { + String s = "exception in `" + _prefix + "':\n" + Ex.toString(ex); + s += "\nevent handler: " + current._handler.toString(); + _instance.initializationData().logger.error(s); + } + } + else if(select) + { + try + { + _selector.select(_serverIdleTime); + } + catch(Selector.TimeoutException ex) + { + synchronized(this) + { + if(!_destroyed && _inUse == 0) + { + _workQueue.queue(new ShutdownWorkItem()); // Select timed-out. + } + continue; + } + } + } + + synchronized(this) + { + if(current._handler == null) + { + if(select) + { + _selector.finishSelect(_handlers); + select = false; + _nextHandler = _handlers.iterator(); + } + else if(!current._leader && followerWait(current)) + { + return; // Wait timed-out. + } + } + else if(_sizeMax > 1) + { + if(!current._ioCompleted) + { + // + // The handler didn't call ioCompleted() so we take care of decreasing + // the IO thread count now. + // + --_inUseIO; + } + else + { + // + // If the handler called ioCompleted(), we re-enable the handler in + // case it was disabled and we decrease the number of thread in use. + // + if(_serialize) + { + _selector.enable(current._handler, current.operation); + } + assert(_inUse > 0); + --_inUse; + } + + if(!current._leader && followerWait(current)) + { + return; // Wait timed-out. + } + } + + // + // Get the next ready handler. + // + current._handler = null; + while(_nextHandler.hasNext()) + { + EventHandlerOpPair n = _nextHandler.next(); + int op = n.op & ~n.handler._disabled & n.handler._registered; + if(op != 0) + { + current._ioCompleted = false; + current._handler = n.handler; + current.operation = op; + thread.setState(Ice.Instrumentation.ThreadState.ThreadStateInUseForIO); + break; + } + } + + if(current._handler == null) + { + // + // If there are no more ready handlers and there are still threads busy performing + // IO, we give up leadership and promote another follower (which will perform the + // select() only once all the IOs are completed). Otherwise, if there's no more + // threads peforming IOs, it's time to do another select(). + // + if(_inUseIO > 0) + { + promoteFollower(current); + } + else + { + _handlers.clear(); + _selector.startSelect(); + select = true; + thread.setState(Ice.Instrumentation.ThreadState.ThreadStateIdle); + } + } + else if(_sizeMax > 1) + { + // + // Increment the IO thread count and if there's still threads available + // to perform IO and more handlers ready, we promote a follower. + // + ++_inUseIO; + if(_nextHandler.hasNext() && _inUseIO < _sizeIO) + { + promoteFollower(current); + } + } + } + } + } + + synchronized void + ioCompleted(ThreadPoolCurrent current) + { + current._ioCompleted = true; // Set the IO completed flag to specify that ioCompleted() has been called. + + current._thread.setState(Ice.Instrumentation.ThreadState.ThreadStateInUseForUser); + + if(_sizeMax > 1) + { + --_inUseIO; + + if(!_destroyed) + { + if(_serialize) + { + _selector.disable(current._handler, current.operation); + } + } + + if(current._leader) + { + // + // If this thread is still the leader, it's time to promote a new leader. + // + promoteFollower(current); + } + else if(_promote && (_nextHandler.hasNext() || _inUseIO == 0)) + { + notify(); + } + + assert(_inUse >= 0); + ++_inUse; + + if(_inUse == _sizeWarn) + { + String s = "thread pool `" + _prefix + "' is running low on threads\n" + + "Size=" + _size + ", " + "SizeMax=" + _sizeMax + ", " + "SizeWarn=" + _sizeWarn; + _instance.initializationData().logger.warning(s); + } + + if(!_destroyed) + { + assert(_inUse <= _threads.size()); + if(_inUse < _sizeMax && _inUse == _threads.size()) + { + if(_instance.traceLevels().threadPool >= 1) + { + String s = "growing " + _prefix + ": Size=" + (_threads.size() + 1); + _instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s); + } + + try + { + EventHandlerThread thread = new EventHandlerThread(_threadPrefix + "-" + _threadIndex++); + _threads.add(thread); + if(_hasPriority) + { + thread.start(_priority); + } + else + { + thread.start(java.lang.Thread.NORM_PRIORITY); + } + } + catch(RuntimeException ex) + { + String s = "cannot create thread for `" + _prefix + "':\n" + Ex.toString(ex); + _instance.initializationData().logger.error(s); + } + } + } + } + } + + private synchronized void + promoteFollower(ThreadPoolCurrent current) + { + assert(!_promote && current._leader); + _promote = true; + if(_inUseIO < _sizeIO && (_nextHandler.hasNext() || _inUseIO == 0)) + { + notify(); + } + current._leader = false; + } + + private synchronized boolean + followerWait(ThreadPoolCurrent current) + { + assert(!current._leader); + + current._thread.setState(Ice.Instrumentation.ThreadState.ThreadStateIdle); + + // + // It's important to clear the handler before waiting to make sure that + // resources for the handler are released now if it's finished. We also + // clear the per-thread stream. + // + current._handler = null; + current.stream.reset(); + + // + // Wait to be promoted and for all the IO threads to be done. + // + while(!_promote || _inUseIO == _sizeIO || (!_nextHandler.hasNext() && _inUseIO > 0)) + { + if(_threadIdleTime > 0) + { + long before = IceInternal.Time.currentMonotonicTimeMillis(); + boolean interrupted = false; + try + { + // + // If the wait is interrupted then we'll let the thread die as if it timed out. + // + wait(_threadIdleTime * 1000); + } + catch (InterruptedException e) + { + interrupted = true; + } + if(interrupted || IceInternal.Time.currentMonotonicTimeMillis() - before >= _threadIdleTime * 1000) + { + if(!_destroyed && (!_promote || _inUseIO == _sizeIO || (!_nextHandler.hasNext() && _inUseIO > 0))) + { + if(_instance.traceLevels().threadPool >= 1) + { + String s = "shrinking " + _prefix + ": Size=" + (_threads.size() - 1); + _instance.initializationData().logger.trace(_instance.traceLevels().threadPoolCat, s); + } + assert(_threads.size() > 1); // Can only be called by a waiting follower thread. + _threads.remove(current._thread); + _workQueue.queue(new JoinThreadWorkItem(current._thread)); + return true; + } + } + } + else + { + try + { + wait(); + } + catch (InterruptedException e) + { + // + // Eat the InterruptedException. + // + } + } + } + current._leader = true; // The current thread has become the leader. + _promote = false; + return false; + } + + private final Instance _instance; + private final Ice.Dispatcher _dispatcher; + private final ThreadPoolWorkQueue _workQueue; + private boolean _destroyed; + private final String _prefix; + private final String _threadPrefix; + private final Selector _selector; + + final class EventHandlerThread implements Runnable + { + EventHandlerThread(String name) + { + _name = name; + _state = Ice.Instrumentation.ThreadState.ThreadStateIdle; + updateObserver(); + } + + public void + updateObserver() + { + // Must be called with the thread pool mutex locked + Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer; + if(obsv != null) + { + _observer = obsv.getThreadObserver(_prefix, _name, _state, _observer); + if(_observer != null) + { + _observer.attach(); + } + } + } + + public void + setState(Ice.Instrumentation.ThreadState s) + { + // Must be called with the thread pool mutex locked + if(_observer != null) + { + if(_state != s) + { + _observer.stateChanged(_state, s); + } + } + _state = s; + } + + public void + join() + throws InterruptedException + { + _thread.join(); + } + + public void + start(int priority) + { + _thread = new Thread(null, this, _name, _stackSize); + _thread.setPriority(priority); + _thread.start(); + } + + @Override + public void + run() + { + if(_instance.initializationData().threadHook != null) + { + try + { + _instance.initializationData().threadHook.start(); + } + catch(java.lang.Exception ex) + { + String s = "thread hook start() method raised an unexpected exception in `"; + s += _prefix + "' thread " + _name + ":\n" + Ex.toString(ex); + _instance.initializationData().logger.error(s); + } + } + + try + { + ThreadPool.this.run(this); + } + catch(java.lang.Exception ex) + { + String s = "exception in `" + _prefix + "' thread " + _name + ":\n" + Ex.toString(ex); + _instance.initializationData().logger.error(s); + } + + if(_observer != null) + { + _observer.detach(); + } + + if(_instance.initializationData().threadHook != null) + { + try + { + _instance.initializationData().threadHook.stop(); + } + catch(java.lang.Exception ex) + { + String s = "thread hook stop() method raised an unexpected exception in `"; + s += _prefix + "' thread " + _name + ":\n" + Ex.toString(ex); + _instance.initializationData().logger.error(s); + } + } + } + + final private String _name; + private Thread _thread; + private Ice.Instrumentation.ThreadState _state; + private Ice.Instrumentation.ThreadObserver _observer; + } + + private final int _size; // Number of threads that are pre-created. + private final int _sizeIO; // Number of threads that can concurrently perform IO. + private final int _sizeMax; // Maximum number of threads. + private final int _sizeWarn; // If _inUse reaches _sizeWarn, a "low on threads" warning will be printed. + private final boolean _serialize; // True if requests need to be serialized over the connection. + private final int _priority; + private final boolean _hasPriority; + private final long _serverIdleTime; + private final long _threadIdleTime; + private final int _stackSize; + + private java.util.List<EventHandlerThread> _threads = new java.util.ArrayList<EventHandlerThread>(); + private int _threadIndex; // For assigning thread names. + private int _inUse; // Number of threads that are currently in use. + private int _inUseIO; // Number of threads that are currently performing IO. + + private java.util.List<EventHandlerOpPair> _handlers = new java.util.ArrayList<EventHandlerOpPair>(); + private java.util.Iterator<EventHandlerOpPair> _nextHandler; + + private boolean _promote; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolCurrent.java b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolCurrent.java new file mode 100644 index 00000000000..cdd5b9fe2bc --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolCurrent.java @@ -0,0 +1,51 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ThreadPoolCurrent +{ + ThreadPoolCurrent(Instance instance, ThreadPool threadPool, ThreadPool.EventHandlerThread thread) + { + operation = SocketOperation.None; + stream = new Ice.InputStream(instance, Protocol.currentProtocolEncoding); + + _threadPool = threadPool; + _thread = thread; + _ioCompleted = false; + _leader = false; + } + + public int operation; + public Ice.InputStream stream; // A per-thread stream to be used by event handlers for optimization. + + public boolean + ioReady() + { + return (_handler._registered & operation) > 0; + } + + public void + ioCompleted() + { + _threadPool.ioCompleted(this); + } + + public void + dispatchFromThisThread(DispatchWorkItem workItem) + { + _threadPool.dispatchFromThisThread(workItem); + } + + final ThreadPool _threadPool; + final ThreadPool.EventHandlerThread _thread; + EventHandler _handler; + boolean _ioCompleted; + boolean _leader; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolWorkItem.java b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolWorkItem.java new file mode 100644 index 00000000000..27f06f9366b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolWorkItem.java @@ -0,0 +1,15 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface ThreadPoolWorkItem +{ + void execute(ThreadPoolCurrent current); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolWorkQueue.java b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolWorkQueue.java new file mode 100644 index 00000000000..ae838d61cdf --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ThreadPoolWorkQueue.java @@ -0,0 +1,116 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.List; + +final class ThreadPoolWorkQueue extends EventHandler +{ + ThreadPoolWorkQueue(Instance instance, ThreadPool threadPool, Selector selector) + { + _threadPool = threadPool; + _selector = selector; + _destroyed = false; + _registered = SocketOperation.Read; + } + + @Override + protected synchronized void finalize() throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_destroyed); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + void destroy() + { + // Called with the thread pool locked + assert(!_destroyed); + _destroyed = true; + _selector.ready(this, SocketOperation.Read, true); + } + + void queue(ThreadPoolWorkItem item) + { + // Called with the thread pool locked + assert(item != null); + _workItems.add(item); + if(_workItems.size() == 1) + { + _selector.ready(this, SocketOperation.Read, true); + } + } + + @Override + public void message(ThreadPoolCurrent current) + { + ThreadPoolWorkItem workItem = null; + synchronized(_threadPool) + { + if(!_workItems.isEmpty()) + { + workItem = _workItems.removeFirst(); + assert(workItem != null); + } + if(_workItems.isEmpty() && !_destroyed) + { + _selector.ready(this, SocketOperation.Read, false); + } + } + + if(workItem != null) + { + workItem.execute(current); + } + else + { + assert(_destroyed); + _threadPool.ioCompleted(current); + throw new ThreadPool.DestroyedException(); + } + } + + @Override + public void finished(ThreadPoolCurrent current, boolean close) + { + assert(false); + } + + @Override + public String toString() + { + return "work queue"; + } + + @Override + public java.nio.channels.SelectableChannel fd() + { + return null; + } + + @Override + public void setReadyCallback(ReadyCallback callback) + { + // Ignore, we don't use the ready callback. + } + + private final ThreadPool _threadPool; + private boolean _destroyed; + private Selector _selector; + private java.util.LinkedList<ThreadPoolWorkItem> _workItems = new java.util.LinkedList<ThreadPoolWorkItem>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Time.java b/java-compat/src/Ice/src/main/java/IceInternal/Time.java new file mode 100644 index 00000000000..e1547f9e552 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Time.java @@ -0,0 +1,19 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final public class Time +{ + static public long + currentMonotonicTimeMillis() + { + return System.nanoTime() / 1000000; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TraceLevels.java b/java-compat/src/Ice/src/main/java/IceInternal/TraceLevels.java new file mode 100644 index 00000000000..8273966cdad --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TraceLevels.java @@ -0,0 +1,45 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class TraceLevels +{ + TraceLevels(Ice.Properties properties) + { + networkCat = "Network"; + protocolCat = "Protocol"; + retryCat = "Retry"; + locationCat = "Locator"; + slicingCat = "Slicing"; + threadPoolCat = "ThreadPool"; + + final String keyBase = "Ice.Trace."; + + network = properties.getPropertyAsInt(keyBase + networkCat); + protocol = properties.getPropertyAsInt(keyBase + protocolCat); + retry = properties.getPropertyAsInt(keyBase + retryCat); + location = properties.getPropertyAsInt(keyBase + locationCat); + slicing = properties.getPropertyAsInt(keyBase + slicingCat); + threadPool = properties.getPropertyAsInt(keyBase + threadPoolCat); + } + + final public int network; + final public String networkCat; + final public int protocol; + final public String protocolCat; + final public int retry; + final public String retryCat; + final public int location; + final public String locationCat; + final public int slicing; + final public String threadPoolCat; + final public int threadPool; + final public String slicingCat; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java b/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java new file mode 100644 index 00000000000..2ff165c475d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TraceUtil.java @@ -0,0 +1,514 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class TraceUtil +{ + public static void + traceSend(Ice.OutputStream str, Ice.Logger logger, TraceLevels tl) + { + if(tl.protocol >= 1) + { + int p = str.pos(); + Ice.InputStream is = new Ice.InputStream(str.instance(), str.getEncoding(), str.getBuffer(), false); + is.pos(0); + + java.io.StringWriter s = new java.io.StringWriter(); + byte type = printMessage(s, is); + + logger.trace(tl.protocolCat, "sending " + getMessageTypeAsString(type) + " " + s.toString()); + + str.pos(p); + } + } + + public static void + traceRecv(Ice.InputStream str, Ice.Logger logger, TraceLevels tl) + { + if(tl.protocol >= 1) + { + int p = str.pos(); + str.pos(0); + + java.io.StringWriter s = new java.io.StringWriter(); + byte type = printMessage(s, str); + + logger.trace(tl.protocolCat, "received " + getMessageTypeAsString(type) + " " + s.toString()); + + str.pos(p); + } + } + + public static void + trace(String heading, Ice.OutputStream str, Ice.Logger logger, TraceLevels tl) + { + if(tl.protocol >= 1) + { + int p = str.pos(); + Ice.InputStream is = new Ice.InputStream(str.instance(), str.getEncoding(), str.getBuffer(), false); + is.pos(0); + + java.io.StringWriter s = new java.io.StringWriter(); + s.write(heading); + printMessage(s, is); + + logger.trace(tl.protocolCat, s.toString()); + str.pos(p); + } + } + + public static void + trace(String heading, Ice.InputStream str, Ice.Logger logger, TraceLevels tl) + { + if(tl.protocol >= 1) + { + int p = str.pos(); + str.pos(0); + + java.io.StringWriter s = new java.io.StringWriter(); + s.write(heading); + printMessage(s, str); + + logger.trace(tl.protocolCat, s.toString()); + str.pos(p); + } + } + + private static java.util.Set<String> slicingIds = new java.util.HashSet<String>(); + + public synchronized static void + traceSlicing(String kind, String typeId, String slicingCat, Ice.Logger logger) + { + if(slicingIds.add(typeId)) + { + java.io.StringWriter s = new java.io.StringWriter(); + s.write("unknown " + kind + " type `" + typeId + "'"); + logger.trace(slicingCat, s.toString()); + } + } + + public static void + dumpStream(Ice.InputStream stream) + { + int pos = stream.pos(); + stream.pos(0); + + byte[] data = stream.readBlob(stream.size()); + dumpOctets(data); + + stream.pos(pos); + } + + public static void + dumpOctets(byte[] data) + { + final int inc = 8; + + for(int i = 0; i < data.length; i += inc) + { + for(int j = i; j - i < inc; j++) + { + if(j < data.length) + { + int n = data[j]; + if(n < 0) + { + n += 256; + } + String s; + if(n < 10) + { + s = " " + n; + } + else if(n < 100) + { + s = " " + n; + } + else + { + s = "" + n; + } + System.out.print(s + " "); + } + else + { + System.out.print(" "); + } + } + + System.out.print('"'); + + for(int j = i; j < data.length && j - i < inc; j++) + { + if(data[j] >= (byte)32 && data[j] < (byte)127) + { + System.out.print((char)data[j]); + } + else + { + System.out.print('.'); + } + } + + System.out.println('"'); + } + } + + private static void + printIdentityFacetOperation(java.io.Writer out, Ice.InputStream stream) + { + try + { + Ice.Identity identity = new Ice.Identity(); + identity.__read(stream); + out.write("\nidentity = " + Ice.Util.identityToString(identity)); + + String[] facet = stream.readStringSeq(); + out.write("\nfacet = "); + if(facet.length > 0) + { + out.write(IceUtilInternal.StringUtil.escapeString(facet[0], "")); + } + + String operation = stream.readString(); + out.write("\noperation = " + operation); + } + catch(java.io.IOException ex) + { + assert(false); + } + } + + private static void + printRequest(java.io.StringWriter s, Ice.InputStream str) + { + int requestId = str.readInt(); + s.write("\nrequest id = " + requestId); + if(requestId == 0) + { + s.write(" (oneway)"); + } + + printRequestHeader(s, str); + } + + private static void + printBatchRequest(java.io.StringWriter s, Ice.InputStream str) + { + int batchRequestNum = str.readInt(); + s.write("\nnumber of requests = " + batchRequestNum); + + for(int i = 0; i < batchRequestNum; ++i) + { + s.write("\nrequest #" + i + ':'); + printRequestHeader(s, str); + } + } + + private static void + printReply(java.io.StringWriter s, Ice.InputStream str) + { + int requestId = str.readInt(); + s.write("\nrequest id = " + requestId); + + byte replyStatus = str.readByte(); + s.write("\nreply status = " + (int)replyStatus + ' '); + + switch(replyStatus) + { + case ReplyStatus.replyOK: + { + s.write("(ok)"); + break; + } + + case ReplyStatus.replyUserException: + { + s.write("(user exception)"); + break; + } + + case ReplyStatus.replyObjectNotExist: + case ReplyStatus.replyFacetNotExist: + case ReplyStatus.replyOperationNotExist: + { + switch(replyStatus) + { + case ReplyStatus.replyObjectNotExist: + { + s.write("(object not exist)"); + break; + } + + case ReplyStatus.replyFacetNotExist: + { + s.write("(facet not exist)"); + break; + } + + case ReplyStatus.replyOperationNotExist: + { + s.write("(operation not exist)"); + break; + } + + default: + { + assert(false); + break; + } + } + + printIdentityFacetOperation(s, str); + break; + } + + case ReplyStatus.replyUnknownException: + case ReplyStatus.replyUnknownLocalException: + case ReplyStatus.replyUnknownUserException: + { + switch(replyStatus) + { + case ReplyStatus.replyUnknownException: + { + s.write("(unknown exception)"); + break; + } + + case ReplyStatus.replyUnknownLocalException: + { + s.write("(unknown local exception)"); + break; + } + + case ReplyStatus.replyUnknownUserException: + { + s.write("(unknown user exception)"); + break; + } + + default: + { + assert(false); + break; + } + } + + String unknown = str.readString(); + s.write("\nunknown = " + unknown); + break; + } + + default: + { + s.write("(unknown)"); + break; + } + } + + if(replyStatus == ReplyStatus.replyOK || replyStatus == ReplyStatus.replyUserException) + { + Ice.EncodingVersion v = str.skipEncapsulation(); + if(!v.equals(Ice.Util.Encoding_1_0)) + { + s.write("\nencoding = "); + s.write(Ice.Util.encodingVersionToString(v)); + } + } + } + + private static void + printRequestHeader(java.io.Writer out, Ice.InputStream stream) + { + printIdentityFacetOperation(out, stream); + + try + { + byte mode = stream.readByte(); + out.write("\nmode = " + (int) mode + ' '); + switch(Ice.OperationMode.values()[mode]) + { + case Normal: + { + out.write("(normal)"); + break; + } + + case Nonmutating: + { + out.write("(nonmutating)"); + break; + } + + case Idempotent: + { + out.write("(idempotent)"); + break; + } + + default: + { + out.write("(unknown)"); + break; + } + } + + int sz = stream.readSize(); + out.write("\ncontext = "); + while(sz-- > 0) + { + String key = stream.readString(); + String value = stream.readString(); + out.write(key + '/' + value); + if(sz > 0) + { + out.write(", "); + } + } + + Ice.EncodingVersion v = stream.skipEncapsulation(); + if(!v.equals(Ice.Util.Encoding_1_0)) + { + out.write("\nencoding = "); + out.write(Ice.Util.encodingVersionToString(v)); + } + } + catch(java.io.IOException ex) + { + assert(false); + } + } + + private static byte + printHeader(java.io.Writer out, Ice.InputStream stream) + { + stream.readByte(); // Don't bother printing the magic number + stream.readByte(); + stream.readByte(); + stream.readByte(); + +// byte pMajor = stream.readByte(); +// byte pMinor = stream.readByte(); +// out.write("\nprotocol version = " + (int)pMajor + "." + (int)pMinor); + stream.readByte(); // major + stream.readByte(); // minor + +// byte eMajor = stream.readByte(); +// byte eMinor = stream.readByte(); +// out.write("\nencoding version = " + (int)eMajor + "." + (int)eMinor); + stream.readByte(); // major + stream.readByte(); // minor + + byte type = stream.readByte(); + + try + { + out.write("\nmessage type = " + (int)type + " (" + getMessageTypeAsString(type) + ')'); + byte compress = stream.readByte(); + out.write("\ncompression status = " + (int)compress + ' '); + switch(compress) + { + case (byte)0: + { + out.write("(not compressed; do not compress response, if any)"); + break; + } + + case (byte)1: + { + out.write("(not compressed; compress response, if any)"); + break; + } + + case (byte)2: + { + out.write("(compressed; compress response, if any)"); + break; + } + + default: + { + out.write("(unknown)"); + break; + } + } + + int size = stream.readInt(); + out.write("\nmessage size = " + size); + return type; + } + catch(java.io.IOException ex) + { + assert(false); + return 0; + } + } + + static private byte + printMessage(java.io.StringWriter s, Ice.InputStream str) + { + byte type = printHeader(s, str); + + switch(type) + { + case Protocol.closeConnectionMsg: + case Protocol.validateConnectionMsg: + { + // We're done. + break; + } + + case Protocol.requestMsg: + { + printRequest(s, str); + break; + } + + case Protocol.requestBatchMsg: + { + printBatchRequest(s, str); + break; + } + + case Protocol.replyMsg: + { + printReply(s, str); + break; + } + + default: + { + break; + } + } + + return type; + } + + static private String + getMessageTypeAsString(byte type) + { + switch(type) + { + case Protocol.requestMsg: + return "request"; + case Protocol.requestBatchMsg: + return "batch request"; + case Protocol.replyMsg: + return "reply"; + case Protocol.closeConnectionMsg: + return "close connection"; + case Protocol.validateConnectionMsg: + return "validate connection"; + default: + return "unknown"; + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Transceiver.java b/java-compat/src/Ice/src/main/java/IceInternal/Transceiver.java new file mode 100644 index 00000000000..c62c00984b6 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Transceiver.java @@ -0,0 +1,32 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface Transceiver +{ + java.nio.channels.SelectableChannel fd(); + void setReadyCallback(ReadyCallback callback); + + int initialize(Buffer readBuffer, Buffer writeBuffer); + int closing(boolean initiator, Ice.LocalException ex); + void close(); + + EndpointI bind(); + int write(Buffer buf); + int read(Buffer buf); + + String protocol(); + @Override + String toString(); + String toDetailedString(); + Ice.ConnectionInfo getInfo(); + void checkSendSize(Buffer buf); + void setBufferSize(int rcvSize, int sndSize); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/TwowayCallback.java b/java-compat/src/Ice/src/main/java/IceInternal/TwowayCallback.java new file mode 100644 index 00000000000..713f965d848 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/TwowayCallback.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public abstract class TwowayCallback extends CallbackBase implements Ice.TwowayCallback +{ + public void sent(boolean sentSynchronously) + { + } + + @Override + public void exception(Ice.SystemException __ex) + { + exception(new Ice.UnknownException(__ex)); + } + + @Override + public final void __sent(Ice.AsyncResult __result) + { + sent(__result.sentSynchronously()); + } + + @Override + public final boolean __hasSentCallback() + { + return true; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/UdpConnector.java b/java-compat/src/Ice/src/main/java/IceInternal/UdpConnector.java new file mode 100644 index 00000000000..ad91ec7fba2 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/UdpConnector.java @@ -0,0 +1,113 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class UdpConnector implements Connector +{ + @Override + public Transceiver connect() + { + return new UdpTransceiver(_instance, _addr, _sourceAddr, _mcastInterface, _mcastTtl); + } + + public java.nio.channels.SelectableChannel fd() + { + assert(false); // Shouldn't be called, startConnect always completes immediately. + return null; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String toString() + { + return Network.addrToString(_addr); + } + + @Override + public int hashCode() + { + return _hashCode; + } + + // + // Only for use by UdpEndpointI + // + UdpConnector(ProtocolInstance instance, java.net.InetSocketAddress addr, java.net.InetSocketAddress sourceAddr, + String mcastInterface, int mcastTtl, String connectionId) + { + _instance = instance; + _addr = addr; + _sourceAddr = sourceAddr; + _mcastInterface = mcastInterface; + _mcastTtl = mcastTtl; + _connectionId = connectionId; + + _hashCode = 5381; + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _addr.getAddress().getHostAddress()); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _addr.getPort()); + if(_sourceAddr != null) + { + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _sourceAddr.getAddress().getHostAddress()); + } + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _mcastInterface); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _mcastTtl); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _connectionId); + } + + @Override + public boolean equals(java.lang.Object obj) + { + if(!(obj instanceof UdpConnector)) + { + return false; + } + + if(this == obj) + { + return true; + } + + UdpConnector p = (UdpConnector)obj; + if(!_connectionId.equals(p._connectionId)) + { + return false; + } + + if(_mcastTtl != p._mcastTtl) + { + return false; + } + + if(_mcastInterface.compareTo(p._mcastInterface) != 0) + { + return false; + } + + if(Network.compareAddress(_sourceAddr, p._sourceAddr) != 0) + { + return false; + } + + return Network.compareAddress(_addr, p._addr) == 0; + } + + private ProtocolInstance _instance; + private java.net.InetSocketAddress _addr; + private java.net.InetSocketAddress _sourceAddr; + private String _mcastInterface; + private int _mcastTtl; + private String _connectionId; + private int _hashCode; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/UdpEndpointFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/UdpEndpointFactory.java new file mode 100644 index 00000000000..6683b57dcb9 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/UdpEndpointFactory.java @@ -0,0 +1,58 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class UdpEndpointFactory implements EndpointFactory +{ + UdpEndpointFactory(ProtocolInstance instance) + { + _instance = instance; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) + { + IPEndpointI endpt = new UdpEndpointI(_instance); + endpt.initWithOptions(args, oaEndpoint); + return endpt; + } + + @Override + public EndpointI read(Ice.InputStream s) + { + return new UdpEndpointI(_instance, s); + } + + @Override + public void destroy() + { + _instance = null; + } + + @Override + public EndpointFactory clone(ProtocolInstance instance, EndpointFactory delegate) + { + return new UdpEndpointFactory(instance); + } + + private ProtocolInstance _instance; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/UdpEndpointI.java b/java-compat/src/Ice/src/main/java/IceInternal/UdpEndpointI.java new file mode 100644 index 00000000000..8c1d0bc837d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/UdpEndpointI.java @@ -0,0 +1,395 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class UdpEndpointI extends IPEndpointI +{ + public UdpEndpointI(ProtocolInstance instance, String ho, int po, java.net.InetSocketAddress sourceAddr, + String mcastInterface, int mttl, boolean conn, String conId, boolean co) + { + super(instance, ho, po, sourceAddr, conId); + _mcastInterface = mcastInterface; + _mcastTtl = mttl; + _connect = conn; + _compress = co; + } + + public UdpEndpointI(ProtocolInstance instance) + { + super(instance); + _connect = false; + _compress = false; + } + + public UdpEndpointI(ProtocolInstance instance, Ice.InputStream s) + { + super(instance, s); + if(s.getEncoding().equals(Ice.Util.Encoding_1_0)) + { + s.readByte(); + s.readByte(); + s.readByte(); + s.readByte(); + } + // Not transmitted. + //_connect = s.readBool(); + _connect = false; + _compress = s.readBool(); + } + + // + // Return the endpoint information. + // + @Override + public Ice.EndpointInfo getInfo() + { + Ice.UDPEndpointInfo info = new Ice.UDPEndpointInfo() + { + @Override + public short type() + { + return UdpEndpointI.this.type(); + } + + @Override + public boolean datagram() + { + return UdpEndpointI.this.datagram(); + } + + @Override + public boolean secure() + { + return UdpEndpointI.this.secure(); + } + }; + fillEndpointInfo(info); + return info; + } + + // + // Return the timeout for the endpoint in milliseconds. 0 means + // non-blocking, -1 means no timeout. + // + @Override + public int timeout() + { + return -1; + } + + // + // Return a new endpoint with a different timeout value, provided + // that timeouts are supported by the endpoint. Otherwise the same + // endpoint is returned. + // + @Override + public EndpointI timeout(int timeout) + { + return this; + } + + // + // Return true if the endpoints support bzip2 compress, or false + // otherwise. + // + @Override + public boolean compress() + { + return _compress; + } + + // + // Return a new endpoint with a different compression value, + // provided that compression is supported by the + // endpoint. Otherwise the same endpoint is returned. + // + @Override + public EndpointI compress(boolean compress) + { + if(compress == _compress) + { + return this; + } + else + { + return new UdpEndpointI(_instance, _host, _port, _sourceAddr, _mcastInterface, _mcastTtl, _connect, + _connectionId, compress); + } + } + + // + // Return true if the endpoint is datagram-based. + // + @Override + public boolean datagram() + { + return true; + } + + // + // Return a server side transceiver for this endpoint, or null if a + // transceiver can only be created by an acceptor. + // + @Override + public Transceiver transceiver() + { + return new UdpTransceiver(this, _instance, _host, _port, _mcastInterface, _connect); + } + + // + // Return an acceptor for this endpoint, or null if no acceptors + // is available. + // + @Override + public Acceptor acceptor(String adapterName) + { + return null; + } + + public UdpEndpointI endpoint(UdpTransceiver transceiver) + { + return new UdpEndpointI(_instance, _host, transceiver.effectivePort(), _sourceAddr, _mcastInterface,_mcastTtl, + _connect, _connectionId, _compress); + } + + // + // Convert the endpoint to its string form + // + @Override + public String options() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = super.options(); + + if(_mcastInterface.length() != 0) + { + s += " --interface " + _mcastInterface; + } + + if(_mcastTtl != -1) + { + s += " --ttl " + _mcastTtl; + } + + if(_connect) + { + s += " -c"; + } + + if(_compress) + { + s += " -z"; + } + + return s; + } + + @Override + public int compareTo(EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof UdpEndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + UdpEndpointI p = (UdpEndpointI)obj; + if(this == p) + { + return 0; + } + + if(!_connect && p._connect) + { + return -1; + } + else if(!p._connect && _connect) + { + return 1; + } + + if(!_compress && p._compress) + { + return -1; + } + else if(!p._compress && _compress) + { + return 1; + } + + if(_mcastTtl < p._mcastTtl) + { + return -1; + } + else if(p._mcastTtl < _mcastTtl) + { + return 1; + } + + int rc = _mcastInterface.compareTo(p._mcastInterface); + if(rc != 0) + { + return rc; + } + + return super.compareTo(obj); + } + + // + // Marshal the endpoint + // + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + super.streamWriteImpl(s); + if(s.getEncoding().equals(Ice.Util.Encoding_1_0)) + { + Ice.Util.Protocol_1_0.__write(s); + Ice.Util.Encoding_1_0.__write(s); + } + // Not transmitted. + //s.writeBool(_connect); + s.writeBool(_compress); + } + + @Override + public int hashInit(int h) + { + h = super.hashInit(h); + h = IceInternal.HashUtil.hashAdd(h, _mcastInterface); + h = IceInternal.HashUtil.hashAdd(h, _mcastTtl); + h = IceInternal.HashUtil.hashAdd(h, _connect); + h = IceInternal.HashUtil.hashAdd(h, _compress); + return h; + } + + @Override + public void fillEndpointInfo(Ice.IPEndpointInfo info) + { + super.fillEndpointInfo(info); + if(info instanceof Ice.UDPEndpointInfo) + { + Ice.UDPEndpointInfo udpInfo = (Ice.UDPEndpointInfo)info; + udpInfo.mcastInterface = _mcastInterface; + udpInfo.mcastTtl = _mcastTtl; + } + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + if(super.checkOption(option, argument, endpoint)) + { + return true; + } + + if(option.equals("-c")) + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -c option in " + endpoint); + } + + _connect = true; + } + else if(option.equals("-z")) + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -z option in " + endpoint); + } + + _compress = true; + } + else if(option.equals("-v") || option.equals("-e")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for " + option + " option in endpoint " + + endpoint); + } + + try + { + Ice.EncodingVersion v = Ice.Util.stringToEncodingVersion(argument); + if(v.major != 1 || v.minor != 0) + { + _instance.logger().warning("deprecated udp endpoint option: " + option); + } + } + catch(Ice.VersionParseException e) + { + throw new Ice.EndpointParseException("invalid version `" + argument + "' in endpoint " + + endpoint + ":\n" + e.str); + } + } + else if(option.equals("--ttl")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for --ttl option in endpoint " + endpoint); + } + + try + { + _mcastTtl = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid TTL value `" + argument + "' in endpoint " + endpoint); + } + + if(_mcastTtl < 0) + { + throw new Ice.EndpointParseException("TTL value `" + argument + "' out of range in endpoint " + + endpoint); + } + } + else if(option.equals("--interface")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for --interface option in endpoint " + + endpoint); + } + _mcastInterface = argument; + } + else + { + return false; + } + return true; + } + + @Override + protected Connector createConnector(java.net.InetSocketAddress addr, NetworkProxy proxy) + { + return new UdpConnector(_instance, addr, _sourceAddr, _mcastInterface, _mcastTtl, _connectionId); + } + + @Override + protected IPEndpointI createEndpoint(String host, int port, String connectionId) + { + return new UdpEndpointI(_instance, host, port, _sourceAddr, _mcastInterface,_mcastTtl, _connect, + connectionId, _compress); + } + + private String _mcastInterface = ""; + private int _mcastTtl = -1; + private boolean _connect; + private boolean _compress; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/UdpTransceiver.java b/java-compat/src/Ice/src/main/java/IceInternal/UdpTransceiver.java new file mode 100644 index 00000000000..1f4899f7bce --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/UdpTransceiver.java @@ -0,0 +1,653 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class UdpTransceiver implements Transceiver +{ + @Override + public java.nio.channels.SelectableChannel fd() + { + assert(_fd != null); + return _fd; + } + + @Override + public void setReadyCallback(ReadyCallback callback) + { + } + + @Override + public int initialize(Buffer readBuffer, Buffer writeBuffer) + { + // + // Nothing to do. + // + return SocketOperation.None; + } + + @Override + public int closing(boolean initiator, Ice.LocalException ex) + { + // + // Nothing to do. + // + return SocketOperation.None; + } + + @Override + public void close() + { + assert(_fd != null); + + try + { + _fd.close(); + } + catch(java.io.IOException ex) + { + } + _fd = null; + } + + @Override + public EndpointI bind() + { + if(_addr.getAddress().isMulticastAddress()) + { + Network.setReuseAddress(_fd, true); + _mcastAddr = _addr; + if(System.getProperty("os.name").startsWith("Windows") || + System.getProperty("java.vm.name").startsWith("OpenJDK")) + { + // + // Windows does not allow binding to the mcast address itself + // so we bind to INADDR_ANY (0.0.0.0) instead. As a result, + // bi-directional connection won't work because the source + // address won't be the multicast address and the client will + // therefore reject the datagram. + // + int protocol = + _mcastAddr.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : Network.EnableIPv6; + _addr = Network.getAddressForServer("", _port, protocol, _instance.preferIPv6()); + } + _addr = Network.doBind(_fd, _addr); + configureMulticast(_mcastAddr, _mcastInterface, -1); + + if(_port == 0) + { + _mcastAddr = new java.net.InetSocketAddress(_mcastAddr.getAddress(), _addr.getPort()); + } + } + else + { + if(!System.getProperty("os.name").startsWith("Windows")) + { + // + // Enable SO_REUSEADDR on Unix platforms to allow + // re-using the socket even if it's in the TIME_WAIT + // state. On Windows, this doesn't appear to be + // necessary and enabling SO_REUSEADDR would actually + // not be a good thing since it allows a second + // process to bind to an address even it's already + // bound by another process. + // + // TODO: using SO_EXCLUSIVEADDRUSE on Windows would + // probably be better but it's only supported by recent + // Windows versions (XP SP2, Windows Server 2003). + // + Network.setReuseAddress(_fd, true); + } + _addr = Network.doBind(_fd, _addr); + } + + _bound = true; + _endpoint = _endpoint.endpoint(this); + return _endpoint; + } + + @Override + public int write(Buffer buf) + { + if(!buf.b.hasRemaining()) + { + return SocketOperation.None; + } + + assert(buf.b.position() == 0); + assert(_fd != null && _state >= StateConnected); + + // The caller is supposed to check the send size before by calling checkSendSize + assert(java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size()); + + int ret = 0; + while(true) + { + try + { + if(_state == StateConnected) + { + ret = _fd.write(buf.b); + } + else + { + if(_peerAddr == null) + { + throw new Ice.SocketException(); // No peer has sent a datagram yet. + } + ret = _fd.send(buf.b, _peerAddr); + } + break; + } + catch(java.nio.channels.AsynchronousCloseException ex) + { + throw new Ice.ConnectionLostException(ex); + } + catch(java.net.PortUnreachableException ex) + { + throw new Ice.ConnectionLostException(ex); + } + catch(java.io.InterruptedIOException ex) + { + continue; + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + + if(ret == 0) + { + return SocketOperation.Write; + } + + assert(ret == buf.b.limit()); + buf.b.position(buf.b.limit()); + return SocketOperation.None; + } + + @Override + public int read(Buffer buf) + { + if(!buf.b.hasRemaining()) + { + return SocketOperation.None; + } + + assert(buf.b.position() == 0); + + final int packetSize = java.lang.Math.min(_maxPacketSize, _rcvSize - _udpOverhead); + buf.resize(packetSize, true); + buf.b.position(0); + + int ret = 0; + while(true) + { + try + { + java.net.SocketAddress peerAddr = _fd.receive(buf.b); + if(peerAddr == null || buf.b.position() == 0) + { + return SocketOperation.Read; + } + + _peerAddr = (java.net.InetSocketAddress)peerAddr; + ret = buf.b.position(); + break; + } + catch(java.nio.channels.AsynchronousCloseException ex) + { + throw new Ice.ConnectionLostException(ex); + } + catch(java.net.PortUnreachableException ex) + { + throw new Ice.ConnectionLostException(ex); + } + catch(java.io.InterruptedIOException ex) + { + continue; + } + catch(java.io.IOException ex) + { + throw new Ice.ConnectionLostException(ex); + } + } + + if(_state == StateNeedConnect) + { + // + // If we must connect, we connect to the first peer that sends us a packet. + // + Network.doConnect(_fd, _peerAddr, null); + _state = StateConnected; + + if(_instance.traceLevel() >= 1) + { + String s = "connected " + _instance.protocol() + " socket\n" + toString(); + _instance.logger().trace(_instance.traceCategory(), s); + } + } + + buf.resize(ret, true); + buf.b.position(ret); + + return SocketOperation.None; + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public String toString() + { + if(_fd == null) + { + return "<closed>"; + } + + String s; + if(_incoming && !_bound) + { + s = "local address = " + Network.addrToString(_addr); + } + else if(_state == StateNotConnected) + { + java.net.DatagramSocket socket = _fd.socket(); + s = "local address = " + Network.addrToString((java.net.InetSocketAddress)socket.getLocalSocketAddress()); + if(_peerAddr != null) + { + s += "\nremote address = " + Network.addrToString(_peerAddr); + } + } + else + { + s = Network.fdToString(_fd); + } + + if(_mcastAddr != null) + { + s += "\nmulticast address = " + Network.addrToString(_mcastAddr); + } + return s; + } + + @Override + public String toDetailedString() + { + StringBuilder s = new StringBuilder(toString()); + java.util.List<String> intfs = + Network.getHostsForEndpointExpand(_addr.getAddress().getHostAddress(), _instance.protocolSupport(), true); + if(!intfs.isEmpty()) + { + s.append("\nlocal interfaces = "); + s.append(IceUtilInternal.StringUtil.joinString(intfs, ", ")); + } + return s.toString(); + } + + @Override + public Ice.ConnectionInfo getInfo() + { + Ice.UDPConnectionInfo info = new Ice.UDPConnectionInfo(); + if(_fd != null) + { + java.net.DatagramSocket socket = _fd.socket(); + info.localAddress = socket.getLocalAddress().getHostAddress(); + info.localPort = socket.getLocalPort(); + if(_state == StateNotConnected) + { + if(_peerAddr != null) + { + info.remoteAddress = _peerAddr.getAddress().getHostAddress(); + info.remotePort = _peerAddr.getPort(); + } + } + else + { + if(socket.getInetAddress() != null) + { + info.remoteAddress = socket.getInetAddress().getHostAddress(); + info.remotePort = socket.getPort(); + } + } + if(!socket.isClosed()) + { + info.rcvSize = Network.getRecvBufferSize(_fd); + info.sndSize = Network.getSendBufferSize(_fd); + } + } + if(_mcastAddr != null) + { + info.mcastAddress = _mcastAddr.getAddress().getHostAddress(); + info.mcastPort = _mcastAddr.getPort(); + } + return info; + } + + @Override + public void checkSendSize(Buffer buf) + { + // + // The maximum packetSize is either the maximum allowable UDP packet size, or + // the UDP send buffer size (which ever is smaller). + // + final int packetSize = java.lang.Math.min(_maxPacketSize, _sndSize - _udpOverhead); + if(packetSize < buf.size()) + { + throw new Ice.DatagramLimitException(); + } + } + + @Override + public void setBufferSize(int rcvSize, int sndSize) + { + setBufSize(rcvSize, sndSize); + } + + public final int effectivePort() + { + return _addr.getPort(); + } + + // + // Only for use by UdpEndpoint + // + UdpTransceiver(ProtocolInstance instance, java.net.InetSocketAddress addr, java.net.InetSocketAddress sourceAddr, + String mcastInterface, int mcastTtl) + { + _instance = instance; + _state = StateNeedConnect; + _addr = addr; + + try + { + _fd = Network.createUdpSocket(_addr); + setBufSize(-1, -1); + Network.setBlock(_fd, false); + // + // NOTE: setting the multicast interface before performing the + // connect is important for some OS such as OS X. + // + if(_addr.getAddress().isMulticastAddress()) + { + configureMulticast(null, mcastInterface, mcastTtl); + } + Network.doConnect(_fd, _addr, sourceAddr); + _state = StateConnected; // We're connected now + } + catch(Ice.LocalException ex) + { + _fd = null; + throw ex; + } + } + + // + // Only for use by UdpEndpoint + // + UdpTransceiver(UdpEndpointI endpoint, ProtocolInstance instance, String host, int port, String mcastInterface, + boolean connect) + { + _endpoint = endpoint; + _instance = instance; + _state = connect ? StateNeedConnect : StateNotConnected; + _mcastInterface = mcastInterface; + _incoming = true; + _port = port; + + try + { + _addr = Network.getAddressForServer(host, port, instance.protocolSupport(), instance.preferIPv6()); + _fd = Network.createUdpSocket(_addr); + setBufSize(-1, -1); + Network.setBlock(_fd, false); + } + catch(Ice.LocalException ex) + { + _fd = null; + throw ex; + } + } + + private synchronized void setBufSize(int rcvSize, int sndSize) + { + assert(_fd != null); + + for(int i = 0; i < 2; ++i) + { + boolean isSnd; + String direction; + String prop; + int dfltSize; + int sizeRequested; + if(i == 0) + { + isSnd = false; + direction = "receive"; + prop = "Ice.UDP.RcvSize"; + dfltSize = Network.getRecvBufferSize(_fd); + sizeRequested = rcvSize; + _rcvSize = dfltSize; + } + else + { + isSnd = true; + direction = "send"; + prop = "Ice.UDP.SndSize"; + dfltSize = Network.getSendBufferSize(_fd); + sizeRequested = sndSize; + _sndSize = dfltSize; + } + + // + // Get property for buffer size if size not passed in. + // + if(sizeRequested == -1) + { + sizeRequested = _instance.properties().getPropertyAsIntWithDefault(prop, dfltSize); + } + // + // Check for sanity. + // + if(sizeRequested < (_udpOverhead + IceInternal.Protocol.headerSize)) + { + _instance.logger().warning("Invalid " + prop + " value of " + sizeRequested + " adjusted to " + + dfltSize); + sizeRequested = dfltSize; + } + + if(sizeRequested != dfltSize) + { + // + // Try to set the buffer size. The kernel will silently adjust + // the size to an acceptable value. Then read the size back to + // get the size that was actually set. + // + int sizeSet; + if(i == 0) + { + Network.setRecvBufferSize(_fd, sizeRequested); + _rcvSize = Network.getRecvBufferSize(_fd); + sizeSet = _rcvSize; + } + else + { + Network.setSendBufferSize(_fd, sizeRequested); + _sndSize = Network.getSendBufferSize(_fd); + sizeSet = _sndSize; + } + + // + // Warn if the size that was set is less than the requested size + // and we have not already warned + // + if(sizeSet < sizeRequested) + { + BufSizeWarnInfo winfo = _instance.getBufSizeWarn(Ice.UDPEndpointType.value); + if((isSnd && (!winfo.sndWarn || winfo.sndSize != sizeRequested)) || + (!isSnd && (!winfo.rcvWarn || winfo.rcvSize != sizeRequested))) + { + _instance.logger().warning("UDP " + direction + " buffer size: requested size of " + + sizeRequested + " adjusted to " + sizeSet); + + if(isSnd) + { + _instance.setSndBufSizeWarn(Ice.UDPEndpointType.value, sizeRequested); + } + else + { + _instance.setRcvBufSizeWarn(Ice.UDPEndpointType.value, sizeRequested); + } + } + } + } + } + } + + private void configureMulticast(java.net.InetSocketAddress group, String interfaceAddr, int ttl) + { + try + { + java.net.NetworkInterface intf = null; + + if(interfaceAddr.length() != 0) + { + intf = java.net.NetworkInterface.getByName(interfaceAddr); + if(intf == null) + { + try + { + intf = java.net.NetworkInterface.getByInetAddress( + java.net.InetAddress.getByName(interfaceAddr)); + } + catch(Exception ex) + { + } + } + } + + if(group != null) + { + // + // Join multicast group. + // + if(intf != null) + { + _fd.join(group.getAddress(), intf); + } + else + { + boolean join = false; + // + // If the user doesn't specify an interface, we join to the multicast group with every + // interface that supports multicast and has a configured address with the same protocol + // as the group address protocol. + // + int protocol = group.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : + Network.EnableIPv6; + + java.util.List<java.net.NetworkInterface> interfaces = + java.util.Collections.list(java.net.NetworkInterface.getNetworkInterfaces()); + for(java.net.NetworkInterface iface : interfaces) + { + boolean hasProtocolAddress = false; + java.util.List<java.net.InetAddress> addresses = + java.util.Collections.list(iface.getInetAddresses()); + for(java.net.InetAddress address : addresses) + { + if(address.getAddress().length == 4 && protocol == Network.EnableIPv4 || + address.getAddress().length != 4 && protocol == Network.EnableIPv6) + { + hasProtocolAddress = true; + break; + } + } + + if(hasProtocolAddress) + { + _fd.join(group.getAddress(), iface); + join = true; + } + } + + if(!join) + { + throw new Ice.SocketException(new IllegalArgumentException( + "There are no interfaces that are configured for the group protocol.\n" + + "Cannot join the multicast group.")); + } + } + } + else if(intf != null) + { + // + // Otherwise, set the multicast interface if specified. + // + _fd.setOption(java.net.StandardSocketOptions.IP_MULTICAST_IF, intf); + } + + if(ttl != -1) + { + _fd.setOption(java.net.StandardSocketOptions.IP_MULTICAST_TTL, ttl); + } + } + catch(Exception ex) + { + throw new Ice.SocketException(ex); + } + } + + @Override + protected synchronized void finalize() + throws Throwable + { + try + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + } + catch(java.lang.Exception ex) + { + } + finally + { + super.finalize(); + } + } + + private UdpEndpointI _endpoint = null; + private ProtocolInstance _instance; + + private int _state; + private int _rcvSize; + private int _sndSize; + private java.nio.channels.DatagramChannel _fd; + private java.net.InetSocketAddress _addr; + private java.net.InetSocketAddress _mcastAddr = null; + private String _mcastInterface; + private java.net.InetSocketAddress _peerAddr = null; + + private boolean _incoming = false; + private int _port = 0; + private boolean _bound = false; + + // + // The maximum IP datagram size is 65535. Subtract 20 bytes for the IP header and 8 bytes for the UDP header + // to get the maximum payload. + // + private final static int _udpOverhead = 20 + 8; + private final static int _maxPacketSize = 65535 - _udpOverhead; + + private static final int StateNeedConnect = 0; + private static final int StateConnected = 1; + private static final int StateNotConnected = 2; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/Util.java b/java-compat/src/Ice/src/main/java/IceInternal/Util.java new file mode 100644 index 00000000000..46920d5d04d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/Util.java @@ -0,0 +1,301 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.util.concurrent.ThreadFactory; + +public final class Util +{ + static String + createThreadName(final Ice.Properties properties, final String name) + { + String threadName = properties.getProperty("Ice.ProgramName"); + if(threadName.length() > 0) + { + threadName += "-"; + } + + threadName = threadName + name; + return threadName; + } + + static ThreadFactory + createThreadFactory(final Ice.Properties properties, final String name) + { + return new java.util.concurrent.ThreadFactory() + { + @Override + public Thread newThread(Runnable r) + { + Thread t = new Thread(r); + t.setName(name); + + if(properties.getProperty("Ice.ThreadPriority").length() > 0) + { + t.setPriority(Util.getThreadPriorityProperty(properties, "Ice")); + } + return t; + } + }; + } + + public static Instance + getInstance(Ice.Communicator communicator) + { + Ice.CommunicatorI p = (Ice.CommunicatorI)communicator; + return p.getInstance(); + } + + public static ProtocolPluginFacade + getProtocolPluginFacade(Ice.Communicator communicator) + { + return new ProtocolPluginFacadeI(communicator); + } + + // + // Given a path name, first try to open it as a class path resource (the path is + // treated as absolute). If that fails, fall back to the file system. Returns null + // if the file does not exist and raises IOException if an error occurs. + // + public static java.io.InputStream + openResource(ClassLoader cl, String path) + throws java.io.IOException + { + // + // Calling getResourceAsStream on the class loader means all paths are absolute, + // whereas calling it on the class means all paths are relative to the class + // unless the path has a leading forward slash. We call it on the class loader. + // + // getResourceAsStream returns null if the resource can't be found. + // + java.io.InputStream stream = null; + try + { + stream = cl.getResourceAsStream(path); + } + catch(IllegalArgumentException ex) + { + // + // With JDK-7 this can happen if the result url (base url + path) produces a + // malformed url for an URLClassLoader. For example the code in following + // comment will produce this exception under Windows. + // + // URLClassLoader cl = new URLClassLoader(new URL[] {new URL("http://localhost:8080/")}); + // java.io.InputStream in = IceInternal.Util.openResource(cl, "c:\\foo.txt"); + // + } + if(stream == null) + { + try + { + java.io.File f = new java.io.File(path); + if(f.exists()) + { + stream = new java.io.FileInputStream(f); + } + } + catch(java.lang.SecurityException ex) + { + // Ignore - a security manager may forbid access to the local file system. + } + } + + return stream; + } + + public static Class<?> + findClass(String className, ClassLoader cl) + throws LinkageError + { + // + // Try to load the class using the given class loader (if any). If that fails (or + // none is provided), we try to load the class a few more ways before giving up. + // + // Calling Class.forName() doesn't always work. For example, if Ice.jar is installed + // as an extension (in $JAVA_HOME/jre/lib/ext), calling Class.forName(name) uses the + // extension class loader, which will not look in CLASSPATH for the target class. + // + + Class<?> c = null; + + if(cl != null) + { + c = loadClass(className, cl); + } + + // + // Try using the current thread's class loader. + // + if(c == null) + { + try + { + cl = Thread.currentThread().getContextClassLoader(); + if(cl != null) + { + c = loadClass(className, cl); + } + } + catch(SecurityException ex) + { + } + } + + // + // Try using Class.forName(). + // + try + { + if(c == null) + { + c = Class.forName(className); + } + } + catch(ClassNotFoundException ex) + { + // Ignore + } + + // + // Fall back to the system class loader (which knows about CLASSPATH). + // + if(c == null) + { + try + { + cl = ClassLoader.getSystemClassLoader(); + if(cl != null) + { + c = loadClass(className, cl); + } + } + catch(SecurityException ex) + { + } + } + + return c; + } + + private static Class<?> + loadClass(String className, ClassLoader cl) + { + if(cl != null) + { + try + { + return cl.loadClass(className); + } + catch(ClassNotFoundException ex) + { + // Ignore + } + } + + return null; + } + + public static int + getThreadPriorityProperty(Ice.Properties properties, String prefix) + { + String pri = properties.getProperty(prefix + ".ThreadPriority"); + if(pri.equals("MIN_PRIORITY") || pri.equals("java.lang.Thread.MIN_PRIORITY")) + { + return java.lang.Thread.MIN_PRIORITY; + } + else if(pri.equals("NORM_PRIORITY") || pri.equals("java.lang.Thread.NORM_PRIORITY")) + { + return java.lang.Thread.NORM_PRIORITY; + } + else if(pri.equals("MAX_PRIORITY") || pri.equals("java.lang.Thread.MAX_PRIORITY")) + { + return java.lang.Thread.MAX_PRIORITY; + } + + try + { + return Integer.parseInt(pri); + } + catch(NumberFormatException ex) + { + } + return java.lang.Thread.NORM_PRIORITY; + } + + // + // Translate a Slice type id (such as "::Module::Type") into its equivalent + // Java class name (such as "Module.Type"). + // + public static String typeIdToClassName(String typeId) + { + if(!typeId.startsWith("::")) + { + return null; + } + + StringBuilder buf = new StringBuilder(typeId.length()); + + int start = 2; + boolean done = false; + while(!done) + { + int end = typeId.indexOf(':', start); + String s; + if(end != -1) + { + s = typeId.substring(start, end); + start = end + 2; + } + else + { + s = typeId.substring(start); + done = true; + } + if(buf.length() > 0) + { + buf.append('.'); + } + buf.append(fixKwd(s)); + } + + return buf.toString(); + } + + private static String fixKwd(String name) + { + // + // Keyword list. *Must* be kept in alphabetical order. Note that checkedCast and uncheckedCast + // are not Java keywords, but are in this list to prevent illegal code being generated if + // someone defines Slice operations with that name. + // + final String[] keywordList = + { + "abstract", "assert", "boolean", "break", "byte", "case", "catch", + "char", "checkedCast", "class", "clone", "const", "continue", "default", "do", + "double", "else", "enum", "equals", "extends", "false", "final", "finalize", + "finally", "float", "for", "getClass", "goto", "hashCode", "if", + "implements", "import", "instanceof", "int", "interface", "long", + "native", "new", "notify", "notifyAll", "null", "package", "private", + "protected", "public", "return", "short", "static", "strictfp", "super", "switch", + "synchronized", "this", "throw", "throws", "toString", "transient", + "true", "try", "uncheckedCast", "void", "volatile", "wait", "while" + }; + boolean found = java.util.Arrays.binarySearch(keywordList, name) >= 0; + return found ? "_" + name : name; + } + + // + // Return true if we're running on Android. + // + public static boolean isAndroid() + { + return System.getProperty("java.vm.name").startsWith("Dalvik"); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ValueFactoryManagerI.java b/java-compat/src/Ice/src/main/java/IceInternal/ValueFactoryManagerI.java new file mode 100644 index 00000000000..dfd51f0cbd5 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ValueFactoryManagerI.java @@ -0,0 +1,33 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class ValueFactoryManagerI implements Ice.ValueFactoryManager +{ + public synchronized void add(Ice.ValueFactory factory, String id) + { + Object o = _factoryMap.get(id); + if(o != null) + { + Ice.AlreadyRegisteredException ex = new Ice.AlreadyRegisteredException(); + ex.id = id; + ex.kindOfObject = "value factory"; + throw ex; + } + _factoryMap.put(id, factory); + } + + public synchronized Ice.ValueFactory find(String id) + { + return _factoryMap.get(id); + } + + private java.util.Map<String, Ice.ValueFactory> _factoryMap = new java.util.HashMap<String, Ice.ValueFactory>(); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/ValueWriter.java b/java-compat/src/Ice/src/main/java/IceInternal/ValueWriter.java new file mode 100644 index 00000000000..3184c250734 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/ValueWriter.java @@ -0,0 +1,191 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class ValueWriter +{ + public static void + write(java.lang.Object obj, IceUtilInternal.OutputBase out) + { + writeValue(null, obj, null, out); + } + + private static void + writeValue(String name, java.lang.Object value, java.util.Map<java.lang.Object, java.lang.Object> objectTable, + IceUtilInternal.OutputBase out) + { + if(value == null) + { + writeName(name, out); + out.print("(null)"); + } + else + { + Class<?> c = value.getClass(); + if(c.equals(Byte.class) || c.equals(Short.class) || c.equals(Integer.class) || c.equals(Long.class) || + c.equals(Double.class) || c.equals(Float.class) || c.equals(Boolean.class)) + { + writeName(name, out); + out.print(value.toString()); + } + else if(c.equals(String.class)) + { + // + // Indent the lines of a string value. + // + writeName(name, out); + out.print("\""); + out.useCurrentPosAsIndent(); + String str = value.toString(); + int start = 0, pos; + while(start < str.length() && (pos = str.indexOf('\n', start)) != -1) + { + out.print(str.substring(start, pos)); + out.nl(); + start = pos + 1; + } + if(start < str.length()) + { + out.print(str.substring(start)); + } + out.print("\""); + out.restoreIndent(); + } + else if(c.isArray()) + { + int n = java.lang.reflect.Array.getLength(value); + for(int i = 0; i < n; i++) + { + String elem = (name != null ? name : ""); + elem += "[" + i + "]"; + writeValue(elem, java.lang.reflect.Array.get(value, i), objectTable, out); + } + } + else if(value instanceof java.util.Map) + { + java.util.Map<?,?> map = (java.util.Map<?,?>)value; + java.util.Iterator<?> i = map.entrySet().iterator(); + while(i.hasNext()) + { + java.util.Map.Entry<?,?> entry = (java.util.Map.Entry<?,?>)i.next(); + String elem = (name != null ? name + "." : ""); + writeValue(elem + "key", entry.getKey(), objectTable, out); + writeValue(elem + "value", entry.getValue(), objectTable, out); + } + } + else if(value instanceof Ice.ObjectPrxHelperBase) + { + writeName(name, out); + Ice.ObjectPrxHelperBase proxy = (Ice.ObjectPrxHelperBase)value; + out.print(proxy.__reference().toString()); + } + else if(value instanceof Ice.Object) + { + // + // Check for recursion. + // + if(objectTable != null && objectTable.containsKey(value)) + { + writeName(name, out); + out.print("(recursive)"); + } + else + { + if(objectTable == null) + { + objectTable = new java.util.IdentityHashMap<java.lang.Object, java.lang.Object>(); + } + objectTable.put(value, null); + writeFields(name, value, c, objectTable, out); + } + } + else if(value instanceof java.lang.Enum) + { + writeName(name, out); + out.print(((java.lang.Enum<?>)value).name()); + } + else + { + // + // Must be struct. + // + writeFields(name, value, c, objectTable, out); + } + } + } + + private static void + writeFields(String name, java.lang.Object obj, Class<?> c, + java.util.Map<java.lang.Object, java.lang.Object> objectTable, IceUtilInternal.OutputBase out) + { + if(!c.equals(java.lang.Object.class)) + { + // + // Write the superclass first. + // + writeFields(name, obj, c.getSuperclass(), objectTable, out); + + // + // Write the declared fields of the given class. We prefer to use the declared + // fields because it includes protected fields that may have been defined using + // the Slice "protected" metadata. However, if a security manager prevents us + // from obtaining the declared fields, we will fall back to using the public ones. + // + java.lang.reflect.Field[] fields = null; + try + { + fields = c.getDeclaredFields(); + } + catch(java.lang.SecurityException ex) + { + try + { + fields = c.getFields(); + } + catch(java.lang.SecurityException e) + { + return; // Nothing else we can do. + } + } + assert(fields != null); + for(java.lang.reflect.Field field : fields) + { + // + // Only write public, non-static fields. + // + int mods = field.getModifiers(); + if(java.lang.reflect.Modifier.isPublic(mods) && !java.lang.reflect.Modifier.isStatic(mods)) + { + String fieldName = (name != null ? name + '.' + field.getName() : field.getName()); + + try + { + java.lang.Object value = field.get(obj); + writeValue(fieldName, value, objectTable, out); + } + catch(IllegalAccessException ex) + { + assert(false); + } + } + } + } + } + + private static void + writeName(String name, IceUtilInternal.OutputBase out) + { + if(name != null) + { + out.nl(); + out.print(name + " = "); + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/WSAcceptor.java b/java-compat/src/Ice/src/main/java/IceInternal/WSAcceptor.java new file mode 100644 index 00000000000..4b87907a671 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/WSAcceptor.java @@ -0,0 +1,82 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class WSAcceptor implements IceInternal.Acceptor +{ + @Override + public java.nio.channels.ServerSocketChannel fd() + { + return _delegate.fd(); + } + + @Override + public void setReadyCallback(ReadyCallback callback) + { + _delegate.setReadyCallback(callback); + } + + @Override + public void close() + { + _delegate.close(); + } + + @Override + public EndpointI listen() + { + _endpoint = _endpoint.endpoint(_delegate.listen()); + return _endpoint; + } + + @Override + public IceInternal.Transceiver accept() + { + // + // WebSocket handshaking is performed in TransceiverI::initialize, since + // accept must not block. + // + return new WSTransceiver(_instance, _delegate.accept()); + } + + @Override + public String protocol() + { + return _delegate.protocol(); + } + + @Override + public String toString() + { + return _delegate.toString(); + } + + @Override + public String toDetailedString() + { + return _delegate.toDetailedString(); + } + + public Acceptor delegate() + { + return _delegate; + } + + WSAcceptor(WSEndpoint endpoint, ProtocolInstance instance, IceInternal.Acceptor del) + { + _endpoint = endpoint; + _instance = instance; + _delegate = del; + } + + private WSEndpoint _endpoint; + private ProtocolInstance _instance; + private IceInternal.Acceptor _delegate; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/WSConnector.java b/java-compat/src/Ice/src/main/java/IceInternal/WSConnector.java new file mode 100644 index 00000000000..3c9ecc7e06b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/WSConnector.java @@ -0,0 +1,77 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class WSConnector implements Connector +{ + @Override + public Transceiver connect() + { + return new WSTransceiver(_instance, _delegate.connect(), _host, _resource); + } + + @Override + public short type() + { + return _delegate.type(); + } + + @Override + public String toString() + { + return _delegate.toString(); + } + + @Override + public int hashCode() + { + return _delegate.hashCode(); + } + + WSConnector(ProtocolInstance instance, Connector del, String host, String resource) + { + _instance = instance; + _delegate = del; + _host = host; + _resource = resource; + } + + @Override + public boolean equals(java.lang.Object obj) + { + if(!(obj instanceof WSConnector)) + { + return false; + } + + if(this == obj) + { + return true; + } + + WSConnector p = (WSConnector)obj; + if(!_delegate.equals(p._delegate)) + { + return false; + } + + if(!_resource.equals(p._resource)) + { + return false; + } + + return true; + } + + private ProtocolInstance _instance; + private Connector _delegate; + private String _host; + private String _resource; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/WSEndpoint.java b/java-compat/src/Ice/src/main/java/IceInternal/WSEndpoint.java new file mode 100644 index 00000000000..91ea36d1a62 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/WSEndpoint.java @@ -0,0 +1,324 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class WSEndpoint extends IceInternal.EndpointI +{ + public WSEndpoint(ProtocolInstance instance, EndpointI del, String res) + { + _instance = instance; + _delegate = del; + _resource = res; + } + + public WSEndpoint(ProtocolInstance instance, EndpointI del, java.util.ArrayList<String> args) + { + _instance = instance; + _delegate = del; + + initWithOptions(args); + + if(_resource == null) + { + _resource = "/"; + } + } + + public WSEndpoint(ProtocolInstance instance, EndpointI del, Ice.InputStream s) + { + _instance = instance; + _delegate = del; + _resource = s.readString(); + } + + @Override + public Ice.EndpointInfo getInfo() + { + Ice.WSEndpointInfo info = new Ice.WSEndpointInfo(_delegate.getInfo(), timeout(), compress(), _resource) + { + @Override + public short type() + { + return WSEndpoint.this.type(); + } + + @Override + public boolean datagram() + { + return WSEndpoint.this.datagram(); + } + + @Override + public boolean secure() + { + return WSEndpoint.this.secure(); + } + }; + info.compress = info.underlying.compress; + info.timeout = info.underlying.timeout; + return info; + } + + @Override + public short type() + { + return _delegate.type(); + } + + @Override + public String protocol() + { + return _delegate.protocol(); + } + + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + _delegate.streamWriteImpl(s); + s.writeString(_resource); + } + + @Override + public int timeout() + { + return _delegate.timeout(); + } + + @Override + public EndpointI timeout(int timeout) + { + if(timeout == _delegate.timeout()) + { + return this; + } + else + { + return new WSEndpoint(_instance, _delegate.timeout(timeout), _resource); + } + } + + @Override + public String connectionId() + { + return _delegate.connectionId(); + } + + @Override + public EndpointI connectionId(String connectionId) + { + if(connectionId.equals(_delegate.connectionId())) + { + return this; + } + else + { + return new WSEndpoint(_instance, _delegate.connectionId(connectionId), _resource); + } + } + + @Override + public boolean compress() + { + return _delegate.compress(); + } + + @Override + public EndpointI compress(boolean compress) + { + if(compress == _delegate.compress()) + { + return this; + } + else + { + return new WSEndpoint(_instance, _delegate.compress(compress), _resource); + } + } + + @Override + public boolean datagram() + { + return _delegate.datagram(); + } + + @Override + public boolean secure() + { + return _delegate.secure(); + } + + @Override + public Transceiver transceiver() + { + return null; + } + + @Override + public void connectors_async(Ice.EndpointSelectionType selType, final EndpointI_connectors callback) + { + Ice.IPEndpointInfo ipInfo = null; + for(Ice.EndpointInfo p = _delegate.getInfo(); p != null; p = p.underlying) + { + if(p instanceof Ice.IPEndpointInfo) + { + ipInfo = (Ice.IPEndpointInfo)p; + } + } + final String host = ipInfo != null ? (ipInfo.host + ":" + ipInfo.port) : ""; + EndpointI_connectors cb = new EndpointI_connectors() + { + @Override + public void connectors(java.util.List<Connector> connectors) + { + java.util.List<Connector> l = new java.util.ArrayList<Connector>(); + for(Connector c : connectors) + { + l.add(new WSConnector(_instance, c, host, _resource)); + } + callback.connectors(l); + } + + @Override + public void exception(Ice.LocalException ex) + { + callback.exception(ex); + } + }; + _delegate.connectors_async(selType, cb); + } + + @Override + public Acceptor acceptor(String adapterName) + { + Acceptor delAcc = _delegate.acceptor(adapterName); + return new WSAcceptor(this, _instance, delAcc); + } + + public WSEndpoint endpoint(EndpointI delEndp) + { + return new WSEndpoint(_instance, delEndp, _resource); + } + + @Override + public java.util.List<EndpointI> expand() + { + java.util.List<EndpointI> endps = _delegate.expand(); + java.util.List<EndpointI> l = new java.util.ArrayList<EndpointI>(); + for(EndpointI e : endps) + { + l.add(e == _delegate ? this : new WSEndpoint(_instance, e, _resource)); + } + return l; + } + + @Override + public boolean equivalent(EndpointI endpoint) + { + if(!(endpoint instanceof WSEndpoint)) + { + return false; + } + WSEndpoint wsEndpointI = (WSEndpoint)endpoint; + return _delegate.equivalent(wsEndpointI._delegate); + } + + @Override + synchronized public int hashCode() + { + int h = _delegate.hashCode(); + h = IceInternal.HashUtil.hashAdd(h, _resource); + return h; + } + + @Override + public String options() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = _delegate.options(); + + if(_resource != null && _resource.length() > 0) + { + s += " -r "; + boolean addQuote = _resource.indexOf(':') != -1; + if(addQuote) + { + s += "\""; + } + s += _resource; + if(addQuote) + { + s += "\""; + } + } + + return s; + } + + @Override + public int compareTo(EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof WSEndpoint)) + { + return type() < obj.type() ? -1 : 1; + } + + WSEndpoint p = (WSEndpoint)obj; + if(this == p) + { + return 0; + } + + int v = _resource.compareTo(p._resource); + if(v != 0) + { + return v; + } + + return _delegate.compareTo(p._delegate); + } + + public EndpointI delegate() + { + return _delegate; + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + switch(option.charAt(1)) + { + case 'r': + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -r option in endpoint " + endpoint + + _delegate.options()); + } + _resource = argument; + return true; + } + + default: + { + return false; + } + } + } + + private ProtocolInstance _instance; + private EndpointI _delegate; + private String _resource; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/WSEndpointFactory.java b/java-compat/src/Ice/src/main/java/IceInternal/WSEndpointFactory.java new file mode 100644 index 00000000000..493cddfd5eb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/WSEndpointFactory.java @@ -0,0 +1,59 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final public class WSEndpointFactory implements EndpointFactory +{ + public WSEndpointFactory(ProtocolInstance instance, EndpointFactory delegate) + { + _instance = instance; + _delegate = delegate; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) + { + return new WSEndpoint(_instance, _delegate.create(args, oaEndpoint), args); + } + + @Override + public EndpointI read(Ice.InputStream s) + { + return new WSEndpoint(_instance, _delegate.read(s), s); + } + + @Override + public void destroy() + { + _delegate.destroy(); + _instance = null; + } + + @Override + public EndpointFactory clone(ProtocolInstance instance, EndpointFactory delegate) + { + return new WSEndpointFactory(instance, delegate); + } + + private ProtocolInstance _instance; + private EndpointFactory _delegate; +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/WSTransceiver.java b/java-compat/src/Ice/src/main/java/IceInternal/WSTransceiver.java new file mode 100644 index 00000000000..8188ab322c8 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/WSTransceiver.java @@ -0,0 +1,1616 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +import java.security.*; + +final class WSTransceiver implements Transceiver +{ + @Override + public java.nio.channels.SelectableChannel fd() + { + return _delegate.fd(); + } + + @Override + public void setReadyCallback(ReadyCallback callback) + { + _readyCallback = callback; + _delegate.setReadyCallback(callback); + } + + @Override + public int initialize(Buffer readBuffer, Buffer writeBuffer) + { + // + // Delegate logs exceptions that occur during initialize(), so there's no need to trap them here. + // + if(_state == StateInitializeDelegate) + { + int op = _delegate.initialize(readBuffer, writeBuffer); + if(op != 0) + { + return op; + } + _state = StateConnected; + } + + try + { + if(_state == StateConnected) + { + // + // We don't know how much we'll need to read. + // + _readBuffer.resize(1024, true); + _readBuffer.b.position(0); + _readBufferPos = 0; + + // + // The server waits for the client's upgrade request, the + // client sends the upgrade request. + // + _state = StateUpgradeRequestPending; + if(!_incoming) + { + // + // Compose the upgrade request. + // + StringBuffer out = new StringBuffer(); + out.append("GET " + _resource + " HTTP/1.1\r\n"); + out.append("Host: " + _host); + out.append("\r\n"); + out.append("Upgrade: websocket\r\n"); + out.append("Connection: Upgrade\r\n"); + out.append("Sec-WebSocket-Protocol: " + _iceProtocol + "\r\n"); + out.append("Sec-WebSocket-Version: 13\r\n"); + out.append("Sec-WebSocket-Key: "); + + // + // The value for Sec-WebSocket-Key is a 16-byte random number, + // encoded with Base64. + // + byte[] key = new byte[16]; + _rand.nextBytes(key); + _key = IceUtilInternal.Base64.encode(key); + out.append(_key + "\r\n\r\n"); // EOM + + _writeBuffer.resize(out.length(), false); + _writeBuffer.b.position(0); + _writeBuffer.b.put(out.toString().getBytes(_ascii)); + _writeBuffer.b.flip(); + } + } + + // + // Try to write the client's upgrade request. + // + if(_state == StateUpgradeRequestPending && !_incoming) + { + if(_writeBuffer.b.hasRemaining()) + { + int s = _delegate.write(_writeBuffer); + if(s != 0) + { + return s; + } + } + assert(!_writeBuffer.b.hasRemaining()); + _state = StateUpgradeResponsePending; + } + + while(true) + { + if(_readBuffer.b.hasRemaining()) + { + int s = _delegate.read(_readBuffer); + if(s == SocketOperation.Write || _readBuffer.b.position() == 0) + { + return s; + } + } + + // + // Try to read the client's upgrade request or the server's response. + // + if((_state == StateUpgradeRequestPending && _incoming) || + (_state == StateUpgradeResponsePending && !_incoming)) + { + // + // Check if we have enough data for a complete message. + // + int p = _parser.isCompleteMessage(_readBuffer.b, 0, _readBuffer.b.position()); + if(p == -1) + { + if(_readBuffer.b.hasRemaining()) + { + return SocketOperation.Read; + } + + // + // Enlarge the buffer and try to read more. + // + final int oldSize = _readBuffer.b.position(); + if(oldSize + 1024 > _instance.messageSizeMax()) + { + throw new Ice.MemoryLimitException(); + } + _readBuffer.resize(oldSize + 1024, true); + _readBuffer.b.position(oldSize); + continue; // Try again to read the response/request + } + + // + // Set _readBufferPos at the end of the response/request message. + // + _readBufferPos = p; + } + + // + // We're done, the client's upgrade request or server's response is read. + // + break; + } + + try + { + // + // Parse the client's upgrade request. + // + if(_state == StateUpgradeRequestPending && _incoming) + { + if(_parser.parse(_readBuffer.b, 0, _readBufferPos)) + { + handleRequest(_writeBuffer); + _state = StateUpgradeResponsePending; + } + else + { + throw new Ice.ProtocolException("incomplete request message"); + } + } + + if(_state == StateUpgradeResponsePending) + { + if(_incoming) + { + if(_writeBuffer.b.hasRemaining()) + { + int s = _delegate.write(_writeBuffer); + if(s != 0) + { + return s; + } + } + } + else + { + // + // Parse the server's response + // + if(_parser.parse(_readBuffer.b, 0, _readBufferPos)) + { + handleResponse(); + } + else + { + throw new Ice.ProtocolException("incomplete response message"); + } + } + } + } + catch(WebSocketException ex) + { + throw new Ice.ProtocolException(ex.getMessage()); + } + + _state = StateOpened; + _nextState = StateOpened; + + if(_readBufferPos < _readBuffer.b.position()) + { + _readyCallback.ready(SocketOperation.Read, true); + } + } + catch(Ice.LocalException ex) + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), + protocol() + " connection HTTP upgrade request failed\n" + toString() + "\n" + ex); + } + throw ex; + } + + if(_instance.traceLevel() >= 1) + { + if(_incoming) + { + _instance.logger().trace(_instance.traceCategory(), + "accepted " + protocol() + " connection HTTP upgrade request\n" + toString()); + } + else + { + _instance.logger().trace(_instance.traceCategory(), + protocol() + " connection HTTP upgrade request accepted\n" + toString()); + } + } + + return SocketOperation.None; + } + + @Override + public int closing(boolean initiator, Ice.LocalException reason) + { + if(_instance.traceLevel() >= 1) + { + _instance.logger().trace(_instance.traceCategory(), + "gracefully closing " + protocol() + " connection\n" + toString()); + } + + int s = _nextState == StateOpened ? _state : _nextState; + + if(s == StateClosingRequestPending && _closingInitiator) + { + // + // If we initiated a close connection but also received a + // close connection, we assume we didn't initiated the + // connection and we send the close frame now. This is to + // ensure that if both peers close the connection at the same + // time we don't hang having both peer waiting for the close + // frame of the other. + // + assert(!initiator); + _closingInitiator = false; + return SocketOperation.Write; + } + else if(s >= StateClosingRequestPending) + { + return SocketOperation.None; + } + + _closingInitiator = initiator; + if(reason instanceof Ice.CloseConnectionException) + { + _closingReason = CLOSURE_NORMAL; + } + else if(reason instanceof Ice.ObjectAdapterDeactivatedException || + reason instanceof Ice.CommunicatorDestroyedException) + { + _closingReason = CLOSURE_SHUTDOWN; + } + else if(reason instanceof Ice.ProtocolException) + { + _closingReason = CLOSURE_PROTOCOL_ERROR; + } + else if(reason instanceof Ice.MemoryLimitException) + { + _closingReason = CLOSURE_TOO_BIG; + } + + if(_state == StateOpened) + { + _state = StateClosingRequestPending; + return initiator ? SocketOperation.Read : SocketOperation.Write; + } + else + { + _nextState = StateClosingRequestPending; + return SocketOperation.None; + } + } + + @Override + public void close() + { + _delegate.close(); + _state = StateClosed; + + // + // Clear the buffers now instead of waiting for destruction. + // + _writeBuffer.clear(); + _readBuffer.clear(); + } + + @Override + public EndpointI bind() + { + assert(false); + return null; + } + + @Override + public int write(Buffer buf) + { + if(_state < StateOpened) + { + if(_state < StateConnected) + { + return _delegate.write(buf); + } + else + { + return _delegate.write(_writeBuffer); + } + } + + int s = SocketOperation.None; + do + { + if(preWrite(buf)) + { + if(_writeState == WriteStateFlush) + { + // + // Invoke write() even though there's nothing to write. + // + assert(!buf.b.hasRemaining()); + s = _delegate.write(buf); + } + + if(s == SocketOperation.None && _writeBuffer.b.hasRemaining()) + { + s = _delegate.write(_writeBuffer); + } + else if(s == SocketOperation.None && _incoming && !buf.empty() && _writeState == WriteStatePayload) + { + s = _delegate.write(buf); + } + } + } + while(postWrite(buf, s)); + + if(s != SocketOperation.None) + { + return s; + } + if(_state == StateClosingResponsePending && !_closingInitiator) + { + return SocketOperation.Read; + } + return SocketOperation.None; + } + + @Override + public int read(Buffer buf) + { + if(_state < StateOpened) + { + if(_state < StateConnected) + { + return _delegate.read(buf); + } + else + { + if(_delegate.read(_readBuffer) == SocketOperation.Write) + { + return SocketOperation.Write; + } + else + { + return SocketOperation.None; + } + } + } + + if(!buf.b.hasRemaining()) + { + if(_readBufferPos < _readBuffer.b.position()) + { + _readyCallback.ready(SocketOperation.Read, true); + } + return SocketOperation.None; + } + + int s = SocketOperation.None; + do + { + if(preRead(buf)) + { + if(_readState == ReadStatePayload) + { + // + // If the payload length is smaller than what remains to be read, we read + // no more than the payload length. The remaining of the buffer will be + // sent over in another frame. + // + int readSz = _readPayloadLength - (buf.b.position() - _readStart); + if(buf.b.remaining() > readSz) + { + int size = buf.size(); + buf.resize(buf.b.position() + readSz, true); + s = _delegate.read(buf); + buf.resize(size, true); + } + else + { + s = _delegate.read(buf); + } + } + else + { + s = _delegate.read(_readBuffer); + } + + if(s == SocketOperation.Write) + { + postRead(buf); + return s; + } + } + } + while(postRead(buf)); + + if(!buf.b.hasRemaining()) + { + if(_readBufferPos < _readBuffer.b.position()) + { + _readyCallback.ready(SocketOperation.Read, true); + } + s = SocketOperation.None; + } + else + { + _readyCallback.ready(SocketOperation.Read, false); + s = SocketOperation.Read; + } + + if(((_state == StateClosingRequestPending && !_closingInitiator) || + (_state == StateClosingResponsePending && _closingInitiator) || + _state == StatePingPending || + _state == StatePongPending) && + _writeState == WriteStateHeader) + { + // We have things to write, ask to be notified when writes are ready. + s |= SocketOperation.Write; + } + + return s; + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public String toString() + { + return _delegate.toString(); + } + + @Override + public String toDetailedString() + { + return _delegate.toDetailedString(); + } + + @Override + public Ice.ConnectionInfo getInfo() + { + Ice.WSConnectionInfo info = new Ice.WSConnectionInfo(); + info.underlying = _delegate.getInfo(); + info.headers = _parser.getHeaders(); + return info; + } + + @Override + public void checkSendSize(Buffer buf) + { + _delegate.checkSendSize(buf); + } + + @Override + public void setBufferSize(int rcvSize, int sndSize) + { + _delegate.setBufferSize(rcvSize, sndSize); + } + + WSTransceiver(ProtocolInstance instance, Transceiver del, String host, String resource) + { + init(instance, del); + _host = host; + _resource = resource; + _incoming = false; + + // + // Use a 16KB write buffer size. We use 16KB for the write + // buffer size because all the data needs to be copied to the + // write buffer for the purpose of masking. A 16KB buffer + // appears to be a good compromise to reduce the number of + // socket write calls and not consume too much memory. + // + _writeBufferSize = 16 * 1024; + + // + // Write and read buffer size must be large enough to hold the frame header! + // + assert(_writeBufferSize > 256); + assert(_readBufferSize > 256); + } + + WSTransceiver(ProtocolInstance instance, Transceiver del) + { + init(instance, del); + _host = ""; + _resource = ""; + _incoming = true; + + // + // Write and read buffer size must be large enough to hold the frame header! + // + assert(_writeBufferSize > 256); + assert(_readBufferSize > 256); + } + + private void init(ProtocolInstance instance, Transceiver del) + { + _instance = instance; + _delegate = del; + _state = StateInitializeDelegate; + _parser = new HttpParser(); + _readState = ReadStateOpcode; + _readBuffer = new Buffer(false, java.nio.ByteOrder.BIG_ENDIAN); // Use network byte order. + _readBufferSize = 1024; + _readLastFrame = true; + _readOpCode = 0; + _readHeaderLength = 0; + _readPayloadLength = 0; + _readMask = new byte[4]; + _writeState = WriteStateHeader; + _writeBuffer = new Buffer(false, java.nio.ByteOrder.BIG_ENDIAN); // Use network byte order. + _writeBufferSize = 1024; + _readMask = new byte[4]; + _writeMask = new byte[4]; + _key = ""; + _pingPayload = new byte[0]; + _rand = new java.util.Random(); + } + + private void handleRequest(Buffer responseBuffer) + { + // + // HTTP/1.1 + // + if(_parser.versionMajor() != 1 || _parser.versionMinor() != 1) + { + throw new WebSocketException("unsupported HTTP version"); + } + + // + // "An |Upgrade| header field containing the value 'websocket', + // treated as an ASCII case-insensitive value." + // + String val = _parser.getHeader("Upgrade", true); + if(val == null) + { + throw new WebSocketException("missing value for Upgrade field"); + } + else if(!val.equals("websocket")) + { + throw new WebSocketException("invalid value `" + val + "' for Upgrade field"); + } + + // + // "A |Connection| header field that includes the token 'Upgrade', + // treated as an ASCII case-insensitive value. + // + val = _parser.getHeader("Connection", true); + if(val == null) + { + throw new WebSocketException("missing value for Connection field"); + } + else if(val.indexOf("upgrade") == -1) + { + throw new WebSocketException("invalid value `" + val + "' for Connection field"); + } + + // + // "A |Sec-WebSocket-Version| header field, with a value of 13." + // + val = _parser.getHeader("Sec-WebSocket-Version", false); + if(val == null) + { + throw new WebSocketException("missing value for WebSocket version"); + } + else if(!val.equals("13")) + { + throw new WebSocketException("unsupported WebSocket version `" + val + "'"); + } + + // + // "Optionally, a |Sec-WebSocket-Protocol| header field, with a list + // of values indicating which protocols the client would like to + // speak, ordered by preference." + // + boolean addProtocol = false; + val = _parser.getHeader("Sec-WebSocket-Protocol", true); + if(val != null) + { + String[] protocols = IceUtilInternal.StringUtil.splitString(val, ","); + if(protocols == null) + { + throw new WebSocketException("invalid value `" + val + "' for WebSocket protocol"); + } + for(String p : protocols) + { + if(!p.trim().equals(_iceProtocol)) + { + throw new WebSocketException("unknown value `" + p + "' for WebSocket protocol"); + } + addProtocol = true; + } + } + + // + // "A |Sec-WebSocket-Key| header field with a base64-encoded + // value that, when decoded, is 16 bytes in length." + // + String key = _parser.getHeader("Sec-WebSocket-Key", false); + if(key == null) + { + throw new WebSocketException("missing value for WebSocket key"); + } + + byte[] decodedKey = IceUtilInternal.Base64.decode(key); + if(decodedKey.length != 16) + { + throw new WebSocketException("invalid value `" + key + "' for WebSocket key"); + } + + // + // Retain the target resource. + // + _resource = _parser.uri(); + + // + // Compose the response. + // + StringBuffer out = new StringBuffer(); + out.append("HTTP/1.1 101 Switching Protocols\r\n"); + out.append("Upgrade: websocket\r\n"); + out.append("Connection: Upgrade\r\n"); + if(addProtocol) + { + out.append("Sec-WebSocket-Protocol: " + _iceProtocol + "\r\n"); + } + + // + // The response includes: + // + // "A |Sec-WebSocket-Accept| header field. The value of this + // header field is constructed by concatenating /key/, defined + // above in step 4 in Section 4.2.2, with the string "258EAFA5- + // E914-47DA-95CA-C5AB0DC85B11", taking the SHA-1 hash of this + // concatenated value to obtain a 20-byte value and base64- + // encoding (see Section 4 of [RFC4648]) this 20-byte hash. + // + out.append("Sec-WebSocket-Accept: "); + final String input = key + _wsUUID; + try + { + final MessageDigest sha1 = MessageDigest.getInstance("SHA1"); + sha1.update(input.getBytes(_ascii)); + final byte[] hash = sha1.digest(); + out.append(IceUtilInternal.Base64.encode(hash) + "\r\n" + "\r\n"); // EOM + } + catch(NoSuchAlgorithmException ex) + { + throw new WebSocketException(ex); + } + + final byte[] bytes = out.toString().getBytes(_ascii); + assert(bytes.length == out.length()); + responseBuffer.resize(bytes.length, false); + responseBuffer.b.position(0); + responseBuffer.b.put(bytes); + responseBuffer.b.flip(); + } + + private void handleResponse() + { + String val; + + // + // HTTP/1.1 + // + if(_parser.versionMajor() != 1 || _parser.versionMinor() != 1) + { + throw new WebSocketException("unsupported HTTP version"); + } + + // + // "If the status code received from the server is not 101, the + // client handles the response per HTTP [RFC2616] procedures. In + // particular, the client might perform authentication if it + // receives a 401 status code; the server might redirect the client + // using a 3xx status code (but clients are not required to follow + // them), etc." + // + if(_parser.status() != 101) + { + StringBuffer out = new StringBuffer("unexpected status value " + _parser.status()); + if(_parser.reason().length() > 0) + { + out.append(":\n" + _parser.reason()); + } + throw new WebSocketException(out.toString()); + } + + // + // "If the response lacks an |Upgrade| header field or the |Upgrade| + // header field contains a value that is not an ASCII case- + // insensitive match for the value "websocket", the client MUST + // _Fail the WebSocket Connection_." + // + val = _parser.getHeader("Upgrade", true); + if(val == null) + { + throw new WebSocketException("missing value for Upgrade field"); + } + else if(!val.equals("websocket")) + { + throw new WebSocketException("invalid value `" + val + "' for Upgrade field"); + } + + // + // "If the response lacks a |Connection| header field or the + // |Connection| header field doesn't contain a token that is an + // ASCII case-insensitive match for the value "Upgrade", the client + // MUST _Fail the WebSocket Connection_." + // + val = _parser.getHeader("Connection", true); + if(val == null) + { + throw new WebSocketException("missing value for Connection field"); + } + else if(val.indexOf("upgrade") == -1) + { + throw new WebSocketException("invalid value `" + val + "' for Connection field"); + } + + // + // "If the response includes a |Sec-WebSocket-Protocol| header field + // and this header field indicates the use of a subprotocol that was + // not present in the client's handshake (the server has indicated a + // subprotocol not requested by the client), the client MUST _Fail + // the WebSocket Connection_." + // + val = _parser.getHeader("Sec-WebSocket-Protocol", true); + if(val != null && !val.equals(_iceProtocol)) + { + throw new WebSocketException("invalid value `" + val + "' for WebSocket protocol"); + } + + // + // "If the response lacks a |Sec-WebSocket-Accept| header field or + // the |Sec-WebSocket-Accept| contains a value other than the + // base64-encoded SHA-1 of the concatenation of the |Sec-WebSocket- + // Key| (as a string, not base64-decoded) with the string "258EAFA5- + // E914-47DA-95CA-C5AB0DC85B11" but ignoring any leading and + // trailing whitespace, the client MUST _Fail the WebSocket + // Connection_." + // + val = _parser.getHeader("Sec-WebSocket-Accept", false); + if(val == null) + { + throw new WebSocketException("missing value for Sec-WebSocket-Accept"); + } + + try + { + final String input = _key + _wsUUID; + final MessageDigest sha1 = MessageDigest.getInstance("SHA1"); + sha1.update(input.getBytes(_ascii)); + if(!val.equals(IceUtilInternal.Base64.encode(sha1.digest()))) + { + throw new WebSocketException("invalid value `" + val + "' for Sec-WebSocket-Accept"); + } + } + catch(NoSuchAlgorithmException ex) + { + throw new WebSocketException(ex); + } + } + + private boolean preRead(Buffer buf) + { + while(true) + { + if(_readState == ReadStateOpcode) + { + // + // Is there enough data available to read the opcode? + // + if(!readBuffered(2)) + { + return true; + } + + // + // Most-significant bit indicates whether this is the + // last frame. Least-significant four bits hold the + // opcode. + // + int ch = _readBuffer.b.get(_readBufferPos++); + if(ch < 0) + { + ch += 256; + } + _readOpCode = ch & 0xf; + + // + // Remember if last frame if we're going to read a data or + // continuation frame, this is only for protocol + // correctness checking purpose. + // + if(_readOpCode == OP_DATA) + { + if(!_readLastFrame) + { + throw new Ice.ProtocolException("invalid data frame, no FIN on previous frame"); + } + _readLastFrame = (ch & FLAG_FINAL) == FLAG_FINAL; + } + else if(_readOpCode == OP_CONT) + { + if(_readLastFrame) + { + throw new Ice.ProtocolException("invalid continuation frame, previous frame FIN set"); + } + _readLastFrame = (ch & FLAG_FINAL) == FLAG_FINAL; + } + + ch = _readBuffer.b.get(_readBufferPos++); + if(ch < 0) + { + ch += 256; + } + + // + // Check the MASK bit. Messages sent by a client must be masked; + // messages sent by a server must not be masked. + // + final boolean masked = (ch & FLAG_MASKED) == FLAG_MASKED; + if(masked != _incoming) + { + throw new Ice.ProtocolException("invalid masking"); + } + + // + // Extract the payload length, which can have the following values: + // + // 0-125: The payload length + // 126: The subsequent two bytes contain the payload length + // 127: The subsequent eight bytes contain the payload length + // + _readPayloadLength = (ch & 0x7f); + if(_readPayloadLength < 126) + { + _readHeaderLength = 0; + } + else if(_readPayloadLength == 126) + { + _readHeaderLength = 2; // Need to read a 16-bit payload length. + } + else + { + _readHeaderLength = 8; // Need to read a 64-bit payload length. + } + if(masked) + { + _readHeaderLength += 4; // Need to read a 32-bit mask. + } + + _readState = ReadStateHeader; + } + + if(_readState == ReadStateHeader) + { + // + // Is there enough data available to read the header? + // + if(_readHeaderLength > 0 && !readBuffered(_readHeaderLength)) + { + return true; + } + + if(_readPayloadLength == 126) + { + _readPayloadLength = _readBuffer.b.getShort(_readBufferPos); // Uses network byte order. + if(_readPayloadLength < 0) + { + _readPayloadLength += 65536; + } + _readBufferPos += 2; + } + else if(_readPayloadLength == 127) + { + long l = _readBuffer.b.getLong(_readBufferPos); // Uses network byte order. + _readBufferPos += 8; + if(l < 0 || l > Integer.MAX_VALUE) + { + throw new Ice.ProtocolException("invalid WebSocket payload length: " + l); + } + _readPayloadLength = (int)l; + } + + // + // Read the mask if this is an incoming connection. + // + if(_incoming) + { + assert(_readBuffer.b.position() - _readBufferPos >= 4); // We must have needed to read the mask. + for(int i = 0; i < 4; ++i) + { + _readMask[i] = _readBuffer.b.get(_readBufferPos++); // Copy the mask. + } + } + + switch(_readOpCode) + { + case OP_TEXT: // Text frame + { + throw new Ice.ProtocolException("text frames not supported"); + } + case OP_CONT: // Continuation frame + case OP_DATA: // Data frame + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), "received " + protocol() + + (_readOpCode == OP_DATA ? " data" : " continuation") + + " frame with payload length of " + _readPayloadLength + " bytes\n" + + toString()); + } + + if(_readPayloadLength <= 0) + { + throw new Ice.ProtocolException("payload length is 0"); + } + _readState = ReadStatePayload; + assert(buf.b.hasRemaining()); + _readFrameStart = buf.b.position(); + break; + } + case OP_CLOSE: // Connection close + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), "received " + protocol() + + " connection close frame\n" + toString()); + } + + int s = _nextState == StateOpened ? _state : _nextState; + if(s == StateClosingRequestPending) + { + // + // If we receive a close frame while we were actually + // waiting to send one, change the role and send a + // close frame response. + // + if(!_closingInitiator) + { + _closingInitiator = true; + } + if(_state == StateClosingRequestPending) + { + _state = StateClosingResponsePending; + } + else + { + _nextState = StateClosingResponsePending; + } + return false; // No longer interested in reading + } + else + { + throw new Ice.ConnectionLostException(); + } + } + case OP_PING: + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), + "received " + protocol() + " connection ping frame\n" + toString()); + } + _readState = ReadStateControlFrame; + break; + } + case OP_PONG: // Pong + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), + "received " + protocol() + " connection pong frame\n" + toString()); + } + _readState = ReadStateControlFrame; + break; + } + default: + { + throw new Ice.ProtocolException("unsupported opcode: " + _readOpCode); + } + } + } + + if(_readState == ReadStateControlFrame) + { + if(_readPayloadLength > 0 && !readBuffered(_readPayloadLength)) + { + return true; + } + + if(_readPayloadLength > 0 && _readOpCode == OP_PING) + { + _pingPayload = new byte[_readPayloadLength]; + if(_readBuffer.b.hasArray()) + { + System.arraycopy(_readBuffer.b.array(), _readBuffer.b.arrayOffset() + _readBufferPos, + _pingPayload, 0, _readPayloadLength); + } + else + { + for(int i = 0; i < _readPayloadLength; ++i) + { + _pingPayload[i] = _readBuffer.b.get(_readBufferPos + i); + } + } + } + + _readBufferPos += _readPayloadLength; + _readPayloadLength = 0; + + if(_readOpCode == OP_PING) + { + if(_state == StateOpened) + { + _state = StatePongPending; // Send pong frame now + } + else if(_nextState < StatePongPending) + { + _nextState = StatePongPending; // Send pong frame next + } + } + + // + // We've read the payload of the PING/PONG frame, we're ready + // to read a new frame. + // + _readState = ReadStateOpcode; + } + + if(_readState == ReadStatePayload) + { + // + // This must be assigned before the check for the buffer. If the buffer is empty + // or already read, postRead will return false. + // + _readStart = buf.b.position(); + + if(buf.empty() || !buf.b.hasRemaining()) + { + return false; + } + + int n = Math.min(_readBuffer.b.position() - _readBufferPos, buf.b.remaining()); + if(n > _readPayloadLength) + { + n = _readPayloadLength; + } + if(n > 0) + { + if(buf.b.hasArray() && _readBuffer.b.hasArray()) + { + System.arraycopy(_readBuffer.b.array(), _readBuffer.b.arrayOffset() + _readBufferPos, + buf.b.array(), buf.b.arrayOffset() + buf.b.position(), n); + buf.b.position(buf.b.position() + n); + } + else + { + for(int i = 0; i < n; ++i) + { + buf.b.put(_readBuffer.b.get(_readBufferPos + i)); + } + } + _readBufferPos += n; + } + + // + // Continue reading if we didn't read the full message or there's more payload data to read. + // + return buf.b.hasRemaining() && n < _readPayloadLength; + } + } + } + + private boolean postRead(Buffer buf) + { + if(_readState != ReadStatePayload) + { + return _readStart < _readBuffer.b.position(); // Returns true if data was read. + } + + if(_readStart == buf.b.position()) + { + return false; // Nothing was read or nothing to read. + } + assert(_readStart < buf.b.position()); + + if(_incoming) + { + // + // Unmask the data we just read. + // + final int pos = buf.b.position(); + if(buf.b.hasArray()) + { + byte[] arr = buf.b.array(); + int offset = buf.b.arrayOffset(); + for(int n = _readStart; n < pos; ++n) + { + arr[n + offset] = (byte)(arr[n + offset] ^ _readMask[(n - _readFrameStart) % 4]); + } + } + else + { + for(int n = _readStart; n < pos; ++n) + { + final byte b = (byte)(buf.b.get(n) ^ _readMask[(n - _readFrameStart) % 4]); + buf.b.put(n, b); + } + } + } + + _readPayloadLength -= buf.b.position() - _readStart; + _readStart = buf.b.position(); + if(_readPayloadLength == 0) + { + // + // We've read the complete payload, we're ready to read a new frame. + // + _readState = ReadStateOpcode; + } + return buf.b.hasRemaining(); + } + + private boolean preWrite(Buffer buf) + { + if(_writeState == WriteStateHeader) + { + if(_state == StateOpened) + { + if(buf.empty() || !buf.b.hasRemaining()) + { + return false; + } + + assert(buf.b.position() == 0); + prepareWriteHeader((byte)OP_DATA, buf.size()); + + _writeState = WriteStatePayload; + } + else if(_state == StatePingPending) + { + prepareWriteHeader((byte)OP_PING, 0); // Don't send any payload + + _writeState = WriteStateControlFrame; + _writeBuffer.b.flip(); + } + else if(_state == StatePongPending) + { + prepareWriteHeader((byte)OP_PONG, _pingPayload.length); + if(_pingPayload.length > _writeBuffer.b.remaining()) + { + final int pos = _writeBuffer.b.position(); + _writeBuffer.resize(pos + _pingPayload.length, false); + _writeBuffer.b.position(pos); + } + _writeBuffer.b.put(_pingPayload); + _pingPayload = new byte[0]; + + _writeState = WriteStateControlFrame; + _writeBuffer.b.flip(); + } + else if((_state == StateClosingRequestPending && !_closingInitiator) || + (_state == StateClosingResponsePending && _closingInitiator)) + { + prepareWriteHeader((byte)OP_CLOSE, 2); + + // Write closing reason + _writeBuffer.b.putShort((short)_closingReason); + + if(!_incoming) + { + byte b; + int pos = _writeBuffer.b.position() - 2; + b = (byte)(_writeBuffer.b.get(pos) ^ _writeMask[0]); + _writeBuffer.b.put(pos, b); + pos++; + b = (byte)(_writeBuffer.b.get(pos) ^ _writeMask[1]); + _writeBuffer.b.put(pos, b); + } + + _writeState = WriteStateControlFrame; + _writeBuffer.b.flip(); + } + else + { + assert(_state != StateClosed); + return false; // Nothing to write in this state + } + + _writePayloadLength = 0; + } + + if(_writeState == WriteStatePayload) + { + // + // For an outgoing connection, each message must be masked with a random + // 32-bit value, so we copy the entire message into the internal buffer + // for writing. For incoming connections, we just copy the start of the + // message in the internal buffer after the hedaer. If the message is + // larger, the reminder is sent directly from the message buffer to avoid + // copying. + // + + if(!_incoming && (_writePayloadLength == 0 || !_writeBuffer.b.hasRemaining())) + { + if(!_writeBuffer.b.hasRemaining()) + { + _writeBuffer.b.position(0); + } + + int n = buf.b.position(); + final int sz = buf.size(); + if(buf.b.hasArray() && _writeBuffer.b.hasArray()) + { + int pos = _writeBuffer.b.position(); + final int count = Math.min(sz - n, _writeBuffer.b.remaining()); + final byte[] src = buf.b.array(); + final int srcOff = buf.b.arrayOffset(); + final byte[] dest = _writeBuffer.b.array(); + final int destOff = _writeBuffer.b.arrayOffset(); + for(int i = 0; i < count; ++i, ++n, ++pos) + { + dest[destOff + pos] = (byte)(src[srcOff + n] ^ _writeMask[n % 4]); + } + _writeBuffer.b.position(pos); + } + else + { + for(; n < sz && _writeBuffer.b.hasRemaining(); ++n) + { + final byte b = (byte)(buf.b.get(n) ^ _writeMask[n % 4]); + _writeBuffer.b.put(b); + } + } + _writePayloadLength = n; + _writeBuffer.b.flip(); + } + else if(_writePayloadLength == 0) + { + assert(_incoming); + if(_writeBuffer.b.hasRemaining()) + { + assert(buf.b.position() == 0); + int n = _writeBuffer.b.remaining(); + if(buf.b.remaining() > n) + { + int limit = buf.b.limit(); + buf.b.limit(n); + _writeBuffer.b.put(buf.b); + buf.b.limit(limit); + _writePayloadLength = n; + } + else + { + _writePayloadLength = buf.b.remaining(); + _writeBuffer.b.put(buf.b); + } + buf.b.position(0); + } + _writeBuffer.b.flip(); + } + return true; + } + else if(_writeState == WriteStateControlFrame) + { + return _writeBuffer.b.hasRemaining(); + } + else + { + assert(_writeState == WriteStateFlush); + return true; + } + } + + private boolean postWrite(Buffer buf, int status) + { + if(_state > StateOpened && _writeState == WriteStateControlFrame) + { + if(!_writeBuffer.b.hasRemaining()) + { + if(_state == StatePingPending) + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), + "sent " + protocol() + " connection ping frame\n" + toString()); + } + } + else if(_state == StatePongPending) + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), + "sent " + protocol() + " connection pong frame\n" + toString()); + } + } + else if((_state == StateClosingRequestPending && !_closingInitiator) || + (_state == StateClosingResponsePending && _closingInitiator)) + { + if(_instance.traceLevel() >= 2) + { + _instance.logger().trace(_instance.traceCategory(), + "sent " + protocol() + " connection close frame\n" + toString()); + } + + if(_state == StateClosingRequestPending && !_closingInitiator) + { + _writeState = WriteStateHeader; + _state = StateClosingResponsePending; + return false; + } + else + { + throw new Ice.ConnectionLostException(); + } + } + else if(_state == StateClosed) + { + return false; + } + + _state = _nextState; + _nextState = StateOpened; + _writeState = WriteStateHeader; + } + else + { + return status == SocketOperation.None; + } + } + + if((!_incoming || buf.b.position() == 0) && _writePayloadLength > 0) + { + if(!_writeBuffer.b.hasRemaining()) + { + buf.b.position(_writePayloadLength); + } + } + + if(status == SocketOperation.Write && !buf.b.hasRemaining() && !_writeBuffer.b.hasRemaining()) + { + // + // Our buffers are empty but the delegate needs another call to write(). + // + _writeState = WriteStateFlush; + return false; + } + else if(!buf.b.hasRemaining()) + { + _writeState = WriteStateHeader; + if(_state == StatePingPending || + _state == StatePongPending || + (_state == StateClosingRequestPending && !_closingInitiator) || + (_state == StateClosingResponsePending && _closingInitiator)) + { + return true; + } + } + else if(_state == StateOpened) + { + return status == SocketOperation.None; + } + + return false; + } + + private boolean readBuffered(int sz) + { + if(_readBufferPos == _readBuffer.b.position()) + { + _readBuffer.resize(_readBufferSize, true); + _readBufferPos = 0; + _readBuffer.b.position(0); + } + else + { + final int available = _readBuffer.b.position() - _readBufferPos; + if(available < sz) + { + if(_readBufferPos > 0) + { + _readBuffer.b.limit(_readBuffer.b.position()); + _readBuffer.b.position(_readBufferPos); + _readBuffer.b.compact(); + assert(_readBuffer.b.position() == available); + } + _readBuffer.resize(Math.max(_readBufferSize, sz), true); + _readBufferPos = 0; + _readBuffer.b.position(available); + } + } + + _readStart = _readBuffer.b.position(); + if(_readBufferPos + sz > _readBuffer.b.position()) + { + return false; // Not enough read. + } + assert(_readBuffer.b.position() > _readBufferPos); + return true; + } + + private void prepareWriteHeader(byte opCode, int payloadLength) + { + // + // We need to prepare the frame header. + // + _writeBuffer.resize(_writeBufferSize, false); + _writeBuffer.b.limit(_writeBufferSize); + _writeBuffer.b.position(0); + + // + // Set the opcode - this is the one and only data frame. + // + _writeBuffer.b.put((byte)(opCode | FLAG_FINAL)); + + // + // Set the payload length. + // + if(payloadLength <= 125) + { + _writeBuffer.b.put((byte)payloadLength); + } + else if(payloadLength > 125 && payloadLength <= 65535) + { + // + // Use an extra 16 bits to encode the payload length. + // + _writeBuffer.b.put((byte)126); + _writeBuffer.b.putShort((short)payloadLength); + } + else if(payloadLength > 65535) + { + // + // Use an extra 64 bits to encode the payload length. + // + _writeBuffer.b.put((byte)127); + _writeBuffer.b.putLong(payloadLength); + } + + if(!_incoming) + { + // + // Add a random 32-bit mask to every outgoing frame, copy the payload data, + // and apply the mask. + // + _writeBuffer.b.put(1, (byte)(_writeBuffer.b.get(1) | FLAG_MASKED)); + _rand.nextBytes(_writeMask); + _writeBuffer.b.put(_writeMask); + } + } + + private ProtocolInstance _instance; + private Transceiver _delegate; + private String _host; + private String _resource; + private boolean _incoming; + private ReadyCallback _readyCallback; + + private static final int StateInitializeDelegate = 0; + private static final int StateConnected = 1; + private static final int StateUpgradeRequestPending = 2; + private static final int StateUpgradeResponsePending = 3; + private static final int StateOpened = 4; + private static final int StatePingPending = 5; + private static final int StatePongPending = 6; + private static final int StateClosingRequestPending = 7; + private static final int StateClosingResponsePending = 8; + private static final int StateClosed = 9; + + private int _state; + private int _nextState; + + private HttpParser _parser; + private String _key; + + private static final int ReadStateOpcode = 0; + private static final int ReadStateHeader = 1; + private static final int ReadStateControlFrame = 2; + private static final int ReadStatePayload = 3; + + private int _readState; + private Buffer _readBuffer; + private int _readBufferPos; + private int _readBufferSize; + + private boolean _readLastFrame; + private int _readOpCode; + private int _readHeaderLength; + private int _readPayloadLength; + private int _readStart; + private int _readFrameStart; + private byte[] _readMask; + + private static final int WriteStateHeader = 0; + private static final int WriteStatePayload = 1; + private static final int WriteStateControlFrame = 2; + private static final int WriteStateFlush = 3; + + private int _writeState; + private Buffer _writeBuffer; + private int _writeBufferSize; + private byte[] _writeMask; + private int _writePayloadLength; + + private boolean _closingInitiator; + private int _closingReason; + + private byte[] _pingPayload; + + private java.util.Random _rand; + + // + // WebSocket opcodes + // + final static private int OP_CONT = 0x0; // Continuation frame + final static private int OP_TEXT = 0x1; // Text frame + final static private int OP_DATA = 0x2; // Data frame + @SuppressWarnings("unused") + final static private int OP_RES_0x3 = 0x3; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0x4 = 0x4; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0x5 = 0x5; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0x6 = 0x6; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0x7 = 0x7; // Reserved + final static private int OP_CLOSE = 0x8; // Connection close + final static private int OP_PING = 0x9; // Ping + final static private int OP_PONG = 0xA; // Pong + @SuppressWarnings("unused") + final static private int OP_RES_0xB = 0xB; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0xC = 0xC; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0xD = 0xD; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0xE = 0xE; // Reserved + @SuppressWarnings("unused") + final static private int OP_RES_0xF = 0xF; // Reserved + final static private int FLAG_FINAL = 0x80; // Last frame + final static private int FLAG_MASKED = 0x80; // Payload is masked + + final static private int CLOSURE_NORMAL = 1000; + final static private int CLOSURE_SHUTDOWN = 1001; + final static private int CLOSURE_PROTOCOL_ERROR = 1002; + final static private int CLOSURE_TOO_BIG = 1009; + + final static private String _iceProtocol = "ice.zeroc.com"; + final static private String _wsUUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + + final static java.nio.charset.Charset _ascii = java.nio.charset.Charset.forName("US-ASCII"); +} diff --git a/java-compat/src/Ice/src/main/java/IceInternal/WebSocketException.java b/java-compat/src/Ice/src/main/java/IceInternal/WebSocketException.java new file mode 100644 index 00000000000..cee046461cb --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceInternal/WebSocketException.java @@ -0,0 +1,28 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +final class WebSocketException extends java.lang.RuntimeException +{ + public WebSocketException(String reason) + { + super(reason); + } + + public WebSocketException(String reason, Throwable cause) + { + super(reason, cause); + } + + public WebSocketException(Throwable cause) + { + super(cause); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceMX/MetricsHelper.java b/java-compat/src/Ice/src/main/java/IceMX/MetricsHelper.java new file mode 100644 index 00000000000..84dfc57d19f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceMX/MetricsHelper.java @@ -0,0 +1,188 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceMX; + +public class MetricsHelper<T> +{ + public static class AttributeResolver + { + private abstract class Resolver + { + abstract Object resolve(Object obj) throws Exception; + + String resolveImpl(Object obj) + { + try + { + Object result = resolve(obj); + if(result != null) + { + return result.toString(); + } + return ""; + } + catch(IllegalArgumentException ex) + { + throw ex; + } + catch(Exception ex) + { + ex.printStackTrace(); + assert(false); + return null; + } + } + } + + protected + AttributeResolver() + { + } + + public String + resolve(MetricsHelper<?> helper, String attribute) + { + Resolver resolver = _attributes.get(attribute); + if(resolver == null) + { + if(attribute.equals("none")) + { + return ""; + } + String v = helper.defaultResolve(attribute); + if(v != null) + { + return v; + } + throw new IllegalArgumentException(attribute); + } + return resolver.resolveImpl(helper); + } + + public void + add(final String name, final java.lang.reflect.Method method) + { + _attributes.put(name, new Resolver() + { + @Override + public Object + resolve(Object obj) throws Exception + { + return method.invoke(obj); + } + }); + } + + public void + add(final String name, final java.lang.reflect.Field field) + { + _attributes.put(name, new Resolver() + { + @Override + public Object + resolve(Object obj) throws Exception + { + return getField(name, field, obj); + } + }); + } + + public void + add(final String name, final java.lang.reflect.Method method, final java.lang.reflect.Field field) + { + _attributes.put(name, new Resolver() + { + @Override + public Object + resolve(Object obj) throws Exception + { + return getField(name, field, method.invoke(obj)); + } + }); + } + + public void + add(final String name, final java.lang.reflect.Method method, final java.lang.reflect.Method subMethod) + { + _attributes.put(name, new Resolver() + { + @Override + public Object + resolve(Object obj) throws Exception + { + Object o = method.invoke(obj); + if(o != null) + { + return subMethod.invoke(o); + } + throw new IllegalArgumentException(name); + } + }); + } + + private Object getField(String name, java.lang.reflect.Field field, Object o) + throws IllegalArgumentException, IllegalAccessException + { + while(o != null) + { + try + { + return field.get(o); + } + catch(IllegalArgumentException ex) + { + // If we're dealing with an endpoint/connection information class, + // check if the field is from the underlying info objects. + if(o instanceof Ice.EndpointInfo) + { + o = ((Ice.EndpointInfo)o).underlying; + } + else if(o instanceof Ice.ConnectionInfo) + { + o = ((Ice.ConnectionInfo)o).underlying; + } + else + { + throw ex; + } + } + } + throw new IllegalArgumentException(name); + } + + private java.util.Map<String, Resolver> _attributes = new java.util.HashMap<String, Resolver>(); + } + + protected + MetricsHelper(AttributeResolver attributes) + { + _attributes = attributes; + } + + public String + resolve(String attribute) + { + return _attributes.resolve(this, attribute); + } + + public void + initMetrics(T metrics) + { + // Override in specialized helpers. + } + + protected String + defaultResolve(String attribute) + { + return null; + } + + private AttributeResolver _attributes; +} diff --git a/java-compat/src/Ice/src/main/java/IceMX/Observer.java b/java-compat/src/Ice/src/main/java/IceMX/Observer.java new file mode 100644 index 00000000000..deec790deff --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceMX/Observer.java @@ -0,0 +1,136 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceMX; + +import IceInternal.MetricsMap; + +public class Observer<T extends Metrics> extends IceUtilInternal.StopWatch implements Ice.Instrumentation.Observer +{ + public interface MetricsUpdate<T> + { + void update(T m); + } + + @Override + public void + attach() + { + if(!isStarted()) + { + start(); + } + } + + @Override + public void + detach() + { + long lifetime = _previousDelay + stop(); + for(MetricsMap<T>.Entry e : _objects) + { + e.detach(lifetime); + } + } + + @Override + public void + failed(String exceptionName) + { + for(MetricsMap<T>.Entry e : _objects) + { + e.failed(exceptionName); + } + } + + public void + forEach(MetricsUpdate<T> u) + { + for(MetricsMap<T>.Entry e : _objects) + { + e.execute(u); + } + } + + public void + init(MetricsHelper<T> helper, java.util.List<MetricsMap<T>.Entry> objects, Observer<T> previous) + { + _objects = objects; + + if(previous == null) + { + return; + } + + _previousDelay = previous._previousDelay + previous.delay(); + + // + // Detach entries from previous observer which are no longer + // attached to this new observer. + // + for(MetricsMap<T>.Entry p : previous._objects) + { + if(!_objects.contains(p)) + { + p.detach(_previousDelay); + } + } + } + + public <S extends Metrics, ObserverImpl extends Observer<S>> ObserverImpl + getObserver(String mapName, MetricsHelper<S> helper, Class<S> mcl, Class<ObserverImpl> ocl) + { + java.util.List<MetricsMap<S>.Entry> metricsObjects = null; + for(MetricsMap<T>.Entry entry : _objects) + { + MetricsMap<S>.Entry e = entry.getMatching(mapName, helper, mcl); + if(e != null) + { + if(metricsObjects == null) + { + metricsObjects = new java.util.ArrayList<MetricsMap<S>.Entry>(_objects.size()); + } + metricsObjects.add(e); + } + } + + if(metricsObjects == null) + { + return null; + } + + try + { + ObserverImpl obsv = ocl.newInstance(); + obsv.init(helper, metricsObjects, null); + return obsv; + } + catch(Exception ex) + { + assert(false); + return null; + } + } + + public MetricsMap<T>.Entry + getEntry(MetricsMap<?> map) + { + for(MetricsMap<T>.Entry e : _objects) + { + if(e.getMap() == map) + { + return e; + } + } + return null; + } + + private java.util.List<MetricsMap<T>.Entry> _objects; + private long _previousDelay = 0; +} diff --git a/java-compat/src/Ice/src/main/java/IceMX/ObserverFactory.java b/java-compat/src/Ice/src/main/java/IceMX/ObserverFactory.java new file mode 100644 index 00000000000..ca06b0a8c00 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceMX/ObserverFactory.java @@ -0,0 +1,142 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceMX; + +import IceInternal.MetricsMap; + +public class ObserverFactory<T extends Metrics, O extends Observer<T>> +{ + public + ObserverFactory(IceInternal.MetricsAdminI metrics, String name, Class<T> cl) + { + _metrics = metrics; + _name = name; + _class = cl; + _metrics.registerMap(name, _class, new Runnable() + { + @Override + public void + run() + { + update(); + } + }); + } + + public void + destroy() + { + if(_metrics != null) + { + _metrics.unregisterMap(_name); + } + } + + public O + getObserver(MetricsHelper<T> helper, Class<O> cl) + { + return getObserver(helper, null, cl); + } + + @SuppressWarnings("unchecked") + public synchronized O + getObserver(MetricsHelper<T> helper, Object observer, Class<O> cl) + { + O old = null; + try + { + old = (O)observer; + } + catch(ClassCastException ex) + { + } + java.util.List<MetricsMap<T>.Entry> metricsObjects = null; + for(MetricsMap<T> m : _maps) + { + MetricsMap<T>.Entry e = m.getMatching(helper, old != null ? old.getEntry(m) : null); + if(e != null) + { + if(metricsObjects == null) + { + metricsObjects = new java.util.ArrayList<MetricsMap<T>.Entry>(_maps.size()); + } + metricsObjects.add(e); + } + } + + if(metricsObjects == null) + { + if(old != null) + { + old.detach(); + } + return null; + } + + O obsv; + try + { + obsv = cl.newInstance(); + } + catch(Exception ex) + { + assert(false); + return null; + } + obsv.init(helper, metricsObjects, old); + return obsv; + } + + public <S extends IceMX.Metrics> void + registerSubMap(String subMap, Class<S> cl, java.lang.reflect.Field field) + { + _metrics.registerSubMap(_name, subMap, cl, field); + } + + public boolean + isEnabled() + { + return _enabled; + } + + public void + update() + { + Runnable updater; + synchronized(this) + { + _maps.clear(); + for(MetricsMap<T> m : _metrics.getMaps(_name, _class)) + { + _maps.add(m); + } + _enabled = !_maps.isEmpty(); + updater = _updater; + } + + if(updater != null) + { + updater.run(); + } + } + + public synchronized void + setUpdater(Runnable updater) + { + _updater = updater; + } + + private final IceInternal.MetricsAdminI _metrics; + private final String _name; + private final Class<T> _class; + private java.util.List<MetricsMap<T>> _maps = new java.util.ArrayList<MetricsMap<T>>(); + private volatile boolean _enabled; + private Runnable _updater; +} diff --git a/java-compat/src/Ice/src/main/java/IceMX/ObserverFactoryWithDelegate.java b/java-compat/src/Ice/src/main/java/IceMX/ObserverFactoryWithDelegate.java new file mode 100644 index 00000000000..9e0e01c2949 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceMX/ObserverFactoryWithDelegate.java @@ -0,0 +1,48 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceMX; + +public class ObserverFactoryWithDelegate<T extends Metrics, + OImpl extends ObserverWithDelegate<T, O>, + O extends Ice.Instrumentation.Observer> + extends ObserverFactory<T, OImpl> +{ + public + ObserverFactoryWithDelegate(IceInternal.MetricsAdminI metrics, String name, Class<T> cl) + { + super(metrics, name, cl); + } + + @SuppressWarnings("unchecked") + public O + getObserver(MetricsHelper<T> helper, Class<OImpl> cl, O delegate) + { + OImpl o = super.getObserver(helper, cl); + if(o != null) + { + o.setDelegate(delegate); + return (O)o; + } + return delegate; + } + + @SuppressWarnings("unchecked") + public O + getObserver(MetricsHelper<T> helper, Object observer, Class<OImpl> cl, O delegate) + { + OImpl o = super.getObserver(helper, observer, cl); + if(o != null) + { + o.setDelegate(delegate); + return (O)o; + } + return delegate; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceMX/ObserverWithDelegate.java b/java-compat/src/Ice/src/main/java/IceMX/ObserverWithDelegate.java new file mode 100644 index 00000000000..94b09bb9821 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceMX/ObserverWithDelegate.java @@ -0,0 +1,74 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceMX; + +public class ObserverWithDelegate<T extends Metrics, O extends Ice.Instrumentation.Observer> extends Observer<T> +{ + @Override + public void + attach() + { + super.attach(); + if(_delegate != null) + { + _delegate.attach(); + } + } + + @Override + public void + detach() + { + super.detach(); + if(_delegate != null) + { + _delegate.detach(); + } + } + + @Override + public void + failed(String exceptionName) + { + super.failed(exceptionName); + if(_delegate != null) + { + _delegate.failed(exceptionName); + } + } + + public O + getDelegate() + { + return _delegate; + } + + public void + setDelegate(O del) + { + _delegate = del; + } + + @SuppressWarnings("unchecked") + public <S extends Metrics, ObserverImpl extends ObserverWithDelegate<S, Obs>, + Obs extends Ice.Instrumentation.Observer> Obs + getObserver(String mapName, MetricsHelper<S> helper, Class<S> mcl, Class<ObserverImpl> ocl, Obs delegate) + { + ObserverImpl obsv = super.getObserver(mapName, helper, mcl, ocl); + if(obsv != null) + { + obsv.setDelegate(delegate); + return (Obs)obsv; + } + return delegate; + } + + protected O _delegate; +} diff --git a/java-compat/src/Ice/src/main/java/IceMX/ObserverWithDelegateI.java b/java-compat/src/Ice/src/main/java/IceMX/ObserverWithDelegateI.java new file mode 100644 index 00000000000..f146b9f9780 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceMX/ObserverWithDelegateI.java @@ -0,0 +1,14 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceMX; + +public class ObserverWithDelegateI extends ObserverWithDelegate<Metrics, Ice.Instrumentation.Observer> +{ +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/AcceptorI.java b/java-compat/src/Ice/src/main/java/IceSSL/AcceptorI.java new file mode 100644 index 00000000000..bf21888839e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/AcceptorI.java @@ -0,0 +1,85 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +final class AcceptorI implements IceInternal.Acceptor +{ + @Override + public java.nio.channels.ServerSocketChannel fd() + { + return _delegate.fd(); + } + + @Override + public void setReadyCallback(IceInternal.ReadyCallback callback) + { + _delegate.setReadyCallback(callback); + } + + @Override + public void close() + { + _delegate.close(); + } + + @Override + public IceInternal.EndpointI listen() + { + _endpoint = _endpoint.endpoint(_delegate.listen()); + return _endpoint; + } + + @Override + public IceInternal.Transceiver accept() + { + // + // The plug-in may not be fully initialized. + // + if(!_instance.initialized()) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plug-in is not initialized"; + throw ex; + } + + return new TransceiverI(_instance, _delegate.accept(), _adapterName, true); + } + + @Override + public String protocol() + { + return _delegate.protocol(); + } + + @Override + public String toString() + { + return _delegate.toString(); + } + + @Override + public String toDetailedString() + { + return _delegate.toDetailedString(); + } + + AcceptorI(EndpointI endpoint, Instance instance, IceInternal.Acceptor delegate, String adapterName) + { + _endpoint = endpoint; + _instance = instance; + _delegate = delegate; + _adapterName = adapterName; + } + + private EndpointI _endpoint; + private Instance _instance; + private IceInternal.Acceptor _delegate; + private String _adapterName; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/CertificateVerifier.java b/java-compat/src/Ice/src/main/java/IceSSL/CertificateVerifier.java new file mode 100644 index 00000000000..4aaa6b91f11 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/CertificateVerifier.java @@ -0,0 +1,26 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +/** + * An application can customize the certificate verification process + * by implementing the CertificateVerifier interface. + **/ +public interface CertificateVerifier +{ + /** + * Determines whether a connection should be accepted or rejected. + * + * @param info The details of the connection. + * @return <code>true</code> if the connection should be accepted; + * <code>false</code>, otherwise. + **/ + boolean verify(NativeConnectionInfo info); +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/ConnectorI.java b/java-compat/src/Ice/src/main/java/IceSSL/ConnectorI.java new file mode 100644 index 00000000000..d463a89bf3d --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/ConnectorI.java @@ -0,0 +1,78 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +final class ConnectorI implements IceInternal.Connector +{ + @Override + public IceInternal.Transceiver connect() + { + // + // The plug-in may not be fully initialized. + // + if(!_instance.initialized()) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plug-in is not initialized"; + throw ex; + } + + return new TransceiverI(_instance, _delegate.connect(), _host, false); + } + + @Override + public short type() + { + return _delegate.type(); + } + + @Override + public String toString() + { + return _delegate.toString(); + } + + @Override + public int hashCode() + { + return _delegate.hashCode(); + } + + // + // Only for use by EndpointI. + // + ConnectorI(Instance instance, IceInternal.Connector delegate, String host) + { + _instance = instance; + _delegate = delegate; + _host = host; + } + + @Override + public boolean equals(java.lang.Object obj) + { + if(!(obj instanceof ConnectorI)) + { + return false; + } + + if(this == obj) + { + return true; + } + + ConnectorI p = (ConnectorI)obj; + return p._delegate.equals(_delegate); + } + + private Instance _instance; + private IceInternal.Connector _delegate; + private String _host; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/EndpointFactoryI.java b/java-compat/src/Ice/src/main/java/IceSSL/EndpointFactoryI.java new file mode 100644 index 00000000000..ffe402c6193 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/EndpointFactoryI.java @@ -0,0 +1,60 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +final class EndpointFactoryI implements IceInternal.EndpointFactory +{ + EndpointFactoryI(Instance instance, IceInternal.EndpointFactory delegate) + { + _instance = instance; + _delegate = delegate; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public IceInternal.EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) + { + return new EndpointI(_instance, _delegate.create(args, oaEndpoint)); + } + + @Override + public IceInternal.EndpointI read(Ice.InputStream s) + { + return new EndpointI(_instance, _delegate.read(s)); + } + + @Override + public void destroy() + { + _delegate.destroy(); + _instance = null; + } + + @Override + public IceInternal.EndpointFactory clone(IceInternal.ProtocolInstance inst, IceInternal.EndpointFactory delegate) + { + Instance instance = new Instance(_instance.engine(), inst.type(), inst.protocol()); + return new EndpointFactoryI(instance, delegate != null ? delegate : _delegate.clone(instance, null)); + } + + private Instance _instance; + private IceInternal.EndpointFactory _delegate; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/EndpointI.java b/java-compat/src/Ice/src/main/java/IceSSL/EndpointI.java new file mode 100644 index 00000000000..08de48c2f11 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/EndpointI.java @@ -0,0 +1,260 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +final class EndpointI extends IceInternal.EndpointI +{ + public EndpointI(Instance instance, IceInternal.EndpointI delegate) + { + _instance = instance; + _delegate = delegate; + } + + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + _delegate.streamWriteImpl(s); + } + + // + // Return the endpoint information. + // + @Override + public Ice.EndpointInfo getInfo() + { + IceSSL.EndpointInfo info = new IceSSL.EndpointInfo(_delegate.getInfo(), timeout(), compress()) + { + @Override + public short type() + { + return EndpointI.this.type(); + } + + @Override + public boolean datagram() + { + return EndpointI.this.datagram(); + } + + @Override + public boolean secure() + { + return EndpointI.this.secure(); + } + }; + info.compress = info.underlying.compress; + info.timeout = info.underlying.timeout; + return info; + } + + @Override + public short type() + { + return _delegate.type(); + } + + @Override + public String protocol() + { + return _delegate.protocol(); + } + + @Override + public int timeout() + { + return _delegate.timeout(); + } + + @Override + public IceInternal.EndpointI timeout(int timeout) + { + if(timeout == _delegate.timeout()) + { + return this; + } + else + { + return new EndpointI(_instance, _delegate.timeout(timeout)); + } + } + + @Override + public String connectionId() + { + return _delegate.connectionId(); + } + + @Override + public IceInternal.EndpointI connectionId(String connectionId) + { + if(connectionId == _delegate.connectionId()) + { + return this; + } + else + { + return new EndpointI(_instance, _delegate.connectionId(connectionId)); + } + } + + @Override + public boolean compress() + { + return _delegate.compress(); + } + + @Override + public IceInternal.EndpointI compress(boolean compress) + { + if(compress == _delegate.compress()) + { + return this; + } + else + { + return new EndpointI(_instance, _delegate.compress(compress)); + } + } + + @Override + public boolean datagram() + { + return _delegate.datagram(); + } + + @Override + public boolean secure() + { + return _delegate.secure(); + } + + // + // Return a server side transceiver for this endpoint, or null if a + // transceiver can only be created by an acceptor. + // + @Override + public IceInternal.Transceiver transceiver() + { + return null; + } + + @Override + public void connectors_async(Ice.EndpointSelectionType selType, final IceInternal.EndpointI_connectors callback) + { + Ice.IPEndpointInfo ipInfo = null; + for(Ice.EndpointInfo p = _delegate.getInfo(); p != null; p = p.underlying) + { + if(p instanceof Ice.IPEndpointInfo) + { + ipInfo = (Ice.IPEndpointInfo)p; + } + } + final String host = ipInfo != null ? ipInfo.host : ""; + IceInternal.EndpointI_connectors cb = new IceInternal.EndpointI_connectors() + { + @Override + public void connectors(java.util.List<IceInternal.Connector> connectors) + { + java.util.List<IceInternal.Connector> l = new java.util.ArrayList<IceInternal.Connector>(); + for(IceInternal.Connector c : connectors) + { + l.add(new ConnectorI(_instance, c, host)); + } + callback.connectors(l); + } + + @Override + public void exception(Ice.LocalException ex) + { + callback.exception(ex); + } + }; + _delegate.connectors_async(selType, cb); + } + + // + // Return an acceptor for this endpoint, or null if no acceptors + // is available. + // + @Override + public IceInternal.Acceptor acceptor(String adapterName) + { + return new AcceptorI(this, _instance, _delegate.acceptor(adapterName), adapterName); + } + + public EndpointI endpoint(IceInternal.EndpointI delEndpt) + { + return new EndpointI(_instance, delEndpt); + } + + @Override + public java.util.List<IceInternal.EndpointI> expand() + { + java.util.List<IceInternal.EndpointI> endps = _delegate.expand(); + java.util.List<IceInternal.EndpointI> l = new java.util.ArrayList<IceInternal.EndpointI>(); + for(IceInternal.EndpointI e : endps) + { + l.add(e == _delegate ? this : new EndpointI(_instance, e)); + } + return l; + } + + @Override + public boolean equivalent(IceInternal.EndpointI endpoint) + { + if(!(endpoint instanceof EndpointI)) + { + return false; + } + EndpointI endpointI = (EndpointI)endpoint; + return _delegate.equivalent(endpointI._delegate); + } + + @Override + synchronized public int hashCode() + { + return _delegate.hashCode(); + } + + @Override + public String options() + { + return _delegate.options(); + } + + // + // Compare endpoints for sorting purposes + // + @Override + public int compareTo(IceInternal.EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof EndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + EndpointI p = (EndpointI)obj; + if(this == p) + { + return 0; + } + + return _delegate.compareTo(p._delegate); + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + return false; + } + + private Instance _instance; + private IceInternal.EndpointI _delegate; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/Instance.java b/java-compat/src/Ice/src/main/java/IceSSL/Instance.java new file mode 100644 index 00000000000..53ffac5c29f --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/Instance.java @@ -0,0 +1,62 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +class Instance extends IceInternal.ProtocolInstance +{ + Instance(SSLEngine engine, short type, String protocol) + { + super(engine.communicator(), type, protocol, true); + _engine = engine; + } + + SSLEngine engine() + { + return _engine; + } + + int securityTraceLevel() + { + return _engine.securityTraceLevel(); + } + + String securityTraceCategory() + { + return _engine.securityTraceCategory(); + } + + boolean initialized() + { + return _engine.initialized(); + } + + javax.net.ssl.SSLEngine createSSLEngine(boolean incoming, String host, int port) + { + return _engine.createSSLEngine(incoming, host, port); + } + + void traceConnection(String desc, javax.net.ssl.SSLEngine engine, boolean incoming) + { + _engine.traceConnection(desc, engine, incoming); + } + + void verifyPeer(String address, NativeConnectionInfo info, String desc) + { + _engine.verifyPeer(address, info, desc); + } + + void trustManagerFailure(boolean incoming, java.security.cert.CertificateException ex) + throws java.security.cert.CertificateException + { + _engine.trustManagerFailure(incoming, ex); + } + + private SSLEngine _engine; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/NativeConnectionInfo.java b/java-compat/src/Ice/src/main/java/IceSSL/NativeConnectionInfo.java new file mode 100644 index 00000000000..3e726309267 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/NativeConnectionInfo.java @@ -0,0 +1,28 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +/** + * + * This class is a native extension of the Slice local class + * IceSSL::ConnectionInfo. It provides access to the native Java + * certificates. + * + * @see CertificateVerifier + **/ +public class NativeConnectionInfo extends ConnectionInfo +{ + /** + * The certificate chain. This may be null if the peer did not + * supply a certificate. The peer's certificate (if any) is the + * first one in the chain. + **/ + public java.security.cert.Certificate[] nativeCerts; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/PasswordCallback.java b/java-compat/src/Ice/src/main/java/IceSSL/PasswordCallback.java new file mode 100644 index 00000000000..227b7c41361 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/PasswordCallback.java @@ -0,0 +1,45 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +/** + * A password callback is an alternate way to supply the plug-in with + * passwords; this avoids using plain text configuration properties. + **/ +public interface PasswordCallback +{ + /** + * Returns the password for the key. If an alias was selected + * by setting the <code>IceSSL.Alias</code> property, <code>alias</code> + * contains the property's value. + * + * @param alias The value of the property <code>IceSSL.Alias</code>, if that + * property is set; <code>null</code>, otherwise. + * @return The password for the key. The return value must not be <code>null</code>. + * + **/ + char[] getPassword(String alias); + + /** + * Returns the password for validating the truststore. + * + * @return The password. To skip truststore validation, + * return <code>null</code>. + **/ + char[] getTruststorePassword(); + + /** + * Returns the password for validating the keystore. + * + * @return The password. To skip keystore validation, + * return <code>null</code>. + **/ + char[] getKeystorePassword(); +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/Plugin.java b/java-compat/src/Ice/src/main/java/IceSSL/Plugin.java new file mode 100644 index 00000000000..7301c37ed6a --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/Plugin.java @@ -0,0 +1,94 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +/** + * Interface that allows applications to interact with the IceSSL plug-in. + **/ +public interface Plugin extends Ice.Plugin +{ + /** + * Establishes the SSL context. The context must be established before + * plug-in is initialized. Therefore, the application must set + * the property <code>Ice.InitPlugins</code> to zero, call + * <code>setContext</code> to set the context, and finally + * invoke {@link PluginManager#initializePlugins}. + * <p> + * If an application supplies its own SSL context, the + * plug-in skips its normal property-based configuration. + * + * @param context The SSL context for the plug-in. + **/ + void setContext(javax.net.ssl.SSLContext context); + + /** + * Returns the SSL context. Use caution when modifying the returned + * value: changes made to this value do not affect existing connections. + * + * @return The SSL context for the plug-in. + **/ + javax.net.ssl.SSLContext getContext(); + + /** + * Establishes the certificate verifier. This must be + * done before any connections are established. + * + * @param verifier The certificate verifier. + **/ + void setCertificateVerifier(CertificateVerifier verifier); + + /** + * Returns the certificate verifier. + * + * @return The certificate verifier (<code>null</code> if not set). + **/ + CertificateVerifier getCertificateVerifier(); + + /** + * Establishes the password callback. This must be + * done before the plug-in is initialized. + * + * @param callback The password callback. + **/ + void setPasswordCallback(PasswordCallback callback); + + /** + * Returns the password callback. + * + * @return The password callback (<code>null</code> if not set). + **/ + PasswordCallback getPasswordCallback(); + + /** + * Supplies an input stream for the keystore. Calling this method + * causes IceSSL to ignore the <code>IceSSL.Keystore</code> property. + * + * @param stream The input stream for the keystore. + **/ + void setKeystoreStream(java.io.InputStream stream); + + /** + * Supplies an input stream for the truststore. Calling this method + * causes IceSSL to ignore the <code>IceSSL.Truststore</code> property. It is + * legal to supply the same input stream as the one for {@link #setKeystoreStream}, + * in which case IceSSL uses the certificates contained in the keystore. + * + * @param stream The input stream for the truststore. + **/ + void setTruststoreStream(java.io.InputStream stream); + + /** + * Adds an input stream for the random number seed. You may call + * this method multiple times if necessary. + * + * @param stream The input stream for the random number seed. + **/ + void addSeedStream(java.io.InputStream stream); +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/PluginFactory.java b/java-compat/src/Ice/src/main/java/IceSSL/PluginFactory.java new file mode 100644 index 00000000000..cb8063fe148 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/PluginFactory.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +/** + * Plug-in factories must implement this interface. + **/ +public class PluginFactory implements Ice.PluginFactory +{ + /** + * Returns a new plug-in. + * + * @param communicator The communicator for the plug-in. + * @param name The name of the plug-in. + * @param args The arguments that are specified in the plug-in's configuration. + * + * @return The new plug-in. <code>null</code> can be returned to indicate + * that a general error occurred. Alternatively, <code>create</code> can throw + * {@link PluginInitializationException} to provide more detailed information. + **/ + @Override + public Ice.Plugin + create(Ice.Communicator communicator, String name, String[] args) + { + return new PluginI(communicator); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/PluginI.java b/java-compat/src/Ice/src/main/java/IceSSL/PluginI.java new file mode 100644 index 00000000000..a57d6e31245 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/PluginI.java @@ -0,0 +1,108 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +class PluginI implements Plugin +{ + public PluginI(Ice.Communicator communicator) + { + final IceInternal.ProtocolPluginFacade facade = IceInternal.Util.getProtocolPluginFacade(communicator); + _engine = new SSLEngine(facade); + + // + // Register the endpoint factory. We have to do this now, rather than + // in initialize, because the communicator may need to interpret + // proxies before the plug-in is fully initialized. + // + + // SSL based on TCP + IceInternal.EndpointFactory tcp = facade.getEndpointFactory(Ice.TCPEndpointType.value); + if(tcp != null) + { + Instance instance = new Instance(_engine, Ice.SSLEndpointType.value, "ssl"); + facade.addEndpointFactory(new EndpointFactoryI(instance, tcp.clone(instance, null))); + } + + // SSL based on Bluetooth + IceInternal.EndpointFactory bluetooth = facade.getEndpointFactory(Ice.BTEndpointType.value); + if(bluetooth != null) + { + Instance instance = new Instance(_engine, Ice.BTSEndpointType.value, "bts"); + facade.addEndpointFactory(new EndpointFactoryI(instance, bluetooth.clone(instance, null))); + } + } + + @Override + public void initialize() + { + _engine.initialize(); + } + + @Override + public void destroy() + { + } + + @Override + public void setContext(javax.net.ssl.SSLContext context) + { + _engine.context(context); + } + + @Override + public javax.net.ssl.SSLContext getContext() + { + return _engine.context(); + } + + @Override + public void setCertificateVerifier(CertificateVerifier verifier) + { + _engine.setCertificateVerifier(verifier); + } + + @Override + public CertificateVerifier getCertificateVerifier() + { + return _engine.getCertificateVerifier(); + } + + @Override + public void setPasswordCallback(PasswordCallback callback) + { + _engine.setPasswordCallback(callback); + } + + @Override + public PasswordCallback getPasswordCallback() + { + return _engine.getPasswordCallback(); + } + + @Override + public void setKeystoreStream(java.io.InputStream stream) + { + _engine.setKeystoreStream(stream); + } + + @Override + public void setTruststoreStream(java.io.InputStream stream) + { + _engine.setTruststoreStream(stream); + } + + @Override + public void addSeedStream(java.io.InputStream stream) + { + _engine.addSeedStream(stream); + } + + private SSLEngine _engine; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/RFC2253.java b/java-compat/src/Ice/src/main/java/IceSSL/RFC2253.java new file mode 100644 index 00000000000..3d88287ca1b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/RFC2253.java @@ -0,0 +1,434 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +// +// See RFC 2253 and RFC 1779. +// +class RFC2253 +{ + static class ParseException extends Ice.LocalException + { + public ParseException() + { + } + + public ParseException(String reason) + { + this.reason = reason; + } + + @Override + public String + ice_id() + { + return "::RFC2253::ParseException"; + } + + public String reason; + } + + static class RDNPair + { + String key; + String value; + } + + static class RDNEntry + { + java.util.List<RDNPair> rdn = new java.util.LinkedList<RDNPair>(); + boolean negate = false; + } + + static private class ParseState + { + String data; + int pos; + } + + public static java.util.List<RDNEntry> + parse(String data) + throws ParseException + { + java.util.List<RDNEntry> results = new java.util.LinkedList<RDNEntry>(); + RDNEntry current = new RDNEntry(); + ParseState state = new ParseState(); + state.data = data; + state.pos = 0; + while(state.pos < state.data.length()) + { + eatWhite(state); + if(state.pos < state.data.length() && state.data.charAt(state.pos) == '!') + { + if(!current.rdn.isEmpty()) + { + throw new ParseException("negation symbol '!' must appear at start of list"); + } + ++state.pos; + current.negate = true; + } + current.rdn.add(parseNameComponent(state)); + eatWhite(state); + if(state.pos < state.data.length() && state.data.charAt(state.pos) == ',') + { + ++state.pos; + } + else if(state.pos < state.data.length() && state.data.charAt(state.pos) == ';') + { + ++state.pos; + results.add(current); + current = new RDNEntry(); + } + else if(state.pos < state.data.length()) + { + throw new ParseException("expected ',' or ';' at `" + state.data.substring(state.pos) + "'"); + } + } + if(!current.rdn.isEmpty()) + { + results.add(current); + } + + return results; + } + + public static java.util.List<RDNPair> + parseStrict(String data) + throws ParseException + { + java.util.List<RDNPair> results = new java.util.LinkedList<RDNPair>(); + ParseState state = new ParseState(); + state.data = data; + state.pos = 0; + while(state.pos < state.data.length()) + { + results.add(parseNameComponent(state)); + eatWhite(state); + if(state.pos < state.data.length() && + (state.data.charAt(state.pos) == ',' || state.data.charAt(state.pos) == ';')) + { + ++state.pos; + } + else if(state.pos < state.data.length()) + { + throw new ParseException("expected ',' or ';' at `" + state.data.substring(state.pos) + "'"); + } + } + return results; + } + + private static RDNPair + parseNameComponent(ParseState state) + throws ParseException + { + RDNPair result = parseAttributeTypeAndValue(state); + while(state.pos < state.data.length()) + { + eatWhite(state); + if(state.pos < state.data.length() && state.data.charAt(state.pos) == '+') + { + ++state.pos; + } + else + { + break; + } + RDNPair p = parseAttributeTypeAndValue(state); + result.value += "+"; + result.value += p.key; + result.value += '='; + result.value += p.value; + } + return result; + } + + private static RDNPair + parseAttributeTypeAndValue(ParseState state) + throws ParseException + { + RDNPair p = new RDNPair(); + p.key = parseAttributeType(state); + eatWhite(state); + if(state.pos >= state.data.length()) + { + throw new ParseException("invalid attribute type/value pair (unexpected end of state.data)"); + } + if(state.data.charAt(state.pos) != '=') + { + throw new ParseException("invalid attribute type/value pair (missing =)"); + } + ++state.pos; + p.value = parseAttributeValue(state); + return p; + } + + private static String + parseAttributeType(ParseState state) + throws ParseException + { + eatWhite(state); + if(state.pos >= state.data.length()) + { + throw new ParseException("invalid attribute type (expected end of state.data)"); + } + + StringBuffer result = new StringBuffer(); + + // + // RFC 1779. + // <key> ::= 1*( <keychar> ) | "OID." <oid> | "oid." <oid> + // <oid> ::= <digitString> | <digitstring> "." <oid> + // RFC 2253: + // attributeType = (ALPHA 1*keychar) | oid + // keychar = ALPHA | DIGIT | "-" + // oid = 1*DIGIT *("." 1*DIGIT) + // + // In section 4 of RFC 2253 the document says: + // Implementations MUST allow an oid in the attribute type to be + // prefixed by one of the character Strings "oid." or "OID.". + // + // Here we must also check for "oid." and "OID." before parsing + // according to the ALPHA KEYCHAR* rule. + // + // First the OID case. + // + if(Character.isDigit(state.data.charAt(state.pos)) || + (state.data.length() - state.pos >= 4 && (state.data.substring(state.pos, state.pos + 4).equals("oid.") || + state.data.substring(state.pos, state.pos + 4).equals("OID.")))) + { + if(!Character.isDigit(state.data.charAt(state.pos))) + { + result.append(state.data.substring(state.pos, state.pos + 4)); + state.pos += 4; + } + + while(true) + { + // 1*DIGIT + while(state.pos < state.data.length() && Character.isDigit(state.data.charAt(state.pos))) + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + } + // "." 1*DIGIT + if(state.pos < state.data.length() && state.data.charAt(state.pos) == '.') + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + // 1*DIGIT must follow "." + if(state.pos < state.data.length() && !Character.isDigit(state.data.charAt(state.pos))) + { + throw new ParseException("invalid attribute type (expected end of state.data)"); + } + } + else + { + break; + } + } + } + else if(Character.isUpperCase(state.data.charAt(state.pos)) || + Character.isLowerCase(state.data.charAt(state.pos))) + { + // + // The grammar is wrong in this case. It should be ALPHA + // KEYCHAR* otherwise it will not accept "O" as a valid + // attribute type. + // + result.append(state.data.charAt(state.pos)); + ++state.pos; + // 1* KEYCHAR + while(state.pos < state.data.length() && + (Character.isDigit(state.data.charAt(state.pos)) || + Character.isUpperCase(state.data.charAt(state.pos)) || + Character.isLowerCase(state.data.charAt(state.pos)) || + state.data.charAt(state.pos) == '-')) + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + } + } + else + { + throw new ParseException("invalid attribute type"); + } + return result.toString(); + } + + private static String + parseAttributeValue(ParseState state) + throws ParseException + { + eatWhite(state); + if(state.pos >= state.data.length()) + { + return ""; + } + + // + // RFC 2253 + // # hexString + // + StringBuffer result = new StringBuffer(); + if(state.data.charAt(state.pos) == '#') + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + while(true) + { + String h = parseHexPair(state, true); + if(h.length() == 0) + { + break; + } + result.append(h); + } + } + // + // RFC 2253 + // QUOTATION *( quotechar | pair ) QUOTATION ; only from v2 + // quotechar = <any character except "\" or QUOTATION > + // + else if(state.data.charAt(state.pos) == '"') + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + while(true) + { + if(state.pos >= state.data.length()) + { + throw new ParseException("invalid attribute value (unexpected end of state.data)"); + } + // final terminating " + if(state.data.charAt(state.pos) == '"') + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + break; + } + // any character except '\' + else if(state.data.charAt(state.pos) != '\\') + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + } + // pair '\' + else + { + result.append(parsePair(state)); + } + } + } + // + // RFC 2253 + // * (Stringchar | pair) + // Stringchar = <any character except one of special, "\" or QUOTATION > + // + else + { + while(state.pos < state.data.length()) + { + if(state.data.charAt(state.pos) == '\\') + { + result.append(parsePair(state)); + } + else if(special.indexOf(state.data.charAt(state.pos)) == -1 && state.data.charAt(state.pos) != '"') + { + result.append(state.data.charAt(state.pos)); + ++state.pos; + } + else + { + break; + } + } + } + return result.toString(); + } + + // + // RFC2253: + // pair = "\" ( special | "\" | QUOTATION | hexpair ) + // + private static String + parsePair(ParseState state) + throws ParseException + { + String result = ""; + + assert(state.data.charAt(state.pos) == '\\'); + result += state.data.charAt(state.pos); + ++state.pos; + + if(state.pos >= state.data.length()) + { + throw new ParseException("invalid escape format (unexpected end of state.data)"); + } + + if(special.indexOf(state.data.charAt(state.pos)) != -1 || state.data.charAt(state.pos) != '\\' || + state.data.charAt(state.pos) != '"') + { + result += state.data.charAt(state.pos); + ++state.pos; + return result; + } + return parseHexPair(state, false); + } + + // + // RFC 2253 + // hexpair = hexchar hexchar + // + private static String + parseHexPair(ParseState state, boolean allowEmpty) + throws ParseException + { + String result = ""; + if(state.pos < state.data.length() && hexvalid.indexOf(state.data.charAt(state.pos)) != -1) + { + result += state.data.charAt(state.pos); + ++state.pos; + } + if(state.pos < state.data.length() && hexvalid.indexOf(state.data.charAt(state.pos)) != -1) + { + result += state.data.charAt(state.pos); + ++state.pos; + } + if(result.length() != 2) + { + if(allowEmpty && result.length() == 0) + { + return result; + } + throw new ParseException("invalid hex format"); + } + return result; + } + + // + // RFC 2253: + // + // Implementations MUST allow for space (' ' ASCII 32) characters to be + // present between name-component and ',', between attributeTypeAndValue + // and '+', between attributeType and '=', and between '=' and + // attributeValue. These space characters are ignored when parsing. + // + private static void + eatWhite(ParseState state) + { + while(state.pos < state.data.length() && state.data.charAt(state.pos) == ' ') + { + ++state.pos; + } + } + + private final static String special = ",=+<>#;"; + private final static String hexvalid = "0123456789abcdefABCDEF"; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java b/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java new file mode 100644 index 00000000000..e8da76b6b26 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java @@ -0,0 +1,1314 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.security.cert.*; + +class SSLEngine +{ + SSLEngine(IceInternal.ProtocolPluginFacade facade) + { + _communicator = facade.getCommunicator(); + _logger = _communicator.getLogger(); + _facade = facade; + _securityTraceLevel = _communicator.getProperties().getPropertyAsIntWithDefault("IceSSL.Trace.Security", 0); + _securityTraceCategory = "Security"; + _trustManager = new TrustManager(_communicator); + } + + void initialize() + { + if(_initialized) + { + return; + } + + final String prefix = "IceSSL."; + Ice.Properties properties = communicator().getProperties(); + + // + // Parse the cipher list. + // + String ciphers = properties.getProperty(prefix + "Ciphers"); + if(ciphers.length() > 0) + { + parseCiphers(ciphers); + } + + String[] protocols = properties.getPropertyAsList(prefix + "Protocols"); + if(protocols.length != 0) + { + java.util.ArrayList<String> l = new java.util.ArrayList<String>(); + for(String prot : protocols) + { + String s = prot.toUpperCase(); + if(s.equals("SSL3") || s.equals("SSLV3")) + { + l.add("SSLv3"); + } + else if(s.equals("TLS") || s.equals("TLS1") || s.equals("TLSV1") || s.equals("TLS1_0") || + s.equals("TLSV1_0")) + { + l.add("TLSv1"); + } + else if(s.equals("TLS1_1") || s.equals("TLSV1_1")) + { + l.add("TLSv1.1"); + } + else if(s.equals("TLS1_2") || s.equals("TLSV1_2")) + { + l.add("TLSv1.2"); + } + else + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: unrecognized protocol `" + prot + "'"; + throw e; + } + } + _protocols = new String[l.size()]; + l.toArray(_protocols); + } + + // + // CheckCertName determines whether we compare the name in a peer's + // certificate against its hostname. + // + _checkCertName = properties.getPropertyAsIntWithDefault(prefix + "CheckCertName", 0) > 0; + + // + // VerifyDepthMax establishes the maximum length of a peer's certificate + // chain, including the peer's certificate. A value of 0 means there is + // no maximum. + // + _verifyDepthMax = properties.getPropertyAsIntWithDefault(prefix + "VerifyDepthMax", 3); + + // + // VerifyPeer determines whether certificate validation failures abort a connection. + // + _verifyPeer = properties.getPropertyAsIntWithDefault("IceSSL.VerifyPeer", 2); + + // + // Check for a certificate verifier. + // + final String certVerifierClass = properties.getProperty(prefix + "CertVerifier"); + if(certVerifierClass.length() > 0) + { + if(_verifier != null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: certificate verifier already installed"; + throw e; + } + + Class<?> cls = null; + try + { + cls = _facade.findClass(certVerifierClass); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load certificate verifier class " + certVerifierClass, ex); + } + + try + { + _verifier = (CertificateVerifier)cls.newInstance(); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to instantiate certificate verifier class " + certVerifierClass, ex); + } + } + + // + // Check for a password callback. + // + final String passwordCallbackClass = properties.getProperty(prefix + "PasswordCallback"); + if(passwordCallbackClass.length() > 0) + { + if(_passwordCallback != null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: password callback already installed"; + throw e; + } + + Class<?> cls = null; + try + { + cls = _facade.findClass(passwordCallbackClass); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load password callback class " + passwordCallbackClass, ex); + } + + try + { + _passwordCallback = (PasswordCallback)cls.newInstance(); + } + catch(Throwable ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to instantiate password callback class " + passwordCallbackClass, ex); + } + } + + // + // If the user doesn't supply an SSLContext, we need to create one based + // on property settings. + // + if(_context == null) + { + try + { + // + // Check for a default directory. We look in this directory for + // files mentioned in the configuration. + // + _defaultDir = properties.getProperty(prefix + "DefaultDir"); + + // + // We need a SecureRandom object. + // + // NOTE: The JDK recommends obtaining a SecureRandom object like this: + // + // java.security.SecureRandom rand = java.security.SecureRandom.getInstance("SHA1PRNG"); + // + // However, there is a bug (6202721) which causes it to always use /dev/random, + // which can lead to long delays at program startup. The workaround is to use + // the default constructor. + // + java.security.SecureRandom rand = new java.security.SecureRandom(); + + // + // Check for seed data for the random number generator. + // + final String seedFiles = properties.getProperty(prefix + "Random"); + if(seedFiles.length() > 0) + { + final String[] arr = seedFiles.split(java.io.File.pathSeparator); + for(String file : arr) + { + try + { + java.io.InputStream seedStream = openResource(file); + if(seedStream == null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: random seed file not found:\n" + file; + throw e; + } + + _seeds.add(seedStream); + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to access random seed file:\n" + file, ex); + } + } + } + + if(!_seeds.isEmpty()) + { + byte[] seed = null; + int start = 0; + for(InputStream in : _seeds) + { + try + { + int num = in.available(); + if(seed == null) + { + seed = new byte[num]; + } + else + { + byte[] tmp = new byte[seed.length + num]; + System.arraycopy(seed, 0, tmp, 0, seed.length); + start = seed.length; + seed = tmp; + } + in.read(seed, start, num); + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException("IceSSL: error while reading random seed", ex); + } + finally + { + try + { + in.close(); + } + catch(java.io.IOException e) + { + // Ignore. + } + } + } + rand.setSeed(seed); + } + _seeds.clear(); + + // + // We call nextInt() in order to force the object to perform any time-consuming + // initialization tasks now. + // + rand.nextInt(); + + // + // The keystore holds private keys and associated certificates. + // + String keystorePath = properties.getProperty(prefix + "Keystore"); + + // + // The password for the keys. + // + String password = properties.getProperty(prefix + "Password"); + + // + // The password for the keystore. + // + String keystorePassword = properties.getProperty(prefix + "KeystorePassword"); + + // + // The default keystore type is usually "JKS", but the legal values are determined + // by the JVM implementation. Other possibilities include "PKCS12" and "BKS". + // + final String defaultType = java.security.KeyStore.getDefaultType(); + final String keystoreType = properties.getPropertyWithDefault(prefix + "KeystoreType", defaultType); + + // + // The alias of the key to use in authentication. + // + String alias = properties.getProperty(prefix + "Alias"); + boolean overrideAlias = !alias.isEmpty(); // Always use the configured alias + + // + // The truststore holds the certificates of trusted CAs. + // + String truststorePath = properties.getProperty(prefix + "Truststore"); + + // + // The password for the truststore. + // + String truststorePassword = properties.getProperty(prefix + "TruststorePassword"); + + // + // The default truststore type is usually "JKS", but the legal values are determined + // by the JVM implementation. Other possibilities include "PKCS12" and "BKS". + // + final String truststoreType = + properties.getPropertyWithDefault(prefix + "TruststoreType", + java.security.KeyStore.getDefaultType()); + + // + // Collect the key managers. + // + javax.net.ssl.KeyManager[] keyManagers = null; + java.security.KeyStore keys = null; + if(_keystoreStream != null || keystorePath.length() > 0) + { + java.io.InputStream keystoreStream = null; + try + { + if(_keystoreStream != null) + { + keystoreStream = _keystoreStream; + } + else + { + keystoreStream = openResource(keystorePath); + if(keystoreStream == null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: keystore not found:\n" + keystorePath; + throw e; + } + } + + keys = java.security.KeyStore.getInstance(keystoreType); + char[] passwordChars = null; + if(keystorePassword.length() > 0) + { + passwordChars = keystorePassword.toCharArray(); + } + else if(_passwordCallback != null) + { + passwordChars = _passwordCallback.getKeystorePassword(); + } + else if(keystoreType.equals("BKS") || keystoreType.equals("PKCS12")) + { + // Bouncy Castle or PKCS12 does not permit null passwords. + passwordChars = new char[0]; + } + + keys.load(keystoreStream, passwordChars); + + if(passwordChars != null) + { + java.util.Arrays.fill(passwordChars, '\0'); + } + keystorePassword = null; + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load keystore:\n" + keystorePath, ex); + } + finally + { + if(keystoreStream != null) + { + try + { + keystoreStream.close(); + } + catch(java.io.IOException e) + { + // Ignore. + } + } + } + + String algorithm = javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm(); + javax.net.ssl.KeyManagerFactory kmf = javax.net.ssl.KeyManagerFactory.getInstance(algorithm); + char[] passwordChars = new char[0]; // This password cannot be null. + if(password.length() > 0) + { + passwordChars = password.toCharArray(); + } + else if(_passwordCallback != null) + { + passwordChars = _passwordCallback.getPassword(alias); + } + kmf.init(keys, passwordChars); + if(passwordChars.length > 0) + { + java.util.Arrays.fill(passwordChars, '\0'); + } + password = null; + keyManagers = kmf.getKeyManagers(); + + // + // If no alias is specified, we look for the first key entry in the key store. + // + // This is required to force the key manager to always choose a certificate + // even if there's no certificate signed by any of the CA names sent by the + // server. Ice servers might indeed not always send the CA names of their + // trusted roots. + // + if(alias.isEmpty()) + { + for(java.util.Enumeration<String> e = keys.aliases(); e.hasMoreElements();) + { + String a = e.nextElement(); + if(keys.isKeyEntry(a)) + { + alias = a; + break; + } + } + } + + if(!alias.isEmpty()) + { + // + // If the user selected a specific alias, we need to wrap the key managers + // in order to return the desired alias. + // + if(!keys.isKeyEntry(alias)) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: keystore does not contain an entry with alias `" + alias + "'"; + throw e; + } + + for(int i = 0; i < keyManagers.length; ++i) + { + keyManagers[i] = new X509KeyManagerI((javax.net.ssl.X509ExtendedKeyManager)keyManagers[i], + alias, overrideAlias); + } + } + } + + // + // Load the truststore. + // + java.security.KeyStore ts = null; + if(_truststoreStream != null || truststorePath.length() > 0) + { + // + // If the trust store and the key store are the same input + // stream or file, don't create another key store. + // + if((_truststoreStream != null && _truststoreStream == _keystoreStream) || + (truststorePath.length() > 0 && truststorePath.equals(keystorePath))) + { + assert keys != null; + ts = keys; + } + else + { + java.io.InputStream truststoreStream = null; + try + { + if(_truststoreStream != null) + { + truststoreStream = _truststoreStream; + } + else + { + truststoreStream = openResource(truststorePath); + if(truststoreStream == null) + { + Ice.PluginInitializationException e = new Ice.PluginInitializationException(); + e.reason = "IceSSL: truststore not found:\n" + truststorePath; + throw e; + } + } + + ts = java.security.KeyStore.getInstance(truststoreType); + + char[] passwordChars = null; + if(truststorePassword.length() > 0) + { + passwordChars = truststorePassword.toCharArray(); + } + else if(_passwordCallback != null) + { + passwordChars = _passwordCallback.getTruststorePassword(); + } + else if(truststoreType.equals("BKS") || truststoreType.equals("PKCS12")) + { + // Bouncy Castle or PKCS12 does not permit null passwords. + passwordChars = new char[0]; + } + + ts.load(truststoreStream, passwordChars); + + if(passwordChars != null) + { + java.util.Arrays.fill(passwordChars, '\0'); + } + truststorePassword = null; + } + catch(java.io.IOException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: unable to load truststore:\n" + truststorePath, ex); + } + finally + { + if(truststoreStream != null) + { + try + { + truststoreStream.close(); + } + catch(java.io.IOException e) + { + // Ignore. + } + } + } + } + } + + // + // Collect the trust managers. Use IceSSL.Truststore if + // specified, otherwise use the Java root CAs if + // Ice.Use.PlatformCAs is enabled. If none of these are enabled, + // use the keystore or a dummy trust manager which rejects any + // certificate. + // + javax.net.ssl.TrustManager[] trustManagers = null; + { + String algorithm = javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm(); + javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory.getInstance(algorithm); + java.security.KeyStore trustStore = null; + if(ts != null) + { + trustStore = ts; + } + else if(properties.getPropertyAsInt("IceSSL.UsePlatformCAs") <= 0) + { + if(keys != null) + { + trustStore = keys; + } + else + { + trustManagers = new javax.net.ssl.TrustManager[] + { + new javax.net.ssl.X509TrustManager() + { + @Override + public void + checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + throw new CertificateException("no trust anchors"); + } + + @Override + public void + checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + throw new CertificateException("no trust anchors"); + } + + @Override + public X509Certificate[] + getAcceptedIssuers() + { + return new X509Certificate[0]; + } + } + }; + } + } + else + { + trustStore = null; + } + + // + // Attempting to establish an outgoing connection with an empty truststore can + // cause hangs that eventually result in an exception such as: + // + // java.security.InvalidAlgorithmParameterException: the trustAnchors parameter + // must be non-empty + // + if(trustStore != null && trustStore.size() == 0) + { + throw new Ice.PluginInitializationException("IceSSL: truststore is empty"); + } + + if(trustManagers == null) + { + tmf.init(trustStore); + trustManagers = tmf.getTrustManagers(); + } + assert(trustManagers != null); + } + + // + // Create a certificate path validator to build the full + // certificate chain of the peer certificate. NOTE: this must + // be done before wrapping the trust manager since our wrappers + // return an empty list of accepted issuers. + // + _validator = CertPathValidator.getInstance("PKIX"); + java.util.Set<TrustAnchor> anchors = new java.util.HashSet<TrustAnchor>(); + for(javax.net.ssl.TrustManager tm : trustManagers) + { + X509Certificate[] certs = ((javax.net.ssl.X509TrustManager)tm).getAcceptedIssuers(); + for(X509Certificate cert : certs) + { + if(cert.getBasicConstraints() >= 0) // Only add CAs + { + anchors.add(new TrustAnchor(cert, null)); + } + } + } + if(!anchors.isEmpty()) + { + _validatorParams = new PKIXParameters(anchors); + _validatorParams.setRevocationEnabled(false); + } + + // + // Wrap each trust manager. + // + for(int i = 0; i < trustManagers.length; ++i) + { + trustManagers[i] = new X509TrustManagerI(this, (javax.net.ssl.X509TrustManager)trustManagers[i]); + } + + // + // Initialize the SSL context. + // + _context = javax.net.ssl.SSLContext.getInstance("TLS"); + _context.init(keyManagers, trustManagers, rand); + } + catch(java.security.GeneralSecurityException ex) + { + throw new Ice.PluginInitializationException("IceSSL: unable to initialize context", ex); + } + } + + // + // Clear cached input streams. + // + _seeds.clear(); + _keystoreStream = null; + _truststoreStream = null; + + _initialized = true; + } + + Certificate[] getVerifiedCertificateChain(Certificate[] chain) + { + if(_validator == null) + { + return chain; // The user provided a custom SSLContext + } + + if(_validatorParams == null) + { + return null; // Couldn't validate the given certificate chain, no trust anchors configured. + } + + List<Certificate> certs = new ArrayList<Certificate>(java.util.Arrays.asList(chain)); + try + { + CertPath path = CertificateFactory.getInstance("X.509").generateCertPath(certs); + CertPathValidatorResult result = _validator.validate(path, _validatorParams); + Certificate root = ((PKIXCertPathValidatorResult)result).getTrustAnchor().getTrustedCert(); + if(!root.equals(chain[chain.length - 1])) // Only add the root certificate if it's not already in the chain + { + certs.add(root); + } + return certs.toArray(new Certificate[certs.size()]); + } + catch(Exception ex) + { + return null; // Couldn't validate the given certificate chain. + } + } + + void context(javax.net.ssl.SSLContext context) + { + if(_initialized) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plug-in is already initialized"; + throw ex; + } + + assert(_context == null); + _context = context; + } + + javax.net.ssl.SSLContext context() + { + return _context; + } + + void setCertificateVerifier(CertificateVerifier verifier) + { + _verifier = verifier; + } + + CertificateVerifier getCertificateVerifier() + { + return _verifier; + } + + void setPasswordCallback(PasswordCallback callback) + { + _passwordCallback = callback; + } + + PasswordCallback getPasswordCallback() + { + return _passwordCallback; + } + + void setKeystoreStream(java.io.InputStream stream) + { + if(_initialized) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is already initialized"; + throw ex; + } + + _keystoreStream = stream; + } + + void setTruststoreStream(java.io.InputStream stream) + { + if(_initialized) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: plugin is already initialized"; + throw ex; + } + + _truststoreStream = stream; + } + + void addSeedStream(java.io.InputStream stream) + { + _seeds.add(stream); + } + + int securityTraceLevel() + { + return _securityTraceLevel; + } + + String securityTraceCategory() + { + return _securityTraceCategory; + } + + boolean initialized() + { + return _initialized; + } + + javax.net.ssl.SSLEngine createSSLEngine(boolean incoming, String host, int port) + { + javax.net.ssl.SSLEngine engine; + if(host != null) + { + engine = _context.createSSLEngine(host, port); + } + else + { + engine = _context.createSSLEngine(); + } + engine.setUseClientMode(!incoming); + + String[] cipherSuites = filterCiphers(engine.getSupportedCipherSuites(), engine.getEnabledCipherSuites()); + try + { + engine.setEnabledCipherSuites(cipherSuites); + } + catch(IllegalArgumentException ex) + { + throw new Ice.SecurityException("IceSSL: invalid ciphersuite", ex); + } + + if(_securityTraceLevel >= 1) + { + StringBuilder s = new StringBuilder(128); + s.append("enabling SSL ciphersuites:"); + for(String suite : cipherSuites) + { + s.append("\n "); + s.append(suite); + } + _logger.trace(_securityTraceCategory, s.toString()); + } + + if(_protocols != null) + { + try + { + engine.setEnabledProtocols(_protocols); + } + catch(IllegalArgumentException ex) + { + throw new Ice.SecurityException("IceSSL: invalid protocol", ex); + } + } + else + { + // + // Disable SSLv3 + // + List<String> protocols = new ArrayList<String>(java.util.Arrays.asList(engine.getEnabledProtocols())); + protocols.remove("SSLv3"); + engine.setEnabledProtocols(protocols.toArray(new String[protocols.size()])); + } + + + if(incoming) + { + if(_verifyPeer == 0) + { + engine.setWantClientAuth(false); + engine.setNeedClientAuth(false); + } + else if(_verifyPeer == 1) + { + engine.setWantClientAuth(true); + } + else + { + engine.setNeedClientAuth(true); + } + } + + try + { + engine.beginHandshake(); + } + catch(javax.net.ssl.SSLException ex) + { + throw new Ice.SecurityException("IceSSL: handshake error", ex); + } + + return engine; + } + + String[] filterCiphers(String[] supportedCiphers, String[] defaultCiphers) + { + java.util.LinkedList<String> result = new java.util.LinkedList<String>(); + if(_allCiphers) + { + for(String cipher : supportedCiphers) + { + result.add(cipher); + } + } + else if(!_noCiphers) + { + for(String cipher : defaultCiphers) + { + result.add(cipher); + } + } + + if(_ciphers != null) + { + for(CipherExpression ce : _ciphers) + { + if(ce.not) + { + java.util.Iterator<String> e = result.iterator(); + while(e.hasNext()) + { + String cipher = e.next(); + if(ce.cipher != null) + { + if(ce.cipher.equals(cipher)) + { + e.remove(); + } + } + else + { + assert(ce.re != null); + java.util.regex.Matcher m = ce.re.matcher(cipher); + if(m.find()) + { + e.remove(); + } + } + } + } + else + { + if(ce.cipher != null) + { + result.add(0, ce.cipher); + } + else + { + assert(ce.re != null); + for(String cipher : supportedCiphers) + { + java.util.regex.Matcher m = ce.re.matcher(cipher); + if(m.find()) + { + result.add(0, cipher); + } + } + } + } + } + } + + String[] arr = new String[result.size()]; + result.toArray(arr); + return arr; + } + + String[] protocols() + { + return _protocols; + } + + void traceConnection(String desc, javax.net.ssl.SSLEngine engine, boolean incoming) + { + javax.net.ssl.SSLSession session = engine.getSession(); + String msg = "SSL summary for " + (incoming ? "incoming" : "outgoing") + " connection\n" + + "cipher = " + session.getCipherSuite() + "\n" + + "protocol = " + session.getProtocol() + "\n" + desc; + _logger.trace(_securityTraceCategory, msg); + } + + Ice.Communicator communicator() + { + return _communicator; + } + + void verifyPeer(String address, NativeConnectionInfo info, String desc) + { + // + // IceSSL.VerifyPeer is translated into the proper SSLEngine configuration + // for a server, but we have to do it ourselves for a client. + // + if(!info.incoming) + { + if(_verifyPeer > 0 && !info.verified) + { + throw new Ice.SecurityException("IceSSL: server did not supply a certificate"); + } + } + + // + // For an outgoing connection, we compare the proxy address (if any) against + // fields in the server's certificate (if any). + // + if(info.nativeCerts != null && info.nativeCerts.length > 0 && address.length() > 0) + { + X509Certificate cert = (X509Certificate)info.nativeCerts[0]; + + // + // Extract the IP addresses and the DNS names from the subject + // alternative names. + // + java.util.ArrayList<String> ipAddresses = new java.util.ArrayList<String>(); + java.util.ArrayList<String> dnsNames = new java.util.ArrayList<String>(); + try + { + java.util.Collection<java.util.List<?> > subjectAltNames = cert.getSubjectAlternativeNames(); + if(subjectAltNames != null) + { + for(java.util.List<?> l : subjectAltNames) + { + assert(!l.isEmpty()); + Integer n = (Integer)l.get(0); + if(n.intValue() == 7) + { + ipAddresses.add((String)l.get(1)); + } + else if(n.intValue() == 2) + { + dnsNames.add(((String)l.get(1)).toLowerCase()); + } + } + } + } + catch(CertificateParsingException ex) + { + assert(false); + } + + // + // Compare the peer's address against the common name as well as + // the dnsName and ipAddress values in the subject alternative name. + // + boolean certNameOK = false; + String dn = ""; + String addrLower = address.toLowerCase(); + { + javax.security.auth.x500.X500Principal principal = cert.getSubjectX500Principal(); + dn = principal.getName(javax.security.auth.x500.X500Principal.CANONICAL); + // + // Canonical format is already in lower case. + // + String cn = "cn=" + addrLower; + int pos = dn.indexOf(cn); + if(pos >= 0) + { + // + // Ensure we match the entire common name. + // + certNameOK = (pos + cn.length() == dn.length()) || (dn.charAt(pos + cn.length()) == ','); + } + } + + // + // Compare the peer's address against the dnsName and ipAddress + // values in the subject alternative name. + // + if(!certNameOK) + { + certNameOK = ipAddresses.contains(addrLower); + } + if(!certNameOK) + { + certNameOK = dnsNames.contains(addrLower); + } + + // + // Log a message if the name comparison fails. If CheckCertName is defined, + // we also raise an exception to abort the connection. Don't log a message if + // CheckCertName is not defined and a verifier is present. + // + if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && _verifier == null))) + { + StringBuilder sb = new StringBuilder(128); + sb.append("IceSSL: "); + if(!_checkCertName) + { + sb.append("ignoring "); + } + sb.append("certificate validation failure:\npeer certificate does not have `"); + sb.append(address); + sb.append("' as its commonName or in its subjectAltName extension"); + if(dn.length() > 0) + { + sb.append("\nSubject DN: "); + sb.append(dn); + } + if(!dnsNames.isEmpty()) + { + sb.append("\nDNS names found in certificate: "); + for(int j = 0; j < dnsNames.size(); ++j) + { + if(j > 0) + { + sb.append(", "); + } + sb.append(dnsNames.get(j)); + } + } + if(!ipAddresses.isEmpty()) + { + sb.append("\nIP addresses found in certificate: "); + for(int j = 0; j < ipAddresses.size(); ++j) + { + if(j > 0) + { + sb.append(", "); + } + sb.append(ipAddresses.get(j)); + } + } + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, sb.toString()); + } + if(_checkCertName) + { + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = sb.toString(); + throw ex; + } + } + } + + if(_verifyDepthMax > 0 && info.nativeCerts != null && info.nativeCerts.length > _verifyDepthMax) + { + String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected:\n" + + "length of peer's certificate chain (" + info.nativeCerts.length + ") exceeds maximum of " + + _verifyDepthMax + "\n" + desc; + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, msg); + } + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = msg; + throw ex; + } + + if(!_trustManager.verify(info, desc)) + { + String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by trust manager\n" + desc; + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, msg); + } + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = msg; + throw ex; + } + + if(_verifier != null && !_verifier.verify(info)) + { + String msg = (info.incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier\n" + + desc; + if(_securityTraceLevel >= 1) + { + _logger.trace(_securityTraceCategory, msg); + } + Ice.SecurityException ex = new Ice.SecurityException(); + ex.reason = msg; + throw ex; + } + } + + void trustManagerFailure(boolean incoming, CertificateException ex) + throws CertificateException + { + if(_verifyPeer == 0) + { + if(_securityTraceLevel >= 1) + { + String msg = "ignoring peer verification failure"; + if(_securityTraceLevel > 1) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + msg += ":\n" + sw.toString(); + } + _logger.trace(_securityTraceCategory, msg); + } + } + else + { + throw ex; + } + } + + private void parseCiphers(String ciphers) + { + java.util.ArrayList<CipherExpression> cipherList = new java.util.ArrayList<CipherExpression>(); + String[] expr = ciphers.split("[ \t]+"); + for(int i = 0; i < expr.length; ++i) + { + if(expr[i].equals("ALL")) + { + if(i != 0) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: `ALL' must be first in cipher list `" + ciphers + "'"; + throw ex; + } + _allCiphers = true; + } + else if(expr[i].equals("NONE")) + { + if(i != 0) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: `NONE' must be first in cipher list `" + ciphers + "'"; + throw ex; + } + _noCiphers = true; + } + else + { + CipherExpression ce = new CipherExpression(); + String exp = expr[i]; + if(exp.charAt(0) == '!') + { + ce.not = true; + if(exp.length() > 1) + { + exp = exp.substring(1); + } + else + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: invalid cipher expression `" + exp + "'"; + throw ex; + } + } + + if(exp.charAt(0) == '(') + { + if(!exp.endsWith(")")) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: invalid cipher expression `" + exp + "'"; + throw ex; + } + + try + { + ce.re = java.util.regex.Pattern.compile(exp.substring(1, exp.length() - 2)); + } + catch(java.util.regex.PatternSyntaxException ex) + { + throw new Ice.PluginInitializationException( + "IceSSL: invalid cipher expression `" + exp + "'", ex); + } + } + else + { + ce.cipher = exp; + } + + cipherList.add(ce); + } + } + _ciphers = new CipherExpression[cipherList.size()]; + cipherList.toArray(_ciphers); + } + + private java.io.InputStream openResource(String path) + throws java.io.IOException + { + boolean isAbsolute = false; + try + { + new java.net.URL(path); + isAbsolute = true; + } + catch(java.net.MalformedURLException ex) + { + java.io.File f = new java.io.File(path); + isAbsolute = f.isAbsolute(); + } + + java.io.InputStream stream = IceInternal.Util.openResource(getClass().getClassLoader(), path); + + // + // If the first attempt fails and IceSSL.DefaultDir is defined and the original path is relative, + // we prepend the default directory and try again. + // + if(stream == null && _defaultDir.length() > 0 && !isAbsolute) + { + stream = IceInternal.Util.openResource(getClass().getClassLoader(), + _defaultDir + java.io.File.separator + path); + } + + if(stream != null) + { + stream = new java.io.BufferedInputStream(stream); + } + + return stream; + } + + private static class CipherExpression + { + boolean not; + String cipher; + java.util.regex.Pattern re; + } + + private Ice.Communicator _communicator; + private Ice.Logger _logger; + private IceInternal.ProtocolPluginFacade _facade; + private int _securityTraceLevel; + private String _securityTraceCategory; + private boolean _initialized; + private javax.net.ssl.SSLContext _context; + private String _defaultDir; + private CipherExpression[] _ciphers; + private boolean _allCiphers; + private boolean _noCiphers; + private String[] _protocols; + private boolean _checkCertName; + private int _verifyDepthMax; + private int _verifyPeer; + private CertificateVerifier _verifier; + private PasswordCallback _passwordCallback; + private TrustManager _trustManager; + + private InputStream _keystoreStream; + private InputStream _truststoreStream; + private List<InputStream> _seeds = new ArrayList<InputStream>(); + + private CertPathValidator _validator; + private PKIXParameters _validatorParams; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/TransceiverI.java b/java-compat/src/Ice/src/main/java/IceSSL/TransceiverI.java new file mode 100644 index 00000000000..d34a83acdae --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/TransceiverI.java @@ -0,0 +1,588 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +import java.nio.*; +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; + +final class TransceiverI implements IceInternal.Transceiver +{ + @Override + public java.nio.channels.SelectableChannel fd() + { + return _delegate.fd(); + } + + @Override + public void setReadyCallback(IceInternal.ReadyCallback callback) + { + _readyCallback = callback; + _delegate.setReadyCallback(callback); + } + + @Override + public int initialize(IceInternal.Buffer readBuffer, IceInternal.Buffer writeBuffer) + { + if(!_isConnected) + { + int status = _delegate.initialize(readBuffer, writeBuffer); + if(status != IceInternal.SocketOperation.None) + { + return status; + } + _isConnected = true; + + Ice.IPConnectionInfo ipInfo = null; + for(Ice.ConnectionInfo p = _delegate.getInfo(); p != null; p = p.underlying) + { + if(p instanceof Ice.IPConnectionInfo) + { + ipInfo = (Ice.IPConnectionInfo)p; + } + } + final String host = _incoming ? (ipInfo != null ? ipInfo.remoteAddress : "") : _host; + final int port = ipInfo != null ? ipInfo.remotePort : -1; + _engine = _instance.createSSLEngine(_incoming, host, port); + _appInput = ByteBuffer.allocateDirect(_engine.getSession().getApplicationBufferSize() * 2); + int bufSize = _engine.getSession().getPacketBufferSize() * 2; + _netInput = new IceInternal.Buffer(ByteBuffer.allocateDirect(bufSize * 2)); + _netOutput = new IceInternal.Buffer(ByteBuffer.allocateDirect(bufSize * 2)); + } + + int status = handshakeNonBlocking(); + if(status != IceInternal.SocketOperation.None) + { + return status; + } + + // + // Additional verification. + // + _instance.verifyPeer(_host, (NativeConnectionInfo)getInfo(), _delegate.toString()); + + if(_instance.securityTraceLevel() >= 1) + { + _instance.traceConnection(_delegate.toString(), _engine, _incoming); + } + return IceInternal.SocketOperation.None; + } + + @Override + public int closing(boolean initiator, Ice.LocalException ex) + { + // If we are initiating the connection closure, wait for the peer + // to close the TCP/IP connection. Otherwise, close immediately. + return initiator ? IceInternal.SocketOperation.Read : IceInternal.SocketOperation.None; + } + + @Override + public void close() + { + if(_engine != null) + { + try + { + // + // Send the close_notify message. + // + _engine.closeOutbound(); + _netOutput.b.clear(); + while(!_engine.isOutboundDone()) + { + _engine.wrap(_emptyBuffer, _netOutput.b); + try + { + // + // Note: we can't block to send the close_notify message. In some cases, the + // close_notify message might therefore not be received by the peer. This is + // not a big issue since the Ice protocol isn't subject to truncation attacks. + // + flushNonBlocking(); + } + catch(Ice.LocalException ex) + { + // Ignore. + } + } + } + catch(SSLException ex) + { + // + // We can't throw in close. + // + // Ice.SecurityException se = new Ice.SecurityException( + // "IceSSL: SSL failure while shutting down socket", ex); + // + } + + try + { + _engine.closeInbound(); + } + catch(SSLException ex) + { + // + // SSLEngine always raises an exception with this message: + // + // Inbound closed before receiving peer's close_notify: possible truncation attack? + // + // We would probably need to wait for a response in shutdown() to avoid this. + // For now, we'll ignore this exception. + // + //_instance.logger().error("IceSSL: error during close\n" + ex.getMessage()); + } + } + + _delegate.close(); + } + + @Override + public IceInternal.EndpointI bind() + { + assert(false); + return null; + } + + @Override + public int write(IceInternal.Buffer buf) + { + if(!_isConnected) + { + return _delegate.write(buf); + } + + int status = writeNonBlocking(buf.b); + assert(status == IceInternal.SocketOperation.None || status == IceInternal.SocketOperation.Write); + return status; + } + + @Override + public int read(IceInternal.Buffer buf) + { + if(!_isConnected) + { + return _delegate.read(buf); + } + + _readyCallback.ready(IceInternal.SocketOperation.Read, false); + + // + // Try to satisfy the request from data we've already decrypted. + // + fill(buf.b); + + // + // Read and decrypt more data if necessary. Note that we might read + // more data from the socket than is actually necessary to fill the + // caller's stream. + // + try + { + while(buf.b.hasRemaining()) + { + _netInput.b.flip(); + SSLEngineResult result = _engine.unwrap(_netInput.b, _appInput); + _netInput.b.compact(); + + Status status = result.getStatus(); + assert status != Status.BUFFER_OVERFLOW; + + if(status == Status.CLOSED) + { + throw new Ice.ConnectionLostException(); + } + // Android API 21 SSLEngine doesn't report underflow, so look at the absence of + // network data and application data to signal a network read. + else if(status == Status.BUFFER_UNDERFLOW || (_appInput.position() == 0 && _netInput.b.position() == 0)) + { + int s = _delegate.read(_netInput); + if(s != IceInternal.SocketOperation.None && _netInput.b.position() == 0) + { + return s; + } + continue; + } + + fill(buf.b); + } + + // If there is no more application data, do one further unwrap to ensure + // that the SSLEngine has no buffered data (Android R21 and greater only). + if(_appInput.position() == 0) + { + _netInput.b.flip(); + _engine.unwrap(_netInput.b, _appInput); + _netInput.b.compact(); + + // Don't check the status here since we may have already filled + // the buffer with a complete request which must be processed. + } + } + catch(SSLException ex) + { + throw new Ice.SecurityException("IceSSL: error during read", ex); + } + + // + // Indicate whether more data is available. + // + if(_netInput.b.position() > 0 || _appInput.position() > 0) + { + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + } + + return IceInternal.SocketOperation.None; + } + + @Override + public String protocol() + { + return _delegate.protocol(); + } + + @Override + public String toString() + { + return _delegate.toString(); + } + + @Override + public String toDetailedString() + { + return toString(); + } + + @Override + public Ice.ConnectionInfo getInfo() + { + NativeConnectionInfo info = new NativeConnectionInfo(); + info.underlying = _delegate.getInfo(); + info.incoming = _incoming; + info.adapterName = _adapterName; + if(_engine != null) + { + SSLSession session = _engine.getSession(); + info.cipher = session.getCipherSuite(); + try + { + java.security.cert.Certificate[] pcerts = session.getPeerCertificates(); + java.security.cert.Certificate[] vcerts = _instance.engine().getVerifiedCertificateChain(pcerts); + info.verified = vcerts != null; + info.nativeCerts = vcerts != null ? vcerts : pcerts; + java.util.ArrayList<String> certs = new java.util.ArrayList<String>(); + for(java.security.cert.Certificate c : info.nativeCerts) + { + StringBuilder s = new StringBuilder("-----BEGIN CERTIFICATE-----\n"); + s.append(IceUtilInternal.Base64.encode(c.getEncoded())); + s.append("\n-----END CERTIFICATE-----"); + certs.add(s.toString()); + } + info.certs = certs.toArray(new String[certs.size()]); + } + catch(javax.net.ssl.SSLPeerUnverifiedException ex) + { + // No peer certificates. + } + catch(java.security.cert.CertificateEncodingException ex) + { + } + } + return info; + } + + @Override + public void setBufferSize(int rcvSize, int sndSize) + { + _delegate.setBufferSize(rcvSize, sndSize); + } + + @Override + public void checkSendSize(IceInternal.Buffer buf) + { + _delegate.checkSendSize(buf); + } + + TransceiverI(Instance instance, IceInternal.Transceiver delegate, String hostOrAdapterName, boolean incoming) + { + _instance = instance; + _delegate = delegate; + _incoming = incoming; + if(_incoming) + { + _adapterName = hostOrAdapterName; + } + else + { + _host = hostOrAdapterName; + } + } + + private int handshakeNonBlocking() + { + try + { + HandshakeStatus status = _engine.getHandshakeStatus(); + while(!_engine.isOutboundDone() && !_engine.isInboundDone()) + { + SSLEngineResult result = null; + switch(status) + { + case FINISHED: + case NOT_HANDSHAKING: + { + return IceInternal.SocketOperation.None; + } + case NEED_TASK: + { + Runnable task; + while((task = _engine.getDelegatedTask()) != null) + { + task.run(); + } + status = _engine.getHandshakeStatus(); + break; + } + case NEED_UNWRAP: + { + if(_netInput.b.position() == 0) + { + int s = _delegate.read(_netInput); + if(s != IceInternal.SocketOperation.None && _netInput.b.position() == 0) + { + return s; + } + } + + // + // The engine needs more data. We might already have enough data in + // the _netInput buffer to satisfy the engine. If not, the engine + // responds with BUFFER_UNDERFLOW and we'll read from the socket. + // + _netInput.b.flip(); + result = _engine.unwrap(_netInput.b, _appInput); + _netInput.b.compact(); + // + // FINISHED is only returned from wrap or unwrap, not from engine.getHandshakeResult(). + // + status = result.getHandshakeStatus(); + switch(result.getStatus()) + { + case BUFFER_OVERFLOW: + { + assert(false); + break; + } + case BUFFER_UNDERFLOW: + { + assert(status == javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP); + int position = _netInput.b.position(); + int s = _delegate.read(_netInput); + if(s != IceInternal.SocketOperation.None && _netInput.b.position() == position) + { + return s; + } + break; + } + case CLOSED: + { + throw new Ice.ConnectionLostException(); + } + case OK: + { + break; + } + } + break; + } + case NEED_WRAP: + { + // + // The engine needs to send a message. + // + result = _engine.wrap(_emptyBuffer, _netOutput.b); + if(result.bytesProduced() > 0) + { + int s = flushNonBlocking(); + if(s != IceInternal.SocketOperation.None) + { + return s; + } + } + + // + // FINISHED is only returned from wrap or unwrap, not from engine.getHandshakeResult(). + // + status = result.getHandshakeStatus(); + break; + } + } + + if(result != null) + { + switch(result.getStatus()) + { + case BUFFER_OVERFLOW: + assert(false); + break; + case BUFFER_UNDERFLOW: + // Need to read again. + assert(status == HandshakeStatus.NEED_UNWRAP); + break; + case CLOSED: + throw new Ice.ConnectionLostException(); + case OK: + break; + } + } + } + } + catch(SSLException ex) + { + throw new Ice.SecurityException("IceSSL: handshake error", ex); + } + return IceInternal.SocketOperation.None; + } + + private int writeNonBlocking(ByteBuffer buf) + { + // + // This method has two purposes: encrypt the application's message buffer into our + // _netOutput buffer, and write the contents of _netOutput to the socket without + // blocking. + // + try + { + while(buf.hasRemaining() || _netOutput.b.position() > 0) + { + if(buf.hasRemaining()) + { + // + // Encrypt the buffer. + // + SSLEngineResult result = _engine.wrap(buf, _netOutput.b); + switch(result.getStatus()) + { + case BUFFER_OVERFLOW: + // + // Need to make room in _netOutput.b. + // + break; + case BUFFER_UNDERFLOW: + assert(false); + break; + case CLOSED: + throw new Ice.ConnectionLostException(); + case OK: + break; + } + } + + // + // Write the encrypted data to the socket. We continue writing until we've written + // all of _netOutput, or until flushNonBlocking indicates that it cannot write + // (i.e., by returning SocketOperation.Write). + // + if(_netOutput.b.position() > 0) + { + int s = flushNonBlocking(); + if(s != IceInternal.SocketOperation.None) + { + return s; + } + } + } + } + catch(SSLException ex) + { + throw new Ice.SecurityException("IceSSL: error while encoding message", ex); + } + + assert(_netOutput.b.position() == 0); + return IceInternal.SocketOperation.None; + } + + private int flushNonBlocking() + { + _netOutput.b.flip(); + + try + { + int s = _delegate.write(_netOutput); + if(s != IceInternal.SocketOperation.None) + { + _netOutput.b.compact(); + return s; + } + } + catch(Ice.SocketException ex) + { + throw new Ice.ConnectionLostException(ex); + } + _netOutput.b.clear(); + return IceInternal.SocketOperation.None; + } + + private void fill(ByteBuffer buf) + { + _appInput.flip(); + if(_appInput.hasRemaining()) + { + int bytesAvailable = _appInput.remaining(); + int bytesNeeded = buf.remaining(); + if(bytesAvailable > bytesNeeded) + { + bytesAvailable = bytesNeeded; + } + if(buf.hasArray()) + { + // + // Copy directly into the destination buffer's backing array. + // + byte[] arr = buf.array(); + _appInput.get(arr, buf.arrayOffset() + buf.position(), bytesAvailable); + buf.position(buf.position() + bytesAvailable); + } + else if(_appInput.hasArray()) + { + // + // Copy directly from the source buffer's backing array. + // + byte[] arr = _appInput.array(); + buf.put(arr, _appInput.arrayOffset() + _appInput.position(), bytesAvailable); + _appInput.position(_appInput.position() + bytesAvailable); + } + else + { + // + // Copy using a temporary array. + // + byte[] arr = new byte[bytesAvailable]; + _appInput.get(arr); + buf.put(arr); + } + } + _appInput.compact(); + } + + private Instance _instance; + private IceInternal.Transceiver _delegate; + private javax.net.ssl.SSLEngine _engine; + private String _host = ""; + private String _adapterName = ""; + private boolean _incoming; + private IceInternal.ReadyCallback _readyCallback; + private boolean _isConnected = false; + + private ByteBuffer _appInput; // Holds clear-text data to be read by the application. + private IceInternal.Buffer _netInput; // Holds encrypted data read from the socket. + private IceInternal.Buffer _netOutput; // Holds encrypted data to be written to the socket. + private static ByteBuffer _emptyBuffer = ByteBuffer.allocate(0); // Used during handshaking. +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java b/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java new file mode 100644 index 00000000000..ba17851dee8 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java @@ -0,0 +1,362 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +class TrustManager +{ + TrustManager(Ice.Communicator communicator) + { + assert communicator != null; + _communicator = communicator; + Ice.Properties properties = communicator.getProperties(); + _traceLevel = properties.getPropertyAsInt("IceSSL.Trace.Security"); + String key = null; + try + { + key = "IceSSL.TrustOnly"; + parse(properties.getProperty(key), _rejectAll, _acceptAll); + key = "IceSSL.TrustOnly.Client"; + parse(properties.getProperty(key), _rejectClient, _acceptClient); + key = "IceSSL.TrustOnly.Server"; + parse(properties.getProperty(key), _rejectAllServer, _acceptAllServer); + java.util.Map<String, String> dict = properties.getPropertiesForPrefix("IceSSL.TrustOnly.Server."); + for(java.util.Map.Entry<String, String> p : dict.entrySet()) + { + key = p.getKey(); + String name = key.substring("IceSSL.TrustOnly.Server.".length()); + java.util.List<java.util.List<RFC2253.RDNPair> > reject = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + java.util.List<java.util.List<RFC2253.RDNPair> > accept = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + parse(p.getValue(), reject, accept); + if(!reject.isEmpty()) + { + _rejectServer.put(name, reject); + } + if(!accept.isEmpty()) + { + _acceptServer.put(name, accept); + } + } + } + catch(RFC2253.ParseException e) + { + Ice.PluginInitializationException ex = new Ice.PluginInitializationException(); + ex.reason = "IceSSL: invalid property " + key + ":\n" + e.reason; + throw ex; + } + } + + boolean + verify(NativeConnectionInfo info, String desc) + { + java.util.List<java.util.List<java.util.List<RFC2253.RDNPair> > > + reject = new java.util.LinkedList<java.util.List<java.util.List<RFC2253.RDNPair> > >(), + accept = new java.util.LinkedList<java.util.List<java.util.List<RFC2253.RDNPair> > >(); + + if(!_rejectAll.isEmpty()) + { + reject.add(_rejectAll); + } + if(info.incoming) + { + if(!_rejectAllServer.isEmpty()) + { + reject.add(_rejectAllServer); + } + if(info.adapterName.length() > 0) + { + java.util.List<java.util.List<RFC2253.RDNPair> > p = _rejectServer.get(info.adapterName); + if(p != null) + { + reject.add(p); + } + } + } + else + { + if(!_rejectClient.isEmpty()) + { + reject.add(_rejectClient); + } + } + + if(!_acceptAll.isEmpty()) + { + accept.add(_acceptAll); + } + if(info.incoming) + { + if(!_acceptAllServer.isEmpty()) + { + accept.add(_acceptAllServer); + } + if(info.adapterName.length() > 0) + { + java.util.List<java.util.List<RFC2253.RDNPair> > p = _acceptServer.get(info.adapterName); + if(p != null) + { + accept.add(p); + } + } + } + else + { + if(!_acceptClient.isEmpty()) + { + accept.add(_acceptClient); + } + } + + // + // If there is nothing to match against, then we accept the cert. + // + if(reject.isEmpty() && accept.isEmpty()) + { + return true; + } + + // + // If there is no certificate then we match false. + // + if(info.nativeCerts != null && info.nativeCerts.length > 0) + { + javax.security.auth.x500.X500Principal subjectDN = ((java.security.cert.X509Certificate)info.nativeCerts[0]).getSubjectX500Principal(); + String subjectName = subjectDN.getName(javax.security.auth.x500.X500Principal.RFC2253); + assert subjectName != null; + try + { + // + // Decompose the subject DN into the RDNs. + // + if(_traceLevel > 0) + { + if(info.incoming) + { + _communicator.getLogger().trace("Security", "trust manager evaluating client:\n" + + "subject = " + subjectName + "\n" + + "adapter = " + info.adapterName + "\n" + + desc); + } + else + { + _communicator.getLogger().trace("Security", "trust manager evaluating server:\n" + + "subject = " + subjectName + "\n" + desc); + } + } + java.util.List<RFC2253.RDNPair> dn = RFC2253.parseStrict(subjectName); + + // + // Fail if we match anything in the reject set. + // + for(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet : reject) + { + if(_traceLevel > 1) + { + StringBuilder s = new StringBuilder("trust manager rejecting PDNs:\n"); + stringify(matchSet, s); + _communicator.getLogger().trace("Security", s.toString()); + } + if(match(matchSet, dn)) + { + return false; + } + } + + // + // Succeed if we match anything in the accept set. + // + for(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet : accept) + { + if(_traceLevel > 1) + { + StringBuilder s = new StringBuilder("trust manager accepting PDNs:\n"); + stringify(matchSet, s); + _communicator.getLogger().trace("Security", s.toString()); + } + if(match(matchSet, dn)) + { + return true; + } + } + } + catch(RFC2253.ParseException e) + { + _communicator.getLogger().warning( + "IceSSL: unable to parse certificate DN `" + subjectName + "'\nreason: " + e.reason); + } + + // + // At this point we accept the connection if there are no explicit accept rules. + // + return accept.isEmpty(); + } + + return false; + } + + private boolean + match(java.util.List<java.util.List<RFC2253.RDNPair> > matchSet, java.util.List<RFC2253.RDNPair> subject) + { + for(java.util.List<RFC2253.RDNPair> r : matchSet) + { + if(matchRDNs(r, subject)) + { + return true; + } + } + return false; + } + + private boolean + matchRDNs(java.util.List<RFC2253.RDNPair> match, java.util.List<RFC2253.RDNPair> subject) + { + for(RFC2253.RDNPair matchRDN : match) + { + boolean found = false; + for(RFC2253.RDNPair subjectRDN : subject) + { + if(matchRDN.key.equals(subjectRDN.key)) + { + found = true; + if(!matchRDN.value.equals(subjectRDN.value)) + { + return false; + } + } + } + if(!found) + { + return false; + } + } + return true; + } + + void + parse(String value, java.util.List<java.util.List<RFC2253.RDNPair> > reject, + java.util.List<java.util.List<RFC2253.RDNPair> > accept) + throws RFC2253.ParseException + { + // + // Java X500Principal.getName says: + // + // If "RFC2253" is specified as the format, this method emits + // the attribute type keywords defined in RFC 2253 (CN, L, ST, + // O, OU, C, STREET, DC, UID). Any other attribute type is + // emitted as an OID. Under a strict reading, RFC 2253 only + // specifies a UTF-8 string representation. The String + // returned by this method is the Unicode string achieved by + // decoding this UTF-8 representation. + // + // This means that things like emailAddress and such will be turned into + // something like: + // + // 1.2.840.113549.1.9.1=#160e696e666f407a65726f632e636f6d + // + // The left hand side is the OID (see + // http://www.columbia.edu/~ariel/ssleay/asn1-oids.html) for a + // list. The right hand side is a BER encoding of the value. + // + // This means that the user input, unless it uses the + // unfriendly OID format, will not directly match the + // principal. + // + // Two possible solutions: + // + // Have the RFC2253 parser convert anything that is not CN, L, + // ST, O, OU, C, STREET, DC, UID into OID format, and have it + // convert the values into a BER encoding. + // + // Send the user data through X500Principal to string form and + // then through the RFC2253 encoder. This uses the + // X500Principal to do the encoding for us. + // + // The latter is much simpler, however, it means we need to + // send the data through the parser twice because we split the + // DNs on ';' which cannot be blindly split because of quotes, + // \ and such. + // + java.util.List<RFC2253.RDNEntry> l = RFC2253.parse(value); + for(RFC2253.RDNEntry e : l) + { + StringBuilder v = new StringBuilder(); + boolean first = true; + for(RFC2253.RDNPair pair : e.rdn) + { + if(!first) + { + v.append(","); + } + first = false; + v.append(pair.key); + v.append("="); + v.append(pair.value); + } + javax.security.auth.x500.X500Principal princ = new javax.security.auth.x500.X500Principal(v.toString()); + String subjectName = princ.getName(javax.security.auth.x500.X500Principal.RFC2253); + if(e.negate) + { + reject.add(RFC2253.parseStrict(subjectName)); + } + else + { + accept.add(RFC2253.parseStrict(subjectName)); + } + } + } + + private static void + stringify(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet, StringBuilder s) + { + boolean addSemi = false; + for(java.util.List<RFC2253.RDNPair> rdnSet : matchSet) + { + if(addSemi) + { + s.append(';'); + } + addSemi = true; + boolean addComma = false; + for(RFC2253.RDNPair rdn : rdnSet) + { + if(addComma) + { + s.append(','); + } + addComma = true; + s.append(rdn.key); + s.append('='); + s.append(rdn.value); + } + } + } + + private Ice.Communicator _communicator; + private int _traceLevel; + + private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectAll = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectClient = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectAllServer = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + private java.util.Map<String, java.util.List<java.util.List<RFC2253.RDNPair> > > _rejectServer = + new java.util.HashMap<String, java.util.List<java.util.List<RFC2253.RDNPair> > >(); + + private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptAll = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptClient = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptAllServer = + new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); + private java.util.Map<String, java.util.List<java.util.List<RFC2253.RDNPair> > > _acceptServer = + new java.util.HashMap<String, java.util.List<java.util.List<RFC2253.RDNPair> > >(); +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/Util.java b/java-compat/src/Ice/src/main/java/IceSSL/Util.java new file mode 100644 index 00000000000..53a71e15896 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/Util.java @@ -0,0 +1,72 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +public final class Util +{ + // + // Create a certificate from a PEM-encoded string. + // + public static java.security.cert.X509Certificate + createCertificate(String certPEM) + throws java.security.cert.CertificateException + { + final String header = "-----BEGIN CERTIFICATE-----"; + final String footer = "-----END CERTIFICATE-----"; + + // + // The generateCertificate method requires that its input begin + // with the PEM header. + // + int pos = certPEM.indexOf(header); + if(pos == -1) + { + certPEM = header + "\n" + certPEM; + } + else if(pos > 0) + { + certPEM = certPEM.substring(pos); + } + + // + // Add the footer if necessary. + // + if(certPEM.indexOf(footer) == -1) + { + certPEM = certPEM + footer; + } + + byte[] bytes = null; + try + { + bytes = certPEM.getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + return null; + } + + java.io.ByteArrayInputStream in = new java.io.ByteArrayInputStream(bytes); + java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509"); + return (java.security.cert.X509Certificate)cf.generateCertificate(in); + } + + public final static String jdkTarget = "1.5"; + + // + // Needed by the test scripts to determine the JDK target of the SSL plug-in. + // + public static void + main(String[] args) + { + System.out.println(jdkTarget); + } +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/X509KeyManagerI.java b/java-compat/src/Ice/src/main/java/IceSSL/X509KeyManagerI.java new file mode 100644 index 00000000000..70ca764bfa1 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/X509KeyManagerI.java @@ -0,0 +1,114 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +import javax.net.ssl.X509ExtendedKeyManager; + +final class X509KeyManagerI extends X509ExtendedKeyManager +{ + X509KeyManagerI(javax.net.ssl.X509ExtendedKeyManager del, String alias, boolean override) + { + _delegate = del; + _alias = alias; + _override = override; // Always use the configured alias, don't check for acceptable issuers + } + + @Override + public String + chooseClientAlias(String[] keyType, java.security.Principal[] issuers, java.net.Socket socket) + { + if(!_override) // Don't bother checking for acceptable issuers if the user configured IceSSL.Alias + { + String alias = _delegate.chooseClientAlias(keyType, issuers, socket); + if(alias != null && !alias.isEmpty()) + { + return alias; + } + } + return _alias; + } + + @Override + public String + chooseEngineClientAlias(String[] keyType, java.security.Principal[] issuers, javax.net.ssl.SSLEngine engine) + { + if(!_override) // Don't bother checking for acceptable issuers if the user configured IceSSL.Alias + { + String alias = _delegate.chooseEngineClientAlias(keyType, issuers, engine); + if(alias != null && !alias.isEmpty()) + { + return alias; + } + } + return _alias; + } + + @Override + public String + chooseServerAlias(String keyType, java.security.Principal[] issuers, java.net.Socket socket) + { + if(!_override) // Don't bother checking for acceptable issuers if the user configured IceSSL.Alias + { + String alias = _delegate.chooseServerAlias(keyType, issuers, socket); + if(alias != null && !alias.isEmpty()) + { + return alias; + } + } + return _alias; + } + + @Override + public String + chooseEngineServerAlias(String keyType, java.security.Principal[] issuers, javax.net.ssl.SSLEngine engine) + { + if(!_override) // Don't bother checking for acceptable issuers if the user configured IceSSL.Alias + { + String alias = _delegate.chooseEngineServerAlias(keyType, issuers, engine); + if(alias != null && !alias.isEmpty()) + { + return alias; + } + } + return _alias; + } + + @Override + public java.security.cert.X509Certificate[] + getCertificateChain(String alias) + { + return _delegate.getCertificateChain(alias); + } + + @Override + public String[] + getClientAliases(String keyType, java.security.Principal[] issuers) + { + return _delegate.getClientAliases(keyType, issuers); + } + + @Override + public String[] + getServerAliases(String keyType, java.security.Principal[] issuers) + { + return _delegate.getServerAliases(keyType, issuers); + } + + @Override + public java.security.PrivateKey + getPrivateKey(String alias) + { + return _delegate.getPrivateKey(alias); + } + + private javax.net.ssl.X509ExtendedKeyManager _delegate; + private String _alias; + private boolean _override; +} diff --git a/java-compat/src/Ice/src/main/java/IceSSL/X509TrustManagerI.java b/java-compat/src/Ice/src/main/java/IceSSL/X509TrustManagerI.java new file mode 100644 index 00000000000..57d03e5200e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceSSL/X509TrustManagerI.java @@ -0,0 +1,82 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceSSL; + +final class X509TrustManagerI implements javax.net.ssl.X509TrustManager +{ + X509TrustManagerI(SSLEngine engine, javax.net.ssl.X509TrustManager delegate) + { + _engine = engine; + _delegate = delegate; + } + + @Override + public void + checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException + { + // + // Do not invoke the wrapped trust manager for anonymous ciphers. + // + // Possible values for authType are "DH_anon" and "ECDH_anon" (IBM JDK). + // + if(authType.indexOf("DH_anon") == -1) + { + try + { + _delegate.checkClientTrusted(chain, authType); + } + catch(java.security.cert.CertificateException ex) + { + _engine.trustManagerFailure(true, ex); + } + } + } + + @Override + public void + checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException + { + // + // Do not invoke the wrapped trust manager for anonymous ciphers. + // + // Possible values for authType are "DH_anon" and "ECDH_anon" (IBM JDK). + // + if(authType.indexOf("DH_anon") == -1) + { + try + { + _delegate.checkServerTrusted(chain, authType); + } + catch(java.security.cert.CertificateException ex) + { + _engine.trustManagerFailure(false, ex); + } + } + } + + @Override + public java.security.cert.X509Certificate[] + getAcceptedIssuers() + { + // + // This method is used to send CA names to the client as part of the CertificateRequest + // message sent by the server to request a client certificate. We want the client to always + // send its certificate so we don't provide any CAs here. + // + //return _delegate.getAcceptedIssuers(); + return EMPTY; + } + + private SSLEngine _engine; + private javax.net.ssl.X509TrustManager _delegate; + private java.security.cert.X509Certificate[] EMPTY = new java.security.cert.X509Certificate[0]; +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/Assert.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/Assert.java new file mode 100644 index 00000000000..545bed9c635 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/Assert.java @@ -0,0 +1,45 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public final class Assert +{ + // + // The JVM ignores exceptions raised in finalizers, therefore finalizers + // that use assertions should call this method instead of assert(). + // + public static void + FinalizerAssert(boolean b) + { + if(!b) + { + // + // Create a Throwable to obtain the stack trace. + // + Throwable t = new Throwable(); + StackTraceElement[] trace = t.getStackTrace(); + if(trace.length > 1) + { + // + // Skip the first frame, which represents this method. + // + System.err.println("Assertion failure:"); + for(StackTraceElement e : trace) + { + System.err.println("\tat " + e); + } + } + else + { + System.err.println("Assertion failure (no stack trace information)"); + } + } + } +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/Base64.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/Base64.java new file mode 100644 index 00000000000..661a464649e --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/Base64.java @@ -0,0 +1,270 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public class Base64 +{ + +public static String +encode(byte[] plainSeq) +{ + if(plainSeq == null || plainSeq.length == 0) + { + return ""; + } + + int base64Bytes = (((plainSeq.length * 4) / 3) + 1); + int newlineBytes = (((base64Bytes * 2) / 76) + 1); + int totalBytes = base64Bytes + newlineBytes; + + StringBuilder retval = new StringBuilder(totalBytes); + + int by1; + int by2; + int by3; + int by4; + int by5; + int by6; + int by7; + + for(int i = 0; i < plainSeq.length; i += 3) + { + by1 = plainSeq[i] & 0xff; + by2 = 0; + by3 = 0; + + if((i + 1) < plainSeq.length) + { + by2 = plainSeq[i+1] & 0xff; + } + + if((i + 2) < plainSeq.length) + { + by3 = plainSeq[i+2] & 0xff; + } + + by4 = (by1 >> 2) & 0xff; + by5 = (((by1 & 0x3) << 4) | (by2 >> 4)) & 0xff; + by6 = (((by2 & 0xf) << 2) | (by3 >> 6)) & 0xff; + by7 = by3 & 0x3f; + + retval.append(encode((byte)by4)); + retval.append(encode((byte)by5)); + + if((i + 1) < plainSeq.length) + { + retval.append(encode((byte)by6)); + } + else + { + retval.append('='); + } + + if((i + 2) < plainSeq.length) + { + retval.append(encode((byte)by7)); + } + else + { + retval.append('='); + } + } + + StringBuilder outString = new StringBuilder(totalBytes); + int iter = 0; + + while((retval.length() - iter) > 76) + { + outString.append(retval.substring(iter, iter + 76)); + outString.append("\r\n"); + iter += 76; + } + + outString.append(retval.substring(iter)); + + return outString.toString(); +} + +public static byte[] +decode(String str) +{ + StringBuilder newStr = new StringBuilder(str.length()); + + for(int j = 0; j < str.length(); j++) + { + char c = str.charAt(j); + if(isBase64(c)) + { + newStr.append(c); + } + } + + if(newStr.length() == 0) + { + return null; + } + + // Note: This is how we were previously computing the size of the return + // sequence. The method below is more efficient (and correct). + // size_t lines = str.size() / 78; + // size_t totalBytes = (lines * 76) + (((str.size() - (lines * 78)) * 3) / 4); + + // Figure out how long the final sequence is going to be. + int totalBytes = (newStr.length() * 3 / 4) + 1; + + java.nio.ByteBuffer retval = java.nio.ByteBuffer.allocate(totalBytes); + + int by1; + int by2; + int by3; + int by4; + + char c1, c2, c3, c4; + + int pos = 0; + for(int i = 0; i < newStr.length(); i += 4) + { + c1 = 'A'; + c2 = 'A'; + c3 = 'A'; + c4 = 'A'; + + c1 = newStr.charAt(i); + + if((i + 1) < newStr.length()) + { + c2 = newStr.charAt(i + 1); + } + + if((i + 2) < newStr.length()) + { + c3 = newStr.charAt(i + 2); + } + + if((i + 3) < newStr.length()) + { + c4 = newStr.charAt(i + 3); + } + + by1 = decode(c1) & 0xff; + by2 = decode(c2) & 0xff; + by3 = decode(c3) & 0xff; + by4 = decode(c4) & 0xff; + + retval.put((byte)((by1 << 2) | (by2 >> 4))); + ++pos; + + if(c3 != '=') + { + retval.put((byte)(((by2 & 0xf) << 4) | (by3 >> 2))); + ++pos; + } + + if(c4 != '=') + { + retval.put((byte)(((by3 & 0x3) << 6) | by4)); + ++pos; + } + } + + byte[] arr = new byte[pos]; + System.arraycopy(retval.array(), 0, arr, 0, pos); + return arr; +} + +public static boolean +isBase64(char c) +{ + if(c >= 'A' && c <= 'Z') + { + return true; + } + + if(c >= 'a' && c <= 'z') + { + return true; + } + + if(c >= '0' && c <= '9') + { + return true; + } + + if(c == '+') + { + return true; + } + + if(c == '/') + { + return true; + } + + if(c == '=') + { + return true; + } + + return false; +} + +private static char +encode(byte uc) +{ + if(uc < 26) + { + return (char)('A' + uc); + } + + if(uc < 52) + { + return (char)('a' + (uc - 26)); + } + + if(uc < 62) + { + return (char)('0' + (uc - 52)); + } + + if(uc == 62) + { + return '+'; + } + + return '/'; +} + +private static byte +decode(char c) +{ + if(c >= 'A' && c <= 'Z') + { + return (byte)(c - 'A'); + } + + if(c >= 'a' && c <= 'z') + { + return (byte)(c - 'a' + 26); + } + + if(c >= '0' && c <= '9') + { + return (byte)(c - '0' + 52); + } + + if(c == '+') + { + return 62; + } + + return 63; +} + +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/Options.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/Options.java new file mode 100644 index 00000000000..a16c0ed56ac --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/Options.java @@ -0,0 +1,403 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public final class Options +{ + static public final class BadQuote extends Exception + { + BadQuote(String message) + { + super(message); + } + } + + static public String[] + split(String line) + throws BadQuote + { + final String IFS = " \t\n"; + final int NormalState = 1; + final int DoubleQuoteState = 2; + final int SingleQuoteState = 3; + final int ANSIQuoteState = 4; + + line = line.trim(); + if(line.length() == 0) + { + return new String[0]; + } + + int state = NormalState; + + StringBuilder arg = new StringBuilder(128); + java.util.List<String> vec = new java.util.ArrayList<String>(); + + for(int i = 0; i < line.length(); ++i) + { + char c = line.charAt(i); + switch(state) + { + case NormalState: + { + switch(c) + { + case '\\': + { + // + // Ignore a backslash at the end of the string, + // and strip backslash-newline pairs. If a + // backslash is followed by a space, single quote, + // double quote, or dollar sign, we drop the backslash + // and write the space, single quote, double quote, + // or dollar sign. This is necessary to allow quotes + // to be escaped. Dropping the backslash preceding a + // space deviates from bash quoting rules, but is + // necessary so we don't drop backslashes from Windows + // path names.) + // + if(i < line.length() - 1 && line.charAt(++i) != '\n') + { + switch(line.charAt(i)) + { + case ' ': + case '$': + case '\\': + case '"': + { + arg.append(line.charAt(i)); + break; + } + default: + { + arg.append('\\'); + arg.append(line.charAt(i)); + break; + } + } + } + break; + } + case '\'': + { + state = SingleQuoteState; + break; + } + case '"': + { + state = DoubleQuoteState; + break; + } + case '$': + { + if(i < line.length() - 1 && line.charAt(i + 1) == '\'') + { + state = ANSIQuoteState; // Bash uses $'<text>' to allow ANSI escape sequences within <text>. + ++i; + } + else + { + arg.append('$'); + } + break; + } + default: + { + if(IFS.indexOf(line.charAt(i)) != -1) + { + vec.add(arg.toString()); + arg = new StringBuilder(128); + + // + // Move to start of next argument. + // + while(++i < line.length() && IFS.indexOf(line.charAt(i)) != -1); + --i; + } + else + { + arg.append(line.charAt(i)); + } + break; + } + } + break; + } + case DoubleQuoteState: + { + // + // Within double quotes, only backslash retains its special + // meaning, and only if followed by double quote, backslash, + // or newline. If not followed by one of these characters, + // both the backslash and the character are preserved. + // + if(c == '\\' && i < line.length() - 1) + { + switch(c = line.charAt(++i)) + { + case '"': + case '\\': + case '\n': + { + arg.append(c); + break; + } + default: + { + arg.append('\\'); + arg.append(c); + break; + } + } + } + else if(c == '"') // End of double-quote mode. + { + state = NormalState; + } + else + { + arg.append(c); // Everything else is taken literally. + } + break; + } + case SingleQuoteState: + { + if(c == '\'') // End of single-quote mode. + { + state = NormalState; + } + else + { + arg.append(c); // Everything else is taken literally. + } + break; + } + case ANSIQuoteState: + { + switch(c) + { + case '\\': + { + if(i == line.length() - 1) + { + break; + } + switch(c = line.charAt(++i)) + { + // + // Single-letter escape sequences. + // + case 'a': + { + arg.append('\007'); + break; + } + case 'b': + { + arg.append('\b'); + break; + } + case 'f': + { + arg.append('\f'); + break; + } + case 'n': + { + arg.append('\n'); + break; + } + case 'r': + { + arg.append('\r'); + break; + } + case 't': + { + arg.append('\t'); + break; + } + case 'v': + { + arg.append('\013'); + break; + } + case '\\': + { + arg.append('\\'); + break; + } + case '\'': + { + arg.append('\''); + break; + } + case 'e': // Not ANSI-C, but used by bash. + { + arg.append('\033'); + break; + } + + // + // Process up to three octal digits. + // + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + final String octalDigits = "01234567"; + short us = 0; + int j; + for(j = i; + j < i + 3 && j < line.length() && octalDigits.indexOf(c = line.charAt(j)) != -1; + ++j) + { + us = (short)(us * 8 + c - '0'); + } + i = j - 1; + arg.append((char)us); + break; + } + + // + // Process up to two hex digits. + // + case 'x': + { + final String hexDigits = "0123456789abcdefABCDEF"; + if(i < line.length() - 1 && hexDigits.indexOf(line.charAt(i + 1)) == -1) + { + arg.append('\\'); + arg.append('x'); + break; + } + + short s = 0; + int j; + for(j = i + 1; + j < i + 3 && j < line.length() && hexDigits.indexOf(c = line.charAt(j)) != -1; + ++j) + { + s *= 16; + if(Character.isDigit(c)) + { + s += (short)(c - '0'); + } + else if(Character.isLowerCase(c)) + { + s += (short)(c - 'a' + 10); + } + else + { + s += (short)(c - 'A' + 10); + } + } + i = j - 1; + arg.append((char)s); + break; + } + + // + // Process control-chars. + // + case 'c': + { + c = line.charAt(++i); + if((Character.toUpperCase(c) >= 'A' && Character.toUpperCase(c) <= 'Z') || + c == '@' || + (c >= '[' && c <= '_')) + { + arg.append((char)(Character.toUpperCase(c) - '@')); + } + else + { + // + // Bash does not define what should happen if a \c + // is not followed by a recognized control character. + // We simply treat this case like other unrecognized + // escape sequences, that is, we preserve the escape + // sequence unchanged. + // + arg.append('\\'); + arg.append('c'); + arg.append(c); + } + break; + } + + // + // If inside an ANSI-quoted string, a backslash isn't followed by + // one of the recognized characters, both the backslash and the + // character are preserved. + // + default: + { + arg.append('\\'); + arg.append(c); + break; + } + } + break; + } + case '\'': // End of ANSI-quote mode. + { + state = NormalState; + break; + } + default: + { + arg.append(c); // Everything else is taken literally. + break; + } + } + break; + } + default: + assert(false); + break; + } + } + + switch(state) + { + case NormalState: + { + vec.add(arg.toString()); + break; + } + case SingleQuoteState: + { + throw new BadQuote("missing closing single quote"); + } + case DoubleQuoteState: + { + throw new BadQuote("missing closing double quote"); + } + case ANSIQuoteState: + { + throw new BadQuote("unterminated $' quote"); + } + default: + { + assert(false); + break; + } + } + + return vec.toArray(new String[0]); + } + + +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/OutputBase.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/OutputBase.java new file mode 100644 index 00000000000..7638be77c0b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/OutputBase.java @@ -0,0 +1,188 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public class OutputBase +{ + public + OutputBase() + { + _out = null; + _pos = 0; + _indent = 0; + _indentSize = 4; + _useTab = true; + _separator = true; + } + + public + OutputBase(java.io.PrintWriter out) + { + _out = out; + _pos = 0; + _indent = 0; + _indentSize = 4; + _useTab = true; + _separator = true; + } + + public + OutputBase(String s) + { + _out = null; + _pos = 0; + _indent = 0; + _indentSize = 4; + _useTab = true; + _separator = true; + + open(s); + } + + public void + setIndent(int indentSize) + { + _indentSize = indentSize; + } + + public void + setUseTab(boolean useTab) + { + _useTab = useTab; + } + + public void + open(String s) + { + try + { + java.io.FileWriter fw = new java.io.FileWriter(s); + java.io.BufferedWriter bw = new java.io.BufferedWriter(fw); + _out = new java.io.PrintWriter(bw); + } + catch(java.io.IOException ex) + { + } + } + + public void + print(String s) + { + final char[] arr = s.toCharArray(); + for(int i = 0; i < arr.length; i++) + { + if(arr[i] == '\n') + { + _pos = 0; + } + else + { + ++_pos; + } + } + + _out.print(s); + } + + public void + inc() + { + _indent += _indentSize; + } + + public void + dec() + { + assert(_indent >= _indentSize); + _indent -= _indentSize; + } + + public void + useCurrentPosAsIndent() + { + _indentSave.addFirst(_indent); + _indent = _pos; + } + + public void + zeroIndent() + { + _indentSave.addFirst(_indent); + _indent = 0; + } + + public void + restoreIndent() + { + assert(!_indentSave.isEmpty()); + _indent = _indentSave.removeFirst().intValue(); + } + + public void + nl() + { + _out.println(); + _pos = 0; + _separator = true; + + int indent = _indent; + + if(_useTab) + { + while(indent >= 8) + { + indent -= 8; + _out.print('\t'); + _pos += 8; + } + } + else + { + while(indent >= _indentSize) + { + indent -= _indentSize; + _out.print(" "); + _pos += _indentSize; + } + } + + while(indent > 0) + { + --indent; + _out.print(' '); + ++_pos; + } + + _out.flush(); + } + + public void + sp() + { + if(_separator) + { + _out.println(); + } + } + + public boolean + valid() + { + return (_out != null); + } + + protected java.io.PrintWriter _out; + protected int _pos; + protected int _indent; + protected int _indentSize; + protected java.util.LinkedList<Integer> _indentSave = new java.util.LinkedList<Integer>(); + protected boolean _useTab; + protected boolean _separator; +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/StopWatch.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/StopWatch.java new file mode 100644 index 00000000000..137a8cad364 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/StopWatch.java @@ -0,0 +1,42 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public class StopWatch +{ + public void + start() + { + _s = System.nanoTime(); + } + + public long + stop() + { + assert(isStarted()); + long d = (System.nanoTime() - _s) / 1000; + _s = 0; + return d; + } + + public boolean + isStarted() + { + return _s != 0; + } + + public long + delay() + { + return (System.nanoTime() - _s) / 1000; + } + + private long _s = 0; +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java new file mode 100644 index 00000000000..953359c5c4b --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/StringUtil.java @@ -0,0 +1,540 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public final class StringUtil +{ + // + // Return the index of the first character in str to + // appear in match, starting from 0. Returns -1 if none is + // found. + // + public static int + findFirstOf(String str, String match) + { + return findFirstOf(str, match, 0); + } + + // + // Return the index of the first character in str to + // appear in match, starting from start. Returns -1 if none is + // found. + // + public static int + findFirstOf(String str, String match, int start) + { + final int len = str.length(); + for(int i = start; i < len; i++) + { + char ch = str.charAt(i); + if(match.indexOf(ch) != -1) + { + return i; + } + } + + return -1; + } + + // + // Return the index of the first character in str which does + // not appear in match, starting from 0. Returns -1 if none is + // found. + // + public static int + findFirstNotOf(String str, String match) + { + return findFirstNotOf(str, match, 0); + } + + // + // Return the index of the first character in str which does + // not appear in match, starting from start. Returns -1 if none is + // found. + // + public static int + findFirstNotOf(String str, String match, int start) + { + final int len = str.length(); + for(int i = start; i < len; i++) + { + char ch = str.charAt(i); + if(match.indexOf(ch) == -1) + { + return i; + } + } + + return -1; + } + + // + // Write the byte b as an escape sequence if it isn't a printable ASCII + // character and append the escape sequence to sb. Additional characters + // that should be escaped can be passed in special. If b is any of these + // characters, b is preceded by a backslash in sb. + // + private static void + encodeChar(byte b, StringBuilder sb, String special) + { + switch(b) + { + case (byte)'\\': + { + sb.append("\\\\"); + break; + } + case (byte)'\'': + { + sb.append("\\'"); + break; + } + case (byte)'"': + { + sb.append("\\\""); + break; + } + case (byte)'\b': + { + sb.append("\\b"); + break; + } + case (byte)'\f': + { + sb.append("\\f"); + break; + } + case (byte)'\n': + { + sb.append("\\n"); + break; + } + case (byte)'\r': + { + sb.append("\\r"); + break; + } + case (byte)'\t': + { + sb.append("\\t"); + break; + } + default: + { + if(!(b >= 32 && b <= 126)) + { + sb.append('\\'); + String octal = Integer.toOctalString(b < 0 ? b + 256 : b); + // + // Add leading zeroes so that we avoid problems during + // decoding. For example, consider the encoded string + // \0013 (i.e., a character with value 1 followed by + // the character '3'). If the leading zeroes were omitted, + // the result would be incorrectly interpreted by the + // decoder as a single character with value 11. + // + for(int j = octal.length(); j < 3; j++) + { + sb.append('0'); + } + sb.append(octal); + } + else if(special != null && special.indexOf((char)b) != -1) + { + sb.append('\\'); + sb.append((char)b); + } + else + { + sb.append((char)b); + } + } + } + } + + // + // Add escape sequences (such as "\n", or "\007") to make a string + // readable in ASCII. Any characters that appear in special are + // prefixed with a backlash in the returned string. + // + public static String + escapeString(String s, String special) + { + if(special != null) + { + for(int i = 0; i < special.length(); ++i) + { + if(special.charAt(i) < 32 || special.charAt(i) > 126) + { + throw new IllegalArgumentException("special characters must be in ASCII range 32-126"); + } + } + } + + byte[] bytes = null; + try + { + bytes = s.getBytes("UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + assert(false); + return null; + } + + StringBuilder result = new StringBuilder(bytes.length); + for(int i = 0; i < bytes.length; i++) + { + encodeChar(bytes[i], result, special); + } + + return result.toString(); + } + + private static char + checkChar(String s, int pos) + { + char c = s.charAt(pos); + if(!(c >= 32 && c <= 126)) + { + String msg; + if(pos > 0) + { + msg = "character after `" + s.substring(0, pos) + "'"; + } + else + { + msg = "first character"; + } + msg += " is not a printable ASCII character (ordinal " + (int)c + ")"; + throw new IllegalArgumentException(msg); + } + return c; + } + + // + // Decode the character or escape sequence starting at start and return it. + // newStart is set to the index of the first character following the decoded character + // or escape sequence. + // + private static char decodeChar(String s, int start, int end, Ice.Holder<Integer> nextStart) + { + assert(start >= 0); + assert(start < end); + assert(end <= s.length()); + + char c; + + if(s.charAt(start) != '\\') + { + c = checkChar(s, start++); + } + else + { + if(start + 1 == end) + { + throw new IllegalArgumentException("trailing backslash"); + } + switch(s.charAt(++start)) + { + case '\\': + case '\'': + case '"': + { + c = s.charAt(start++); + break; + } + case 'b': + { + ++start; + c = '\b'; + break; + } + case 'f': + { + ++start; + c = '\f'; + break; + } + case 'n': + { + ++start; + c = '\n'; + break; + } + case 'r': + { + ++start; + c = '\r'; + break; + } + case 't': + { + ++start; + c = '\t'; + break; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int val = 0; + for(int j = 0; j < 3 && start < end; ++j) + { + int charVal = s.charAt(start++) - '0'; + if(charVal < 0 || charVal > 7) + { + --start; + break; + } + val = val * 8 + charVal; + } + if(val > 255) + { + String msg = "octal value \\" + Integer.toOctalString(val) + " (" + val + ") is out of range"; + throw new IllegalArgumentException(msg); + } + c = (char)val; + break; + } + default: + { + c = checkChar(s, start++); + break; + } + } + } + nextStart.value = start; + return c; + } + + // + // Remove escape sequences from s and append the result to sb. + // Return true if successful, false otherwise. + // + private static void + decodeString(String s, int start, int end, StringBuilder sb) + { + Ice.Holder<Integer> nextStart = new Ice.Holder<Integer>(); + while(start < end) + { + sb.append(decodeChar(s, start, end, nextStart)); + start = nextStart.value; + } + } + + // + // Remove escape sequences added by escapeString. Throws IllegalArgumentException + // for an invalid input string. + // + public static String + unescapeString(String s, int start, int end) + { + assert(start >= 0 && start <= end && end <= s.length()); + + StringBuilder sb = new StringBuilder(end - start); + decodeString(s, start, end, sb); + String decodedString = sb.toString(); + + byte[] arr = new byte[decodedString.length()]; + for(int i = 0; i < arr.length; ++i) + { + arr[i] = (byte)decodedString.charAt(i); + } + + try + { + return new String(arr, 0, arr.length, "UTF8"); + } + catch(java.io.UnsupportedEncodingException ex) + { + throw new IllegalArgumentException("unsupported encoding", ex); + } + } + + // + // Join a list of strings using the given delimiter. + // + public static String + joinString(java.util.List<String> values, String delimiter) + { + StringBuffer s = new StringBuffer(); + boolean first = true; + for(String v : values) + { + if(!first) + { + s.append(delimiter); + } + s.append(v); + first = false; + } + return s.toString(); + } + + // + // Split string helper; returns null for unmatched quotes + // + static public String[] + splitString(String str, String delim) + { + java.util.List<String> l = new java.util.ArrayList<String>(); + char[] arr = new char[str.length()]; + int pos = 0; + + int n = 0; + char quoteChar = '\0'; + while(pos < str.length()) + { + if(quoteChar == '\0' && (str.charAt(pos) == '"' || str.charAt(pos) == '\'')) + { + quoteChar = str.charAt(pos++); + continue; // Skip the quote. + } + else if(quoteChar == '\0' && str.charAt(pos) == '\\' && pos + 1 < str.length() && + (str.charAt(pos + 1) == '"' || str.charAt(pos + 1) == '\'')) + { + ++pos; // Skip the backslash + } + else if(quoteChar != '\0' && str.charAt(pos) == '\\' && pos + 1 < str.length() && + str.charAt(pos + 1) == quoteChar) + { + ++pos; // Skip the backslash + } + else if(quoteChar != '\0' && str.charAt(pos) == quoteChar) + { + ++pos; + quoteChar = '\0'; + continue; // Skip the quote. + } + else if(delim.indexOf(str.charAt(pos)) != -1) + { + if(quoteChar == '\0') + { + ++pos; + if(n > 0) + { + l.add(new String(arr, 0, n)); + n = 0; + } + continue; + } + } + + if(pos < str.length()) + { + arr[n++] = str.charAt(pos++); + } + } + + if(n > 0) + { + l.add(new String(arr, 0, n)); + } + if(quoteChar != '\0') + { + return null; // Unmatched quote. + } + return l.toArray(new String[0]); + } + + public static int + checkQuote(String s) + { + return checkQuote(s, 0); + } + + // + // If a single or double quotation mark is found at the start position, + // then the position of the matching closing quote is returned. If no + // quotation mark is found at the start position, then 0 is returned. + // If no matching closing quote is found, then -1 is returned. + // + public static int + checkQuote(String s, int start) + { + char quoteChar = s.charAt(start); + if(quoteChar == '"' || quoteChar == '\'') + { + start++; + final int len = s.length(); + int pos; + while(start < len && (pos = s.indexOf(quoteChar, start)) != -1) + { + if(s.charAt(pos - 1) != '\\') + { + return pos; + } + start = pos + 1; + } + return -1; // Unmatched quote + } + return 0; // Not quoted + } + + public static boolean + match(String s, String pat, boolean emptyMatch) + { + assert(s.length() > 0); + assert(pat.length() > 0); + + // + // If pattern does not contain a wildcard just compare strings. + // + int beginIndex = pat.indexOf('*'); + if(beginIndex < 0) + { + return s.equals(pat); + } + + // + // Make sure start of the strings match + // + if(beginIndex > s.length() || !s.substring(0, beginIndex).equals(pat.substring(0, beginIndex))) + { + return false; + } + + // + // Make sure there is something present in the middle to match the + // wildcard. If emptyMatch is true, allow a match of "". + // + int endLength = pat.length() - beginIndex - 1; + if(endLength == 0) + { + return true; + } + if(endLength > s.length()) + { + return false; + } + int endIndex = s.length() - endLength; + if(endIndex < beginIndex || (!emptyMatch && endIndex == beginIndex)) + { + return false; + } + + // + // Make sure end of the strings match + // + if(!s.substring(endIndex, s.length() - endIndex).equals( + pat.substring(beginIndex + 1, pat.length() - beginIndex - 1))) + { + return false; + } + + return true; + } +} diff --git a/java-compat/src/Ice/src/main/java/IceUtilInternal/XMLOutput.java b/java-compat/src/Ice/src/main/java/IceUtilInternal/XMLOutput.java new file mode 100644 index 00000000000..8d6f4ab9569 --- /dev/null +++ b/java-compat/src/Ice/src/main/java/IceUtilInternal/XMLOutput.java @@ -0,0 +1,275 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceUtilInternal; + +public class XMLOutput extends OutputBase +{ + public + XMLOutput() + { + super(); + _se = false; + _text = false; + _sgml = false; + _escape = false; + } + + public + XMLOutput(java.io.PrintWriter writer) + { + super(writer); + _se = false; + _text = false; + _sgml = false; + _escape = false; + } + + public + XMLOutput(String s) + { + super(s); + _se = false; + _text = false; + _sgml = false; + _escape = false; + } + + public void + setSGML(boolean sgml) + { + _sgml = true; + } + + @Override + public void + print(String s) + { + if(_se) + { + _out.print('>'); + _se = false; + } + _text = true; + + if(_escape) + { + String escaped = escape(s); + super.print(escaped); + } + else + { + super.print(s); + } + } + + public XMLOutput + write(String s) + { + print(s); + return this; + } + + @Override + public void + nl() + { + if(_se) + { + _se = false; + _out.print('>'); + } + super.nl(); + } + + public XMLOutput + se(String element) + { + nl(); + + // + // If we're not in SGML mode the output of the '>' character is + // deferred until either the end-element (in which case a /> is + // emitted) or until something is displayed. + // + if(_escape) + { + _out.print('<'); + _out.print(escape(element)); + } + else + { + _out.print('<'); + _out.print(element); + } + _se = true; + _text = false; + + int pos = element.indexOf(' '); + if(pos == -1) + { + pos = element.indexOf('\t'); + } + if(pos == -1) + { + _elementStack.addFirst(element); + } + else + { + _elementStack.addFirst(element.substring(0, pos)); + } + + ++_pos; // TODO: ??? + inc(); + _separator = false; + return this; + } + + public XMLOutput + ee() + { + String element = _elementStack.removeFirst(); + + dec(); + if(_se) + { + // + // SGML (docbook) doesn't support <foo/> + // + if(_sgml) + { + _out.print("></"); + _out.print(element); + _out.print(">"); + } + else + { + _out.print("/>"); + } + } + else + { + if(!_text) + { + nl(); + } + _out.print("</"); + _out.print(element); + _out.print(">"); + } + --_pos; // TODO: ??? + + _se = false; + _text = false; + return this; + } + + public XMLOutput + attr(String name, String value) + { + // + // Precondition: Attributes can only be attached to elements. + // + assert(_se); + _out.print(" "); + _out.print(name); + _out.print("=\""); + _out.print(escape(value)); + _out.print("\""); + return this; + } + + public XMLOutput + startEscapes() + { + _escape = true; + return this; + } + + public XMLOutput + endEscapes() + { + _escape = false; + return this; + } + + public String + currentElement() + { + if(_elementStack.size() > 0) + { + return _elementStack.getFirst(); + } + else + { + return ""; + } + } + + private String + escape(String input) + { + String v = input; + + // + // Find out whether there is a reserved character to avoid + // conversion if not necessary. + // + final String allReserved = "<>'\"&"; + boolean hasReserved = false; + char[] arr = input.toCharArray(); + for(int i = 0; i < arr.length; i++) + { + if(allReserved.indexOf(arr[i]) != -1) + { + hasReserved = true; + break; + } + } + if(hasReserved) + { + // + // First convert all & to & + // + if(v.indexOf('&') != -1) + { + v = v.replaceAll("&", "&"); + } + + // + // Next convert remaining reserved characters. + // + if(v.indexOf('>') != -1) + { + v = v.replaceAll(">", ">"); + } + if(v.indexOf('<') != -1) + { + v = v.replaceAll("<", "<"); + } + if(v.indexOf('\'') != -1) + { + v = v.replaceAll("'", "'"); + } + if(v.indexOf('"') != -1) + { + v = v.replaceAll("\"", """); + } + } + return v; + } + + private java.util.LinkedList<String> _elementStack = new java.util.LinkedList<String>(); + + boolean _se; + boolean _text; + + private boolean _sgml; + private boolean _escape; +} diff --git a/java-compat/src/IceBT/build.gradle b/java-compat/src/IceBT/build.gradle new file mode 100644 index 00000000000..190900f0f07 --- /dev/null +++ b/java-compat/src/IceBT/build.gradle @@ -0,0 +1,37 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IceBT Compat" +project.ext.description = "Bluetooth support for Ice" + +slice { + java { + set1 { + args = "--ice" + files = fileTree(dir: "$sliceDir/IceBT", includes:['*.ice'], excludes:["*F.ice"]) + } + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" + +jar { + // + // The classes in src/main/java/android/bluetooth are stubs that allow us to compile the IceBT transport + // plug-in without requiring an Android SDK. These classes are excluded from the IceBT JAR file. + // + exclude("android/**") +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/AcceptorI.java b/java-compat/src/IceBT/src/main/java/IceBT/AcceptorI.java new file mode 100644 index 00000000000..553e13ae149 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/AcceptorI.java @@ -0,0 +1,224 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +import android.bluetooth.BluetoothSocket; +import android.bluetooth.BluetoothServerSocket; +import java.util.UUID; + +final class AcceptorI implements IceInternal.Acceptor +{ + @Override + public java.nio.channels.ServerSocketChannel fd() + { + return null; + } + + @Override + public void setReadyCallback(IceInternal.ReadyCallback callback) + { + _readyCallback = callback; + } + + @Override + public void close() + { + synchronized(this) + { + _closed = true; + } + + if(_socket != null) + { + try + { + _socket.close(); // Wakes up the thread blocked in accept(). + } + catch(Exception ex) + { + // Ignore. + } + } + if(_thread != null) + { + try + { + _thread.join(); + } + catch(Exception ex) + { + // Ignore. + } + } + } + + @Override + public IceInternal.EndpointI listen() + { + try + { + // + // We always listen using the "secure" method. + // + _socket = _instance.bluetoothAdapter().listenUsingRfcommWithServiceRecord(_name, _uuid); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + + // + // Use a helper thread to perform the blocking accept() calls. + // + _thread = new Thread() + { + public void run() + { + runAccept(); + } + }; + _thread.start(); + + return _endpoint; + } + + @Override + public synchronized IceInternal.Transceiver accept() + { + if(_exception != null) + { + throw new Ice.SocketException(_exception); + } + + // + // accept() should only be called when we have at least one socket ready. + // + assert(!_pending.isEmpty()); + + BluetoothSocket socket = _pending.pop(); + + // + // Update our status with the thread pool. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, !_pending.isEmpty()); + + return new TransceiverI(_instance, socket, _uuid, _adapterName); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public String toString() + { + StringBuffer s = new StringBuffer("local address = "); + s.append(_instance.bluetoothAdapter().getAddress()); + return s.toString(); + } + + @Override + public String toDetailedString() + { + StringBuffer s = new StringBuffer(toString()); + if(!_name.isEmpty()) + { + s.append("\nservice name = '"); + s.append(_name); + s.append("'"); + } + if(_uuid != null) + { + s.append("\nservice uuid = "); + s.append(_uuid.toString()); + } + return s.toString(); + } + + AcceptorI(EndpointI endpoint, Instance instance, String adapterName, UUID uuid, String name) + { + _endpoint = endpoint; + _instance = instance; + _adapterName = adapterName; + _name = name; + _uuid = uuid; + + _pending = new java.util.Stack<BluetoothSocket>(); + _closed = false; + } + + private void runAccept() + { + try + { + while(true) + { + BluetoothSocket socket = _socket.accept(); + synchronized(this) + { + _pending.push(socket); + + // + // Notify the thread pool that we are ready to "read". The thread pool will invoke accept() + // and we can return a new transceiver. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + } + } + } + catch(Exception ex) + { + synchronized(this) + { + if(!_closed) + { + _exception = ex; + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + } + } + } + + // + // Close any remaining incoming sockets that haven't been accepted yet. + // + java.util.Stack<BluetoothSocket> pending; + synchronized(this) + { + pending = _pending; + _pending = null; + } + + for(BluetoothSocket s : pending) + { + try + { + s.close(); + } + catch(Exception ex) + { + // Ignore. + } + } + } + + private EndpointI _endpoint; + private Instance _instance; + private String _adapterName; + private String _name; + private UUID _uuid; + private IceInternal.ReadyCallback _readyCallback; + private BluetoothServerSocket _socket; + private java.util.Stack<BluetoothSocket> _pending; + private Thread _thread; + private Exception _exception; + private boolean _closed; +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/ConnectorI.java b/java-compat/src/IceBT/src/main/java/IceBT/ConnectorI.java new file mode 100644 index 00000000000..e8c8e8d47f5 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/ConnectorI.java @@ -0,0 +1,109 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +import java.util.UUID; + +final class ConnectorI implements IceInternal.Connector +{ + @Override + public IceInternal.Transceiver connect() + { + return new TransceiverI(_instance, _addr, _uuid, _connectionId); + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String toString() + { + StringBuffer buf = new StringBuffer(); + if(!_addr.isEmpty()) + { + buf.append(_addr); + } + if(_uuid != null) + { + if(!_addr.isEmpty()) + { + buf.append(';'); + } + buf.append(_uuid.toString()); + } + return buf.toString(); + } + + @Override + public int hashCode() + { + return _hashCode; + } + + // + // Only for use by EndpointI. + // + ConnectorI(Instance instance, String addr, UUID uuid, int timeout, String connectionId) + { + _instance = instance; + _addr = addr; + _uuid = uuid; + _timeout = timeout; + _connectionId = connectionId; + + _hashCode = 5381; + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _addr); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _uuid); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _timeout); + _hashCode = IceInternal.HashUtil.hashAdd(_hashCode , _connectionId); + } + + @Override + public boolean equals(java.lang.Object obj) + { + if(!(obj instanceof ConnectorI)) + { + return false; + } + + if(this == obj) + { + return true; + } + + ConnectorI p = (ConnectorI)obj; + if(!_uuid.equals(p._uuid)) + { + return false; + } + + if(_timeout != p._timeout) + { + return false; + } + + if(!_connectionId.equals(p._connectionId)) + { + return false; + } + + return _addr.equals(p._addr); + } + + private Instance _instance; + private String _addr; + private UUID _uuid; + private int _timeout; + private String _connectionId; + private int _hashCode; +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/EndpointFactoryI.java b/java-compat/src/IceBT/src/main/java/IceBT/EndpointFactoryI.java new file mode 100644 index 00000000000..5ffc5141907 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/EndpointFactoryI.java @@ -0,0 +1,59 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +final class EndpointFactoryI implements IceInternal.EndpointFactory +{ + EndpointFactoryI(Instance instance) + { + _instance = instance; + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public IceInternal.EndpointI create(java.util.ArrayList<String> args, boolean oaEndpoint) + { + EndpointI endpt = new EndpointI(_instance); + endpt.initWithOptions(args, oaEndpoint); + return endpt; + } + + @Override + public IceInternal.EndpointI read(Ice.InputStream s) + { + return new EndpointI(_instance, s); + } + + @Override + public void destroy() + { + _instance.destroy(); + _instance = null; + } + + @Override + public IceInternal.EndpointFactory clone(IceInternal.ProtocolInstance inst, IceInternal.EndpointFactory del) + { + return new EndpointFactoryI(new Instance(_instance.communicator(), inst.type(), inst.protocol())); + } + + private Instance _instance; +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/EndpointI.java b/java-compat/src/IceBT/src/main/java/IceBT/EndpointI.java new file mode 100644 index 00000000000..7576f458fae --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/EndpointI.java @@ -0,0 +1,551 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +import android.bluetooth.BluetoothAdapter; +import java.util.UUID; + +final class EndpointI extends IceInternal.EndpointI +{ + public EndpointI(Instance instance, String addr, UUID uuid, String name, int channel, int timeout, + String connectionId, boolean compress) + { + _instance = instance; + _addr = addr; + _uuid = uuid; + _name = name; + _channel = channel; + _timeout = timeout; + _connectionId = connectionId; + _compress = compress; + hashInit(); + } + + public EndpointI(Instance instance) + { + _instance = instance; + _addr = ""; + _uuid = null; + _name = ""; + _channel = 0; + _timeout = instance.defaultTimeout(); + _connectionId = ""; + _compress = false; + } + + public EndpointI(Instance instance, Ice.InputStream s) + { + _instance = instance; + + // + // _name and _channel are not marshaled. + // + _name = ""; + _channel = 0; + + _addr = s.readString().toUpperCase(); + if(!BluetoothAdapter.checkBluetoothAddress(_addr)) + { + throw new Ice.MarshalException("invalid address `" + _addr + "' in endpoint"); + } + + try + { + _uuid = UUID.fromString(s.readString()); + } + catch(IllegalArgumentException ex) + { + throw new Ice.MarshalException("invalid UUID for Bluetooth endpoint", ex); + } + + _timeout = s.readInt(); + _compress = s.readBool(); + hashInit(); + } + + @Override + public void streamWriteImpl(Ice.OutputStream s) + { + // + // _name and _channel are not marshaled. + // + s.writeString(_addr); + s.writeString(_uuid.toString()); + s.writeInt(_timeout); + s.writeBool(_compress); + } + + @Override + public short type() + { + return _instance.type(); + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public int timeout() + { + return _timeout; + } + + @Override + public IceInternal.EndpointI timeout(int timeout) + { + if(timeout == _timeout) + { + return this; + } + else + { + return new EndpointI(_instance, _addr, _uuid, _name, _channel, timeout, _connectionId, _compress); + } + } + + @Override + public String connectionId() + { + return _connectionId; + } + + @Override + public IceInternal.EndpointI connectionId(String connectionId) + { + if(connectionId.equals(_connectionId)) + { + return this; + } + else + { + return new EndpointI(_instance, _addr, _uuid, _name, _channel, _timeout, connectionId, _compress); + } + } + + @Override + public boolean compress() + { + return _compress; + } + + @Override + public IceInternal.EndpointI compress(boolean compress) + { + if(compress == _compress) + { + return this; + } + else + { + return new EndpointI(_instance, _addr, _uuid, _name, _channel, _timeout, _connectionId, compress); + } + } + + @Override + public boolean datagram() + { + return false; + } + + @Override + public boolean secure() + { + return _instance.secure(); + } + + @Override + public IceInternal.Transceiver transceiver() + { + return null; + } + + @Override + public void connectors_async(Ice.EndpointSelectionType selType, IceInternal.EndpointI_connectors callback) + { + java.util.List<IceInternal.Connector> conns = new java.util.ArrayList<IceInternal.Connector>(); + conns.add(new ConnectorI(_instance, _addr, _uuid, _timeout, _connectionId)); + callback.connectors(conns); + } + + @Override + public IceInternal.Acceptor acceptor(String adapterName) + { + return new AcceptorI(this, _instance, adapterName, _uuid, _name); + } + + @Override + public java.util.List<IceInternal.EndpointI> expand() + { + java.util.List<IceInternal.EndpointI> endps = new java.util.ArrayList<IceInternal.EndpointI>(); + endps.add(this); + return endps; + } + + @Override + public boolean equivalent(IceInternal.EndpointI endpoint) + { + if(!(endpoint instanceof EndpointI)) + { + return false; + } + EndpointI btEndpointI = (EndpointI)endpoint; + return btEndpointI.type() == type() && btEndpointI._addr.equals(_addr) && btEndpointI._uuid.equals(_uuid) && + btEndpointI._channel == _channel; + } + + @Override + public String options() + { + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + String s = ""; + + if(_addr != null && _addr.length() > 0) + { + s += " -a "; + boolean addQuote = _addr.indexOf(':') != -1; + if(addQuote) + { + s += "\""; + } + s += _addr; + if(addQuote) + { + s += "\""; + } + } + + if(_uuid != null) + { + s += " -u "; + String uuidStr = _uuid.toString(); + boolean addQuote = uuidStr.indexOf(':') != -1; + if(addQuote) + { + s += "\""; + } + s += uuidStr; + if(addQuote) + { + s += "\""; + } + } + + if(_channel > 0) + { + s += " -c " + _channel; + } + + if(_timeout == -1) + { + s += " -t infinite"; + } + else + { + s += " -t " + _timeout; + } + + if(_compress) + { + s += " -z"; + } + + return s; + } + + public void initWithOptions(java.util.ArrayList<String> args, boolean oaEndpoint) + { + super.initWithOptions(args); + + if(_addr.length() == 0) + { + _addr = _instance.defaultHost(); + if(_addr == null) + { + _addr = ""; + } + } + + if(_addr.length() == 0 || _addr.equals("*")) + { + if(oaEndpoint) + { + // + // Ignore a missing address, we always use the default adapter anyway. + // + } + else + { + throw new Ice.EndpointParseException( + "a device address must be specified using the -a option or Ice.Default.Host"); + } + } + + if(_name.length() == 0) + { + _name = "Ice Service"; + } + + if(_uuid == null) + { + if(oaEndpoint) + { + // + // Generate a UUID for object adapters that don't specify one. + // + _uuid = UUID.randomUUID(); + } + else + { + throw new Ice.EndpointParseException("a UUID must be specified using the -u option"); + } + } + + hashInit(); + } + + @Override + public Ice.EndpointInfo getInfo() + { + EndpointInfo info = new EndpointInfo() + { + @Override + public short type() + { + return EndpointI.this.type(); + } + + @Override + public boolean datagram() + { + return EndpointI.this.datagram(); + } + + @Override + public boolean secure() + { + return EndpointI.this.secure(); + } + }; + info.addr = _addr; + info.uuid = _uuid.toString(); + return info; + } + + @Override + public int compareTo(IceInternal.EndpointI obj) // From java.lang.Comparable + { + if(!(obj instanceof EndpointI)) + { + return type() < obj.type() ? -1 : 1; + } + + EndpointI p = (EndpointI)obj; + if(this == p) + { + return 0; + } + + int v = _addr.compareTo(p._addr); + if(v != 0) + { + return v; + } + + v = _uuid.toString().compareTo(p._uuid.toString()); + if(v != 0) + { + return v; + } + + if(_channel < p._channel) + { + return -1; + } + else if(p._channel < _channel) + { + return 1; + } + + if(_timeout < p._timeout) + { + return -1; + } + else if(p._timeout < _timeout) + { + return 1; + } + + v = _connectionId.compareTo(p._connectionId); + if(v != 0) + { + return v; + } + + if(!_compress && p._compress) + { + return -1; + } + else if(!p._compress && _compress) + { + return 1; + } + + return 0; + } + + @Override + public int hashCode() + { + return _hashValue; + } + + @Override + protected boolean checkOption(String option, String argument, String endpoint) + { + if(super.checkOption(option, argument, endpoint)) + { + return true; + } + + if(option.equals("-a")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -a option in endpoint " + endpoint); + } + if(!argument.equals("*") && !BluetoothAdapter.checkBluetoothAddress(argument.toUpperCase())) + { + throw new Ice.EndpointParseException("invalid address provided for -a option in endpoint " + endpoint); + } + _addr = argument.toUpperCase(); // Android requires a hardware address to use upper case letters. + } + else if(option.equals("-u")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -u option in endpoint " + endpoint); + } + try + { + _uuid = UUID.fromString(argument); + } + catch(IllegalArgumentException ex) + { + throw new Ice.EndpointParseException("invalid UUID for Bluetooth endpoint", ex); + } + } + else if(option.equals("-c")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -c option in endpoint " + endpoint); + } + + try + { + _channel = Integer.parseInt(argument); + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid channel value `" + argument + + "' in endpoint " + endpoint); + } + + if(_channel < 0 || _channel > 30) // RFCOMM channel limit is 30 + { + throw new Ice.EndpointParseException("channel value `" + argument + + "' out of range in endpoint " + endpoint); + } + } + else if(option.equals("-t")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for -t option in endpoint " + endpoint); + } + + if(argument.equals("infinite")) + { + _timeout = -1; + } + else + { + try + { + _timeout = Integer.parseInt(argument); + if(_timeout < 1) + { + throw new Ice.EndpointParseException("invalid timeout value `" + argument + "' in endpoint " + + endpoint); + } + } + catch(NumberFormatException ex) + { + throw new Ice.EndpointParseException("invalid timeout value `" + argument + "' in endpoint " + + endpoint); + } + } + } + else if(option.equals("-z")) + { + if(argument != null) + { + throw new Ice.EndpointParseException("unexpected argument `" + argument + + "' provided for -z option in " + endpoint); + } + + _compress = true; + } + else if(option.equals("--name")) + { + if(argument == null) + { + throw new Ice.EndpointParseException("no argument provided for --name option in endpoint " + endpoint); + } + + _name = argument; + } + else + { + return false; + } + return true; + } + + private void hashInit() + { + int h = 5381; + h = IceInternal.HashUtil.hashAdd(h, _addr); + h = IceInternal.HashUtil.hashAdd(h, _uuid.toString()); + h = IceInternal.HashUtil.hashAdd(h, _timeout); + h = IceInternal.HashUtil.hashAdd(h, _connectionId); + h = IceInternal.HashUtil.hashAdd(h, _compress); + _hashValue = h; + } + + private Instance _instance; + private String _addr; + private UUID _uuid; + private String _name; + private int _channel; + private int _timeout; + private String _connectionId; + private boolean _compress; + private int _hashValue; +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/Instance.java b/java-compat/src/IceBT/src/main/java/IceBT/Instance.java new file mode 100644 index 00000000000..db5d516adcb --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/Instance.java @@ -0,0 +1,54 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +import android.bluetooth.BluetoothAdapter; + +class Instance extends IceInternal.ProtocolInstance +{ + Instance(Ice.Communicator communicator, short type, String protocol) + { + // + // We consider the transport to be "secure" because it uses the secure versions Android's Bluetooth API + // methods for establishing and accepting connections. The boolean argument below sets secure=true. + // + super(communicator, type, protocol, true); + + _communicator = communicator; + + _bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if(_bluetoothAdapter == null) + { + throw new Ice.PluginInitializationException("bluetooth adapter not available"); + } + else if(!_bluetoothAdapter.isEnabled()) + { + throw new Ice.PluginInitializationException("bluetooth is not enabled"); + } + } + + void destroy() + { + _communicator = null; + } + + Ice.Communicator communicator() + { + return _communicator; + } + + BluetoothAdapter bluetoothAdapter() + { + return _bluetoothAdapter; + } + + private Ice.Communicator _communicator; + private BluetoothAdapter _bluetoothAdapter; +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/PluginFactory.java b/java-compat/src/IceBT/src/main/java/IceBT/PluginFactory.java new file mode 100644 index 00000000000..fc523108cae --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/PluginFactory.java @@ -0,0 +1,34 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +/** + * Plug-in factories must implement this interface. + **/ +public class PluginFactory implements Ice.PluginFactory +{ + /** + * Returns a new plug-in. + * + * @param communicator The communicator for the plug-in. + * @param name The name of the plug-in. + * @param args The arguments that are specified in the plug-in's configuration. + * + * @return The new plug-in. <code>null</code> can be returned to indicate + * that a general error occurred. Alternatively, <code>create</code> can throw + * {@link PluginInitializationException} to provide more detailed information. + **/ + @Override + public Ice.Plugin + create(Ice.Communicator communicator, String name, String[] args) + { + return new PluginI(communicator); + } +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/PluginI.java b/java-compat/src/IceBT/src/main/java/IceBT/PluginI.java new file mode 100644 index 00000000000..bee179f55ca --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/PluginI.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +class PluginI implements Ice.Plugin +{ + public PluginI(Ice.Communicator communicator) + { + final IceInternal.ProtocolPluginFacade facade = IceInternal.Util.getProtocolPluginFacade(communicator); + + // + // Register the endpoint factory. We have to do this now, rather than + // in initialize, because the communicator may need to interpret + // proxies before the plug-in is fully initialized. + // + EndpointFactoryI factory = new EndpointFactoryI(new Instance(communicator, Ice.BTEndpointType.value, "bt")); + facade.addEndpointFactory(factory); + + IceInternal.EndpointFactory sslFactory = facade.getEndpointFactory(Ice.SSLEndpointType.value); + if(sslFactory != null) + { + Instance instance = new Instance(communicator, Ice.BTSEndpointType.value, "bts"); + facade.addEndpointFactory(sslFactory.clone(instance, new EndpointFactoryI(instance))); + } + } + + @Override + public void initialize() + { + } + + @Override + public void destroy() + { + } +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/TransceiverI.java b/java-compat/src/IceBT/src/main/java/IceBT/TransceiverI.java new file mode 100644 index 00000000000..fe6df651826 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/TransceiverI.java @@ -0,0 +1,693 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +import java.lang.Thread; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.UUID; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; + +final class TransceiverI implements IceInternal.Transceiver +{ + @Override + public java.nio.channels.SelectableChannel fd() + { + // + // Android doesn't provide non-blocking APIs for Bluetooth. + // + return null; + } + + @Override + public void setReadyCallback(IceInternal.ReadyCallback callback) + { + _readyCallback = callback; + } + + @Override + public synchronized int initialize(IceInternal.Buffer readBuffer, IceInternal.Buffer writeBuffer) + { + if(_exception != null) + { + throw _exception; + //throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + if(_state == StateConnecting) + { + // + // Wait until the connect thread is finished. + // + return IceInternal.SocketOperation.Read; + } + else if(_state == StateConnected) + { + // + // Update our Read state to indicate whether we still have more data waiting to be read. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, _readBuffer.b.position() > 0); + } + + return IceInternal.SocketOperation.None; + } + + @Override + public int closing(boolean initiator, Ice.LocalException ex) + { + // + // If we are initiating the connection closure, wait for the peer + // to close the connection. Otherwise, close immediately. + // + return initiator ? IceInternal.SocketOperation.Read : IceInternal.SocketOperation.None; + } + + @Override + public void close() + { + Thread connectThread = null, readThread = null, writeThread = null; + + synchronized(this) + { + // + // Close the socket first in order to interrupt the helper threads. + // + if(_socket != null) + { + try + { + _socket.close(); + } + catch(java.io.IOException ex) + { + // Ignore. + } + _socket = null; + } + + connectThread = _connectThread; + _connectThread = null; + readThread = _readThread; + _readThread = null; + writeThread = _writeThread; + _writeThread = null; + + _state = StateClosed; + + if(writeThread != null) + { + notifyAll(); // Wake up the read/write threads. + } + } + + if(connectThread != null) + { + try + { + connectThread.join(); + } + catch(InterruptedException ex) + { + // Ignore. + } + } + + if(readThread != null) + { + try + { + readThread.join(); + } + catch(InterruptedException ex) + { + // Ignore. + } + } + + if(writeThread != null) + { + try + { + writeThread.join(); + } + catch(InterruptedException ex) + { + // Ignore. + } + } + } + + @Override + public IceInternal.EndpointI bind() + { + assert(false); + return null; + } + + @Override + public synchronized int write(IceInternal.Buffer buf) + { + if(_exception != null) + { + throw _exception; + //throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + // + // Accept up to _sndSize bytes in our internal buffer. + // + final int capacity = _sndSize - _writeBuffer.b.position(); + if(capacity > 0) + { + final int num = Math.min(capacity, buf.b.remaining()); + _writeBuffer.expand(num); + final int lim = buf.b.limit(); // Save the current limit. + buf.b.limit(buf.b.position() + num); // Temporarily change the limit. + _writeBuffer.b.put(buf.b); // Copy to our internal buffer. + buf.b.limit(lim); // Restore the previous limit. + + notifyAll(); // We've added data to the internal buffer, so wake up the write thread. + } + + return buf.b.hasRemaining() ? IceInternal.SocketOperation.Write : IceInternal.SocketOperation.None; + } + + @Override + public synchronized int read(IceInternal.Buffer buf) + { + if(_exception != null) + { + throw _exception; + //throw (Ice.LocalException) _exception.fillInStackTrace(); + } + + // + // Copy the requested amount of data from our internal buffer to the given buffer. + // + _readBuffer.b.flip(); + if(_readBuffer.b.hasRemaining()) + { + int bytesAvailable = _readBuffer.b.remaining(); + int bytesNeeded = buf.b.remaining(); + if(bytesAvailable > bytesNeeded) + { + bytesAvailable = bytesNeeded; + } + if(buf.b.hasArray()) + { + // + // Copy directly into the destination buffer's backing array. + // + byte[] arr = buf.b.array(); + _readBuffer.b.get(arr, buf.b.arrayOffset() + buf.b.position(), bytesAvailable); + buf.b.position(buf.b.position() + bytesAvailable); + } + else if(_readBuffer.b.hasArray()) + { + // + // Copy directly from the source buffer's backing array. + // + byte[] arr = _readBuffer.b.array(); + buf.b.put(arr, _readBuffer.b.arrayOffset() + _readBuffer.b.position(), bytesAvailable); + _readBuffer.b.position(_readBuffer.b.position() + bytesAvailable); + } + else + { + // + // Copy using a temporary array. + // + byte[] arr = new byte[bytesAvailable]; + _readBuffer.b.get(arr); + buf.b.put(arr); + } + } + _readBuffer.b.compact(); + + // + // The read thread will temporarily stop reading if we exceed our configured limit. + // + if(_readBuffer.b.position() < _rcvSize) + { + notifyAll(); + } + + // + // Update our Read state to indicate whether we still have more data waiting to be read. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, _readBuffer.b.position() > 0); + + return buf.b.hasRemaining() ? IceInternal.SocketOperation.Read : IceInternal.SocketOperation.None; + } + + @Override + public String protocol() + { + return _instance.protocol(); + } + + @Override + public String toString() + { + return _desc; + } + + @Override + public String toDetailedString() + { + return toString(); + } + + @Override + public Ice.ConnectionInfo getInfo() + { + ConnectionInfo info = new ConnectionInfo(); + info.incoming = _adapterName != null; + info.adapterName = _adapterName != null ? _adapterName : ""; + info.connectionId = _connectionId; + info.rcvSize = _rcvSize; + info.sndSize = _sndSize; + info.localAddress = BluetoothAdapter.getDefaultAdapter().getAddress(); + //info.localChannel - not available, use default value of -1 + info.remoteAddress = _remoteAddr; + //info.remoteChannel - not available, use default value of -1 + info.uuid = _uuid.toString(); + return info; + } + + @Override + public synchronized void setBufferSize(int rcvSize, int sndSize) + { + _rcvSize = Math.max(1024, rcvSize); + _sndSize = Math.max(1024, sndSize); + } + + @Override + public void checkSendSize(IceInternal.Buffer buf) + { + } + + // + // Used by ConnectorI. + // + TransceiverI(Instance instance, String remoteAddr, UUID uuid, String connectionId) + { + _instance = instance; + _remoteAddr = remoteAddr; + _uuid = uuid; + _connectionId = connectionId; + _state = StateConnecting; + + init(); + + BluetoothAdapter adapter = _instance.bluetoothAdapter(); + assert(adapter != null); + + BluetoothDevice device = null; + try + { + device = adapter.getRemoteDevice(_remoteAddr); + } + catch(IllegalArgumentException ex) + { + // + // Illegal address - This should have been detected by the endpoint. + // + assert(false); + throw new Ice.SocketException(ex); + } + + try + { + // + // We always connect using the "secure" method. + // + _socket = device.createRfcommSocketToServiceRecord(_uuid); + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + + _connectThread = new Thread() + { + public void run() + { + String name = "IceBT.ConnectThread"; + if(_remoteAddr != null && !_remoteAddr.isEmpty()) + { + name += "-" + _remoteAddr; + } + if(_uuid != null) + { + name += "-" + _uuid.toString(); + } + setName(name); + + runConnectThread(); + } + }; + _connectThread.start(); + } + + // + // Used by AcceptorI. + // + TransceiverI(Instance instance, BluetoothSocket socket, UUID uuid, String adapterName) + { + _instance = instance; + _remoteAddr = socket.getRemoteDevice().getAddress(); + _uuid = uuid; + _connectionId = ""; + _adapterName = adapterName; + _socket = socket; + _state = StateConnected; + + init(); + + startReadWriteThreads(); + } + + private void init() + { + _desc = "local address = " + _instance.bluetoothAdapter().getAddress(); + if(_remoteAddr != null && !_remoteAddr.isEmpty()) + { + _desc += "\nremote address = " + _remoteAddr; + } + if(_uuid != null) + { + _desc += "\nservice uuid = " + _uuid.toString(); + } + + final int defaultBufSize = 128 * 1024; + _rcvSize = _instance.properties().getPropertyAsIntWithDefault("IceBT.RcvSize", defaultBufSize); + _sndSize = _instance.properties().getPropertyAsIntWithDefault("IceBT.SndSize", defaultBufSize); + + _readBuffer = new IceInternal.Buffer(false); + _writeBuffer = new IceInternal.Buffer(false); + } + + private synchronized void exception(Ice.LocalException ex) + { + if(_exception == null) + { + _exception = ex; + } + } + + private void runConnectThread() + { + // + // Always cancel discovery prior to a connect attempt. + // + _instance.bluetoothAdapter().cancelDiscovery(); + + try + { + // + // This can block for several seconds. + // + _socket.connect(); + } + catch(java.io.IOException ex) + { + exception(new Ice.ConnectFailedException(ex)); + } + + synchronized(this) + { + _connectThread = null; + + if(_exception == null) + { + // + // Connect succeeded. + // + _state = StateConnected; + + startReadWriteThreads(); + } + } + + // + // This causes the Ice run time to invoke initialize() again. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + } + + private void startReadWriteThreads() + { + String s = ""; + if(_remoteAddr != null && !_remoteAddr.isEmpty()) + { + s += "-" + _remoteAddr; + } + if(_uuid != null) + { + s += "-" + _uuid.toString(); + } + final String suffix = s; + + _readThread = new Thread() + { + public void run() + { + setName("IceBT.ReadThread" + suffix); + + runReadThread(); + } + }; + _readThread.start(); + + _writeThread = new Thread() + { + public void run() + { + setName("IceBT.WriteThread" + suffix); + + runWriteThread(); + } + }; + _writeThread.start(); + } + + private void runReadThread() + { + java.io.InputStream in = null; + + try + { + byte[] buf = null; + + synchronized(this) + { + if(_socket == null) + { + return; + } + in = _socket.getInputStream(); + + buf = new byte[_rcvSize]; + } + + while(true) + { + ByteBuffer b = null; + + synchronized(this) + { + // + // If we've read too much data, wait until the application consumes some before we read again. + // + while(_state == StateConnected && _exception == null && _readBuffer.b.position() > _rcvSize) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + break; + } + } + + if(_state != StateConnected || _exception != null) + { + break; + } + } + + int num = in.read(buf); + if(num > 0) + { + synchronized(this) + { + _readBuffer.expand(num); + _readBuffer.b.put(buf, 0, num); + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + + if(buf.length != _rcvSize) + { + // + // Application must have called setBufferSize. + // + buf = new byte[_rcvSize]; + } + } + } + } + } + catch(java.io.IOException ex) + { + exception(new Ice.SocketException(ex)); + // + // Mark as ready for reading so that the Ice run time will invoke read() and we can report the exception. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + } + catch(Ice.LocalException ex) + { + exception(ex); + // + // Mark as ready for reading so that the Ice run time will invoke read() and we can report the exception. + // + _readyCallback.ready(IceInternal.SocketOperation.Read, true); + } + finally + { + if(in != null) + { + try + { + in.close(); + } + catch(java.io.IOException ex) + { + // Ignore. + } + } + } + } + + private void runWriteThread() + { + java.io.OutputStream out = null; + + try + { + synchronized(this) + { + if(_socket == null) + { + return; + } + out = _socket.getOutputStream(); + } + + boolean done = false; + while(!done) + { + ByteBuffer b = null; + + synchronized(this) + { + while(_state == StateConnected && _exception == null && _writeBuffer.b.position() == 0) + { + try + { + wait(); + } + catch(InterruptedException ex) + { + break; + } + } + + if(_state != StateConnected || _exception != null) + { + done = true; + } + + b = _writeBuffer.b; // Adopt the ByteBuffer. + _writeBuffer.clear(); + } + + assert(b != null && b.hasArray()); + b.flip(); + if(b.hasRemaining() && !done) + { + // + // write() blocks until all the data has been written. + // + out.write(b.array(), b.arrayOffset(), b.remaining()); + } + + // TBD: Recycle the buffer? + + synchronized(this) + { + // + // After the write is complete, indicate whether we can accept more data. + // + _readyCallback.ready(IceInternal.SocketOperation.Write, _writeBuffer.b.position() < _sndSize); + } + } + } + catch(java.io.IOException ex) + { + exception(new Ice.SocketException(ex)); + } + finally + { + if(out != null) + { + try + { + out.close(); + } + catch(java.io.IOException ex) + { + // Ignore. + } + } + } + } + + private Instance _instance; + private String _remoteAddr; + private UUID _uuid; + private String _connectionId; + private String _adapterName; + + private BluetoothSocket _socket; + + private static final int StateConnecting = 0; + private static final int StateConnected = 1; + private static final int StateClosed = 2; + private int _state; + + private Thread _connectThread; + private Thread _readThread; + private Thread _writeThread; + + private Ice.LocalException _exception; + + private int _rcvSize; + private int _sndSize; + + private IceInternal.Buffer _readBuffer; + private IceInternal.Buffer _writeBuffer; + + private String _desc; + + private IceInternal.ReadyCallback _readyCallback; +} diff --git a/java-compat/src/IceBT/src/main/java/IceBT/Util.java b/java-compat/src/IceBT/src/main/java/IceBT/Util.java new file mode 100644 index 00000000000..ffb07e0a2f5 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/IceBT/Util.java @@ -0,0 +1,14 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBT; + +public final class Util +{ +} diff --git a/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothAdapter.java b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothAdapter.java new file mode 100644 index 00000000000..8d00d879d3b --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothAdapter.java @@ -0,0 +1,55 @@ +// +// This is a placeholder for the Android API. It is not included in the IceBT JAR file. +// + +package android.bluetooth; + +public final class BluetoothAdapter +{ + public boolean cancelDiscovery() + { + return false; + } + + public boolean isEnabled() + { + return false; + } + + public String getAddress() + { + return ""; + } + + public static boolean checkBluetoothAddress(String address) + { + return false; + } + + public static BluetoothAdapter getDefaultAdapter() + { + return null; + } + + public BluetoothDevice getRemoteDevice(byte[] address) + { + return null; + } + + public BluetoothDevice getRemoteDevice(String address) + { + return null; + } + + public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, java.util.UUID uuid) + throws java.io.IOException + { + return null; + } + + public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, java.util.UUID uuid) + throws java.io.IOException + { + return null; + } +} diff --git a/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothDevice.java b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothDevice.java new file mode 100644 index 00000000000..7fbee8880de --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothDevice.java @@ -0,0 +1,25 @@ +// +// This is a placeholder for the Android API. It is not included in the IceBT JAR file. +// + +package android.bluetooth; + +public final class BluetoothDevice +{ + public BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID uuid) + throws java.io.IOException + { + return null; + } + + public BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID uuid) + throws java.io.IOException + { + return null; + } + + public String getAddress() + { + return ""; + } +} diff --git a/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothServerSocket.java b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothServerSocket.java new file mode 100644 index 00000000000..c6e6f2a6978 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothServerSocket.java @@ -0,0 +1,19 @@ +// +// This is a placeholder for the Android API. It is not included in the IceBT JAR file. +// + +package android.bluetooth; + +public final class BluetoothServerSocket implements java.io.Closeable +{ + public BluetoothSocket accept() + throws java.io.IOException + { + return null; + } + + public void close() + throws java.io.IOException + { + } +} diff --git a/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothSocket.java b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothSocket.java new file mode 100644 index 00000000000..80470a11a52 --- /dev/null +++ b/java-compat/src/IceBT/src/main/java/android/bluetooth/BluetoothSocket.java @@ -0,0 +1,40 @@ +// +// This is a placeholder for the Android API. It is not included in the IceBT JAR file. +// + +package android.bluetooth; + +public final class BluetoothSocket implements java.io.Closeable +{ + public void close() + throws java.io.IOException + { + } + + public void connect() + throws java.io.IOException + { + } + + public java.io.InputStream getInputStream() + throws java.io.IOException + { + return null; + } + + public java.io.OutputStream getOutputStream() + throws java.io.IOException + { + return null; + } + + public BluetoothDevice getRemoteDevice() + { + return null; + } + + public boolean isConnected() + { + return false; + } +} diff --git a/java-compat/src/IceBox/build.gradle b/java-compat/src/IceBox/build.gradle new file mode 100644 index 00000000000..19aac05e3d3 --- /dev/null +++ b/java-compat/src/IceBox/build.gradle @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IceBox Compat" +project.ext.description = "IceBox is an easy-to-use framework for Ice application services" + +slice { + java { + set1 { + args = "--ice --tie --checksum IceBox.SliceChecksums" + files = fileTree(dir: "$sliceDir/IceBox", includes:['*.ice'], excludes:["*F.ice"]) + } + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/IceBox/src/main/java/IceBox/Admin.java b/java-compat/src/IceBox/src/main/java/IceBox/Admin.java new file mode 100644 index 00000000000..52e39ee771e --- /dev/null +++ b/java-compat/src/IceBox/src/main/java/IceBox/Admin.java @@ -0,0 +1,184 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBox; + +public final class Admin +{ + private static class Client extends Ice.Application + { + private void + usage() + { + System.err.println( + "Usage: " + appName() + " [options] [command...]\n" + + "Options:\n" + + "-h, --help Show this message.\n" + + "\n" + + "Commands:\n" + + "start SERVICE Start a service.\n" + + "stop SERVICE Stop a service.\n" + + "shutdown Shutdown the server."); + } + + @Override + public int + run(String[] args) + { + java.util.List<String> commands = new java.util.ArrayList<String>(); + + int idx = 0; + while(idx < args.length) + { + if(args[idx].equals("-h") || args[idx].equals("--help")) + { + usage(); + return 1; + } + else if(args[idx].charAt(0) == '-') + { + System.err.println(appName() + ": unknown option `" + args[idx] + "'"); + usage(); + return 1; + } + else + { + commands.add(args[idx]); + ++idx; + } + } + + if(commands.isEmpty()) + { + usage(); + return 0; + } + + Ice.ObjectPrx base = communicator().propertyToProxy("IceBoxAdmin.ServiceManager.Proxy"); + + if(base == null) + { + // + // The old deprecated way to retrieve the service manager proxy + // + + Ice.Properties properties = communicator().getProperties(); + + Ice.Identity managerIdentity = new Ice.Identity(); + managerIdentity.category = properties.getPropertyWithDefault("IceBox.InstanceName", "IceBox"); + managerIdentity.name = "ServiceManager"; + + String managerProxy; + if(properties.getProperty("Ice.Default.Locator").length() == 0) + { + String managerEndpoints = properties.getProperty("IceBox.ServiceManager.Endpoints"); + if(managerEndpoints.length() == 0) + { + System.err.println(appName() + ": property `IceBoxAdmin.ServiceManager.Proxy' is not set"); + return 1; + } + + managerProxy = "\"" + Ice.Util.identityToString(managerIdentity) + "\" :" + managerEndpoints; + } + else + { + String managerAdapterId = properties.getProperty("IceBox.ServiceManager.AdapterId"); + if(managerAdapterId.length() == 0) + { + System.err.println(appName() + ": property `IceBoxAdmin.ServiceManager.Proxy' is not set"); + return 1; + } + + managerProxy = "\"" + Ice.Util.identityToString(managerIdentity) + "\" @" + managerAdapterId; + } + + base = communicator().stringToProxy(managerProxy); + } + + IceBox.ServiceManagerPrx manager = IceBox.ServiceManagerPrxHelper.checkedCast(base); + if(manager == null) + { + System.err.println(appName() + ": `" + base.toString() + "' is not an IceBox::ServiceManager"); + return 1; + } + + for(int i = 0; i < commands.size(); i++) + { + String command = commands.get(i); + if(command.equals("shutdown")) + { + manager.shutdown(); + } + else if(command.equals("start")) + { + if(++i >= commands.size()) + { + System.err.println(appName() + ": no service name specified."); + return 1; + } + + String service = commands.get(i); + try + { + manager.startService(service); + } + catch(IceBox.NoSuchServiceException ex) + { + System.err.println(appName() + ": unknown service `" + service + "'"); + return 1; + } + catch(IceBox.AlreadyStartedException ex) + { + System.err.println(appName() + "service already started."); + } + } + else if(command.equals("stop")) + { + if(++i >= commands.size()) + { + System.err.println(appName() + ": no service name specified."); + return 1; + } + + String service = commands.get(i); + try + { + manager.stopService(service); + } + catch(IceBox.NoSuchServiceException ex) + { + System.err.println(appName() + ": unknown service `" + service + "'"); + return 1; + } + catch(IceBox.AlreadyStoppedException ex) + { + System.err.println(appName() + "service already stopped."); + } + } + else + { + System.err.println(appName() + ": unknown command `" + command + "'"); + usage(); + return 1; + } + } + + return 0; + } + } + + public static void + main(String[] args) + { + Client app = new Client(); + int rc = app.main("IceBox.Admin", args); + + System.exit(rc); + } +} diff --git a/java-compat/src/IceBox/src/main/java/IceBox/Server.java b/java-compat/src/IceBox/src/main/java/IceBox/Server.java new file mode 100644 index 00000000000..f6147ea423b --- /dev/null +++ b/java-compat/src/IceBox/src/main/java/IceBox/Server.java @@ -0,0 +1,79 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBox; + +public final class Server extends Ice.Application +{ + private static void + usage() + { + System.err.println("Usage: IceBox.Server [options] --Ice.Config=<file>\n"); + System.err.println( + "Options:\n" + + "-h, --help Show this message.\n" + ); + } + + public static void + main(String[] args) + { + Ice.InitializationData initData = new Ice.InitializationData(); + initData.properties = Ice.Util.createProperties(); + initData.properties.setProperty("Ice.Admin.DelayCreation", "1"); + + Server server = new Server(); + System.exit(server.main("IceBox.Server", args, initData)); + } + + @Override + public int + run(String[] args) + { + final String prefix = "IceBox.Service."; + Ice.Properties properties = communicator().getProperties(); + java.util.Map<String, String> services = properties.getPropertiesForPrefix(prefix); + java.util.List<String> argSeq = new java.util.ArrayList<String>(args.length); + for(String s : args) + { + argSeq.add(s); + } + + for(java.util.Map.Entry<String, String> entry : services.entrySet()) + { + String name = entry.getKey().substring(prefix.length()); + for(int i = 0; i < argSeq.size(); ++i) + { + if(argSeq.get(i).startsWith("--" + name)) + { + argSeq.remove(i); + i--; + } + } + } + + for(String arg : argSeq) + { + if(arg.equals("-h") || arg.equals("--help")) + { + usage(); + return 0; + } + else + { + System.err.println("Server: unknown option `" + arg + "'"); + usage(); + return 1; + } + } + + ServiceManagerI serviceManagerImpl = new ServiceManagerI(communicator(), args); + return serviceManagerImpl.run(); + } +} diff --git a/java-compat/src/IceBox/src/main/java/IceBox/ServiceManagerI.java b/java-compat/src/IceBox/src/main/java/IceBox/ServiceManagerI.java new file mode 100644 index 00000000000..ceefc3170ff --- /dev/null +++ b/java-compat/src/IceBox/src/main/java/IceBox/ServiceManagerI.java @@ -0,0 +1,1178 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceBox; + +import java.net.URLEncoder; + +// +// NOTE: the class isn't final on purpose to allow users to eventually +// extend it. +// +public class ServiceManagerI extends _ServiceManagerDisp +{ + public + ServiceManagerI(Ice.Communicator communicator, String[] args) + { + _communicator = communicator; + _logger = _communicator.getLogger(); + + Ice.Properties props = _communicator.getProperties(); + + if(props.getProperty("Ice.Admin.Enabled").isEmpty()) + { + _adminEnabled = !props.getProperty("Ice.Admin.Endpoints").isEmpty(); + } + else + { + _adminEnabled = props.getPropertyAsInt("Ice.Admin.Enabled") > 0; + } + + if(_adminEnabled) + { + String[] facetFilter = props.getPropertyAsList("Ice.Admin.Facets"); + if(facetFilter.length > 0) + { + _adminFacetFilter = new java.util.HashSet<String>(java.util.Arrays.asList(facetFilter)); + } + else + { + _adminFacetFilter = new java.util.HashSet<String>(); + } + } + + _argv = args; + _traceServiceObserver = props.getPropertyAsInt("IceBox.Trace.ServiceObserver"); + _observerCompletedCB = new Ice.Callback() + { + @Override + public void completed(Ice.AsyncResult result) + { + try + { + result.throwLocalException(); + } + catch(Ice.LocalException ex) + { + ServiceObserverPrx observer = ServiceObserverPrxHelper.uncheckedCast(result.getProxy()); + synchronized(ServiceManagerI.this) + { + if(_observers.remove(observer)) + { + observerRemoved(observer, ex); + } + } + } + } + }; + } + + @Override + public java.util.Map<String, String> + getSliceChecksums(Ice.Current current) + { + return SliceChecksums.checksums; + } + + @Override + public void + startService(String name, Ice.Current current) + throws AlreadyStartedException, NoSuchServiceException + { + ServiceInfo info = null; + synchronized(this) + { + // + // Search would be more efficient if services were contained in + // a map, but order is required for shutdown. + // + for(ServiceInfo p : _services) + { + if(p.name.equals(name)) + { + if(p.status == StatusStarted) + { + throw new AlreadyStartedException(); + } + p.status = StatusStarting; + info = p.clone(); + break; + } + } + if(info == null) + { + throw new NoSuchServiceException(); + } + _pendingStatusChanges = true; + } + + boolean started = false; + try + { + info.service.start(name, info.communicator == null ? _sharedCommunicator : info.communicator, info.args); + started = true; + } + catch(java.lang.Exception e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ServiceManager: exception while starting service " + info.name + ":\n" + sw.toString()); + } + + synchronized(this) + { + for(ServiceInfo p : _services) + { + if(p.name.equals(name)) + { + if(started) + { + p.status = StatusStarted; + + java.util.List<String> services = new java.util.ArrayList<String>(); + services.add(name); + servicesStarted(services, _observers); + } + else + { + p.status = StatusStopped; + } + break; + } + } + _pendingStatusChanges = false; + notifyAll(); + } + } + + @Override + public void + stopService(String name, Ice.Current current) + throws AlreadyStoppedException, NoSuchServiceException + { + ServiceInfo info = null; + synchronized(this) + { + // + // Search would be more efficient if services were contained in + // a map, but order is required for shutdown. + // + for(ServiceInfo p : _services) + { + if(p.name.equals(name)) + { + if(p.status == StatusStopped) + { + throw new AlreadyStoppedException(); + } + p.status = StatusStopping; + info = p.clone(); + break; + } + } + if(info == null) + { + throw new NoSuchServiceException(); + } + _pendingStatusChanges = true; + } + + boolean stopped = false; + try + { + info.service.stop(); + stopped = true; + } + catch(java.lang.Exception e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ServiceManager: exception while stopping service " + info.name + ":\n" + sw.toString()); + } + + synchronized(this) + { + for(ServiceInfo p : _services) + { + if(p.name.equals(name)) + { + if(stopped) + { + p.status = StatusStopped; + + java.util.List<String> services = new java.util.ArrayList<String>(); + services.add(name); + servicesStopped(services, _observers); + } + else + { + p.status = StatusStarted; + } + break; + } + } + _pendingStatusChanges = false; + notifyAll(); + } + } + + @Override + public void + addObserver(final ServiceObserverPrx observer, Ice.Current current) + { + java.util.List<String> activeServices = new java.util.LinkedList<String>(); + + // + // Null observers and duplicate registrations are ignored + // + + synchronized(this) + { + if(observer != null && _observers.add(observer)) + { + if(_traceServiceObserver >= 1) + { + _logger.trace("IceBox.ServiceObserver", + "Added service observer " + _communicator.proxyToString(observer)); + } + + for(ServiceInfo info: _services) + { + if(info.status == StatusStarted) + { + activeServices.add(info.name); + } + } + } + } + + if(activeServices.size() > 0) + { + observer.begin_servicesStarted(activeServices.toArray(new String[0]), _observerCompletedCB); + } + } + + @Override + public void + shutdown(Ice.Current current) + { + _communicator.shutdown(); + } + + public int + run() + { + try + { + Ice.Properties properties = _communicator.getProperties(); + + // + // Create an object adapter. Services probably should NOT share + // this object adapter, as the endpoint(s) for this object adapter + // will most likely need to be firewalled for security reasons. + // + Ice.ObjectAdapter adapter = null; + if(properties.getProperty("IceBox.ServiceManager.Endpoints").length() != 0) + { + adapter = _communicator.createObjectAdapter("IceBox.ServiceManager"); + + Ice.Identity identity = new Ice.Identity(); + identity.category = properties.getPropertyWithDefault("IceBox.InstanceName", "IceBox"); + identity.name = "ServiceManager"; + adapter.add(this, identity); + } + + // + // Parse the property set with the prefix "IceBox.Service.". These + // properties should have the following format: + // + // IceBox.Service.Foo=[jar-or-dir:]Package.Foo [args] + // + // We parse the service properties specified in IceBox.LoadOrder + // first, then the ones from remaining services. + // + final String prefix = "IceBox.Service."; + java.util.Map<String, String> services = properties.getPropertiesForPrefix(prefix); + String[] loadOrder = properties.getPropertyAsList("IceBox.LoadOrder"); + java.util.List<StartServiceInfo> servicesInfo = new java.util.ArrayList<StartServiceInfo>(); + for(String name : loadOrder) + { + if(name.length() > 0) + { + String key = prefix + name; + String value = services.get(key); + if(value == null) + { + FailureException ex = new FailureException(); + ex.reason = "ServiceManager: no service definition for `" + name + "'"; + throw ex; + } + servicesInfo.add(new StartServiceInfo(name, value, _argv)); + services.remove(key); + } + } + for(java.util.Map.Entry<String, String> p : services.entrySet()) + { + String name = p.getKey().substring(prefix.length()); + String value = p.getValue(); + servicesInfo.add(new StartServiceInfo(name, value, _argv)); + } + + // + // Check if some services are using the shared communicator in which + // case we create the shared communicator now with a property set that + // is the union of all the service properties (from services that use + // the shared communicator). + // + if(properties.getPropertiesForPrefix("IceBox.UseSharedCommunicator.").size() > 0) + { + Ice.InitializationData initData = new Ice.InitializationData(); + initData.properties = createServiceProperties("SharedCommunicator"); + for(StartServiceInfo service : servicesInfo) + { + if(properties.getPropertyAsInt("IceBox.UseSharedCommunicator." + service.name) <= 0) + { + continue; + } + + // + // Load the service properties using the shared communicator properties as + // the default properties. + // + Ice.StringSeqHolder serviceArgs = new Ice.StringSeqHolder(service.args); + Ice.Properties svcProperties = Ice.Util.createProperties(serviceArgs, initData.properties); + service.args = serviceArgs.value; + + // + // Remove properties from the shared property set that a service explicitly clears. + // + java.util.Map<String, String> allProps = initData.properties.getPropertiesForPrefix(""); + for(String key : allProps.keySet()) + { + if(svcProperties.getProperty(key).length() == 0) + { + initData.properties.setProperty(key, ""); + } + } + + // + // Add the service properties to the shared communicator properties. + // + for(java.util.Map.Entry<String, String> p : svcProperties.getPropertiesForPrefix("").entrySet()) + { + initData.properties.setProperty(p.getKey(), p.getValue()); + } + + // + // Parse <service>.* command line options (the Ice command line options + // were parsed by the call to createProperties above). + // + service.args = initData.properties.parseCommandLineOptions(service.name, service.args); + } + + String facetNamePrefix = "IceBox.SharedCommunicator."; + boolean addFacets = configureAdmin(initData.properties, facetNamePrefix); + + _sharedCommunicator = Ice.Util.initialize(initData); + + if(addFacets) + { + // Add all facets created on shared communicator to the IceBox communicator + // but renamed <prefix>.<facet-name>, except for the Process facet which is + // never added. + for(java.util.Map.Entry<String, Ice.Object> p : _sharedCommunicator.findAllAdminFacets().entrySet()) + { + if(!p.getKey().equals("Process")) + { + _communicator.addAdminFacet(p.getValue(), facetNamePrefix + p.getKey()); + } + } + } + } + + for(StartServiceInfo s : servicesInfo) + { + start(s.name, s.className, s.classDir, s.absolutePath, s.args); + } + + // + // We may want to notify external scripts that the services + // have started. This is done by defining the property: + // + // IceBox.PrintServicesReady=bundleName + // + // Where bundleName is whatever you choose to call this set of + // services. It will be echoed back as "bundleName ready". + // + // This must be done after start() has been invoked on the + // services. + // + String bundleName = properties.getProperty("IceBox.PrintServicesReady"); + if(bundleName.length() > 0) + { + System.out.println(bundleName + " ready"); + } + + // + // Don't move after the adapter activation. This allows + // applications to wait for the service manager to be + // reachable before sending a signal to shutdown the + // IceBox. + // + Ice.Application.shutdownOnInterrupt(); + + // + // Register "this" as a facet to the Admin object and + // create Admin object + // + try + { + _communicator.addAdminFacet(this, "IceBox.ServiceManager"); + _communicator.getAdmin(); + } + catch(Ice.ObjectAdapterDeactivatedException ex) + { + // + // Expected if the communicator has been shutdown. + // + } + + // + // Start request dispatching after we've started the services. + // + if(adapter != null) + { + try + { + adapter.activate(); + } + catch(Ice.ObjectAdapterDeactivatedException ex) + { + // + // Expected if the communicator has been shutdown. + // + } + } + + _communicator.waitForShutdown(); + Ice.Application.defaultInterrupt(); + } + catch(FailureException ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + pw.println(ex.reason); + ex.printStackTrace(pw); + pw.flush(); + _logger.error(sw.toString()); + return 1; + } + catch(Throwable ex) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + ex.printStackTrace(pw); + pw.flush(); + _logger.error("ServiceManager: caught exception:\n" + sw.toString()); + return 1; + } + finally + { + // + // Invoke stop() on the services. + // + stopAll(); + } + + return 0; + } + + synchronized private void + start(String service, String className, String classDir, boolean absolutePath, String[] args) + throws FailureException + { + // + // Load the class. + // + + // + // Use a class loader if the user specified a JAR file or class directory. + // + Class<?> c = null; + if(classDir != null) + { + try + { + if(!absolutePath) + { + classDir = new java.io.File(System.getProperty("user.dir") + java.io.File.separator + + classDir).getCanonicalPath(); + } + + if(!classDir.endsWith(java.io.File.separator) && !classDir.endsWith(".jar")) + { + classDir += java.io.File.separator; + } + classDir = URLEncoder.encode(classDir, "UTF-8"); + + // + // Reuse an existing class loader if we have already loaded a plug-in with + // the same value for classDir, otherwise create a new one. + // + ClassLoader cl = null; + + if(_classLoaders == null) + { + _classLoaders = new java.util.HashMap<String, ClassLoader>(); + } + else + { + cl = _classLoaders.get(classDir); + } + + if(cl == null) + { + final java.net.URL[] url = new java.net.URL[] { new java.net.URL("file:///" + classDir) }; + + cl = new java.net.URLClassLoader(url); + + _classLoaders.put(classDir, cl); + } + + c = cl.loadClass(className); + } + catch(java.net.MalformedURLException ex) + { + throw new FailureException("ServiceManager: invalid entry point format `" + classDir + "'", ex); + } + catch(java.io.IOException ex) + { + throw new FailureException("ServiceManager: invalid path in plug-in entry point `" + classDir + + "'", ex); + } + catch(java.lang.ClassNotFoundException ex) + { + // Ignored + } + } + else + { + c = IceInternal.Util.findClass(className, null); + } + + if(c == null) + { + throw new FailureException("ServiceManager: class " + className + " not found"); + } + + ServiceInfo info = new ServiceInfo(); + info.name = service; + info.status = StatusStopped; + info.args = args; + + // + // If Ice.UseSharedCommunicator.<name> is defined, create a + // communicator for the service. The communicator inherits + // from the shared communicator properties. If it's not + // defined, add the service properties to the shared + // commnunicator property set. + // + Ice.Communicator communicator; + if(_communicator.getProperties().getPropertyAsInt("IceBox.UseSharedCommunicator." + service) > 0) + { + assert(_sharedCommunicator != null); + communicator = _sharedCommunicator; + } + else + { + try + { + // + // Create the service properties. We use the communicator properties as the default + // properties if IceBox.InheritProperties is set. + // + Ice.InitializationData initData = new Ice.InitializationData(); + initData.properties = createServiceProperties(service); + Ice.StringSeqHolder serviceArgs = new Ice.StringSeqHolder(info.args); + if(serviceArgs.value.length > 0) + { + // + // Create the service properties with the given service arguments. This should + // read the service config file if it's specified with --Ice.Config. + // + initData.properties = Ice.Util.createProperties(serviceArgs, initData.properties); + + // + // Next, parse the service "<service>.*" command line options (the Ice command + // line options were parsed by the createProperties above) + // + serviceArgs.value = initData.properties.parseCommandLineOptions(service, serviceArgs.value); + } + + // + // Clone the logger to assign a new prefix. If one of the built-in loggers is configured + // don't set any logger. + // + if(initData.properties.getProperty("Ice.LogFile").length() == 0 && + (initData.properties.getPropertyAsInt("Ice.UseSyslog") <= 0 || + System.getProperty("os.name").startsWith("Windows"))) + { + initData.logger = _logger.cloneWithPrefix(initData.properties.getProperty("Ice.ProgramName")); + } + + // + // If Admin is enabled on the IceBox communicator, for each service that does not set + // Ice.Admin.Enabled, we set Ice.Admin.Enabled=1 to have this service create facets; then + // we add these facets to the IceBox Admin object as IceBox.Service.<service>.<facet>. + // + String serviceFacetNamePrefix = "IceBox.Service." + service + "."; + boolean addFacets = configureAdmin(initData.properties, serviceFacetNamePrefix); + + // + // Remaining command line options are passed to the communicator. This is + // necessary for Ice plug-in properties (e.g.: IceSSL). + // + info.communicator = Ice.Util.initialize(serviceArgs, initData); + info.args = serviceArgs.value; + communicator = info.communicator; + + if(addFacets) + { + // Add all facets created on the service communicator to the IceBox communicator + // but renamed IceBox.Service.<service>.<facet-name>, except for the Process facet + // which is never added + for(java.util.Map.Entry<String, Ice.Object> p : communicator.findAllAdminFacets().entrySet()) + { + if(!p.getKey().equals("Process")) + { + _communicator.addAdminFacet(p.getValue(), serviceFacetNamePrefix + p.getKey()); + } + } + } + } + catch(Throwable ex) + { + FailureException e = new FailureException(); + e.reason = "ServiceManager: exception while starting service " + service; + e.initCause(ex); + throw e; + } + } + + try + { + // + // Instantiate the service. + // + try + { + // + // If the service class provides a constructor that accepts an Ice.Communicator argument, + // use that in preference to the default constructor. + // + java.lang.Object obj = null; + try + { + java.lang.reflect.Constructor<?> con = c.getDeclaredConstructor(Ice.Communicator.class); + obj = con.newInstance(_communicator); + } + catch(IllegalAccessException ex) + { + throw new FailureException( + "ServiceManager: unable to access service constructor " + className + "(Ice.Communicator)", ex); + } + catch(NoSuchMethodException ex) + { + // Ignore. + } + catch(java.lang.reflect.InvocationTargetException ex) + { + if(ex.getCause() != null) + { + throw ex.getCause(); + } + else + { + throw new FailureException("ServiceManager: exception in service constructor for " + className, ex); + } + } + + if(obj == null) + { + // + // Fall back to the default constructor. + // + try + { + obj = c.newInstance(); + } + catch(IllegalAccessException ex) + { + throw new FailureException( + "ServiceManager: unable to access default service constructor in class " + className, ex); + } + } + + try + { + info.service = (Service)obj; + } + catch(ClassCastException ex) + { + throw new FailureException("ServiceManager: class " + className + " does not implement IceBox.Service"); + } + } + catch(InstantiationException ex) + { + throw new FailureException("ServiceManager: unable to instantiate class " + className, ex); + } + catch(FailureException ex) + { + throw ex; + } + catch(Throwable ex) + { + throw new FailureException("ServiceManager: exception in service constructor for " + className, ex); + } + + try + { + info.service.start(service, communicator, info.args); + + // + // There is no need to notify the observers since the 'start all' + // (that indirectly calls this method) occurs before the creation of + // the Server Admin object, and before the activation of the main + // object adapter (so before any observer can be registered) + // + } + catch(FailureException ex) + { + throw ex; + } + catch(Throwable ex) + { + FailureException e = new FailureException(); + e.reason = "ServiceManager: exception while starting service " + service; + e.initCause(ex); + throw e; + } + + info.status = StatusStarted; + _services.add(info); + } + catch(RuntimeException ex) + { + if(info.communicator != null) + { + destroyServiceCommunicator(service, info.communicator); + } + + throw ex; + } + } + + private synchronized void + stopAll() + { + // + // First wait for any active startService/stopService calls to complete. + // + while(_pendingStatusChanges) + { + try + { + wait(); + } + catch(java.lang.InterruptedException ex) + { + } + } + + // + // For each service, we call stop on the service and flush its database environment to + // the disk. Services are stopped in the reverse order of the order they were started. + // + java.util.List<String> stoppedServices = new java.util.ArrayList<String>(); + java.util.ListIterator<ServiceInfo> p = _services.listIterator(_services.size()); + while(p.hasPrevious()) + { + ServiceInfo info = p.previous(); + if(info.status == StatusStarted) + { + try + { + info.service.stop(); + info.status = StatusStopped; + stoppedServices.add(info.name); + } + catch(Throwable e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ServiceManager: exception while stopping service " + info.name + ":\n" + + sw.toString()); + } + } + + if(info.communicator != null) + { + destroyServiceCommunicator(info.name, info.communicator); + } + } + + if(_sharedCommunicator != null) + { + removeAdminFacets("IceBox.SharedCommunicator."); + + try + { + _sharedCommunicator.destroy(); + } + catch(java.lang.Exception e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ServiceManager: exception while destroying shared communicator:\n" + sw.toString()); + } + _sharedCommunicator = null; + } + + _services.clear(); + servicesStopped(stoppedServices, _observers); + } + + private void + servicesStarted(java.util.List<String> services, java.util.Set<ServiceObserverPrx> observers) + { + if(services.size() > 0) + { + String[] servicesArray = services.toArray(new String[0]); + + for(final ServiceObserverPrx observer: observers) + { + observer.begin_servicesStarted(servicesArray, _observerCompletedCB); + } + } + } + + private void + servicesStopped(java.util.List<String> services, java.util.Set<ServiceObserverPrx> observers) + { + if(services.size() > 0) + { + String[] servicesArray = services.toArray(new String[0]); + + for(final ServiceObserverPrx observer: observers) + { + observer.begin_servicesStopped(servicesArray, _observerCompletedCB); + } + } + } + + private void + observerRemoved(ServiceObserverPrx observer, RuntimeException ex) + { + if(_traceServiceObserver >= 1) + { + // + // CommunicatorDestroyedException may occur during shutdown. The observer notification has + // been sent, but the communicator was destroyed before the reply was received. We do not + // log a message for this exception. + // + if(!(ex instanceof Ice.CommunicatorDestroyedException)) + { + _logger.trace("IceBox.ServiceObserver", + "Removed service observer " + _communicator.proxyToString(observer) + + "\nafter catching " + ex.toString()); + } + } + } + + public final static int StatusStopping = 0; + public final static int StatusStopped = 1; + public final static int StatusStarting = 2; + public final static int StatusStarted = 3; + + static final class ServiceInfo implements Cloneable + { + @Override + public ServiceInfo clone() + { + ServiceInfo c = null; + try + { + c = (ServiceInfo)super.clone(); + } + catch(CloneNotSupportedException ex) + { + } + return c; + } + + public String name; + public Service service; + public Ice.Communicator communicator = null; + public int status; + public String[] args; + } + + static class StartServiceInfo + { + StartServiceInfo(String service, String value, String[] serverArgs) + { + name = service; + + // + // We support the following formats: + // + // <class-name> [args] + // <jar-file>:<class-name> [args] + // <class-dir>:<class-name> [args] + // "<path with spaces>":<class-name> [args] + // "<path with spaces>:<class-name>" [args] + // + + try + { + args = IceUtilInternal.Options.split(value); + } + catch(IceUtilInternal.Options.BadQuote ex) + { + throw new FailureException("ServiceManager: invalid arguments for service `" + name + "':\n" + + ex.getMessage()); + } + + assert(args.length > 0); + + final String entryPoint = args[0]; + + final boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + absolutePath = false; + + // + // Find first ':' that isn't part of the file path. + // + int pos = entryPoint.indexOf(':'); + if(isWindows) + { + final String driveLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if(pos == 1 && entryPoint.length() > 2 && driveLetters.indexOf(entryPoint.charAt(0)) != -1 && + (entryPoint.charAt(2) == '\\' || entryPoint.charAt(2) == '/')) + { + absolutePath = true; + pos = entryPoint.indexOf(':', pos + 1); + } + if(!absolutePath) + { + absolutePath = entryPoint.startsWith("\\\\"); + } + } + else + { + absolutePath = entryPoint.startsWith("/"); + } + + if((pos == -1 && absolutePath) || (pos != -1 && entryPoint.length() <= pos + 1)) + { + // + // Class name is missing. + // + throw new FailureException("ServiceManager: invalid entry point for service `" + name + "':\n" + + entryPoint); + } + + // + // Extract the JAR file or subdirectory, if any. + // + classDir = null; // Path name of JAR file or subdirectory. + + if(pos == -1) + { + className = entryPoint; + } + else + { + classDir = entryPoint.substring(0, pos).trim(); + className = entryPoint.substring(pos + 1).trim(); + } + + // + // Shift the arguments. + // + String[] tmp = new String[args.length - 1]; + System.arraycopy(args, 1, tmp, 0, args.length - 1); + args = tmp; + + if(serverArgs.length > 0) + { + java.util.List<String> l = new java.util.ArrayList<String>(java.util.Arrays.asList(args)); + for(String arg : serverArgs) + { + if(arg.startsWith("--" + service + ".")) + { + l.add(arg); + } + } + args = l.toArray(args); + } + } + + String name; + String[] args; + String className; + String classDir; + boolean absolutePath; + } + + private Ice.Properties + createServiceProperties(String service) + { + Ice.Properties properties; + Ice.Properties communicatorProperties = _communicator.getProperties(); + if(communicatorProperties.getPropertyAsInt("IceBox.InheritProperties") > 0) + { + properties = communicatorProperties._clone(); + // Inherit all except Ice.Admin.xxx properties + for(String p : properties.getPropertiesForPrefix("Ice.Admin.").keySet()) + { + properties.setProperty(p, ""); + } + } + else + { + properties = Ice.Util.createProperties(); + } + + String programName = communicatorProperties.getProperty("Ice.ProgramName"); + if(programName.length() == 0) + { + properties.setProperty("Ice.ProgramName", service); + } + else + { + properties.setProperty("Ice.ProgramName", programName + "-" + service); + } + return properties; + } + + private void + destroyServiceCommunicator(String service, Ice.Communicator communicator) + { + try + { + communicator.shutdown(); + communicator.waitForShutdown(); + } + catch(Ice.CommunicatorDestroyedException e) + { + // + // Ignore, the service might have already destroyed + // the communicator for its own reasons. + // + } + catch(java.lang.Exception e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ServiceManager: exception in shutting down communicator for service " + + service + "\n" + sw.toString()); + } + + removeAdminFacets("IceBox.Service." + service + "."); + + try + { + communicator.destroy(); + } + catch(java.lang.Exception e) + { + java.io.StringWriter sw = new java.io.StringWriter(); + java.io.PrintWriter pw = new java.io.PrintWriter(sw); + e.printStackTrace(pw); + pw.flush(); + _logger.warning("ServiceManager: exception in destroying communicator for service " + + service + "\n" + sw.toString()); + } + } + + private boolean configureAdmin(Ice.Properties properties, String prefix) + { + if(_adminEnabled && properties.getProperty("Ice.Admin.Enabled").isEmpty()) + { + java.util.List<String> facetNames = new java.util.LinkedList<String>(); + for(String p : _adminFacetFilter) + { + if(p.startsWith(prefix)) + { + facetNames.add(p.substring(prefix.length())); + } + } + + if(_adminFacetFilter.isEmpty() || !facetNames.isEmpty()) + { + properties.setProperty("Ice.Admin.Enabled", "1"); + + if(!facetNames.isEmpty()) + { + // TODO: need joinString with escape! + properties.setProperty("Ice.Admin.Facets", IceUtilInternal.StringUtil.joinString(facetNames, " ")); + } + return true; + } + } + return false; + } + + private void removeAdminFacets(String prefix) + { + try + { + for(String p : _communicator.findAllAdminFacets().keySet()) + { + if(p.startsWith(prefix)) + { + _communicator.removeAdminFacet(p); + } + } + } + catch(Ice.CommunicatorDestroyedException ex) + { + // Ignored + } + catch(Ice.ObjectAdapterDeactivatedException ex) + { + // Ignored + } + } + + + private Ice.Communicator _communicator; + private boolean _adminEnabled = false; + private java.util.Set<String> _adminFacetFilter; + private Ice.Communicator _sharedCommunicator; + private Ice.Logger _logger; + private String[] _argv; // Filtered server argument vector + private java.util.List<ServiceInfo> _services = new java.util.LinkedList<ServiceInfo>(); + private boolean _pendingStatusChanges = false; + private Ice.Callback _observerCompletedCB; + private java.util.HashSet<ServiceObserverPrx> _observers = new java.util.HashSet<ServiceObserverPrx>(); + private int _traceServiceObserver = 0; + private java.util.Map<String, ClassLoader> _classLoaders; +} diff --git a/java-compat/src/IceDiscovery/build.gradle b/java-compat/src/IceDiscovery/build.gradle new file mode 100644 index 00000000000..c64a33f1ccd --- /dev/null +++ b/java-compat/src/IceDiscovery/build.gradle @@ -0,0 +1,27 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IceDiscovery Compat" +project.ext.description = "Allow Ice applications to discover objects and object adapters" + +slice { + java { + args = "--ice" + files = fileTree(dir: "$sliceDir/IceDiscovery", includes:['*.ice'], excludes:["*F.ice"]) + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LocatorI.java b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LocatorI.java new file mode 100644 index 00000000000..7061f168010 --- /dev/null +++ b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LocatorI.java @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceDiscovery; + +class LocatorI extends Ice._LocatorDisp +{ + public LocatorI(LookupI lookup, Ice.LocatorRegistryPrx registry) + { + _lookup = lookup; + _registry = registry; + } + + @Override + public void + findObjectById_async(Ice.AMD_Locator_findObjectById cb, Ice.Identity id, Ice.Current current) + { + _lookup.findObject(cb, id); + } + + @Override + public void + findAdapterById_async(Ice.AMD_Locator_findAdapterById cb, String adapterId, Ice.Current current) + { + _lookup.findAdapter(cb, adapterId); + } + + @Override + public Ice.LocatorRegistryPrx + getRegistry(Ice.Current current) + { + return _registry; + } + + private final LookupI _lookup; + private final Ice.LocatorRegistryPrx _registry; +} diff --git a/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LocatorRegistryI.java b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LocatorRegistryI.java new file mode 100644 index 00000000000..be8e0e6f220 --- /dev/null +++ b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LocatorRegistryI.java @@ -0,0 +1,179 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceDiscovery; + +import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; + +class LocatorRegistryI extends Ice._LocatorRegistryDisp +{ + public LocatorRegistryI(Ice.Communicator com) + { + _wellKnownProxy = com.stringToProxy("p").ice_locator(null).ice_router(null).ice_collocationOptimized(true); + } + + @Override + synchronized public void + setAdapterDirectProxy_async(Ice.AMD_LocatorRegistry_setAdapterDirectProxy cb, + String adapterId, + Ice.ObjectPrx proxy, + Ice.Current current) + { + if(proxy != null) + { + _adapters.put(adapterId, proxy); + } + else + { + _adapters.remove(adapterId); + } + cb.ice_response(); + } + + @Override + synchronized public void + setReplicatedAdapterDirectProxy_async(Ice.AMD_LocatorRegistry_setReplicatedAdapterDirectProxy cb, + String adapterId, + String replicaGroupId, + Ice.ObjectPrx proxy, + Ice.Current current) + { + if(proxy != null) + { + _adapters.put(adapterId, proxy); + Set<String> s = _replicaGroups.get(replicaGroupId); + if(s == null) + { + s = new HashSet<String>(); + _replicaGroups.put(replicaGroupId, s); + } + s.add(adapterId); + } + else + { + _adapters.remove(adapterId); + Set<String> s = _replicaGroups.get(replicaGroupId); + if(s != null) + { + s.remove(adapterId); + if(s.isEmpty()) + { + _replicaGroups.remove(adapterId); + } + } + } + cb.ice_response(); + } + + @Override + public void + setServerProcessProxy_async(Ice.AMD_LocatorRegistry_setServerProcessProxy cb, + String serverId, + Ice.ProcessPrx process, + Ice.Current current) + { + cb.ice_response(); + } + + synchronized Ice.ObjectPrx + findObject(Ice.Identity id) + { + if(id.name.length() == 0) + { + return null; + } + + Ice.ObjectPrx prx = _wellKnownProxy.ice_identity(id); + + List<String> adapterIds = new ArrayList<String>(); + for(String a : _replicaGroups.keySet()) + { + try + { + prx.ice_adapterId(a).ice_ping(); + adapterIds.add(a); + } + catch(Ice.LocalException ex) + { + } + } + if(adapterIds.isEmpty()) + { + for(String a : _adapters.keySet()) + { + try + { + prx.ice_adapterId(a).ice_ping(); + adapterIds.add(a); + } + catch(Ice.LocalException ex) + { + } + } + } + + if(adapterIds.isEmpty()) + { + return null; + } + java.util.Collections.shuffle(adapterIds); + return prx.ice_adapterId(adapterIds.get(0)); + } + + synchronized Ice.ObjectPrx + findAdapter(String adapterId, Ice.Holder<Boolean> isReplicaGroup) + { + Ice.ObjectPrx proxy = _adapters.get(adapterId); + if(proxy != null) + { + isReplicaGroup.value = false; + return proxy; + } + + Set<String> s = _replicaGroups.get(adapterId); + if(s != null) + { + List<Ice.Endpoint> endpoints = new ArrayList<Ice.Endpoint>(); + Ice.ObjectPrx prx = null; + for(String a : s) + { + proxy = _adapters.get(a); + if(proxy == null) + { + continue; // TODO: Inconsistency + } + + if(prx == null) + { + prx = proxy; + } + + endpoints.addAll(java.util.Arrays.asList(proxy.ice_getEndpoints())); + } + + if(prx != null) + { + isReplicaGroup.value = true; + return prx.ice_endpoints(endpoints.toArray(new Ice.Endpoint[endpoints.size()])); + } + } + isReplicaGroup.value = false; + return null; + } + + final Ice.ObjectPrx _wellKnownProxy; + final Map<String, Ice.ObjectPrx> _adapters = new HashMap<String, Ice.ObjectPrx>(); + final Map<String, Set<String>> _replicaGroups = new HashMap<String, Set<String>>(); +} + diff --git a/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LookupI.java b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LookupI.java new file mode 100644 index 00000000000..003fe63c53b --- /dev/null +++ b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LookupI.java @@ -0,0 +1,399 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceDiscovery; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; + +class LookupI extends _LookupDisp +{ + abstract private class Request<T, AmdCB> implements Runnable + { + Request(T id, int retryCount) + { + _id = id; + _nRetry = retryCount; + } + + T + getId() + { + return _id; + } + + boolean + addCallback(AmdCB cb) + { + _callbacks.add(cb); + return _callbacks.size() == 1; + } + + boolean + retry() + { + return --_nRetry >= 0; + } + + void + scheduleTimer(long timeout) + { + _future = _timer.schedule(this, timeout, java.util.concurrent.TimeUnit.MILLISECONDS); + } + + void + cancelTimer() + { + assert _future != null; + _future.cancel(false); + _future = null; + } + + protected int _nRetry; + protected List<AmdCB> _callbacks = new ArrayList<AmdCB>(); + private T _id; + protected java.util.concurrent.Future<?> _future; + }; + + private class AdapterRequest extends Request<String, Ice.AMD_Locator_findAdapterById> + { + AdapterRequest(String id, int retryCount) + { + super(id, retryCount); + _start = System.nanoTime(); + _latency = 0; + } + + @Override + boolean + retry() + { + return _proxies.size() == 0 && --_nRetry >= 0; + } + + boolean + response(Ice.ObjectPrx proxy, boolean isReplicaGroup) + { + if(isReplicaGroup) + { + _proxies.add(proxy); + if(_latency == 0) + { + _latency = (long)((System.nanoTime() - _start) * _latencyMultiplier / 100000.0); + if(_latency == 0) + { + _latency = 1; // 1ms + } + cancelTimer(); + scheduleTimer(_latency); + } + return false; + } + finished(proxy); + return true; + } + + void + finished(Ice.ObjectPrx proxy) + { + if(proxy != null || _proxies.isEmpty()) + { + sendResponse(proxy); + return; + } + else if(_proxies.size() == 1) + { + sendResponse(_proxies.get(0)); + return; + } + + List<Ice.Endpoint> endpoints = new ArrayList<Ice.Endpoint>(); + Ice.ObjectPrx result = null; + for(Ice.ObjectPrx prx : _proxies) + { + if(result == null) + { + result = prx; + } + endpoints.addAll(java.util.Arrays.asList(prx.ice_getEndpoints())); + } + sendResponse(result.ice_endpoints(endpoints.toArray(new Ice.Endpoint[endpoints.size()]))); + } + + @Override + public void + run() + { + adapterRequestTimedOut(this); + } + + private void + sendResponse(Ice.ObjectPrx proxy) + { + for(Ice.AMD_Locator_findAdapterById cb : _callbacks) + { + cb.ice_response(proxy); + } + _callbacks.clear(); + } + + private List<Ice.ObjectPrx> _proxies = new ArrayList<Ice.ObjectPrx>(); + private long _start; + private long _latency; + }; + + private class ObjectRequest extends Request<Ice.Identity, Ice.AMD_Locator_findObjectById> + { + ObjectRequest(Ice.Identity id, int retryCount) + { + super(id, retryCount); + } + + void + response(Ice.ObjectPrx proxy) + { + finished(proxy); + } + + void + finished(Ice.ObjectPrx proxy) + { + for(Ice.AMD_Locator_findObjectById cb : _callbacks) + { + cb.ice_response(proxy); + } + _callbacks.clear(); + } + + @Override + public void + run() + { + objectRequestTimedOut(this); + } + }; + + public LookupI(LocatorRegistryI registry, LookupPrx lookup, Ice.Properties properties) + { + _registry = registry; + _lookup = lookup; + _timeout = properties.getPropertyAsIntWithDefault("IceDiscovery.Timeout", 300); + _retryCount = properties.getPropertyAsIntWithDefault("IceDiscovery.RetryCount", 3); + _latencyMultiplier = properties.getPropertyAsIntWithDefault("IceDiscovery.LatencyMultiplier", 1); + _domainId = properties.getProperty("IceDiscovery.DomainId"); + _timer = IceInternal.Util.getInstance(lookup.ice_getCommunicator()).timer(); + } + + void + setLookupReply(LookupReplyPrx lookupReply) + { + _lookupReply = lookupReply; + } + + @Override + public void + findObjectById(String domainId, Ice.Identity id, IceDiscovery.LookupReplyPrx reply, Ice.Current c) + { + if(!domainId.equals(_domainId)) + { + return; // Ignore. + } + + Ice.ObjectPrx proxy = _registry.findObject(id); + if(proxy != null) + { + // + // Reply to the mulicast request using the given proxy. + // + try + { + reply.begin_foundObjectById(id, proxy); + } + catch(Ice.LocalException ex) + { + // Ignore + } + } + } + + @Override + public void + findAdapterById(String domainId, String adapterId, IceDiscovery.LookupReplyPrx reply, Ice.Current c) + { + if(!domainId.equals(_domainId)) + { + return; // Ignore. + } + + Ice.Holder<Boolean> isReplicaGroup = new Ice.Holder<Boolean>(); + Ice.ObjectPrx proxy = _registry.findAdapter(adapterId, isReplicaGroup); + if(proxy != null) + { + // + // Reply to the multicast request using the given proxy. + // + try + { + reply.begin_foundAdapterById(adapterId, proxy, isReplicaGroup.value); + } + catch(Ice.LocalException ex) + { + // Ignore + } + } + } + + synchronized void + findObject(Ice.AMD_Locator_findObjectById cb, Ice.Identity id) + { + ObjectRequest request = _objectRequests.get(id); + if(request == null) + { + request = new ObjectRequest(id, _retryCount); + _objectRequests.put(id, request); + } + + if(request.addCallback(cb)) + { + try + { + _lookup.begin_findObjectById(_domainId, id, _lookupReply); + request.scheduleTimer(_timeout); + } + catch(Ice.LocalException ex) + { + request.finished(null); + _objectRequests.remove(id); + } + } + } + + synchronized void + findAdapter(Ice.AMD_Locator_findAdapterById cb, String adapterId) + { + AdapterRequest request = _adapterRequests.get(adapterId); + if(request == null) + { + request = new AdapterRequest(adapterId, _retryCount); + _adapterRequests.put(adapterId, request); + } + + if(request.addCallback(cb)) + { + try + { + _lookup.begin_findAdapterById(_domainId, adapterId, _lookupReply); + request.scheduleTimer(_timeout); + } + catch(Ice.LocalException ex) + { + request.finished(null); + _adapterRequests.remove(adapterId); + } + } + } + + synchronized void + foundObject(Ice.Identity id, Ice.ObjectPrx proxy) + { + ObjectRequest request = _objectRequests.get(id); + if(request == null) + { + return; + } + + request.response(proxy); + request.cancelTimer(); + _objectRequests.remove(id); + } + + synchronized void + foundAdapter(String adapterId, Ice.ObjectPrx proxy, boolean isReplicaGroup) + { + AdapterRequest request = _adapterRequests.get(adapterId); + if(request == null) + { + return; + } + + if(request.response(proxy, isReplicaGroup)) + { + request.cancelTimer(); + _adapterRequests.remove(adapterId); + } + } + + synchronized void + objectRequestTimedOut(ObjectRequest request) + { + ObjectRequest r = _objectRequests.get(request.getId()); + if(r == null || request != r) + { + return; + } + + if(request.retry()) + { + try + { + _lookup.begin_findObjectById(_domainId, request.getId(), _lookupReply); + request.scheduleTimer(_timeout); + return; + } + catch(Ice.LocalException ex) + { + } + } + + request.finished(null); + _objectRequests.remove(request.getId()); + } + + synchronized void + adapterRequestTimedOut(AdapterRequest request) + { + AdapterRequest r = _adapterRequests.get(request.getId()); + if(r == null || r != request) + { + return; + } + + if(request.retry()) + { + try + { + _lookup.begin_findAdapterById(_domainId, request.getId(), _lookupReply); + request.scheduleTimer(_timeout); + return; + } + catch(Ice.LocalException ex) + { + } + } + + request.finished(null); + _adapterRequests.remove(request.getId()); + } + + private LocatorRegistryI _registry; + private final LookupPrx _lookup; + private LookupReplyPrx _lookupReply; + private final int _timeout; + private final int _retryCount; + private final int _latencyMultiplier; + private final String _domainId; + + private final java.util.concurrent.ScheduledExecutorService _timer; + + private Map<Ice.Identity, ObjectRequest> _objectRequests = new HashMap<Ice.Identity, ObjectRequest>(); + private Map<String, AdapterRequest> _adapterRequests = new HashMap<String, AdapterRequest>(); +} + diff --git a/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LookupReplyI.java b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LookupReplyI.java new file mode 100644 index 00000000000..c848d425630 --- /dev/null +++ b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/LookupReplyI.java @@ -0,0 +1,35 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceDiscovery; + +class LookupReplyI extends _LookupReplyDisp +{ + public LookupReplyI(LookupI lookup) + { + _lookup = lookup; + } + + @Override + public void + foundObjectById(Ice.Identity id, Ice.ObjectPrx proxy, Ice.Current current) + { + _lookup.foundObject(id, proxy); + } + + @Override + public void + foundAdapterById(String adapterId, Ice.ObjectPrx proxy, boolean isReplicaGroup, Ice.Current current) + { + _lookup.foundAdapter(adapterId, proxy, isReplicaGroup); + } + + private final LookupI _lookup; +} + diff --git a/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/PluginFactory.java b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/PluginFactory.java new file mode 100644 index 00000000000..506746369a6 --- /dev/null +++ b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/PluginFactory.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceDiscovery; + +public class PluginFactory implements Ice.PluginFactory +{ + @Override + public Ice.Plugin + create(Ice.Communicator communicator, String name, String[] args) + { + return new PluginI(communicator); + } +} diff --git a/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/PluginI.java b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/PluginI.java new file mode 100644 index 00000000000..4f45834c7ea --- /dev/null +++ b/java-compat/src/IceDiscovery/src/main/java/IceDiscovery/PluginI.java @@ -0,0 +1,138 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceDiscovery; + +public class PluginI implements Ice.Plugin +{ + public + PluginI(Ice.Communicator communicator) + { + _communicator = communicator; + } + + @Override + public void + initialize() + { + Ice.Properties properties = _communicator.getProperties(); + + boolean ipv4 = properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0; + boolean preferIPv6 = properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0; + String address; + if(ipv4 && !preferIPv6) + { + address = properties.getPropertyWithDefault("IceDiscovery.Address", "239.255.0.1"); + } + else + { + address = properties.getPropertyWithDefault("IceDiscovery.Address", "ff15::1"); + } + int port = properties.getPropertyAsIntWithDefault("IceDiscovery.Port", 4061); + String intf = properties.getProperty("IceDiscovery.Interface"); + + if(properties.getProperty("IceDiscovery.Multicast.Endpoints").isEmpty()) + { + StringBuilder s = new StringBuilder(); + s.append("udp -h \"").append(address).append("\" -p ").append(port); + if(!intf.isEmpty()) + { + s.append(" --interface \"").append(intf).append("\""); + } + properties.setProperty("IceDiscovery.Multicast.Endpoints", s.toString()); + } + if(properties.getProperty("IceDiscovery.Reply.Endpoints").isEmpty()) + { + StringBuilder s = new StringBuilder(); + s.append("udp"); + if(!intf.isEmpty()) + { + s.append(" -h \"").append(intf).append("\""); + } + properties.setProperty("IceDiscovery.Reply.Endpoints", s.toString()); + } + if(properties.getProperty("IceDiscovery.Locator.Endpoints").isEmpty()) + { + properties.setProperty("IceDiscovery.Locator.AdapterId", java.util.UUID.randomUUID().toString()); + } + + _multicastAdapter = _communicator.createObjectAdapter("IceDiscovery.Multicast"); + _replyAdapter = _communicator.createObjectAdapter("IceDiscovery.Reply"); + _locatorAdapter = _communicator.createObjectAdapter("IceDiscovery.Locator"); + + // + // Setup locatory registry. + // + LocatorRegistryI locatorRegistry = new LocatorRegistryI(_communicator); + Ice.LocatorRegistryPrx locatorRegistryPrx = Ice.LocatorRegistryPrxHelper.uncheckedCast( + _locatorAdapter.addWithUUID(locatorRegistry)); + + String lookupEndpoints = properties.getProperty("IceDiscovery.Lookup"); + if(lookupEndpoints.isEmpty()) + { + StringBuilder s = new StringBuilder(); + s.append("udp -h \"").append(address).append("\" -p ").append(port); + if(!intf.isEmpty()) + { + s.append(" --interface \"").append(intf).append("\""); + } + lookupEndpoints = s.toString(); + } + + Ice.ObjectPrx lookupPrx = _communicator.stringToProxy("IceDiscovery/Lookup -d:" + lookupEndpoints); + lookupPrx = lookupPrx.ice_collocationOptimized(false); // No collocation optimization for the multicast proxy! + try + { + lookupPrx.ice_getConnection(); + } + catch(Ice.LocalException ex) + { + StringBuilder b = new StringBuilder(); + b.append("IceDiscovery is unable to establish a multicast connection:\n"); + b.append("proxy = "); + b.append(lookupPrx.toString()); + b.append('\n'); + b.append(ex.toString()); + throw new Ice.PluginInitializationException(b.toString()); + } + + // + // Add lookup and lookup reply Ice objects + // + LookupI lookup = new LookupI(locatorRegistry, LookupPrxHelper.uncheckedCast(lookupPrx), properties); + _multicastAdapter.add(lookup, Ice.Util.stringToIdentity("IceDiscovery/Lookup")); + + Ice.ObjectPrx lookupReply = _replyAdapter.addWithUUID(new LookupReplyI(lookup)).ice_datagram(); + lookup.setLookupReply(LookupReplyPrxHelper.uncheckedCast(lookupReply)); + + // + // Setup locator on the communicator. + // + Ice.ObjectPrx locator = _locatorAdapter.addWithUUID(new LocatorI(lookup, locatorRegistryPrx)); + _communicator.setDefaultLocator(Ice.LocatorPrxHelper.uncheckedCast(locator)); + + _multicastAdapter.activate(); + _replyAdapter.activate(); + _locatorAdapter.activate(); + } + + @Override + public void + destroy() + { + _multicastAdapter.destroy(); + _replyAdapter.destroy(); + _locatorAdapter.destroy(); + } + + private Ice.Communicator _communicator; + private Ice.ObjectAdapter _multicastAdapter; + private Ice.ObjectAdapter _replyAdapter; + private Ice.ObjectAdapter _locatorAdapter; +} diff --git a/java-compat/src/IceGrid/build.gradle b/java-compat/src/IceGrid/build.gradle new file mode 100644 index 00000000000..d2bd4fc5f70 --- /dev/null +++ b/java-compat/src/IceGrid/build.gradle @@ -0,0 +1,30 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IceGrid Compat" +project.ext.description = "Locate, deploy, and manage Ice servers" + +slice { + java { + set1 { + args = "--ice --tie --checksum IceGrid.SliceChecksums" + files = fileTree(dir: "$sliceDir/IceGrid", includes:['*.ice'], excludes:["*F.ice"]) + } + } +} + +dependencies { + compile project(':ice-compat') + compile project(':glacier2-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/IceLocatorDiscovery/build.gradle b/java-compat/src/IceLocatorDiscovery/build.gradle new file mode 100644 index 00000000000..be398fe5e31 --- /dev/null +++ b/java-compat/src/IceLocatorDiscovery/build.gradle @@ -0,0 +1,27 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IceLocatorDiscovery Compat" +project.ext.description = "Ice plug-in that enables the discovery of IceGrid and custom locators via UDP multicast" + +slice { + java { + args = "--ice" + files = fileTree(dir: "$sliceDir/IceLocatorDiscovery", includes:['*.ice'], excludes:["*F.ice"]) + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/IceLocatorDiscovery/src/main/java/IceLocatorDiscovery/PluginFactory.java b/java-compat/src/IceLocatorDiscovery/src/main/java/IceLocatorDiscovery/PluginFactory.java new file mode 100644 index 00000000000..89b2cbba771 --- /dev/null +++ b/java-compat/src/IceLocatorDiscovery/src/main/java/IceLocatorDiscovery/PluginFactory.java @@ -0,0 +1,20 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceLocatorDiscovery; + +public class PluginFactory implements Ice.PluginFactory +{ + @Override + public Ice.Plugin + create(Ice.Communicator communicator, String name, String[] args) + { + return new PluginI(communicator); + } +} diff --git a/java-compat/src/IceLocatorDiscovery/src/main/java/IceLocatorDiscovery/PluginI.java b/java-compat/src/IceLocatorDiscovery/src/main/java/IceLocatorDiscovery/PluginI.java new file mode 100644 index 00000000000..b2fb41d7ced --- /dev/null +++ b/java-compat/src/IceLocatorDiscovery/src/main/java/IceLocatorDiscovery/PluginI.java @@ -0,0 +1,456 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceLocatorDiscovery; + +import java.util.List; +import java.util.Arrays; +import java.util.ArrayList; + +class PluginI implements Ice.Plugin +{ + private static class Request + { + Request(LocatorI locator, + String operation, + Ice.OperationMode mode, + byte[] inParams, + java.util.Map<String, String> context, + Ice.AMD_Object_ice_invoke amdCB) + { + _locator = locator; + _operation = operation; + _mode = mode; + _inParams = inParams; + _context = context; + _amdCB = amdCB; + } + + void + invoke(Ice.LocatorPrx l) + { + _locatorPrx = l; + try + { + l.begin_ice_invoke(_operation, _mode, _inParams, _context, + new Ice.Callback_Object_ice_invoke() + { + @Override + public void + response(boolean ok, byte[] outParams) + { + _amdCB.ice_response(ok, outParams); + } + + @Override + public void + exception(Ice.LocalException ex) + { + Request.this.exception(ex); + } + }); + } + catch(Ice.LocalException ex) + { + exception(ex); + } + } + + private void + exception(Ice.LocalException ex) + { + try + { + throw ex; + } + catch(Ice.RequestFailedException exc) + { + _amdCB.ice_exception(ex); + } + catch(Ice.UnknownException exc) + { + _amdCB.ice_exception(ex); + } + catch(Ice.NoEndpointException exc) + { + _amdCB.ice_exception(new Ice.ObjectNotExistException()); + } + catch(Ice.ObjectAdapterDeactivatedException exc) + { + _amdCB.ice_exception(new Ice.ObjectNotExistException()); + } + catch(Ice.CommunicatorDestroyedException exc) + { + _amdCB.ice_exception(new Ice.ObjectNotExistException()); + } + catch(Ice.LocalException exc) + { + _locator.invoke(_locatorPrx, Request.this); // Retry with new locator proxy + } + } + + private final LocatorI _locator; + private final String _operation; + private final Ice.OperationMode _mode; + private final java.util.Map<String, String> _context; + private final byte[] _inParams; + private final Ice.AMD_Object_ice_invoke _amdCB; + + private Ice.LocatorPrx _locatorPrx; + }; + + static private class VoidLocatorI extends Ice._LocatorDisp + { + @Override + public void + findObjectById_async(Ice.AMD_Locator_findObjectById amdCB, Ice.Identity id, Ice.Current current) + { + amdCB.ice_response(null); + } + + @Override + public void + findAdapterById_async(Ice.AMD_Locator_findAdapterById amdCB, String id, Ice.Current current) + { + amdCB.ice_response(null); + } + + @Override + public Ice.LocatorRegistryPrx + getRegistry(Ice.Current current) + { + return null; + } + }; + + private static class LocatorI extends Ice.BlobjectAsync + { + LocatorI(LookupPrx lookup, Ice.Properties properties, String instanceName, Ice.LocatorPrx voidLocator) + { + _lookup = lookup; + _timeout = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.Timeout", 300); + _retryCount = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.RetryCount", 3); + _retryDelay = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.RetryDelay", 2000); + _timer = IceInternal.Util.getInstance(lookup.ice_getCommunicator()).timer(); + _instanceName = instanceName; + _warned = false; + _locator = lookup.ice_getCommunicator().getDefaultLocator(); + _voidLocator = voidLocator; + _pendingRetryCount = 0; + } + + public void + setLookupReply(LookupReplyPrx lookupReply) + { + _lookupReply = lookupReply; + } + + @Override + public synchronized void + ice_invoke_async(Ice.AMD_Object_ice_invoke amdCB, byte[] inParams, Ice.Current current) + { + invoke(null, new Request(this, current.operation, current.mode, inParams, current.ctx, amdCB)); + } + + public synchronized void + foundLocator(Ice.LocatorPrx locator) + { + if(locator == null || + (!_instanceName.isEmpty() && !locator.ice_getIdentity().category.equals(_instanceName))) + { + return; + } + + // + // If we already have a locator assigned, ensure the given locator + // has the same identity, otherwise ignore it. + // + if(_locator != null && !locator.ice_getIdentity().category.equals(_locator.ice_getIdentity().category)) + { + if(!_warned) + { + _warned = true; // Only warn once + + locator.ice_getCommunicator().getLogger().warning( + "received Ice locator with different instance name:\n" + + "using = `" + _locator.ice_getIdentity().category + "'\n" + + "received = `" + locator.ice_getIdentity().category + "'\n" + + "This is typically the case if multiple Ice locators with different " + + "instance names are deployed and the property `IceLocatorDiscovery.InstanceName'" + + "is not set."); + } + return; + } + + if(_pendingRetryCount > 0) // No need to retry, we found a locator + { + _future.cancel(false); + _future = null; + + _pendingRetryCount = 0; + } + + if(_locator != null) + { + // + // We found another locator replica, append its endpoints to the + // current locator proxy endpoints. + // + List<Ice.Endpoint> newEndpoints = new ArrayList<Ice.Endpoint>( + Arrays.asList(_locator.ice_getEndpoints())); + for(Ice.Endpoint p : locator.ice_getEndpoints()) + { + // + // Only add endpoints if not already in the locator proxy endpoints + // + boolean found = false; + for(Ice.Endpoint q : newEndpoints) + { + if(p.equals(q)) + { + found = true; + break; + } + } + if(!found) + { + newEndpoints.add(p); + } + + } + _locator = (Ice.LocatorPrx)_locator.ice_endpoints( + newEndpoints.toArray(new Ice.Endpoint[newEndpoints.size()])); + } + else + { + _locator = locator; + if(_instanceName.isEmpty()) + { + _instanceName = _locator.ice_getIdentity().category; // Stick to the first locator + } + } + + // + // Send pending requests if any. + // + for(Request req : _pendingRequests) + { + req.invoke(_locator); + } + _pendingRequests.clear(); + } + + + public synchronized void + invoke(Ice.LocatorPrx locator, Request request) + { + if(_locator != null && _locator != locator) + { + request.invoke(_locator); + } + else if(IceInternal.Time.currentMonotonicTimeMillis() < _nextRetry) + { + request.invoke(_voidLocator); // Don't retry to find a locator before the retry delay expires + } + else + { + _locator = null; + + _pendingRequests.add(request); + + if(_pendingRetryCount == 0) // No request in progress + { + _pendingRetryCount = _retryCount; + try + { + _lookup.begin_findLocator(_instanceName, _lookupReply); // Send multicast request. + _future = _timer.schedule(_retryTask, _timeout, java.util.concurrent.TimeUnit.MILLISECONDS); + } + catch(Ice.LocalException ex) + { + for(Request req : _pendingRequests) + { + req.invoke(_voidLocator); + } + _pendingRequests.clear(); + _pendingRetryCount = 0; + } + } + } + } + + private Runnable _retryTask = new Runnable() + { + @Override + public void run() + { + synchronized(LocatorI.this) + { + if(--_pendingRetryCount > 0) + { + try + { + _lookup.begin_findLocator(_instanceName, _lookupReply); // Send multicast request. + _future = _timer.schedule(_retryTask, _timeout, java.util.concurrent.TimeUnit.MILLISECONDS); + return; + } + catch(Ice.LocalException ex) + { + } + _pendingRetryCount = 0; + } + + for(Request req : _pendingRequests) + { + req.invoke(_voidLocator); + } + _pendingRequests.clear(); + _nextRetry = IceInternal.Time.currentMonotonicTimeMillis() + _retryDelay; + } + + } + }; + + private final LookupPrx _lookup; + private final int _timeout; + private java.util.concurrent.Future<?> _future; + private final java.util.concurrent.ScheduledExecutorService _timer; + private final int _retryCount; + private final int _retryDelay; + + private String _instanceName; + private boolean _warned; + private LookupReplyPrx _lookupReply; + private Ice.LocatorPrx _locator; + private Ice.LocatorPrx _voidLocator; + + private int _pendingRetryCount; + private List<Request> _pendingRequests = new ArrayList<Request>(); + private long _nextRetry; + }; + + private class LookupReplyI extends _LookupReplyDisp + { + LookupReplyI(LocatorI locator) + { + _locator = locator; + } + + @Override + public void + foundLocator(Ice.LocatorPrx locator, Ice.Current curr) + { + _locator.foundLocator(locator); + } + + private final LocatorI _locator; + }; + + public + PluginI(Ice.Communicator communicator) + { + _communicator = communicator; + } + + @Override + public void + initialize() + { + Ice.Properties properties = _communicator.getProperties(); + + boolean ipv4 = properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0; + boolean preferIPv6 = properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0; + String address; + if(ipv4 && !preferIPv6) + { + address = properties.getPropertyWithDefault("IceLocatorDiscovery.Address", "239.255.0.1"); + } + else + { + address = properties.getPropertyWithDefault("IceLocatorDiscovery.Address", "ff15::1"); + } + int port = properties.getPropertyAsIntWithDefault("IceLocatorDiscovery.Port", 4061); + String intf = properties.getProperty("IceLocatorDiscovery.Interface"); + + if(properties.getProperty("IceLocatorDiscovery.Reply.Endpoints").isEmpty()) + { + StringBuilder s = new StringBuilder(); + s.append("udp"); + if(!intf.isEmpty()) + { + s.append(" -h \"").append(intf).append("\""); + } + properties.setProperty("IceLocatorDiscovery.Reply.Endpoints", s.toString()); + } + if(properties.getProperty("IceLocatorDiscovery.Locator.Endpoints").isEmpty()) + { + properties.setProperty("IceLocatorDiscovery.Locator.AdapterId", java.util.UUID.randomUUID().toString()); + } + + _replyAdapter = _communicator.createObjectAdapter("IceLocatorDiscovery.Reply"); + _locatorAdapter = _communicator.createObjectAdapter("IceLocatorDiscovery.Locator"); + + // We don't want those adapters to be registered with the locator so clear their locator. + _replyAdapter.setLocator(null); + _locatorAdapter.setLocator(null); + + String lookupEndpoints = properties.getProperty("IceLocatorDiscovery.Lookup"); + if(lookupEndpoints.isEmpty()) + { + StringBuilder s = new StringBuilder(); + s.append("udp -h \"").append(address).append("\" -p ").append(port); + if(!intf.isEmpty()) + { + s.append(" --interface \"").append(intf).append("\""); + } + lookupEndpoints = s.toString(); + } + + Ice.ObjectPrx lookupPrx = _communicator.stringToProxy("IceLocatorDiscovery/Lookup -d:" + lookupEndpoints); + lookupPrx = lookupPrx.ice_collocationOptimized(false); // No collocation optimization for the multicast proxy! + try + { + lookupPrx.ice_getConnection(); // Ensure we can establish a connection to the multicast proxy + } + catch(Ice.LocalException ex) + { + StringBuilder s = new StringBuilder(); + s.append("IceLocatorDiscovery is unable to establish a multicast connection:\n"); + s.append("proxy = ").append(lookupPrx.toString()).append("\n").append(ex); + throw new Ice.PluginInitializationException(s.toString()); + } + + Ice.LocatorPrx voidLoc = Ice.LocatorPrxHelper.uncheckedCast(_locatorAdapter.addWithUUID(new VoidLocatorI())); + + String instanceName = properties.getProperty("IceLocatorDiscovery.InstanceName"); + Ice.Identity id = new Ice.Identity(); + id.name = "Locator"; + id.category = !instanceName.isEmpty() ? instanceName : java.util.UUID.randomUUID().toString(); + LocatorI locator = new LocatorI(LookupPrxHelper.uncheckedCast(lookupPrx), properties, instanceName, voidLoc); + _communicator.setDefaultLocator(Ice.LocatorPrxHelper.uncheckedCast(_locatorAdapter.addWithUUID(locator))); + + Ice.ObjectPrx lookupReply = _replyAdapter.addWithUUID(new LookupReplyI(locator)).ice_datagram(); + locator.setLookupReply(LookupReplyPrxHelper.uncheckedCast(lookupReply)); + + _replyAdapter.activate(); + _locatorAdapter.activate(); + } + + @Override + public void + destroy() + { + _replyAdapter.destroy(); + _locatorAdapter.destroy(); + } + + private Ice.Communicator _communicator; + private Ice.ObjectAdapter _locatorAdapter; + private Ice.ObjectAdapter _replyAdapter; +} diff --git a/java-compat/src/IcePatch2/build.gradle b/java-compat/src/IcePatch2/build.gradle new file mode 100644 index 00000000000..31ede53de5a --- /dev/null +++ b/java-compat/src/IcePatch2/build.gradle @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IcePatch2 Compat" +project.ext.description = "File distribution and patching for Ice" + +slice { + java { + set1 { + args = "--ice --tie --checksum IcePatch2.SliceChecksums" + files = fileTree(dir: "$sliceDir/IcePatch2", includes:['*.ice'], excludes:["*F.ice"]) + } + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" diff --git a/java-compat/src/IceStorm/build.gradle b/java-compat/src/IceStorm/build.gradle new file mode 100644 index 00000000000..9ce6d131b0f --- /dev/null +++ b/java-compat/src/IceStorm/build.gradle @@ -0,0 +1,29 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +sourceCompatibility = iceSourceCompatibility +targetCompatibility = iceTargetCompatibility + +project.ext.displayName = "IceStorm Compat" +project.ext.description = "Publish-subscribe event distribution service" + +slice { + java { + set1 { + args = "--ice --tie --checksum IceStorm.SliceChecksums" + files = fileTree(dir: "$sliceDir/IceStorm", includes:['*.ice'], excludes:["*F.ice"]) + } + } +} + +dependencies { + compile project(':ice-compat') +} + +apply from: "$rootProject.projectDir/../java/gradle/library.gradle" |