// ============================================================================ // // Copyright (C) 2006-2012 Talend Inc. - www.talend.com // // This source code is available under agreement available at // %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt // // You should have received a copy of the agreement // along with this program; if not, write to Talend SA // 9 rue Pages 92150 Suresnes, France // // ============================================================================ package org.talend.designer.components.lookup.memory; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import org.apache.commons.collections.list.GrowthList; import org.talend.commons.utils.data.map.MultiLazyValuesMap; /** * DOC amaumont class global comment. Detailled comment
* * @param value */ public class AdvancedMemoryLookup implements IMemoryLookup, Cloneable { private MultiLazyValuesMap mapOfCol; private Map uniqueHash; private boolean countValuesForEachKey; private Map counterHash; private List list = new ArrayList(); private Object[] arrayValues; private boolean arrayIsDirty = true; private List listResult; private V objectResult; private boolean keepAllValues; private MATCHING_MODE matchingMode; private static final int ZERO = 0; private static final int ONE = 1; int currentIndex = 0; private int sizeResultList; private boolean hasResult; /** * * AdvancedLookup can be configured to store values in different modes. * * @param useHashKeys use equals() and hashCode() methods by storing objects in hash maps * @param matchingMode to optimize storing and searching, and to specify which matching mode should used * @param uniqueMatch keep in the lookup only the last put object, but store the current number of same values for * each key * @param keepAllValues keep all identical values (with same key values) in each list of each key * @param countValuesForEachKey force internal count of values */ public AdvancedMemoryLookup(MATCHING_MODE matchingMode, boolean keepAllValues, boolean countValuesForEachKey) { super(); this.keepAllValues = keepAllValues; this.matchingMode = matchingMode == null ? MATCHING_MODE.UNIQUE_MATCH : matchingMode; this.countValuesForEachKey = countValuesForEachKey; // || this.matchingMode == MATCHING_MODE.UNIQUE_MATCH; if (matchingMode != MATCHING_MODE.ALL_ROWS) { if (matchingMode == MATCHING_MODE.UNIQUE_MATCH && !keepAllValues) { uniqueHash = new HashMap(); } if (this.countValuesForEachKey) { counterHash = new HashMap(); } mapOfCol = new MultiLazyValuesMap(new HashMap()) { @Override public Collection instanciateNewCollection() { return new GrowthList(3); } }; } } public AdvancedMemoryLookup() { } public static AdvancedMemoryLookup getLookup(MATCHING_MODE matchingMode) { return new AdvancedMemoryLookup(matchingMode, false, false); } public Object[] getResultArray() { if (matchingMode == MATCHING_MODE.ALL_ROWS) { if (listResult == null) { listResult = list; } if (arrayIsDirty) { arrayValues = listResult.toArray(); arrayIsDirty = false; } return arrayValues; } else { return listResult.toArray(); } } public List getResultList() { return listResult; } public V getResultObject() { return objectResult; } public boolean resultIsObject() { return objectResult != null; } public boolean resultIsList() { return listResult != null; } public void initPut() { } public V put(V value) { if (value != null) { if (matchingMode == MATCHING_MODE.UNIQUE_MATCH && !keepAllValues) { V previousValue = uniqueHash.put(value, value); incrementCountValues(value, previousValue); return previousValue; } else { if (matchingMode == MATCHING_MODE.ALL_ROWS) { list.add(value); return null; } else { arrayIsDirty = true; V previousValue = (V) mapOfCol.put(value, value); incrementCountValues(value, previousValue); return previousValue; } } } return null; } public void endPut() { } public void initGet() { } public void lookup(V key) { if (matchingMode == MATCHING_MODE.UNIQUE_MATCH) { listResult = null; objectResult = uniqueHash.get(key); } else { if (matchingMode != MATCHING_MODE.ALL_ROWS && key != null) { Object v = mapOfCol.get(key); if (v instanceof List) { List localList = (List) v; if (matchingMode == MATCHING_MODE.ALL_MATCHES) { listResult = localList; currentIndex = 0; sizeResultList = localList.size(); objectResult = null; } else if (matchingMode == MATCHING_MODE.FIRST_MATCH) { objectResult = localList.get(ZERO); } else if (matchingMode == MATCHING_MODE.LAST_MATCH) { hasResult = false; listResult = null; objectResult = localList.get(localList.size() - ONE); } } else { hasResult = false; objectResult = (V) v; listResult = null; } } else { hasResult = false; listResult = list; currentIndex = 0; sizeResultList = list.size(); objectResult = null; } } } public boolean hasNext() { if (objectResult != null) { return true; } else if (listResult != null && currentIndex != sizeResultList) { return true; } return false; } public V next() { if (objectResult != null) { hasResult = true; V object = objectResult; objectResult = null; return object; } else if (listResult != null) { hasResult = true; return listResult.get(currentIndex++); } throw new NoSuchElementException(); } public void endGet() { clear(); } /** * DOC amaumont Comment method "incrementCountValues". * * @param value * @param previousValue */ private void incrementCountValues(V value, V previousValue) { if (countValuesForEachKey) { Integer count; if (previousValue == null) { count = ONE; } else { count = counterHash.get(value); count++; } counterHash.put(value, count); } } public void clear() { if (mapOfCol != null) { mapOfCol.clear(); } if (uniqueHash != null) { uniqueHash.clear(); } if (counterHash != null) { counterHash.clear(); } arrayValues = null; if (list != null) { list.clear(); } listResult = null; } /** * DOC amaumont Comment method "hasResult". * * @return */ public boolean hasResult() { return hasResult; } public boolean isEmpty() { if (matchingMode == MATCHING_MODE.UNIQUE_MATCH && !keepAllValues) { return uniqueHash.isEmpty(); } else if (matchingMode == MATCHING_MODE.ALL_ROWS) { return list.isEmpty(); } else { return mapOfCol.isEmpty(); } } /** * Getter for hasHashKeys. * * @return the hasHashKeys */ public boolean isUseHashKeys() { return matchingMode != MATCHING_MODE.ALL_ROWS; } /** * Getter for countValuesForEachKey. * * @return the countValuesForEachKey */ public boolean isCountValuesForEachKey() { return this.countValuesForEachKey; } /** * Getter for keepAllValues. * * @return the keepAllValues */ public boolean isKeepAllValues() { return this.keepAllValues; } /** * Getter for uniqueMatch. * * @return the uniqueMatch */ public boolean isUniqueMatch() { return matchingMode == MATCHING_MODE.UNIQUE_MATCH; } /** * Getter for uniqueMatch. * * @return the uniqueMatch */ public boolean isOnlyOneMatchResult() { return matchingMode == MATCHING_MODE.UNIQUE_MATCH || matchingMode == MATCHING_MODE.FIRST_MATCH || matchingMode == MATCHING_MODE.LAST_MATCH; } public int getCount(V key) { if (countValuesForEachKey) { Integer count = counterHash.get(key); if (count == null) { return ZERO; } else { return count; } } else if (matchingMode == MATCHING_MODE.UNIQUE_MATCH && !keepAllValues) { if (uniqueHash.get(key) != null) { return ONE; } else { return ZERO; } } else if (matchingMode != MATCHING_MODE.ALL_ROWS) { Object v = mapOfCol.get(key); if (v instanceof List) { List localList = (List) v; return localList.size(); } else { if (v != null) { return ONE; } else { return ZERO; } } } else { if (list.contains(key)) { return 1; } else { return ZERO; } } } /** * Getter for matchingMode. * * @return the matchingMode */ public MATCHING_MODE getMatchingMode() { return matchingMode; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * Getter for id_Document lookup(for tXMLMap) Purpose : Get all value data storing in the lookup Object Use case : * When no basic lookup(not Document lookup) exists,but Document lookup exists for ALL,First Matching(When no basic * lookup,not override the hashCode(),equals() method,so no List value,only V value) */ public void lookup() { List localList = new ArrayList(); if (matchingMode == MATCHING_MODE.UNIQUE_MATCH) { for (V value : uniqueHash.values()) { localList.add(value); } } else { for (Object value : mapOfCol.values()) { localList.add((V) value); } } listResult = localList; sizeResultList = localList.size(); objectResult = null; currentIndex = 0; } }