KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > scriptella > driver > csv > CsvQuery


1 /*
2  * Copyright 2006-2007 The Scriptella Project Team.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package scriptella.driver.csv;
17
18 import au.com.bytecode.opencsv.CSVReader;
19 import scriptella.expression.PropertiesSubstitutor;
20 import scriptella.spi.AbstractConnection;
21 import scriptella.spi.ParametersCallback;
22 import scriptella.spi.QueryCallback;
23 import scriptella.util.ColumnsMap;
24 import scriptella.util.ExceptionUtils;
25
26 import java.io.Closeable JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.regex.Matcher JavaDoc;
31 import java.util.regex.Pattern JavaDoc;
32
33 /**
34  * Query for CSV file.
35  *
36  * @author Fyodor Kupolov
37  * @version 1.0
38  */

39 public class CsvQuery implements ParametersCallback, Closeable JavaDoc {
40     private CSVReader reader;
41     private final boolean headers;
42     private final boolean trim;
43     private ColumnsMap columnsMap;
44     private String JavaDoc[] row;
45     private Pattern JavaDoc[][] patterns;
46     private Matcher JavaDoc[][] matchers;
47     private PropertiesSubstitutor substitutor = new PropertiesSubstitutor();
48
49     /**
50      * Creates a query for CSVReader.
51      *
52      * @param reader CSV reader.
53      * @param headers true if first line contains headers.
54      * @param trim true if if extra whitespaces in the query should be trimmed.
55      */

56     public CsvQuery(CSVReader reader, boolean headers, boolean trim) {
57         if (reader == null) {
58             throw new IllegalArgumentException JavaDoc("CSV reader cannot be null");
59         }
60         this.reader = reader;
61         this.headers = headers;
62         this.trim = trim;
63     }
64
65     /**
66      * Executes a query.
67      *
68      * @param queryReader query content reader. Closed after this method completes.
69      * @param parametersCallback parameters to use.
70      * @param queryCallback callback to use for result set iteration.
71      * @param counter statements counter.
72      * @throws IOException if IO error occurs.
73      */

74     public void execute(CSVReader queryReader, ParametersCallback parametersCallback, QueryCallback queryCallback, AbstractConnection.StatementCounter counter) throws IOException JavaDoc {
75         try {
76             substitutor.setParameters(parametersCallback);
77             compileQueries(queryReader);
78
79             columnsMap = new ColumnsMap();
80             if (headers) {
81                 String JavaDoc[] row = reader.readNext();
82                 for (int i = 0; i < row.length; i++) {
83                     columnsMap.registerColumn(row[i], i + 1);
84                 }
85             }
86             //For each row
87

88             while ((row = reader.readNext()) != null) {
89                 if (rowMatches()) {
90                     queryCallback.processRow(this);
91                 }
92             }
93         } finally { //clean up
94
try {
95                 queryReader.close();
96             } catch (Exception JavaDoc e) {
97                 ExceptionUtils.ignoreThrowable(e);
98             }
99         }
100         if (patterns != null) {
101             counter.statements += patterns.length;
102         }
103     }
104
105     /**
106      * Checks if current CSV row matches any of the specified patterns.
107      *
108      * @return true if row matches one of queries.
109      */

110     boolean rowMatches() {
111         //Checking border conditions
112
Pattern JavaDoc[][] ptrs = patterns;
113         int columnsCount = row.length;
114         if (ptrs == null) {
115             return true;
116         } else if (columnsCount == 0) {
117             return false;
118         }
119
120         for (int i = 0; i < ptrs.length; i++) {
121             Pattern JavaDoc[] rowPatterns = ptrs[i];
122             Matcher JavaDoc[] rowMatchers = matchers[i];
123             boolean rowMatches = true;
124             int patternsCount = rowPatterns.length;
125             if (patternsCount > columnsCount) { //If patterns length exceeds row columns count
126
continue; //Skip this query line
127
}
128             for (int j = 0; j < patternsCount; j++) {
129                 Pattern JavaDoc columnPtr = rowPatterns[j];
130                 if (columnPtr != null) {
131                     Matcher JavaDoc m = rowMatchers[j];
132                     String JavaDoc col = row[j]; //Current column value
133
if (m == null) { //create new matcher
134
m = columnPtr.matcher(col);
135                         rowMatchers[j] = m;
136                     } else { //reuse
137
m.reset(col);
138                     }
139                     if (!m.matches()) {
140                         rowMatches = false;
141                         break;
142                     }
143                 }
144             }
145             if (rowMatches) { //If this row matches current patterns
146
return true;
147             } //otherwise continue matching
148
}
149         return false; //no matches
150

151
152     }
153
154     /**
155      * Compiles queries into a list of patterns.
156      *
157      * @param r CSV reader for query text.
158      */

159     @SuppressWarnings JavaDoc("unchecked")
160     void compileQueries(final CSVReader r) {
161         List JavaDoc<String JavaDoc[]> list;
162         try {
163             list = r.readAll();
164         } catch (IOException JavaDoc e) {
165             throw new CsvProviderException("Unable to read CSV query", e);
166         }
167         List JavaDoc<Pattern JavaDoc[]> res = null;
168         for (String JavaDoc[] columns : list) {
169             Pattern JavaDoc[] patterns = null;
170             for (int i = 0; i < columns.length; i++) {
171                 String JavaDoc s = trim(columns[i]);
172                 if (s != null && s.length() > 0) {
173                     if (patterns == null) {
174                         patterns = new Pattern JavaDoc[columns.length];
175                     }
176                     try {
177                         patterns[i] = Pattern.compile(substitutor.substitute(s), Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
178                     } catch (Exception JavaDoc e) {
179                         throw new CsvProviderException("Illegal regular expression syntax for query", e, s);
180                     }
181                 }
182             }
183             if (patterns != null) { //if the line has at least on not empty pattern
184
if (res == null) {
185                     res = new ArrayList JavaDoc<Pattern JavaDoc[]>();
186                 }
187                 res.add(patterns);
188             }
189         }
190         if (res != null) {
191             int len = res.size();
192             Pattern JavaDoc[][] ptrs = res.toArray(new Pattern JavaDoc[len][]);
193             //Create the matchers array to reuse for better performance
194
Matcher JavaDoc[][] matchers = new Matcher JavaDoc[len][];
195             for (int i = 0; i < len; i++) {
196                 matchers[i] = new Matcher JavaDoc[ptrs[i].length];
197             }
198             this.patterns = ptrs;
199             this.matchers = matchers;
200         }
201
202     }
203
204     /**
205      * Trims string if {@link #trim} flag is true.
206      *
207      * @param s string to trim. May be null.
208      * @return possibly trimmed string or null.
209      */

210     private String JavaDoc trim(String JavaDoc s) {
211         return (trim && s != null) ? s.trim() : s;
212     }
213
214     public Object JavaDoc getParameter(final String JavaDoc name) {
215         if (reader == null) {
216             throw new IllegalStateException JavaDoc("CSV Resultset is closed");
217         }
218         Integer JavaDoc col = columnsMap.find(name);
219         if (col != null && col > 0 && col <= row.length) { //If col is not null and in range
220
return row[col - 1];
221         } else { //otherwise call parent
222
return substitutor.getParameters().getParameter(name);
223         }
224     }
225
226     public void close() throws IOException JavaDoc {
227         if (reader != null) {
228             reader.close();
229             reader = null;
230             columnsMap = null;
231         }
232     }
233 }
234
Popular Tags