• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.jme3.network.serializing.serializers;
34 
35 import com.jme3.network.serializing.Serializer;
36 import com.jme3.network.serializing.SerializerRegistration;
37 import java.io.IOException;
38 import java.nio.ByteBuffer;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.Map;
42 import java.util.Map.Entry;
43 import java.util.Set;
44 import java.util.logging.Level;
45 
46 public class MapSerializer extends Serializer {
47 
48     /*
49 
50     Structure:
51 
52     struct Map {
53         INT length
54         BYTE flags = { 0x01 = all keys have the same type,
55                        0x02 = all values have the same type }
56         if (flags has 0x01 set)
57             SHORT keyType
58         if (flags has 0x02 set)
59             SHORT valType
60 
61         struct MapEntry[length] entries {
62             if (flags does not have 0x01 set)
63                 SHORT keyType
64             OBJECT key
65 
66             if (flags does not have 0x02 set)
67                 SHORT valType
68             OBJECT value
69         }
70     }
71 
72      */
73 
74     @SuppressWarnings("unchecked")
readObject(ByteBuffer data, Class<T> c)75     public <T> T readObject(ByteBuffer data, Class<T> c) throws IOException {
76         int length = data.getInt();
77 
78         Map map;
79         try {
80             map = (Map)c.newInstance();
81         } catch (Exception e) {
82             log.log(Level.WARNING, "[Serializer][???] Could not determine map type. Using HashMap.");
83             map = new HashMap();
84         }
85 
86         if (length == 0) return (T)map;
87 
88         int flags = data.get() & 0xff;
89         boolean uniqueKeys = (flags & 0x01) == 0;
90         boolean uniqueVals = (flags & 0x02) == 0;
91 
92         Class keyClazz = null;
93         Class valClazz = null;
94         Serializer keySerial = null;
95         Serializer valSerial = null;
96         if (!uniqueKeys){
97             SerializerRegistration reg = Serializer.readClass(data);
98             keyClazz = reg.getType();
99             keySerial = reg.getSerializer();
100         }
101         if (!uniqueVals){
102             SerializerRegistration reg = Serializer.readClass(data);
103             valClazz = reg.getType();
104             valSerial = reg.getSerializer();
105         }
106 
107         for (int i = 0; i < length; i++){
108             Object key;
109             Object value;
110             if (uniqueKeys){
111                 key = Serializer.readClassAndObject(data);
112             }else{
113                 key = keySerial.readObject(data, keyClazz);
114             }
115             if (uniqueVals){
116                 value = Serializer.readClassAndObject(data);
117             }else{
118                 value = valSerial.readObject(data, valClazz);
119             }
120 
121             map.put(key, value);
122         }
123 
124         return (T)map;
125     }
126 
127     @SuppressWarnings("unchecked")
writeObject(ByteBuffer buffer, Object object)128     public void writeObject(ByteBuffer buffer, Object object) throws IOException {
129         Map map = (Map)object;
130         int length = map.size();
131 
132         buffer.putInt(length);
133         if (length == 0) return;
134 
135 
136         Set<Entry> entries = map.entrySet();
137 
138         Iterator<Entry> it = entries.iterator();
139 
140         Entry entry = it.next();
141         Class keyClass = entry.getKey().getClass();
142         Class valClass = entry.getValue().getClass();
143         while (it.hasNext()) {
144             entry = it.next();
145 
146             if (entry.getKey().getClass() != keyClass){
147                 keyClass = null;
148                 if (valClass == null)
149                     break;
150             }
151             if (entry.getValue().getClass() != valClass){
152                 valClass = null;
153                 if (keyClass == null)
154                     break;
155             }
156         }
157 
158         boolean uniqueKeys = keyClass == null;
159         boolean uniqueVals = valClass == null;
160         int flags = 0;
161         if (!uniqueKeys) flags |= 0x01;
162         if (!uniqueVals) flags |= 0x02;
163         buffer.put( (byte) flags );
164 
165         Serializer keySerial = null, valSerial = null;
166         if (!uniqueKeys){
167             Serializer.writeClass(buffer, keyClass);
168             keySerial = Serializer.getSerializer(keyClass);
169         }
170         if (!uniqueVals){
171             Serializer.writeClass(buffer, valClass);
172             valSerial = Serializer.getSerializer(valClass);
173         }
174 
175         it = entries.iterator();
176         while (it.hasNext()) {
177             entry = it.next();
178             if (uniqueKeys){
179                 Serializer.writeClassAndObject(buffer, entry.getKey());
180             }else{
181                 keySerial.writeObject(buffer, entry.getKey());
182             }
183             if (uniqueVals){
184                 Serializer.writeClassAndObject(buffer, entry.getValue());
185             }else{
186                 valSerial.writeObject(buffer, entry.getValue());
187             }
188         }
189     }
190 }
191