/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2007-2008, Open Source Geospatial Foundation (OSGeo) * * 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; * version 2.1 of the License. * * 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. */ package org.geotools.caching.spatialindex; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.ref.SoftReference; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; /** Instances of this class provide unique identifiers for nodes, * and are used to store and retrieve nodes from their storage. * Implementors must take care that instances have to be immutable. * Nodes are basically identified by the region they represent. * Kinds of nodes or kinds of storage may require to use other elements to identify * nodes. Implementors must take care to override hashCode() and equals() accordingly. * NodeIdentifier should not reference the node they identify, * as they are likely to be used to passivate nodes in secondary storage. * * @author crousson * * * * * @source $URL$ */ public abstract class NodeIdentifier implements Serializable { private static final long serialVersionUID = 1L; //wait a maximum of 5 minutes for lock; this should never be necessary it's just a safe guard against unexpected behaviour private static final long LOCK_TIMEOUT = 5 * 60; //5min timeout private static final TimeUnit LOCK_TIMEOUT_UNITS = TimeUnit.SECONDS; private boolean valid = false; transient ReentrantReadWriteLock lock; transient SoftReference<Node> node; NodeIdentifier(){ lock = new ReentrantReadWriteLock(); } public abstract Shape getShape(); /** * * @return if the nodes data is valid */ public boolean isValid() { return valid; } /** * Sets the validity of the node; true means the data * in the node is ready for reading. * * @param valid */ public void setValid(boolean valid) { this.valid = valid; } /** * Acquire a write lock on the node */ public void writeLock() throws Exception { if (!lock.writeLock().tryLock(LOCK_TIMEOUT, LOCK_TIMEOUT_UNITS)){ throw new Exception("Timed out waiting for write lock on node."); } //lock.writeLock().lock(); } /** * Unlock the write lock */ public void writeUnLock(){ lock.writeLock().unlock(); } /** * Acquire a read lock on the node */ public void readLock() throws Exception { if (!lock.readLock().tryLock(LOCK_TIMEOUT, LOCK_TIMEOUT_UNITS)){ throw new Exception("Timed out waiting for read lock on node."); } //lock.readLock().lock(); } /** * Unlock read lock */ public void readUnLock(){ lock.readLock().unlock(); } /** * Only want to write to nodes that aren't being read. */ public boolean isWritable(){ return lock.getReadLockCount() == 0; } public boolean isLocked(){ return lock.getReadLockCount() >0 || lock.isWriteLocked(); } /** * Sets the node associated with the nodeid; this node * is stored as a soft reference so getNode() may * return null. * * @param n */ public void setNode(Node n){ this.node = new SoftReference<Node>(n); } /** * May return null; node is held onto with a soft reference * * @return */ public Node getNode(){ if (this.node == null) return null; return this.node.get(); } private void writeObject(ObjectOutputStream stream) throws IOException{ stream.writeBoolean(valid); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException{ this.valid = stream.readBoolean(); this.lock = new ReentrantReadWriteLock(); } }