001: /**
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */package com.tc.util;
005:
006: import com.tc.logging.TCLogger;
007: import com.tc.logging.TCLogging;
008:
009: import java.util.Collection;
010: import java.util.HashMap;
011: import java.util.Map;
012: import java.util.SortedSet;
013: import java.util.TreeSet;
014:
015: public class SequenceValidator {
016:
017: private static final TCLogger logger = TCLogging
018: .getLogger(SequenceValidator.class);
019:
020: private final Map sequences = new HashMap();
021: private final long start;
022:
023: public SequenceValidator(long start) {
024: this .start = start;
025: }
026:
027: // Used in tests
028: public synchronized boolean isNext(Object key, SequenceID candidate) {
029: if (candidate.isNull())
030: return true;
031: Sequencer sequencer = getOrCreate(key);
032: return sequencer.isNext(candidate);
033: }
034:
035: public synchronized void setCurrent(Object key, SequenceID next)
036: throws InvalidSequenceIDException {
037: if (key == null || SequenceID.NULL_ID.equals(next))
038: return;
039: Sequencer s = getOrCreate(key);
040: s.setCurrent(next);
041: }
042:
043: // Used in tests
044: public synchronized SequenceID getCurrent(Object key) {
045: Sequencer s = (Sequencer) sequences.get(key);
046: Assert.assertNotNull(s);
047: return s.getCurrent();
048:
049: }
050:
051: public synchronized void initSequence(Object key,
052: Collection sequenceIDs) {
053: Assert.assertFalse(sequences.containsKey(key));
054: sequences.put(key, new Sequencer(key, start, sequenceIDs));
055: }
056:
057: public synchronized void remove(Object key) {
058: sequences.remove(key);
059: }
060:
061: public synchronized int size() {
062: return sequences.size();
063: }
064:
065: private Sequencer getOrCreate(Object key) {
066: Sequencer sequencer = (Sequencer) sequences.get(key);
067: if (sequencer == null) {
068: sequencer = new Sequencer(key, start);
069: sequences.put(key, sequencer);
070: }
071: return sequencer;
072: }
073:
074: private static class Sequencer {
075:
076: SortedSet sequenceIDs;
077: SequenceID current;
078:
079: Sequencer(Object key, long start, Collection sequenceIDs) {
080: if (sequenceIDs.size() > 0) {
081: this .sequenceIDs = new TreeSet(SequenceID.COMPARATOR);
082: this .sequenceIDs.addAll(sequenceIDs);
083: current = new SequenceID(start);
084: } else {
085: throw new AssertionError(
086: "Sequencer should be set to a valid SequenceID Sequence !!!");
087: }
088: logger.info("Setting initial Sequence IDs for " + key
089: + " current = " + current + " next = "
090: + this .sequenceIDs);
091: }
092:
093: Sequencer(Object key, long start) {
094: current = new SequenceID(start);
095: logger.debug("Setting initial Sequence IDs for " + key
096: + " current = " + current);
097: }
098:
099: public boolean isNext(SequenceID candidate) {
100: if (candidate.toLong() <= current.toLong()) {
101: logger.warn("Sequence IDs = " + sequenceIDs
102: + " current = " + current + " but candidate = "
103: + candidate);
104: return false;
105: }
106: if (sequenceIDs == null) {
107: return current.toLong() + 1 == candidate.toLong();
108: } else {
109: return (((SequenceID) sequenceIDs.first()).toLong() == candidate
110: .toLong());
111: }
112: }
113:
114: public void setCurrent(SequenceID next)
115: throws InvalidSequenceIDException {
116: if (!isNext(next)) {
117: throw new InvalidSequenceIDException(
118: "Trying to set to " + next + " but current = "
119: + current);
120: }
121: if (sequenceIDs != null) {
122: logger
123: .info("Setting current Sequence IDs from current = "
124: + current + " to next = " + next);
125: sequenceIDs.headSet(next.next()).clear();
126: if (sequenceIDs.size() == 0) {
127: sequenceIDs = null;
128: }
129: }
130: current = next;
131: }
132:
133: public SequenceID getCurrent() {
134: return current;
135: }
136: }
137: }
|