xref: /AOO41X/main/jurt/com/sun/star/lib/uno/protocols/urp/urp.java (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package com.sun.star.lib.uno.protocols.urp;
29 
30 import com.sun.star.bridge.InvalidProtocolChangeException;
31 import com.sun.star.bridge.ProtocolProperty;
32 import com.sun.star.bridge.XProtocolProperties;
33 import com.sun.star.lang.DisposedException;
34 import com.sun.star.lib.uno.environments.remote.IProtocol;
35 import com.sun.star.lib.uno.environments.remote.Message;
36 import com.sun.star.lib.uno.environments.remote.ThreadId;
37 import com.sun.star.lib.uno.typedesc.MethodDescription;
38 import com.sun.star.lib.uno.typedesc.TypeDescription;
39 import com.sun.star.uno.Any;
40 import com.sun.star.uno.IBridge;
41 import com.sun.star.uno.IMethodDescription;
42 import com.sun.star.uno.ITypeDescription;
43 import com.sun.star.uno.Type;
44 import com.sun.star.uno.TypeClass;
45 import com.sun.star.uno.UnoRuntime;
46 import com.sun.star.uno.XCurrentContext;
47 import java.io.DataInput;
48 import java.io.DataInputStream;
49 import java.io.DataOutputStream;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.io.OutputStream;
53 import java.lang.reflect.Array;
54 import java.util.ArrayList;
55 import java.util.Random;
56 import java.util.StringTokenizer;
57 
58 // This class internally relies on the availability of Java UNO type information
59 // for the interface type com.sun.star.bridge.XProtocolProperties, even though
60 // URP itself does not rely on that type.
61 
62 public final class urp implements IProtocol {
63     public urp(
64         IBridge bridge, String attributes, InputStream input,
65         OutputStream output)
66     {
67         this.input = new DataInputStream(input);
68         this.output = new DataOutputStream(output);
69         marshal = new Marshal(bridge, CACHE_SIZE);
70         unmarshal = new Unmarshal(bridge, CACHE_SIZE);
71         forceSynchronous = parseAttributes(attributes);
72     }
73 
74     // @see IProtocol#init
75     public void init() throws IOException {
76         synchronized (monitor) {
77             if (state == STATE_INITIAL0) {
78                 sendRequestChange();
79             }
80         }
81     }
82 
83     // @see IProtocol#terminate
84     public void terminate() {
85         synchronized (monitor) {
86             state = STATE_TERMINATED;
87             initialized = true;
88             monitor.notifyAll();
89         }
90     }
91 
92     // @see IProtocol#readMessage
93     public Message readMessage() throws IOException {
94         for (;;) {
95             if (!unmarshal.hasMore()) {
96                 unmarshal.reset(readBlock());
97                 if (!unmarshal.hasMore()) {
98                     throw new IOException("closeConnection message received");
99                 }
100             }
101             UrpMessage msg;
102             int header = unmarshal.read8Bit();
103             if ((header & HEADER_LONGHEADER) != 0) {
104                 if ((header & HEADER_REQUEST) != 0) {
105                     msg = readLongRequest(header);
106                 } else {
107                     msg = readReply(header);
108                 }
109             } else {
110                 msg = readShortRequest(header);
111             }
112             if (msg.isInternal()) {
113                 handleInternalMessage(msg);
114             } else {
115                 return msg;
116             }
117         }
118     }
119 
120     // @see IProtocol#writeRequest
121     public boolean writeRequest(
122         String oid, TypeDescription type, String function, ThreadId tid,
123         Object[] arguments)
124         throws IOException
125     {
126         if (oid.equals(PROPERTIES_OID)) {
127             throw new IllegalArgumentException("illegal OID " + oid);
128         }
129         synchronized (monitor) {
130             while (!initialized) {
131                 try {
132                     monitor.wait();
133                 } catch (InterruptedException e) {
134                     Thread.currentThread().interrupt();
135                     throw new RuntimeException(e.toString());
136                 }
137             }
138             if (state == STATE_TERMINATED) {
139                 throw new DisposedException();
140             }
141             return writeRequest(false, oid, type, function, tid, arguments);
142         }
143     }
144 
145     // @see IProtocol#writeReply
146     public void writeReply(boolean exception, ThreadId tid, Object result)
147         throws IOException
148     {
149         synchronized (output) {
150             writeQueuedReleases();
151             int header = HEADER_LONGHEADER;
152             PendingRequests.Item pending = pendingIn.pop(tid);
153             TypeDescription resultType;
154             ITypeDescription[] argTypes;
155             Object[] args;
156             if (exception) {
157                 header |= HEADER_EXCEPTION;
158                 resultType = TypeDescription.getTypeDescription(TypeClass.ANY);
159                 argTypes = null;
160                 args = null;
161             } else {
162                 resultType = (TypeDescription)
163                     pending.function.getReturnSignature();
164                 argTypes = pending.function.getOutSignature();
165                 args = pending.arguments;
166             }
167             if (!tid.equals(outL1Tid)) {
168                 header |= HEADER_NEWTID;
169                 outL1Tid = tid;
170             } else {
171                 tid = null;
172             }
173             marshal.write8Bit(header);
174             if (tid != null) {
175                 marshal.writeThreadId(tid);
176             }
177             marshal.writeValue(resultType, result);
178             if (argTypes != null) {
179                 for (int i = 0; i < argTypes.length; ++i) {
180                     if (argTypes[i] != null) {
181                         marshal.writeValue(
182                             (TypeDescription) argTypes[i].getComponentType(),
183                             Array.get(args[i], 0));
184                     }
185                 }
186             }
187             writeBlock(true);
188         }
189     }
190 
191     private void sendRequestChange() throws IOException {
192         if (propertiesTid == null) {
193             propertiesTid = ThreadId.createFresh();
194         }
195         random = new Random().nextInt();
196         writeRequest(
197             true, PROPERTIES_OID,
198             TypeDescription.getTypeDescription(XProtocolProperties.class),
199             PROPERTIES_FUN_REQUEST_CHANGE, propertiesTid,
200             new Object[] { new Integer(random) });
201         state = STATE_REQUESTED;
202     }
203 
204     private void handleInternalMessage(Message message) throws IOException {
205         if (message.isRequest()) {
206             String t = message.getType().getTypeName();
207             if (!t.equals("com.sun.star.bridge.XProtocolProperties")) {
208                 throw new IOException(
209                     "read URP protocol properties request with unsupported"
210                     + " type " + t);
211             }
212             int fid = message.getMethod().getIndex();
213             switch (fid) {
214             case PROPERTIES_FID_REQUEST_CHANGE:
215                 checkSynchronousPropertyRequest(message);
216                 synchronized (monitor) {
217                     switch (state) {
218                     case STATE_INITIAL0:
219                     case STATE_INITIAL:
220                         writeReply(
221                             false, message.getThreadId(), new Integer(1));
222                         state = STATE_WAIT;
223                         break;
224                     case STATE_REQUESTED:
225                         int n
226                             = ((Integer) message.getArguments()[0]).intValue();
227                         if (random < n) {
228                             writeReply(
229                                 false, message.getThreadId(), new Integer(1));
230                             state = STATE_WAIT;
231                         } else if (random == n) {
232                             writeReply(
233                                 false, message.getThreadId(), new Integer(-1));
234                             state = STATE_INITIAL;
235                             sendRequestChange();
236                         } else {
237                             writeReply(
238                                 false, message.getThreadId(), new Integer(0));
239                         }
240                         break;
241                     default:
242                         writeReply(
243                             true, message.getThreadId(),
244                             new com.sun.star.uno.RuntimeException(
245                                 "read URP protocol properties requestChange"
246                                 + " request in illegal state"));
247                         break;
248                     }
249                 }
250                 break;
251             case PROPERTIES_FID_COMMIT_CHANGE:
252                 checkSynchronousPropertyRequest(message);
253                 synchronized (monitor) {
254                     if (state == STATE_WAIT) {
255                         ProtocolProperty[] p = (ProtocolProperty[])
256                             message.getArguments()[0];
257                         boolean ok = true;
258                         boolean cc = false;
259                         int i = 0;
260                         for (; i < p.length; ++i) {
261                             if (p[i].Name.equals(PROPERTY_CURRENT_CONTEXT)) {
262                                 cc = true;
263                             } else {
264                                 ok = false;
265                                 break;
266                             }
267                         }
268                         if (ok) {
269                             writeReply(false, message.getThreadId(), null);
270                         } else {
271                             writeReply(
272                                 true, message.getThreadId(),
273                                 new InvalidProtocolChangeException(
274                                     "", null, p[i], 1));
275                         }
276                         state = STATE_INITIAL;
277                         if (!initialized) {
278                             if (cc) {
279                                 currentContext = true;
280                                 initialized = true;
281                                 monitor.notifyAll();
282                             } else {
283                                 sendRequestChange();
284                             }
285                         }
286                     } else {
287                         writeReply(
288                             true, message.getThreadId(),
289                             new com.sun.star.uno.RuntimeException(
290                                 "read URP protocol properties commitChange"
291                                 + " request in illegal state"));
292                     }
293                 }
294                 break;
295             default:
296                 throw new IOException(
297                     "read URP protocol properties request with unsupported"
298                     + " function ID " + fid);
299             }
300         } else {
301             synchronized (monitor) {
302                 if (state == STATE_COMMITTED) {
303                     // commitChange reply:
304                     if (!message.isAbnormalTermination()) {
305                         currentContext = true;
306                     }
307                     state = STATE_INITIAL;
308                     initialized = true;
309                     monitor.notifyAll();
310                 } else {
311                     // requestChange reply:
312                     if (message.isAbnormalTermination()) {
313                         // remote side probably does not support negotiation:
314                         state = STATE_INITIAL;
315                         initialized = true;
316                         monitor.notifyAll();
317                     } else {
318                         int n = ((Integer) message.getResult()).intValue();
319                         switch (n) {
320                         case -1:
321                         case 0:
322                             break;
323                         case 1:
324                             writeRequest(
325                                 true, PROPERTIES_OID,
326                                 TypeDescription.getTypeDescription(
327                                     XProtocolProperties.class),
328                                 PROPERTIES_FUN_COMMIT_CHANGE, propertiesTid,
329                                 new Object[] {
330                                     new ProtocolProperty[] {
331                                         new ProtocolProperty(
332                                             PROPERTY_CURRENT_CONTEXT,
333                                             Any.VOID) } });
334                             state = STATE_COMMITTED;
335                             break;
336                         default:
337                             throw new IOException(
338                                 "read URP protocol properties "
339                                 + PROPERTIES_FUN_REQUEST_CHANGE
340                                 + " reply with illegal return value " + n);
341                         }
342                     }
343                 }
344             }
345         }
346     }
347 
348     private void checkSynchronousPropertyRequest(Message message)
349         throws IOException
350     {
351         if (!message.isSynchronous()) {
352             throw new IOException(
353                 "read URP protocol properties request for synchronous function"
354                 + " marked as not SYNCHRONOUS");
355         }
356     }
357 
358     private byte[] readBlock() throws IOException {
359         int size = input.readInt();
360         input.readInt(); // ignore count
361         byte[] bytes = new byte[size];
362         input.readFully(bytes);
363         return bytes;
364     }
365 
366     private UrpMessage readLongRequest(int header) throws IOException {
367         boolean sync = false;
368         if ((header & HEADER_MOREFLAGS) != 0) {
369             if (unmarshal.read8Bit() != (HEADER_MUSTREPLY | HEADER_SYNCHRONOUS))
370             {
371                 throw new IOException(
372                     "read URP request with bad MUSTREPLY/SYNCHRONOUS byte");
373             }
374             sync = true;
375         }
376         int funId = (header & HEADER_FUNCTIONID16) != 0
377             ? unmarshal.read16Bit() : unmarshal.read8Bit();
378         if ((header & HEADER_NEWTYPE) != 0) {
379             inL1Type = unmarshal.readType();
380             if (inL1Type.getTypeClass() != TypeClass.INTERFACE) {
381                 throw new IOException(
382                     "read URP request with non-interface type " + inL1Type);
383             }
384         }
385         if ((header & HEADER_NEWOID) != 0) {
386             inL1Oid = unmarshal.readObjectId();
387         }
388         if ((header & HEADER_NEWTID) != 0) {
389             inL1Tid = unmarshal.readThreadId();
390         }
391         return readRequest(funId, sync);
392     }
393 
394     private UrpMessage readShortRequest(int header) {
395         int funId = (header & HEADER_FUNCTIONID14) != 0
396             ? ((header & HEADER_FUNCTIONID) << 8) | unmarshal.read8Bit()
397             : header & HEADER_FUNCTIONID;
398         return readRequest(funId, false);
399     }
400 
401     private UrpMessage readRequest(int functionId, boolean forcedSynchronous) {
402         boolean internal = PROPERTIES_OID.equals(inL1Oid);
403             // inL1Oid may be null in XInstanceProvider.getInstance("")
404         XCurrentContext cc =
405             (currentContext && !internal
406              && functionId != MethodDescription.ID_RELEASE)
407             ? (XCurrentContext) unmarshal.readInterface(
408                 new Type(XCurrentContext.class))
409             : null;
410         IMethodDescription desc = inL1Type.getMethodDescription(functionId);
411         ITypeDescription[] inSig = desc.getInSignature();
412         ITypeDescription[] outSig = desc.getOutSignature();
413         Object[] args = new Object[inSig.length];
414         for (int i = 0; i < args.length; ++i) {
415             if (inSig[i] != null) {
416                 if (outSig[i] != null) {
417                     Object inout = Array.newInstance(
418                         outSig[i].getComponentType().getZClass(), 1);
419                     Array.set(
420                         inout, 0,
421                         unmarshal.readValue(
422                             (TypeDescription) outSig[i].getComponentType()));
423                     args[i] = inout;
424                 } else {
425                     args[i] = unmarshal.readValue((TypeDescription) inSig[i]);
426                 }
427             } else {
428                 args[i] = Array.newInstance(
429                     outSig[i].getComponentType().getZClass(), 1);
430             }
431         }
432         boolean sync = forcedSynchronous || !desc.isOneway();
433         if (sync) {
434             pendingIn.push(
435                 inL1Tid, new PendingRequests.Item(internal, desc, args));
436         }
437         return new UrpMessage(
438             inL1Tid, true, inL1Oid, inL1Type, desc, sync, cc, false, null, args,
439             internal);
440     }
441 
442     private UrpMessage readReply(int header) {
443         if ((header & HEADER_NEWTID) != 0) {
444             inL1Tid = unmarshal.readThreadId();
445         }
446         PendingRequests.Item pending = pendingOut.pop(inL1Tid);
447         TypeDescription resultType;
448         ITypeDescription[] argTypes;
449         Object[] args;
450         boolean exception = (header & HEADER_EXCEPTION) != 0;
451         if (exception) {
452             resultType = TypeDescription.getTypeDescription(TypeClass.ANY);
453             argTypes = null;
454             args = null;
455         } else {
456             resultType = (TypeDescription)
457                 pending.function.getReturnSignature();
458             argTypes = pending.function.getOutSignature();
459             args = pending.arguments;
460         }
461         Object result = resultType == null
462             ? null : unmarshal.readValue(resultType);
463         if (argTypes != null) {
464             for (int i = 0; i < argTypes.length; ++i) {
465                 if (argTypes[i] != null) {
466                     Array.set(
467                         args[i], 0,
468                         unmarshal.readValue(
469                             (TypeDescription) argTypes[i].getComponentType()));
470                 }
471             }
472         }
473         return new UrpMessage(
474             inL1Tid, false, null, null, null, false, null, exception, result,
475             args, pending.internal);
476     }
477 
478     private boolean writeRequest(
479         boolean internal, String oid, TypeDescription type, String function,
480         ThreadId tid, Object[] arguments)
481         throws IOException
482     {
483         IMethodDescription desc = type.getMethodDescription(function);
484         synchronized (output) {
485             if (desc.getIndex() == MethodDescription.ID_RELEASE
486                 && releaseQueue.size() < MAX_RELEASE_QUEUE_SIZE)
487             {
488                 releaseQueue.add(
489                     new QueuedRelease(internal, oid, type, desc, tid));
490                 return false;
491             } else {
492                 writeQueuedReleases();
493                 return writeRequest(
494                     internal, oid, type, desc, tid, arguments, true);
495             }
496         }
497     }
498 
499     private boolean writeRequest(
500         boolean internal, String oid, TypeDescription type,
501         IMethodDescription desc, ThreadId tid, Object[] arguments,
502         boolean flush)
503         throws IOException
504     {
505         int funId = desc.getIndex();
506         if (funId < 0 || funId > MAX_FUNCTIONID16) {
507             throw new IllegalArgumentException(
508                 "function ID " + funId + " out of range");
509         }
510         boolean forceSync = forceSynchronous
511             && funId != MethodDescription.ID_RELEASE;
512         boolean moreFlags = forceSync && desc.isOneway();
513         boolean longHeader = moreFlags;
514         int header = 0;
515         if (!type.equals(outL1Type)) {
516             longHeader = true;
517             header |= HEADER_NEWTYPE;
518             outL1Type = type;
519         } else {
520             type = null;
521         }
522         if (!oid.equals(outL1Oid)) {
523             longHeader = true;
524             header |= HEADER_NEWOID;
525             outL1Oid = oid;
526         } else {
527             oid = null;
528         }
529         if (!tid.equals(outL1Tid)) {
530             longHeader = true;
531             header |= HEADER_NEWTID;
532             outL1Tid = tid;
533         } else {
534             tid = null;
535         }
536         if (funId > MAX_FUNCTIONID14) {
537             longHeader = true;
538         }
539         if (longHeader) {
540             header |= HEADER_LONGHEADER | HEADER_REQUEST;
541             if (funId > MAX_FUNCTIONID8) {
542                 header |= HEADER_FUNCTIONID16;
543             }
544             if (moreFlags) {
545                 header |= HEADER_MOREFLAGS;
546             }
547             marshal.write8Bit(header);
548             if (moreFlags) {
549                 marshal.write8Bit(HEADER_MUSTREPLY | HEADER_SYNCHRONOUS);
550             }
551             if (funId > MAX_FUNCTIONID8) {
552                 marshal.write16Bit(funId);
553             } else {
554                 marshal.write8Bit(funId);
555             }
556             if (type != null) {
557                 marshal.writeType(type);
558             }
559             if (oid != null) {
560                 marshal.writeObjectId(oid);
561             }
562             if (tid != null) {
563                 marshal.writeThreadId(tid);
564             }
565         } else {
566             if (funId > HEADER_FUNCTIONID) {
567                 marshal.write8Bit(HEADER_FUNCTIONID14 | (funId >> 8));
568             }
569             marshal.write8Bit(funId);
570         }
571         if (currentContext && !internal
572             && funId != MethodDescription.ID_RELEASE)
573         {
574             marshal.writeInterface(
575                 UnoRuntime.getCurrentContext(),
576                 new Type(XCurrentContext.class));
577         }
578         ITypeDescription[] inSig = desc.getInSignature();
579         ITypeDescription[] outSig = desc.getOutSignature();
580         for (int i = 0; i < inSig.length; ++i) {
581             if (inSig[i] != null) {
582                 if (outSig[i] != null) {
583                     marshal.writeValue(
584                         (TypeDescription) outSig[i].getComponentType(),
585                         ((Object[]) arguments[i])[0]);
586                 } else {
587                     marshal.writeValue(
588                         (TypeDescription) inSig[i], arguments[i]);
589                 }
590             }
591         }
592         boolean sync = forceSync || !desc.isOneway();
593         if (sync) {
594             pendingOut.push(
595                 outL1Tid, new PendingRequests.Item(internal, desc, arguments));
596         }
597         writeBlock(flush);
598         return sync;
599     }
600 
601     private void writeBlock(boolean flush) throws IOException {
602         byte[] data = marshal.reset();
603         output.writeInt(data.length);
604         output.writeInt(1);
605         output.write(data);
606         if (flush) {
607             output.flush();
608         }
609     }
610 
611     private void writeQueuedReleases() throws IOException {
612         for (int i = releaseQueue.size(); i > 0;) {
613             --i;
614             QueuedRelease r = (QueuedRelease) releaseQueue.get(i);
615             writeRequest(
616                 r.internal, r.objectId, r.type, r.method, r.threadId, null,
617                 false);
618             releaseQueue.remove(i);
619         }
620     }
621 
622     private static boolean parseAttributes(String attributes) {
623         boolean forceSynchronous = true;
624         if (attributes != null) {
625             StringTokenizer t = new StringTokenizer(attributes, ",");
626             while (t.hasMoreTokens()) {
627                 String a = t.nextToken();
628                 String v = null;
629                 int i = a.indexOf('=');
630                 if (i >= 0) {
631                     v = a.substring(i + 1);
632                     a = a.substring(0, i);
633                 }
634                 if (a.equalsIgnoreCase("ForceSynchronous")) {
635                     forceSynchronous = parseBooleanAttributeValue(a, v);
636                 } else if (a.equalsIgnoreCase("negotiate")) {
637                     // Ignored:
638                     parseBooleanAttributeValue(a, v);
639                 } else {
640                     throw new IllegalArgumentException(
641                         "unknown protocol attribute " + a);
642                 }
643             }
644         }
645         return forceSynchronous;
646     }
647 
648     private static boolean parseBooleanAttributeValue(
649         String attribute, String value)
650     {
651         if (value == null) {
652             throw new IllegalArgumentException(
653                 "missing value for protocol attribute " + attribute);
654         }
655         if (value.equals("0")) {
656             return false;
657         } else if (value.equals("1")) {
658             return true;
659         } else {
660             throw new IllegalArgumentException(
661                 "bad value " + value + " for protocol attribute " + attribute);
662         }
663     }
664 
665     private static final class QueuedRelease {
666         public QueuedRelease(
667             boolean internal, String objectId, TypeDescription type,
668             IMethodDescription method, ThreadId threadId)
669         {
670             this.internal = internal;
671             this.objectId = objectId;
672             this.type = type;
673             this.method = method;
674             this.threadId = threadId;
675         }
676 
677         public final boolean internal;
678         public final String objectId;
679         public final TypeDescription type;
680         public final IMethodDescription method;
681         public final ThreadId threadId;
682     }
683 
684     private static final String PROPERTIES_OID = "UrpProtocolProperties";
685     private static final int PROPERTIES_FID_REQUEST_CHANGE = 4;
686     private static final String PROPERTIES_FUN_REQUEST_CHANGE = "requestChange";
687     private static final int PROPERTIES_FID_COMMIT_CHANGE = 5;
688     private static final String PROPERTIES_FUN_COMMIT_CHANGE = "commitChange";
689     private static final String PROPERTY_CURRENT_CONTEXT = "CurrentContext";
690 
691     private static final short CACHE_SIZE = 256;
692 
693     private static final int HEADER_LONGHEADER = 0x80;
694     private static final int HEADER_REQUEST = 0x40;
695     private static final int HEADER_NEWTYPE = 0x20;
696     private static final int HEADER_NEWOID = 0x10;
697     private static final int HEADER_NEWTID = 0x08;
698     private static final int HEADER_FUNCTIONID16 = 0x04;
699     private static final int HEADER_MOREFLAGS = 0x01;
700     private static final int HEADER_MUSTREPLY = 0x80;
701     private static final int HEADER_SYNCHRONOUS = 0x40;
702     private static final int HEADER_FUNCTIONID14 = 0x40;
703     private static final int HEADER_FUNCTIONID = 0x3F;
704     private static final int HEADER_EXCEPTION = 0x20;
705 
706     private static final int MAX_FUNCTIONID16 = 0xFFFF;
707     private static final int MAX_FUNCTIONID14 = 0x3FFF;
708     private static final int MAX_FUNCTIONID8 = 0xFF;
709 
710     private static final int STATE_INITIAL0 = 0;
711     private static final int STATE_INITIAL = 1;
712     private static final int STATE_REQUESTED = 2;
713     private static final int STATE_COMMITTED = 3;
714     private static final int STATE_WAIT = 4;
715     private static final int STATE_TERMINATED = 5;
716 
717     private static final int MAX_RELEASE_QUEUE_SIZE = 100;
718 
719     private final DataInput input;
720     private final DataOutputStream output;
721 
722     private final Marshal marshal;
723     private final Unmarshal unmarshal;
724 
725     private final boolean forceSynchronous;
726 
727     private final PendingRequests pendingIn = new PendingRequests();
728     private final PendingRequests pendingOut = new PendingRequests();
729 
730     private final Object monitor = new Object();
731     private int state = STATE_INITIAL0;
732     private boolean initialized = false;
733     private ThreadId propertiesTid = null;
734     private int random;
735     private boolean currentContext = false;
736 
737     private ThreadId inL1Tid = null;
738     private String inL1Oid = null;
739     private TypeDescription inL1Type = null;
740 
741     private ThreadId outL1Tid = null;
742     private String outL1Oid = null;
743     private ITypeDescription outL1Type = null;
744 
745     private final ArrayList releaseQueue = new ArrayList(); // of QueuedRelease
746 }
747