diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ridljar/com/sun/star/lib/uno/protocols/urp | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
6 files changed, 1818 insertions, 0 deletions
diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java b/ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java new file mode 100644 index 000000000..26c2d449d --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/protocols/urp/Cache.java @@ -0,0 +1,114 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package com.sun.star.lib.uno.protocols.urp; + +import java.util.HashMap; + +/** + * An LRU cache for arbitrary objects. + * + * <p>This class is not synchronized, as any necessary synchronization will already + * take place in the client.</p> + */ +final class Cache { + /** + * Create a cache. + * + * @param size the maximum cache size, must be between 0, inclusive, and + * NOT_CACHED, exclusive. + */ + public Cache(int size) { + maxSize = size; + } + + public int add(boolean[] found, Object content) { + Entry e = map.get(content); + found[0] = e != null; + if (e == null) { + if (map.size() < maxSize) { + // There is still room for a new entry at the front: + e = new Entry(content, map.size(), null, first); + if (first == null) { + last = e; + } else { + first.prev = e; + } + first = e; + } else if (last != null) { + // Take last entry out and recycle as new front: + map.remove(last.content); + e = last; + e.content = content; + if (first != last) { + // Reached only if maxSize > 1: + last = last.prev; + last.next = null; + e.prev = null; + e.next = first; + first.prev = e; + first = e; + } + } else { + // Reached iff maxSize == 0: + return NOT_CACHED; + } + map.put(content, e); + } else if (e != first) { + // Move to front (reached only if maxSize > 1): + e.prev.next = e.next; + if (e.next == null) { + last = e.prev; + } else { + e.next.prev = e.prev; + } + e.prev = null; + e.next = first; + first.prev = e; + first = e; + } + return e.index; + } + + public static final int NOT_CACHED = 0xFFFF; + + private static final class Entry { + public Entry(Object content, int index, Entry prev, Entry next) { + this.content = content; + this.index = index; + this.prev = prev; + this.next = next; + } + + public Object content; + public int index; + public Entry prev; + public Entry next; + } + + // first/last form a list of 0 to maxSize entries, most recently used first; + // map contains the same entries; each entry has a unique index in the range + // 0 to maxSize - 1 + private final int maxSize; + private final HashMap<Object, Entry> map = new HashMap<Object, Entry>(); // from Object to Entry + private Entry first = null; + private Entry last = null; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java b/ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java new file mode 100644 index 000000000..106a8736c --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/protocols/urp/Marshal.java @@ -0,0 +1,355 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package com.sun.star.lib.uno.protocols.urp; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; + +import com.sun.star.lib.uno.environments.remote.ThreadId; +import com.sun.star.lib.uno.typedesc.FieldDescription; +import com.sun.star.lib.uno.typedesc.TypeDescription; +import com.sun.star.uno.Any; +import com.sun.star.uno.Enum; +import com.sun.star.uno.IBridge; +import com.sun.star.uno.Type; +import com.sun.star.uno.TypeClass; +import com.sun.star.uno.XInterface; + +final class Marshal { + public Marshal(IBridge bridge, short cacheSize) { + this.bridge = bridge; + objectIdCache = new Cache(cacheSize); + threadIdCache = new Cache(cacheSize); + typeCache = new Cache(cacheSize); + } + + public void write8Bit(int value) { + try { + output.writeByte(value); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void write16Bit(int value) { + try { + output.writeShort(value); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void writeObjectId(String objectId) { + try { + if (objectId == null) { + writeStringValue(null); + write16Bit(0xFFFF); + } else { + boolean[] found = new boolean[1]; + int index = objectIdCache.add(found, objectId); + writeStringValue(found[0] ? null : objectId); + write16Bit(index); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void writeInterface(XInterface object, Type type) { + writeObjectId((String) bridge.mapInterfaceTo(object, type)); + } + + public void writeThreadId(ThreadId threadId) { + try { + byte[] data = threadId.getBytes(); + boolean[] found = new boolean[1]; + int index = threadIdCache.add(found, data); + if (found[0]) { + writeCompressedNumber(0); + } else { + writeCompressedNumber(data.length); + writeBytes(data); + } + write16Bit(index); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void writeType(TypeDescription type) { + try { + TypeClass typeClass = type.getTypeClass(); + if (TypeDescription.isTypeClassSimple(typeClass)) { + write8Bit(typeClass.getValue()); + } else { + boolean[] found = new boolean[1]; + int index = typeCache.add(found, type.getTypeName()); + write8Bit(typeClass.getValue() | (found[0] ? 0 : 0x80)); + write16Bit(index); + if (!found[0]) { + writeStringValue(type.getTypeName()); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void writeValue(TypeDescription type, Object value) { + try { + switch(type.getTypeClass().getValue()) { + case TypeClass.VOID_value: + break; + + case TypeClass.BOOLEAN_value: + writeBooleanValue((Boolean) value); + break; + + case TypeClass.BYTE_value: + writeByteValue((Byte) value); + break; + + case TypeClass.SHORT_value: + case TypeClass.UNSIGNED_SHORT_value: + writeShortValue((Short) value); + break; + + case TypeClass.LONG_value: + case TypeClass.UNSIGNED_LONG_value: + writeLongValue((Integer) value); + break; + + case TypeClass.HYPER_value: + case TypeClass.UNSIGNED_HYPER_value: + writeHyperValue((Long) value); + break; + + case TypeClass.FLOAT_value: + writeFloatValue((Float) value); + break; + + case TypeClass.DOUBLE_value: + writeDoubleValue((Double) value); + break; + + case TypeClass.CHAR_value: + writeCharValue((Character) value); + break; + + case TypeClass.STRING_value: + writeStringValue((String) value); + break; + + case TypeClass.TYPE_value: + writeTypeValue((Type) value); + break; + + case TypeClass.ANY_value: + writeAnyValue(value); + break; + + case TypeClass.SEQUENCE_value: + writeSequenceValue(type, value); + break; + + case TypeClass.ENUM_value: + writeEnumValue(type, (Enum) value); + break; + + case TypeClass.STRUCT_value: + writeStructValue(type, value); + break; + + case TypeClass.EXCEPTION_value: + writeExceptionValue(type, (Exception) value); + break; + + case TypeClass.INTERFACE_value: + writeInterfaceValue(type, (XInterface) value); + break; + + default: + throw new IllegalArgumentException("Bad type descriptor " + type); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public byte[] reset() { + byte[] data = buffer.toByteArray(); + buffer.reset(); + return data; + } + + private void writeBooleanValue(Boolean value) throws IOException { + output.writeBoolean(value != null && value.booleanValue()); + } + + private void writeByteValue(Byte value) { + write8Bit(value == null ? 0 : value.byteValue()); + } + + private void writeShortValue(Short value) { + write16Bit(value == null ? 0 : value.shortValue()); + } + + private void writeLongValue(Integer value) throws IOException { + write32Bit(value == null ? 0 : value.intValue()); + } + + private void writeHyperValue(Long value) throws IOException { + output.writeLong(value == null ? 0 : value.longValue()); + } + + private void writeFloatValue(Float value) throws IOException { + output.writeFloat(value == null ? 0 : value.floatValue()); + } + + private void writeDoubleValue(Double value) throws IOException { + output.writeDouble(value == null ? 0 : value.doubleValue()); + } + + private void writeCharValue(Character value) throws IOException { + output.writeChar(value == null ? 0 : value.charValue()); + } + + private void writeStringValue(String value) throws IOException { + if (value == null) { + writeCompressedNumber(0); + } else { + byte[] data = value.getBytes("UTF8"); + writeCompressedNumber(data.length); + writeBytes(data); + } + } + + private void writeTypeValue(Type value) throws ClassNotFoundException { + writeType( + TypeDescription.getTypeDescription( + value == null ? Type.VOID : value)); + } + + private void writeAnyValue(Object value) throws ClassNotFoundException { + TypeDescription type; + if (value == null || value instanceof XInterface) { + type = TypeDescription.getTypeDescription(XInterface.class); + } else if (value instanceof Any) { + Any any = (Any) value; + type = TypeDescription.getTypeDescription(any.getType()); + value = any.getObject(); + } else if (value.getClass() == Object.class) { + // Avoid StackOverflowError: + throw new IllegalArgumentException( + "Object instance does not represent UNO value"); + } else { + type = TypeDescription.getTypeDescription(value.getClass()); + } + writeType(type); + writeValue(type, value); + } + + private void writeSequenceValue(TypeDescription type, Object value) throws IOException { + if (value == null) { + writeCompressedNumber(0); + } else { + TypeDescription ctype = type.getComponentType(); + if (ctype.getTypeClass() == TypeClass.BYTE) { + byte[] data = (byte[]) value; + writeCompressedNumber(data.length); + writeBytes(data); + } else { + int len = Array.getLength(value); + writeCompressedNumber(len); + for (int i = 0; i < len; ++i) { + writeValue(ctype, Array.get(value, i)); + } + } + } + } + + private void writeEnumValue(TypeDescription type, Enum value) throws IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException { + int n; + if (value == null) { + n = ((Enum) + (type.getZClass().getMethod("getDefault", (Class[]) null). + invoke(null, (Object[]) null))). + getValue(); + } else { + n = value.getValue(); + } + write32Bit(n); + } + + private void writeStructValue(TypeDescription type, Object value) throws IllegalAccessException { + FieldDescription[] fields = type.getFieldDescriptions(); + for (int i = 0; i < fields.length; ++i) { + writeValue( + fields[i].getTypeDescription(), + value == null ? null : fields[i].getField().get(value)); + } + } + + private void writeExceptionValue(TypeDescription type, Exception value) throws IllegalAccessException, IOException { + writeStringValue(value == null ? null : value.getMessage()); + writeStructValue(type, value); + } + + private void writeInterfaceValue(TypeDescription type, XInterface value) { + writeInterface(value, new Type(type)); + } + + private void write32Bit(int value) throws IOException { + output.writeInt(value); + } + + private void writeCompressedNumber(int number) throws IOException { + if (number >= 0 && number < 0xFF) { + write8Bit(number); + } else { + write8Bit(0xFF); + write32Bit(number); + } + } + + private void writeBytes(byte[] data) throws IOException { + output.write(data); + } + + private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + private final DataOutput output = new DataOutputStream(buffer); + private final IBridge bridge; + private final Cache objectIdCache; + private final Cache threadIdCache; + private final Cache typeCache; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java b/ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java new file mode 100644 index 000000000..928cdcd63 --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/protocols/urp/PendingRequests.java @@ -0,0 +1,65 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package com.sun.star.lib.uno.protocols.urp; + +import java.util.HashMap; +import java.util.Stack; + +import com.sun.star.lib.uno.environments.remote.ThreadId; +import com.sun.star.lib.uno.typedesc.MethodDescription; + +final class PendingRequests { + + public synchronized void push(ThreadId tid, Item item) { + Stack<Item> s = map.get(tid); + if (s == null) { + s = new Stack<Item>(); + map.put(tid, s); + } + s.push(item); + } + + public synchronized Item pop(ThreadId tid) { + Stack<Item> s = map.get(tid); + Item i = s.pop(); + if (s.empty()) { + map.remove(tid); + } + return i; + } + + public static final class Item { + public Item( + boolean internal, MethodDescription function, Object[] arguments) + { + this.internal = internal; + this.function = function; + this.arguments = arguments; + } + + public final boolean internal; + public final MethodDescription function; + public final Object[] arguments; + } + + private final HashMap<ThreadId, Stack<Item>> map = new HashMap<ThreadId, Stack<Item>>(); // from ThreadId to Stack of Item +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java b/ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java new file mode 100644 index 000000000..c16d19291 --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/protocols/urp/Unmarshal.java @@ -0,0 +1,476 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package com.sun.star.lib.uno.protocols.urp; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; + +import com.sun.star.lib.uno.environments.remote.ThreadId; +import com.sun.star.lib.uno.typedesc.TypeDescription; +import com.sun.star.uno.Any; +import com.sun.star.uno.Enum; +import com.sun.star.uno.IBridge; +import com.sun.star.uno.Type; +import com.sun.star.uno.TypeClass; +import com.sun.star.uno.XInterface; +import com.sun.star.lib.uno.typedesc.FieldDescription; + +final class Unmarshal { + public Unmarshal(IBridge bridge, int cacheSize) { + this.bridge = bridge; + objectIdCache = new String[cacheSize]; + threadIdCache = new ThreadId[cacheSize]; + typeCache = new TypeDescription[cacheSize]; + reset(new byte[0]); + } + + public int read8Bit() { + try { + return input.readUnsignedByte(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public int read16Bit() { + try { + return input.readUnsignedShort(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public String readObjectId() { + try { + String id = readStringValue(); + int index = read16Bit(); + if (index == 0xFFFF) { + if (id.length() == 0) { + id = null; + } + } else { + if (id.length() == 0) { + id = objectIdCache[index]; + } else { + objectIdCache[index] = id; + } + } + return id; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Object readInterface(Type type) { + String id = readObjectId(); + return id == null ? null : bridge.mapInterfaceFrom(id, type); + } + + public ThreadId readThreadId() { + try { + int len = readCompressedNumber(); + byte[] data ; + ThreadId id = null; + if (len != 0) { + data = new byte[len]; + readBytes(data); + id = new ThreadId(data); + } + int index = read16Bit(); + if (index != 0xFFFF) { + if (len == 0) { + id = threadIdCache[index]; + } else { + threadIdCache[index] = id; + } + } + return id; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public TypeDescription readType() { + int b = read8Bit(); + TypeClass typeClass = TypeClass.fromInt(b & 0x7F); + if (typeClass == null) { + throw new RuntimeException( + "Reading TYPE with bad type class " + (b & 0x7F)); + } + if (TypeDescription.isTypeClassSimple(typeClass)) { + if ((b & 0x80) != 0) { + throw new RuntimeException( + "Reading TYPE with bad type class/cache flag " + b); + } + return TypeDescription.getTypeDescription(typeClass); + } else { + int index = read16Bit(); + TypeDescription type; + if ((b & 0x80) == 0) { + if (index >= typeCache.length) { + throw new RuntimeException( + "Reading TYPE with bad cache index " + index); + } + type = typeCache[index]; + if (type == null) { + throw new RuntimeException( + "Reading TYPE with empty cache index " + index); + } + } else { + try { + type = TypeDescription.getTypeDescription( + readStringValue()); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + if (index != 0xFFFF) { + if (index >= typeCache.length) { + throw new RuntimeException( + "Reading TYPE with bad cache index " + index); + } + typeCache[index] = type; + } + } + return type; + } + } + + public Object readValue(TypeDescription type) { + try { + switch (type.getTypeClass().getValue()) { + case TypeClass.VOID_value: + return null; + + case TypeClass.BOOLEAN_value: + return readBooleanValue(); + + case TypeClass.BYTE_value: + return readByteValue(); + + case TypeClass.SHORT_value: + case TypeClass.UNSIGNED_SHORT_value: + return readShortValue(); + + case TypeClass.LONG_value: + case TypeClass.UNSIGNED_LONG_value: + return readLongValue(); + + case TypeClass.HYPER_value: + case TypeClass.UNSIGNED_HYPER_value: + return readHyperValue(); + + case TypeClass.FLOAT_value: + return readFloatValue(); + + case TypeClass.DOUBLE_value: + return readDoubleValue(); + + case TypeClass.CHAR_value: + return readCharValue(); + + case TypeClass.STRING_value: + return readStringValue(); + + case TypeClass.TYPE_value: + return readTypeValue(); + + case TypeClass.ANY_value: + return readAnyValue(); + + case TypeClass.SEQUENCE_value: + return readSequenceValue(type); + + case TypeClass.ENUM_value: + return readEnumValue(type); + + case TypeClass.STRUCT_value: + return readStructValue(type); + + case TypeClass.EXCEPTION_value: + return readExceptionValue(type); + + case TypeClass.INTERFACE_value: + return readInterfaceValue(type); + + default: + throw new IllegalArgumentException("Bad type descriptor " + type); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public boolean hasMore() { + try { + return input.available() > 0; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void reset(byte[] data) { + input = new DataInputStream(new ByteArrayInputStream(data)); + } + + private Boolean readBooleanValue() throws IOException { + return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE; + } + + private Byte readByteValue() throws IOException { + return Byte.valueOf(input.readByte()); + } + + private Short readShortValue() throws IOException { + return Short.valueOf(input.readShort()); + } + + private Integer readLongValue() throws IOException { + return Integer.valueOf(input.readInt()); + } + + private Long readHyperValue() throws IOException { + return Long.valueOf(input.readLong()); + } + + private Float readFloatValue() throws IOException { + return new Float(input.readFloat()); + } + + private Double readDoubleValue() throws IOException { + return new Double(input.readDouble()); + } + + private Character readCharValue() throws IOException { + return new Character(input.readChar()); + } + + private String readStringValue() throws IOException { + int len = readCompressedNumber(); + byte[] data = new byte[len]; + readBytes(data); + try { + return new String(data, "UTF8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + private Type readTypeValue() { + return new Type(readType()); + } + + private Object readAnyValue() throws IOException { + TypeDescription type = readType(); + switch (type.getTypeClass().getValue()) { + case TypeClass.VOID_value: + return Any.VOID; + + case TypeClass.BOOLEAN_value: + return readBooleanValue(); + + case TypeClass.BYTE_value: + return readByteValue(); + + case TypeClass.SHORT_value: + return readShortValue(); + + case TypeClass.UNSIGNED_SHORT_value: + return new Any(Type.UNSIGNED_SHORT, readShortValue()); + + case TypeClass.LONG_value: + return readLongValue(); + + case TypeClass.UNSIGNED_LONG_value: + return new Any(Type.UNSIGNED_LONG, readLongValue()); + + case TypeClass.HYPER_value: + return readHyperValue(); + + case TypeClass.UNSIGNED_HYPER_value: + return new Any(Type.UNSIGNED_HYPER, readHyperValue()); + + case TypeClass.FLOAT_value: + return readFloatValue(); + + case TypeClass.DOUBLE_value: + return readDoubleValue(); + + case TypeClass.CHAR_value: + return readCharValue(); + + case TypeClass.STRING_value: + return readStringValue(); + + case TypeClass.TYPE_value: + return readTypeValue(); + + case TypeClass.SEQUENCE_value: + { + Object value = readSequenceValue(type); + TypeDescription ctype = type.getComponentType(); + while (ctype.getTypeClass() == TypeClass.SEQUENCE) { + ctype = ctype.getComponentType(); + } + switch (ctype.getTypeClass().getValue()) { + case TypeClass.UNSIGNED_SHORT_value: + case TypeClass.UNSIGNED_LONG_value: + case TypeClass.UNSIGNED_HYPER_value: + return new Any(new Type(type), value); + + case TypeClass.STRUCT_value: + if (ctype.hasTypeArguments()) { + return new Any(new Type(type), value); + } + default: + return value; + } + } + + case TypeClass.ENUM_value: + return readEnumValue(type); + + case TypeClass.STRUCT_value: + { + Object value = readStructValue(type); + return type.hasTypeArguments() + ? new Any(new Type(type), value) : value; + } + + case TypeClass.EXCEPTION_value: + return readExceptionValue(type); + + case TypeClass.INTERFACE_value: + { + Object value = readInterfaceValue(type); + return type.getZClass() == XInterface.class + ? value : new Any(new Type(type), value); + } + + default: + throw new RuntimeException( + "Reading ANY with bad type " + type.getTypeClass()); + } + } + + private Object readSequenceValue(TypeDescription type) throws IOException { + int len = readCompressedNumber(); + TypeDescription ctype = type.getComponentType(); + if (ctype.getTypeClass() == TypeClass.BYTE) { + byte[] data = new byte[len]; + readBytes(data); + return data; + } else { + Object value = Array.newInstance( + ctype.getTypeClass() == TypeClass.ANY + ? Object.class : ctype.getZClass(), len); + for (int i = 0; i < len; ++i) { + Array.set(value, i, readValue(ctype)); + } + return value; + } + } + + private Enum readEnumValue(TypeDescription type) throws IOException { + try { + return (Enum) + type.getZClass().getMethod( + "fromInt", new Class[] { int.class }). + invoke(null, new Object[] { readLongValue() }); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private Object readStructValue(TypeDescription type) { + Object value; + try { + value = type.getZClass().newInstance(); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } + readFields(type, value); + return value; + } + + private Exception readExceptionValue(TypeDescription type) throws IOException { + Exception value; + try { + value = (Exception) + type.getZClass().getConstructor(new Class[] { String.class }). + newInstance(new Object[] { readStringValue() }); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + readFields(type, value); + return value; + } + + private Object readInterfaceValue(TypeDescription type) { + return readInterface(new Type(type)); + } + + private int readCompressedNumber() throws IOException { + int number = read8Bit(); + return number < 0xFF ? number : input.readInt(); + } + + private void readBytes(byte[] data) throws IOException { + input.readFully(data); + } + + private void readFields(TypeDescription type, Object value) { + FieldDescription[] fields = type.getFieldDescriptions(); + for (int i = 0; i < fields.length; ++i) { + try { + fields[i].getField().set( + value, + readValue( + fields[i].getTypeDescription())); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + + private final IBridge bridge; + private final String[] objectIdCache; + private final ThreadId[] threadIdCache; + private final TypeDescription[] typeCache; + private DataInputStream input; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java b/ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java new file mode 100644 index 000000000..34cdf7073 --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/protocols/urp/UrpMessage.java @@ -0,0 +1,48 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package com.sun.star.lib.uno.protocols.urp; + +import com.sun.star.lib.uno.environments.remote.Message; +import com.sun.star.lib.uno.environments.remote.ThreadId; +import com.sun.star.lib.uno.typedesc.MethodDescription; +import com.sun.star.lib.uno.typedesc.TypeDescription; +import com.sun.star.uno.XCurrentContext; + +final class UrpMessage extends Message { + public UrpMessage( + ThreadId threadId, boolean request, String objectId, + TypeDescription type, MethodDescription method, boolean synchronous, + XCurrentContext currentContext, boolean abnormalTermination, + Object result, Object[] arguments, boolean internal) + { + super( + threadId, request, objectId, type, method, synchronous, + currentContext, abnormalTermination, result, arguments); + this.internal = internal; + } + + public boolean isInternal() { + return internal; + } + + private final boolean internal; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ridljar/com/sun/star/lib/uno/protocols/urp/urp.java b/ridljar/com/sun/star/lib/uno/protocols/urp/urp.java new file mode 100644 index 000000000..0ce9d35be --- /dev/null +++ b/ridljar/com/sun/star/lib/uno/protocols/urp/urp.java @@ -0,0 +1,760 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package com.sun.star.lib.uno.protocols.urp; + +import com.sun.star.bridge.InvalidProtocolChangeException; +import com.sun.star.bridge.ProtocolProperty; +import com.sun.star.bridge.XProtocolProperties; +import com.sun.star.lang.DisposedException; +import com.sun.star.lib.uno.environments.remote.IProtocol; +import com.sun.star.lib.uno.environments.remote.Message; +import com.sun.star.lib.uno.environments.remote.ThreadId; +import com.sun.star.lib.uno.typedesc.MethodDescription; +import com.sun.star.lib.uno.typedesc.TypeDescription; +import com.sun.star.uno.Any; +import com.sun.star.uno.IBridge; +import com.sun.star.uno.Type; +import com.sun.star.uno.TypeClass; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XCurrentContext; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Random; +import java.util.StringTokenizer; + +/** + * This class internally relies on the availability of Java UNO type information + * for the interface type <code>com.sun.star.bridge.XProtocolProperties</code>, + * even though URP itself does not rely on that type. + */ +public final class urp implements IProtocol { + public urp( + IBridge bridge, String attributes, InputStream input, + OutputStream output) + { + this.input = new DataInputStream(input); + this.output = new DataOutputStream(output); + marshal = new Marshal(bridge, CACHE_SIZE); + unmarshal = new Unmarshal(bridge, CACHE_SIZE); + forceSynchronous = parseAttributes(attributes); + } + + /** + * + * @see IProtocol#init + */ + public void init() throws IOException { + synchronized (monitor) { + if (state == STATE_INITIAL0) { + sendRequestChange(); + } + } + } + + /** + * + * @see IProtocol#terminate + */ + public void terminate() { + synchronized (monitor) { + state = STATE_TERMINATED; + initialized = true; + monitor.notifyAll(); + } + } + + /** + * + * @see IProtocol#readMessage + */ + public Message readMessage() throws IOException { + for (;;) { + if (!unmarshal.hasMore()) { + unmarshal.reset(readBlock()); + if (!unmarshal.hasMore()) { + throw new IOException("closeConnection message received"); + } + } + UrpMessage msg; + int header = unmarshal.read8Bit(); + if ((header & HEADER_LONGHEADER) != 0) { + if ((header & HEADER_REQUEST) != 0) { + msg = readLongRequest(header); + } else { + msg = readReply(header); + } + } else { + msg = readShortRequest(header); + } + if (msg.isInternal()) { + handleInternalMessage(msg); + } else { + return msg; + } + } + } + + /** + * + * @see IProtocol#writeRequest + */ + public boolean writeRequest( + String oid, TypeDescription type, String function, ThreadId tid, + Object[] arguments) + throws IOException + { + if (oid.equals(PROPERTIES_OID)) { + throw new IllegalArgumentException("illegal OID " + oid); + } + synchronized (monitor) { + while (!initialized) { + try { + monitor.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + if (state == STATE_TERMINATED) { + throw new DisposedException(); + } + return writeRequest(false, oid, type, function, tid, arguments); + } + } + + /** + * + * @see IProtocol#writeReply + */ + public void writeReply(boolean exception, ThreadId tid, Object result) + throws IOException + { + synchronized (output) { + writeQueuedReleases(); + int header = HEADER_LONGHEADER; + PendingRequests.Item pending = pendingIn.pop(tid); + TypeDescription resultType; + TypeDescription[] argTypes; + Object[] args; + if (exception) { + header |= HEADER_EXCEPTION; + resultType = TypeDescription.getTypeDescription(TypeClass.ANY); + argTypes = null; + args = null; + } else { + resultType = pending.function.getReturnSignature(); + argTypes = pending.function.getOutSignature(); + args = pending.arguments; + } + if (!tid.equals(outL1Tid)) { + header |= HEADER_NEWTID; + outL1Tid = tid; + } else { + tid = null; + } + marshal.write8Bit(header); + if (tid != null) { + marshal.writeThreadId(tid); + } + marshal.writeValue(resultType, result); + if (argTypes != null) { + for (int i = 0; i < argTypes.length; ++i) { + if (argTypes[i] != null) { + marshal.writeValue( + argTypes[i].getComponentType(), + Array.get(args[i], 0)); + } + } + } + writeBlock(true); + } + } + + private void sendRequestChange() throws IOException { + if (propertiesTid == null) { + propertiesTid = ThreadId.createFresh(); + } + random = randomGenerator.nextInt(); + writeRequest( + true, PROPERTIES_OID, + TypeDescription.getTypeDescription(XProtocolProperties.class), + PROPERTIES_FUN_REQUEST_CHANGE, propertiesTid, + new Object[] { Integer.valueOf(random) }); + state = STATE_REQUESTED; + } + + private void handleInternalMessage(Message message) throws IOException { + if (message.isRequest()) { + String t = message.getType().getTypeName(); + if (!t.equals("com.sun.star.bridge.XProtocolProperties")) { + throw new IOException( + "read URP protocol properties request with unsupported" + + " type " + t); + } + int fid = message.getMethod().getIndex(); + switch (fid) { + case PROPERTIES_FID_REQUEST_CHANGE: + checkSynchronousPropertyRequest(message); + synchronized (monitor) { + switch (state) { + case STATE_INITIAL0: + case STATE_INITIAL: + writeReply( + false, message.getThreadId(), Integer.valueOf(1)); + state = STATE_WAIT; + break; + case STATE_REQUESTED: + int n + = ((Integer) message.getArguments()[0]).intValue(); + if (random < n) { + writeReply( + false, message.getThreadId(), Integer.valueOf(1)); + state = STATE_WAIT; + } else if (random == n) { + writeReply( + false, message.getThreadId(), Integer.valueOf(-1)); + state = STATE_INITIAL; + sendRequestChange(); + } else { + writeReply( + false, message.getThreadId(), Integer.valueOf(0)); + } + break; + default: + writeReply( + true, message.getThreadId(), + new com.sun.star.uno.RuntimeException( + "read URP protocol properties requestChange" + + " request in illegal state")); + break; + } + } + break; + case PROPERTIES_FID_COMMIT_CHANGE: + checkSynchronousPropertyRequest(message); + synchronized (monitor) { + if (state == STATE_WAIT) { + ProtocolProperty[] p = (ProtocolProperty[]) + message.getArguments()[0]; + boolean ok = true; + boolean cc = false; + int i = 0; + for (; i < p.length; ++i) { + if (p[i].Name.equals(PROPERTY_CURRENT_CONTEXT)) { + cc = true; + } else { + ok = false; + break; + } + } + if (ok) { + writeReply(false, message.getThreadId(), null); + } else { + writeReply( + true, message.getThreadId(), + new InvalidProtocolChangeException( + "", null, p[i], 1)); + } + state = STATE_INITIAL; + if (!initialized) { + if (cc) { + currentContext = true; + initialized = true; + monitor.notifyAll(); + } else { + sendRequestChange(); + } + } + } else { + writeReply( + true, message.getThreadId(), + new com.sun.star.uno.RuntimeException( + "read URP protocol properties commitChange" + + " request in illegal state")); + } + } + break; + default: + throw new IOException( + "read URP protocol properties request with unsupported" + + " function ID " + fid); + } + } else { + synchronized (monitor) { + if (state == STATE_COMMITTED) { + // commitChange reply: + if (!message.isAbnormalTermination()) { + currentContext = true; + } + state = STATE_INITIAL; + initialized = true; + monitor.notifyAll(); + } else { + // requestChange reply: + if (message.isAbnormalTermination()) { + // remote side probably does not support negotiation: + state = STATE_INITIAL; + initialized = true; + monitor.notifyAll(); + } else { + int n = ((Integer) message.getResult()).intValue(); + switch (n) { + case -1: + case 0: + break; + case 1: + writeRequest( + true, PROPERTIES_OID, + TypeDescription.getTypeDescription( + XProtocolProperties.class), + PROPERTIES_FUN_COMMIT_CHANGE, propertiesTid, + new Object[] { + new ProtocolProperty[] { + new ProtocolProperty( + PROPERTY_CURRENT_CONTEXT, + Any.VOID) } }); + state = STATE_COMMITTED; + break; + default: + throw new IOException( + "read URP protocol properties " + + PROPERTIES_FUN_REQUEST_CHANGE + + " reply with illegal return value " + n); + } + } + } + } + } + } + + private void checkSynchronousPropertyRequest(Message message) + throws IOException + { + if (!message.isSynchronous()) { + throw new IOException( + "read URP protocol properties request for synchronous function" + + " marked as not SYNCHRONOUS"); + } + } + + private byte[] readBlock() throws IOException { + int size = input.readInt(); + input.readInt(); // ignore count + byte[] bytes = new byte[size]; + input.readFully(bytes); + return bytes; + } + + private UrpMessage readLongRequest(int header) throws IOException { + boolean sync = false; + if ((header & HEADER_MOREFLAGS) != 0) { + if (unmarshal.read8Bit() != (HEADER_MUSTREPLY | HEADER_SYNCHRONOUS)) + { + throw new IOException( + "read URP request with bad MUSTREPLY/SYNCHRONOUS byte"); + } + sync = true; + } + int funId = (header & HEADER_FUNCTIONID16) != 0 + ? unmarshal.read16Bit() : unmarshal.read8Bit(); + if ((header & HEADER_NEWTYPE) != 0) { + inL1Type = unmarshal.readType(); + if (inL1Type.getTypeClass() != TypeClass.INTERFACE) { + throw new IOException( + "read URP request with non-interface type " + inL1Type); + } + } + if ((header & HEADER_NEWOID) != 0) { + inL1Oid = unmarshal.readObjectId(); + } + if ((header & HEADER_NEWTID) != 0) { + inL1Tid = unmarshal.readThreadId(); + } + return readRequest(funId, sync); + } + + private UrpMessage readShortRequest(int header) throws IOException { + int funId = (header & HEADER_FUNCTIONID14) != 0 + ? ((header & HEADER_FUNCTIONID) << 8) | unmarshal.read8Bit() + : header & HEADER_FUNCTIONID; + return readRequest(funId, false); + } + + private UrpMessage readRequest(int functionId, boolean forcedSynchronous) + throws IOException + { + boolean internal = PROPERTIES_OID.equals(inL1Oid); + // inL1Oid may be null in XInstanceProvider.getInstance("") + XCurrentContext cc = + (currentContext && !internal + && functionId != MethodDescription.ID_RELEASE) + ? (XCurrentContext) unmarshal.readInterface( + new Type(XCurrentContext.class)) + : null; + MethodDescription desc = inL1Type.getMethodDescription(functionId); + if (desc == null) { + throw new IOException( + "read URP request with unsupported function ID " + functionId); + } + TypeDescription[] inSig = desc.getInSignature(); + TypeDescription[] outSig = desc.getOutSignature(); + Object[] args = new Object[inSig.length]; + for (int i = 0; i < args.length; ++i) { + if (inSig[i] != null) { + if (outSig[i] != null) { + Object inout = Array.newInstance( + outSig[i].getComponentType().getZClass(), 1); + Array.set( + inout, 0, + unmarshal.readValue( + outSig[i].getComponentType())); + args[i] = inout; + } else { + args[i] = unmarshal.readValue(inSig[i]); + } + } else { + args[i] = Array.newInstance( + outSig[i].getComponentType().getZClass(), 1); + } + } + boolean sync = forcedSynchronous || !desc.isOneway(); + if (sync) { + pendingIn.push( + inL1Tid, new PendingRequests.Item(internal, desc, args)); + } + return new UrpMessage( + inL1Tid, true, inL1Oid, inL1Type, desc, sync, cc, false, null, args, + internal); + } + + private UrpMessage readReply(int header) { + if ((header & HEADER_NEWTID) != 0) { + inL1Tid = unmarshal.readThreadId(); + } + PendingRequests.Item pending = pendingOut.pop(inL1Tid); + TypeDescription resultType; + TypeDescription[] argTypes; + Object[] args; + boolean exception = (header & HEADER_EXCEPTION) != 0; + if (exception) { + resultType = TypeDescription.getTypeDescription(TypeClass.ANY); + argTypes = null; + args = null; + } else { + resultType = pending.function.getReturnSignature(); + argTypes = pending.function.getOutSignature(); + args = pending.arguments; + } + Object result = resultType == null + ? null : unmarshal.readValue(resultType); + if (argTypes != null) { + for (int i = 0; i < argTypes.length; ++i) { + if (argTypes[i] != null) { + Array.set( + args[i], 0, + unmarshal.readValue( + argTypes[i].getComponentType())); + } + } + } + return new UrpMessage( + inL1Tid, false, null, null, null, false, null, exception, result, + args, pending.internal); + } + + private boolean writeRequest( + boolean internal, String oid, TypeDescription type, String function, + ThreadId tid, Object[] arguments) + throws IOException + { + MethodDescription desc = type.getMethodDescription(function); + synchronized (output) { + if (desc.getIndex() == MethodDescription.ID_RELEASE + && releaseQueue.size() < MAX_RELEASE_QUEUE_SIZE) + { + releaseQueue.add( + new QueuedRelease(internal, oid, type, desc, tid)); + return false; + } else { + writeQueuedReleases(); + return writeRequest( + internal, oid, type, desc, tid, arguments, true); + } + } + } + + private boolean writeRequest( + boolean internal, String oid, TypeDescription type, + MethodDescription desc, ThreadId tid, Object[] arguments, + boolean flush) + throws IOException + { + int funId = desc.getIndex(); + if (funId < 0 || funId > MAX_FUNCTIONID16) { + throw new IllegalArgumentException( + "function ID " + funId + " out of range"); + } + boolean forceSync = forceSynchronous + && funId != MethodDescription.ID_RELEASE; + boolean moreFlags = forceSync && desc.isOneway(); + boolean longHeader = moreFlags; + int header = 0; + if (!type.equals(outL1Type)) { + longHeader = true; + header |= HEADER_NEWTYPE; + outL1Type = type; + } else { + type = null; + } + if (!oid.equals(outL1Oid)) { + longHeader = true; + header |= HEADER_NEWOID; + outL1Oid = oid; + } else { + oid = null; + } + if (!tid.equals(outL1Tid)) { + longHeader = true; + header |= HEADER_NEWTID; + outL1Tid = tid; + } else { + tid = null; + } + if (funId > MAX_FUNCTIONID14) { + longHeader = true; + } + if (longHeader) { + header |= HEADER_LONGHEADER | HEADER_REQUEST; + if (funId > MAX_FUNCTIONID8) { + header |= HEADER_FUNCTIONID16; + } + if (moreFlags) { + header |= HEADER_MOREFLAGS; + } + marshal.write8Bit(header); + if (moreFlags) { + marshal.write8Bit(HEADER_MUSTREPLY | HEADER_SYNCHRONOUS); + } + if (funId > MAX_FUNCTIONID8) { + marshal.write16Bit(funId); + } else { + marshal.write8Bit(funId); + } + if (type != null) { + marshal.writeType(type); + } + if (oid != null) { + marshal.writeObjectId(oid); + } + if (tid != null) { + marshal.writeThreadId(tid); + } + } else { + if (funId > HEADER_FUNCTIONID) { + marshal.write8Bit(HEADER_FUNCTIONID14 | (funId >> 8)); + } + marshal.write8Bit(funId); + } + if (currentContext && !internal + && funId != MethodDescription.ID_RELEASE) + { + marshal.writeInterface( + UnoRuntime.getCurrentContext(), + new Type(XCurrentContext.class)); + } + TypeDescription[] inSig = desc.getInSignature(); + TypeDescription[] outSig = desc.getOutSignature(); + for (int i = 0; i < inSig.length; ++i) { + if (inSig[i] != null) { + if (outSig[i] != null) { + marshal.writeValue( + outSig[i].getComponentType(), + ((Object[]) arguments[i])[0]); + } else { + marshal.writeValue( + inSig[i], arguments[i]); + } + } + } + boolean sync = forceSync || !desc.isOneway(); + if (sync) { + pendingOut.push( + outL1Tid, new PendingRequests.Item(internal, desc, arguments)); + } + writeBlock(flush); + return sync; + } + + private void writeBlock(boolean flush) throws IOException { + byte[] data = marshal.reset(); + output.writeInt(data.length); + output.writeInt(1); + output.write(data); + if (flush) { + output.flush(); + } + } + + private void writeQueuedReleases() throws IOException { + for (int i = releaseQueue.size(); i > 0;) { + --i; + QueuedRelease r = releaseQueue.get(i); + writeRequest( + r.internal, r.objectId, r.type, r.method, r.threadId, null, + false); + releaseQueue.remove(i); + } + } + + private static boolean parseAttributes(String attributes) { + boolean forceSynchronous = true; + if (attributes != null) { + StringTokenizer t = new StringTokenizer(attributes, ","); + while (t.hasMoreTokens()) { + String a = t.nextToken(); + String v = null; + int i = a.indexOf('='); + if (i >= 0) { + v = a.substring(i + 1); + a = a.substring(0, i); + } + if (a.equalsIgnoreCase("ForceSynchronous")) { + forceSynchronous = parseBooleanAttributeValue(a, v); + } else if (a.equalsIgnoreCase("negotiate")) { + // Ignored: + parseBooleanAttributeValue(a, v); + } else { + throw new IllegalArgumentException( + "unknown protocol attribute " + a); + } + } + } + return forceSynchronous; + } + + private static boolean parseBooleanAttributeValue( + String attribute, String value) + { + if (value == null) { + throw new IllegalArgumentException( + "missing value for protocol attribute " + attribute); + } + if (value.equals("0")) { + return false; + } else if (value.equals("1")) { + return true; + } else { + throw new IllegalArgumentException( + "bad value " + value + " for protocol attribute " + attribute); + } + } + + private static final class QueuedRelease { + public QueuedRelease( + boolean internal, String objectId, TypeDescription type, + MethodDescription method, ThreadId threadId) + { + this.internal = internal; + this.objectId = objectId; + this.type = type; + this.method = method; + this.threadId = threadId; + } + + public final boolean internal; + public final String objectId; + public final TypeDescription type; + public final MethodDescription method; + public final ThreadId threadId; + } + + private static final String PROPERTIES_OID = "UrpProtocolProperties"; + private static final int PROPERTIES_FID_REQUEST_CHANGE = 4; + private static final String PROPERTIES_FUN_REQUEST_CHANGE = "requestChange"; + private static final int PROPERTIES_FID_COMMIT_CHANGE = 5; + private static final String PROPERTIES_FUN_COMMIT_CHANGE = "commitChange"; + private static final String PROPERTY_CURRENT_CONTEXT = "CurrentContext"; + + private static final short CACHE_SIZE = 256; + + private static final int HEADER_LONGHEADER = 0x80; + private static final int HEADER_REQUEST = 0x40; + private static final int HEADER_NEWTYPE = 0x20; + private static final int HEADER_NEWOID = 0x10; + private static final int HEADER_NEWTID = 0x08; + private static final int HEADER_FUNCTIONID16 = 0x04; + private static final int HEADER_MOREFLAGS = 0x01; + private static final int HEADER_MUSTREPLY = 0x80; + private static final int HEADER_SYNCHRONOUS = 0x40; + private static final int HEADER_FUNCTIONID14 = 0x40; + private static final int HEADER_FUNCTIONID = 0x3F; + private static final int HEADER_EXCEPTION = 0x20; + + private static final int MAX_FUNCTIONID16 = 0xFFFF; + private static final int MAX_FUNCTIONID14 = 0x3FFF; + private static final int MAX_FUNCTIONID8 = 0xFF; + + private static final int STATE_INITIAL0 = 0; + private static final int STATE_INITIAL = 1; + private static final int STATE_REQUESTED = 2; + private static final int STATE_COMMITTED = 3; + private static final int STATE_WAIT = 4; + private static final int STATE_TERMINATED = 5; + + private static final int MAX_RELEASE_QUEUE_SIZE = 100; + + private static final Random randomGenerator = new Random(); + + private final DataInput input; + private final DataOutputStream output; + + private final Marshal marshal; + private final Unmarshal unmarshal; + + private final boolean forceSynchronous; + + private final PendingRequests pendingIn = new PendingRequests(); + private final PendingRequests pendingOut = new PendingRequests(); + + private final Object monitor = new Object(); + private int state = STATE_INITIAL0; + private boolean initialized = false; + private ThreadId propertiesTid = null; + private int random; + private boolean currentContext = false; + + private ThreadId inL1Tid = null; + private String inL1Oid = null; + private TypeDescription inL1Type = null; + + private ThreadId outL1Tid = null; + private String outL1Oid = null; + private TypeDescription outL1Type = null; + + private final ArrayList<QueuedRelease> releaseQueue = new ArrayList<QueuedRelease>(); // of QueuedRelease +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |