001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.openwire.v6;
018
019import java.io.DataInput;
020import java.io.DataOutput;
021import java.io.IOException;
022import java.lang.reflect.Constructor;
023
024import org.apache.activemq.command.DataStructure;
025import org.apache.activemq.openwire.BooleanStream;
026import org.apache.activemq.openwire.DataStreamMarshaller;
027import org.apache.activemq.openwire.OpenWireFormat;
028import org.apache.activemq.util.ByteSequence;
029
030public abstract class BaseDataStreamMarshaller implements DataStreamMarshaller {
031
032    public static final Constructor STACK_TRACE_ELEMENT_CONSTRUCTOR;
033
034    static {
035        Constructor constructor = null;
036        try {
037            constructor = StackTraceElement.class.getConstructor(new Class[] {String.class, String.class,
038                                                                              String.class, int.class});
039        } catch (Throwable e) {
040        }
041        STACK_TRACE_ELEMENT_CONSTRUCTOR = constructor;
042    }
043
044    public abstract byte getDataStructureType();
045
046    public abstract DataStructure createObject();
047
048    public int tightMarshal1(OpenWireFormat wireFormat, Object o, BooleanStream bs) throws IOException {
049        return 0;
050    }
051
052    public void tightMarshal2(OpenWireFormat wireFormat, Object o, DataOutput dataOut, BooleanStream bs)
053        throws IOException {
054    }
055
056    public void tightUnmarshal(OpenWireFormat wireFormat, Object o, DataInput dataIn, BooleanStream bs)
057        throws IOException {
058    }
059
060    public int tightMarshalLong1(OpenWireFormat wireFormat, long o, BooleanStream bs) throws IOException {
061        if (o == 0) {
062            bs.writeBoolean(false);
063            bs.writeBoolean(false);
064            return 0;
065        } else if ((o & 0xFFFFFFFFFFFF0000L) == 0) {
066            bs.writeBoolean(false);
067            bs.writeBoolean(true);
068            return 2;
069        } else if ((o & 0xFFFFFFFF00000000L) == 0) {
070            bs.writeBoolean(true);
071            bs.writeBoolean(false);
072            return 4;
073        } else {
074            bs.writeBoolean(true);
075            bs.writeBoolean(true);
076            return 8;
077        }
078    }
079
080    public void tightMarshalLong2(OpenWireFormat wireFormat, long o, DataOutput dataOut, BooleanStream bs)
081        throws IOException {
082        if (bs.readBoolean()) {
083            if (bs.readBoolean()) {
084                dataOut.writeLong(o);
085            } else {
086                dataOut.writeInt((int)o);
087            }
088        } else {
089            if (bs.readBoolean()) {
090                dataOut.writeShort((int)o);
091            }
092        }
093    }
094
095    public long tightUnmarshalLong(OpenWireFormat wireFormat, DataInput dataIn, BooleanStream bs)
096        throws IOException {
097        if (bs.readBoolean()) {
098            if (bs.readBoolean()) {
099                return dataIn.readLong();
100            } else {
101                return toLong(dataIn.readInt());
102            }
103        } else {
104            if (bs.readBoolean()) {
105                return toLong(dataIn.readShort());
106            } else {
107                return 0;
108            }
109        }
110    }
111
112    protected long toLong(short value) {
113        // lets handle negative values
114        long answer = value;
115        return answer & 0xffffL;
116    }
117
118    protected long toLong(int value) {
119        // lets handle negative values
120        long answer = value;
121        return answer & 0xffffffffL;
122    }
123
124    protected DataStructure tightUnmarsalNestedObject(OpenWireFormat wireFormat, DataInput dataIn,
125                                                      BooleanStream bs) throws IOException {
126        return wireFormat.tightUnmarshalNestedObject(dataIn, bs);
127    }
128
129    protected int tightMarshalNestedObject1(OpenWireFormat wireFormat, DataStructure o, BooleanStream bs)
130        throws IOException {
131        return wireFormat.tightMarshalNestedObject1(o, bs);
132    }
133
134    protected void tightMarshalNestedObject2(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut,
135                                             BooleanStream bs) throws IOException {
136        wireFormat.tightMarshalNestedObject2(o, dataOut, bs);
137    }
138
139    protected DataStructure tightUnmarsalCachedObject(OpenWireFormat wireFormat, DataInput dataIn,
140                                                      BooleanStream bs) throws IOException {
141        if (wireFormat.isCacheEnabled()) {
142            if (bs.readBoolean()) {
143                short index = dataIn.readShort();
144                DataStructure object = wireFormat.tightUnmarshalNestedObject(dataIn, bs);
145                wireFormat.setInUnmarshallCache(index, object);
146                return object;
147            } else {
148                short index = dataIn.readShort();
149                return wireFormat.getFromUnmarshallCache(index);
150            }
151        } else {
152            return wireFormat.tightUnmarshalNestedObject(dataIn, bs);
153        }
154    }
155
156    protected int tightMarshalCachedObject1(OpenWireFormat wireFormat, DataStructure o, BooleanStream bs)
157        throws IOException {
158        if (wireFormat.isCacheEnabled()) {
159            Short index = wireFormat.getMarshallCacheIndex(o);
160            bs.writeBoolean(index == null);
161            if (index == null) {
162                int rc = wireFormat.tightMarshalNestedObject1(o, bs);
163                wireFormat.addToMarshallCache(o);
164                return 2 + rc;
165            } else {
166                return 2;
167            }
168        } else {
169            return wireFormat.tightMarshalNestedObject1(o, bs);
170        }
171    }
172
173    protected void tightMarshalCachedObject2(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut,
174                                             BooleanStream bs) throws IOException {
175        if (wireFormat.isCacheEnabled()) {
176            Short index = wireFormat.getMarshallCacheIndex(o);
177            if (bs.readBoolean()) {
178                dataOut.writeShort(index.shortValue());
179                wireFormat.tightMarshalNestedObject2(o, dataOut, bs);
180            } else {
181                dataOut.writeShort(index.shortValue());
182            }
183        } else {
184            wireFormat.tightMarshalNestedObject2(o, dataOut, bs);
185        }
186    }
187
188    protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn, BooleanStream bs)
189        throws IOException {
190        if (bs.readBoolean()) {
191            String clazz = tightUnmarshalString(dataIn, bs);
192            String message = tightUnmarshalString(dataIn, bs);
193            Throwable o = createThrowable(clazz, message);
194            if (wireFormat.isStackTraceEnabled()) {
195                if (STACK_TRACE_ELEMENT_CONSTRUCTOR != null) {
196                    StackTraceElement ss[] = new StackTraceElement[dataIn.readShort()];
197                    for (int i = 0; i < ss.length; i++) {
198                        try {
199                            ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR
200                                .newInstance(new Object[] {tightUnmarshalString(dataIn, bs),
201                                                           tightUnmarshalString(dataIn, bs),
202                                                           tightUnmarshalString(dataIn, bs),
203                                                           Integer.valueOf(dataIn.readInt())});
204                        } catch (IOException e) {
205                            throw e;
206                        } catch (Throwable e) {
207                        }
208                    }
209                    o.setStackTrace(ss);
210                } else {
211                    short size = dataIn.readShort();
212                    for (int i = 0; i < size; i++) {
213                        tightUnmarshalString(dataIn, bs);
214                        tightUnmarshalString(dataIn, bs);
215                        tightUnmarshalString(dataIn, bs);
216                        dataIn.readInt();
217                    }
218                }
219                o.initCause(tightUnmarsalThrowable(wireFormat, dataIn, bs));
220
221            }
222            return o;
223        } else {
224            return null;
225        }
226    }
227
228    private Throwable createThrowable(String className, String message) {
229        try {
230            Class clazz = Class.forName(className, false, BaseDataStreamMarshaller.class.getClassLoader());
231            Constructor constructor = clazz.getConstructor(new Class[] {String.class});
232            return (Throwable)constructor.newInstance(new Object[] {message});
233        } catch (Throwable e) {
234            return new Throwable(className + ": " + message);
235        }
236    }
237
238    protected int tightMarshalThrowable1(OpenWireFormat wireFormat, Throwable o, BooleanStream bs)
239        throws IOException {
240        if (o == null) {
241            bs.writeBoolean(false);
242            return 0;
243        } else {
244            int rc = 0;
245            bs.writeBoolean(true);
246            rc += tightMarshalString1(o.getClass().getName(), bs);
247            rc += tightMarshalString1(o.getMessage(), bs);
248            if (wireFormat.isStackTraceEnabled()) {
249                rc += 2;
250                StackTraceElement[] stackTrace = o.getStackTrace();
251                for (int i = 0; i < stackTrace.length; i++) {
252                    StackTraceElement element = stackTrace[i];
253                    rc += tightMarshalString1(element.getClassName(), bs);
254                    rc += tightMarshalString1(element.getMethodName(), bs);
255                    rc += tightMarshalString1(element.getFileName(), bs);
256                    rc += 4;
257                }
258                rc += tightMarshalThrowable1(wireFormat, o.getCause(), bs);
259            }
260            return rc;
261        }
262    }
263
264    protected void tightMarshalThrowable2(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut,
265                                          BooleanStream bs) throws IOException {
266        if (bs.readBoolean()) {
267            tightMarshalString2(o.getClass().getName(), dataOut, bs);
268            tightMarshalString2(o.getMessage(), dataOut, bs);
269            if (wireFormat.isStackTraceEnabled()) {
270                StackTraceElement[] stackTrace = o.getStackTrace();
271                dataOut.writeShort(stackTrace.length);
272                for (int i = 0; i < stackTrace.length; i++) {
273                    StackTraceElement element = stackTrace[i];
274                    tightMarshalString2(element.getClassName(), dataOut, bs);
275                    tightMarshalString2(element.getMethodName(), dataOut, bs);
276                    tightMarshalString2(element.getFileName(), dataOut, bs);
277                    dataOut.writeInt(element.getLineNumber());
278                }
279                tightMarshalThrowable2(wireFormat, o.getCause(), dataOut, bs);
280            }
281        }
282    }
283
284    @SuppressWarnings("deprecation")
285    protected String tightUnmarshalString(DataInput dataIn, BooleanStream bs) throws IOException {
286        if (bs.readBoolean()) {
287            if (bs.readBoolean()) {
288                int size = dataIn.readShort();
289                byte data[] = new byte[size];
290                dataIn.readFully(data);
291                // Yes deprecated, but we know what we are doing.
292                // This allows us to create a String from a ASCII byte array. (no UTF-8 decoding)
293                return new String(data, 0);
294            } else {
295                return dataIn.readUTF();
296            }
297        } else {
298            return null;
299        }
300    }
301
302    protected int tightMarshalString1(String value, BooleanStream bs) throws IOException {
303        bs.writeBoolean(value != null);
304        if (value != null) {
305
306            int strlen = value.length();
307            int utflen = 0;
308            char[] charr = new char[strlen];
309            int c = 0;
310            boolean isOnlyAscii = true;
311
312            value.getChars(0, strlen, charr, 0);
313
314            for (int i = 0; i < strlen; i++) {
315                c = charr[i];
316                if ((c >= 0x0001) && (c <= 0x007F)) {
317                    utflen++;
318                } else if (c > 0x07FF) {
319                    utflen += 3;
320                    isOnlyAscii = false;
321                } else {
322                    isOnlyAscii = false;
323                    utflen += 2;
324                }
325            }
326
327            if (utflen >= Short.MAX_VALUE) {
328                throw new IOException("Encountered a String value that is too long to encode.");
329            }
330            bs.writeBoolean(isOnlyAscii);
331            return utflen + 2;
332
333        } else {
334            return 0;
335        }
336    }
337
338    protected void tightMarshalString2(String value, DataOutput dataOut, BooleanStream bs) throws IOException {
339        if (bs.readBoolean()) {
340            // If we verified it only holds ascii values
341            if (bs.readBoolean()) {
342                dataOut.writeShort(value.length());
343                dataOut.writeBytes(value);
344            } else {
345                dataOut.writeUTF(value);
346            }
347        }
348    }
349
350    protected int tightMarshalObjectArray1(OpenWireFormat wireFormat, DataStructure[] objects,
351                                           BooleanStream bs) throws IOException {
352        if (objects != null) {
353            int rc = 0;
354            bs.writeBoolean(true);
355            rc += 2;
356            for (int i = 0; i < objects.length; i++) {
357                rc += tightMarshalNestedObject1(wireFormat, objects[i], bs);
358            }
359            return rc;
360        } else {
361            bs.writeBoolean(false);
362            return 0;
363        }
364    }
365
366    protected void tightMarshalObjectArray2(OpenWireFormat wireFormat, DataStructure[] objects,
367                                            DataOutput dataOut, BooleanStream bs) throws IOException {
368        if (bs.readBoolean()) {
369            dataOut.writeShort(objects.length);
370            for (int i = 0; i < objects.length; i++) {
371                tightMarshalNestedObject2(wireFormat, objects[i], dataOut, bs);
372            }
373        }
374    }
375
376    protected int tightMarshalConstByteArray1(byte[] data, BooleanStream bs, int i) throws IOException {
377        return i;
378    }
379
380    protected void tightMarshalConstByteArray2(byte[] data, DataOutput dataOut, BooleanStream bs, int i)
381        throws IOException {
382        dataOut.write(data, 0, i);
383    }
384
385    protected byte[] tightUnmarshalConstByteArray(DataInput dataIn, BooleanStream bs, int i)
386        throws IOException {
387        byte data[] = new byte[i];
388        dataIn.readFully(data);
389        return data;
390    }
391
392    protected int tightMarshalByteArray1(byte[] data, BooleanStream bs) throws IOException {
393        bs.writeBoolean(data != null);
394        if (data != null) {
395            return data.length + 4;
396        } else {
397            return 0;
398        }
399    }
400
401    protected void tightMarshalByteArray2(byte[] data, DataOutput dataOut, BooleanStream bs)
402        throws IOException {
403        if (bs.readBoolean()) {
404            dataOut.writeInt(data.length);
405            dataOut.write(data);
406        }
407    }
408
409    protected byte[] tightUnmarshalByteArray(DataInput dataIn, BooleanStream bs) throws IOException {
410        byte rc[] = null;
411        if (bs.readBoolean()) {
412            int size = dataIn.readInt();
413            rc = new byte[size];
414            dataIn.readFully(rc);
415        }
416        return rc;
417    }
418
419    protected int tightMarshalByteSequence1(ByteSequence data, BooleanStream bs) throws IOException {
420        bs.writeBoolean(data != null);
421        if (data != null) {
422            return data.getLength() + 4;
423        } else {
424            return 0;
425        }
426    }
427
428    protected void tightMarshalByteSequence2(ByteSequence data, DataOutput dataOut, BooleanStream bs)
429        throws IOException {
430        if (bs.readBoolean()) {
431            dataOut.writeInt(data.getLength());
432            dataOut.write(data.getData(), data.getOffset(), data.getLength());
433        }
434    }
435
436    protected ByteSequence tightUnmarshalByteSequence(DataInput dataIn, BooleanStream bs) throws IOException {
437        ByteSequence rc = null;
438        if (bs.readBoolean()) {
439            int size = dataIn.readInt();
440            byte[] t = new byte[size];
441            dataIn.readFully(t);
442            return new ByteSequence(t, 0, size);
443        }
444        return rc;
445    }
446
447    //
448    // The loose marshaling logic
449    //
450
451    public void looseMarshal(OpenWireFormat wireFormat, Object o, DataOutput dataOut) throws IOException {
452    }
453
454    public void looseUnmarshal(OpenWireFormat wireFormat, Object o, DataInput dataIn) throws IOException {
455    }
456
457    public void looseMarshalLong(OpenWireFormat wireFormat, long o, DataOutput dataOut) throws IOException {
458        dataOut.writeLong(o);
459    }
460
461    public long looseUnmarshalLong(OpenWireFormat wireFormat, DataInput dataIn) throws IOException {
462        return dataIn.readLong();
463    }
464
465    protected DataStructure looseUnmarsalNestedObject(OpenWireFormat wireFormat, DataInput dataIn)
466        throws IOException {
467        return wireFormat.looseUnmarshalNestedObject(dataIn);
468    }
469
470    protected void looseMarshalNestedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut)
471        throws IOException {
472        wireFormat.looseMarshalNestedObject(o, dataOut);
473    }
474
475    protected DataStructure looseUnmarsalCachedObject(OpenWireFormat wireFormat, DataInput dataIn)
476        throws IOException {
477        if (wireFormat.isCacheEnabled()) {
478            if (dataIn.readBoolean()) {
479                short index = dataIn.readShort();
480                DataStructure object = wireFormat.looseUnmarshalNestedObject(dataIn);
481                wireFormat.setInUnmarshallCache(index, object);
482                return object;
483            } else {
484                short index = dataIn.readShort();
485                return wireFormat.getFromUnmarshallCache(index);
486            }
487        } else {
488            return wireFormat.looseUnmarshalNestedObject(dataIn);
489        }
490    }
491
492    protected void looseMarshalCachedObject(OpenWireFormat wireFormat, DataStructure o, DataOutput dataOut)
493        throws IOException {
494        if (wireFormat.isCacheEnabled()) {
495            Short index = wireFormat.getMarshallCacheIndex(o);
496            dataOut.writeBoolean(index == null);
497            if (index == null) {
498                index = wireFormat.addToMarshallCache(o);
499                dataOut.writeShort(index.shortValue());
500                wireFormat.looseMarshalNestedObject(o, dataOut);
501            } else {
502                dataOut.writeShort(index.shortValue());
503            }
504        } else {
505            wireFormat.looseMarshalNestedObject(o, dataOut);
506        }
507    }
508
509    protected Throwable looseUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn)
510        throws IOException {
511        if (dataIn.readBoolean()) {
512            String clazz = looseUnmarshalString(dataIn);
513            String message = looseUnmarshalString(dataIn);
514            Throwable o = createThrowable(clazz, message);
515            if (wireFormat.isStackTraceEnabled()) {
516                if (STACK_TRACE_ELEMENT_CONSTRUCTOR != null) {
517                    StackTraceElement ss[] = new StackTraceElement[dataIn.readShort()];
518                    for (int i = 0; i < ss.length; i++) {
519                        try {
520                            ss[i] = (StackTraceElement)STACK_TRACE_ELEMENT_CONSTRUCTOR
521                                .newInstance(new Object[] {looseUnmarshalString(dataIn),
522                                                           looseUnmarshalString(dataIn),
523                                                           looseUnmarshalString(dataIn),
524                                                           Integer.valueOf(dataIn.readInt())});
525                        } catch (IOException e) {
526                            throw e;
527                        } catch (Throwable e) {
528                        }
529                    }
530                    o.setStackTrace(ss);
531                } else {
532                    short size = dataIn.readShort();
533                    for (int i = 0; i < size; i++) {
534                        looseUnmarshalString(dataIn);
535                        looseUnmarshalString(dataIn);
536                        looseUnmarshalString(dataIn);
537                        dataIn.readInt();
538                    }
539                }
540                o.initCause(looseUnmarsalThrowable(wireFormat, dataIn));
541
542            }
543            return o;
544        } else {
545            return null;
546        }
547    }
548
549    protected void looseMarshalThrowable(OpenWireFormat wireFormat, Throwable o, DataOutput dataOut)
550        throws IOException {
551        dataOut.writeBoolean(o != null);
552        if (o != null) {
553            looseMarshalString(o.getClass().getName(), dataOut);
554            looseMarshalString(o.getMessage(), dataOut);
555            if (wireFormat.isStackTraceEnabled()) {
556                StackTraceElement[] stackTrace = o.getStackTrace();
557                dataOut.writeShort(stackTrace.length);
558                for (int i = 0; i < stackTrace.length; i++) {
559                    StackTraceElement element = stackTrace[i];
560                    looseMarshalString(element.getClassName(), dataOut);
561                    looseMarshalString(element.getMethodName(), dataOut);
562                    looseMarshalString(element.getFileName(), dataOut);
563                    dataOut.writeInt(element.getLineNumber());
564                }
565                looseMarshalThrowable(wireFormat, o.getCause(), dataOut);
566            }
567        }
568    }
569
570    protected String looseUnmarshalString(DataInput dataIn) throws IOException {
571        if (dataIn.readBoolean()) {
572            return dataIn.readUTF();
573        } else {
574            return null;
575        }
576    }
577
578    protected void looseMarshalString(String value, DataOutput dataOut) throws IOException {
579        dataOut.writeBoolean(value != null);
580        if (value != null) {
581            dataOut.writeUTF(value);
582        }
583    }
584
585    protected void looseMarshalObjectArray(OpenWireFormat wireFormat, DataStructure[] objects,
586                                           DataOutput dataOut) throws IOException {
587        dataOut.writeBoolean(objects != null);
588        if (objects != null) {
589            dataOut.writeShort(objects.length);
590            for (int i = 0; i < objects.length; i++) {
591                looseMarshalNestedObject(wireFormat, objects[i], dataOut);
592            }
593        }
594    }
595
596    protected void looseMarshalConstByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut,
597                                              int i) throws IOException {
598        dataOut.write(data, 0, i);
599    }
600
601    protected byte[] looseUnmarshalConstByteArray(DataInput dataIn, int i) throws IOException {
602        byte data[] = new byte[i];
603        dataIn.readFully(data);
604        return data;
605    }
606
607    protected void looseMarshalByteArray(OpenWireFormat wireFormat, byte[] data, DataOutput dataOut)
608        throws IOException {
609        dataOut.writeBoolean(data != null);
610        if (data != null) {
611            dataOut.writeInt(data.length);
612            dataOut.write(data);
613        }
614    }
615
616    protected byte[] looseUnmarshalByteArray(DataInput dataIn) throws IOException {
617        byte rc[] = null;
618        if (dataIn.readBoolean()) {
619            int size = dataIn.readInt();
620            rc = new byte[size];
621            dataIn.readFully(rc);
622        }
623        return rc;
624    }
625
626    protected void looseMarshalByteSequence(OpenWireFormat wireFormat, ByteSequence data, DataOutput dataOut)
627        throws IOException {
628        dataOut.writeBoolean(data != null);
629        if (data != null) {
630            dataOut.writeInt(data.getLength());
631            dataOut.write(data.getData(), data.getOffset(), data.getLength());
632        }
633    }
634
635    protected ByteSequence looseUnmarshalByteSequence(DataInput dataIn) throws IOException {
636        ByteSequence rc = null;
637        if (dataIn.readBoolean()) {
638            int size = dataIn.readInt();
639            byte[] t = new byte[size];
640            dataIn.readFully(t);
641            rc = new ByteSequence(t, 0, size);
642        }
643        return rc;
644    }
645}