I have an application that has to send data via TCP socket to another application. This is a 1 way stream from client to server. When sending data the client must retry/reconnect and try to insure all data is sent should the receiver/listener/server die/disappear or drop the connection. My code is as follow:
public class TCPSocket implements Closeable {
private static final int SIXTY_FOUR_KB = 65536;
private final String ip;
private final int port;
private Socket socket;
private BufferedOutputStream writer;
public TCPSocket(String ip, int port) {
this.ip = ip;
this.port = port;
}
public TCPSocket connect() throws ConnectException {
try {
socket = new Socket(ip, port);
socket.setSendBufferSize(SIXTY_FOUR_KB);
writer = new BufferedOutputStream(socket.getOutputStream(), SIXTY_FOUR_KB);
} catch (Exception e) {
throw new ConnectException(e.getMessage());
}
return this;
}
public void write(String message) throws InterruptedException {
boolean succeeded = true;
do {
try {
writer.write(message.getBytes(StandardCharsets.UTF_8));
writer.write("\n".getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
System.out.println(e.getMessage());
succeeded = false;
// Exponential backoff to go here
try {
System.out.println("Attempting reconnection");
tryClose();
connect();
} catch (ConnectException connectException) {
System.out.println(connectException.getMessage());
}
}
} while (!succeeded);
}
private void tryClose() {
try {
close();
} catch (Exception ex) {
System.out.println("Failed closing TCPSocket");
}
}
#Override
public void close() throws IOException {
if (writer != null) {
writer.flush();
writer.close();
writer = null;
}
if (socket != null && !socket.isClosed()) {
socket.close();
socket = null;
}
}
}
N.B: Reason for using the BufferedOutputStream is because I'm sending small messages and all other methods couldn't get the same throughput in real world test scenario.
This all works as expected for me however I have a few points.
Is this the right way to do this or totally insane and will cause
serious problems?
When trying to clean up and close connections and the writer before
opening a new connection the following error is thrown and I am
unable to close the bufferedOutputStream
java.net.SocketException: Connection reset by peer: socket write error
If I socket.shutdownOutput(); before attempting to close the output stream then that also throws an exception. What is the correct way to clean up and reconnect?
I Have a code that connects to a bluetooth device, opens a bluetooth socket that communicates with a running thread which operates functions running in main activity.
I would like to move all the connecting sequence to another activity, and then operate the thread from the main one as done now. The problem is they are all connected.
I would like to have the option of sending a message between these activities(meaning remaining the socket operating from the other activity), i.e this message:
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
because it is impossible to pass handler between activities I don't know how/if possible to do so.
What is the best way of doing such a thing?
added part of the code.
Thanks.
mHandler = new Handler(){
public void handleMessage(android.os.Message msg){
if(msg.what == MESSAGE_READ){
String readMessage = null;
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
RxMessage = readMessage.split(" ");
if (sH.isStringInCorrectOrder(RxMessage,Weight))
populateListView(RxMessage);
mReadBuffer.setText(readMessage);
}
if(msg.what == CONNECTING_STATUS){
if(msg.arg1 == 1)
mBluetoothStatus.setText("Connected to Device: " + (String)(msg.obj));
else
mBluetoothStatus.setText("Connection Failed");
}
}
};
private void connectBT (){
mBluetoothStatus.setText("Connecting...");
// Get the device MAC address, which is the last 17 chars in the View
final String address = "98:D3:31:30:39:75";
final String name = "HC-06";
// Spawn a new thread to avoid blocking the GUI one
new Thread()
{
public void run() {
boolean fail = false;
BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
try {
mBTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
mBTSocket.connect();
} catch (IOException e) {
try {
fail = true;
mBTSocket.close();
mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
if(fail == false) {
mConnectedThread = new ConnectedThread(mBTSocket);
mConnectedThread.start();
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
}
}
}.start();
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.available();
if(bytes != 0) {
SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String input) {
byte[] bytes = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
Just declare mHandler as static and you can access it from all other activities. This will create a small temporary memory leak, but don't worry about it.
Few days ago, I struggled with how to access file sent by NettyClient without killing NettyServer. I got solution on StackOverFlow and the detail of question is here. The solution is that the client close channel after sending the file, and the server close the fileoutputstream in channelInactive method. The main code is below.
ClientHandler
public class FileClientHandler extends ChannelInboundHandlerAdapter {
private int readLength = 128;
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
sendFile(ctx.channel());
}
private void sendFile(Channel channel) throws IOException {
File file = new File("C:\\Users\\xxx\\Desktop\\1.png");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
ChannelFuture lastFuture = null;
for (;;) {
byte[] bytes = new byte[readLength];
int readNum = bis.read(bytes, 0, readLength);
if (readNum == -1) { // The end of the stream has been reached
bis.close();
fis.close();
lastFuture = sendToServer(bytes, channel, 0);
if(lastFuture == null) { // When our file is 0 bytes long, this is true
channel.close();
} else {
lastFuture.addListener(ChannelFutureListener.CLOSE);
}
return;
}
lastFuture = sendToServer(bytes, channel, readNum);
}
}
private ChannelFuture sendToServer(byte[] bytes, Channel channel, int length)
throws IOException {
return channel.writeAndFlush(Unpooled.copiedBuffer(bytes, 0, length));
}
}
ServerHandler
public class FileServerHandler extends ChannelInboundHandlerAdapter {
private File file = new File("C:\\Users\\xxx\\Desktop\\2.png");
private FileOutputStream fos;
public FileServerHandler() {
try {
if (!file.exists()) {
file.createNewFile();
} else {
file.delete();
file.createNewFile();
}
fos = new FileOutputStream(file);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("I want to close fileoutputstream!");
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
ByteBuf buf = (ByteBuf) msg;
try {
buf.readBytes(fos, buf.readableBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
buf.release(); // Should always be done, even if writing to the file fails
}
}
}
If now I need to send 10 thousands pictures but every picture is small like 1KB. I have to close and then establish channel frequently. It is a thing wasting many resources. How can I only close fileoutputstream but the channel is alive?
This is just an idea, and I have not tested it, but rather than sending each file in its own connection, you could start a stream where you send:
The number of files to be sent (once)
The file info and content (for each file)
The file size
The file name size
The file name
The file content (bytes)
The client would look something like this:
public void sendFiles(Channel channel, File...files) {
ByteBufAllocator allocator = PooledByteBufAllocator.DEFAULT;
int fileCount = files.length;
// Send the file count
channel.write(allocator.buffer(4).writeInt(fileCount));
// For each file
Arrays.stream(files).forEach(f -> {
try {
// Get the file content
byte[] content = Files.readAllBytes(f.toPath());
byte[] fileName = f.getAbsolutePath().getBytes(UTF8);
// Write the content size, filename and the content
channel.write(allocator.buffer(4 + content.length + fileName.length)
.writeInt(content.length)
.writeInt(fileName.length)
.writeBytes(fileName)
.writeBytes(content)
);
} catch (IOException e) {
throw new RuntimeException(e); // perhaps do something better here.
}
});
// Flush the channel
channel.flush();
}
On the server side, you would need a slightly more sophisticated channel handler. I was thinking of a replaying decoder. (Example here)
In that example, the decoder will read all the files and then forward to the next handler which would receive a list of Upload instances, but you could send each upload up the pipeline after each received file so you don't allocate as much memory. But the intent is to send all your files in one stream rather than having to connect/disconnect for each file.
I have java application deployed in weblogic the principal role from app is the communication with another API via socket. This another API is installed in another server. Ok
Sometime to here the java app started getting incomplete data from socket. I have analyzed the logs on the API side. The API return complete data but on weblogic server where java app is deployed not read complete data. Locally the java app work as well.
I suppose that it have something with server memory. I have no idea to solve this problem.
I search on google but have no answers.
Below this original message returned locally with succes:
#**#0 100-Autorizado o uso da NF-e 33170845242914003465652000000007511200000067 http://www4.fazenda.rj.gov.br/retrieve/QRCode?chNFe=33170845242914003465652000000007511200000067&nVersao=100&tpAmb=2&cDest=12345678998&dhEmi=323031372d30382d31385431333a30343a32302d30333a3030&vNF=110.00&vICMS=22.80&digVal=6b6e3774696b652f616b4878574a35414d766367347074497a62343d&cIdToken=000001&cHashQRCode=998144c803f3f5e56a0e1764647ccd6928c2a70d 333170000817607|2017-08-18T13:04:23-03:00|SVRSnfce201707171030|100 http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode? 6989*##*
Below is message returned in weblogic server incomplete:
#**#0 100-Autorizado o uso da NF-e 33170845242914003465652000000007501000000449 http://www4.fazenda.rj.gov.br/consultaNFCe/QRCode?chNFe=33170845242914003465652000000007501000000449&nVersao=100&tpAmb=2&cDest=22233344405&dhEmi=323031372d30382d31385431323a35343a30342d30333a3030&vNF=325.00&vICMS=61.75&digVal=7955796b6b4e64687a7342335470755166495847516c4343566e453d&cIdToken=000001&cHashQRCode=03e10ca5299ed5cb5acd7de5dc5db98df9c49d0e 333170000817573|2017-08-18T12:54:06-03:00|SVRSnfce201707171030|100 http://www4.fazenda.rj.go
Below is responsible class to send and read data:
#Repository
public class SocketRepository implements BaseRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(SocketRepository.class);
private Socket socket;
private static int BUFFER_SIZE = 2048;
private BufferedOutputStream bos;
private BufferedInputStream bis;
#Override
public synchronized String sendDataSocket(String buff, final OsbRequestDTO osbDto) throws Exception {
try {
LOGGER.info("start send data. ");
URL url = new URL(osbDto.getEmissor().getUrlLoja());
openConnection(url.getHost(), url.getPort());
if (this.bos == null) {
this.bos = new BufferedOutputStream(this.socket.getOutputStream(), BUFFER_SIZE);
}
if (this.bis == null) {
this.bis = new BufferedInputStream(this.socket.getInputStream(), BUFFER_SIZE);
}
this.bos.write(buff.getBytes(StandardCharsets.UTF_8));
this.bos.flush();
LOGGER.info("end send data. ");
return readMessagePaperless(bis);
} catch (Exception e) {
LOGGER.error("Erro :" + e.getMessage());
throw e;
} finally {
LOGGER.info("start finally block. ");
closeConnection();
LOGGER.info("End finally block.");
}
}
private String readMessagePaperless(final BufferedInputStream bis) throws IOException {
try {
LOGGER.info("start read data .");
byte[] bufferSize = new byte[512 * 1024];
int data = bis.read(bufferSize);
if (data == -1) {
return "";
}
LOGGER.info("end read data.");
return new String(bufferSize, 0, data, StandardCharsets.UTF_8);
} catch (Exception e) {
LOGGER.error("err." + e.getMessage());
throw e;
}
}
private void closeConnection() throws Exception {
try {
if (this.bos != null && this.bis != null) {
try {
this.bos.close();
this.bis.close();
} catch (Exception e) {
LOGGER.error("err :" + e.getMessage());
throw e;
}
}
if (this.socket == null) {
return;
}
this.socket.close();
this.socket = null;
this.bis = null;
this.bos = null;
} catch (Exception e) {
LOGGER.error("err :" + e.getMessage());
throw e;
}
}
private void openConnection(final String host, final int port) throws UnknownHostException, IOException {
LOGGER.info("start open socket conn.");
if (this.socket != null) {
return;
}
this.socket = new Socket(host, port);
LOGGER.info("end.");
}
}
The read will only read a chunk of data as provided by the network, normally around 1500 bytes depending on various factors. You should continue reading until you have received the complete message. When the connection is local it works differently.
I am programming my first Java Socket application that uses a Client/Server paradigm.
I have the following classes:
SocketServer
SocketClient
The objective of the application is to have a user input a file path to a .csv file on the Client Console/File System:
1. Create a Server Program that uses a Socket.
a. The Server receives a CSV path/filename located on the Client from the Client.
b. The Server accesses the Client CSV file and converts it to an XML file.
c. The Server streams the XML file contents, not the XML path/file
name, back to the Client.
Create a Client Program that uses a Socket. Use the same port as the
Server.
a. Prompt the user for the path/filename of a CSV file.
b. Send the path/filename to the Server for processing.
c. Receive the XML file stream from the Server Socket.
d. Save the XML file stream to a file stored on the Client.
e. Store the generated XML file anywhere on the Client.
I have already written the code for connecting the Sockets on both the Server and Client as well as for converting the .csv to .xml, however, I am struggling with:
Step 1b.The Server accesses the Client CSV file and converts it to an
XML file.
Can I access the .csv file located on the Client directly from the Server
OR
Do I have to transfer the file path back from the Server to the Client, then transfer the file to the Server for conversion, then transfer the new XML document back?
Based on the instructions, it sounds like there should be a way to access the file from the Server.
Here is the code that I have already written.
ClientController.java
public class ClientController extends ConsoleController {
// DEBUG
private static final boolean DEBUG = true;
private static final boolean DEBUG_STORE = false;
private static final boolean DEBUG_PROMPT = false;
private static final boolean DEBUG_VALUES = true;
// CONSTANTS
public static final String PROMPT_MESSAGE = "Enter the filepath to a '.csv' file to convert to a '.xml' file: ";
// MEMBERS
private String userFilepath;
private SocketClient mClient;
// CONSTRUCTORS
public ClientController() {
super();
mClient = null;
}
// LIFE-CYCLE METHODS
#Override
public void onCreate() {
// Setup the Connection to the Server
mClient = setupServerConnection();
// Get the path to the CSV file for conversion
requestPathToCSVFile();
// Attempt to Transfer the file
try {
sendPathToServer(userFilepath);
} catch (Exception e) {
System.out.println("Failed to transfer the file!");
System.out.println("Exception: ");
e.printStackTrace();
}
// Attempt to send some message 50 times
mClient.sendSomeMessages(3);
}
// CONVENIENCE METHODS
private SocketClient setupServerConnection() {
String hostname = "localhost";
int port = 54321;
byte[] data = "Hello Server".getBytes();
return new SocketClient(hostname, port, data);
}
private void requestPathToCSVFile() {
// Debug vars
boolean isEmpty = true;
boolean isDefaultMessage = true;
boolean isCSV = false;
while (true){
if (!isEmpty && !isDefaultMessage && isCSV) break;
// Prompt user
userFilepath = promptUser(PROMPT_MESSAGE);
System.out.println(userFilepath);
// Debugging
isEmpty = userFilepath.isEmpty();
isDefaultMessage = userFilepath.equals(DEFAULT_MESSAGE);
isCSV = isCSVPath(userFilepath);
// Output Debugging
if (DEBUG && DEBUG_VALUES) {
if (userFilepath != null) {
System.out.println("DEBUG userFilepath: " + userFilepath);
} else {
System.out.println("DEBUG userFilepath: isNull");
}
System.out.println("isEmpty: " + (isEmpty? "true":"false"));
System.out.println("DEBUG userFilepath:" + (isDefaultMessage? "true":"false"));
System.out.println("isCSVPath: " + (isCSVPath(userFilepath)? "true":"false"));
}
}
}
private void sendPathToServer(String path) {
// Send the filepath to the Server
mClient.sendMessage(path);
}
private boolean isCSVPath(String path) {
return Regex.hasExtension(path, "csv");
}
}
SocketServer.java
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
// An example of a very simple socket server.
public class SocketServer
{
// CONSTANTS
private static final boolean DEBUG = true;
private static final boolean DEBUG_NODES = true;
// FLAGS
private static final int FLAG_MESSAGE = 0;
private static final int FLAG_CONVERT_CSV_TO_XML = 1;
// CONSTANTS
private static final String TEMPORARY_FOLDER_PATH = "/tmp";
private static final String TEMP_CSV_FILENAME = "csvToConvertToXml.csv";
private static final String TEMP_XML_FILENAME = "xmlOfCsv.xml";
// MEMBERS
private int serverPort;
private ServerSocket mServerSocket = null;
private Socket mSocket;
private InputStream mSocketInput;
private OutputStream mSocketOutput;
private int mSocketFlag;
private String mPathToCsv;
public SocketServer(int serverPort)
{
this.serverPort = serverPort;
try
{
mServerSocket = new ServerSocket(serverPort);
}
catch (IOException e)
{
e.printStackTrace(System.err);
}
}
public void waitForConnections()
{
mSocket = null;
mSocketInput = null;
mSocketOutput = null;
while (true)
{
// Open a Socket on the Server and Wait for a Connection
openSocket();
// TODO CODE THE FLAGGING
mSocketFlag = 1;
switch (mSocketFlag) {
case FLAG_MESSAGE:
handleConnection();
break;
case FLAG_CONVERT_CSV_TO_XML:
handleFileConversionConnection();
break;
}
// Now close the socket.
closeSocket();
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleFileConversionConnection()
{
while(true)
{
byte[] buffer = new byte[1024];
int bytes_read = 0;
try
{
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = mSocketInput.read(buffer, 0, buffer.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0)
{
System.err.println("Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
// Set the mPathToCsv
mPathToCsv = new String(buffer, 0, bytes_read);
// Log the RECIEVED DATA
System.out.println("Server Received "+ bytes_read +" bytes, data=" + mPathToCsv);
System.out.println("mPathToCsv: " + mPathToCsv);
// Get the a the path supplied by the Client and save it in the /temp folder on the server
String pathToTempCsv = getFileFromClient(mPathToCsv,TEMPORARY_FOLDER_PATH, TEMP_CSV_FILENAME);
// Convert the Csv to XML
String pathToXmlForClient = convertCsvToXml(pathToTempCsv, TEMPORARY_FOLDER_PATH, TEMP_XML_FILENAME);
// Transfer the new XML Document to the Client
//transfer(pathToXmlForClient);
//
mSocketOutput.write(buffer, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering it.
mSocketOutput.flush();
}
catch (Exception e)
{
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleConnection()
{
while(true)
{
byte[] buffer = new byte[1024];
int bytes_read = 0;
try
{
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = mSocketInput.read(buffer, 0, buffer.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0)
{
System.err.println("Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.out.println("Server Received "+ bytes_read +" bytes, data=" + (new String(buffer, 0, bytes_read)));
mSocketOutput.write(buffer, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering it.
mSocketOutput.flush();
}
catch (Exception e)
{
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void openSocket() {
try
{
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
mSocket = mServerSocket.accept();
System.err.println("Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until accept() is called again.
mSocketInput = mSocket.getInputStream();
mSocketOutput = mSocket.getOutputStream();
}
catch (IOException e)
{
e.printStackTrace(System.err);
}
}
public void closeSocket() {
try
{
System.err.println("Closing socket.");
mSocket.close();
}
catch (Exception e)
{
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
// CONVENIENCE METHODS
public void transfer(String sfile) throws IOException {
if (DEBUG && DEBUG_NODES) System.out.println("Enter transfer(String sfile)");
// Create a new File object
File myFile = new File(sfile);
while (true) {
byte[] mybytearray = new byte[(int) myFile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
bis.read(mybytearray, 0, mybytearray.length);
// Get the OutputStream for the Socket
mSocketOutput.write(mybytearray, 0, mybytearray.length);
mSocketOutput.flush();
// Close the socket
bis.close();
}
}
public String getFileFromClient(String pathToFile, String destinationDirectory, String newFilename) {
if (DEBUG && DEBUG_NODES) System.out.println("Enter getFileFromClient(String pathToFile, String destinationDirectory, String newFilename)");
String pathToNewFile = destinationDirectory + "/" + newFilename;
// TODO GET THE FILE FROM THE CLIENT
if (DEBUG && DEBUG_NODES) System.out.println("Exit getFileFromClient(String pathToFile, String destinationDirectory, String newFilename)");
return pathToNewFile;
}
public String convertCsvToXml(String pathToCsv, String pathToDestinationDirectory, String newFilename) {
if (DEBUG && DEBUG_NODES) System.out.println("Enter convertCsvToXml(String pathToCsv, String pathToDestinationDirectory, String newFilename)");
String pathToNewFile = pathToDestinationDirectory + "/" + newFilename;
// TODO CREATE THE NEW FILE AND CONVERT THE CSV TO XML
XMLWriter xmlFile = new XMLWriter(pathToCsv, pathToNewFile);
xmlFile.csvToXml();
if (DEBUG && DEBUG_NODES) System.out.println("Exit convertCsvToXml(String pathToCsv, String pathToDestinationDirectory, String newFilename)");
return pathToNewFile;
}
public static void main(String argv[])
{
int port = 54321;
SocketServer server = new SocketServer(port);
server.waitForConnections();
}
}
SocketClient.java
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class SocketClient
{
// CONSTANTS
public static final int TRANSFER_SIZE_1KB = 1024;
// MEMBERS
private String mServerHostname = null;
private int mServerPort = 0;
private byte[] data = null;
private Socket mSocket = null;
private InputStream mSocketInput = null;
private OutputStream mSocketOutput = null;
public SocketClient(String ServerHostname, int ServerPort)
{
this(ServerHostname, ServerPort, null);
}
public SocketClient(String mServerHostname, int mServerPort, byte[] data)
{
this.mServerHostname = mServerHostname;
this.mServerPort = mServerPort;
this.data = data;
}
public void transfer( String outfile ) throws Exception {
// Open the Socket
openSocket();
// Create a new byte array size of 1KB
byte[] bytearray = new byte[TRANSFER_SIZE_1KB];
// Create a bufferedOutputStream from the outfile path
FileOutputStream fos = new FileOutputStream(outfile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// TESTING
fos.toString();
// Initialize values to 0
int bytesRead = 0;
int count = 0;
System.out.println("GOT HERE");
// Transfer the 'outfile' 1KB (1024 bytes) increments, each pass is 1KB chunk of files
while ((bytesRead = mSocketInput.read(bytearray, 0, bytearray.length)) != -1)
{
System.out.println("GOT HERE");
// Send the data to the Server
bos.write(bytearray, 0, bytesRead);
// If less than 1KB, finish the transfer using flush()
bos.flush();
System.out.println(++count);
}
// Log to console
System.out.println("Finished transferring " + outfile);
// Close the bufferedOutputStream
bos.close();
// Close the socket
closeSocket();
}
public void sendSomeMessages(int iterations)
{
// Open the Socket
openSocket();
byte[] buf = new byte[data.length];
int bytes_read = 0;
for(int x=1; x<=iterations; x++)
{
try
{
mSocketOutput.write(data, 0, data.length);
bytes_read = mSocketInput.read(buf, 0, buf.length);
}
catch (IOException e)
{
e.printStackTrace(System.err);
}
if( bytes_read != data.length )
{
System.out.println("run: Sent "+ data.length +" bytes, server should have sent them back, read "+bytes_read+" bytes, not the same number of bytes.");
}
else
{
System.out.println("Client Sent "+bytes_read+" bytes to server and received them back again, msg = "+(new String(data)));
}
// Sleep for a bit so the action doesn't happen to fast -
// this is purely for reasons of demonstration, and not required technically.
try { Thread.sleep(50);}
catch (Exception e) {};
}
System.err.println("Done reading/writing to/from socket, closing socket.");
// Close the Socket
closeSocket();
}
public void sendMessage(String str) {
// Open the Socket
openSocket();
// Convert the String to a Byte Array
byte[] data = str.getBytes();
// Create a buffer object the size of the data byte array
byte[] buf = new byte[data.length];
int bytes_read = 0;
// Attempt to send the data over the network
try
{
mSocketOutput.write(data, 0, data.length);
bytes_read = mSocketInput.read(buf, 0, buf.length);
}
catch (IOException e)
{
e.printStackTrace(System.err);
}
if( bytes_read != data.length )
{
System.out.println("run: Sent "+ data.length +" bytes, server should have sent them back, read "+bytes_read+" bytes, not the same number of bytes.");
}
else
{
System.out.println("Client Sent "+bytes_read+" bytes to server and received them back again, msg = "+(new String(data)));
}
// Sleep for a bit so the action doesn't happen to fast -
// this is purely for reasons of demonstration, and not required technically.
try { Thread.sleep(50);}
catch (Exception e) {};
System.err.println("Done reading/writing to/from socket, closing socket.");
// Close the Socket
closeSocket();
}
public void openSocket() {
// Open the Socket
System.err.println("Opening connection to "+mServerHostname+" port "+mServerPort);
try
{
mSocket = new Socket(mServerHostname, mServerPort);
mSocketInput = mSocket.getInputStream();
mSocketOutput = mSocket.getOutputStream();
}
catch (IOException e)
{
e.printStackTrace(System.err);
return;
}
System.err.println("About to start reading/writing to/from socket.");
}
public void closeSocket() {
// Close the Socket
try
{
mSocket.close();
}
catch (IOException e)
{
System.err.println("Exception closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Exiting.");
}
// GETTERS & SETTERS
public String getServerHostname() {
return mServerHostname;
}
public void setServerHostname(String serverHostname) {
this.mServerHostname = mServerHostname;
}
public int getServerPort() {
return mServerPort;
}
public void setServerPort(int serverPort) {
this.mServerPort = mServerPort;
}
public Socket getSocket() {
return mSocket;
}
public void setSocket(Socket socket) {
this.mSocket = mSocket;
}
public InputStream getSocketInput() {
return mSocketInput;
}
public void setSocketInput(InputStream socketInput) {
this.mSocketInput = mSocketInput;
}
public OutputStream getSocketOutput() {
return mSocketOutput;
}
public void setSocketOutput(OutputStream socketOutput) {
this.mSocketOutput = mSocketOutput;
}
}
SUPPORTING CLASSES
ConsoleController.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Comparator;
#SuppressWarnings("unused")
public abstract class ConsoleController {
// DEBUG
private static final boolean DEBUG = false;
private static final boolean DEBUG_STORE = false;
private static final boolean DEBUG_PROMPT = false;
private static final boolean DEBUG_VALUES = false;
// CONSTANTS
protected static final String DEFAULT_MESSAGE = "No input recieved";
// MEMBERS
private String mRecentInput;
// CONSTRUCTORS
public ConsoleController() {
mRecentInput = DEFAULT_MESSAGE;
}
// LIFE-CYCLE METHODS
abstract public void onCreate();
public String promptUser(String userPrompt) {
System.out.println(userPrompt);
try{
// Create BufferedReader to read from the Console
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
// Read the line from the console
mRecentInput = bufferRead.readLine();
if (mRecentInput.equalsIgnoreCase("Exit")) exit();
}
catch(IOException e)
{
e.printStackTrace();
}
return mRecentInput;
}
public String getInput() {
return mRecentInput;
}
public void exit() {
//System.out.println("Quiting");
System.exit(0);
}
}
Regex.java
import java.util.regex.Matcher;
import java.util.regex.Pattern;
#SuppressWarnings("unused")
public class Regex {
public static final boolean DEBUG = false;
public static final boolean DEBUG_HAS_EXT = true;
public static boolean hasExtension(String path, String extension) {
// Match Numberic and Hexadecimal Values
Pattern extTest = Pattern.compile("\\.(" + extension.trim() + ")$");
Matcher values = extTest.matcher(path);
if (DEBUG && DEBUG_HAS_EXT) {
System.out.println("Regex - Extension Matches");
System.out.println("Search String: " + path);
System.out.println("Pattern: " + extTest.pattern());
System.out.print("Match: ");
}
// Returns true if there is anotherMatch remaining, returns false if no matches remain
boolean anotherMatch = values.find();
if (anotherMatch == true) {
while(anotherMatch) {
// If we get here, there is a match
// Log
if (DEBUG && DEBUG_HAS_EXT) System.out.println(values.group());
// Check to see if there is anotherMatch
anotherMatch = values.find();
}
return true;
} else {
if (DEBUG && DEBUG_HAS_EXT) System.out.println("There was no match");
return false;
}
}
}
XMLWriter.java
import java.io.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
public class XMLWriter
{
// Members
private Document mDocumentForOutput;
private String mInFilePath;
private String mOutFilePath;
// CONSTRUCTORS
public XMLWriter(String filePathForConversion, String filePathForOutput) {
mInFilePath = filePathForConversion;
mOutFilePath = filePathForOutput;
try {
mDocumentForOutput = createDocument();
} catch (Exception e) {
System.out.println("Exception: ");
e.printStackTrace();
}
}
public Document createDocument() throws IOException, ParserConfigurationException
{
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = builderFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
return doc;
}
public void processDocument(String delimeter) throws Exception
{
// Get a File object from the InPath
File inFile = new File(mInFilePath);
// Create a BufferedReader from the file
BufferedReader reader = new BufferedReader(new FileReader(inFile));
// Read a line from the file
String sline = reader.readLine();
//
String[] sheaders = sline.split(delimeter);
sline = reader.readLine();
String[] snodes = sline.split(delimeter);
Element aroot;
Element achild;
aroot = mDocumentForOutput.createElement(sheaders[0].trim());
mDocumentForOutput.appendChild(aroot);
while ((sline=reader.readLine()) != null)
{
achild = mDocumentForOutput.createElement(sheaders[1].trim());
String[] sdata = sline.split(delimeter);
for (int x=0; x<snodes.length; ++x)
{
Element c = mDocumentForOutput.createElement(snodes[x].trim());
c.appendChild(mDocumentForOutput.createTextNode(sdata[x].trim()));
achild.appendChild(c);
}
aroot.appendChild(achild);
}
}
public void createXML() throws Exception
{
//TransformerFactory instance is used to create Transformer objects.
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// create string from xml tree
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(mDocumentForOutput);
transformer.transform(source, result);
String xmlString = sw.toString();
File file = new File(mOutFilePath);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
bw.write(xmlString);
bw.flush();
bw.close();
}
public void createXmlDocument(String delimeter) throws Exception
{
processDocument(delimeter);
createXML();
}
public void csvToXml() {
try {
createXmlDocument(",");
} catch (Exception e) {
System.out.print("Exception: ");
e.printStackTrace();
}
}
public static void testWriter(String csvFile)
{
try
{
try {
XMLWriter xmlWriter = new XMLWriter(csvFile, "Output.xml");
xmlWriter.csvToXml();
} catch (Exception e) {
System.out.println("'" + csvFile + "' does not exist in the given directory! Please check that you have properly entered your filepath");
}
System.out.println("<b>Xml File Created Successfully</b>");
}
catch(Exception e)
{
System.out.println(e);
}
}
}