Package org.teiid.dqp.internal.datamgr

Source Code of org.teiid.dqp.internal.datamgr.ConnectorWorkItem

/*
* 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.internal.datamgr;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.resource.ResourceException;

import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.util.Assertion;
import org.teiid.dqp.message.AtomicRequestID;
import org.teiid.dqp.message.AtomicRequestMessage;
import org.teiid.dqp.message.AtomicResultsMessage;
import org.teiid.language.Call;
import org.teiid.language.QueryExpression;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.CommandLogMessage.Event;
import org.teiid.metadata.RuntimeMetadata;
import org.teiid.query.QueryPlugin;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataAdapter;
import org.teiid.query.metadata.TempMetadataStore;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.resource.spi.WrappedConnection;
import org.teiid.translator.DataNotAvailableException;
import org.teiid.translator.Execution;
import org.teiid.translator.ExecutionFactory;
import org.teiid.translator.ProcedureExecution;
import org.teiid.translator.ResultSetExecution;
import org.teiid.translator.TranslatorException;
import org.teiid.translator.UpdateExecution;


public class ConnectorWorkItem implements ConnectorWork {
 
  /* Permanent state members */
  private AtomicRequestID id;
    private ConnectorManager manager;
    private AtomicRequestMessage requestMsg;
    private ExecutionFactory connector;
    private QueryMetadataInterface queryMetadata;
   
    /* Created on new request */
    private Object connection;
    private Object connectionFactory;
    private ExecutionContextImpl securityContext;
    private volatile ResultSetExecution execution;
    private ProcedureBatchHandler procedureBatchHandler;
    private org.teiid.language.Command translatedCommand;
    private int expectedColumns;
       
    /* End state information */   
    private boolean lastBatch;
    private int rowCount;
    private boolean error;
   
    private AtomicBoolean isCancelled = new AtomicBoolean();
   
    ConnectorWorkItem(AtomicRequestMessage message, ConnectorManager manager) {
        this.id = message.getAtomicRequestID();
        this.requestMsg = message;
        this.manager = manager;
        AtomicRequestID requestID = this.requestMsg.getAtomicRequestID();
        this.securityContext = new ExecutionContextImpl(requestMsg.getWorkContext().getVdbName(),
                requestMsg.getWorkContext().getVdbVersion(),               
                requestMsg.getExecutionPayload(),                                                                      
                requestMsg.getWorkContext().getSessionId(),                                                                     
                requestMsg.getConnectorName(),
                requestMsg.getRequestID().toString(),
                Integer.toString(requestID.getNodeID()),
                Integer.toString(requestID.getExecutionId())
                );
        this.securityContext.setUser(requestMsg.getWorkContext().getSubject());
        this.securityContext.setBatchSize(this.requestMsg.getFetchSize());
       
        this.connector = manager.getExecutionFactory();
      VDBMetaData vdb = requestMsg.getWorkContext().getVDB();
      this.queryMetadata = vdb.getAttachment(QueryMetadataInterface.class);
        this.queryMetadata = new TempMetadataAdapter(this.queryMetadata, new TempMetadataStore());
    this.securityContext.setTransactional(requestMsg.isTransactional());
    }
   
    public AtomicRequestID getId() {
    return id;
  }
   
    public void cancel() {
      try {
            LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Processing CANCEL request"}); //$NON-NLS-1$
            if (this.isCancelled.compareAndSet(false, true)) {
                this.manager.logSRCCommand(this.requestMsg, this.securityContext, Event.CANCEL, -1);
              if(execution != null) {
                  execution.cancel();
              }           
              LogManager.logDetail(LogConstants.CTX_CONNECTOR, QueryPlugin.Util.getString("DQPCore.The_atomic_request_has_been_cancelled", this.id)); //$NON-NLS-1$
          }
        } catch (TranslatorException e) {
            LogManager.logWarning(LogConstants.CTX_CONNECTOR, e, QueryPlugin.Util.getString("Cancel_request_failed", this.id)); //$NON-NLS-1$
        }
    }
   
    public AtomicResultsMessage more() throws TranslatorException {
      LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Processing MORE request"}); //$NON-NLS-1$
      try {
        return handleBatch();
      } catch (Throwable t) {
        throw handleError(t);
      }
    }
   
    public void close() {
      LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Processing Close :", this.requestMsg.getCommand()}); //$NON-NLS-1$
      if (!error) {
            manager.logSRCCommand(this.requestMsg, this.securityContext, Event.END, this.rowCount);
        }
        try {
          if (execution != null) {
              execution.close();
              LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Closed execution"}); //$NON-NLS-1$                   
          }         
        } catch (Throwable e) {
            LogManager.logError(LogConstants.CTX_CONNECTOR, e, e.getMessage());
        } finally {
          try {
            this.connector.closeConnection(connection, connectionFactory);
          } catch (Throwable e) {
            LogManager.logError(LogConstants.CTX_CONNECTOR, e, e.getMessage());
          } finally {
            manager.removeState(this.id);
          }
        LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Closed connection"}); //$NON-NLS-1$
        }
    }
   
    private TranslatorException handleError(Throwable t) {
      if (t instanceof DataNotAvailableException) {
        throw (DataNotAvailableException)t;
      }
      error = true;
      if (t instanceof RuntimeException && t.getCause() != null) {
        t = t.getCause();
      }
        manager.logSRCCommand(this.requestMsg, this.securityContext, Event.ERROR, null);
       
        String msg = QueryPlugin.Util.getString("ConnectorWorker.process_failed", this.id); //$NON-NLS-1$
        if (isCancelled.get()) {           
            LogManager.logDetail(LogConstants.CTX_CONNECTOR, msg);
        } else if (t instanceof TranslatorException || t instanceof TeiidProcessingException) {
          LogManager.logWarning(LogConstants.CTX_CONNECTOR, t, msg);
        } else {
            LogManager.logError(LogConstants.CTX_CONNECTOR, t, msg);
        }
    if (t instanceof TranslatorException) {
      return (TranslatorException)t;
    }
    if (t instanceof RuntimeException) {
      throw (RuntimeException)t;
    }
    return new TranslatorException(t);
    }
   
  public AtomicResultsMessage execute() throws TranslatorException, BlockedException {
        if(isCancelled()) {
        throw new TranslatorException("Request canceled"); //$NON-NLS-1$
      }
       
      LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.requestMsg.getAtomicRequestID(), "Processing NEW request:", this.requestMsg.getCommand()}); //$NON-NLS-1$                                    
      try {
        this.connectionFactory = this.manager.getConnectionFactory();
          this.connection = this.connector.getConnection(this.connectionFactory);

          Object unwrapped = null;
      if (connection instanceof WrappedConnection) {
        try {
          unwrapped = ((WrappedConnection)connection).unwrap();
        } catch (ResourceException e) {
          throw new TranslatorException(QueryPlugin.Util.getString("failed_to_unwrap_connection")); //$NON-NLS-1$
       
      }
     
          // Translate the command
          Command command = this.requestMsg.getCommand();
          this.expectedColumns = command.getProjectedSymbols().size();
          LanguageBridgeFactory factory = new LanguageBridgeFactory(queryMetadata);
          this.translatedCommand = factory.translate(command);
 
          RuntimeMetadata rmd = new RuntimeMetadataImpl(queryMetadata);
         
          // Create the execution based on mode
          final Execution exec = connector.createExecution(this.translatedCommand, this.securityContext, rmd, (unwrapped == null) ? this.connection:unwrapped);
          if (this.translatedCommand instanceof Call) {
            this.execution = Assertion.isInstanceOf(exec, ProcedureExecution.class, "Call Executions are expected to be ProcedureExecutions"); //$NON-NLS-1$
            StoredProcedure proc = (StoredProcedure)command;
            if (proc.returnParameters()) {
              this.procedureBatchHandler = new ProcedureBatchHandler((Call)this.translatedCommand, (ProcedureExecution)exec);
            }
          } else if (this.translatedCommand instanceof QueryExpression){
            this.execution = Assertion.isInstanceOf(exec, ResultSetExecution.class, "QueryExpression Executions are expected to be ResultSetExecutions"); //$NON-NLS-1$
          } else {
            Assertion.isInstanceOf(exec, UpdateExecution.class, "Update Executions are expected to be UpdateExecutions"); //$NON-NLS-1$
            this.execution = new ResultSetExecution() {
              private int[] results;
              private int index;
             
              @Override
              public void cancel() throws TranslatorException {
                exec.cancel();
              }
              @Override
              public void close() {
                exec.close();
              }
              @Override
              public void execute() throws TranslatorException {
                exec.execute();
              }
              @Override
              public List<?> next() throws TranslatorException,
                  DataNotAvailableException {
                if (results == null) {
                  results = ((UpdateExecution)exec).getUpdateCounts();
                }
                if (index < results.length) {
                  return Arrays.asList(results[index++]);
                }
                return null;
              }
            };
          }
          LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.requestMsg.getAtomicRequestID(), "Obtained execution"}); //$NON-NLS-1$     
          //Log the Source Command (Must be after obtaining the execution context)
          manager.logSRCCommand(this.requestMsg, this.securityContext, Event.NEW, null);
         
          // Execute query
        this.execution.execute();
          LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Executed command"}); //$NON-NLS-1$
 
          return handleBatch();
      } catch (Throwable t) {
        throw handleError(t);
      }
  }
   
    protected AtomicResultsMessage handleBatch() throws TranslatorException {
      Assertion.assertTrue(!this.lastBatch);
        LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Getting results from connector"}); //$NON-NLS-1$
        int batchSize = 0;
        List<List> rows = new ArrayList<List>(batchSize/4);
       
        try {
          while (batchSize < this.requestMsg.getFetchSize()) {
           
            List row = this.execution.next();
              if (row == null) {
                this.lastBatch = true;
                break;
              }
              if (row.size() != this.expectedColumns) {
                throw new AssertionError("Inproper results returned.  Expected " + this.expectedColumns + " columns, but was " + row.size()); //$NON-NLS-1$ //$NON-NLS-2$
            }
              this.rowCount += 1;
              batchSize++;
              if (this.procedureBatchHandler != null) {
                row = this.procedureBatchHandler.padRow(row);
              }
             
              rows.add(row);
              // Check for max result rows exceeded
              if(this.requestMsg.getMaxResultRows() > -1 && this.rowCount >= this.requestMsg.getMaxResultRows()){
                  if (this.rowCount == this.requestMsg.getMaxResultRows() && !this.requestMsg.isExceptionOnMaxRows()) {
                    LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Exceeded max, returning", this.requestMsg.getMaxResultRows()}); //$NON-NLS-1$
                this.lastBatch = true;
                break;
                } else if (this.rowCount > this.requestMsg.getMaxResultRows() && this.requestMsg.isExceptionOnMaxRows()) {
                      String msg = QueryPlugin.Util.getString("ConnectorWorker.MaxResultRowsExceed", this.requestMsg.getMaxResultRows()); //$NON-NLS-1$
                      throw new TranslatorException(msg);
                  }
              }
          }
      } catch (DataNotAvailableException e) {
        if (rows.size() == 0) {
          throw e;
        }
      }
               
        if (lastBatch) {
          if (this.procedureBatchHandler != null) {
            List row = this.procedureBatchHandler.getParameterRow();
            if (row != null) {
              rows.add(row);
              this.rowCount++;
            }
          }
            LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Obtained last batch, total row count:", rowCount}); //$NON-NLS-1$\
        else {
          LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Obtained results from connector, current row count:", rowCount}); //$NON-NLS-1$
        }
       
      int currentRowCount = rows.size();
    if ( !lastBatch && currentRowCount == 0 ) {
        // Defect 13366 - Should send all batches, even if they're zero size.
        // Log warning if received a zero-size non-last batch from the connector.
        LogManager.logWarning(LogConstants.CTX_CONNECTOR, QueryPlugin.Util.getString("ConnectorWorker.zero_size_non_last_batch", requestMsg.getConnectorName())); //$NON-NLS-1$
    }

    AtomicResultsMessage response = createResultsMessage(rows.toArray(new List[currentRowCount]), requestMsg.getCommand().getProjectedSymbols());
   
    // if we need to keep the execution alive, then we can not support implicit close.
    response.setSupportsImplicitClose(!this.securityContext.keepExecutionAlive());
    response.setTransactional(this.securityContext.isTransactional());
    response.setWarnings(this.securityContext.getWarnings());
    response.setSupportsCloseWithLobs(this.connector.areLobsUsableAfterClose());

    if ( lastBatch ) {
        response.setFinalRow(rowCount);
    }
    return response;
  }

    public static AtomicResultsMessage createResultsMessage(List[] batch, List columnSymbols) {
        String[] dataTypes = TupleBuffer.getTypeNames(columnSymbols);       
        return new AtomicResultsMessage(batch, dataTypes);
    }   
           
    boolean isCancelled() {
      return this.isCancelled.get();
    }

  @Override
  public String toString() {
    return this.id.toString();
  }

}
TOP

Related Classes of org.teiid.dqp.internal.datamgr.ConnectorWorkItem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.