1 package org.apache.ojb.broker.util.sequence;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.apache.commons.lang.SystemUtils;
22 import org.apache.ojb.broker.Identity;
23 import org.apache.ojb.broker.OptimisticLockException;
24 import org.apache.ojb.broker.PersistenceBroker;
25 import org.apache.ojb.broker.PersistenceBrokerFactory;
26 import org.apache.ojb.broker.metadata.FieldDescriptor;
27 import org.apache.ojb.broker.util.ObjectModification;
28 import org.apache.ojb.broker.util.logging.Logger;
29 import org.apache.ojb.broker.util.logging.LoggerFactory;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public class SequenceManagerHighLowImpl extends AbstractSequenceManager
117 {
118 private static Logger log = LoggerFactory.getLogger(SequenceManagerHighLowImpl.class);
119
120
121
122 private static final String GLOBAL_SEQUENCE_NAME = "global - default sequence name";
123 public static final String PROPERTY_GRAB_SIZE = "grabSize";
124 public static final String PROPERTY_GLOBAL_SEQUENCE_ID = "globalSequenceId";
125 public static final String PROPERTY_GLOBAL_SEQUENCE_START = "globalSequenceStart";
126
127 protected static Map sequencesDBMap = new HashMap();
128
129 protected boolean useGlobalSequenceIdentities;
130 protected int grabSize;
131 protected long sequenceStart;
132 protected int attempts;
133
134 public SequenceManagerHighLowImpl(PersistenceBroker broker)
135 {
136 super(broker);
137 Long start = SequenceManagerHelper.getSeqStart(getConfigurationProperties());
138 sequenceStart = start != null ? start.longValue() : 1;
139 grabSize = Integer.parseInt(getConfigurationProperty(PROPERTY_GRAB_SIZE, "20"));
140 useGlobalSequenceIdentities = Boolean.getBoolean(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_ID, "false"));
141
142 long globalSequenceStart = Long.parseLong(getConfigurationProperty(PROPERTY_GLOBAL_SEQUENCE_START, "1"));
143 if(useGlobalSequenceIdentities && globalSequenceStart > sequenceStart)
144 {
145 sequenceStart = globalSequenceStart;
146 }
147 }
148
149 protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
150 {
151 HighLowSequence seq;
152 String sequenceName = buildSequenceName(field);
153 synchronized (SequenceManagerHighLowImpl.class)
154 {
155
156 seq = getSequence(sequenceName);
157
158 if (seq == null)
159 {
160
161 seq = getSequence(getBrokerForClass(), field, sequenceName);
162 addSequence(sequenceName, seq);
163 }
164
165
166 long id = seq.getNextId();
167
168 if (id == 0)
169 {
170 seq = getSequence(getBrokerForClass(), field, sequenceName);
171
172 addSequence(sequenceName, seq);
173 id = seq.getNextId();
174 if (id == 0)
175 {
176
177 removeSequence(sequenceName);
178 throw new SequenceManagerException("Sequence generation failed: " +
179 SystemUtils.LINE_SEPARATOR + "Sequence: " + seq +
180 ". Unable to build new ID, id was always 0." +
181 SystemUtils.LINE_SEPARATOR + "Thread: " + Thread.currentThread() +
182 SystemUtils.LINE_SEPARATOR + "PB: " + getBrokerForClass());
183 }
184 }
185 return id;
186 }
187 }
188
189
190
191
192
193
194
195
196 private HighLowSequence getSequence(String sequenceName)
197 {
198 HighLowSequence result = null;
199
200 Map mapForDB = (Map) sequencesDBMap.get(getBrokerForClass()
201 .serviceConnectionManager().getConnectionDescriptor().getJcdAlias());
202 if(mapForDB != null)
203 {
204 result = (HighLowSequence) mapForDB.get(sequenceName);
205 }
206 return result;
207 }
208
209
210
211
212
213
214 private void addSequence(String sequenceName, HighLowSequence seq)
215 {
216
217 String jcdAlias = getBrokerForClass()
218 .serviceConnectionManager().getConnectionDescriptor().getJcdAlias();
219 Map mapForDB = (Map) sequencesDBMap.get(jcdAlias);
220 if(mapForDB == null)
221 {
222 mapForDB = new HashMap();
223 }
224 mapForDB.put(sequenceName, seq);
225 sequencesDBMap.put(jcdAlias, mapForDB);
226 }
227
228
229
230
231
232
233 protected void removeSequence(String sequenceName)
234 {
235
236 Map mapForDB = (Map) sequencesDBMap.get(getBrokerForClass()
237 .serviceConnectionManager().getConnectionDescriptor().getJcdAlias());
238 if(mapForDB != null)
239 {
240 synchronized(SequenceManagerHighLowImpl.class)
241 {
242 mapForDB.remove(sequenceName);
243 }
244 }
245 }
246
247 protected HighLowSequence getSequence(PersistenceBroker brokerForSequence,
248 FieldDescriptor field,
249 String sequenceName) throws SequenceManagerException
250 {
251 HighLowSequence newSequence = null;
252 PersistenceBroker internBroker = null;
253 try
254 {
255
256
257
258
259
260
261
262
263
264 internBroker = PersistenceBrokerFactory.createPersistenceBroker(brokerForSequence.getPBKey());
265 internBroker.beginTransaction();
266
267 newSequence = lookupStoreSequence(internBroker, field, sequenceName);
268
269 internBroker.commitTransaction();
270
271 if (log.isDebugEnabled()) log.debug("new sequence was " + newSequence);
272 }
273 catch(Exception e)
274 {
275 log.error("Can't lookup new HighLowSequence for field "
276 + (field != null ? field.getAttributeName() : null)
277 + " using sequence name " + sequenceName, e);
278 if(internBroker != null && internBroker.isInTransaction()) internBroker.abortTransaction();
279 throw new SequenceManagerException("Can't build new sequence", e);
280 }
281 finally
282 {
283 attempts = 0;
284 if (internBroker != null) internBroker.close();
285 }
286 return newSequence;
287 }
288
289 protected HighLowSequence lookupStoreSequence(PersistenceBroker broker, FieldDescriptor field, String seqName)
290 {
291 HighLowSequence newSequence;
292 boolean needsInsert = false;
293
294 Identity oid = broker.serviceIdentity().buildIdentity(HighLowSequence.class, seqName);
295
296 newSequence = (HighLowSequence) broker.getObjectByIdentity(oid);
297
298
299 if (newSequence == null)
300 {
301 if (log.isDebugEnabled())
302 {
303 log.debug("sequence for field " + field + " not found in db, store new HighLowSequence");
304 }
305
306
307
308
309 long maxKey = getMaxKeyForSequence(getBrokerForClass(), field);
310
311 newSequence = newSequenceObject(seqName, field);
312 newSequence.setMaxKey(maxKey);
313 needsInsert = true;
314 }
315
316
317 if(newSequence.getMaxKey() < sequenceStart)
318 {
319 newSequence.setMaxKey(sequenceStart);
320 }
321
322
323 newSequence.setGrabSize(grabSize);
324
325
326 newSequence.grabNextKeySet();
327
328
329 try
330 {
331 if(needsInsert) broker.store(newSequence, ObjectModification.INSERT);
332 else broker.store(newSequence, ObjectModification.UPDATE);
333 }
334 catch (OptimisticLockException e)
335 {
336
337 if(attempts < 5)
338 {
339 log.info("OptimisticLockException was thrown, will try again to store sequence. Sequence was "+newSequence);
340 attempts++;
341 newSequence = lookupStoreSequence(broker, field, seqName);
342 }
343 else throw e;
344 }
345 return newSequence;
346 }
347
348 protected HighLowSequence newSequenceObject(String sequenceName,
349 FieldDescriptor field)
350 {
351 HighLowSequence seq = new HighLowSequence();
352 seq.setName(sequenceName);
353 seq.setGrabSize(grabSize);
354 return seq;
355 }
356
357 protected long getMaxKeyForSequence(PersistenceBroker broker,
358 FieldDescriptor field)
359 {
360 long maxKey;
361 if (useGlobalSequenceIdentities)
362 {
363 maxKey = sequenceStart;
364 }
365 else
366 {
367
368
369
370 maxKey = SequenceManagerHelper.getMaxForExtent(broker, field);
371
372 maxKey = sequenceStart > maxKey ? sequenceStart : maxKey;
373 }
374 return maxKey;
375 }
376
377 private String buildSequenceName(FieldDescriptor field) throws SequenceManagerException
378 {
379 String seqName;
380 if (useGlobalSequenceIdentities)
381 {
382 seqName = GLOBAL_SEQUENCE_NAME;
383 }
384 else
385 {
386 seqName = calculateSequenceName(field);
387 }
388 return seqName;
389 }
390 }