/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 by Pentaho : 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.socketwriter; import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import org.pentaho.di.core.Const; import org.pentaho.di.core.exception.KettleException; 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; /** * Write data to a TCP/IP socket read by SocketReader. The data being sent over the socket is one serialized Row object * including metadata and then a series of serialized rows, data only. * * This part of the SocketWriter/SocketRead pair contains the ServerSocket. * * @author Matt * @since 1-dec-2006 */ public class SocketWriter extends BaseStep implements StepInterface { private static Class<?> PKG = SocketWriterMeta.class; // for i18n purposes, needed by Translator2!! private SocketWriterMeta meta; private SocketWriterData data; public SocketWriter( 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 = (SocketWriterMeta) smi; data = (SocketWriterData) sdi; try { if ( first ) { int bufferSize = Const.toInt( environmentSubstitute( meta.getBufferSize() ), 1000 ); data.clientSocket = data.serverSocket.accept(); if ( meta.isCompressed() ) { data.outputStream = new DataOutputStream( new BufferedOutputStream( new GZIPOutputStream( data.clientSocket .getOutputStream() ), bufferSize ) ); } else { data.outputStream = new DataOutputStream( new BufferedOutputStream( data.clientSocket.getOutputStream(), bufferSize ) ); } data.flushInterval = Const.toInt( environmentSubstitute( meta.getFlushInterval() ), 4000 ); } } catch ( Exception e ) { logError( "Error accepting from socket : " + e.toString() ); logError( "Stack trace: " + Const.CR + Const.getStackTracker( e ) ); setErrors( 1 ); stopAll(); setOutputDone(); if ( data.clientSocket != null ) { try { data.clientSocket.shutdownInput(); data.clientSocket.shutdownOutput(); data.clientSocket.close(); logError( "Closed connection to SocketWriter" ); } catch ( IOException e1 ) { logError( "Failed to close connection to SocketWriter" ); } } return false; } Object[] r = getRow(); // get row, set busy! // Input rowMeta is automatically set, available when needed if ( r == null ) { // no more input to be expected... setOutputDone(); return false; } try { if ( first ) { getInputRowMeta().writeMeta( data.outputStream ); first = false; } getInputRowMeta().writeData( data.outputStream, r ); incrementLinesOutput(); // flush every X rows if ( getLinesOutput() > 0 && data.flushInterval > 0 && ( getLinesOutput() % data.flushInterval ) == 0 ) { data.outputStream.flush(); } } catch ( Exception e ) { logError( "Error writing to socket : " + e.toString() ); logError( "Failing row : " + getInputRowMeta().getString( r ) ); logError( "Stack trace: " + Const.CR + Const.getStackTracker( e ) ); setErrors( 1 ); stopAll(); setOutputDone(); return false; } if ( checkFeedback( getLinesRead() ) ) { logBasic( BaseMessages.getString( PKG, "SocketWriter.Log.LineNumber" ) + getLinesRead() ); } return true; } public boolean init( StepMetaInterface smi, StepDataInterface sdi ) { meta = (SocketWriterMeta) smi; data = (SocketWriterData) sdi; if ( super.init( smi, sdi ) ) { try { data.serverSocketPort = Integer.parseInt( environmentSubstitute( meta.getPort() ) ); data.serverSocket = getTrans().getSocketRepository().openServerSocket( data.serverSocketPort, getTransMeta().getName() + " - " + this.toString() ); return true; } catch ( Exception e ) { logError( "Error creating server socket: " + e.toString() ); logError( Const.getStackTracker( e ) ); } } 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. // if ( data.outputStream != null ) { try { data.outputStream.close(); } catch ( Exception e ) { // Ignore errors } } if ( data.clientSocket != null && !data.clientSocket.isClosed() ) { try { data.clientSocket.shutdownInput(); data.clientSocket.shutdownOutput(); data.clientSocket.close(); if ( log.isDetailed() ) { logDetailed( "Closed connection to SocketWriter" ); } } catch ( IOException e1 ) { logError( "Failed to close connection to SocketWriter" ); } } if ( data.serverSocket != null && !data.serverSocket.isClosed() ) { try { data.serverSocket.close(); } catch ( IOException e ) { // Ignore errors } } try { getTrans().getSocketRepository().releaseSocket( data.serverSocketPort ); } catch ( IOException ignore ) { // Ignore errors } super.dispose( smi, sdi ); } }