summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2001-11-15 23:20:31 +0000
committerMark Spruiell <mes@zeroc.com>2001-11-15 23:20:31 +0000
commit1743bba7dd12d7cab787cd9f16ecd1df875d421c (patch)
tree05a2621e726e688315d27fb1ed02bfc0637e71fc
parentminor fixes (diff)
downloadice-1743bba7dd12d7cab787cd9f16ecd1df875d421c.tar.bz2
ice-1743bba7dd12d7cab787cd9f16ecd1df875d421c.tar.xz
ice-1743bba7dd12d7cab787cd9f16ecd1df875d421c.zip
initial check-in
-rw-r--r--java/src/Ice/CommunicatorI.java206
-rw-r--r--java/src/Ice/PropertiesI.java175
-rw-r--r--java/src/IceInternal/CollectorFactory.java352
-rw-r--r--java/src/IceInternal/Protocol.java38
-rw-r--r--java/src/IceInternal/TraceLevels.java87
-rw-r--r--java/src/IceInternal/TraceUtil.java145
6 files changed, 1003 insertions, 0 deletions
diff --git a/java/src/Ice/CommunicatorI.java b/java/src/Ice/CommunicatorI.java
new file mode 100644
index 00000000000..a300cec912e
--- /dev/null
+++ b/java/src/Ice/CommunicatorI.java
@@ -0,0 +1,206 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+package Ice;
+
+class CommunicatorI implements Communicator
+{
+ public synchronized void
+ destroy()
+ {
+ if (_instance != null)
+ {
+ _instance.destroy();
+ _instance = null;
+ }
+ }
+
+ public void
+ shutdown()
+ {
+ //
+ // No mutex locking here!
+ //
+ _threadPool.initiateServerShutdown();
+ }
+
+ public void
+ waitForShutdown()
+ {
+ //
+ // No mutex locking here, otherwise the communicator is blocked
+ // while waiting for shutdown.
+ //
+ _threadPool.waitUntilServerFinished();
+ }
+
+ public synchronized Ice.ObjectPrx
+ stringToProxy(String s)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.proxyFactory().stringToProxy(s);
+ }
+
+ public synchronized String
+ proxyToString(Ice.ObjectPrx proxy)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.proxyFactory().proxyToString(proxy);
+ }
+
+ public synchronized ObjectAdapter
+ createObjectAdapter(String name)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ String endpts = _instance.properties().getProperty(
+ "Ice.Adapter." + name + ".Endpoints");
+ return createObjectAdapterWithEndpoints(name, endpts);
+ }
+
+ public synchronized ObjectAdapter
+ createObjectAdapterWithEndpoints(String name, String endpts)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.objectAdapterFactory().createObjectAdapter(
+ name, endpts);
+ }
+
+ public synchronized void
+ addObjectFactory(ObjectFactory factory, String id)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ _instance.servantFactoryManager().add(factory, id);
+ }
+
+ public synchronized void
+ removeObjectFactory(String id)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ _instance.servantFactoryManager().remove(id);
+ }
+
+ public synchronized ObjectFactory
+ findObjectFactory(String id)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.servantFactoryManager().find(id);
+ }
+
+ public synchronized void
+ addUserExceptionFactory(UserExceptionFactory factory, String id)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ _instance.userExceptionFactoryManager().add(factory, id);
+ }
+
+ public synchronized void
+ removeUserExceptionFactory(String id)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ _instance.userExceptionFactoryManager().remove(id);
+ }
+
+ public synchronized UserExceptionFactory
+ findUserExceptionFactory(String id)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.userExceptionFactoryManager().find(id);
+ }
+
+ public synchronized Properties
+ getProperties()
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.properties();
+ }
+
+ public synchronized Logger
+ getLogger()
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ return _instance.logger();
+ }
+
+ public synchronized void
+ setLogger(Logger logger)
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+ _instance.logger(logger);
+ }
+
+ public Stream
+ createStream()
+ {
+ if (_instance == null)
+ {
+ throw new CommunicatorDestroyedException();
+ }
+
+ return new StreamI(_instance);
+ }
+
+ CommunicatorI(Properties propertites)
+ {
+ _instance = new IceInternal.Instance(this, properties);
+ _threadPool = _instance.threadPool();
+ }
+
+ protected void
+ finalize()
+ throws Throwable
+ {
+ if (_instance != null)
+ {
+ _instance.logger().warning("communicator has not been destroyed");
+ }
+ }
+
+ private IceInternal.Instance _instance;
+ private IceInternal.ThreadPool _threadPool;
+}
diff --git a/java/src/Ice/PropertiesI.java b/java/src/Ice/PropertiesI.java
new file mode 100644
index 00000000000..8a506ef4171
--- /dev/null
+++ b/java/src/Ice/PropertiesI.java
@@ -0,0 +1,175 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+package Ice;
+
+class PropertiesI implements Properties
+{
+ public String
+ getProperty(String key)
+ {
+ String result = (String)_properties.get(key);
+ if (result == null)
+ {
+ result = System.getProperty(key);
+ }
+ return result;
+ }
+
+ public void
+ setProperty(String key, String value)
+ {
+ _properties.put(key, value);
+ }
+
+ public Properties
+ _clone()
+ {
+ PropertiesI p = new PropertiesI(new String[0]);
+ p._properties.putAll(_properties);
+ return p;
+ }
+
+ PropertiesI(String[] args)
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ if (args[i].startsWith("--Ice.Config"))
+ {
+ String line = args[i];
+ if (line.indexOf('=') == -1)
+ {
+ line += "=1";
+ }
+ parseLine(line.substring(2));
+ }
+ }
+
+ String file = getProperty("Ice.Config");
+
+ if (file == null || file.equals("1"))
+ {
+ file = "";
+ }
+
+ if (file.length() > 0)
+ {
+ load(file);
+ }
+
+ parseArgs(args);
+ setProperty("Ice.Config", file);
+ }
+
+ PropertiesI(String[] args, String file)
+ {
+ if (file == null)
+ {
+ file = "";
+ }
+
+ if (file.length() > 0)
+ {
+ load(file);
+ }
+
+ parseArgs(args);
+ setProperty("Ice.Config", file);
+ }
+
+ private void
+ parseArgs(String[] args)
+ {
+ int idx = 0;
+ while (idx < args.length)
+ {
+ if (args[idx].startsWith("--Ice."))
+ {
+ String line = args[idx];
+ if (line.indexOf('=') == -1)
+ {
+ line += "=1";
+ }
+
+ parseLine(line.substring(2));
+ }
+ else
+ {
+ idx++;
+ }
+ }
+ }
+
+ private void
+ load(String file)
+ {
+ try
+ {
+ java.io.FileReader fr = new java.io.FileReader(file);
+ java.io.BufferedReader br = new java.io.BufferedReader(br);
+ parse(br);
+ }
+ catch (java.io.IOException ex)
+ {
+ SystemException ex = new SystemException();
+ ex.initCause(ex); // Exception chaining
+ throw ex;
+ }
+ }
+
+ private void
+ parse(java.io.BufferedReader in)
+ {
+ String line;
+ while ((line = in.readLine()) != null)
+ {
+ parseLine(line);
+ }
+ }
+
+ private void
+ parseLine(String line)
+ {
+ String s = line;
+
+ int hash = s.indexOf('#');
+ if (hash == 0)
+ {
+ return; // ignore comment lines
+ }
+ else if (hash != -1)
+ {
+ s = s.substring(0, hash);
+ }
+
+ s = s.trim();
+
+ // TODO: Could also use a regex
+ int pos = s.indexOf(' ');
+ if (pos == -1)
+ {
+ pos = s.indexOf('\t');
+ }
+ if (pos == -1)
+ {
+ pos = s.indexOf('=');
+ }
+ if (pos == -1 || pos == s.length() - 1)
+ {
+ return;
+ }
+
+ String key = s.substring(0, pos);
+ String value = s.substring(pos + 1).trim();
+ setProperty(key, value);
+ }
+
+ private java.util.HashMap _properties = new java.util.HashMap();
+}
diff --git a/java/src/IceInternal/CollectorFactory.java b/java/src/IceInternal/CollectorFactory.java
new file mode 100644
index 00000000000..7e82e67868d
--- /dev/null
+++ b/java/src/IceInternal/CollectorFactory.java
@@ -0,0 +1,352 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+package IceInternal;
+
+public class CollectorFactory extends EventHandler
+{
+ public synchronized void
+ destroy()
+ {
+ setState(StateClosed);
+ }
+
+ public synchronized void
+ hold()
+ {
+ setState(StateHolding);
+ }
+
+ public synchronized void
+ activate()
+ {
+ setState(StateActive);
+ }
+
+ public Endpoint
+ endpoint()
+ {
+ return _endpoint;
+ }
+
+ public boolean
+ equivalent(Endpoint endp)
+ {
+ if (_transceiver != null)
+ {
+ return endp.equivalent(_transceiver);
+ }
+
+ assert(_acceptor != null);
+ return endp.equivalent(_acceptor);
+ }
+
+ //
+ // Operations from EventHandler
+ //
+ public boolean
+ server()
+ {
+ return true;
+ }
+
+ public boolean
+ readable()
+ {
+ return false;
+ }
+
+ public void
+ read(Ice.Stream is)
+ {
+ assert(false); // Must not be called
+ }
+
+ public synchronized void
+ message(Ice.Stream stream)
+ {
+ _threadPool.promoteFollower();
+
+ if (_state != StateActive)
+ {
+ return;
+ }
+
+ //
+ // First reap destroyed collectors
+ //
+ java.util.ListIterator i = _collectors.listIterator();
+ while (i.hasNext())
+ {
+ Collector c = (Collector)i.next();
+ if (c.destroyed())
+ {
+ i.remove();
+ }
+ }
+
+ //
+ // Now accept a new connection and create a new Collector
+ //
+ try
+ {
+ Transceive transceiver = _acceptor.accept(0);
+ Collector collector = new Collector(_instance, _adapter,
+ transceiver, _endpoint);
+ collector.activate();
+ _collectors.add(collector);
+ }
+ catch (SecurityException ex)
+ {
+ // Ignore, nothing we can do here
+ }
+ catch (SocketException ex)
+ {
+ // Ignore, nothing we can do here
+ }
+ catch (TimeoutException ex)
+ {
+ // Ignore timeouts
+ }
+ catch (LocalException ex)
+ {
+ warning(ex);
+ setState(StateClosed);
+ }
+ }
+
+ public void
+ exception(Ice.LocalException ex)
+ {
+ assert(false); // Must not be called
+ }
+
+ public synchronized void
+ finished()
+ {
+ //
+ // We also unregister with the thread pool if we go to holding
+ // state, but in this case we may not close the connection.
+ //
+ if (_state == StateClosed)
+ {
+ _acceptor.shutdown();
+ clearBacklog();
+ _acceptor.close();
+ }
+ }
+
+ public boolean
+ tryDestroy()
+ {
+ //
+ // Do nothing. We don't want collector factories to be closed by
+ // active connection management.
+ //
+ return false;
+ }
+
+ //
+ // Only for use by Ice.ObjectAdapterI
+ //
+ public
+ CollectorFactory(Instance instance,
+ Ice.ObjectAdapter adapter,
+ Endpoint endpoint)
+ {
+ super(instance);
+ _adapter = adapter;
+ _endpoint = endpoint;
+ _traceLevels = instance.traceLevels();
+ _logger = instance.logger();
+ _state = StateHolding;
+
+ try
+ {
+ String value = instance.properties().getProperty(
+ "Ice.WarnAboutServerExceptions");
+ _warnAboutExceptions = Integer.parseInt(value) > 0 ? true : false;
+ }
+ catch(NumberFormatException ex)
+ {
+ _warnAboutExceptions = false;
+ }
+
+ try
+ {
+ _transceiver = _endpoint.serverTransceiver(_instance, _endpoint);
+ if (_transceiver != null)
+ {
+ Collector collector = new Collector(_instance, _adapter,
+ _transceiver, _endpoint);
+ _collectors.add(collector);
+ }
+ else
+ {
+ _acceptor = _endpoint.acceptor(_instance, _endpoint);
+ assert(_acceptor != null);
+ _acceptor.listen();
+ _threadPool = instance.threadPool();
+ }
+ }
+ catch (Ice.LocalException ex)
+ {
+ setState(StateClosed);
+ throw ex;
+ }
+ }
+
+ protected void
+ finalize()
+ throws Throwable
+ {
+ assert(_state == StateClosed);
+ }
+
+ private static final int StateActive = 0;
+ private static final int StateHolding = 1;
+ private static final int StateClosing = 2;
+ private static final int StateClosed = 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 (_threadPool != null)
+ {
+ _threadPool._register(_acceptor.fd(), this);
+ }
+
+ java.util.ListIterator i = _collectors.listIterator();
+ while (i.hasNext())
+ {
+ Collector c = (Collector)i.next();
+ c.activate();
+ }
+
+ break;
+ }
+
+ case StateHolding:
+ {
+ if (_state != StateActive) // Can only switch from active
+ { // to holding
+ return;
+ }
+
+ if (_threadPool != null)
+ {
+ _threadPool.unregister(_acceptor.fd());
+ }
+
+ java.util.ListIterator i = _collectors.listIterator();
+ while (i.hasNext())
+ {
+ Collector c = (Collector)i.next();
+ c.hold();
+ }
+
+ break;
+ }
+
+ case StateClosed:
+ {
+ if (_threadPool != null)
+ {
+ //
+ // If we come from holding state, we are already
+ // unregistered, so we can close right away.
+ //
+ if (_state == StateHolding)
+ {
+ _acceptor.shutdown();
+ clearBacklog();
+ _acceptor.close();
+ }
+ else
+ {
+ _threadPool.unregister(_acceptor.fd());
+ }
+ }
+
+ java.util.ListIterator i = _collectors.listIterator();
+ while (i.hasNext())
+ {
+ Collector c = (Collector)i.next();
+ c.destroy();
+ }
+ _collectors.clear();
+
+ break;
+ }
+ }
+
+ _state = state;
+ }
+
+ private void
+ clearBacklog()
+ {
+ //
+ // Clear listen() backlog properly by accepting all queued
+ // connections, and then shutting them down.
+ //
+ while (true)
+ {
+ try
+ {
+ Transceiver transceiver = _acceptor.accept(0);
+ Collector collector = new Collector(_instance, _adapter,
+ transceiver, _endpoint);
+ collector.destroy();
+ }
+ catch (Ice.LocalException ex)
+ {
+ break;
+ }
+ }
+ }
+
+ private void
+ warning(Ice.LocalException ex)
+ {
+ if (_warnAboutExceptions)
+ {
+ String s = "server exception:\n" + ex + '\n' +
+ _transceiver.toString();
+ // TODO: Stack trace?
+ _logger.warning(s);
+ }
+ }
+
+ private Ice.ObjectAdapter _adapter;
+ private Acceptor _acceptor;
+ private Transceiver _transceiver;
+ private Endpoint _endpoint;
+ private TraceLevels _traceLevels;
+ private Ice.Logger _logger;
+ private ThreadPool _threadPool;
+ private java.util.LinkedList _collectors = new java.util.LinkedList();
+ private int _state;
+ private boolean _warnAboutExceptions;
+}
diff --git a/java/src/IceInternal/Protocol.java b/java/src/IceInternal/Protocol.java
new file mode 100644
index 00000000000..4b326fef4fc
--- /dev/null
+++ b/java/src/IceInternal/Protocol.java
@@ -0,0 +1,38 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+package IceInternal;
+
+final class Protocol
+{
+ //
+ // Size of the Ice protocol header
+ //
+ // Protocol version (Byte)
+ // Encoding version (Byte)
+ // Message type (Byte)
+ // Message size (Int)
+ //
+ final static int headerSize = 7;
+
+ //
+ // The current Ice protocol and encoding version
+ //
+ final static byte protocolVersion = 0;
+ final static byte encodingVersion = 0;
+
+ //
+ // The Ice protocol message types
+ //
+ final static byte requestMsg = 0;
+ final static byte requestBatchMsg = 1;
+ final static byte replyMsg = 2;
+ final static byte closeConnectionMsg = 3;
+}
diff --git a/java/src/IceInternal/TraceLevels.java b/java/src/IceInternal/TraceLevels.java
new file mode 100644
index 00000000000..331b40a7147
--- /dev/null
+++ b/java/src/IceInternal/TraceLevels.java
@@ -0,0 +1,87 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+package IceInternal;
+
+final class TraceLevels
+{
+ public
+ TraceLevels(Ice.Properties properties)
+ {
+ network = 0;
+ networkCat = "Network";
+ protocol = 0;
+ protocolCat = "Protocol";
+ retry = 0;
+ retryCat = "Retry";
+ security = 0;
+ securityCat = "Security";
+
+ String value;
+ final String keyBase = "Ice.Trace.";
+
+ value = properties.getProperty(keyBase + networkCat);
+ if (value != null)
+ {
+ try
+ {
+ network = Integer.parseInt(value);
+ }
+ catch (NumberFormatException ex)
+ {
+ }
+ }
+
+ value = properties.getProperty(keyBase + protocolCat);
+ if (value != null)
+ {
+ try
+ {
+ protocol = Integer.parseInt(value);
+ }
+ catch (NumberFormatException ex)
+ {
+ }
+ }
+
+ value = properties.getProperty(keyBase + retryCat);
+ if (value != null)
+ {
+ try
+ {
+ retry = Integer.parseInt(value);
+ }
+ catch (NumberFormatException ex)
+ {
+ }
+ }
+
+ value = properties.getProperty(keyBase + securityCat);
+ if (value != null)
+ {
+ try
+ {
+ security = Integer.parseInt(value);
+ }
+ catch (NumberFormatException ex)
+ {
+ }
+ }
+ }
+
+ int network;
+ String networkCat;
+ int protocol;
+ String protocolCat;
+ int retry;
+ String retryCat;
+ int security;
+ String securityCat;
+}
diff --git a/java/src/IceInternal/TraceUtil.java b/java/src/IceInternal/TraceUtil.java
new file mode 100644
index 00000000000..f4f6116251d
--- /dev/null
+++ b/java/src/IceInternal/TraceUtil.java
@@ -0,0 +1,145 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+package IceInternal;
+
+final class TraceUtil
+{
+ static void
+ traceHeader(String heading, Ice.Stream stream, Ice.Logger logger,
+ TraceLevels tl)
+ {
+ if (tl.protocol >= 1)
+ {
+ // TODO: stream stuff
+ java.io.StringWriter s = new java.io.StringWriter();
+ s.write(heading);
+ printHeader(s, stream);
+ logger.trace(tl.protocolCat, s.toString());
+ }
+ }
+
+ static void
+ traceRequest(String heading, Ice.Stream stream, Ice.Logger logger,
+ TraceLevels tl)
+ {
+ if (tl.protocol >= 1)
+ {
+ // TODO: stream stuff
+ java.io.StringWriter s = new java.io.StringWriter();
+ s.write(heading);
+ printHeader(s, stream);
+ int requestId = stream.readInt();
+ s.write("\nrequest id = " + requestId);
+ if (requestId == 0)
+ {
+ s.write(" (oneway)");
+ }
+ String identity = stream.readString();
+ s.write("\nidentity = " + identity);
+ String facet = stream.readString();
+ s.write("\nfacet = " + facet);
+ String operation = stream.readString();
+ s.write("\noperation name = " + operation);
+ logger.trace(tl.protocolCat, s.toString());
+ }
+ }
+
+ static void
+ traceBatchRequest(String heading, Ice.Stream stream, Ice.Logger logger,
+ TraceLevels tl)
+ {
+ if (tl.protocol >= 1)
+ {
+ // TODO: stream stuff
+ java.io.StringWriter s = new java.io.StringWriter();
+ s.write(heading);
+ printHeader(s, stream);
+ int cnt = 0;
+ while (true /* stream.i != stream.b.end() */ )
+ {
+ s.write("\nrequest #" + cnt + ':');
+ cnt++;
+ // TODO
+ stream.startReadEncaps();
+ String identity = stream.readString();
+ s.write("\nidentity = " + identity);
+ String facet = stream.readString();
+ s.write("\nfacet = " + facet);
+ String operation = stream.readString();
+ s.write("\noperation name = " + operation);
+ // TODO
+ stream.skipEncaps();
+ }
+ logger.trace(tl.protocolCat, s.toString());
+ }
+ }
+
+ static void
+ traceReply(String heading, Ice.Stream stream, Ice.Logger logger,
+ TraceLevels tl)
+ {
+ if (tl.protocol >= 1)
+ {
+ // TODO: stream stuff
+ java.io.StringWriter s = new java.io.StringWriter();
+ s.write(heading);
+ printHeader(s, stream);
+ int requestId = stream.readInt();
+ s.write("\nrequest id = " + requestId);
+ byte status = stream.readByte();
+ s.write("\nreply status = " + (int)status + ' ');
+ switch (status)
+ {
+ case DispatchStatus._DispatchOK:
+ {
+ s.write("(ok)");
+ break;
+ }
+ case DispatchStatus._DispatchUserException:
+ {
+ s.write("(user exception)");
+ break;
+ }
+ case DispatchStatus._DispatchLocationForward:
+ {
+ s.write("(location forward)");
+ break;
+ }
+ case DispatchStatus._DispatchObjectNotExist:
+ {
+ s.write("(object not exist)");
+ break;
+ }
+ case DispatchStatus._DispatchOperationNotExist:
+ {
+ s.write("(operation not exist)");
+ break;
+ }
+ case DispatchStatus._DispatchUnknownLocalException:
+ {
+ s.write("(unknown local exception)");
+ break;
+ }
+ case DispatchStatus._DispatchUnknownException:
+ {
+ s.write("(unknown exception)");
+ break;
+ }
+ default:
+ {
+ s.write("(unknown)");
+ break;
+ }
+ }
+ logger.trace(tl.protocolCat, s.toString());
+ }
+ }
+}