Digital Edition

SYS-CON.TV
Sending Data to a Java Server
Sending Data to a Java Server

When I read about the opportunity to submit articles to Java Developer's Journal one of the first topics that came to mind concerns the desire to be able to record or log data from a web page on the server. Every day I hear questions about outputting data to the server, be it to simply log user information in a guest book, or to have some other, more critical business data sent to the server for more processing; such as an order form.

Of course, you and I both know this is possible using some sort of CGI (considerably goofy intermediary?) program that will write the file. You could also hook your web server up to a several thousand dollar database back end and use another method to get the data there.

No, what many of us are looking for is a simple way, in Java, to send data to the server. Why in Java and not a CGI program? The simplest answer is so that we can have a cross platform solution written in a simple, stable, OO language. While we're at it we'll plop half of it into a web page so that customers or friends will have easy access from a browser!

Enter DataReceiver, DataSender and DataApplet. All three combine into a simple solution to get some formatted text from an applet in a web page to a file on your web server.

What It Looks Like at a Glance
Your customer fires up his web browser and types in http://your.home.page.here/. He sees a small Java applet (DataApplet) that has some editable TextFields for him to enter his personal information and a request for some product information to the web master (you), as shown in Figure 1. He then clicks the Submit Request' button and the text is saved to a log file on the server. You read the text file and contact the customer regarding his request.

The "Under the Hood" Basics
When the Submit Request' button is clicked, DataApplet gets the text from all the TextField and TextArea objects in the applet and formats it into one long String with commas separating each field. DataSender is responsible for establishing a connection to DataReceiver on the web server and sending it the formatted String. It wasn't too difficult for DataSender to determine which server DataReceiver is on because of applet security restrictions. Currently, an applet can only make a network connection to the server that it was loaded from. DataApplet gets the name of its server using the getDocumentBase().getHost() methods and then passes it to DataSender at the same time it passes it the String to be sent.

Meanwhile, on the server, DataReceiver is waiting for incoming connections. After accepting a connection, it reads the incoming data and writes it to a file. In the example code the file is formatted as a comma delimited text file so that it can easily be imported into your favorite spread sheet or database program (See Figure 2).

Java Sockets and How They Relate to Our Problem
The key to the data transfer is a very useful package included with the Sun JDK called java.net'. The java.net package gives us the essential tools to wait for connections on the DataReceiver side and attempt to establish connections on the DataSender side. Remember, DataApplet only passes the String to DataSender who then does all the work of sending it, as shown in Listing 1.

To break things down further (you may want to peek at the code in Listings 2 and 3) let's talk about sockets. Sockets, simply put, are end points of communication. When using them directly, as I do with DataSender and DataReceiver, we are sending data from one "end" to the other, or from the client socket to the server socket. When programming with sockets I usually think in terms of what I have to do to get the data to the socket on the local side of the link and then how I will handle it on the other side. Whatever happens between here and there is left up to the socket implementation and network conditions. Basically, with sockets, most of the hairy details of network programming are hidden from the programmer.

In Java, sockets are quite elegant, thanks to Sun's abstraction of sockets into the Socket class and the ServerSocket class. The Socket class represents a connection to another Socket that data can be both read from and written to. By using the getInputStream() and getOutputStream() methods with an instance of Socket you can read and write data the way you would anywhere else in Java. ServerSocket, as its name implies, is meant for accepting connections, which coincidentally is accomplished by calling its accept()' method. On the server side, when accept() gets an incoming connection it returns a Socket object that can then be used to read from and write to.

In my example, DataSender uses an instance of the Socket class to connect to DataReceiver, which uses an instance of the ServerSocket class. Let's move on into the code.

On the Receiving End
Following the basic model in Figure 1, let's start with the receiving end. DataReceiver is a simple Java application that has a couple of clearly defined responsibilities. First it must accept connections, possibly many at a time. Then, it must be able to receive and write some data from those connections to a file.

It doesn't seem too difficult, and it isn't! The only tricky part is handling the "possibly many" connections. This is where that almighty concept of threaded programming comes into play. The makers of Java of course have built threads into the language and these threads are exactly what I use in DataReceiver. A thread basically does its work and then dies. A Thread class has a run()' method which is analogous to the main() method of a Java application. The run() method is where a thread's execution starts (and usually finishes).

DataReceiver's main' method creates a ServerSocket object and then starts a loop which calls the ServerSocket's accept() method. Since accept() won't return until an inbound connection is made a loop seemed like the simplest way to always be waiting for a connection. When a connection is made we create a new DataReceiver object and pass it the Socket returned by accept(). Since DataReceiver extends the Java Thread class all we have to do to get it going is call its start() method. When DataReceiver's start() method is called, the loop execution resumes at the top and the DataReceiver object starts running (concurrently) with its run() method (See Listing 2).

Now that we have an inbound connection established and a DataReceiver thread running we have to get the appropriate input stream, read the incoming data and then write it to the file.

DataReceiver's constructor handles creating a DataInputStream object by using the passed Socket's getInputStream() method. This means that any data read from this DataInputStream object will be data that has come in from the network, and hence data that needs to be written to the file. DataInputStream seemed like a good choice for this project because it provides some handy methods for reading the simple data being sent from DataSender (i.e. readLine()).

In the run() method, where thread execution actually begins, we call the DataInputStream's readLine() method. This method will stop reading when an end of line character is reached and then return a String object containing the data read. This String is then passed to the local writeData() method where it is then written to the file. You may notice that the writeData() method is declared with the synchronized' modifier. This is very important to avoid file corruption and general havoc on the server end. The reason being is that there is a good chance that many DataReceiver threads could running concurrently (possibly because of several hits to your web page), our job is to make sure that only one will be writing its data to the file at any given time. When the synchronized keyword is used, Java guarantees that only one thread will be executing that method and others will be queued and have access when it becomes available. You may also want to take note of the FILENAME' constant in DataReceiver.java. This represents a system dependent filename. If your server machine is not running on Windows NT, Windows 95, or does not otherwise understand DOS style directory names you should change this to represent a valid path + filename for your system (See Listing 3).

Sending Data with DataSender
DataSender is quite straightforward. Its constructor takes a String object that represents the server machine it must connect to and a String object that contains the data which it must sent to that server.

The Socket object constructor I use in DataSender takes the above host name and also a port number. The host name argument is the name of the machine that DataReceiver is running on. This could be a DNS name such as inetserver.company.com' or an IP address string such as 155.64.182.122'. The port used with the Socket in DataSender must match the port being used by the ServerSocket in DataReceiver. If they don't match, a connection will not be made, so, be sure that the USE_PORT constants in both DataSender.java and DataReceiver.java match (see the "Additional information" section for more about ports). The Socket, on construction will attempt a connection to the server.

DataSender's constructor also creates a DataOutputStream using the newly created Socket's getOutputStream() method. The DataSender run() method simply uses DataOutputStream's writeBytes() method to write the passed String to the socket. After data has been written to the Socket I close the output stream and the Socket. The run() method then completes and exits the thread.

DataApplet is still around , so if the customer wants to enter some different information, or clicks the "Submit Request" button again another DataSender thread will start and send that data to DataReceiver.

In the example code provided in this article DataApplet manages collecting and formatting the data and then creates the DataSender object to send it. I decided it would be best to have DataSender extend from Java's Thread class so that the class could be used in more advanced situations than DataApplet (I'll leave those to you). Making use of threads in communications also makes good sense because of the wait that could occur when establishing connections or when data is being sent or received. When a thread is handling communications the main execution of the application can continue. This is especially useful in a windowed environment where we might need to accept user input while communications occur in the background.

That About Says It!
Using Java for socket communication is quite elegant. Sockets, once constructed allow us to send data over the network using the standard Java input and output streams via their getInputStream() and getOutputStream() methods. The idea, once socket communication is established, is that we worry about getting the data to the socket on our side and then worry about handling it properly on the other side.

Threads are useful tools to handle communications in the "background" without interrupting the current flow of execution. The key factor to using threads is properly using the synchronized' modifier on thread methods that should only be in use by a single thread at any given time.

A Java Applet can be a quick and easy front end for user input that needs to be sent to the server. Currently, for security reasons applets can only make socket connections to the machine they were loaded from, so, in our example the DataReceiver must be running on the web server machine.

Additional Information (and the Gotchas)
One thing I ran into while coding the examples was a misunderstanding of the DataInputStream's readLine() method. I was under the impression that the data I read would be up to and including the \r\n' characters. Not so, when writing the data to the file and then looking at it with an editor it appeared to be one long continuous line of text. After some playing around, and reading the documentation a little closer I realized that the \r\n' characters were not being read and that I would simply have to provide them in my writeData() method.

The Socket.close() method is currently not working as designed on Win NT and 95 platforms. This didn't have any ill effects in my testing as the sockets eventually timed out and were cleaned up by the system (netstat -a 5' revealed this). This is listed on Sun's known bugs list and should be corrected in a future JDK release.

If you are planning on using the example code with an Internet service provider they must be using an operating system that supports a Java interpreter. This is because DataReceiver is a Java application and must be run directly on the server via the Java interpreter. These days this doesn't seem like a real problem as many OS vendors are rushing to support the wave of Java applications and applets.

Ports
Ports are basically a way of routing incoming connections to their appropriate socket applications. Under normal conditions it is important that only one application use a given port at any one time. So before starting up DataReceiver be sure you know that nothing else is using its port (or the USE_PORT variable in DataReceiver.java is changed accordingly). On UNIX systems this information can usually be found in the /etc/services file. In Win95 it can be found in the windows directory and on Win NT it can be found in the \winnt\system32\drivers\etc directory. This file defines which applications use which ports.

Steps to run the examples as provided: First, be sure that the USE_PORT constants in DataReceiver.java and DataSender.java match. Then be sure the FILENAME constant in DataReceiver.java represents a system dependent path + filename that will work on your system. Compile the source with javac (or your favorite).

To get things running you need put the compiled .class files from DataReceiver, DataSender, and DataApplet in a directory accessible to your web server. Add the <applet> tag provided in DataApplet.html to the .html document your users/customers can access, as shown in Listing 4. Run the DataReceiver application on your server and then load the page that you added the <applet> tag to into your favorite Java aware browser.

About Andrew Idsinga
Andrew is currently a support technician on the Café team at Symantec. He writes network programming examples and research on current Java networking technologies. Before joining the Café team he supported network administration utilities.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1



ADS BY GOOGLE
Subscribe to the World's Most Powerful Newsletters

ADS BY GOOGLE

"Cloud Academy is an enterprise training platform for the cloud, specifically public clouds. We offe...
In his session at 21st Cloud Expo, Carl J. Levine, Senior Technical Evangelist for NS1, will objecti...
While some developers care passionately about how data centers and clouds are architected, for most,...
"NetApp is known as a data management leader but we do a lot more than just data management on-prem ...
"Akvelon is a software development company and we also provide consultancy services to folks who are...
"We're focused on how to get some of the attributes that you would expect from an Amazon, Azure, Goo...
Enterprises are adopting Kubernetes to accelerate the development and the delivery of cloud-native a...
"We work around really protecting the confidentiality of information, and by doing so we've develope...
High-velocity engineering teams are applying not only continuous delivery processes, but also lesson...
The question before companies today is not whether to become intelligent, it’s a question of how and...
In his session at 21st Cloud Expo, James Henry, Co-CEO/CTO of Calgary Scientific Inc., introduced yo...
"We're developing a software that is based on the cloud environment and we are providing those servi...
SYS-CON Events announced today that Telecom Reseller has been named “Media Sponsor” of SYS-CON's 22n...
SYS-CON Events announced today that CrowdReviews.com has been named “Media Sponsor” of SYS-CON's 22n...
"CA has been doing a lot of things in the area of DevOps. Now we have a complete set of tool sets in...
Agile has finally jumped the technology shark, expanding outside the software world. Enterprises are...
"MobiDev is a software development company and we do complex, custom software development for everyb...
"Codigm is based on the cloud and we are here to explore marketing opportunities in America. Our mis...
Data scientists must access high-performance computing resources across a wide-area network. To achi...
Coca-Cola’s Google powered digital signage system lays the groundwork for a more valuable connection...