001 package org.apache.ojb.broker.metadata;
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.PersistenceBrokerException;
019 import org.apache.ojb.broker.locking.IsolationLevels;
020 import org.apache.ojb.broker.util.logging.Logger;
021 import org.apache.ojb.broker.util.logging.LoggerFactory;
022 import org.apache.ojb.broker.util.ClassHelper;
023 import org.xml.sax.Attributes;
024 import org.xml.sax.SAXException;
025 import org.xml.sax.SAXParseException;
026 import org.xml.sax.helpers.DefaultHandler;
027
028 import java.util.ArrayList;
029 import java.util.Iterator;
030 import java.util.List;
031
032 /**
033 * The handler catches Parsing events raised by the xml-parser
034 * and builds up the {@link ConnectionRepository} that is used
035 * within the OJB.
036 * <p>
037 * TODO: Reading of metadata are split in two classes {@link RepositoryXmlHandler} and
038 * {@link ConnectionDescriptorXmlHandler}. Thus we should only read relevant tags in this
039 * classes. In further versions we should split repository.dtd in two parts, one for connetion
040 * metadata, one for pc object metadata.
041 * </p>
042 *
043 * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
044 * @version $Id: ConnectionDescriptorXmlHandler.java,v 1.1 2007-08-24 22:17:29 ewestfal Exp $
045 */
046 public class ConnectionDescriptorXmlHandler
047 extends DefaultHandler
048 implements RepositoryElements, IsolationLevels
049 {
050 private Logger logger = LoggerFactory.getLogger(ConnectionDescriptorXmlHandler.class);
051
052 private ConnectionRepository con_repository;
053 private JdbcConnectionDescriptor m_CurrentJCD;
054 private SequenceDescriptor currentSequenceDescriptor;
055 private List conDesList;
056 private AttributeContainer currentAttributeContainer;
057 private boolean defaultConnectionFound = false;
058
059 /**
060 * All known xml tags are kept in this table.
061 * The tags table allows lookup from literal to id
062 * and from id to literal.
063 */
064 private RepositoryTags tags = RepositoryTags.getInstance();
065
066 /**
067 * build a handler that fills the given repository
068 * from an XML file.
069 */
070 public ConnectionDescriptorXmlHandler(ConnectionRepository cr)
071 {
072 if (cr != null)
073 {
074 con_repository = cr;
075 conDesList = new ArrayList();
076 }
077 else
078 {
079 throw new MetadataException("Given ConnectionRepository argument was null");
080 }
081 }
082
083 /**
084 * startDocument callback, nothing to do here.
085 */
086 public void startDocument()
087 {
088 logger.debug("**** startDoc ****");
089 }
090
091 /**
092 * Here we overgive the found descriptors to {@link ConnectionRepository}.
093 */
094 public void endDocument()
095 {
096 logger.debug("**** endDoc ****");
097 for (Iterator iterator = conDesList.iterator(); iterator.hasNext();)
098 {
099 JdbcConnectionDescriptor jcd = (JdbcConnectionDescriptor) iterator.next();
100 con_repository.addDescriptor(jcd);
101 }
102 }
103
104 /**
105 * startElement callback.
106 * Only some Elements need special start operations.
107 * @throws MetadataException indicating mapping errors
108 */
109 public void startElement(String uri, String name, String qName, Attributes atts)
110 {
111 boolean isDebug = logger.isDebugEnabled();
112 try
113 {
114 switch (getLiteralId(qName))
115 {
116 case JDBC_CONNECTION_DESCRIPTOR:
117 {
118 if (isDebug) logger.debug(" > " + tags.getTagById(JDBC_CONNECTION_DESCRIPTOR));
119 JdbcConnectionDescriptor newJcd = new JdbcConnectionDescriptor();
120 currentAttributeContainer = newJcd;
121
122 conDesList.add(newJcd);
123 m_CurrentJCD = newJcd;
124
125 // set the jcdAlias attribute
126 String jcdAlias = atts.getValue(tags.getTagById(JCD_ALIAS));
127 if (isDebug) logger.debug(" " + tags.getTagById(JCD_ALIAS) + ": " + jcdAlias);
128 m_CurrentJCD.setJcdAlias(jcdAlias);
129
130 // set the jcdAlias attribute
131 String defaultConnection = atts.getValue(tags.getTagById(DEFAULT_CONNECTION));
132 if (isDebug) logger.debug(" " + tags.getTagById(DEFAULT_CONNECTION) + ": " + defaultConnection);
133 m_CurrentJCD.setDefaultConnection(Boolean.valueOf(defaultConnection).booleanValue());
134 if (m_CurrentJCD.isDefaultConnection())
135 {
136 if (defaultConnectionFound)
137 {
138 throw new MetadataException("Found two jdbc-connection-descriptor elements with default-connection=\"true\"");
139 }
140 else
141 {
142 defaultConnectionFound = true;
143 }
144 }
145
146 // set platform attribute
147 String platform = atts.getValue(tags.getTagById(DBMS_NAME));
148 if (isDebug) logger.debug(" " + tags.getTagById(DBMS_NAME) + ": " + platform);
149 m_CurrentJCD.setDbms(platform);
150
151 // set jdbc-level attribute
152 String level = atts.getValue(tags.getTagById(JDBC_LEVEL));
153 if (isDebug) logger.debug(" " + tags.getTagById(JDBC_LEVEL) + ": " + level);
154 m_CurrentJCD.setJdbcLevel(level);
155
156 // set driver attribute
157 String driver = atts.getValue(tags.getTagById(DRIVER_NAME));
158 if (isDebug) logger.debug(" " + tags.getTagById(DRIVER_NAME) + ": " + driver);
159 m_CurrentJCD.setDriver(driver);
160
161 // set protocol attribute
162 String protocol = atts.getValue(tags.getTagById(URL_PROTOCOL));
163 if (isDebug) logger.debug(" " + tags.getTagById(URL_PROTOCOL) + ": " + protocol);
164 m_CurrentJCD.setProtocol(protocol);
165
166 // set subprotocol attribute
167 String subprotocol = atts.getValue(tags.getTagById(URL_SUBPROTOCOL));
168 if (isDebug) logger.debug(" " + tags.getTagById(URL_SUBPROTOCOL) + ": " + subprotocol);
169 m_CurrentJCD.setSubProtocol(subprotocol);
170
171 // set the dbalias attribute
172 String dbalias = atts.getValue(tags.getTagById(URL_DBALIAS));
173 if (isDebug) logger.debug(" " + tags.getTagById(URL_DBALIAS) + ": " + dbalias);
174 m_CurrentJCD.setDbAlias(dbalias);
175
176 // set the datasource attribute
177 String datasource = atts.getValue(tags.getTagById(DATASOURCE_NAME));
178 // check for empty String
179 if(datasource != null && datasource.trim().equals("")) datasource = null;
180 if (isDebug) logger.debug(" " + tags.getTagById(DATASOURCE_NAME) + ": " + datasource);
181 m_CurrentJCD.setDatasourceName(datasource);
182
183 // set the user attribute
184 String user = atts.getValue(tags.getTagById(USER_NAME));
185 if (isDebug) logger.debug(" " + tags.getTagById(USER_NAME) + ": " + user);
186 m_CurrentJCD.setUserName(user);
187
188 // set the password attribute
189 String password = atts.getValue(tags.getTagById(USER_PASSWD));
190 if (isDebug) logger.debug(" " + tags.getTagById(USER_PASSWD) + ": " + password);
191 m_CurrentJCD.setPassWord(password);
192
193 // set eager-release attribute
194 String eagerRelease = atts.getValue(tags.getTagById(EAGER_RELEASE));
195 if (isDebug) logger.debug(" " + tags.getTagById(EAGER_RELEASE) + ": " + eagerRelease);
196 m_CurrentJCD.setEagerRelease(Boolean.valueOf(eagerRelease).booleanValue());
197
198 // set batch-mode attribute
199 String batchMode = atts.getValue(tags.getTagById(BATCH_MODE));
200 if (isDebug) logger.debug(" " + tags.getTagById(BATCH_MODE) + ": " + batchMode);
201 m_CurrentJCD.setBatchMode(Boolean.valueOf(batchMode).booleanValue());
202
203 // set useAutoCommit attribute
204 String useAutoCommit = atts.getValue(tags.getTagById(USE_AUTOCOMMIT));
205 if (isDebug) logger.debug(" " + tags.getTagById(USE_AUTOCOMMIT) + ": " + useAutoCommit);
206 m_CurrentJCD.setUseAutoCommit(Integer.valueOf(useAutoCommit).intValue());
207
208 // set ignoreAutoCommitExceptions attribute
209 String ignoreAutoCommitExceptions = atts.getValue(tags.getTagById(IGNORE_AUTOCOMMIT_EXCEPTION));
210 if (isDebug) logger.debug(" " + tags.getTagById(IGNORE_AUTOCOMMIT_EXCEPTION) + ": " + ignoreAutoCommitExceptions);
211 m_CurrentJCD.setIgnoreAutoCommitExceptions(Boolean.valueOf(ignoreAutoCommitExceptions).booleanValue());
212
213 break;
214 }
215 case CONNECTION_POOL:
216 {
217 if (m_CurrentJCD != null)
218 {
219 if (isDebug) logger.debug(" > " + tags.getTagById(CONNECTION_POOL));
220 final ConnectionPoolDescriptor m_CurrentCPD = m_CurrentJCD.getConnectionPoolDescriptor();
221 this.currentAttributeContainer = m_CurrentCPD;
222
223 String maxActive = atts.getValue(tags.getTagById(CON_MAX_ACTIVE));
224 if (isDebug) logger.debug(" " + tags.getTagById(CON_MAX_ACTIVE) + ": " + maxActive);
225 if (checkString(maxActive)) m_CurrentCPD.setMaxActive(Integer.parseInt(maxActive));
226
227 String maxIdle = atts.getValue(tags.getTagById(CON_MAX_IDLE));
228 if (isDebug) logger.debug(" " + tags.getTagById(CON_MAX_IDLE) + ": " + maxIdle);
229 if (checkString(maxIdle)) m_CurrentCPD.setMaxIdle(Integer.parseInt(maxIdle));
230
231 String maxWait = atts.getValue(tags.getTagById(CON_MAX_WAIT));
232 if (isDebug) logger.debug(" " + tags.getTagById(CON_MAX_WAIT) + ": " + maxWait);
233 if (checkString(maxWait)) m_CurrentCPD.setMaxWait(Integer.parseInt(maxWait));
234
235 String minEvictableIdleTimeMillis = atts.getValue(tags.getTagById(CON_MIN_EVICTABLE_IDLE_TIME_MILLIS));
236 if (isDebug) logger.debug(" " + tags.getTagById(CON_MIN_EVICTABLE_IDLE_TIME_MILLIS) + ": " + minEvictableIdleTimeMillis);
237 if (checkString(minEvictableIdleTimeMillis)) m_CurrentCPD.setMinEvictableIdleTimeMillis(Long.parseLong(minEvictableIdleTimeMillis));
238
239 String numTestsPerEvictionRun = atts.getValue(tags.getTagById(CON_NUM_TESTS_PER_EVICTION_RUN));
240 if (isDebug) logger.debug(" " + tags.getTagById(CON_NUM_TESTS_PER_EVICTION_RUN) + ": " + numTestsPerEvictionRun);
241 if (checkString(numTestsPerEvictionRun)) m_CurrentCPD.setNumTestsPerEvictionRun(Integer.parseInt(numTestsPerEvictionRun));
242
243 String testOnBorrow = atts.getValue(tags.getTagById(CON_TEST_ON_BORROW));
244 if (isDebug) logger.debug(" " + tags.getTagById(CON_TEST_ON_BORROW) + ": " + testOnBorrow);
245 if (checkString(testOnBorrow)) m_CurrentCPD.setTestOnBorrow(Boolean.valueOf(testOnBorrow).booleanValue());
246
247 String testOnReturn = atts.getValue(tags.getTagById(CON_TEST_ON_RETURN));
248 if (isDebug) logger.debug(" " + tags.getTagById(CON_TEST_ON_RETURN) + ": " + testOnReturn);
249 if (checkString(testOnReturn)) m_CurrentCPD.setTestOnReturn(Boolean.valueOf(testOnReturn).booleanValue());
250
251 String testWhileIdle = atts.getValue(tags.getTagById(CON_TEST_WHILE_IDLE));
252 if (isDebug) logger.debug(" " + tags.getTagById(CON_TEST_WHILE_IDLE) + ": " + testWhileIdle);
253 if (checkString(testWhileIdle)) m_CurrentCPD.setTestWhileIdle(Boolean.valueOf(testWhileIdle).booleanValue());
254
255 String timeBetweenEvictionRunsMillis = atts.getValue(tags.getTagById(CON_TIME_BETWEEN_EVICTION_RUNS_MILLIS));
256 if (isDebug) logger.debug(" " + tags.getTagById(CON_TIME_BETWEEN_EVICTION_RUNS_MILLIS) + ": " + timeBetweenEvictionRunsMillis);
257 if (checkString(timeBetweenEvictionRunsMillis)) m_CurrentCPD.setTimeBetweenEvictionRunsMillis(Long.parseLong(timeBetweenEvictionRunsMillis));
258
259 String whenExhaustedAction = atts.getValue(tags.getTagById(CON_WHEN_EXHAUSTED_ACTION));
260 if (isDebug) logger.debug(" " + tags.getTagById(CON_WHEN_EXHAUSTED_ACTION) + ": " + whenExhaustedAction);
261 if (checkString(whenExhaustedAction)) m_CurrentCPD.setWhenExhaustedAction(Byte.parseByte(whenExhaustedAction));
262
263 String connectionFactoryStr = atts.getValue(tags.getTagById(CONNECTION_FACTORY));
264 if (isDebug) logger.debug(" " + tags.getTagById(CONNECTION_FACTORY) + ": " + connectionFactoryStr);
265 if (checkString(connectionFactoryStr)) m_CurrentCPD.setConnectionFactory(ClassHelper.getClass(connectionFactoryStr));
266
267 String validationQuery = atts.getValue(tags.getTagById(VALIDATION_QUERY));
268 if (isDebug) logger.debug(" " + tags.getTagById(VALIDATION_QUERY) + ": " + validationQuery);
269 if (checkString(validationQuery)) m_CurrentCPD.setValidationQuery(validationQuery);
270
271 // abandoned connection properties
272 String logAbandoned = atts.getValue(tags.getTagById(CON_LOG_ABANDONED));
273 if (isDebug) logger.debug(" " + tags.getTagById(CON_LOG_ABANDONED) + ": " + logAbandoned);
274 if (checkString(logAbandoned)) m_CurrentCPD.setLogAbandoned(Boolean.valueOf(logAbandoned).booleanValue());
275
276 String removeAbandoned = atts.getValue(tags.getTagById(CON_REMOVE_ABANDONED));
277 if (isDebug) logger.debug(" " + tags.getTagById(CON_REMOVE_ABANDONED) + ": " + removeAbandoned);
278 if (checkString(removeAbandoned)) m_CurrentCPD.setRemoveAbandoned(Boolean.valueOf(removeAbandoned).booleanValue());
279
280 String removeAbandonedTimeout = atts.getValue(tags.getTagById(CON_REMOVE_ABANDONED_TIMEOUT));
281 if (isDebug) logger.debug(" " + tags.getTagById(CON_REMOVE_ABANDONED_TIMEOUT) + ": " + removeAbandonedTimeout);
282 if (checkString(removeAbandonedTimeout)) m_CurrentCPD.setRemoveAbandonedTimeout(Integer.parseInt(removeAbandonedTimeout));
283 }
284 break;
285 }
286
287 case OBJECT_CACHE:
288 {
289 String className = atts.getValue(tags.getTagById(CLASS_NAME));
290 if(checkString(className) && m_CurrentJCD != null)
291 {
292 ObjectCacheDescriptor ocd = m_CurrentJCD.getObjectCacheDescriptor();
293 this.currentAttributeContainer = ocd;
294 ocd.setObjectCache(ClassHelper.getClass(className));
295 if (isDebug) logger.debug(" > " + tags.getTagById(OBJECT_CACHE));
296 if (isDebug) logger.debug(" " + tags.getTagById(CLASS_NAME) + ": " + className);
297 }
298 break;
299 }
300 case SEQUENCE_MANAGER:
301 {
302 String className = atts.getValue(tags.getTagById(SEQUENCE_MANAGER_CLASS));
303 if(checkString(className))
304 {
305 this.currentSequenceDescriptor = new SequenceDescriptor(this.m_CurrentJCD);
306 this.currentAttributeContainer = currentSequenceDescriptor;
307 this.m_CurrentJCD.setSequenceDescriptor(this.currentSequenceDescriptor);
308 if (isDebug) logger.debug(" > " + tags.getTagById(SEQUENCE_MANAGER));
309 if (isDebug) logger.debug(" " + tags.getTagById(SEQUENCE_MANAGER_CLASS) + ": " + className);
310 if (checkString(className)) currentSequenceDescriptor.setSequenceManagerClass(ClassHelper.getClass(className));
311 }
312 break;
313 }
314 case ATTRIBUTE:
315 {
316 //handle custom attributes
317 String attributeName = atts.getValue(tags.getTagById(ATTRIBUTE_NAME));
318 String attributeValue = atts.getValue(tags.getTagById(ATTRIBUTE_VALUE));
319
320 // If we have a container to store this attribute in, then do so.
321 if (this.currentAttributeContainer != null)
322 {
323
324 if (checkString(attributeName))
325 {
326 if (isDebug) logger.debug(" > " + tags.getTagById(ATTRIBUTE));
327 if (isDebug) logger.debug(" " + tags.getTagById(ATTRIBUTE_NAME) + ": " + attributeName
328 + " "+tags.getTagById(ATTRIBUTE_VALUE) + ": " + attributeValue);
329 this.currentAttributeContainer.addAttribute(attributeName, attributeValue);
330 // logger.info("attribute ["+attributeName+"="+attributeValue+"] add to "+currentAttributeContainer.getClass());
331 }
332 else
333 {
334 logger.info("Found 'null' or 'empty' attribute object for element "+currentAttributeContainer.getClass() +
335 " attribute-name=" + attributeName + ", attribute-value=" + attributeValue+
336 " See jdbc-connection-descriptor with jcdAlias '"+m_CurrentJCD.getJcdAlias()+"'");
337 }
338 }
339 // else
340 // {
341 // logger.info("Found attribute (name="+attributeName+", value="+attributeValue+
342 // ") but I could not assign them to a descriptor");
343 // }
344
345 break;
346 }
347 default :
348 {
349 // noop
350 }
351 }
352 }
353 catch (Exception ex)
354 {
355 logger.error(ex);
356 throw new PersistenceBrokerException(ex);
357 }
358 }
359
360 private boolean checkString(String str)
361 {
362 return (str != null && !str.trim().equals(""));
363 }
364
365 /**
366 * returns the XmlCapable id associated with the literal.
367 * OJB maintains a RepositoryTags table that provides
368 * a mapping from xml-tags to XmlCapable ids.
369 * @param literal the literal to lookup
370 * @return the int value representing the XmlCapable
371 *
372 * @throws MetadataException if no literal was found in tags mapping
373 */
374 private int getLiteralId(String literal) throws PersistenceBrokerException
375 {
376 try
377 {
378 return tags.getIdByTag(literal);
379 }
380 catch (NullPointerException e)
381 {
382 throw new MetadataException("unknown literal: '" + literal + "'", e);
383 }
384 }
385
386 /**
387 * endElement callback. most elements are build up from here.
388 */
389 public void endElement(String uri, String name, String qName)
390 {
391 boolean isDebug = logger.isDebugEnabled();
392 try
393 {
394 switch (getLiteralId(qName))
395 {
396 case MAPPING_REPOSITORY:
397 {
398 currentAttributeContainer = null;
399 break;
400 }
401 case CLASS_DESCRIPTOR:
402 {
403 currentAttributeContainer = null;
404 break;
405 }
406 case JDBC_CONNECTION_DESCRIPTOR:
407 {
408 logger.debug(" < " + tags.getTagById(JDBC_CONNECTION_DESCRIPTOR));
409 m_CurrentJCD = null;
410 currentAttributeContainer = null;
411 break;
412 }
413 case CONNECTION_POOL:
414 {
415 logger.debug(" < " + tags.getTagById(CONNECTION_POOL));
416 currentAttributeContainer = m_CurrentJCD;
417 break;
418 }
419 case SEQUENCE_MANAGER:
420 {
421 if (isDebug) logger.debug(" < " + tags.getTagById(SEQUENCE_MANAGER));
422 // set to null at the end of the tag!!
423 this.currentSequenceDescriptor = null;
424 currentAttributeContainer = m_CurrentJCD;
425 break;
426 }
427 case OBJECT_CACHE:
428 {
429 if(currentAttributeContainer != null)
430 {
431 if (isDebug) logger.debug(" < " + tags.getTagById(OBJECT_CACHE));
432 // set to null or previous element level at the end of the tag!!
433 currentAttributeContainer = m_CurrentJCD;
434 }
435 break;
436 }
437 case ATTRIBUTE:
438 {
439 if(currentAttributeContainer != null)
440 {
441 if (isDebug) logger.debug(" < " + tags.getTagById(ATTRIBUTE));
442 }
443 break;
444 }
445 default :
446 {
447 // noop
448 }
449 }
450 }
451 catch (Exception ex)
452 {
453 logger.error(ex);
454 throw new PersistenceBrokerException(ex);
455 }
456 }
457
458 /**
459 * Error callback.
460 */
461 public void error(SAXParseException e) throws SAXException
462 {
463 logger.error(e);
464 throw e;
465 }
466
467 /**
468 * fatal error callback.
469 */
470 public void fatalError(SAXParseException e) throws SAXException
471 {
472 logger.fatal(e);
473 throw e;
474 }
475
476 /**
477 * warning callback.
478 */
479 public void warning(SAXParseException e) throws SAXException
480 {
481 logger.warn(e);
482 throw e;
483 }
484 }