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    }