001package arcommon.xml;
002
003import java.io.IOException;
004import java.io.ObjectOutputStream;
005import java.util.ArrayList;
006
007import arcommon.ReflectionUtil;
008import arcommon.StringUtil;
009import arcommon.xml.XmlSerializer.FieldData;
010
011public class XmlObjectOutputStream extends ObjectOutputStream {
012    private XmlSerializer xmlSerializer;
013    private Object object;
014    private Class<? extends Object> clazz;
015    private ArrayList<FieldData> fields;
016    private int level;
017    private boolean tagClosed;
018    private Class<?> specialHandlingClass;
019    private boolean specialHandlingAdded;
020    
021    private boolean fieldsWritten;
022    private String dataIndent;
023    
024    protected XmlObjectOutputStream(XmlSerializer pxmlSerializer, Object pobject, Class<? extends Object> pclazz, ArrayList<FieldData> pfields, int plevel, boolean ptagClosed, Class<?> pspecialHandlingClass) throws IOException, SecurityException {
025        xmlSerializer = pxmlSerializer;
026        object = pobject;
027        clazz = pclazz;
028        fields = pfields;
029        level = plevel;
030        tagClosed = ptagClosed;
031        specialHandlingClass = pspecialHandlingClass;
032    }
033    
034    private String getCloseTagString() {
035        String result = "";
036        if (!tagClosed) {
037            tagClosed = true;
038            result += ">\n";
039        }
040        
041        if (!specialHandlingAdded) {
042            specialHandlingAdded = true;
043            String indent = StringUtil.stringWithNumberOfChar((level + 1) * 4, ' ');
044            result += indent + "<" + XmlSerializerHelperUtil.TAG_SPECIAL_HANDLING;
045            result += " " + XmlSerializerHelperUtil.ATTRIBUTE_CLASS + "=\"";
046            result += ReflectionUtil.classToClassNameInJavaSyntax(specialHandlingClass);
047            result += "\">\n";
048        }
049        
050        return result;
051    }
052
053    public String completeOutput() {
054        if (!tagClosed) {
055            return null;
056        }
057        
058        if (specialHandlingAdded) {
059            String indent = StringUtil.stringWithNumberOfChar((level + 1) * 4, ' ');
060            return indent + "</" + XmlSerializerHelperUtil.TAG_SPECIAL_HANDLING + ">\n";
061        }
062        
063        return null;
064    }
065    
066    public void defaultWriteObject() throws IOException {
067        if (fieldsWritten) {
068            throw new RuntimeException("Fields have already been written");
069        }
070        fieldsWritten = true;
071        String closeTagString = getCloseTagString();
072        try {
073            tagClosed = xmlSerializer.addFieldsToOutput(object, clazz, fields, level + 1, closeTagString.length() == 0, closeTagString);
074            if (!tagClosed) {
075                specialHandlingAdded = false;
076            }
077        } catch (IllegalArgumentException e) {
078            throw new RuntimeException(e);
079        } catch (SecurityException e) {
080            throw new RuntimeException(e);
081        } catch (IllegalAccessException e) {
082            throw new RuntimeException(e);
083        }
084    }
085
086    private void writeData(Class<?> c, Object value) {
087        boolean reference = false;
088        if (c != null && XmlSerializerHelperUtil.shouldClassHaveAnId(c)) {
089            if (xmlSerializer.objectMapContains(value)) {
090                reference = true;
091            } else {
092                xmlSerializer.giveIdsToObject(c, value);
093            }
094        }
095        if (dataIndent == null) {
096            dataIndent = StringUtil.stringWithNumberOfChar((level + 2) * 4, ' ');
097        }
098        xmlSerializer.addToOutput(getCloseTagString());
099        xmlSerializer.addToOutput(dataIndent + "<" + XmlSerializerHelperUtil.TAG_DATA);
100        if (value == null) {
101            xmlSerializer.addToOutput(" ");
102            xmlSerializer.addToOutput(XmlSerializerHelperUtil.ATTRIBUTE_DATA_OBJECT_IS_NULL);
103            xmlSerializer.addToOutput("=\"");
104            xmlSerializer.addToOutput(XmlSerializerHelperUtil.ATTRIBUTE_VALUE_TRUE);
105            xmlSerializer.addToOutput("\" />\n");
106        } else if (reference) {
107            xmlSerializer.addToOutput(" ");
108            xmlSerializer.addToOutput(XmlSerializerHelperUtil.ATTRIBUTE_REFERENCE);
109            xmlSerializer.addToOutput("=\"");
110            int id = xmlSerializer.objectMapGetId(value);
111            xmlSerializer.addToOutput("" + id);
112            xmlSerializer.addToOutput("\" />\n");
113        } else if (XmlSerializerHelperUtil.isSimpleClass(c)) {
114            xmlSerializer.addClassLengthValueAndId(c, value);
115            xmlSerializer.addToOutput(" />\n");
116        } else {
117            xmlSerializer.addToOutput(">\n");
118            try {
119                xmlSerializer.addObjectToOutput(value, level + 3);
120                xmlSerializer.addToOutput(dataIndent + "</" + XmlSerializerHelperUtil.TAG_DATA + ">\n");
121            } catch (Exception e) {
122                throw new RuntimeException(e);
123            }
124        }
125    }
126
127    public void write(byte[] bytes) throws IOException {
128        writeData(byte[].class, bytes);
129    }
130
131    public void write(byte[] b, int offset, int length) throws IOException {
132        byte[] bytes = new byte[length];
133        System.arraycopy(b, offset, bytes, 0, length);
134        writeData(byte[].class, bytes);
135    }
136
137    public void write(int b) throws IOException {
138        writeData(byte.class, b);
139    }
140
141    public void writeInt(int i) throws IOException {
142        writeData(int.class, i);
143    }
144
145    public void writeChar(int c) throws IOException {
146        writeData(char.class, (char)c);
147    }
148
149    public void writeBytes(String p0) throws IOException {
150        throw new RuntimeException("Not implemented");
151    }
152
153    public void writeByte(int b) throws IOException {
154        writeData(byte.class, b);
155    }
156
157    public void writeLong(long l) throws IOException {
158        writeData(long.class, l);
159    }
160
161    public void writeShort(int s) throws IOException {
162        writeData(short.class, s);
163    }
164
165    public void writeUTF(String s) throws IOException {
166        writeData(String.class, s);
167    }
168
169    public void writeFloat(float f) throws IOException {
170        writeData(float.class, f);
171    }
172
173    public void writeBoolean(boolean b) throws IOException {
174        writeData(boolean.class, b);
175    }
176
177    public void writeChars(String s) throws IOException {
178        writeData(String.class, s);
179    }
180
181    public void writeDouble(double d) throws IOException {
182        writeData(double.class, d);
183    }
184    
185    public void writeFields() throws IOException {
186        throw new RuntimeException("Not implemented");
187    }
188
189    public PutField putFields() throws IOException {
190        throw new RuntimeException("Not implemented");
191    }
192
193    public void close() throws IOException {
194        throw new RuntimeException("Not implemented");
195    }
196
197    public void flush() throws IOException {
198        throw new RuntimeException("Not implemented");
199    }
200
201    public void useProtocolVersion(int p0) throws IOException {
202        throw new RuntimeException("Not implemented");
203    }
204
205    public void reset() throws IOException {
206        throw new RuntimeException("Not implemented");
207    }
208
209    public void writeUnshared(Object p0) throws IOException {
210        throw new RuntimeException("Not implemented");
211    }
212    
213    @Override
214    protected void writeObjectOverride(Object o) throws IOException {
215        if (o == null) {
216            writeData(null, null);
217        } else {
218            writeData(o.getClass(), o);
219        }
220    }
221}