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