Ignore:
Timestamp:
03/18/13 11:43:33 (12 years ago)
Author:
pharms
Message:
  • changed implementation for equality management so that GUI elements as well as their equality relationships are serializable
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElement.java

    r1115 r1121  
    1515package de.ugoe.cs.autoquest.eventcore.guimodel; 
    1616 
    17 import java.util.IdentityHashMap; 
    1817import java.util.LinkedList; 
    1918import java.util.List; 
     
    3837    /** 
    3938     * <p> 
    40      * The reference to equal GUI element manager (needed to preserve singleton behavior, even 
    41      * though the objects are not singleton). 
    42      * </p> 
    43      */ 
    44     private static final EqualGUIElementManager equalGUIElementManager = 
    45         new EqualGUIElementManager(); 
    46  
    47     /** 
    48      * <p> 
    4939     * Specification of the GUI element 
    5040     * </p> 
     
    5848     */ 
    5949    private final IGUIElement parent; 
     50     
     51    /** 
     52     * <p> 
     53     * List of other GUI elements being equal to this 
     54     * </p> 
     55     */ 
     56    private List<AbstractDefaultGUIElement> equalGUIElements = null; 
    6057     
    6158    /** 
     
    109106    @Override 
    110107    public void addEqualGUIElement(IGUIElement equalElement) { 
    111         equalGUIElementManager.addEqualGUIElements(this, equalElement); 
     108        if (!(equalElement instanceof AbstractDefaultGUIElement)) { 
     109            throw new IllegalArgumentException 
     110                ("this implementation can only handle other AbstractDefaultGUIElements"); 
     111        } 
     112         
     113        AbstractDefaultGUIElement other = (AbstractDefaultGUIElement) equalElement; 
     114         
     115        synchronized (AbstractDefaultGUIElement.class) { 
     116            if (this.equalGUIElements == null) { 
     117                if (other.equalGUIElements == null) { 
     118                    this.equalGUIElements = new LinkedList<AbstractDefaultGUIElement>(); 
     119                    this.equalGUIElements.add(this); 
     120                    this.equalGUIElements.add(other); 
     121                    other.equalGUIElements = this.equalGUIElements; 
     122                } 
     123                else { 
     124                    addIfNotContained(other.equalGUIElements, this); 
     125                    this.equalGUIElements = other.equalGUIElements; 
     126                } 
     127            } 
     128            else { 
     129                if (other.equalGUIElements == null) { 
     130                    addIfNotContained(this.equalGUIElements, other); 
     131                    other.equalGUIElements = this.equalGUIElements; 
     132                } 
     133                else if (this.equalGUIElements != other.equalGUIElements) { 
     134                    this.equalGUIElements.addAll(other.equalGUIElements); 
     135 
     136                    // we also have to set this new list for all other elements for which so 
     137                    // far list2 was registered 
     138                    for (AbstractDefaultGUIElement candidate : other.equalGUIElements) { 
     139                        candidate.equalGUIElements = this.equalGUIElements; 
     140                    } 
     141 
     142                    other.equalGUIElements = this.equalGUIElements; 
     143                } 
     144                // else 
     145                // in this case, both GUI elements should already be registered with the same 
     146                // lists. 
     147            } 
     148        } 
    112149    } 
    113150 
     
    140177        // implement final, as GUI elements are all singletons and they equal only if they are the 
    141178        // same object or if they are in the list of equal GUI elements 
    142         return super.equals(other) || equalGUIElementManager.equals(this, other); 
     179        if (super.equals(other)) { 
     180            return true; 
     181        } 
     182        else if (other instanceof AbstractDefaultGUIElement) { 
     183            synchronized (AbstractDefaultGUIElement.class) { 
     184                if (equalGUIElements != null) { 
     185                    for (IGUIElement candidate : equalGUIElements) { 
     186                        if (candidate == other) { 
     187                            return true; 
     188                        } 
     189                    } 
     190                } 
     191            } 
     192        } 
     193 
     194        return false; 
    143195    } 
    144196 
     
    154206        // then they are stored in the list of equal elements. In this case, the hash code of the 
    155207        // list is unique within the system 
    156         return equalGUIElementManager.hashCode(this); 
     208        synchronized (AbstractDefaultGUIElement.class) { 
     209            if (this.equalGUIElements == null) { 
     210                this.equalGUIElements = new LinkedList<AbstractDefaultGUIElement>(); 
     211                this.equalGUIElements.add(this); 
     212            } 
     213             
     214            return System.identityHashCode(this.equalGUIElements); 
     215        } 
    157216    } 
    158217     
    159218    /** 
    160219     * <p> 
    161      * This internal helper class manages equal GUI elements. This is necessary, as we often first 
    162      * identify many GUI elements as different and later use a heuristic to determine that they are 
    163      * the same. This class provides the means to preserve the singleton behavior of the GUI 
    164      * elements after we merge two GUI elements. 
    165      * </p> 
    166      *  
    167      * @version 1.0 
    168      * @author Patrick Harms 
    169      */ 
    170     private static class EqualGUIElementManager { 
    171  
    172         /** 
    173          * <p> 
    174          * The internal map of GUI elements mapping each registered element to its equal variants. 
    175          * We use the {@link IdentityHashMap} as a normal hash map would not work because of the 
    176          * changing of the hash code of GUI elements at runtime. 
    177          * </p> 
    178          */ 
    179         private IdentityHashMap<IGUIElement, List<IGUIElement>> identityHashMap = 
    180             new IdentityHashMap<IGUIElement, List<IGUIElement>>(); 
    181  
    182         /** 
    183          * <p> 
    184          * Adds a new equals relationship between two {@link IGUIElement}s to the equality manager. 
    185          * </p> 
    186          *  
    187          * @param guiElement1 
    188          *            first equal GUI element 
    189          * @param guiElement2 
    190          *            second equal GUI element 
    191          */ 
    192         private synchronized void addEqualGUIElements(IGUIElement guiElement1, 
    193                                                       IGUIElement guiElement2) 
    194         { 
    195             List<IGUIElement> list1 = identityHashMap.get(guiElement1); 
    196             List<IGUIElement> list2 = identityHashMap.get(guiElement2); 
    197  
    198             if (list1 == null) { 
    199                 if (list2 == null) { 
    200                     list2 = new LinkedList<IGUIElement>(); 
    201                     list2.add(guiElement1); 
    202                     list2.add(guiElement2); 
    203                     identityHashMap.put(guiElement1, list2); 
    204                     identityHashMap.put(guiElement2, list2); 
    205                 } 
    206                 else { 
    207                     addIfNotContained(list2, guiElement1); 
    208                     identityHashMap.put(guiElement1, list2); 
    209                 } 
    210             } 
    211             else { 
    212                 if (list2 == null) { 
    213                     addIfNotContained(list1, guiElement2); 
    214                     identityHashMap.put(guiElement2, list1); 
    215                 } 
    216                 else if (list1 != list2) { 
    217                     list1.addAll(list2); 
    218                     identityHashMap.put(guiElement2, list1); 
    219                      
    220                     // we also have to set this new list for all other elements for which so 
    221                     // far list2 was registered 
    222                     for (IGUIElement candidate : list2) { 
    223                         identityHashMap.put(candidate, list1); 
    224                     } 
    225                 } 
    226                 // else 
    227                 // in this case, both GUI elements should already be registered with the same 
    228                 // lists. 
    229             } 
    230         } 
    231  
    232         /** 
    233          * <p> 
    234          * Returns the object hash of a {@link IGUIElement}. 
    235          * </p> 
    236          *  
    237          * @param guiElement 
    238          *            gui element whose object hash is determined 
    239          * @return the object hash 
    240          */ 
    241         private synchronized int hashCode(IGUIElement guiElement) { 
    242             return System.identityHashCode(getEqualElementsList(guiElement)); 
    243         } 
    244  
    245         /** 
    246          * <p> 
    247          * Determines the equality of two {@link IGUIElement}s based on the information of the 
    248          * identify manager. Two elements are equal, if they have been added as equal using 
    249          * {@link #addEqualGUIElements(IGUIElement, IGUIElement)}. 
    250          * </p> 
    251          *  
    252          * @param guiElement 
    253          *            GUI element to which the object is compared 
    254          * @param other 
    255          *            object that is compared to the GUI element 
    256          * @return 
    257          */ 
    258         private synchronized boolean equals(IGUIElement guiElement, Object other) { 
    259             if (other instanceof IGUIElement) { 
    260                 for (IGUIElement candidate : getEqualElementsList(guiElement)) { 
    261                     if (candidate == other) { 
    262                         return true; 
    263                     } 
    264                 } 
    265             } 
    266  
    267             return false; 
    268         } 
    269  
    270         /** 
    271          * <p> 
    272          * Returns the equal {@link IGUIElement} of a given {@link IGUIElement}. 
    273          * </p> 
    274          *  
    275          * @param guiElement 
    276          *            GUI element of which the equal elements are returned 
    277          * @return the equal GUI elements 
    278          */ 
    279         private List<IGUIElement> getEqualElementsList(IGUIElement guiElement) { 
    280             List<IGUIElement> returnValue = identityHashMap.get(guiElement); 
    281  
    282             if (returnValue == null) { 
    283                 returnValue = new LinkedList<IGUIElement>(); 
    284                 returnValue.add(guiElement); 
    285                 identityHashMap.put(guiElement, returnValue); 
    286             } 
    287  
    288             return returnValue; 
    289         } 
    290  
    291         /** 
    292          * <p> 
    293          * Adds {@link IGUIElement} as equal to a list of {@link IGUIElement} if and only if it is 
    294          * not already contained. 
    295          * </p> 
    296          *  
    297          * @param equalElementsList 
    298          *            list of {@link IGUIElement} to which the GUI element is added 
    299          * @param guiElement 
    300          *            GUI element to be added 
    301          */ 
    302         private void addIfNotContained(List<IGUIElement> equalElementsList, IGUIElement guiElement) 
    303         { 
    304             for (IGUIElement candidate : equalElementsList) { 
    305                 if (candidate == guiElement) { 
    306                     return; 
    307                 } 
    308             } 
    309  
    310             equalElementsList.add(guiElement); 
    311         } 
    312  
     220     * Adds an {@link AbstractDefaultGUIElement} as equal to a list of 
     221     * {@link AbstractDefaultGUIElement}s if and only if it is not already contained. 
     222     * </p> 
     223     *  
     224     * @param equalElementsList 
     225     *            list of {@link AbstractDefaultGUIElement} to which the GUI element is added 
     226     * @param guiElement 
     227     *            GUI element to be added 
     228     */ 
     229    private void addIfNotContained(List<AbstractDefaultGUIElement> equalElementsList, 
     230                                   AbstractDefaultGUIElement       guiElement) 
     231    { 
     232        for (IGUIElement candidate : equalElementsList) { 
     233            if (candidate == guiElement) { 
     234                return; 
     235            } 
     236        } 
     237 
     238        equalElementsList.add(guiElement); 
    313239    } 
    314240 
Note: See TracChangeset for help on using the changeset viewer.