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;
022
023 import java.io.IOException;
024 import java.io.OutputStream;
025 import java.lang.reflect.Field;
026 import java.util.HashMap;
027 import java.util.IdentityHashMap;
028 import java.util.Map;
029
030 import org.granite.messaging.jmf.codec.StandardCodec;
031 import org.granite.messaging.jmf.reflect.Reflection;
032
033 /**
034 * @author Franck WOLFF
035 */
036 public class JMFSerializer implements OutputContext {
037
038 ///////////////////////////////////////////////////////////////////////////
039 // Fields
040
041 protected final Map<String, Integer> storedStrings = new HashMap<String, Integer>(256);
042 protected final Map<Object, Integer> storedObjects = new IdentityHashMap<Object, Integer>(256);
043
044 protected final OutputStream outputStream;
045 protected final SharedContext context;
046
047 protected final CodecRegistry codecRegistry;
048
049 ///////////////////////////////////////////////////////////////////////////
050 // Initialization
051
052 public JMFSerializer(OutputStream outputStream, SharedContext context) {
053 this.outputStream = outputStream;
054 this.codecRegistry = context.getCodecRegistry();
055 this.context = context;
056
057 for (String s : context.getDefaultStoredStrings())
058 addToStoredStrings(s);
059 }
060
061 ///////////////////////////////////////////////////////////////////////////
062 // ObjectOutput implementation
063
064 public void writeBoolean(boolean v) throws IOException {
065 codecRegistry.getBooleanCodec().encodePrimitive(this, v);
066 }
067
068 public void writeByte(int v) throws IOException {
069 codecRegistry.getByteCodec().encodePrimitive(this, v);
070 }
071
072 public void writeShort(int v) throws IOException {
073 codecRegistry.getShortCodec().encodePrimitive(this, v);
074 }
075
076 public void writeChar(int v) throws IOException {
077 codecRegistry.getCharacterCodec().encodePrimitive(this, v);
078 }
079
080 public void writeInt(int v) throws IOException {
081 codecRegistry.getIntegerCodec().encodePrimitive(this, v);
082 }
083
084 public void writeLong(long v) throws IOException {
085 codecRegistry.getLongCodec().encodePrimitive(this, v);
086 }
087
088 public void writeFloat(float v) throws IOException {
089 codecRegistry.getFloatCodec().encodePrimitive(this, v);
090 }
091
092 public void writeDouble(double v) throws IOException {
093 codecRegistry.getDoubleCodec().encodePrimitive(this, v);
094 }
095
096 public void writeUTF(String s) throws IOException {
097 if (s == null)
098 codecRegistry.getNullCodec().encode(this, s);
099 else
100 codecRegistry.getStringCodec().encode(this, s);
101 }
102
103 public void writeObject(Object obj) throws IOException {
104 StandardCodec<Object> codec = codecRegistry.getCodec(obj);
105 if (codec == null)
106 throw new JMFEncodingException("Unsupported Java class: " + obj);
107
108 try {
109 codec.encode(this, obj);
110 }
111 catch (IllegalAccessException e) {
112 throw new IOException(e);
113 }
114 }
115
116 public void flush() throws IOException {
117 outputStream.flush();
118 }
119
120 public void close() throws IOException {
121 outputStream.close();
122 }
123
124 ///////////////////////////////////////////////////////////////////////////
125 // ObjectOutput implementation (unsupported, marked at deprecated)
126
127 @Deprecated
128 public void write(int b) throws IOException {
129 throw new UnsupportedOperationException("Use writeByte(b)");
130 }
131
132 @Deprecated
133 public void write(byte[] b) throws IOException {
134 throw new UnsupportedOperationException("Use writeObject(b)");
135 }
136
137 @Deprecated
138 public void write(byte[] b, int off, int len) throws IOException {
139 throw new UnsupportedOperationException("Use writeObject(Arrays.copyOfRange(b, off, off+len))");
140 }
141
142 @Deprecated
143 public void writeBytes(String s) throws IOException {
144 throw new UnsupportedOperationException("Use writeUTF(s)");
145 }
146
147 @Deprecated
148 public void writeChars(String s) throws IOException {
149 throw new UnsupportedOperationException("Use writeUTF(s)");
150 }
151
152 ///////////////////////////////////////////////////////////////////////////
153 // OutputContext implementation
154
155 public SharedContext getSharedContext() {
156 return context;
157 }
158
159 public OutputStream getOutputStream() {
160 return outputStream;
161 }
162
163 public void addToStoredStrings(String s) {
164 if (s != null && !storedStrings.containsKey(s)) {
165 Integer index = Integer.valueOf(storedStrings.size());
166 storedStrings.put(s, index);
167 }
168 }
169
170 public int indexOfStoredStrings(String s) {
171 if (s != null) {
172 Integer index = storedStrings.get(s);
173 if (index != null)
174 return index.intValue();
175 }
176 return -1;
177 }
178
179 public void addToStoredObjects(Object o) {
180 if (o != null && !storedObjects.containsKey(o)) {
181 Integer index = Integer.valueOf(storedObjects.size());
182 storedObjects.put(o, index);
183 }
184 }
185
186 public int indexOfStoredObjects(Object o) {
187 if (o != null) {
188 Integer index = storedObjects.get(o);
189 if (index != null)
190 return index.intValue();
191 }
192 return -1;
193 }
194
195 ///////////////////////////////////////////////////////////////////////////
196 // ExtendedObjectOutput implementation
197
198 public Reflection getReflection() {
199 return context.getReflection();
200 }
201
202 public String getAlias(String className) {
203 return context.getAlias(className);
204 }
205
206 public void getAndWriteField(Object obj, Field field) throws IOException, IllegalAccessException {
207 if (field.getType().isPrimitive())
208 codecRegistry.getPrimitiveFieldCodec(field.getType()).encodePrimitive(this, obj, field);
209 else
210 writeObject(field.get(obj));
211 }
212 }