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 */
022package org.granite.messaging.jmf;
023
024import java.io.IOException;
025import java.io.OutputStream;
026import java.lang.reflect.InvocationTargetException;
027import java.util.HashMap;
028import java.util.IdentityHashMap;
029import java.util.Map;
030
031import org.granite.messaging.jmf.codec.StandardCodec;
032import org.granite.messaging.reflect.Property;
033import org.granite.messaging.reflect.Reflection;
034
035/**
036 * @author Franck WOLFF
037 */
038public 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}