001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.serialization.classes;
018
019import java.io.DataInputStream;
020import java.io.DataOutputStream;
021import java.io.IOException;
022import java.io.ObjectStreamConstants;
023import java.util.ArrayList;
024import java.util.List;
025
026import org.conqat.lib.commons.serialization.SerializedEntityBase;
027import org.conqat.lib.commons.serialization.SerializedEntityParser;
028import org.conqat.lib.commons.serialization.SerializedEntityPool;
029import org.conqat.lib.commons.serialization.SerializedEntitySerializer;
030
031/**
032 * Base class for all serialized classes.
033 */
034public abstract class SerializedClassBase extends SerializedEntityBase {
035
036        /** Handle to the super class (or null handle). */
037        protected int superClassHandle = SerializedEntityPool.NULL_HANDLE;
038
039        /**
040         * Class annotations. These are either byte arrays for block data, or integer
041         * values representing handles.
042         */
043        private final List<Object> classAnnotations = new ArrayList<>();
044
045        /** Constructor for parsing. */
046        protected SerializedClassBase(DataInputStream din, SerializedEntityPool pool, SerializedEntityParser parser)
047                        throws IOException {
048                super(pool);
049
050                parseClass(din, pool, parser);
051
052                readClassAnnotation(din, parser);
053                readSuperClassDescription(parser);
054        }
055
056        /** Direct constructor. */
057        protected SerializedClassBase(SerializedEntityPool pool) {
058                super(pool);
059        }
060
061        /**
062         * Parses the class content. This is called from the constructor, so fields of
063         * sub classes might not be initialized.
064         */
065        protected abstract void parseClass(DataInputStream din, SerializedEntityPool pool, SerializedEntityParser parser)
066                        throws IOException;
067
068        /** Reads the description of the super class. */
069        private void readSuperClassDescription(SerializedEntityParser parser) throws IOException {
070                this.superClassHandle = parser.parseClassDesc();
071        }
072
073        /** Reads the <code>classAnnotation</code> part of a class description. */
074        private void readClassAnnotation(DataInputStream din, SerializedEntityParser parser) throws IOException {
075                while (true) {
076                        din.mark(1);
077
078                        byte next = din.readByte();
079                        switch (next) {
080                        case ObjectStreamConstants.TC_ENDBLOCKDATA:
081                                return;
082                        case ObjectStreamConstants.TC_BLOCKDATA:
083                                classAnnotations.add(readBlockData(din, din.readUnsignedByte()));
084                                break;
085                        case ObjectStreamConstants.TC_BLOCKDATALONG:
086                                classAnnotations.add(readBlockData(din, din.readInt()));
087                                break;
088                        default:
089                                din.reset();
090                                classAnnotations.add(parser.parseContent());
091                                break;
092                        }
093                }
094        }
095
096        /** Reads block data. */
097        private static byte[] readBlockData(DataInputStream din, int length) throws IOException {
098                byte[] result = new byte[length];
099                din.readFully(result);
100                return result;
101        }
102
103        /** {@inheritDoc} */
104        @Override
105        protected final void serializeContent(DataOutputStream dos, SerializedEntitySerializer serializer)
106                        throws IOException {
107                serializer.registerHandle(this);
108
109                serializeClass(dos, serializer);
110
111                serializeClassAnnotation(dos, serializer);
112                serializeSuperClass(dos, serializer);
113        }
114
115        /** Serializes the class part of this entity. */
116        protected abstract void serializeClass(DataOutputStream dos, SerializedEntitySerializer serializer)
117                        throws IOException;
118
119        /** Serializes the super class. */
120        private void serializeSuperClass(DataOutputStream dos, SerializedEntitySerializer serializer) throws IOException {
121                SerializedEntitySerializer.serializeObject(superClassHandle, SerializedClassBase.class, pool, dos, serializer);
122        }
123
124        /** Serializes the class annotation part. */
125        private void serializeClassAnnotation(DataOutputStream dos, SerializedEntitySerializer serializer)
126                        throws IOException {
127                serializer.serializeAnnotationList(classAnnotations, pool);
128
129                // end of class annotation always signaled via endBlockData
130                dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
131        }
132
133        /** Returns the handle of the super class. */
134        public int getSuperClassHandle() {
135                return superClassHandle;
136        }
137}