/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * 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 net.ontopia.topicmaps.impl.basic.index; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.SortedMap; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.topicmaps.core.OccurrenceIF; import net.ontopia.topicmaps.impl.utils.IndexManagerIF; import net.ontopia.topicmaps.core.index.OccurrenceIndexIF; import net.ontopia.topicmaps.impl.utils.BasicIndex; import net.ontopia.topicmaps.impl.utils.EventManagerIF; import net.ontopia.topicmaps.impl.utils.ObjectTreeManager; import net.ontopia.utils.DeciderIF; import net.ontopia.utils.CollectionUtils; import net.ontopia.utils.CollectionSortedMap; import net.ontopia.utils.ObjectUtils; /** * INTERNAL: The basic dynamic locator index implementation. */ public class OccurrenceIndex extends BasicIndex implements OccurrenceIndexIF { protected CollectionSortedMap occurs; OccurrenceIndex(IndexManagerIF imanager, EventManagerIF emanager, ObjectTreeManager otree) { // Initialize index maps occurs = new CollectionSortedMap(STRING_PREFIX_COMPARATOR); // Initialize object tree event handlers [objects added or removed] otree.addListener(new OccurrenceIF_added(occurs), OccurrenceIF.EVENT_ADDED); otree.addListener(new OccurrenceIF_removed(occurs), OccurrenceIF.EVENT_REMOVED); // Initialize object property event handlers handlers.put(OccurrenceIF.EVENT_SET_VALUE, new OccurrenceIF_setValue(occurs)); // Register dynamic index as event listener Iterator iter = handlers.keySet().iterator(); while (iter.hasNext()) emanager.addListener(this, (String)iter.next()); } // ----------------------------------------------------------------------------- // Utility class // ----------------------------------------------------------------------------- protected static final Comparator STRING_PREFIX_COMPARATOR = new Comparator() { // NOTE: need this comparator because otherwise we will get // null pointer exceptions when comparing with null values. public int compare(Object o1, Object o2) { String s1 = (String)o1; String s2 = (String)o2; if (s1 == null) { return s2 == null ? 0 : -1; } else { return s2 == null ? 1 : s1.compareTo(s2); } } }; // ---------------------------------------------------------------------------- // OccurrenceIndexIF // ---------------------------------------------------------------------------- public Collection getOccurrences(String value) { return extractExactValues(occurs, value); } public Collection getOccurrences(String value, final LocatorIF datatype) { return CollectionUtils.filterSet(extractExactValues(occurs, value), new DeciderIF() { public boolean ok(Object o) { OccurrenceIF occ = (OccurrenceIF)o; return ObjectUtils.equals(occ.getDataType(), datatype); } }); } public Collection getOccurrencesByPrefix(String prefix) { return extractPrefixValues(occurs, prefix); } public Collection getOccurrencesByPrefix(String prefix, final LocatorIF datatype) { return CollectionUtils.filterSet(extractPrefixValues(occurs, prefix), new DeciderIF() { public boolean ok(Object o) { OccurrenceIF occ = (OccurrenceIF)o; return ObjectUtils.equals(occ.getDataType(), datatype); } }); } public Iterator getValuesGreaterThanOrEqual(String value) { return occurs.tailMap(value).keySet().iterator(); } public Iterator getValuesSmallerThanOrEqual(String value) { return occurs.headMap(value, true).navigableKeySet().descendingIterator(); } // ---------------------------------------------------------------------------- // Helper methods // ---------------------------------------------------------------------------- private Collection extractExactValues(CollectionSortedMap map, String value) { Collection result = (Collection)map.get(value); if (result == null) return Collections.EMPTY_SET; // Create new collection return new ArrayList(result); } /** * INTERNAL: utility method used to extract all keys from the sorted * map that matches the prefix and aggregate all values stores as * entry values. */ private Collection extractPrefixValues(CollectionSortedMap map, String prefix) { Collection result = null; SortedMap tail = map.tailMap(prefix); Iterator iter = tail.keySet().iterator(); while (iter.hasNext()) { String key = (String)iter.next(); if (key == null || !key.startsWith(prefix)) { break; } // add values to result if (result == null) result = new HashSet(); Collection c = (Collection)map.get(key); result.addAll(c); } return (result == null ? Collections.EMPTY_SET : result); } // ----------------------------------------------------------------------------- // Event handlers // ----------------------------------------------------------------------------- /** * EventHandler: OccurrenceIF.setValue */ class OccurrenceIF_setValue extends EventHandler { protected CollectionSortedMap objects; OccurrenceIF_setValue(CollectionSortedMap objects) { this.objects = objects; } public void processEvent(Object object, String event, Object new_value, Object old_value) { objects.move(object, old_value, new_value); } } /** * EventHandler: OccurrenceIF.added */ class OccurrenceIF_added extends EventHandler { protected CollectionSortedMap objects; OccurrenceIF_added(CollectionSortedMap objects) { this.objects = objects; } public void processEvent(Object object, String event, Object new_value, Object old_value) { objects.add(((OccurrenceIF)new_value).getValue(), new_value); } } /** * EventHandler: OccurrenceIF.removed */ class OccurrenceIF_removed extends EventHandler { protected CollectionSortedMap objects; OccurrenceIF_removed(CollectionSortedMap objects) { this.objects = objects; } public void processEvent(Object object, String event, Object new_value, Object old_value) { objects.remove(((OccurrenceIF)old_value).getValue(), old_value); } } }