001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  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    package org.apache.geronimo.converter.jboss;
018    
019    import java.io.Reader;
020    import java.io.IOException;
021    import java.util.List;
022    import java.util.ArrayList;
023    import javax.xml.parsers.DocumentBuilderFactory;
024    import javax.xml.parsers.DocumentBuilder;
025    import javax.xml.parsers.ParserConfigurationException;
026    import org.apache.geronimo.converter.DatabaseConversionStatus;
027    import org.apache.geronimo.converter.JDBCPool;
028    import org.apache.geronimo.converter.XADatabasePool;
029    import org.apache.geronimo.converter.AbstractDatabasePool;
030    import org.apache.geronimo.converter.DOMUtils;
031    import org.apache.geronimo.kernel.util.XmlUtil;
032    import org.w3c.dom.Document;
033    import org.w3c.dom.Element;
034    import org.w3c.dom.NodeList;
035    import org.w3c.dom.Node;
036    import org.xml.sax.InputSource;
037    import org.xml.sax.SAXException;
038    
039    /**
040     * Converts database pools from JBoss 4 to Geronimo
041     *
042     * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
043     */
044    public class JBoss4DatabaseConverter extends DOMUtils {
045        public static DatabaseConversionStatus convert(Reader dsXml) throws IOException {
046            List status = new ArrayList();
047            List noTx = new ArrayList();
048            List local = new ArrayList();
049            List xa = new ArrayList();
050    
051            DocumentBuilderFactory factory = XmlUtil.newDocumentBuilderFactory();
052            factory.setValidating(false);
053            try {
054                DocumentBuilder builder = factory.newDocumentBuilder();
055                Document doc = builder.parse(new InputSource(dsXml));
056                dsXml.close();
057                parseDocument(doc, status, noTx, local, xa);
058            } catch (ParserConfigurationException e) {
059                throw (IOException)new IOException().initCause(e);
060            } catch (SAXException e) {
061                throw (IOException)new IOException().initCause(e);
062            }
063    
064            DatabaseConversionStatus result = new DatabaseConversionStatus();
065            result.setMessages((String[]) status.toArray(new String[status.size()]));
066            result.setNoTXPools((JDBCPool[]) noTx.toArray(new JDBCPool[noTx.size()]));
067            result.setJdbcPools((JDBCPool[]) local.toArray(new JDBCPool[noTx.size()]));
068            result.setXaPools((XADatabasePool[]) xa.toArray(new XADatabasePool[xa.size()]));
069            return result;
070        }
071    
072        private static void parseDocument(Document doc, List status, List noTx, List local, List xa) {
073            Element datasources = doc.getDocumentElement();
074            if(!datasources.getNodeName().equalsIgnoreCase("datasources")) {
075                if(datasources.getNodeName().equals("connection-factories")) {
076                    status.add("ERROR: Geronimo cannot parse a JBoss data source configured using conection-factories.  This typically means a custom RAR file is required.");
077                    return;
078                } else {
079                    status.add("ERROR: Unrecognized file beginning with "+datasources.getNodeName()+" element.  Expected a JBoss *-ds.xml file.");
080                    return;
081                }
082            }
083            NodeList list = datasources.getChildNodes();
084            for(int i=0; i<list.getLength(); i++) {
085                Node node = list.item(i);
086                if(node.getNodeType() == Node.ELEMENT_NODE) {
087                    String name = node.getNodeName();
088                    if(name.equalsIgnoreCase("no-tx-datasource")) {
089                        addJDBCDataSource((Element)node, status, noTx);
090                    } else if(name.equalsIgnoreCase("local-tx-datasource")) {
091                        addJDBCDataSource((Element)node, status, local);
092                    } else if(name.equalsIgnoreCase("xa-datasource")) {
093                        addXADataSource((Element)node, status, xa);
094                    } else if(name.equalsIgnoreCase("mbean")) {
095                        status.add("Skipping MBean element");
096                    } else {
097                        status.add("WARN: Skipped element "+name);
098                    }
099                }
100            }
101        }
102    
103        private static void addDataSourceCommon(Element root, AbstractDatabasePool pool, List status) {
104            pool.setJndiName(getChildText(root, "jndi-name"));
105            pool.setName(pool.getJndiName());
106            if(pool.getJndiName() != null && pool.getJndiName().indexOf('/') > -1) {
107                status.add("NOTE: pool will use name '"+pool.getJndiName()+"' though Geronimo doesn't put it in JNDI");
108            }
109            String test = getChildText(root, "min-pool-size");
110            if(test != null && !test.equals("")) pool.setMinSize(new Integer(test));
111            test = getChildText(root, "max-pool-size");
112            if(test != null && !test.equals("")) pool.setMaxSize(new Integer(test));
113            test = getChildText(root, "blocking-timeout-millis");
114            if(test != null && !test.equals("")) pool.setBlockingTimeoutMillis(new Integer(test));
115            test = getChildText(root, "idle-timeout-minutes");
116            if(test != null && !test.equals("")) pool.setIdleTimeoutMillis(new Integer(Integer.parseInt(test)*60*1000));
117            pool.setNewConnectionSQL(getChildText(root, "new-connection-sql"));
118            pool.setTestConnectionSQL(getChildText(root, "check-valid-connection-sql"));
119            String sorter = getChildText(root, "exception-sorter-class-name");
120            if(sorter != null) {
121                if(sorter.indexOf("Oracle") > -1) pool.setVendor(AbstractDatabasePool.VENDOR_ORACLE);
122                if(sorter.indexOf("MySQL") > -1) pool.setVendor(AbstractDatabasePool.VENDOR_MYSQL);
123                if(sorter.indexOf("Sybase") > -1) pool.setVendor(AbstractDatabasePool.VENDOR_SYBASE);
124                if(sorter.indexOf("Informix") > -1) pool.setVendor(AbstractDatabasePool.VENDOR_INFORMIX);
125            }
126            test = getChildText(root, "prepared-statement-cache-size");
127            if(test != null && !test.equals("")) pool.setStatementCacheSize(new Integer(test));
128        }
129    
130        private static void addJDBCDataSource(Element root, List status, List results) {
131            JDBCPool pool = new JDBCPool();
132            addDataSourceCommon(root, pool, status);
133            pool.setJdbcURL(getChildText(root, "connection-url"));
134            pool.setDriverClass(getChildText(root, "driver-class"));
135            NodeList list = root.getElementsByTagName("connection-property");
136            for(int i=0; i<list.getLength(); i++) {
137                Element prop = (Element) list.item(i);
138                pool.getConnectionProperties().setProperty(prop.getAttribute("name"), getText(prop));
139            }
140            pool.setUsername(getChildText(root, "user-name"));
141            pool.setPassword(getChildText(root, "password"));
142    
143    
144            if(pool.getName() != null && !pool.getName().equals("")) {
145                results.add(pool);
146            } else {
147                status.add("WARN: Ignoring pool with no JNDI name");
148            }
149        }
150    
151        private static void addXADataSource(Element root, List status, List results) {
152            XADatabasePool pool = new XADatabasePool();
153            addDataSourceCommon(root, pool, status);
154            pool.setXaDataSourceClass(getChildText(root, "xa-datasource-class"));
155            NodeList list = root.getElementsByTagName("xa-datasource-property");
156            for(int i=0; i<list.getLength(); i++) {
157                Element prop = (Element) list.item(i);
158                pool.getProperties().setProperty(prop.getAttribute("name"), getText(prop));
159            }
160    
161            if(pool.getName() != null && !pool.getName().equals("")) {
162                results.add(pool);
163            } else {
164                status.add("WARN: Ignoring pool with no JNDI name");
165            }
166        }
167    
168        /*
169        public static void main(String[] args) {
170            File dir = new File("/Users/ammulder/temp/jboss-4.0.3SP1/docs/examples/jca/");
171            File[] files = dir.listFiles(new FilenameFilter() {
172                public boolean accept(File dir, String name) {
173                    return name.endsWith("-ds.xml");
174                }
175            });
176            for (int i = 0; i < files.length; i++) {
177                File file = files[i];
178                System.out.println("Reading "+file.getName());
179                try {
180                    FileReader reader = new FileReader(file);
181                    DatabaseConversionStatus status = JBoss4DatabaseConverter.convert(reader);
182                    for (int j = 0; j < status.getMessages().length; j++) {
183                        String message = status.getMessages()[j];
184                        System.out.println("    "+message);
185                    }
186                    System.out.println("    FOUND "+status.getNoTXPools().length+" NoTX Pools");
187                    System.out.println("    FOUND "+status.getJdbcPools().length+" JDBC Pools");
188                    System.out.println("    FOUND "+status.getXaPools().length+" XA Pools");
189                } catch (IOException e) {
190                    e.printStackTrace();
191                }
192            }
193        } */
194    }