All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.zeno.genericobject.DiffHtmlGenerator Maven / Gradle / Ivy

/*
 *
 *  Copyright 2013 Netflix, Inc.
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 *
 */
package com.netflix.zeno.genericobject;

import com.netflix.zeno.genericobject.GenericObject.CollectionType;
import com.netflix.zeno.genericobject.GenericObject.Field;
import com.netflix.zeno.serializer.SerializerFactory;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * This class generates HTML describing the differences between two GenericObjects.
 *
 * @author dkoszewnik
 *
 */
/*
 * This is extremely messy code and is ripe for replacement.
 *
 * It is the result of an afternoon spike several months ago and has not yet needed any updates.
 */
public class DiffHtmlGenerator {

    private final DiffHtmlCollectionLocker locker;
    private final GenericObjectSerializationFramework genericObjectFramework;

    private final boolean moreAtFromLevels[] = new boolean[1024];
    private final boolean moreAtToLevels[] = new boolean[1024];

    private int hierarchyLevel = 1;

    /**
     * Instantiate with the SerializerFactory describing an object model.
     */
    public DiffHtmlGenerator(SerializerFactory factory) {
        locker = new DiffHtmlCollectionLocker(factory);
        genericObjectFramework = new GenericObjectSerializationFramework(factory);
    }

    /**
     * Generate the HTML difference between two objects.
     *
     * @param objectType - The NFTypeSerializer name of the objects
     * @param from - The first object to diff
     * @param to - The second object to diff
     * @return
     */
    public String generateDiff(String objectType, Object from, Object to) {
        GenericObject fromGenericObject = from == null ? null : genericObjectFramework.serialize(from, objectType);
        GenericObject toGenericObject = to == null ? null : genericObjectFramework.serialize(to, objectType);

        return generateDiff(fromGenericObject, toGenericObject);
    }

    /**
     * Generate the HTML difference between two GenericObjects.
     *
     * @return
     */
    public String generateDiff(GenericObject from, GenericObject to) {
        StringBuilder builder = new StringBuilder();

        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");
        builder.append("");

        builder.append("");

        writeDiff(builder, from, to);

        builder.append("");
        builder.append("
"); builder.append("From"); builder.append("To
"); return builder.toString(); } private void writeDiff(StringBuilder builder, GenericObject from, GenericObject to) { if(from != null && to != null) { writeDiffBothObjectsPresent(builder, from, to); } else if(from != null || to != null) { writeDiffOneObjectNull(builder, from, to); } } private void writeDiffBothObjectsPresent(StringBuilder builder, GenericObject from, GenericObject to) { if(from.getCollectionType() == CollectionType.COLLECTION) { writeCollectionDiff(builder, from, to); } else if(from.getCollectionType() == CollectionType.MAP) { writeMapDiff(builder, from, to); } else { writeObjectDiff(builder, from, to); } } private void writeCollectionDiff(StringBuilder builder, GenericObject from, GenericObject to) { locker.lockCollectionFields(from, to); /// both objects' fields length should be the same after the lockCollectionFields operation for(int i=0;i fieldList, int position) { if(position >= fieldList.size()) return false; for(int i=position+1;i"); if(fromField != null && fromField.getCollectionPosition() != 0) builder.append("").append(fromField.getCollectionPosition()).append(""); else builder.append(""); builder.append(""); if(fromField != null) { if(nonNullValue instanceof GenericObject) { openNewObject(builder, fromField.getFieldName(), ((GenericObject) nonNullValue).getObjectType(), moreAtFromLevel, true); } else { appendFieldValue(builder, fromField.getFieldName(), fromField.getValue(), moreAtFromLevel, true); } } else { appendEmptyHierarchyLevel(builder, moreAtFromLevels); } builder.append(""); if(toField != null && toField.getCollectionPosition() != 0) builder.append("").append(toField.getCollectionPosition()).append(""); else builder.append(""); builder.append(""); if(toField != null) { if(nonNullValue instanceof GenericObject) { openNewObject(builder, toField.getFieldName(), ((GenericObject) nonNullValue).getObjectType(), moreAtToLevel, false); } else { appendFieldValue(builder, toField.getFieldName(), toField.getValue(), moreAtToLevel, false); } } else { appendEmptyHierarchyLevel(builder, moreAtToLevels); } builder.append(""); builder.append(""); if(nonNullValue instanceof GenericObject) { hierarchyLevel++; writeDiff(builder, (GenericObject)fieldValue(fromField), (GenericObject)fieldValue(toField)); hierarchyLevel--; } moreAtFromLevels[hierarchyLevel] = false; moreAtToLevels[hierarchyLevel] = false; } private Object fieldValue(Field field) { if(field == null) return null; return field.getValue(); } private Object getNonNullValue(Field fromField, Field toField) { if(fromField != null && fromField.getValue() != null) return fromField.getValue(); if(toField != null) return toField.getValue(); return null; } private void openNewObject(StringBuilder builder, String fieldName, String typeName, boolean lastFieldAtLevel, boolean from) { appendHierarchyLevel(builder, true, hierarchyLevel, lastFieldAtLevel, from); builder.append(fieldName).append(": ").append("(").append(typeName).append(")\n"); } private String cssClass(Field field1, Field field2, String missingCssClass) { if(field1 == null) return "empty"; if(field2 == null) return missingCssClass; if(field1.getValue() == null && field2.getValue() != null) return "replace"; if(field1.getValue() == null && field2.getValue() == null) return "equal"; if(field1.getValue() != null && field2.getValue() == null) return "replace"; if(!(field1.getValue() instanceof GenericObject)) { if(!field1.getValue().equals(field2.getValue())) return "replace"; } return "equal"; } private void appendFieldValue(StringBuilder builder, String fieldName, Object value, boolean moreFieldsAtLevel, boolean from) { appendHierarchyLevel(builder, false, hierarchyLevel, moreFieldsAtLevel, from); builder.append(fieldName).append(": ").append(value).append("\n"); } private void appendHierarchyLevel(StringBuilder builder, boolean objectField, int hierarchyLevel, boolean moreFieldsAtLevel, boolean from) { boolean levelGuide[] = from ? moreAtFromLevels : moreAtToLevels; for(int i=1;i"); else builder.append(".┕━┯━>"); } else { if(moreFieldsAtLevel) builder.append(".├───>"); else builder.append(".└───>"); } } private void appendEmptyHierarchyLevel(StringBuilder builder, boolean[] levelGuide) { for(int i=1;i<=hierarchyLevel;i++) { if(levelGuide[i]) { builder.append(" │"); } else { for(int j=i;j<=hierarchyLevel;j++) { if(levelGuide[j]) { builder.append(" "); break; } } } } } private static final Comparator mapFieldComparator = new Comparator() { @SuppressWarnings({ "unchecked", "rawtypes" }) public int compare(Field o1, Field o2) { if(o1 == null && o2 == null) return 0; if(o1 == null) return 1; if(o2 == null) return -1; Object key1 = getKey(o1); Object key2 = getKey(o2); if(key1 instanceof Comparable) { return ((Comparable) key1).compareTo(key2); } return key1.hashCode() - key2.hashCode(); } }; private static Object getKey(Field entryField) { GenericObject entryObject = (GenericObject) entryField.getValue(); Field keyField = entryObject.getFields().get(0); GenericObject keyObject = (GenericObject)keyField.getValue(); return keyObject.getActualObject(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy