001: package org.enhydra.dm.util;
002:
003: import java.math.BigDecimal;
004: import java.util.HashMap;
005: import java.util.Map;
006: import java.util.Properties;
007:
008: import javax.naming.InitialContext;
009: import javax.transaction.Status;
010: import javax.transaction.TransactionManager;
011:
012: import org.enhydra.dm.api.exceptions.BaseException;
013: import org.enhydra.dm.data.CounterDO;
014: import org.enhydra.dm.data.CounterQuery;
015:
016: /**
017: * Numerator represents a <i>toolbox</i> for DODS based modules. There are static
018: * methods only in charge of some specific task.
019: *
020: */
021: public class Numerator {
022:
023: private static final String COUNTER_CACHE_PREFFIX = "Numerator.";
024:
025: private static final String COUNTER_CACHE_POSTFIX = ".CacheSize";
026:
027: private static Properties props;
028:
029: private static Map counterCachesSizes = new HashMap();
030:
031: private static Map counterCachesMax = new HashMap();
032:
033: private static Map counterCachesCurrent = new HashMap();
034:
035: private static Map counterCachesNext = new HashMap();
036:
037: private static final long DEFAULT_CACHE_SIZE = 100;
038:
039: private static int allocTryCount = 50;
040:
041: private static int cache_size = 100;
042:
043: private static String userTransactionJNDIPath = "java:comp/env/UserTransaction";
044:
045: // private constructor to prevent instantiate of Counter
046: private Numerator() {
047: }
048:
049: /**
050: * Gets next value for counter named in objectName parameter if counter exists,
051: * otherwise new one will be started with value 1.
052: *
053: * @param objectName name of a counter
054: * @return next value available for the counter
055: * @exception Exception thrown if counter value cannot be acquired
056: */
057: public static synchronized BigDecimal getNext(String objectName)
058: throws Exception {
059:
060: if (objectName == null) {
061: throw new Exception("Object name parameter can't be null");
062: }
063: try {
064: if (counterCachesNext.get(objectName) == null
065: || counterCachesMax.get(objectName) == null
066: || counterCachesNext.get(objectName).equals(
067: counterCachesMax.get(objectName))) {
068: updateCaches(objectName);
069: }
070: counterCachesCurrent.put(objectName, counterCachesNext
071: .get(objectName)); // next
072: // free
073: counterCachesNext.put(objectName,
074: ((BigDecimal) counterCachesNext.get(objectName))
075: .add(new BigDecimal("1")));
076: return (BigDecimal) counterCachesCurrent.get(objectName);
077: } catch (Exception e) {
078: System.err
079: .println("Counter Id Allocator failed to allocate object id.");
080: throw e;
081: }
082: }
083:
084: private static void updateCaches(String objectName)
085: throws Exception {
086: javax.transaction.Transaction mainOne = null;
087: TransactionManager tm = null;
088: // try it 50 times
089: try {
090: tm = (TransactionManager) new InitialContext()
091: .lookup(userTransactionJNDIPath);
092: if (Status.STATUS_NO_TRANSACTION != tm.getStatus()) {
093: mainOne = tm.suspend();
094: }
095:
096: } catch (Exception e) {
097: System.err.println("Can't allocate Id for object table "
098: + objectName);
099: throw e;
100: }
101: for (int iTry = 0; iTry < allocTryCount; iTry++) {
102: try {
103: tm.begin();
104: CounterQuery qryCounter = new CounterQuery();
105:
106: qryCounter.requireUniqueInstance();
107: qryCounter.setQueryName(objectName);
108: CounterDO doCounter = qryCounter.getNextDO();
109:
110: BigDecimal dbNext;
111: if (doCounter == null) {
112: // insert new Counter
113: doCounter = CounterDO.createVirgin();
114: doCounter.setName(objectName);
115: dbNext = new BigDecimal("1");
116: } else {
117: // increment existing Counter
118: dbNext = doCounter.getThe_number();
119: }
120: BigDecimal dbLast = dbNext;
121: dbNext = dbNext.add(BigDecimal
122: .valueOf(getCacheSize(objectName)));
123:
124: doCounter.setThe_number(dbNext);
125: doCounter.save();
126: tm.commit();
127:
128: counterCachesNext.put(objectName, dbLast);
129: counterCachesMax.put(objectName, dbNext);
130:
131: if (null != mainOne) {
132: tm.resume(mainOne);
133: }
134: return;
135: } catch (Exception e) {
136: try {
137: if (Status.STATUS_NO_TRANSACTION != tm.getStatus()) {
138: tm.rollback();
139: }
140: } catch (Exception _) {
141: }
142: }
143: }
144: // this line should normaly never be executed
145: throw new Exception("Can't allocate Id for object table "
146: + objectName);
147: }
148:
149: public static String getUserTransactionJNDIPath() {
150: return userTransactionJNDIPath;
151: }
152:
153: public static void setUserTransactionJNDIPath(
154: String userTransactionJNDIPath) {
155: Numerator.userTransactionJNDIPath = userTransactionJNDIPath;
156: }
157:
158: public static int getAllocTryCount() {
159: return allocTryCount;
160: }
161:
162: public static void setAllocTryCount(int allocTryCount) {
163: Numerator.allocTryCount = allocTryCount;
164: }
165:
166: public static int getCache_size() {
167: return cache_size;
168: }
169:
170: public static void setCache_size(int cache_size) {
171: Numerator.cache_size = cache_size;
172: }
173:
174: /**
175: * Configure method that read parameters from Properties
176: *
177: * @param properties
178: * @throws BaseException
179: */
180: public static void configure(Properties properties)
181: throws BaseException {
182:
183: Numerator.props = properties;
184:
185: };
186:
187: private static long getCacheSize(String objectName) {
188: long cacheSize = -1;
189: Object cs = counterCachesSizes.get(objectName);
190: if (cs == null) {
191: String propName = COUNTER_CACHE_PREFFIX + objectName
192: + COUNTER_CACHE_POSTFIX;
193: String cSize = Numerator.props.getProperty(propName);
194: if (cSize != null) {
195: try {
196: cacheSize = Long.parseLong(cSize);
197: if (cacheSize <= 0) {
198: cacheSize = -1;
199: System.err.println("Wrong value for "
200: + objectName + " cache size");
201: }
202: } catch (Exception ex) {
203: cacheSize = -1;
204: System.err.println("Wrong value for " + objectName
205: + " cache size");
206: }
207: }
208: if (cacheSize == -1) {
209:
210: cacheSize = DEFAULT_CACHE_SIZE;
211:
212: }
213: counterCachesSizes.put(objectName, new Long(cacheSize));
214: } else {
215: cacheSize = ((Long) cs).longValue();
216: }
217: return cacheSize;
218: }
219:
220: }
|