org.pentaho.di.www.AllocateServerSocketServlet Maven / Gradle / Ivy
Show all versions of kettle-engine Show documentation
/*! ******************************************************************************
*
* 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.www;
import java.io.IOException;
import java.io.PrintStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.owasp.encoder.Encode;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.xml.XMLHandler;
/**
* This servlet allows a client (TransSplitter in our case) to ask for a port number.
* This port number will be allocated in such a way that the port number is unique for a given hostname.
* This in turn will ensure that all the slaves will use valid port numbers, even if multiple slaves run on the same
* host.
*
* @author matt
*
*/
public class AllocateServerSocketServlet extends BaseHttpServlet implements CartePluginInterface {
private static final long serialVersionUID = 3634806745372015720L;
public static final String CONTEXT_PATH = "/kettle/allocateSocket";
public static final String PARAM_RANGE_START = "rangeStart";
public static final String PARAM_HOSTNAME = "host";
public static final String PARAM_ID = "id";
public static final String PARAM_TRANSFORMATION_NAME = "trans";
public static final String PARAM_SOURCE_SLAVE = "sourceSlave";
public static final String PARAM_SOURCE_STEPNAME = "sourceStep";
public static final String PARAM_SOURCE_STEPCOPY = "sourceCopy";
public static final String PARAM_TARGET_SLAVE = "targetSlave";
public static final String PARAM_TARGET_STEPNAME = "targetStep";
public static final String PARAM_TARGET_STEPCOPY = "targetCopy";
public static final String XML_TAG_PORT = "port";
public AllocateServerSocketServlet() {
}
public AllocateServerSocketServlet( TransformationMap transformationMap ) {
super( transformationMap );
}
/**
/kettle/allocateSocket
GET
Allocates port to use by client.
Allows any client to ask for a port number to use. This is necessary several slaves can be run on the same host.
The method ensures the port number is unique for host name provided and makes sure the slaves are using
valid port numbers. Data communication across a cluster of Carte servers happens through TCP/IP sockets.
Slave transformations sometimes open (or listen to) tens to hundreds of sockets. When you want to allocate
the port numbers for data communication between slave transformation in a kettle clustering run, you need
unique combinations of all the parameters below.
port number
will be returned in the Response object. If an error occurred you'll receive html output
describing the problem. HTTP status code of such response is 500.
Example Request:
GET /kettle/allocateSocket/?xml=Y&rangeStart=100&host=locahost&id=clust&trans=my_trans&sourceSlave=slave_1
&sourceStep=200&sourceCopy=1&targetSlave=slave_2&targetStep=50&targetCopy=1
Parameters
name
description
type
xml
Boolean flag set to either Y
or N
describing if xml or html reply
should be produced.
boolean, optional
rangeStart
Port number to start looking from.
integer
host
Port's host.
query
id
Carte container id.
query
trans
Running transformation id.
query
sourceSlave
Name of the source slave server.
query
sourceStep
Port number step used on source slave server.
integer
sourceCopy
Number of copies of the step on source server.
integer
targetSlave
Name of the target slave server.
query
targetStep
Port number step used on target slave server.
integer
targetCopy
Number of copies of the step on target server.
integer
Response Body
element:
(custom)
media types:
text/xml, text/html
Response wraps port number that was allocated or error stack trace
if an error occurred. Response HTTP code is 200 if there were no errors. Otherwise it is 500.
Example Response:
100
Status Codes
code
description
200
Request was processed and XML response is returned.
500
Internal server error occurs during request processing.
This might also be caused by missing request parameter.
*/
public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
IOException {
if ( isJettyMode() && !request.getContextPath().startsWith( CONTEXT_PATH ) ) {
return;
}
if ( log.isDebug() ) {
logDebug( "Reservation of port number of step requested" );
}
response.setStatus( HttpServletResponse.SC_OK );
boolean useXML = "Y".equalsIgnoreCase( request.getParameter( "xml" ) );
String rangeStart = request.getParameter( PARAM_RANGE_START );
String hostname = request.getParameter( PARAM_HOSTNAME );
String clusteredRunId = request.getParameter( PARAM_ID );
String transName = request.getParameter( PARAM_TRANSFORMATION_NAME );
String sourceSlaveName = request.getParameter( PARAM_SOURCE_SLAVE );
String sourceStepName = request.getParameter( PARAM_SOURCE_STEPNAME );
String sourceStepCopy = request.getParameter( PARAM_SOURCE_STEPCOPY );
String targetSlaveName = request.getParameter( PARAM_TARGET_SLAVE );
String targetStepName = request.getParameter( PARAM_TARGET_STEPNAME );
String targetStepCopy = request.getParameter( PARAM_TARGET_STEPCOPY );
if ( useXML ) {
response.setContentType( "text/xml" );
response.setCharacterEncoding( Const.XML_ENCODING );
} else {
response.setContentType( "text/html" );
}
SocketPortAllocation port =
getTransformationMap().allocateServerSocketPort(
Const.toInt( rangeStart, 40000 ), hostname, clusteredRunId, transName, sourceSlaveName,
sourceStepName, sourceStepCopy, targetSlaveName, targetStepName, targetStepCopy );
PrintStream out = new PrintStream( response.getOutputStream() );
if ( useXML ) {
out.print( XMLHandler.getXMLHeader( Const.XML_ENCODING ) );
out.print( XMLHandler.addTagValue( XML_TAG_PORT, port.getPort() ) );
} else {
out.println( "" );
out.println( "Allocation of a server socket port number " );
out.println( "" );
out.println( "Status
" );
out.println( "" );
out.println( "Run ID : " + Encode.forHtml( clusteredRunId ) + "
" );
out.println( "Host name : " + Encode.forHtml( hostname ) + "
" );
out.println( "Transformation name : " + Encode.forHtml( transName ) + "
" );
out.println( "Source step : "
+ Encode.forHtml( sourceStepName ) + "." + Encode.forHtml( sourceStepCopy ) + "
" );
out.println( "Target step : "
+ Encode.forHtml( targetStepName ) + "." + Encode.forHtml( targetStepCopy ) + "
" );
out.println( "Step copy: " + Encode.forHtml( sourceStepCopy ) + "
" );
out.println( "
" );
out.println( "--> port : " + Encode.forHtml( port.toString() ) + "
" );
out.println( "
" );
out.println( "" );
out.println( "" );
}
}
public String toString() {
return "Servet socket port number reservation request";
}
public String getService() {
return CONTEXT_PATH + " (" + toString() + ")";
}
public String getContextPath() {
return CONTEXT_PATH;
}
}