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    }