/* * ModeShape (http://www.modeshape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.modeshape.jdbc; import static org.mockito.Mockito.when; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.TimeZone; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.query.QueryResult; import javax.jcr.query.Row; import javax.jcr.query.RowIterator; import org.mockito.Mockito; /** * This provides common result set metadata used by various tests */ public class TestUtil { public static final String STRING = PropertyType.nameFromValue(PropertyType.STRING).toUpperCase(); public static final String DOUBLE = PropertyType.nameFromValue(PropertyType.DOUBLE).toUpperCase(); public static final String LONG = PropertyType.nameFromValue(PropertyType.LONG).toUpperCase(); public static final String BOOLEAN = PropertyType.nameFromValue(PropertyType.BOOLEAN).toUpperCase(); public static final String DATE = PropertyType.nameFromValue(PropertyType.DATE).toUpperCase(); public static final String PATH = PropertyType.nameFromValue(PropertyType.STRING).toUpperCase(); public static final String BINARY = PropertyType.nameFromValue(PropertyType.BINARY).toUpperCase(); public static final String REFERENCE = PropertyType.nameFromValue(PropertyType.REFERENCE).toUpperCase(); public static String[] COLUMN_NAMES; public static String TIME_ZONE = "Europe/London"; public static DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ public static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); //$NON-NLS-1$ public static DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss a"); //$NON-NLS-1$ public static String USE_TIMESTAMP_FOR_SOURCE = "2004-06-30 02:39:10.201"; public static String USE_TIME_FOR_SOURCE = "02:39:10"; public static String USE_DATE_FOR_SOURCE = "2004-06-30"; // this is the expected date based on the test using "GMT-05:00" when testing rsultset methods that take a calendar public static String EXPECTED_TIMESTAMP_FOR_TARGET = "2004-06-29 20:39:10.201"; public static String EXPECTED_TIME_FOR_TARGET = "20:39:10"; public static String EXPECTED_DATE_FOR_TARGET = "2004-06-29"; public static String EXPECTED_TIMEZONE = "America/Chicago"; public static interface COLUMN_NAME_PROPERTIES { public static final String PROP_A = "propA"; public static final String PROP_B = "propB"; public static final String PROP_C = "propC"; public static final String PROP_D = "propD"; public static final String PROP_E = "propE"; public static final String PROP_F = "propF"; public static final String PROP_G = "propG"; public static final String PROP_H = "propH"; public static final String PROP_I = "propI"; } public static String[] TABLE_NAMES; public static String[] TYPE_NAMES; public static String[] NODE_NAMES; public static List<Object[]> TUPLES; public static final String SQL_SELECT = "Select propA FROM typeA"; static { Calendar cal_instance = createTestCalendar(); // The column names must match the number of columns in #TUPLES COLUMN_NAMES = new String[] {COLUMN_NAME_PROPERTIES.PROP_A, COLUMN_NAME_PROPERTIES.PROP_B, COLUMN_NAME_PROPERTIES.PROP_C, COLUMN_NAME_PROPERTIES.PROP_D, COLUMN_NAME_PROPERTIES.PROP_E, COLUMN_NAME_PROPERTIES.PROP_F, COLUMN_NAME_PROPERTIES.PROP_G, COLUMN_NAME_PROPERTIES.PROP_H, COLUMN_NAME_PROPERTIES.PROP_I}; TABLE_NAMES = new String[] {"typeA", "typeB", "typeA", "", "typeA"}; // The TYPE_NAMES correspond to the column value types defined in #TUPLES TYPE_NAMES = new String[] {STRING, LONG, PATH, REFERENCE, DOUBLE, BOOLEAN, DATE, BINARY, LONG}; NODE_NAMES = new String[] {"node1", "node2"}; // Provides the resultset rows TUPLES = new ArrayList<Object[]>(); /* * the tuples data types for each column correspond to @see TYPE_NAMES */ TUPLES.add(new Object[] {"r1c1", (long)1, null, null, (double)1, true, cal_instance, "Heres my data at r1".getBytes(), null}); cal_instance = createTestCalendar(); TUPLES.add(new Object[] {"r2c1", (long)2, null, null, (double)2, false, cal_instance, "Heres my data r2 ".getBytes(), null}); cal_instance = createTestCalendar(); TUPLES.add(new Object[] {"r3c1", (long)3, null, null, (double)3, true, cal_instance, "Heres my data at r3 ".getBytes(), null}); cal_instance = createTestCalendar(); TUPLES.add(new Object[] {"r4c1", 4L, null, null, 4D, Boolean.TRUE, cal_instance, "Heres my data r4 ".getBytes(), null}); } private static Calendar createTestCalendar() { Calendar cal_instance = new GregorianCalendar(); cal_instance.clear(); cal_instance.setTimeZone(TimeZone.getTimeZone(TIME_ZONE)); cal_instance.set(Calendar.MONTH, Calendar.JUNE); cal_instance.set(Calendar.DAY_OF_MONTH, 30); cal_instance.set(Calendar.YEAR, 2004); cal_instance.set(Calendar.HOUR_OF_DAY, 2); cal_instance.set(Calendar.MINUTE, 39); cal_instance.set(Calendar.SECOND, 10); cal_instance.set(Calendar.MILLISECOND, 201); cal_instance.set(Calendar.AM_PM, Calendar.AM); return cal_instance; } static Node[] createNodes() { Node[] nodes = new Node[NODE_NAMES.length]; for (int i = 0; i < NODE_NAMES.length; i++) { // Create the new definition ... Node n = Mockito.mock(Node.class); try { when(n.getName()).thenReturn(NODE_NAMES[i]); } catch (RepositoryException e) { } nodes[i] = n; } return nodes; } public static int minorVersion( String versionString ) { String[] coords = versionString.split("[.-]"); @SuppressWarnings( "unused" ) final int major = Integer.parseInt(coords[0]); return Integer.parseInt(coords[1]); } public static int majorVersion( String versionString ) { String[] coords = versionString.split("[.-]"); return Integer.parseInt(coords[0]); } public static QueryResult createQueryResult() { final Node[] nodes = createNodes(); QueryResult qr = new org.modeshape.jcr.api.query.QueryResult() { @Override public String getPlan() { return null; } @Override public Collection<String> getWarnings() { return Collections.emptySet(); } @Override public String[] getColumnNames() { String[] cns = new String[COLUMN_NAMES.length]; System.arraycopy(COLUMN_NAMES, 0, cns, 0, COLUMN_NAMES.length); return cns; } @Override public boolean isEmpty() { return nodes.length == 0; } @Override public NodeIterator getNodes() { List<Node> nodeArray = new ArrayList<Node>(); for (int i = 0; i < nodes.length; i++) { nodeArray.add(nodes[i]); } return new QueryResultNodeIterator(nodeArray); } @Override public RowIterator getRows() { List<Object[]> tuplesArray = new ArrayList<Object[]>(TUPLES); RowIterator ri = new QueryResultRowIterator(nodes, SQL_SELECT, tuplesArray.iterator(), tuplesArray.size()); return ri; } @Override public String[] getColumnTypes() { return null; } @Override public String[] getSelectorNames() { return null; } @Override public void close() { // nothing to do } }; return qr; } } /** */ class QueryResultNodeIterator implements NodeIterator { private final Iterator<? extends Node> nodes; private final int size; private long position = 0L; protected QueryResultNodeIterator( List<? extends Node> nodes ) { this.nodes = nodes.iterator(); this.size = nodes.size(); } @Override public Node nextNode() { Node node = nodes.next(); ++position; return node; } @Override public long getPosition() { return position; } @Override public long getSize() { return size; } @Override public void skip( long skipNum ) { for (long i = 0L; i != skipNum; ++i) nextNode(); } @Override public boolean hasNext() { return nodes.hasNext(); } @Override public Object next() { return nextNode(); } @Override public void remove() { throw new UnsupportedOperationException(); } } class QueryResultRowIterator implements RowIterator { private final Iterator<Object[]> tuples; protected final String query; private long position = 0L; private long numRows; private Row nextRow; private Node[] nodes; protected QueryResultRowIterator( Node[] nodes, String query, Iterator<Object[]> tuples, long numRows ) { this.tuples = tuples; this.query = query; this.numRows = numRows; this.nodes = nodes; } @Override public Row nextRow() { if (nextRow == null) { // Didn't call 'hasNext()' ... if (!hasNext()) { throw new NoSuchElementException(); } } assert nextRow != null; Row result = nextRow; nextRow = null; position++; return result; } @Override public long getPosition() { return position; } @Override public long getSize() { return numRows; } @Override public void skip( long skipNum ) { for (long i = 0L; i != skipNum; ++i) { tuples.next(); } position += skipNum; } @Override public boolean hasNext() { if (nextRow != null) { return true; } while (tuples.hasNext()) { final Object[] tuple = tuples.next(); // Get the next row ... nextRow = getNextRow(tuple); if (nextRow != null) return true; --numRows; } return false; } private Row getNextRow( Object[] tuple ) { return new QueryResultRow(this, nodes, tuple); } @Override public Object next() { return nextRow(); } @Override public void remove() { throw new UnsupportedOperationException(); } } class QueryResultRow implements javax.jcr.query.Row { protected final QueryResultRowIterator iterator; private Node[] nodes; protected final Object[] tuple; protected QueryResultRow( QueryResultRowIterator iterator, Node[] nodes, Object[] tuple ) { this.iterator = iterator; this.tuple = tuple; this.nodes = nodes; } @Override public Node getNode() throws RepositoryException { if (nodes.length == 1) return nodes[0]; throw new RepositoryException("More than one selector"); } @Override public Node getNode( String selectorName ) throws RepositoryException { for (int i = 0; i < nodes.length; i++) { if (nodes[i].getName().equals(selectorName)) { return nodes[i]; } } return null; } @Override public String getPath() throws RepositoryException { if (nodes.length == 1) return nodes[0].getPath(); throw new RepositoryException("More than one selector"); } @Override public String getPath( String selectorName ) throws RepositoryException { for (int i = 0; i < nodes.length; i++) { if (nodes[i].getName().equals(selectorName)) { return nodes[i].getPath(); } } return null; } @Override public double getScore() /*throws RepositoryException*/{ throw new UnsupportedOperationException(); } @Override public double getScore( String selectorName ) /* throws RepositoryException */{ throw new UnsupportedOperationException(); } @Override public Value getValue( String arg0 ) throws ItemNotFoundException { for (int i = 0; i < TestUtil.COLUMN_NAMES.length; i++) { if (TestUtil.COLUMN_NAMES[i].equals(arg0)) { return JdbcJcrValueFactory.createValue(tuple[i]); } } throw new ItemNotFoundException("Item " + arg0 + " not found"); } @Override public Value[] getValues() { Value[] values = new Value[tuple.length]; for (int i = 0; i < tuple.length; i++) { values[i] = JdbcJcrValueFactory.createValue(tuple[i]); } return values; } }