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