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.objects; 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.collections.Pair; 027import org.conqat.lib.commons.serialization.SerializedEntityParser; 028import org.conqat.lib.commons.serialization.SerializedEntityPool; 029import org.conqat.lib.commons.serialization.SerializedEntitySerializer; 030import org.conqat.lib.commons.serialization.classes.SerializedClass; 031import org.conqat.lib.commons.serialization.classes.SerializedClassBase; 032import org.conqat.lib.commons.serialization.classes.SerializedFieldBase; 033import org.conqat.lib.commons.string.StringUtils; 034 035/** 036 * A serialized object. 037 */ 038public class SerializedObject extends SerializedObjectBase { 039 040 /** 041 * The field values for this class organized as field sets. Each field set 042 * corresponds to one class in the class hierarchy (from sub class to super 043 * class). 044 */ 045 private final List<SerializedClassValues> fieldSets = new ArrayList<>(); 046 047 /** Constructor. */ 048 public SerializedObject(DataInputStream din, SerializedEntityPool pool, SerializedEntityParser parser, 049 int classHandle) throws IOException { 050 super(pool, classHandle); 051 052 for (SerializedClass serializedClass : getPlainClassHierarchy()) { 053 fieldSets.add(new SerializedClassValues(serializedClass, din, parser)); 054 } 055 } 056 057 /** Constructor. */ 058 public SerializedObject(int classHandle, List<SerializedClassValues> fieldSets, SerializedEntityPool pool) { 059 super(pool, classHandle); 060 this.fieldSets.addAll(fieldSets); 061 } 062 063 /** {@inheritDoc} */ 064 @Override 065 protected byte getObjectTagConstant() { 066 return ObjectStreamConstants.TC_OBJECT; 067 } 068 069 /** {@inheritDoc} */ 070 @Override 071 protected void serializeObjectContent(DataOutputStream dos, SerializedEntitySerializer serializer) 072 throws IOException { 073 int index = 0; 074 for (SerializedClass serializedClass : getPlainClassHierarchy()) { 075 SerializedClassValues fieldSet = fieldSets.get(index++); 076 fieldSet.serialize(serializedClass, pool, dos, serializer); 077 } 078 } 079 080 /** {@inheritDoc} */ 081 @Override 082 public String toString() { 083 StringBuilder builder = new StringBuilder(); 084 String className = "<unknown>"; 085 try { 086 className = pool.getEntity(classHandle, SerializedClassBase.class).toString(); 087 builder.append("Object " + getHandle() + ": " + className + StringUtils.LINE_SEPARATOR); 088 089 int index = 0; 090 for (SerializedClass serializedClass : getPlainClassHierarchy()) { 091 appendFieldSet(fieldSets.get(index++), serializedClass, builder); 092 } 093 } catch (IOException e) { 094 builder.append("Could not resolve hierarchy for class " + className + ": " + e.getMessage()); 095 } 096 return builder.toString(); 097 } 098 099 /** Appends the information on a field set to the given builder. */ 100 private static void appendFieldSet(SerializedClassValues fieldSet, SerializedClass serializedClass, 101 StringBuilder builder) { 102 if (fieldSet.hasFieldValues()) { 103 int fieldIndex = 0; 104 for (SerializedFieldBase field : serializedClass.getFields()) { 105 builder.append(" " + serializedClass.getName() + "#" + field.getName() + ": " 106 + fieldSet.getValue(fieldIndex++) + StringUtils.LINE_SEPARATOR); 107 } 108 } else { 109 builder.append(" " + serializedClass.getName() + ": <no data>"); 110 } 111 } 112 113 /** 114 * Return the value object for the field with the given name. 115 * 116 * @return The fields value or null if no field with the name was found 117 */ 118 public Object getFieldValue(String name) throws IOException { 119 Pair<SerializedClassValues, Integer> fieldSetAndValue = getFieldSetAndIndex(name); 120 if (fieldSetAndValue == null) { 121 return null; 122 } 123 return fieldSetAndValue.getFirst().getValue(fieldSetAndValue.getSecond()); 124 } 125 126 /** Sets the value object for the field with the given name. */ 127 public void setFieldValue(String name, Object value) throws IOException { 128 Pair<SerializedClassValues, Integer> fieldSetAndValue = getFieldSetAndIndex(name); 129 if (fieldSetAndValue != null) { 130 fieldSetAndValue.getFirst().setValue(fieldSetAndValue.getSecond(), value); 131 } 132 } 133 134 /** 135 * Removes the value object for the field with the given name. This does not 136 * only set the vlaue to 0 or null, but corresponds to a deletion of the field. 137 */ 138 public void removeFieldValue(String name) throws IOException { 139 Pair<SerializedClassValues, Integer> fieldSetAndValue = getFieldSetAndIndex(name); 140 if (fieldSetAndValue != null) { 141 fieldSetAndValue.getFirst().removeValue(fieldSetAndValue.getSecond()); 142 } 143 } 144 145 /** 146 * Returns the field set and index within this fieldset for a field with given 147 * name. Returns null if none is found. 148 */ 149 private Pair<SerializedClassValues, Integer> getFieldSetAndIndex(String fieldName) throws IOException { 150 int classIndex = 0; 151 for (SerializedClass serializedClass : getPlainClassHierarchy()) { 152 SerializedFieldBase field = serializedClass.getField(fieldName); 153 if (field != null) { 154 int index = serializedClass.getFields().indexOf(field); 155 SerializedClassValues fieldSet = fieldSets.get(classIndex); 156 return new Pair<>(fieldSet, index); 157 } 158 classIndex++; 159 } 160 return null; 161 } 162 163 /** Returns number of field sets. */ 164 public int getFieldSetCount() { 165 return fieldSets.size(); 166 } 167 168 /** Returns field sets of given index. */ 169 public SerializedClassValues getFieldSet(int index) { 170 return fieldSets.get(index); 171 } 172}