/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-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.data; /** * Default implementation of the FeatureLockFactory. Generates id numbers. * * @author Jody Garnett, Refractions Research, Inc. * @author Chris Holmes, TOPP. * @source $URL$ * @version $Id$ * * @task REVISIT: Should more of this code move to the parent? I guess if * other implementations came along they may want to implement * differently. * @task REVISIT: The generation code can move to the parent. Even if other * implementations come along we do not want the to implement the * generation differently. */ public class DefaultFeatureLockFactory extends FeatureLockFactory { /** Count used to generate unique ID numbers */ static long count = 0; protected FeatureLock createLock(String name, long duration) { long number = nextIdNumber(duration); return new DefaultFeatureLock(name + "_" + Long.toString(number, 16), duration); } /** * Package visiable generate function for JUnit tests * * @param name The name to give this lock. * @param duration How long it is to last. * * @return The new FeatureLock. */ static FeatureLock createTestLock(String name, long duration) { return new DefaultFeatureLock(name, duration); } /** * Used to seed nextIDNumber to allow for reproduceable JUnit tests. Not * part of the public API - package protected method used for JUnits * Tests * * @param seed The number to start seeding with. */ static void seedIdNumber(long seed) { count = seed; } /** * Produces the next ID number based on count, duration and the current * time. The uniquity is 'good enough' although not provable as per * security systems. The method used will probably have to be changed * later, the api is what is important right now. * <table border=1, bgcolor="lightgray", width="100%"><tr><td><code><pre> * count: 000000000000000000000000000001011 (increasing count) * date: 000000000001111010101010101000000 (expriry date milliseconds usually empty) * now: 000101100111011010011111000000000 (bit order reverse of current time) * --------------------------------- * number: 000101100110100000110101001001011 * </pre></code></td></tr></table> * Once again method is package visible for testing. * * @param duration The time for the lock to last. * * @return The next generated id number. */ static long nextIdNumber(long duration) { long number; long now = System.currentTimeMillis(); long time = now + duration; // start of with number count++; number = count; number = number ^ time; // count fills 'empty' milliseconds StringBuffer reverse = new StringBuffer(asBits(now)); now = Long.parseLong(reverse.reverse().toString(), 2); // flip now around number = number ^ now; return number; } /** * Utility method used to reverse bits. * <p> * Since generating ID numbers is not performance critical I won't care * right now. * </p> * * @param number * @return Number represented as bits */ private static String asBits(long number) { long yum = number; StringBuffer buf = new StringBuffer(32); for (int i = 0; i < 63; i++) { buf.append(yum & 1); yum = yum >> 1; } buf.reverse(); return buf.toString(); } }