001 package org.apache.ojb.broker.util.sequence;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import org.apache.ojb.broker.PersistenceBroker;
019 import org.apache.ojb.broker.metadata.FieldDescriptor;
020
021 import java.util.HashMap;
022 import java.util.Map;
023
024 /**
025 * <p>
026 * Very fast in memory sequence manager implementation, only the first
027 * time an id was requested for a class, the manager query the database
028 * for the max id in requested column - all following request were
029 * performed in memory.
030 * </p>
031 * <b>Limitations:</b>
032 * <ul type="disc">
033 * <li>do not use in clustered environments</li>
034 * <li>do not use if other applications generate id's for objects</li>
035 * </ul>
036 *
037 *
038 *
039 * <p>
040 * Implementation configuration properties:
041 * </p>
042 *
043 * <table cellspacing="2" cellpadding="2" border="3" frame="box">
044 * <tr>
045 * <td><strong>Property Key</strong></td>
046 * <td><strong>Property Values</strong></td>
047 * </tr>
048 * <tr>
049 * <td>seq.start</td>
050 * <td>
051 * Set the start index of used sequences (e.g. set 100000, id generation starts with 100001).
052 * Default start index is <em>1</em>.
053 * </td>
054 * </tr>
055 * <tr>
056 * <td>autoNaming</td>
057 * <td>
058 * Default was 'true'. If set 'true' OJB try to build a
059 * sequence name automatic if none found in field-descriptor
060 * and set this generated name as <code>sequence-name</code>
061 * in field-descriptor. If set 'false' OJB throws an exception
062 * if none sequence name was found in field-descriptor.
063 * </td>
064 * </tr>
065 * <tr>
066 * <td>sequenceStart</td>
067 * <td>
068 * <em>Deprecated, use property 'seq.start'.</em> Set the start index
069 * of used sequences (e.g. set 100000, id generation starts with 100001).
070 * Default start index is <em>1</em>.
071 * </td>
072 * </tr>
073 * </table>
074 *
075 * <br/>
076 * <br/>
077 * <br/>
078 *
079 * @see org.apache.ojb.broker.util.sequence.SequenceManager
080 * @see org.apache.ojb.broker.util.sequence.SequenceManagerFactory
081 * @see org.apache.ojb.broker.util.sequence.SequenceManagerHelper
082 *
083 *
084 * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
085 * @version $Id: SequenceManagerInMemoryImpl.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
086 */
087 public class SequenceManagerInMemoryImpl extends AbstractSequenceManager
088 {
089 protected static Map sequencesDBMap = new HashMap();
090 private long sequenceStart;
091
092 public SequenceManagerInMemoryImpl(PersistenceBroker broker)
093 {
094 super(broker);
095 Long start = SequenceManagerHelper.getSeqStart(getConfigurationProperties());
096 sequenceStart = start != null ? start.longValue() : 1;
097 }
098
099 protected long getUniqueLong(FieldDescriptor field) throws SequenceManagerException
100 {
101 String seqName = calculateSequenceName(field);
102 // we have to be threadsafe
103 synchronized (SequenceManagerInMemoryImpl.class)
104 {
105 // get id for given seq name
106 Long currentId = getSequence(seqName);
107 // check - first time we search for sequence name
108 if (currentId == null)
109 {
110 long maxKey = SequenceManagerHelper.getMaxForExtent(getBrokerForClass(), field);
111 maxKey = sequenceStart > maxKey ? sequenceStart : maxKey;
112 currentId = new Long(maxKey);
113 }
114 currentId = new Long(currentId.longValue() + 1);
115 // put new id back to map
116 addSequence(seqName, currentId);
117 return currentId.intValue();
118 }
119 }
120
121 /**
122 * Returns last used sequence value or <code>null</code> if no sequence
123 * was add for given sequence name.
124 *
125 * @param sequenceName Name of the sequence.
126 * @return Last used sequence value or <code>null</code>
127 */
128 private Long getSequence(String sequenceName)
129 {
130 Long result = null;
131 // now lookup the sequence map for calling DB
132 Map mapForDB = (Map) sequencesDBMap.get(getBrokerForClass()
133 .serviceConnectionManager().getConnectionDescriptor().getJcdAlias());
134 if(mapForDB != null)
135 {
136 result = (Long) mapForDB.get(sequenceName);
137 }
138 return result;
139 }
140
141 /**
142 * Add new sequence value for sequence name.
143 * @param sequenceName Name of the sequence.
144 * @param seq The sequence value to add.
145 */
146 private void addSequence(String sequenceName, Long seq)
147 {
148 // lookup the sequence map for calling DB
149 String jcdAlias = getBrokerForClass()
150 .serviceConnectionManager().getConnectionDescriptor().getJcdAlias();
151 Map mapForDB = (Map) sequencesDBMap.get(jcdAlias);
152 if(mapForDB == null)
153 {
154 mapForDB = new HashMap();
155 }
156 mapForDB.put(sequenceName, seq);
157 sequencesDBMap.put(jcdAlias, mapForDB);
158 }
159
160 /**
161 * Remove the sequence for given sequence name.
162 *
163 * @param sequenceName Name of the sequence to remove.
164 */
165 protected void removeSequence(String sequenceName)
166 {
167 // lookup the sequence map for calling DB
168 Map mapForDB = (Map) sequencesDBMap.get(getBrokerForClass()
169 .serviceConnectionManager().getConnectionDescriptor().getJcdAlias());
170 if(mapForDB != null)
171 {
172 synchronized(SequenceManagerInMemoryImpl.class)
173 {
174 mapForDB.remove(sequenceName);
175 }
176 }
177 }
178 }