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