/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.dqp.service; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Clob; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.teiid.core.TeiidComponentException; import org.teiid.core.types.ClobImpl; import org.teiid.core.types.DataTypeManager; import org.teiid.core.types.InputStreamFactory; import org.teiid.core.types.Streamable; import org.teiid.dqp.internal.datamgr.ConnectorManager; import org.teiid.dqp.internal.datamgr.ConnectorWork; import org.teiid.dqp.internal.datamgr.ConnectorWorkItem; import org.teiid.dqp.message.AtomicRequestID; import org.teiid.dqp.message.AtomicRequestMessage; import org.teiid.dqp.message.AtomicResultsMessage; import org.teiid.query.optimizer.TestOptimizer; import org.teiid.query.optimizer.capabilities.SourceCapabilities; import org.teiid.query.processor.relational.RelationalNodeUtil; import org.teiid.query.sql.symbol.Expression; import org.teiid.translator.CacheDirective; import org.teiid.translator.DataNotAvailableException; import org.teiid.translator.TranslatorException; /** * This data service will automatically generate results when called with a query - basically * the same as the old loopback connector. */ @SuppressWarnings("nls") public class AutoGenDataService extends ConnectorManager{ // Number of rows that will be generated for each query private int rows = 10; private SourceCapabilities caps; public boolean throwExceptionOnExecute; public Integer dataNotAvailable; public boolean strict; public int sleep; private final AtomicInteger executeCount = new AtomicInteger(); private final AtomicInteger closeCount = new AtomicInteger(); private boolean useIntCounter; public boolean addWarning; public CacheDirective cacheDirective; public boolean dataAvailable; public boolean threadBound; public AutoGenDataService() { super("FakeConnector","FakeConnector"); //$NON-NLS-1$ //$NON-NLS-2$ caps = TestOptimizer.getTypicalCapabilities(); } public void setUseIntCounter(boolean useIntCounter) { this.useIntCounter = useIntCounter; } public void setSleep(int sleep) { this.sleep = sleep; } public void setCaps(SourceCapabilities caps) { this.caps = caps; } public void setRows(int rows) { this.rows = rows; } public int getRows() { return this.rows; } @Override public ConnectorWork registerRequest(AtomicRequestMessage message) throws TeiidComponentException { List projectedSymbols = (message.getCommand()).getProjectedSymbols(); List[] results = createResults(projectedSymbols, rows, useIntCounter); if (RelationalNodeUtil.isUpdate(message.getCommand())) { results = new List[] {Arrays.asList(1)}; } final AtomicResultsMessage msg = ConnectorWorkItem.createResultsMessage(results); msg.setFinalRow(rows); return new ConnectorWork() { boolean returnedInitial; @Override public boolean isDataAvailable() { return dataAvailable; } @Override public AtomicResultsMessage more() throws TranslatorException { if (dataNotAvailable != null) { int delay = dataNotAvailable; dataNotAvailable = null; DataNotAvailableException dnae = new DataNotAvailableException(delay); dnae.setStrict(strict); throw dnae; } if (addWarning) { msg.setWarnings(Arrays.asList(new Exception())); } if (!returnedInitial) { returnedInitial = true; return msg; } throw new RuntimeException("Should not be called"); //$NON-NLS-1$ } @Override public void execute() throws TranslatorException { executeCount.incrementAndGet(); if (sleep > 0) { try { Thread.sleep(sleep); } catch (InterruptedException e) { throw new RuntimeException(e); } } if (throwExceptionOnExecute) { throw new TranslatorException("Connector Exception"); //$NON-NLS-1$ } } @Override public void close() { closeCount.incrementAndGet(); } @Override public void cancel(boolean abnormal) { } @Override public CacheDirective getCacheDirective() { return cacheDirective; } @Override public boolean isForkable() { return true; } @Override public boolean isThreadBound() { return threadBound; } @Override public AtomicRequestID getId() { return null; } }; } public AtomicInteger getExecuteCount() { return executeCount; } public AtomicInteger getCloseCount() { return closeCount; } public static List[] createResults(List symbols, int rowCount, boolean useIntCounter) { List[] rows = new List[rowCount]; for(int i=0; i<rowCount; i++) { List row = new ArrayList(); Iterator iter = symbols.iterator(); while(iter.hasNext()) { Expression symbol = (Expression) iter.next(); Class type = symbol.getType(); row.add( getValue(type, i, useIntCounter) ); } rows[i] = row; } return rows; } private static final String STRING_VAL = "ABCDEFG"; //$NON-NLS-1$ private static final Integer INTEGER_VAL = new Integer(0); private static final Long LONG_VAL = new Long(0); private static final Float FLOAT_VAL = new Float(0.0); private static final Short SHORT_VAL = new Short((short)0); private static final Double DOUBLE_VAL = new Double(0.0); private static final Character CHAR_VAL = new Character('c'); private static final Byte BYTE_VAL = new Byte((byte)0); public static final Clob CLOB_VAL = new ClobImpl(new InputStreamFactory() { @Override public InputStream getInputStream() throws IOException { return new ByteArrayInputStream("hello world".getBytes(Streamable.CHARSET)); } }, -1); private static final Boolean BOOLEAN_VAL = Boolean.FALSE; private static final BigInteger BIG_INTEGER_VAL = new BigInteger("0"); //$NON-NLS-1$ private static final BigDecimal BIG_DECIMAL_VAL = new BigDecimal("0"); //$NON-NLS-1$ private static final java.sql.Date SQL_DATE_VAL = new java.sql.Date(0); private static final java.sql.Time TIME_VAL = new java.sql.Time(0); private static final java.sql.Timestamp TIMESTAMP_VAL = new java.sql.Timestamp(0); static Object getValue(Class<?> type, int row, boolean useIntCounter) { if(type.equals(DataTypeManager.DefaultDataClasses.STRING)) { return STRING_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.INTEGER)) { return useIntCounter?row:INTEGER_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.SHORT)) { return SHORT_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.LONG)) { return LONG_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.FLOAT)) { return FLOAT_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.DOUBLE)) { return DOUBLE_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.CHAR)) { return CHAR_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.BYTE)) { return BYTE_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.BOOLEAN)) { return BOOLEAN_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.BIG_INTEGER)) { return BIG_INTEGER_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.BIG_DECIMAL)) { return BIG_DECIMAL_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.DATE)) { return SQL_DATE_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.TIME)) { return TIME_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.TIMESTAMP)) { return TIMESTAMP_VAL; } else if(type.equals(DataTypeManager.DefaultDataClasses.CLOB)) { return CLOB_VAL; } else { return null; } } @Override public SourceCapabilities getCapabilities(){ return caps; } }