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.codec.std.impl;
022    
023    import java.io.IOException;
024    import java.io.OutputStream;
025    
026    import org.granite.messaging.jmf.CodecRegistry;
027    import org.granite.messaging.jmf.DumpContext;
028    import org.granite.messaging.jmf.InputContext;
029    import org.granite.messaging.jmf.OutputContext;
030    import org.granite.messaging.jmf.codec.std.EnumCodec;
031    
032    /**
033     * @author Franck WOLFF
034     */
035    public class EnumCodecImpl extends AbstractIntegerStringCodec<Object> implements EnumCodec {
036    
037            protected static final StringTypeHandler TYPE_HANDLER = new StringTypeHandler() {
038    
039                    public int type(IntegerComponents ics, boolean reference) {
040                            return (reference ? (0x40 | (ics.length << 4) | JMF_ENUM) : ((ics.length << 4) | JMF_ENUM));
041                    }
042    
043                    public int indexOrLengthBytesCount(int parameterizedJmfType) {
044                            return (parameterizedJmfType >> 4) & 0x03;
045                    }
046    
047                    public boolean isReference(int parameterizedJmfType) {
048                            return (parameterizedJmfType & 0x40) != 0;
049                    }
050            };
051    
052            public int getObjectType() {
053                    return JMF_ENUM;
054            }
055    
056            public boolean canEncode(Object v) {
057                    return v.getClass().isEnum();
058            }
059    
060            public void encode(OutputContext ctx, Object v) throws IOException {
061                    final OutputStream os = ctx.getOutputStream();
062                    
063                    int indexOfStoredObject = ctx.indexOfStoredObjects(v);
064                    if (indexOfStoredObject >= 0) {
065                            IntegerComponents ics = intComponents(indexOfStoredObject);
066                            os.write(0x80 | (ics.length << 4) | JMF_ENUM);
067                            writeIntData(ctx, ics);
068                    }
069                    else {
070                            ctx.addToStoredObjects(v);
071                            
072                            String className = ctx.getAlias(v.getClass().getName());
073                            writeString(ctx, className, TYPE_HANDLER);
074                            
075                            int ordinal = ((Enum<?>)v).ordinal();
076                            ctx.getSharedContext().getCodecRegistry().getIntegerCodec().writeVariableInt(ctx, ordinal);
077                    }
078            }
079    
080            public Object decode(InputContext ctx, int parameterizedJmfType) throws IOException, ClassNotFoundException {
081                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
082                    
083                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
084                    
085                    if (jmfType != JMF_ENUM)
086                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
087                    
088                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 4) & 0x03, false);
089                    
090                    Object v = null;
091                    if ((parameterizedJmfType & 0x80) != 0)
092                            v = ctx.getSharedObject(indexOrLength);
093                    else {
094                            String className = readString(ctx, parameterizedJmfType, indexOrLength, TYPE_HANDLER);
095                            className = ctx.getAlias(className);
096                            Class<?> cls = ctx.getSharedContext().getReflection().loadClass(className);
097                            
098                            int ordinal = codecRegistry.getIntegerCodec().readVariableInt(ctx);
099                            
100                            v = cls.getEnumConstants()[ordinal];
101                            ctx.addSharedObject(v);
102                    }
103                    
104                    return v;
105            }
106    
107            public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
108                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
109                    
110                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
111                    
112                    if (jmfType != JMF_ENUM)
113                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
114                    
115                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 4) & 0x03, false);
116                    if ((parameterizedJmfType & 0x80) != 0) {
117                            String className = (String)ctx.getSharedObject(indexOrLength);
118                            ctx.indentPrintLn("<" + className + "@" + indexOrLength + ">");
119                    }
120                    else {
121                            String className = readString(ctx, parameterizedJmfType, indexOrLength, TYPE_HANDLER);
122                            className = ctx.getAlias(className);
123                            int ordinal = codecRegistry.getIntegerCodec().readVariableInt(ctx);
124                            
125                            int indexOfStoredObject = ctx.addSharedObject(className);
126                            ctx.indentPrintLn(className + "@" + indexOfStoredObject + ": <" + ordinal + ">");
127                    }
128            }
129    }