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