001: /**
002: * Copyright (C) 2001 Yasna.com. All rights reserved.
003: *
004: * ===================================================================
005: * The Apache Software License, Version 1.1
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution,
020: * if any, must include the following acknowledgment:
021: * "This product includes software developed by
022: * Yasna.com (http://www.yasna.com)."
023: * Alternately, this acknowledgment may appear in the software itself,
024: * if and wherever such third-party acknowledgments normally appear.
025: *
026: * 4. The names "Yazd" and "Yasna.com" must not be used to
027: * endorse or promote products derived from this software without
028: * prior written permission. For written permission, please
029: * contact yazd@yasna.com.
030: *
031: * 5. Products derived from this software may not be called "Yazd",
032: * nor may "Yazd" appear in their name, without prior written
033: * permission of Yasna.com.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL YASNA.COM OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of Yasna.com. For more information
051: * on Yasna.com, please see <http://www.yasna.com>.
052: */
053:
054: /**
055: * Copyright (C) 2000 CoolServlets.com. All rights reserved.
056: *
057: * ===================================================================
058: * The Apache Software License, Version 1.1
059: *
060: * Redistribution and use in source and binary forms, with or without
061: * modification, are permitted provided that the following conditions
062: * are met:
063: *
064: * 1. Redistributions of source code must retain the above copyright
065: * notice, this list of conditions and the following disclaimer.
066: *
067: * 2. Redistributions in binary form must reproduce the above copyright
068: * notice, this list of conditions and the following disclaimer in
069: * the documentation and/or other materials provided with the
070: * distribution.
071: *
072: * 3. The end-user documentation included with the redistribution,
073: * if any, must include the following acknowledgment:
074: * "This product includes software developed by
075: * CoolServlets.com (http://www.coolservlets.com)."
076: * Alternately, this acknowledgment may appear in the software itself,
077: * if and wherever such third-party acknowledgments normally appear.
078: *
079: * 4. The names "Jive" and "CoolServlets.com" must not be used to
080: * endorse or promote products derived from this software without
081: * prior written permission. For written permission, please
082: * contact webmaster@coolservlets.com.
083: *
084: * 5. Products derived from this software may not be called "Jive",
085: * nor may "Jive" appear in their name, without prior written
086: * permission of CoolServlets.com.
087: *
088: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
089: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
090: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
091: * DISCLAIMED. IN NO EVENT SHALL COOLSERVLETS.COM OR
092: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
093: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
094: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
095: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
096: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
097: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
098: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
099: * SUCH DAMAGE.
100: * ====================================================================
101: *
102: * This software consists of voluntary contributions made by many
103: * individuals on behalf of CoolServlets.com. For more information
104: * on CoolServlets.com, please see <http://www.coolservlets.com>.
105: */package com.Yasna.forum.database;
106:
107: import com.Yasna.forum.PropertyManager;
108:
109: import java.util.HashMap;
110: import java.sql.*;
111:
112: /**
113: * Manages sequences of unique ID's that get stored in the database. Database
114: * support for sequences varies widely; some don't support them at all. So,
115: * we handle unique ID generation with synchronized counters.<p>
116: *
117: * Selecting the initial ID for each sequence is trivial: we simply query the
118: * database to get the last highest unique ID, and then add 1 to that.<p>
119: *
120: * This method only works if a single instance of Yazd is pointed at a database.
121: * Otherwise, the unique ID's will stop being unique. :) A refined class that
122: * deals with this is coming soon.
123: */
124: public class DbSequenceManager {
125:
126: private static final String NEXT_FORUM_ID = "SELECT max(forumID) FROM yazdForum";
127: private static final String NEXT_THREAD_ID = "SELECT max(threadID) FROM yazdThread";
128: private static final String NEXT_MESSAGE_ID = "SELECT max(messageID) FROM yazdMessage";
129: private static final String NEXT_GROUP_ID = "SELECT max(groupID) FROM yazdGroup";
130: private static final String NEXT_USER_ID = "SELECT max("
131: + SystemProperty.getProperty("User.Column.UserID")
132: + ") FROM " + SystemProperty.getProperty("User.Table");
133: private static final String NEXT_CATEGORY_ID = "SELECT max(categoryID) FROM yazdCategory";
134: private static final String NEXT_FORUM_GROUP_ID = "SELECT max(forumGroupID) FROM yazdForumGroup";
135: /**
136: * Singleton type access to the class.
137: */
138: private static DbSequenceManager sequenceManager = null;
139:
140: /**
141: * Lock so that we can synchronize during initialization.
142: */
143: private static Object initLock = new Object();
144:
145: /**
146: * Returns the next ID of the specified type.
147: *
148: * @param type the type of unique ID.
149: * @return the next unique ID of the specified type.
150: */
151: public static int nextID(String type) {
152: if (sequenceManager == null) {
153: synchronized (initLock) {
154: if (sequenceManager == null) {
155: sequenceManager = new DbSequenceManager();
156: }
157: }
158: }
159: return sequenceManager.nextUniqueID(type);
160: }
161:
162: private HashMap uniqueIDCounters;
163: private HashMap keys;
164:
165: /**
166: * Creates a new DbSequenceManager and initializes all of the counters.
167: */
168: public DbSequenceManager() {
169: keys = new HashMap();
170: keys.put("Forum", NEXT_FORUM_ID);
171: keys.put("ForumThread", NEXT_THREAD_ID);
172: keys.put("ForumMessage", NEXT_MESSAGE_ID);
173: keys.put("Group", NEXT_GROUP_ID);
174: keys.put("User", NEXT_USER_ID);
175: keys.put("Category", NEXT_CATEGORY_ID);
176: keys.put("ForumGroup", NEXT_FORUM_GROUP_ID);
177:
178: uniqueIDCounters = new HashMap();
179:
180: //Forum counter.
181: uniqueIDCounters.put("Forum", new Counter(
182: getNextDbID((String) keys.get("Forum"))));
183: //ForumThread counter.
184: uniqueIDCounters.put("ForumThread", new Counter(
185: getNextDbID((String) keys.get("ForumThread"))));
186: //ForumMessage counter.
187: uniqueIDCounters.put("ForumMessage", new Counter(
188: getNextDbID((String) keys.get("ForumMessage"))));
189: //Group counter.
190: uniqueIDCounters.put("Group", new Counter(
191: getNextDbID((String) keys.get("Group"))));
192: //User counter.
193: uniqueIDCounters.put("User", new Counter(
194: getNextDbID((String) keys.get("User"))));
195: uniqueIDCounters.put("Category", new Counter(
196: getNextDbID((String) keys.get("Category"))));
197: uniqueIDCounters.put("ForumGroup", new Counter(
198: getNextDbID((String) keys.get("ForumGroup"))));
199: }
200:
201: /**
202: * Provides the next available unique ID for a particular object type.
203: * Essentially this provides for the functionality of an auto-increment
204: * database field. Valid counter names are Forum, ForumThread, ForumMessage,
205: * Group, and User.
206: * <p>
207: * Those that are integrating Yazd into existing tables should be sure
208: * that the table names match up so that the correct starting unique
209: * id can be determined.
210: */
211: public int nextUniqueID(String counterName) {
212: if (Boolean.valueOf(
213: PropertyManager.getProperty("Sequence.UseDatabase"))
214: .booleanValue()) {
215: return getNextDbID((String) keys.get(counterName)) + 1;
216: } else {
217: Counter counter = (Counter) uniqueIDCounters
218: .get(counterName);
219: return counter.next();
220: }
221: }
222:
223: /**
224: * Do a lookup to see what the next available unique ID is for a
225: * particular table. Yazd uses the convention of always making the name of
226: * the column that holds the unique id be called id, so this works.
227: */
228: private int getNextDbID(String query) {
229: int currentID = 0;
230: Connection con = null;
231: PreparedStatement pstmt = null;
232:
233: try {
234: con = DbConnectionManager.getConnection();
235: pstmt = con.prepareStatement(query);
236: ResultSet rs = pstmt.executeQuery();
237: rs.next();
238: currentID = rs.getInt(1);
239: } catch (Exception sqle) {
240: System.err
241: .println("Error in DbSequenceManager:getNextDbID()-"
242: + sqle);
243: sqle.printStackTrace();
244: } finally {
245: try {
246: pstmt.close();
247: } catch (Exception e) {
248: e.printStackTrace();
249: }
250: try {
251: con.close();
252: } catch (Exception e) {
253: e.printStackTrace();
254: }
255: }
256: //If the table is empty, start with id 0
257: if (currentID < 0) {
258: currentID = 0;
259: }
260: return currentID;
261: }
262:
263: /**
264: * Internal class to keep track of the current count of a unique id.
265: */
266: private final class Counter {
267:
268: private int count;
269:
270: public Counter(int currentCount) {
271: count = currentCount;
272: }
273:
274: public final synchronized int next() {
275: return (++count);
276: }
277: }
278: }
|