AbstractDecoder.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.transport.codec;
022 
023 import java.io.UnsupportedEncodingException;
024 
025 import java.util.ArrayList;
026 import java.util.Collections;
027 import java.util.LinkedHashMap;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.UUID;
031 
032 import org.apache.qpid.transport.Binary;
033 import org.apache.qpid.transport.RangeSet;
034 import org.apache.qpid.transport.Struct;
035 import org.apache.qpid.transport.Type;
036 
037 import static org.apache.qpid.transport.util.Functions.*;
038 
039 
040 /**
041  * AbstractDecoder
042  *
043  @author Rafael H. Schloming
044  */
045 
046 abstract class AbstractDecoder implements Decoder
047 {
048 
049     private final Map<Binary,String> str8cache = new LinkedHashMap<Binary,String>()
050     {
051         @Override protected boolean removeEldestEntry(Map.Entry<Binary,String> me)
052         {
053             return size() 4*1024;
054         }
055     };
056 
057     protected abstract byte doGet();
058 
059     protected abstract void doGet(byte[] bytes);
060 
061     protected byte get()
062     {
063         return doGet();
064     }
065 
066     protected void get(byte[] bytes)
067     {
068         doGet(bytes);
069     }
070 
071     protected Binary get(int size)
072     {
073         byte[] bytes = new byte[size];
074         get(bytes);
075         return new Binary(bytes);
076     }
077 
078     protected short uget()
079     {
080         return (short) (0xFF & get());
081     }
082 
083     public short readUint8()
084     {
085         return uget();
086     }
087 
088     public int readUint16()
089     {
090         int i = uget() << 8;
091         i |= uget();
092         return i;
093     }
094 
095     public long readUint32()
096     {
097         long l = uget() << 24;
098         l |= uget() << 16;
099         l |= uget() << 8;
100         l |= uget();
101         return l;
102     }
103 
104     public int readSequenceNo()
105     {
106         return (intreadUint32();
107     }
108 
109     public long readUint64()
110     {
111         long l = 0;
112         for (int i = 0; i < 8; i++)
113         {
114             l |= ((long) (0xFF & get())) << (56 - i*8);
115         }
116         return l;
117     }
118 
119     public long readDatetime()
120     {
121         return readUint64();
122     }
123 
124     private static final String decode(byte[] bytes, int offset, int length, String charset)
125     {
126         try
127         {
128             return new String(bytes, offset, length, charset);
129         }
130         catch (UnsupportedEncodingException e)
131         {
132             throw new RuntimeException(e);
133         }
134     }
135 
136     private static final String decode(byte[] bytes, String charset)
137     {
138         return decode(bytes, 0, bytes.length, charset);
139     }
140 
141     public String readStr8()
142     {
143         short size = readUint8();
144         Binary bin = get(size);
145         String str = str8cache.get(bin);
146         if (str == null)
147         {
148             str = decode(bin.array(), bin.offset(), bin.size()"UTF-8");
149             str8cache.put(bin, str);
150         }
151         return str;
152     }
153 
154     public String readStr16()
155     {
156         int size = readUint16();
157         byte[] bytes = new byte[size];
158         get(bytes);
159         return decode(bytes, "UTF-8");
160     }
161 
162     public byte[] readVbin8()
163     {
164         int size = readUint8();
165         byte[] bytes = new byte[size];
166         get(bytes);
167         return bytes;
168     }
169 
170     public byte[] readVbin16()
171     {
172         int size = readUint16();
173         byte[] bytes = new byte[size];
174         get(bytes);
175         return bytes;
176     }
177 
178     public byte[] readVbin32()
179     {
180         int size = (intreadUint32();
181         byte[] bytes = new byte[size];
182         get(bytes);
183         return bytes;
184     }
185 
186     public RangeSet readSequenceSet()
187     {
188         int count = readUint16()/8;
189         if (count == 0)
190         {
191             return null;
192         }
193         else
194         {
195             RangeSet ranges = new RangeSet();
196             for (int i = 0; i < count; i++)
197             {
198                 ranges.add(readSequenceNo(), readSequenceNo());
199             }
200             return ranges;
201         }
202     }
203 
204     public RangeSet readByteRanges()
205     {
206         throw new Error("not implemented");
207     }
208 
209     public UUID readUuid()
210     {
211         long msb = readUint64();
212         long lsb = readUint64();
213         return new UUID(msb, lsb);
214     }
215 
216     public String readContent()
217     {
218         throw new Error("Deprecated");
219     }
220 
221     public Struct readStruct(int type)
222     {
223         Struct st = Struct.create(type);
224         int width = st.getSizeWidth();
225         if (width > 0)
226         {
227             long size = readSize(width);
228             if (size == 0)
229             {
230                 return null;
231             }
232         }
233         if (type > 0)
234         {
235             int code = readUint16();
236             assert code == type;
237         }
238         st.read(this);
239         return st;
240     }
241 
242     public Struct readStruct32()
243     {
244         long size = readUint32();
245         if (size == 0)
246         {
247             return null;
248         }
249         else
250         {
251             int type = readUint16();
252             Struct result = Struct.create(type);
253             result.read(this);
254             return result;
255         }
256     }
257 
258     public Map<String,Object> readMap()
259     {
260         long size = readUint32();
261 
262         if (size == 0)
263         {
264             return null;
265         }
266 
267         long count = readUint32();
268 
269         if (count == 0)
270         {
271             return Collections.EMPTY_MAP;
272         }
273 
274         Map<String,Object> result = new LinkedHashMap();
275         for (int i = 0; i < count; i++)
276         {
277             String key = readStr8();
278             byte code = get();
279             Type t = getType(code);
280             Object value = read(t);
281             result.put(key, value);
282         }
283 
284         return result;
285     }
286 
287     public List<Object> readList()
288     {
289         long size = readUint32();
290 
291         if (size == 0)
292         {
293             return null;
294         }
295 
296         long count = readUint32();
297 
298         if (count == 0)
299         {
300             return Collections.EMPTY_LIST;
301         }
302 
303         List<Object> result = new ArrayList();
304         for (int i = 0; i < count; i++)
305         {
306             byte code = get();
307             Type t = getType(code);
308             Object value = read(t);
309             result.add(value);
310         }
311         return result;
312     }
313 
314     public List<Object> readArray()
315     {
316         long size = readUint32();
317 
318         if (size == 0)
319         {
320             return null;
321         }
322 
323         byte code = get();
324         Type t = getType(code);
325         long count = readUint32();
326 
327         if (count == 0)
328         {
329             return Collections.EMPTY_LIST;
330         }
331 
332         List<Object> result = new ArrayList<Object>();
333         for (int i = 0; i < count; i++)
334         {
335             Object value = read(t);
336             result.add(value);
337         }
338         return result;
339     }
340 
341     private Type getType(byte code)
342     {
343         Type type = Type.get(code);
344         if (type == null)
345         {
346             throw new IllegalArgumentException("unknown code: " + code);
347         }
348         else
349         {
350             return type;
351         }
352     }
353 
354     private long readSize(Type t)
355     {
356         if (t.fixed)
357         {
358             return t.width;
359         }
360         else
361         {
362             return readSize(t.width);
363         }
364     }
365 
366     private long readSize(int width)
367     {
368         switch (width)
369         {
370         case 1:
371             return readUint8();
372         case 2:
373             return readUint16();
374         case 4:
375             return readUint32();
376         default:
377             throw new IllegalStateException("illegal width: " + width);
378         }
379     }
380 
381     private byte[] readBytes(Type t)
382     {
383         long size = readSize(t);
384         byte[] result = new byte[(intsize];
385         get(result);
386         return result;
387     }
388 
389     private Object read(Type t)
390     {
391         switch (t)
392         {
393         case BIN8:
394         case UINT8:
395             return readUint8();
396         case INT8:
397             return get();
398         case CHAR:
399             return (charget();
400         case BOOLEAN:
401             return get() 0;
402 
403         case BIN16:
404         case UINT16:
405             return readUint16();
406 
407         case INT16:
408             return (shortreadUint16();
409 
410         case BIN32:
411         case UINT32:
412             return readUint32();
413 
414         case CHAR_UTF32:
415         case INT32:
416             return (intreadUint32();
417 
418         case FLOAT:
419             return Float.intBitsToFloat((intreadUint32());
420 
421         case BIN64:
422         case UINT64:
423         case INT64:
424         case DATETIME:
425             return readUint64();
426 
427         case DOUBLE:
428             return Double.longBitsToDouble(readUint64());
429 
430         case UUID:
431             return readUuid();
432 
433         case STR8:
434             return readStr8();
435 
436         case STR16:
437             return readStr16();
438 
439         case STR8_LATIN:
440         case STR8_UTF16:
441         case STR16_LATIN:
442         case STR16_UTF16:
443             // XXX: need to do character conversion
444             return new String(readBytes(t));
445 
446         case MAP:
447             return readMap();
448         case LIST:
449             return readList();
450         case ARRAY:
451             return readArray();
452         case STRUCT32:
453             return readStruct32();
454 
455         case BIN40:
456         case DEC32:
457         case BIN72:
458         case DEC64:
459             // XXX: what types are we supposed to use here?
460             return readBytes(t);
461 
462         case VOID:
463             return null;
464 
465         default:
466             return readBytes(t);
467         }
468     }
469 
470 }