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