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    }