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