/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * A synchronized reference implementation of {@link ILookupService}. * * @author Tuukka Lehtonen */ public class LookupService implements ILookupService { private final Object lookupLock = new Object(); private final Map toNode = new HashMap(); private final Map toId = new HashMap(); Logger logger = Logger.getLogger(getClass().getName()); @Override public INode map(String id, INode node) { if (id == null) throw new NullPointerException("null id"); if (node == null) throw new NullPointerException("null node"); INode oldNode; String oldId; synchronized (lookupLock) { oldNode = toNode.put(id, node); oldId = toId.put(node, id); // Keep the mapping a consistent bijection: // If ID => INode mapping is removed, the INode => ID mappings must // removed also. if (oldNode != null && !oldNode.equals(node)) { String removedId = toId.remove(oldNode); if (!id.equals(removedId)) toNode.remove(removedId); } if (oldId != null && !oldId.equals(id)) { INode removedNode = toNode.remove(oldId); if (removedNode != node) toId.remove(removedNode); } } if (logger.isLoggable(Level.FINE)) logger.fine("map(" + id + ", " + node + ")"); if (oldNode != null || oldId != null) { if (logger.isLoggable(Level.INFO)) { logger.info("replaced mappings for ID " + oldId + " and node " + oldNode); } } return oldNode; } @Override public INode unmap(String id) { INode node; String mappedId; synchronized (lookupLock) { node = toNode.remove(id); if (node == null) return null; mappedId = toId.remove(node); } if (logger.isLoggable(Level.FINE)) logger.fine("unmap(" + id + "): " + node); if (mappedId != null && !mappedId.equals(id)) { if (logger.isLoggable(Level.WARNING)) logger.log(Level.WARNING, "mapping was out-of-sync: " + id + " => " + node + " & " + mappedId + " => " + node, new Exception("trace")); } return node; } @Override public String unmap(INode node) { String id; INode mappedNode; synchronized (lookupLock) { id = toId.remove(node); if (node == null) return null; mappedNode = toNode.remove(id); } if (logger.isLoggable(Level.FINE)) logger.fine("unmap(" + node + "): " + id); if (mappedNode != null && node != mappedNode) { if (logger.isLoggable(Level.WARNING)) logger.log(Level.WARNING, "mapping was out-of-sync: " + node + " => " + id + " & " + id + " => " + mappedNode, new Exception("trace")); } return id; } @Override public INode lookupNode(String id) { synchronized (lookupLock) { return toNode.get(id); } } @Override public String lookupId(INode node) { synchronized (lookupLock) { return toId.get(node); } } }