xref: /AOO41X/main/jurt/com/sun/star/lib/uno/protocols/urp/Marshal.java (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 package com.sun.star.lib.uno.protocols.urp;
28 
29 import com.sun.star.lib.uno.environments.remote.ThreadId;
30 import com.sun.star.lib.uno.typedesc.TypeDescription;
31 import com.sun.star.uno.Any;
32 import com.sun.star.uno.Enum;
33 import com.sun.star.uno.IBridge;
34 import com.sun.star.uno.IFieldDescription;
35 import com.sun.star.uno.Type;
36 import com.sun.star.uno.TypeClass;
37 import com.sun.star.uno.XInterface;
38 import java.io.ByteArrayOutputStream;
39 import java.io.DataOutput;
40 import java.io.DataOutputStream;
41 import java.io.IOException;
42 import java.io.UnsupportedEncodingException;
43 import java.lang.reflect.Array;
44 import java.lang.reflect.InvocationTargetException;
45 
46 final class Marshal {
47     public Marshal(IBridge bridge, short cacheSize) {
48         this.bridge = bridge;
49         objectIdCache = new Cache(cacheSize);
50         threadIdCache = new Cache(cacheSize);
51         typeCache = new Cache(cacheSize);
52     }
53 
54     public void write8Bit(int value) {
55         try {
56             output.writeByte(value);
57         } catch (IOException e) {
58             throw new RuntimeException(e.toString());
59         }
60     }
61 
62     public void write16Bit(int value) {
63         try {
64             output.writeShort(value);
65         } catch (IOException e) {
66             throw new RuntimeException(e.toString());
67         }
68     }
69 
70     public void writeObjectId(String objectId) {
71         if (objectId == null) {
72             writeStringValue(null);
73             write16Bit(0xFFFF);
74         } else {
75             boolean[] found = new boolean[1];
76             int index = objectIdCache.add(found, objectId);
77             writeStringValue(found[0] ? null : objectId);
78             write16Bit(index);
79         }
80     }
81 
82     public void writeInterface(XInterface object, Type type) {
83         writeObjectId((String) bridge.mapInterfaceTo(object, type));
84     }
85 
86     public void writeThreadId(ThreadId threadId) {
87         byte[] data = threadId.getBytes();
88         boolean[] found = new boolean[1];
89         int index = threadIdCache.add(found, data);
90         if (found[0]) {
91             writeCompressedNumber(0);
92         } else {
93             writeCompressedNumber(data.length);
94             writeBytes(data);
95         }
96         write16Bit(index);
97     }
98 
99     public void writeType(TypeDescription type) {
100         TypeClass typeClass = type.getTypeClass();
101         if (TypeDescription.isTypeClassSimple(typeClass)) {
102             write8Bit(typeClass.getValue());
103         } else {
104             boolean[] found = new boolean[1];
105             int index = typeCache.add(found, type.getTypeName());
106             write8Bit(typeClass.getValue() | (found[0] ? 0 : 0x80));
107             write16Bit(index);
108             if (!found[0]) {
109                 writeStringValue(type.getTypeName());
110             }
111         }
112     }
113 
114     public void writeValue(TypeDescription type, Object value) {
115         switch(type.getTypeClass().getValue()) {
116         case TypeClass.VOID_value:
117             break;
118 
119         case TypeClass.BOOLEAN_value:
120             writeBooleanValue((Boolean) value);
121             break;
122 
123         case TypeClass.BYTE_value:
124             writeByteValue((Byte) value);
125             break;
126 
127         case TypeClass.SHORT_value:
128         case TypeClass.UNSIGNED_SHORT_value:
129             writeShortValue((Short) value);
130             break;
131 
132         case TypeClass.LONG_value:
133         case TypeClass.UNSIGNED_LONG_value:
134             writeLongValue((Integer) value);
135             break;
136 
137         case TypeClass.HYPER_value:
138         case TypeClass.UNSIGNED_HYPER_value:
139             writeHyperValue((Long) value);
140             break;
141 
142         case TypeClass.FLOAT_value:
143             writeFloatValue((Float) value);
144             break;
145 
146         case TypeClass.DOUBLE_value:
147             writeDoubleValue((Double) value);
148             break;
149 
150         case TypeClass.CHAR_value:
151             writeCharValue((Character) value);
152             break;
153 
154         case TypeClass.STRING_value:
155             writeStringValue((String) value);
156             break;
157 
158         case TypeClass.TYPE_value:
159             writeTypeValue((Type) value);
160             break;
161 
162         case TypeClass.ANY_value:
163             writeAnyValue(value);
164             break;
165 
166         case TypeClass.SEQUENCE_value:
167             writeSequenceValue(type, value);
168             break;
169 
170         case TypeClass.ENUM_value:
171             writeEnumValue(type, (Enum) value);
172             break;
173 
174         case TypeClass.STRUCT_value:
175             writeStructValue(type, value);
176             break;
177 
178         case TypeClass.EXCEPTION_value:
179             writeExceptionValue(type, (Exception) value);
180             break;
181 
182         case TypeClass.INTERFACE_value:
183             writeInterfaceValue(type, (XInterface) value);
184             break;
185 
186         default:
187             throw new IllegalArgumentException("Bad type descriptor " + type);
188         }
189     }
190 
191     public byte[] reset() {
192         byte[] data = buffer.toByteArray();
193         buffer.reset();
194         return data;
195     }
196 
197     private void writeBooleanValue(Boolean value) {
198         try {
199             output.writeBoolean(value != null && value.booleanValue());
200         } catch (IOException e) {
201             throw new RuntimeException(e.toString());
202         }
203     }
204 
205     private void writeByteValue(Byte value) {
206         write8Bit(value == null ? 0 : value.byteValue());
207     }
208 
209     private void writeShortValue(Short value) {
210         write16Bit(value == null ? 0 : value.shortValue());
211     }
212 
213     private void writeLongValue(Integer value) {
214         write32Bit(value == null ? 0 : value.intValue());
215     }
216 
217     private void writeHyperValue(Long value) {
218         try {
219             output.writeLong(value == null ? 0 : value.longValue());
220         } catch (IOException e) {
221             throw new RuntimeException(e.toString());
222         }
223     }
224 
225     private void writeFloatValue(Float value) {
226         try {
227             output.writeFloat(value == null ? 0 : value.floatValue());
228         } catch (IOException e) {
229             throw new RuntimeException(e.toString());
230         }
231     }
232 
233     private void writeDoubleValue(Double value) {
234         try {
235             output.writeDouble(value == null ? 0 : value.doubleValue());
236         } catch (IOException e) {
237             throw new RuntimeException(e.toString());
238         }
239     }
240 
241     private void writeCharValue(Character value) {
242         try {
243             output.writeChar(value == null ? 0 : value.charValue());
244         } catch (IOException e) {
245             throw new RuntimeException(e.toString());
246         }
247     }
248 
249     private void writeStringValue(String value) {
250         if (value == null) {
251             writeCompressedNumber(0);
252         } else {
253             byte[] data;
254             try {
255                 data = value.getBytes("UTF8");
256             } catch (UnsupportedEncodingException e) {
257                 throw new RuntimeException(e.toString());
258             }
259             writeCompressedNumber(data.length);
260             writeBytes(data);
261         }
262     }
263 
264     private void writeTypeValue(Type value) {
265         try {
266             writeType(
267                 TypeDescription.getTypeDescription(
268                     value == null ? Type.VOID : value));
269         } catch (ClassNotFoundException e) {
270             throw new RuntimeException(e.toString());
271         }
272     }
273 
274     private void writeAnyValue(Object value) {
275         TypeDescription type;
276         if (value == null || value instanceof XInterface) {
277             type = TypeDescription.getTypeDescription(XInterface.class);
278         } else if (value instanceof Any) {
279             Any any = (Any) value;
280             try {
281                 type = TypeDescription.getTypeDescription(any.getType());
282             } catch (ClassNotFoundException e) {
283                 throw new RuntimeException(e.toString());
284             }
285             value = any.getObject();
286         } else if (value.getClass() == Object.class) {
287             // Avoid StackOverflowError:
288             throw new IllegalArgumentException(
289                 "Object instance does not represent UNO value");
290         } else {
291             type = TypeDescription.getTypeDescription(value.getClass());
292         }
293         writeType(type);
294         writeValue(type, value);
295     }
296 
297     private void writeSequenceValue(TypeDescription type, Object value) {
298         if (value == null) {
299             writeCompressedNumber(0);
300         } else {
301             TypeDescription ctype = (TypeDescription) type.getComponentType();
302             if (ctype.getTypeClass() == TypeClass.BYTE) {
303                 byte[] data = (byte[]) value;
304                 writeCompressedNumber(data.length);
305                 writeBytes(data);
306             } else {
307                 int len = Array.getLength(value);
308                 writeCompressedNumber(len);
309                 for (int i = 0; i < len; ++i) {
310                     writeValue(ctype, Array.get(value, i));
311                 }
312             }
313         }
314     }
315 
316     private void writeEnumValue(TypeDescription type, Enum value) {
317         int n;
318         if (value == null) {
319             try {
320                 n = ((Enum)
321                      (type.getZClass().getMethod("getDefault", null).
322                       invoke(null, null))).
323                     getValue();
324             } catch (IllegalAccessException e) {
325                 throw new RuntimeException(e.toString());
326             } catch (InvocationTargetException e) {
327                 throw new RuntimeException(e.toString());
328             } catch (NoSuchMethodException e) {
329                 throw new RuntimeException(e.toString());
330             }
331         } else {
332             n = value.getValue();
333         }
334         write32Bit(n);
335     }
336 
337     private void writeStructValue(TypeDescription type, Object value) {
338         IFieldDescription[] fields = type.getFieldDescriptions();
339         for (int i = 0; i < fields.length; ++i) {
340             try {
341                 writeValue(
342                     (TypeDescription) fields[i].getTypeDescription(),
343                     value == null ? null : fields[i].getField().get(value));
344             } catch (IllegalAccessException e) {
345                 throw new RuntimeException(e.toString());
346             }
347         }
348     }
349 
350     private void writeExceptionValue(TypeDescription type, Exception value) {
351         writeStringValue(value == null ? null : value.getMessage());
352         writeStructValue(type, value);
353     }
354 
355     private void writeInterfaceValue(TypeDescription type, XInterface value) {
356         writeInterface(value, new Type(type));
357     }
358 
359     private void write32Bit(int value) {
360         try {
361             output.writeInt(value);
362         } catch (IOException e) {
363             throw new RuntimeException(e.toString());
364         }
365     }
366 
367     private void writeCompressedNumber(int number) {
368         if (number >= 0 && number < 0xFF) {
369             write8Bit(number);
370         } else {
371             write8Bit(0xFF);
372             write32Bit(number);
373         }
374     }
375 
376     private void writeBytes(byte[] data) {
377         try {
378             output.write(data);
379         } catch (IOException e) {
380             throw new RuntimeException(e.toString());
381         }
382     }
383 
384     private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
385     private final DataOutput output = new DataOutputStream(buffer);
386     private final IBridge bridge;
387     private final Cache objectIdCache;
388     private final Cache threadIdCache;
389     private final Cache typeCache;
390 }
391