/******************************************************************************* * 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.browsing.ui.common.internal; import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.THashSet; import java.util.Collections; import java.util.Map; import java.util.Set; import org.simantics.browsing.ui.NodeContext; import org.simantics.browsing.ui.NodeContext.CacheKey; public class GECache implements IGECache { final Map entries = new THashMap(); final Map> treeReferences = new THashMap>(); final private static class GECacheKey { private NodeContext context; private CacheKey key; GECacheKey(NodeContext context, CacheKey key) { this.context = context; this.key = key; if (context == null || key == null) throw new IllegalArgumentException("Null context or key is not accepted"); } GECacheKey(GECacheKey other) { this.context = other.context; this.key = other.key; if (context == null || key == null) throw new IllegalArgumentException("Null context or key is not accepted"); } void setValues(NodeContext context, CacheKey key) { this.context = context; this.key = key; if (context == null || key == null) throw new IllegalArgumentException("Null context or key is not accepted"); } @Override public int hashCode() { return context.hashCode() | key.hashCode(); } @Override public boolean equals(Object object) { if (this == object) return true; else if (object == null) return false; // else if (getClass() != object.getClass()) // return false; GECacheKey i = (GECacheKey)object; return key.equals(i.key) && context.equals(i.context); } }; /** * This single instance is used for all get operations from the cache. This * should work since the GE cache is meant to be single-threaded within the * current UI thread, what ever that thread is. For put operations which * store the key, this is not used. */ NodeContext getNC = new NodeContext() { @Override public T getAdapter(Class adapter) { return null; } @Override public T getConstant(ConstantKey key) { return null; } @Override public Set> getKeys() { return Collections.emptySet(); } }; CacheKey getCK = new CacheKey() { @Override public Object processorIdenfitier() { return this; } }; GECacheKey getKey = new GECacheKey(getNC, getCK); public IGECacheEntry put(NodeContext context, CacheKey key, T value) { IGECacheEntry entry = new GECacheEntry(context, key, value); entries.put(new GECacheKey(context, key), entry); return entry; } @SuppressWarnings("unchecked") public T get(NodeContext context, CacheKey key) { getKey.setValues(context, key); IGECacheEntry entry = entries.get(getKey); if (entry == null) return null; return (T) entry.getValue(); } @Override public IGECacheEntry getEntry(NodeContext context, CacheKey key) { assert(context != null); assert(key != null); getKey.setValues(context, key); return entries.get(getKey); } @Override public void remove(NodeContext context, CacheKey key) { getKey.setValues(context, key); entries.remove(getKey); } @Override public Set getTreeReference(NodeContext context, CacheKey key) { assert(context != null); assert(key != null); getKey.setValues(context, key); return treeReferences.get(getKey); } @Override public void putTreeReference(NodeContext context, CacheKey key, UIElementReference reference) { assert(context != null); assert(key != null); getKey.setValues(context, key); Set refs = treeReferences.get(getKey); if (refs != null) { refs.add(reference); } else { refs = new THashSet(4); refs.add(reference); treeReferences.put(new GECacheKey(getKey), refs); } } @Override public Set removeTreeReference(NodeContext context, CacheKey key) { assert(context != null); assert(key != null); getKey.setValues(context, key); return treeReferences.remove(getKey); } @Override public boolean isShown(NodeContext context) { return references.get(context) > 0; } private TObjectIntHashMap references = new TObjectIntHashMap(); @Override synchronized public void incRef(NodeContext context) { int exist = references.get(context); references.put(context, exist+1); } @Override synchronized public void decRef(NodeContext context) { int exist = references.get(context); references.put(context, exist-1); if(exist == 1) { references.remove(context); } } public void dispose() { references.clear(); entries.clear(); treeReferences.clear(); } }