001: /*
002: * NEMESIS-FORUM.
003: * Copyright (C) 2002 David Laurent(lithium2@free.fr). All rights reserved.
004: *
005: * Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
006: *
007: * Copyright (C) 2001 Yasna.com. All rights reserved.
008: *
009: * Copyright (C) 2000 CoolServlets.com. All rights reserved.
010: *
011: * NEMESIS-FORUM. is free software; you can redistribute it and/or
012: * modify it under the terms of the Apache Software License, Version 1.1,
013: * or (at your option) any later version.
014: *
015: * NEMESIS-FORUM core framework, NEMESIS-FORUM backoffice, NEMESIS-FORUM frontoffice
016: * application are parts of NEMESIS-FORUM and are distributed under
017: * same terms of licence.
018: *
019: *
020: * NEMESIS-FORUM includes software developed by the Apache Software Foundation (http://www.apache.org/)
021: * and software developed by CoolServlets.com (http://www.coolservlets.com).
022: * and software developed by Yasna.com (http://www.yasna.com).
023: *
024: */
025:
026: package org.nemesis.forum.impl;
027:
028: import java.sql.Connection;
029: import java.sql.PreparedStatement;
030: import java.sql.ResultSet;
031: import java.util.HashMap;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.nemesis.forum.util.jdbc.DbConnectionManager;
036:
037: /**
038: * Manages sequences of unique ID's that get stored in the database. Database
039: * support for sequences varies widely; some don't support them at all. So,
040: * we handle unique ID generation with synchronized counters.<p>
041: *
042: * Selecting the initial ID for each sequence is trivial: we simply query the
043: * database to get the last highest unique ID, and then add 1 to that.<p>
044: *
045: * This method only works if a single instance is pointed at a database.
046: * Otherwise, the unique ID's will stop being unique. :) A refined class that
047: * deals with this is coming soon.
048: */
049: public class DbSequenceManager {
050: static protected Log log = LogFactory
051: .getLog(DbSequenceManager.class);
052: private static final String NEXT_FORUM_ID = "SELECT max(forumID) FROM yazdForum";
053: private static final String NEXT_THREAD_ID = "SELECT max(threadID) FROM yazdThread";
054: private static final String NEXT_MESSAGE_ID = "SELECT max(messageID) FROM yazdMessage";
055: private static final String NEXT_GROUP_ID = "SELECT max(groupID) FROM yazdGroup";
056: private static final String NEXT_USER_ID = "SELECT max(userID) FROM yazdUser";
057:
058: /**
059: * Singleton type access to the class.
060: */
061: private static DbSequenceManager sequenceManager = null;
062:
063: /**
064: * Lock so that we can synchronize during initialization.
065: */
066: private static Object initLock = new Object();
067:
068: /**
069: * Returns the next ID of the specified type.
070: *
071: * @param type the type of unique ID.
072: * @return the next unique ID of the specified type.
073: */
074: public static int nextID(String type) {
075: if (sequenceManager == null) {
076: synchronized (initLock) {
077: if (sequenceManager == null) {
078: sequenceManager = new DbSequenceManager();
079: }
080: }
081: }
082: return sequenceManager.nextUniqueID(type);
083: }
084:
085: private HashMap uniqueIDCounters;
086:
087: /**
088: * Creates a new DbSequenceManager and initializes all of the counters.
089: */
090: public DbSequenceManager() {
091: uniqueIDCounters = new HashMap();
092: //Forum counter.
093: uniqueIDCounters.put("Forum", new Counter(
094: getNextDbID(NEXT_FORUM_ID)));
095: //ForumThread counter.
096: uniqueIDCounters.put("ForumThread", new Counter(
097: getNextDbID(NEXT_THREAD_ID)));
098: //ForumMessage counter.
099: uniqueIDCounters.put("ForumMessage", new Counter(
100: getNextDbID(NEXT_MESSAGE_ID)));
101: //Group counter.
102: uniqueIDCounters.put("Group", new Counter(
103: getNextDbID(NEXT_GROUP_ID)));
104: //User counter.
105: uniqueIDCounters.put("User", new Counter(
106: getNextDbID(NEXT_USER_ID)));
107: }
108:
109: /**
110: * Provides the next available unique ID for a particular object type.
111: * Essentially this provides for the functionality of an auto-increment
112: * database field. Valid counter names are Forum, ForumThread, ForumMessage,
113: * Group, and User.
114: * <p>
115: * Those that are integrating into existing tables should be sure
116: * that the table names match up so that the correct starting unique
117: * id can be determined.
118: */
119: public int nextUniqueID(String counterName) {
120: Counter counter = (Counter) uniqueIDCounters.get(counterName);
121: return counter.next();
122: }
123:
124: /**
125: * Do a lookup to see what the next available unique ID is for a
126: * particular table. uses the convention of always making the name of
127: * the column that holds the unique id be called id, so this works.
128: */
129: private int getNextDbID(String query) {
130: int currentID = 0;
131: Connection con = null;
132: PreparedStatement pstmt = null;
133:
134: try {
135: con = DbConnectionManager.getConnection();
136: pstmt = con.prepareStatement(query);
137: ResultSet rs = pstmt.executeQuery();
138: rs.next();
139: currentID = rs.getInt(1);
140: } catch (Exception sqle) {
141: log
142: .error("Error in DbSequenceManager:getNextDbID()-",
143: sqle);
144:
145: } finally {
146: try {
147: pstmt.close();
148: } catch (Exception e) {
149: log.error("", e);
150: }
151: try {
152: con.close();
153: } catch (Exception e) {
154: log.error("", e);
155: }
156: }
157: //If the table is empty, start with id 0
158: if (currentID < 0) {
159: currentID = 0;
160: }
161: return currentID;
162: }
163:
164: /**
165: * Internal class to keep track of the current count of a unique id.
166: */
167: private final class Counter {
168:
169: private int count;
170:
171: public Counter(int currentCount) {
172: count = currentCount;
173: }
174:
175: public final synchronized int next() {
176: return (++count);
177: }
178: }
179: }
|