001    package com.mockrunner.jdbc;
002    
003    import java.io.File;
004    import java.util.Iterator;
005    import java.util.List;
006    
007    import org.jdom.Document;
008    import org.jdom.Element;
009    import org.jdom.input.SAXBuilder;
010    
011    import com.mockrunner.base.NestedApplicationException;
012    import com.mockrunner.mock.jdbc.MockResultSet;
013    import com.mockrunner.util.common.FileUtil;
014    
015    /**
016     * Can be used to create a <code>ResultSet</code> based on
017     * a an XML <code>Document</code> of the proper format. You can specify 
018     * the dialect, for proper parsing of the document. Furthermore you can 
019     * specify the dialect of the <code>ResultSet</code>, which determines 
020     * the expected format of the XML <code>Document</code> and whether or not  
021     * the column entries should be trimmed (default is <code>true</code>).
022     * The file can be specified directly or by its name. The class
023     * tries to find the file in the absolut or relative path and
024     * (if not found) by calling <code>getResource</code>. Note that the
025     * file must exist in the local file system and cannot be loaded from
026     * inside a jar archive.
027     */
028    public class XMLResultSetFactory implements ResultSetFactory 
029    {
030        public final static int SYBASE_DIALECT = 0;
031        
032        private File file = null;
033        private String fileName = null;
034        private boolean trim = true;
035        private int dialect = SYBASE_DIALECT;
036        
037        public XMLResultSetFactory(String fileName)
038        {
039            this.file = new File(fileName);
040            this.fileName = fileName;
041        }
042        
043        public XMLResultSetFactory(File file)
044        {
045            this.file = file;
046            this.fileName = file.getAbsolutePath();
047        }
048        
049        /**
050         * Makes and returns a MockResultSet created from 
051         * an existing and valid XML <code>Document</code>.
052         * 
053         * @return a new MockResultSet
054         */
055        public MockResultSet create(String id) 
056        {
057            MockResultSet resultSet;
058            
059            switch (dialect) 
060            {
061                    case SYBASE_DIALECT:
062                        resultSet = createSybaseResultSet(id);
063                        break;
064                    default:
065                        resultSet = createSybaseResultSet(id);
066                        break;
067            }
068            
069            return resultSet;
070        }
071        
072        /**
073         * Get the <code>File</code> being used to read in the 
074         * <code>ResultSet</code>. Returns <code>null</code> if
075         * the file does not exist.
076         * @return the file 
077         */
078        public File getXMLFile()
079        {
080            if(file.exists() && file.isFile())
081            {
082                return file;
083            }
084            else
085            {
086                return FileUtil.findFile(fileName);
087            }
088        }
089    
090        /**
091         * Set if the column entries should be trimmed.
092         * Default is <code>true</code>.
093         * 
094         * @param trim
095         */
096        public void setTrim(boolean trim)
097        {
098            this.trim = trim;
099        }
100        
101        /**
102         * Get whether or not trim is true or false.
103         */
104        public boolean getTrim() 
105        {
106            return trim;
107        }
108        
109        /**
110         * Set the dialect of the XML <code>Document</code>.  Can be 
111         * different for different database systems.  
112         * Will determine the expected XML format for 
113         * the <code>ResultSet</code>.  <code>SYBASE_DIALECT</code> 
114         * is the <b>only</b> accepted dialect for now.
115         * @param dialect int specifying which createXXXResultSet 
116         * method to call.
117         */
118        public void setDialect(int dialect) 
119        {
120            //this.dialect = dialect;
121            this.dialect = SYBASE_DIALECT;
122        }
123        
124        /**
125         * Get the dialect of the XML <code>Document</code.
126         * 
127         * @return dialect
128         */
129        public int getDialect() 
130        {
131            return dialect;
132        }
133        
134        /**
135         * Return a MockResultSet with proper column names and 
136         * rows based on the XML <code>Document</code>.
137         * @return MockResultSet Results read from XML 
138         * <code>Document</code>.
139         */
140        public MockResultSet createSybaseResultSet(String id) 
141        {
142           MockResultSet resultSet = new MockResultSet(id);
143           SAXBuilder builder = new SAXBuilder();
144           Document doc = null;
145           File fileToParse = getXMLFile();
146           if(null == fileToParse)
147           {
148               throw new RuntimeException("File " + fileName + " not found.");
149           }
150           try 
151           {
152               doc = builder.build(fileToParse);
153               Element root = doc.getRootElement();
154               List rows = root.getChildren("row");
155               Iterator ri = rows.iterator();
156               boolean firstIteration = true;
157               int colNum = 0;
158               while (ri.hasNext()) 
159               {
160                   Element cRow = (Element)ri.next();
161                   List cRowChildren = cRow.getChildren();
162                   Iterator cri = cRowChildren.iterator();   
163                   if (firstIteration)
164                   {
165                       List columns = cRowChildren;
166                       Iterator ci = columns.iterator();
167                       
168                       while (ci.hasNext()) 
169                       {
170                           Element ccRow = (Element)ci.next();
171                           resultSet.addColumn(ccRow.getName());
172                           colNum++;
173                       }
174                       firstIteration = false;
175                   }
176                   String[] cRowValues = new String[colNum];
177                   int curCol = 0;
178                   while (cri.hasNext())
179                   {
180                       Element crValue = (Element)cri.next();
181                       String value = trim ? crValue.getTextTrim() : crValue.getText();
182                       cRowValues[curCol] = value;
183                       curCol++;
184                   }
185                   resultSet.addRow(cRowValues);
186               }
187           } 
188           catch(Exception exc) 
189           {
190               throw new NestedApplicationException("Failure while reading from XML file", exc);
191           }
192           return resultSet;
193        }
194    }