001: /**********************************************************************
002: Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015:
016: Contributors:
017: ...
018: **********************************************************************/package org.jpox.store.poid;
019:
020: import java.util.Properties;
021:
022: import org.jpox.exceptions.JPOXDataStoreException;
023: import org.jpox.util.JPOXLogger;
024: import org.jpox.util.Localiser;
025:
026: /**
027: * Abstract POID generator.
028: *
029: * @version $Revision: 1.9 $
030: */
031: public abstract class AbstractPoidGenerator implements PoidGenerator {
032: /** Localisation of messages */
033: protected static final Localiser LOCALISER = Localiser
034: .getInstance("org.jpox.store.Localisation");
035:
036: /** Symbolic name for the sequence. */
037: protected String name;
038:
039: /** Properties controlling the generator behaviour. */
040: protected Properties properties;
041:
042: /** Allocation size */
043: protected int allocationSize = 5;
044:
045: /** Initial value (of the first id). */
046: protected int initialValue = 0;
047:
048: /** The current block of ids that have been reserved. */
049: protected PoidBlock poidBlock;
050:
051: /**
052: * Constructor.
053: * JPOX Core will pass the following properties (as a minimum) through this constructor.
054: * <ul>
055: * <li>class-name : Name of the class whose object is being inserted.</li>
056: * <li>root-class-name : Name of the root class in this inheritance tree</li>
057: * <li>field-name : Name of the field with the strategy (unless datastore identity field)</li>
058: * <li>catalog-name : Catalog of the table (if specified)</li>
059: * <li>schema-name : Schema of the table (if specified)</li>
060: * <li>table-name : Name of the root table for this inheritance tree (containing the field).</li>
061: * <li>column-name : Name of the column in the table (for the field)</li>
062: * <li>sequence-name : Name of the sequence (if specified in MetaData as "sequence)</li>
063: * </ul>
064: *
065: * @param name Symbolic name for this generator
066: * @param props Properties controlling the behaviour of the generator (or null if not required).
067: */
068: public AbstractPoidGenerator(String name, Properties props) {
069: this .name = name;
070: this .properties = props;
071: }
072:
073: /**
074: * Accessor for the storage class for POIDs generated with this generator.
075: * @return Storage class (e.g Long.class)
076: */
077: public static Class getStorageClass() {
078: return Long.class;
079: }
080:
081: /**
082: * Accessor for the symbolic name for this generator.
083: * @return Symbolic name for the generator.
084: */
085: public String getName() {
086: return name;
087: }
088:
089: /**
090: * Get next value from the reserved block of values.
091: * @return The next value
092: */
093: public synchronized Object next() {
094: // If the current block of ids is null or empty get a new one
095: if (poidBlock == null || !poidBlock.hasNext()) {
096: // No more elements left in the block so replace it with a new one
097: poidBlock = obtainPoidBlock();
098: }
099:
100: return poidBlock.next().getOid();
101: }
102:
103: /**
104: * Accessor for the current value allocated.
105: * Returns null if none are allocated
106: * @return The current value
107: */
108: public synchronized Object current() {
109: if (poidBlock == null) {
110: return null;
111: }
112: return poidBlock.current().getOid();
113: }
114:
115: /**
116: * Accessor for the next element in the sequence as a long.
117: * @return The next element
118: * @throws JPOXDataStoreException Thrown if not numeric
119: */
120: public long nextValue() {
121: return getLongValueForObject(next());
122: }
123:
124: /**
125: * Accessor for the current element in the sequence as a long.
126: * @return The current element
127: * @throws JPOXDataStoreException Thrown if not numeric
128: */
129: public long currentValue() {
130: return getLongValueForObject(current());
131: }
132:
133: /**
134: * Convenience method to convert an object id into a long.
135: * Throws JPOXDataStoreException if the id is not numeric.
136: * @param oid The id
137: * @return The long value
138: * @throws JPOXDataStoreException Thrown if not numeric
139: */
140: private long getLongValueForObject(Object oid) {
141: if (oid instanceof Long) {
142: return ((Long) oid).longValue();
143: } else if (oid instanceof Integer) {
144: return ((Integer) oid).longValue();
145: } else if (oid instanceof Short) {
146: return ((Short) oid).longValue();
147: }
148:
149: throw new JPOXDataStoreException(LOCALISER.msg("040009", name));
150: }
151:
152: /**
153: * Method to allocate a number of values into the block.
154: * If the block already exists and has remaining values, the
155: * additional values are added to the block.
156: * @param additional The number to allocate
157: */
158: public synchronized void allocate(int additional) {
159: if (poidBlock == null) {
160: // No existing block so replace the existing block
161: poidBlock = obtainPoidBlock(additional);
162: } else {
163: // Existing block so append to it
164: poidBlock.addBlock(obtainPoidBlock(additional));
165: }
166: }
167:
168: /**
169: * Get a new PoidBlock with the default number of ids.
170: * @return the PoidBlock
171: */
172: protected PoidBlock obtainPoidBlock() {
173: // -1 here implies just use the default reserveBlock on the generator
174: return obtainPoidBlock(-1);
175: }
176:
177: /**
178: * Get a new PoidBlock with the specified number of ids.
179: * @param number The number of additional ids required
180: * @return the PoidBlock
181: */
182: protected PoidBlock obtainPoidBlock(int number) {
183: PoidBlock block = null;
184:
185: // Try getting the block
186: boolean repository_exists = true;
187: try {
188: try {
189: if (number < 0) {
190: block = reserveBlock();
191: } else {
192: block = reserveBlock(number);
193: }
194: } catch (PoidException poidex) {
195: JPOXLogger.POID.info(LOCALISER.msg("040003", poidex
196: .getMessage()));
197:
198: // attempt to obtain the block of unique identifiers is invalid
199: if (requiresRepository()) {
200: repository_exists = false;
201: } else {
202: throw poidex;
203: }
204: } catch (RuntimeException ex) {
205: //exceptions cached by the poid should be enclosed in PoidException
206: //when the exceptions are not catched exception by poid, we give a new try
207: //in creating the repository
208: JPOXLogger.POID.info(LOCALISER.msg("040003", ex
209: .getMessage()));
210: // attempt to obtain the block of unique identifiers is invalid
211: if (requiresRepository()) {
212: repository_exists = false;
213: } else {
214: throw ex;
215: }
216: }
217: } finally {
218: }
219:
220: // If repository didn't exist, try creating it and then get block
221: if (!repository_exists) {
222: try {
223: JPOXLogger.POID.info(LOCALISER.msg("040005"));
224: if (!createRepository()) {
225: throw new PoidException(LOCALISER.msg("040002"));
226: } else {
227: if (number < 0) {
228: block = reserveBlock();
229: } else {
230: block = reserveBlock(number);
231: }
232: }
233: } finally {
234: }
235: }
236: return block;
237: }
238:
239: /**
240: * Method to reserve a default sized block of identities.
241: * @return The reserved block
242: */
243: protected PoidBlock reserveBlock() {
244: return reserveBlock(allocationSize);
245: }
246:
247: /**
248: * Method to reserve a blobk of "size" ids.
249: * @param size Number of ids to reserve
250: * @return The allocated block
251: */
252: protected abstract PoidBlock reserveBlock(long size);
253:
254: /**
255: * Indicator for whether the generator requires its own repository.
256: * AbstractPoidGenerator returns false and this should be overridden by all
257: * generators requiring a repository.
258: * @return Whether a repository is required.
259: */
260: protected boolean requiresRepository() {
261: return false;
262: }
263:
264: /**
265: * Method to create any needed repository for the ids.
266: * AbstractPoidGenerator just returns true and should be overridden by any
267: * implementing generator requiring its own repository.
268: * @return If all is ready for use
269: */
270: protected boolean createRepository() {
271: // Do nothing - to be overridden by generators that want to create a repository for their ids
272: return true;
273: }
274: }
|