
com.centurylink.mdw.soccom.SoccomClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mdw-common Show documentation
Show all versions of mdw-common Show documentation
MDW is a microservices based workflow framework
/*
* Copyright (C) 2017 CenturyLink, Inc.
*
* 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 com.centurylink.mdw.soccom;
// need to log time
// need to set timeout
// need to check msg ID in client_getresp
import java.io.*;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
/**
* This class defines the method for soccom client.
*
* Sample usage:
*
* try {
* SoccomClient client = new SoccomClient(host, port);
* client.putreq("test message");
* String resp = client.getresp();
* System.out.println("response: " + resp);
* client.close();
* } catch (SoccomException e) {
* System.out.println("Exception: " + e);
* }
*
*
* For large messages, if we'd like to get the messages line-by-line
* in order to display first part of messages before the entire message is
* received, instead of getresp()
, we can use the following code:
*
* String resp = client.getresp_first();
* System.out.println("response first: " + resp);
* while (client.getresp_hasmore()) {
* resp = client.getresp_next();
* System.out.println("response next: " + resp);
* }
*
*
* Similarly, we can also send message line-by-line, as shown in the following
* example:
*
* String endmark = "////";
* putreq_vheader(endmark);
* for (int i=0; i<number_of_lines; i++) {
* putreq_vline(lines[i]);
* }
* putreq_vfooter(endmark);
*
*
* It is not necessary to open/close the connection for each request,
* although a server or a pool has a limited number of open connection
* allowed.
*
* @auther Jiyang Xu
* @version 4.5
*/
public class SoccomClient
{
/**
* Basic constructor.
* @param host Either a domain name or an IP address.
* @param port The port number.
* @param log A PrintStream for printint log lines
* @exception SoccomException The exception is thrown possibly because
* of the following reasons:
*
* - Host name is unknown
* - Cannot connect to the service
* - Failed to create the socket
*
*/
public SoccomClient(String host, int port, PrintStream log)
throws SoccomException
{
_log = log;
try {
_socket = new Socket(host, port);
logline("Client connect on host " + host +
", port " + port);
logline("Local address: " + _socket.getLocalAddress());
_in = _socket.getInputStream();
_out = _socket.getOutputStream();
_msgid = new byte[SoccomMessage.MSGID_SIZE];
} catch (UnknownHostException e) {
throw new SoccomException(SoccomException.HOSTNAME, e);
} catch (ConnectException e) {
throw new SoccomException(SoccomException.CONNECT, e);
} catch (IOException e) {
throw new SoccomException(SoccomException.CREATE_SOCKET, e);
}
}
/**
* Alternative constructor. It has no parameter for log PrintStream
* and it logs all messages to the terminal screen.
*
* @param host Either a domain name or an IP address.
* @param port The port number.
* @exception SoccomException The exception is thrown possibly because
* of the following reasons:
*
* - Host name is unknown
* - Cannot connect to the service
* - Failed to create the socket
*
*/
public SoccomClient(String host, int port)
throws SoccomException
{
this(host, port, System.out);
}
private void copy_msgid(byte[] target, byte[] source) {
for (int i=0; i0) got += n;
else if (n==-1)
throw new SoccomException(SoccomException.SOCKET_CLOSED);
else throw new SoccomException(SoccomException.RECV_ERROR);
}
msg = new String(buffer, 0, size);
}
logline("RECV MSG: " + msg);
return msg;
} catch (InterruptedIOException e) {
throw new SoccomException(SoccomException.RECV_ERROR);
} catch (IOException e) {
throw new SoccomException(SoccomException.RECV_ERROR);
}
}
/**
* This is the same as getresp(int timeout)
* except the timeout value is set to the default 120 seconds.
* @return The response message.
* @exception SoccomException Thrown when an IOException is encountered.
*/
public String getresp()
throws SoccomException
{
return getresp(120);
}
/**
* The method receives the first part of response message from the
* server, up to maxbytes bytes.
* Use getresp_hasmore and getresp_next to get
* getresp_rest to get the remaining part of messages.
* When the server sends the message using ENDM, the string returned
* may be longer than maxbytes, but only till the first line after that.
* When maxbytes is 0, the procedure reads the first line.
* @param maxbytes The maximum number of bytes to be returned.
* @param timeout timeout in seconds
* @return The string converted from the bytes read.
* @exception SoccomException
* Any transmission error such as reading socket error.
*/
public String getresp_first(int maxbytes, int timeout)
throws SoccomException
{
int n;
String sizestr, msg;
_resp_read = -1;
try {
byte[] _header = new byte[SoccomMessage.HEADER_SIZE];
_socket.setSoTimeout(timeout*1000);
n = _in.read(_header, 0, SoccomMessage.HEADER_SIZE);
if (n!=SoccomMessage.HEADER_SIZE)
throw new SoccomException(SoccomException.RECV_HEADER);
logline("RECV HDR: " + new String(_header));
check_msgid(_msgid, _header);
sizestr = new String(_header, SoccomMessage.MSGSIZE_OFFSET, 8);
if (sizestr.startsWith("ENDM")) _resp_size = -1;
else _resp_size = Integer.parseInt(sizestr);
} catch (InterruptedIOException e) {
throw new SoccomException(SoccomException.RECV_HEADER);
} catch (IOException e) {
throw new SoccomException(SoccomException.RECV_HEADER);
}
try {
if (maxbytes==0) {
if (_resp_size == -1) {
_endm = sizestr.substring(4,8);
}
_resp_read = 0;
if (getresp_hasmore()) msg = getresp_next(maxbytes);
else msg = "";
} else if (_resp_size == -1) {
_endm = sizestr.substring(4,8);
byte[] buffer = new byte[maxbytes];
int k=0;
boolean done = false;
while (!done && k=0) {
_resp_read = n;
msg = new String(buffer, 0, n);
} else if (n==-1)
throw new SoccomException(SoccomException.SOCKET_CLOSED);
else throw new SoccomException(SoccomException.RECV_ERROR);
logline("RECV MSG: " + msg);
}
return msg;
} catch (InterruptedIOException e) {
throw new SoccomException(SoccomException.RECV_ERROR);
} catch (IOException e) {
throw new SoccomException(SoccomException.RECV_ERROR);
}
}
/**
* same as getresp_first(int maxbytes, int timeout)
* except the timeout is default to 120 seconds
*/
public String getresp_first(int maxbytes)
throws SoccomException
{
return getresp_first(maxbytes, 120);
}
/**
* same as getresp_first(int maxbytes, int timeout)
* except the timeout is default to 120 seconds and maxbytes is 0
*/
public String getresp_first()
throws SoccomException
{
return getresp_first(0, 120);
}
/**
* The method checks if the message is completed read.
* @return true
if the message has not been completed
* read by getresp_first()
or
* getresp_next()
.
*/
public boolean getresp_hasmore() {
if (_resp_size>0) {
return _resp_read>=0 && _resp_size > _resp_read;
} else {
return (_resp_read>=0);
}
}
private int readLine(InputStream in, byte buffer[], int offset,
int maxbytes)
throws IOException
{
int n = 0;
boolean line_read = false;
while (!line_read && n=0) _resp_read += n;
else if (n==-1)
throw new SoccomException(SoccomException.SOCKET_CLOSED);
else throw new SoccomException(SoccomException.RECV_ERROR);
msg = new String(buffer, 0, n);
}
}
logline("RECV MSG: " + msg);
return msg;
} catch (InterruptedIOException e) {
throw new SoccomException(SoccomException.RECV_ERROR);
} catch (IOException e) {
throw new SoccomException(SoccomException.RECV_ERROR);
}
}
private void logline(String msg) {
if (_log!=null) _log.println(msg);
}
/**
* Same as getresp_next(0), i.e. read in the next line
*/
public String getresp_next()
throws SoccomException
{
return getresp_next(0);
}
/**
* This method is a simple wrapper for synchronous invocation
* of server's service. It is roughly implemented as:
*
* SoccomClient soccom = new SoccomClient(host,port,log);
* putreq(msg);
* return getresp();
* soccom.close();
*
* @param serverspec In the form of host:port. If ':' is missing, assume
* port is 4001
* @param msg The message to be sent.
* @param timeout Time out in seconds
* @param log For logging information
* @return The respose message.
* @exception SoccomException It passes up any exception encountered
* along the way.
*/
public static String call(String serverspec, String msg,
int timeout, PrintStream log)
throws SoccomException
{
String host;
int port;
int k = serverspec.indexOf(':');
if (k >= 0) {
host = serverspec.substring(0,k);
port = Integer.parseInt(serverspec.substring(k+1));
} else {
host = serverspec;
port = 4001;
}
SoccomClient soccom = new SoccomClient(host, port, log);
String reply;
try {
soccom.putreq(msg);
reply = soccom.getresp(timeout);
soccom.close();
} catch (SoccomException e) {
soccom.close();
throw e;
}
return reply;
}
/**
* Close the connection.
* This is automatically called at garbage collection but
* it is a good idea to voluntarily call it as soon as the connection
* is not needed any more.
*/
public void close()
{
if (_socket!=null) {
try {
_socket.close();
_socket = null;
} catch (IOException e) {
System.err.println("Exception: " + e);
// throw new SoccomException(SoccomException.RECV_ERROR);
}
_in = null;
_out = null;
}
}
/**
* The method calls close()
if the socket has not been
* closed yet.
*/
protected void finalize() {
close();
}
/**
* Tests for client
*/
private String tests(String msg)
{
String testcase = msg.substring(6,12);
String resp;
try {
if (testcase.equals("TIMEOU")) {
int timeout = Integer.parseInt(msg.substring(13));
putreq("SLEEP " + (timeout+5));
resp = getresp(timeout);
} else if (testcase.equals("COMBIN")) {
/* test combination of sending/receiving line-by-line
* or as a whole. Spec has 4 characters as follows:
* 1. for client send: W - as a whole, L - line-by-line
* 2. for server recv: W - as a whole, L - not implemented
* 3. for server send: W - as a whole, L - line-by-line
* 4. for client recv: W - as a whole, L - line-by-line
*/
StringTokenizer st = new StringTokenizer(msg.substring(12));
String testspec = msg.substring(13,17);
if (testspec.charAt(0)=='L') {
String endmark = "////";
putreq_vheader(endmark);
st = new StringTokenizer(msg, "\n");
while (st.hasMoreTokens()) {
putreq_vline(st.nextToken());
}
putreq_vfooter(endmark);
} else putreq(msg);
if (testspec.charAt(3)=='L') {
resp = getresp_first();
while (getresp_hasmore()) {
resp = resp + getresp_next();
}
} else if (testspec.charAt(3)=='P') {
String one;
resp = getresp_first(80);
while (getresp_hasmore()) {
one = getresp_next(80);
resp = resp + one;
}
} else resp = getresp();
} else { // default: REQRES, testing reqresp
/* SV_LBL falls here, too */
putreq(msg);
resp = getresp();
}
} catch (SoccomException e) {
resp = "TEST ERROR " + e.errdesc() + "\n";
}
return resp;
}
private static void printUsage()
{
System.err.println("Usage: java soccom.SoccomClient host port msg");
}
private InputStream _in;
private OutputStream _out;
private byte _msgid[];
private Socket _socket;
private PrintStream _log;
// the followings are used only by getresp_first() and getresp_next();
private int _resp_size;
private int _resp_read;
private String _endm;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy