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