001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2013 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.messaging.jmf.codec.std.impl;
022    
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.util.HashMap;
026    import java.util.Map;
027    
028    import org.granite.messaging.jmf.CodecRegistry;
029    import org.granite.messaging.jmf.DumpContext;
030    import org.granite.messaging.jmf.InputContext;
031    import org.granite.messaging.jmf.JMFEncodingException;
032    import org.granite.messaging.jmf.OutputContext;
033    import org.granite.messaging.jmf.codec.StandardCodec;
034    import org.granite.messaging.jmf.codec.std.HashMapCodec;
035    
036    /**
037     * @author Franck WOLFF
038     */
039    public class HashMapCodecImpl extends AbstractIntegerStringCodec<HashMap<?, ?>> implements HashMapCodec {
040    
041            public int getObjectType() {
042                    return JMF_HASH_MAP;
043            }
044    
045            public Class<?> getObjectClass() {
046                    return HashMap.class;
047            }
048    
049            public void encode(OutputContext ctx, HashMap<?, ?> v) throws IOException {
050                    final OutputStream os = ctx.getOutputStream();
051                    
052                    int indexOfStoredObject = ctx.indexOfStoredObjects(v);
053                    if (indexOfStoredObject >= 0) {
054                            IntegerComponents ics = intComponents(indexOfStoredObject);
055                            os.write(0x80 | (ics.length << 5) | JMF_HASH_MAP);
056                            writeIntData(ctx, ics);
057                    }
058                    else {
059                            ctx.addToStoredObjects(v);
060                            
061                            Map.Entry<?, ?>[] snapshot = v.entrySet().toArray(new Map.Entry<?, ?>[0]);
062                            
063                            IntegerComponents ics = intComponents(snapshot.length);
064                            os.write((ics.length << 5) | JMF_HASH_MAP);
065                            writeIntData(ctx, ics);
066                            
067                            for (Map.Entry<?, ?> entry : snapshot) {
068                                    ctx.writeObject(entry.getKey());
069                                    ctx.writeObject(entry.getValue());
070                            }
071                    }
072            }
073    
074            public HashMap<?, ?> decode(InputContext ctx, int parameterizedJmfType) throws IOException, ClassNotFoundException {
075                    int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
076                    
077                    if (jmfType != JMF_HASH_MAP)
078                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
079                    
080                    final int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 5) & 0x03, false);
081                    if ((parameterizedJmfType & 0x80) != 0)
082                            return (HashMap<?, ?>)ctx.getSharedObject(indexOrLength);
083    
084                    HashMap<Object, Object> v = new HashMap<Object, Object>(indexOrLength);
085                    ctx.addSharedObject(v);
086                    
087                    for (int index = 0; index < indexOrLength; index++) {
088                            Object key = ctx.readObject();
089                            Object value = ctx.readObject();
090                            v.put(key, value);
091                    }
092                                    
093                    return v;
094            }
095    
096            public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
097                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
098                    
099                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
100                    
101                    if (jmfType != JMF_HASH_MAP)
102                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
103                    
104                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 5) & 0x03, false);
105                    if ((parameterizedJmfType & 0x80) != 0) {
106                            String v = (String)ctx.getSharedObject(indexOrLength);
107                            ctx.indentPrintLn("<" + v + "@" + indexOrLength + ">");
108                            return;
109                    }
110    
111                    String v = HashMap.class.getName() + "[" + indexOrLength + "]";
112                    int indexOfStoredObject = ctx.addSharedObject(v);
113                    ctx.indentPrintLn(v + "@" + indexOfStoredObject + " {");
114                    ctx.incrIndent(1);
115                    
116                    for (int index = 0; index < indexOrLength; index++) {
117                            parameterizedJmfType = ctx.safeRead();
118                            jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
119                            StandardCodec<?> codec = codecRegistry.getCodec(jmfType);
120                            
121                            if (codec == null)
122                                    throw new JMFEncodingException("No codec for JMF type: " + jmfType);
123                            
124                            codec.dump(ctx, parameterizedJmfType);
125    
126                            ctx.incrIndent(1);
127                            parameterizedJmfType = ctx.safeRead();
128                            jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
129                            codec = codecRegistry.getCodec(jmfType);
130                            
131                            if (codec == null)
132                                    throw new JMFEncodingException("No codec for JMF type: " + jmfType);
133                            
134                            codec.dump(ctx, parameterizedJmfType);
135                            ctx.incrIndent(-1);
136                    }
137                            
138                    ctx.incrIndent(-1);
139                    ctx.indentPrintLn("}");
140            }
141    }