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.utils;
018
019import java.io.IOException;
020import java.util.ArrayList;
021import java.util.HashSet;
022import java.util.List;
023
024import org.conqat.lib.commons.assertion.CCSMAssert;
025import org.conqat.lib.commons.io.SerializationUtils;
026import org.conqat.lib.commons.serialization.SerializedEntityBase;
027import org.conqat.lib.commons.serialization.SerializedEntityPool;
028import org.conqat.lib.commons.serialization.SerializedEntitySerializer;
029import org.conqat.lib.commons.serialization.classes.SerializedClass;
030import org.conqat.lib.commons.serialization.objects.SerializedClassValues;
031import org.conqat.lib.commons.serialization.objects.SerializedObject;
032import org.conqat.lib.commons.serialization.objects.SerializedStringObject;
033
034/**
035 * Utility methods for migrating serialized objects.
036 */
037public class SerializationMigrationUtils {
038
039        /** Transforms all strings in a (de)serialized string set. */
040        public static void transformStringsInHashSet(SerializedObject setObject, IStringTransformation transformation,
041                        SerializedEntityPool pool) throws IOException {
042
043                SerializedClass setClass = findClassInHierarchy(setObject, HashSet.class);
044
045                SerializedClassValues fieldSets = setObject.getFieldSet(setObject.getPlainClassHierarchy().indexOf(setClass));
046
047                for (Object data : fieldSets.getPreFieldData()) {
048                        if (!(data instanceof Integer)) {
049                                continue;
050                        }
051
052                        SerializedEntityBase containedElement = pool.getEntity((Integer) data, SerializedEntityBase.class);
053                        if (containedElement instanceof SerializedStringObject) {
054                                SerializedStringObject stringContent = (SerializedStringObject) containedElement;
055                                stringContent.setValue(transformation.transform(stringContent.getValue()));
056                        }
057                }
058        }
059
060        /** Returns all objects in a (de)serialized {@link ArrayList}. */
061        @SuppressWarnings("unchecked")
062        public static <T extends SerializedEntityBase> List<T> getObjectsFromArrayList(SerializedObject setObject,
063                        SerializedEntityPool pool) throws IOException {
064
065                SerializedClass setClass = findClassInHierarchy(setObject, ArrayList.class);
066
067                SerializedClassValues fieldSets = setObject.getFieldSet(setObject.getPlainClassHierarchy().indexOf(setClass));
068                List<T> objects = new ArrayList<>();
069                for (Object data : fieldSets.getPostFieldData()) {
070                        if (!(data instanceof Integer)) {
071                                continue;
072                        }
073                        SerializedEntityBase containedElement = pool.getEntity((Integer) data, SerializedEntityBase.class);
074                        objects.add((T) containedElement);
075                }
076                return objects;
077        }
078
079        /**
080         * Tries to find a given class in the {@link SerializedObject}'s classHierarchy
081         */
082        public static SerializedClass findClassInHierarchy(SerializedObject setObject, Class<?> classToFind)
083                        throws IOException {
084                for (SerializedClass classObject : setObject.getPlainClassHierarchy()) {
085                        if (classToFind.getName().equals(classObject.getName())) {
086                                return classObject;
087                        }
088                }
089                CCSMAssert.fail("Only works on " + classToFind.getName() + " objects!");
090                return null;
091        }
092
093        /**
094         * Renames the given entity class, reads it from the pool and returns it. The
095         * given class must be a root entity in the pool.
096         */
097        @SuppressWarnings("unchecked")
098        public static <T> T serializeRootEntities(SerializedEntityPool entityPool)
099                        throws AssertionError, IOException, ClassNotFoundException {
100                List<SerializedEntityBase> rootEntities = entityPool.getRootEntities();
101                byte[] newValue = SerializedEntitySerializer.serializeToBytes(rootEntities);
102                return (T) SerializationUtils.deserializeFromByteArray(newValue,
103                                Thread.currentThread().getContextClassLoader());
104        }
105
106        /** Interface for transforming strings. */
107        public interface IStringTransformation {
108
109                /** Transforms a single string. */
110                String transform(String input);
111        }
112
113        /** Deletes a single field from a class. */
114        public static void deleteField(SerializedEntityPool pool, String className, String fieldName) throws IOException {
115                SerializedClass migratedClass = pool.findClass(className);
116                if (migratedClass == null) {
117                        return;
118                }
119                for (SerializedObject object : pool.getRootEntities(SerializedObject.class)) {
120                        if (object.getClassHandle() == migratedClass.getHandle()) {
121                                object.removeFieldValue(fieldName);
122                        }
123                }
124                migratedClass.removeField(fieldName);
125        }
126
127}