/* * Created on Jun 27, 2007 Copyright (C) 2001-2007, Anthony Harrison * anh23@pitt.edu (jactr.org) This library is free software; you can * redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation; either version * 2.1 of the License, or (at your option) any later version. This library is * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.jactr.modules.pm.aural.audicon.map; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.Executor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.commonreality.identifier.IIdentifier; import org.commonreality.modalities.aural.DefaultAuralPropertyHandler; import org.commonreality.modalities.aural.IAuralPropertyHandler; import org.commonreality.object.IAfferentObject; import org.commonreality.object.UnknownPropertyNameException; import org.commonreality.object.delta.IObjectDelta; import org.jactr.core.chunk.IChunk; import org.jactr.core.chunktype.IChunkType; import org.jactr.core.module.declarative.IDeclarativeModule; import org.jactr.core.production.request.ChunkTypeRequest; import org.jactr.core.slot.BasicSlot; import org.jactr.core.slot.IConditionalSlot; import org.jactr.modules.pm.aural.IAuralModule; import org.jactr.modules.pm.common.memory.IPerceptualMemory; import org.jactr.modules.pm.common.memory.map.IFeatureMap; import org.jactr.modules.pm.common.memory.map.IFeatureMapListener; /** * @author developer */ public class KindFeatureMap implements IAuralFeatureMap<String[]> { /** * logger definition */ static private final Log LOGGER = LogFactory .getLog(KindFeatureMap.class); private IAuralPropertyHandler _propertyHandler; private Map<String, Set<IIdentifier>> _kindMap; private Map<IIdentifier, Set<String>> _identifierKindMap; private IAuralModule _module; public KindFeatureMap(IAuralModule module) { _module = module; _propertyHandler = new DefaultAuralPropertyHandler(); _kindMap = new TreeMap<String, Set<IIdentifier>>(); _identifierKindMap = new HashMap<IIdentifier, Set<String>>(); } /** * @see org.jactr.modules.pm.common.memory.map.IFeatureMap#clear() */ public void clear() { _kindMap.clear(); _identifierKindMap.clear(); } /** * @see org.jactr.modules.pm.common.memory.map.IFeatureMap#dispose() */ public void dispose() { clear(); } protected Collection<String> getKinds(IAfferentObject object) { String[] kinds = new String[0]; try { kinds = _propertyHandler.getTypes(object); } catch (UnknownPropertyNameException e) { if (LOGGER.isDebugEnabled()) LOGGER.debug("No kinds associated with " + object.getIdentifier(), e); } return Arrays.asList(kinds); } protected String toKindString(Object object) { if (object instanceof IChunkType) return ((IChunkType) object).getSymbolicChunkType().getName(); if (object instanceof IChunk) return ((IChunk) object).getSymbolicChunk().getName(); if (object != null) return object.toString(); return null; } protected Object toKindObject(String kind) { IDeclarativeModule decM = _module.getModel().getDeclarativeModule(); try { IChunkType ct = decM.getChunkType(kind).get(); if (ct != null) return ct; IChunk c = decM.getChunk(kind).get(); if (c != null) return c; return kind; } catch (Exception e) { if (LOGGER.isDebugEnabled()) LOGGER.debug("Could not get chunk or chunktype for " + kind, e); return kind; } } /** * @see org.jactr.modules.pm.common.memory.map.IFeatureMap#fillSlotValues(ChunkTypeRequest, * org.commonreality.identifier.IIdentifier, * IChunk, ChunkTypeRequest) */ public void fillSlotValues(ChunkTypeRequest mutableRequest, IIdentifier identifier, IChunk encodedChunk, ChunkTypeRequest originalSearchRequest) { Collection<String> kinds = _identifierKindMap.get(identifier); if (kinds == null) return; for (String kind : kinds) { Object kindObject = toKindObject(kind); boolean matched = true; for (IConditionalSlot slot : originalSearchRequest.getConditionalSlots()) if (slot.getName().equalsIgnoreCase(IAuralModule.KIND_SLOT)) matched &= slot.matchesCondition(kindObject); if (matched) { mutableRequest .addSlot(new BasicSlot(IAuralModule.KIND_SLOT, kindObject)); return; } } } /** * @see org.jactr.modules.pm.common.memory.map.IFeatureMap#getCandidateRealObjects(ChunkTypeRequest, Set) */ public void getCandidateRealObjects( ChunkTypeRequest request, Set<IIdentifier> container) { Set<IIdentifier> identifiers = new HashSet<IIdentifier>(); boolean firstIteration = true; for (IConditionalSlot cSlot : request.getConditionalSlots()) if (cSlot.getName().equalsIgnoreCase(IAuralModule.KIND_SLOT)) { Object value = toKindString(cSlot.getValue()); Collection<IIdentifier> eval = Collections.EMPTY_LIST; switch (cSlot.getCondition()) { case IConditionalSlot.EQUALS: if (value != null) eval = equals(value.toString()); break; case IConditionalSlot.NOT_EQUALS: if (value != null) eval = not(cSlot.getValue().toString()); else eval = all(); break; default: if (LOGGER.isWarnEnabled()) LOGGER.warn(getClass().getSimpleName() + " can only handle equals and not equals"); break; } if (eval.size() == 0) break; if (firstIteration) { identifiers.addAll(eval); firstIteration = false; } else identifiers.retainAll(eval); } } protected Collection<IIdentifier> all() { Set<IIdentifier> identifiers = new HashSet<IIdentifier>(); for (Set<IIdentifier> ids : _kindMap.values()) identifiers.addAll(ids); return identifiers; } protected Collection<IIdentifier> not(String kind) { kind = kind.toLowerCase(); Set<IIdentifier> identifiers = new HashSet<IIdentifier>(); for (Map.Entry<String, Set<IIdentifier>> entry : _kindMap.entrySet()) if (!entry.getKey().equalsIgnoreCase(kind)) identifiers.addAll(entry.getValue()); return identifiers; } protected Collection<IIdentifier> equals(String kind) { kind = kind.toLowerCase(); Set<IIdentifier> identifiers = _kindMap.get(kind); if (identifiers == null) identifiers = Collections.EMPTY_SET; return identifiers; } /** * @see org.jactr.modules.pm.common.memory.map.IFeatureMap#isInterestedIn(ChunkTypeRequest) */ public boolean isInterestedIn(ChunkTypeRequest request) { for (IConditionalSlot cSlot : request.getConditionalSlots()) if (cSlot.getName().equals(IAuralModule.KIND_SLOT)) return true; return false; } /** * @see org.jactr.modules.pm.common.afferent.IAfferentObjectListener#afferentObjectAdded(org.commonreality.object.IAfferentObject) */ public void afferentObjectAdded(IAfferentObject object) { add(object.getIdentifier(), getKinds(object)); } protected void add(IIdentifier identifier, Collection<String> kinds) { for (String kind : kinds) { kind = kind.toLowerCase(); Set<IIdentifier> identifiers = _kindMap.get(kind); if (identifiers == null) { identifiers = new HashSet<IIdentifier>(); _kindMap.put(kind, identifiers); } identifiers.add(identifier); } Set<String> objectKinds = _identifierKindMap.get(identifier); if (objectKinds == null) { objectKinds = new TreeSet<String>(); _identifierKindMap.put(identifier, objectKinds); } objectKinds.addAll(kinds); } protected void remove(IIdentifier identifier) { Set<String> kinds = _identifierKindMap.remove(identifier); if (kinds == null) return; for (String kind : kinds) { kind = kind.toLowerCase(); Set<IIdentifier> identifiers = _kindMap.get(kind); if (identifiers != null) if (identifiers.remove(identifier)) if (identifiers.size() == 0) _kindMap.remove(kind); } } /** * @see org.jactr.modules.pm.common.afferent.IAfferentObjectListener#afferentObjectRemoved(org.commonreality.object.IAfferentObject) */ public void afferentObjectRemoved(IAfferentObject object) { // noop remove(object.getIdentifier()); } /** * @see org.jactr.modules.pm.common.afferent.IAfferentObjectListener#afferentObjectUpdated(org.commonreality.object.IAfferentObject, * org.commonreality.object.delta.IObjectDelta) */ public void afferentObjectUpdated(IAfferentObject object, IObjectDelta delta) { remove(object.getIdentifier()); add(object.getIdentifier(), getKinds(object)); } /** * @see org.jactr.modules.pm.common.afferent.IAfferentObjectListener#isInterestedIn(org.commonreality.object.IAfferentObject) */ public boolean isInterestedIn(IAfferentObject object) { return _identifierKindMap.containsKey(object.getIdentifier()) || _propertyHandler.hasModality(object) && _propertyHandler.isAudible(object) && _propertyHandler.hasProperty(IAuralPropertyHandler.TYPE, object); } /** * @see org.jactr.modules.pm.aural.audicon.map.IAuralFeatureMap#removeFeatureFor(org.commonreality.object.IAfferentObject) */ public void removeFeatureFor(IAfferentObject object) { remove(object.getIdentifier()); } public void addListener(IFeatureMapListener listener, Executor executor) { // TODO Auto-generated method stub } public String[] getInformation(IIdentifier identifier) { // TODO Auto-generated method stub return null; } public IPerceptualMemory getPerceptualMemory() { // TODO Auto-generated method stub return null; } public void removeListener(IFeatureMapListener listener) { // TODO Auto-generated method stub } public void setPerceptualMemory(IPerceptualMemory memory) { // TODO Auto-generated method stub } public void normalizeRequest(ChunkTypeRequest request) { // TODO Auto-generated method stub } }