1. Introduction
There are 2 servers:
- Web server that makes the request to the socket server
- The Socket server that receives the request and executes a shell program
The shell program may include a shell script or it can execute a java program. The call to this programs is similar:
2. The SocketAction class in the webserver
This class inherits from BaseExecute that defines the base facilities.
It has a method "execute" that receives the fix and form params from the "application.yaml" file that is in the IFXX java project, for instance:
fixParams: '[STRING:JAVA_PATH -jar JARS_FOLDER/IF/MiJar.jar AYTOSOPERATION]', formParams: '{name: s_n, type: STRING, length: 1, value: S, required: true }'
In addition, it constructs a message to send to the socket server adding these additional parameters to the fix and form parameters:
- INET address of the user
- user name
- user-agent (Mozilla, Chrome..)
- Session-Id (HTTP)
Then the socket server IO and port is got from the properties: "var server".ip and "var server".port from the "app.properties" file.
The "var server" is an attribute of the action. By default, the value is "socket". This value is set in the application.yaml file when defining an action
server: socket,
The logic of sending and receiving messages with the server is defined in the procedure sendMessageCommand :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | private void sendMessageCommand(String msg) throws IOException { //System.out.println("Sending to server:"+ msg); String fileName1=null; byte[] bytes=null; String fileName1Key="(DOWNLOADER-FILENAME)"; String bytesKey="(DOWNLOADER-BYTES)"; String nRecords="(N.RECORDS=)"; out.println(msg); String line = in.readLine().trim(); //ERROR:* means that an error has occurred //FIN:* means the end of the process while (! line.toUpperCase().startsWith("ERROR") && ! line.toUpperCase().startsWith("FIN:")) { if (line.contains(fileName1Key)) { int pos=line.indexOf(fileName1Key); fileName1=line.substring(pos+fileName1Key.length()); } else if (line.contains(bytesKey)) { int pos=line.indexOf(bytesKey); bytes=Base64.getDecoder().decode(line.substring(pos+bytesKey.length())); bytes=ZipUtils.decompress(bytes); addDownloaderEdu(fileName1, bytes); } else if (line.contains(nRecords)) { aS[2]=line.substring(line.indexOf(nRecords)+nRecords.length()); showMessage(line); } else showMessage(line, line.contains("ERROR")); line = in.readLine(); //getAfectedRecords(line); } if (line.toUpperCase().startsWith("ERROR")) showError(line); else showMessage(line, line.contains("ERROR")); } |
We can see that the condition for finishing the communication is that the message line starts with "ERROR" or "FIN:" . The first key indicates that an error has occurred, and the second one that the end of the process has been reached.
there are other keys that can contain the line message:
- (DOWNLOADER-FILENAME) and (DOWNLOADER-BYTES): To create a component called "DownloaderEdu" that downloads a file whose name is after the first key and the byte array to download is after the second key. NOTE that the byte arrays are compressed with ZIP and transformed to Base64.
- (N.RECORDS=) the number of affected records by the process is sent after this key
3. The Socket server
There are 3 important files:
- app.properties: defines port to listen and paths to java and shells scripts
- SimpleSocketServer class: the class with the main method to be executed once and manage the requests
- ServerRequestHandler: Manages the treatment of the requests.
Here is the code:
app.properties:
1 2 3 4 5 | #---location of shells scripts and java programs to be executed as external options socket.port = 6666 java.path = /home/USER/MyPrograms/jdk-15.0.1/bin/java jars.folder = /home/OTHERUSER/MyJars shells.folder = /home/OTHERUSER/MyShells |
SimpleSocketServer.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | package u.requests.sockets; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; import utils.PropertiesUtils; /** * Only open port for serving messages * The important part is the access to ServerRequestHandler03 that manages all the logic * @author ximo * */ public class SimpleSocketServer extends Thread { private boolean isExecutedFromJar=false; //????? Cambiar al compilar private ServerSocket serverSocket; private int port; private boolean running = false; //private String propsFileName="properties"+File.separator+"app.properties"; private Properties props=null; public SimpleSocketServer(){ port=6666; try { props=PropertiesUtils.getProperties(isExecutedFromJar,"app"); port=Integer.parseInt(props.getProperty("socket.port",""+port)); } catch (Exception e) {e.printStackTrace();} } public void startServer() { try { serverSocket = new ServerSocket( port ); this.start(); } catch (IOException e) { e.printStackTrace(); } } public void stopServer() { running = false; this.interrupt(); } @Override public void run() { running = true; //This is for accepting multiple connections while( running ) { try { System.out.println( "System.out.println-->Listening for a connection" ); // Call accept() to receive the next connection Socket socket = serverSocket.accept(); // Pass the socket to the RequestHandler thread for processing ServerRequestHandler requestHandler = new ServerRequestHandler(socket, props ); requestHandler.start(); } catch (IOException e) { e.printStackTrace(); } } } public static void main( String[] args ) { SimpleSocketServer server=null; try { server=new SimpleSocketServer(); System.out.println( "SimpleSocketServer03.Start server on port: " + server.port ); server.startServer(); /* // Automatically shutdown in 1 minute try { Thread.sleep( 60000 ); } catch( Exception e ) { e.printStackTrace(); } */ } catch (Exception e) { if (server!=null) { server.stopServer(); System.out.println("server stopped"); e.printStackTrace(); } } } } |
ServerRequestHandler.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | package u.requests.sockets; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Properties; import utils.CmdUtils; class ServerRequestHandler extends Thread { private Socket socket; private String command=""; //private String myPath=""; private String shellsFolder=""; private String jarsFolder=""; private String javaPath=""; private Properties props=null; private Boolean isError=false; private BufferedReader inSocket =null; private PrintWriter outSocket=null; private ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); public ServerRequestHandler(Socket socket, Properties props ) { this.socket = socket; this.props=props; } @Override public void run() { try { System.out.println( "RH-->Received a connection" ); // Get input and output streams inSocket = new BufferedReader( new InputStreamReader( socket.getInputStream() ) ); outSocket = new PrintWriter( socket.getOutputStream(), true ); command = inSocket.readLine(); outSocket.println("4.1 Des del server: Obtenint comandament a executar...("+ command +")"); if (command.trim().length() <2) showError("ERROR: Comandament curt:("+ command + ")"); else { try { shellsFolder=props.getProperty("shells.folder").trim(); jarsFolder=props.getProperty("jars.folder").trim(); javaPath=props.getProperty("java.path").trim(); //command=myPath.trim() + File.separator+ command; command=command .replace("JAVA_PATH", javaPath) .replace("SHELLS_FOLDER", shellsFolder) .replace("JARS_FOLDER", jarsFolder); System.out.println("COMMAND="+ command); } catch (Exception e) { showError("ERROR : Obrint paràmetres del fitxer de propietats... app.properties" + e.getMessage());} } if (!isError) { outSocket.println("4.2 Des del server: Executant...("+ command +")"); try { //Execute and wait for end of execution if(CmdUtils.execProgram(command, null, null, false, outputStream) !=0) showError("ERROR 4: Executant " + command + "... "); }catch (Exception e) { showError("ERROR 4.2: Executant " + command + "... " + e.getMessage());} } if (!isError) { outSocket.println("4.3 Des del server: Informant ..."); try { //Show execution details int i=0; for (String line : outputStream.toString().split("\\n")) { String lineUP=line.toUpperCase(); if (lineUP.contains("SHOWMESS") || lineUP.contains("ERROR")) { outSocket.println("4.3." + ++i + "-->" + line); System.out.println("4.3." + i + "-->" + line); } } }catch (Exception e) { showError("ERROR 4.3: Executant " + command + "... " + e.getMessage());} } if (!isError) outSocket.println("FIN:"); //END OF PROCESS SIGNAL!! // Close our connection inSocket.close(); outSocket.close(); socket.close(); System.out.println( "Rh:->Connection closed" ); } catch( Exception e ) { e.printStackTrace(); } } private void showError(String message) { isError=true; outSocket.println(message); } } |