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     */
017    package org.apache.activemq.openwire.v3;
018    
019    import java.io.DataInput;
020    import java.io.DataOutput;
021    import java.io.IOException;
022    import java.lang.reflect.Constructor;
023    
024    import org.apache.activemq.command.DataStructure;
025    import org.apache.activemq.openwire.BooleanStream;
026    import org.apache.activemq.openwire.DataStreamMarshaller;
027    import org.apache.activemq.openwire.OpenWireFormat;
028    import org.apache.activemq.util.ByteSequence;
029    
030    public 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    }