001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * Created Sep 15, 2005
014: * @author wseyler
015: */
016: package org.pentaho.data.connection.xquery;
017:
018: import java.math.BigDecimal;
019: import java.sql.Date;
020: import java.sql.Timestamp;
021: import java.util.Iterator;
022: import java.util.Map;
023: import net.sf.saxon.om.Axis;
024: import net.sf.saxon.om.AxisIterator;
025: import net.sf.saxon.query.DynamicQueryContext;
026: import net.sf.saxon.query.XQueryExpression;
027: import net.sf.saxon.tinytree.TinyNodeImpl;
028: import net.sf.saxon.trans.XPathException;
029: import net.sf.saxon.type.Type;
030: import org.apache.commons.collections.OrderedMap;
031: import org.apache.commons.collections.map.ListOrderedMap;
032: import org.pentaho.commons.connection.IPentahoMetaData;
033: import org.pentaho.commons.connection.IPentahoResultSet;
034: import org.pentaho.commons.connection.memory.MemoryMetaData;
035: import org.pentaho.commons.connection.memory.MemoryResultSet;
036:
037: /**
038: * @author wseyler
039: *
040: * TODO To change the template for this generated type comment go to Window -
041: * Preferences - Java - Code Style - Code Templates
042: */
043: public class XQResultSet implements IPentahoResultSet {
044: protected XQueryExpression exp = null;
045:
046: protected DynamicQueryContext dynamicContext = null;
047:
048: protected XQMetaData metaData = null;
049:
050: protected static final String DELIM = ", "; //$NON-NLS-1$
051:
052: protected static final String EMPTY_STR = ""; //$NON-NLS-1$
053:
054: Iterator iter = null;
055:
056: protected String columnTypes[] = null;
057:
058: /**
059: * @param exp
060: * @param dynamicContext
061: * @param columnTypes
062: * @throws XPathException
063: */
064: public XQResultSet(XQueryExpression exp,
065: DynamicQueryContext dynamicContext, String columnTypes[])
066: throws XPathException {
067: super ();
068: this .columnTypes = columnTypes;
069: this .exp = exp;
070: this .dynamicContext = dynamicContext;
071: init();
072: }
073:
074: protected void init() throws XPathException {
075: iter = this .exp.evaluate(this .dynamicContext).iterator();
076: metaData = new XQMetaData(iter);
077: // reset the iterator for the data
078: iter = this .exp.evaluate(this .dynamicContext).iterator();
079: }
080:
081: /*
082: * (non-Javadoc)
083: *
084: * @see org.pentaho.connection.IPentahoResultSet#getMetaData()
085: */
086: public IPentahoMetaData getMetaData() {
087: return metaData;
088: }
089:
090: /*
091: * (non-Javadoc)
092: *
093: * @see org.pentaho.connection.IPentahoResultSet#next()
094: */
095: public Object[] next() {
096: // Create a map of the headers and assign empty string to them
097: OrderedMap resultList = new ListOrderedMap();
098: for (int i = 0; i < metaData.getColumnCount(); i++) {
099: resultList
100: .put(metaData.getColumnHeaders()[0][i], EMPTY_STR);
101: }
102: // Get the next row of data
103: if (iter.hasNext()) {
104: Object o = iter.next();
105: decodeNode(o, resultList);
106: }
107: // get the values
108: Object[] retArray = new Object[resultList.size()];
109: Iterator keyIter = resultList.keySet().iterator();
110: int i = 0;
111: while (keyIter.hasNext()) {
112: retArray[i] = resultList.get(keyIter.next());
113: i++;
114: }
115: // if all the values are the empty string then we're done.
116: boolean done = true;
117: for (int j = 0; j < retArray.length; j++) {
118: if (!("".equals(retArray[j]))) { //$NON-NLS-1$
119: done = false;
120: }
121: }
122: if (done) {
123: return null;
124: }
125: return retArray;
126: }
127:
128: protected void decodeNode(Object obj, Map retValue) {
129: if (obj instanceof TinyNodeImpl) {
130: AxisIterator aIter = ((TinyNodeImpl) obj)
131: .iterateAxis(Axis.DESCENDANT);
132: Object descendent = aIter.next();
133: boolean processedChildren = false;
134: int columnIndex = 0;
135: while (descendent != null) {
136: if (descendent instanceof TinyNodeImpl
137: && ((TinyNodeImpl) descendent).getNodeKind() == Type.ELEMENT) {
138: TinyNodeImpl descNode = (TinyNodeImpl) descendent;
139: Object value = retValue.get(descNode
140: .getDisplayName());
141: if (value == null) {
142: value = EMPTY_STR;
143: }
144: if (!(EMPTY_STR.equals(value))) {
145: value = value.toString() + DELIM;
146: }
147: value = value.toString()
148: + descNode.getStringValue();
149: if (value != null
150: && !value.equals("") && columnTypes != null && columnIndex >= 0 && columnIndex < columnTypes.length) { //$NON-NLS-1$
151: String columnType = columnTypes[columnIndex]
152: .trim();
153: if (columnType.equals("java.math.BigDecimal")) { //$NON-NLS-1$
154: value = new BigDecimal(value.toString());
155: } else if (columnType
156: .equals("java.sql.Timestamp")) { //$NON-NLS-1$
157: value = new Timestamp(Long.parseLong(value
158: .toString()));
159: } else if (columnType.equals("java.sql.Date")) { //$NON-NLS-1$
160: value = new Date(Long.parseLong(value
161: .toString()));
162: } else if (columnType
163: .equals("java.lang.Integer")) { //$NON-NLS-1$
164: value = new Integer(Integer.parseInt(value
165: .toString()));
166: } else if (columnType
167: .equals("java.lang.Double")) { //$NON-NLS-1$
168: value = new Double(Double.parseDouble(value
169: .toString()));
170: } else if (columnType.equals("java.lang.Long")) { //$NON-NLS-1$
171: value = new Long(Long.parseLong(value
172: .toString()));
173: }
174: }
175: retValue.put(descNode.getDisplayName(), value);
176: processedChildren = true;
177: columnIndex++;
178: }
179: descendent = aIter.next();
180: }
181: if (!processedChildren) {
182: Object key = ((TinyNodeImpl) obj).getDisplayName();
183: Object value = ((TinyNodeImpl) obj).getStringValue();
184: retValue.put(key, value);
185: }
186: } else {
187: retValue
188: .put(XQMetaData.DEFAULT_COLUMN_NAME, obj.toString());
189: }
190: }
191:
192: /*
193: * (non-Javadoc)
194: *
195: * @see org.pentaho.connection.IPentahoResultSet#close()
196: */
197: public void close() {
198: // TODO Auto-generated method stub
199: }
200:
201: /*
202: * (non-Javadoc)
203: *
204: * @see org.pentaho.connection.IPentahoResultSet#closeConnection()
205: */
206: public void closeConnection() {
207: // TODO Auto-generated method stub
208: }
209:
210: /*
211: * (non-Javadoc)
212: *
213: * @see org.pentaho.connection.IPentahoResultSet#isScrollable()
214: */
215: public boolean isScrollable() {
216: // TODO Auto-generated method stub
217: return false;
218: }
219:
220: /*
221: * (non-Javadoc)
222: *
223: * @see org.pentaho.connection.IPentahoResultSet#getValueAt(int, int)
224: */
225: public Object getValueAt(int row, int column) {
226: Object rowarr[] = getDataRow(row);
227: if (rowarr != null && column >= 0 && column < rowarr.length) {
228: return rowarr[column];
229: }
230: return null;
231: }
232:
233: /*
234: * (non-Javadoc)
235: *
236: * @see org.pentaho.connection.IPentahoResultSet#getRowCount()
237: */
238: public int getRowCount() {
239: return metaData.getRowCount();
240: }
241:
242: /*
243: * (non-Javadoc)
244: *
245: * @see org.pentaho.connection.IPentahoResultSet#getColumnCount()
246: */
247: public int getColumnCount() {
248: return metaData.getColumnCount();
249: }
250:
251: /*
252: * (non-Javadoc)
253: *
254: * @see org.pentaho.core.runtime.IDisposable#dispose()
255: */
256: public void dispose() {
257: // TODO Auto-generated method stub
258: }
259:
260: public IPentahoResultSet memoryCopy() {
261: try {
262: IPentahoMetaData metadata = getMetaData();
263: Object columnHeaders[][] = metadata.getColumnHeaders();
264: MemoryMetaData cachedMetaData = new MemoryMetaData(
265: columnHeaders, null);
266: MemoryResultSet cachedResultSet = new MemoryResultSet(
267: cachedMetaData);
268: Object[] rowObjects = next();
269: while (rowObjects != null) {
270: cachedResultSet.addRow(rowObjects);
271: rowObjects = next();
272: }
273: return cachedResultSet;
274: } finally {
275: close();
276: }
277: }
278:
279: public void beforeFirst() {
280: try {
281: init();
282: } catch (Throwable t) {
283: t.printStackTrace();
284: }
285: }
286:
287: /*
288: * (non-Javadoc)
289: *
290: * @see org.pentaho.connection.IPentahoResultSet#getDataColumn(int)
291: *
292: * NOTE: calling this will move the cursor to the top of the result stack
293: */
294: public Object[] getDataColumn(int column) {
295: beforeFirst(); // go to top just in case we called this after some
296: // next()s
297: Object[] result = new Object[getRowCount()];
298: int rowIndex = 0;
299: Object[] rowData = next();
300: while (rowData != null) {
301: result[rowIndex] = rowData[column];
302: rowIndex++;
303: rowData = next();
304: }
305: beforeFirst();
306: return result;
307: }
308:
309: public Object[] getDataRow(int row) {
310: beforeFirst(); // go to top
311: int count = 0;
312: while (count < row) {
313: next();
314: }
315: Object[] dataRow = next();
316: beforeFirst();
317: return dataRow;
318: }
319: }
|