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