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

org.glassfish.hk2.xml.internal.Differences Maven / Gradle / Ivy

There is a newer version: 4.0.0-M3
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2016-2017 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.hk2.xml.internal;

import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.glassfish.hk2.xml.jaxb.internal.BaseHK2JAXBBean;

/**
 * @author jwells
 *
 */
public class Differences {
    private Map differences = new LinkedHashMap();
    
    public void addDifference(Difference difference) {
        DifferenceKey addedKey = new DifferenceKey(difference.getSource());
        
        Difference existingDifference = differences.get(addedKey);
        if (existingDifference == null) {
            differences.put(addedKey, difference);
        }
        else {
            existingDifference.merge(difference);
        }
    }
    
    public List getDifferences() {
        return new ArrayList(differences.values());
    }
    
    public int getDifferenceCost() {
        int retVal = 0;
        
        for (Difference d : differences.values()) {
            retVal += d.getSize();
        }
        
        return retVal;
    }
    
    public void merge(Differences diffs) {
        for (Difference diff : diffs.getDifferences()) {
          addDifference(diff);
        }
    }
    
    public static class Difference {
        private final BaseHK2JAXBBean source;
        private final List nonChildChanges = new LinkedList();
        
        private final Map childChanges = new LinkedHashMap();
        
        public Difference(BaseHK2JAXBBean source) {
            this.source = source;
        }
        
        public BaseHK2JAXBBean getSource() {
            return source;
        }
        
        public void addNonChildChange(PropertyChangeEvent evt) {
            nonChildChanges.add(evt);
        }
        
        public List getNonChildChanges() {
            return nonChildChanges;
        }
        
        public Map getChildChanges() {
            return childChanges;
        }
        
        private AddRemoveMoveDifference getARMDiff(String propName) {
            AddRemoveMoveDifference field = childChanges.get(propName);
            if (field == null) {
                field = new AddRemoveMoveDifference();
                
                childChanges.put(propName, field);
            }
            
            return field;
        }
        
        public void addAdd(String propName, AddData toAdd) {
            AddRemoveMoveDifference arm = getARMDiff(propName);
            arm.addAdd(toAdd);
        }
        
        public void addAdd(String propName, BaseHK2JAXBBean toAdd, int index) {
            addAdd(propName, new AddData(toAdd, index));
        }
        
        public void addMove(String propName, MoveData md) {
            AddRemoveMoveDifference arm = getARMDiff(propName);
            arm.addMove(md);
        }
        
        public void addRemove(String propName, RemoveData removeData) {
            AddRemoveMoveDifference arm = getARMDiff(propName);
            arm.addRemove(removeData);
        }
        
        private void merge(Difference mergeMe) {
            for (PropertyChangeEvent pce : mergeMe.getNonChildChanges()) {
                addNonChildChange(pce);
            }
            
            Map childChanges = mergeMe.getChildChanges();
            for (Map.Entry childEntry : childChanges.entrySet()) {
                String propertyName = childEntry.getKey();
                AddRemoveMoveDifference arm = childEntry.getValue();
                
                for (AddData add : arm.getAdds()) {
                    addAdd(propertyName, new AddData(add));
                }
                
                for (RemoveData remove : arm.getRemoves()) {
                    addRemove(propertyName, new RemoveData(remove));
                }
                
                for (MoveData move : arm.getMoves()) {
                    addMove(propertyName, new MoveData(move));
                }
                
            }
        }
        
        public boolean isDirty() {
            return !nonChildChanges.isEmpty() || !childChanges.isEmpty();
        }
        
        public boolean hasChildChanges() {
            return !childChanges.isEmpty();
        }
        
        public int getSize() {
            int retVal = nonChildChanges.size();
            
            retVal += childChanges.size();
            
            return retVal;
        }
        
        @Override
        public String toString() {
            return "Difference(" + source + "," + System.identityHashCode(this) + ")";
        }
    }
    
    public static class AddRemoveMoveDifference {
        private final List adds = new ArrayList();
        private final List removes = new ArrayList();
        private final List moves = new ArrayList();
        
        private void addAdd(AddData add) {
            adds.add(add);
        }
        
        private void addRemove(RemoveData remove) {
            removes.add(remove);
        }
        
        private void addMove(MoveData move) {
            moves.add(move);
        }
        
        public List getAdds() {
            return adds;
        }
        
        public List getRemoves() {
            return removes;
        }
        
        public List getMoves() {
            return moves;
        }
        
        public boolean requiresListChange() {
            return !adds.isEmpty() || !removes.isEmpty() || !moves.isEmpty();
        }
        
        public int getSize() {
            return adds.size() + removes.size() + moves.size();
        }
        
        public int getNewSize(int oldSize) {
            return oldSize - removes.size() + adds.size();
        }
    }
    
    public static class AddData {
        private final BaseHK2JAXBBean toAdd;
        private final int index;
        
        public AddData(BaseHK2JAXBBean toAdd, int index) {
            this.toAdd = toAdd;
            this.index = index;
        }
        
        private AddData(BaseHK2JAXBBean toAdd) {
            this(toAdd, -1);
        }
        
        public AddData(AddData copyMe) {
            this.toAdd = copyMe.toAdd;
            this.index = copyMe.index;
        }
        
        public BaseHK2JAXBBean getToAdd() { return toAdd; }
        public int getIndex() { return index; }
    }
    
    public static class RemoveData {
        private final String childProperty;
        private final String childKey;
        private final int index;
        private final BaseHK2JAXBBean child;
        
        public RemoveData(String childProperty, BaseHK2JAXBBean child) {
            this(childProperty, null, -1, child);
        }
        
        public RemoveData(String childProperty, String childKey, BaseHK2JAXBBean child) {
            this(childProperty, childKey, -1, child);
        }
        
        public RemoveData(String childProperty, int index, BaseHK2JAXBBean child) {
            this(childProperty, null, index, child);
        }
        
        public RemoveData(RemoveData copyMe) {
            this(copyMe.childProperty, copyMe.childKey, copyMe.index, copyMe.child);
        }
        
        private RemoveData (String childProperty,
                String childKey,
                int index,
                BaseHK2JAXBBean child) {
            this.childProperty = childProperty;
            this.childKey = childKey;
            this.index = index;
            this.child = child;
        }
        
        /**
         * @return the childProperty
         */
        public String getChildProperty() {
            return childProperty;
        }
        /**
         * @return the childKey
         */
        public String getChildKey() {
            return childKey;
        }
        /**
         * @return the index
         */
        public int getIndex() {
            return index;
        }
        /**
         * @return the child
         */
        public BaseHK2JAXBBean getChild() {
            return child;
        }
        
    }
    
    public static class MoveData {
        private final int oldIndex;
        private final int newIndex;
        
        public MoveData(int oldIndex, int newIndex) {
            this.oldIndex = oldIndex;
            this.newIndex = newIndex;
        }
        
        public MoveData(MoveData copyMe) {
            this(copyMe.oldIndex, copyMe.newIndex);
        }
        
        public int getOldIndex() { return oldIndex; }
        public int getNewIndex() { return newIndex; }
    }

    /**
     * Prints very pretty version of modifications
     */
    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("Differences(num=" + differences.size() + ",cost=" + getDifferenceCost() + "\n");
        
        int lcv = 1;
        for (Difference d : differences.values()) {
            BaseHK2JAXBBean source = d.getSource();
            
            String xmlPath = source._getXmlPath();
            String instanceName = source._getInstanceName();
            
            List events = d.getNonChildChanges();
            sb.append(lcv + ". Modified Bean sourcePath=" + xmlPath + " sourceInstance=" + instanceName + "\n");
            
            for (PropertyChangeEvent event : events) {
                sb.append("\tCHANGED: " + event.getPropertyName() + " from " + event.getOldValue() + " to " + event.getNewValue() + "\n");
            }
            
            Map childChanges = d.getChildChanges();
            
            for (Map.Entry childEntry : childChanges.entrySet()) {
                String propertyName = childEntry.getKey();
                
                sb.append("  CHANGED CHILD: " + propertyName + "\n");
                AddRemoveMoveDifference arm = childEntry.getValue();
                
                for (AddData ad : arm.getAdds()) {
                    BaseHK2JAXBBean added = ad.getToAdd();
                    int index = ad.getIndex();
                    
                    String addedXmlPath = added._getXmlPath();
                    String addedInstanceName = added._getInstanceName();
                    
                    sb.append("    ADDED: addedPath=" + addedXmlPath + " addedInstanceName=" + addedInstanceName + " addedIndex=" + index + "\n");
                }
                
                for (RemoveData rd : arm.getRemoves()) {
                    String removedXmlPath = rd.getChild()._getXmlPath();
                    String removedInstanceName = rd.getChild()._getInstanceName();
                    
                    sb.append("    REMOVED: removedPath=" + removedXmlPath + " removedInstanceName=" + removedInstanceName + "\n");
                }
                
                for (MoveData md : arm.getMoves()) {
                    sb.append("    MOVED: oldIndex=" + md.getOldIndex() + " newIndex=" + md.getNewIndex() + "\n");
                }
            }
            
            lcv++;
        }
        
        return sb.toString() + "\n," + System.identityHashCode(this) + ")";
    }
    
    private static class DifferenceKey {
        private final String xmlPath;
        private final String instanceName;
        private final int hash;
        
        private DifferenceKey(BaseHK2JAXBBean bean) {
            xmlPath = bean._getXmlPath();
            instanceName = bean._getInstanceName();
            
            hash = xmlPath.hashCode() ^ instanceName.hashCode();
        }
        
        @Override
        public int hashCode() {
            return hash;
        }
        
        @Override
        public boolean equals(Object o) {
            if (o == null) return false;
            if (!(o instanceof DifferenceKey)) return false;
            
            DifferenceKey other = (DifferenceKey) o;
            
            return xmlPath.equals(other.xmlPath) && instanceName.equals(other.instanceName) ;
        }
        
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy