All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pentaho.di.trans.steps.socketreader.SocketReader Maven / Gradle / Ivy

The newest version!
/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2017 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * 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.pentaho.di.trans.steps.socketreader;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleEOFException;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStep;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;

/**
 * Read data from a TCP/IP socket supplied by SocketWriter. The data coming over the socket is one serialized Row object
 * including metadata and then a series of serialized rows, data only.
 *
 * @author Matt
 * @since 01-dec-2006
 */
public class SocketReader extends BaseStep implements StepInterface {
  private static Class PKG = SocketReaderMeta.class; // for i18n purposes, needed by Translator2!!

  public static final String STRING_FINISHED = "Finished";
  private static final int TIMEOUT_IN_SECONDS = 30;
  private SocketReaderMeta meta;
  private SocketReaderData data;

  public SocketReader( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta,
    Trans trans ) {
    super( stepMeta, stepDataInterface, copyNr, transMeta, trans );
  }

  public boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
    meta = (SocketReaderMeta) smi;
    data = (SocketReaderData) sdi;

    try {
      Object[] r;

      if ( first ) {
        // Connect to the server socket (started during init)
        // Because the accept() call on the server socket can be called after we reached this code
        // it is best to build in a retry loop with a time-out here.
        //
        long startTime = System.currentTimeMillis();
        boolean connected = false;
        KettleException lastException = null;

        // // timeout with retry until connected
        while ( !connected
          && ( TIMEOUT_IN_SECONDS > ( System.currentTimeMillis() - startTime ) / 1000 ) && !isStopped() ) {
          try {
            int port = Integer.parseInt( environmentSubstitute( meta.getPort() ) );
            int bufferSize = Integer.parseInt( environmentSubstitute( meta.getBufferSize() ) );

            data.socket = new Socket( environmentSubstitute( meta.getHostname() ), port );
            connected = true;

            if ( meta.isCompressed() ) {
              data.outputStream =
                new DataOutputStream( new BufferedOutputStream( new GZIPOutputStream( data.socket
                  .getOutputStream() ), bufferSize ) );
              data.inputStream =
                new DataInputStream( new BufferedInputStream(
                  new GZIPInputStream( data.socket.getInputStream() ), bufferSize ) );
            } else {
              data.outputStream =
                new DataOutputStream( new BufferedOutputStream( data.socket.getOutputStream(), bufferSize ) );
              data.inputStream =
                new DataInputStream( new BufferedInputStream( data.socket.getInputStream(), bufferSize ) );
            }
            lastException = null;
          } catch ( Exception e ) {
            lastException =
              new KettleException( "Unable to open socket to server "
                + environmentSubstitute( meta.getHostname() ) + " port "
                + environmentSubstitute( meta.getPort() ), e );
          }

          if ( lastException != null ) { // Sleep for a second

            Thread.sleep( 1000 );
          }
        }

        if ( lastException != null ) {
          logError( "Error initialising step: " + lastException.toString() );
          logError( Const.getStackTracker( lastException ) );
          if ( data.socket != null ) {
            data.socket.shutdownInput();
            data.socket.shutdownOutput();
            data.socket.close();
            logError( "Closed connection to data socket to "
              + environmentSubstitute( meta.getHostname() ) + " port " + environmentSubstitute( meta.getPort() ) );
          }

          throw lastException;
        } else {
          if ( data.inputStream == null ) {
            throw new KettleException( "Unable to connect to the SocketWriter in the "
              + TIMEOUT_IN_SECONDS + "s timeout period." );
          }
        }

        data.rowMeta = new RowMeta( data.inputStream ); // This is the metadata
        first = false;
      }
      r = data.rowMeta.readData( data.inputStream );

      incrementLinesInput();

      if ( checkFeedback( getLinesInput() ) ) {
        logBasic( BaseMessages.getString( PKG, "SocketReader.Log.LineNumber" ) + getLinesInput() );
      }

      putRow( data.rowMeta, r );
    } catch ( KettleEOFException e ) {
      setOutputDone(); // finished reading.
      return false;
    } catch ( Exception e ) {
      if ( data.socket != null ) {
        try {
          data.socket.shutdownInput();
          data.socket.shutdownOutput();
          data.socket.close();
          logError( "Closed connection to data socket to "
            + environmentSubstitute( meta.getHostname() ) + " port " + environmentSubstitute( meta.getPort() ) );
        } catch ( IOException e1 ) {
          logError( "Failed to close connection to data socket to "
            + environmentSubstitute( meta.getHostname() ) + " port " + environmentSubstitute( meta.getPort() ) );
        }
      }
      throw new KettleException( e );
    }

    return true;
  }

  public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
    meta = (SocketReaderMeta) smi;
    data = (SocketReaderData) sdi;

    if ( super.init( smi, sdi ) ) {
      return true;
    }
    return false;
  }

  public void dispose( StepMetaInterface smi, StepDataInterface sdi ) {
    // Ignore errors, we don't care
    // If we are here, it means all work is done
    // It's a lot of work to keep it all in sync for now we don't need to do that.
    //
    try {
      data.inputStream.close();
    } catch ( Exception e ) {
      // Ignore nested exception
    }
    try {
      data.outputStream.close();
    } catch ( Exception e ) {
      // Ignore nested exception
    }
    try {
      data.socket.shutdownInput();
      data.socket.shutdownOutput();
      data.socket.close();
    } catch ( Exception e ) {
      // Ignore nested exception
    }

    super.dispose( smi, sdi );
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy