WebDeveloper.com �: Where Web Developers and Designers Learn How to Build Web Sites, Program in Java and JavaScript, and More!   
Web Developer Resource Directory WebDev Jobs
Animated GIFs
CSS Properties
HTML 4.01 Tags
Site Management
WD Forums

    Web Video
    Expression Web



    Forum, Blog, Wiki & CMS

 Site Management
    Domain Names
    Search Engines
    Website Reviews

 Web Development
  Business Issues

    Business Matters

    The Coffee Lounge
    Computer Issues

Java Jive: File I/O with Java: It Can be Done!

Java Jive: File I/O with Java: It Can be Done!

by Scott Clark
Reprinted from Web Developer® magazine, Vol. 3 No.2 Mar/Apr 1997 ©1997

Will Java security stop you from reading and writing to a file? Only if you can't hack it....

Java security: without it, Java would never even be looked at seriously as a viable programming option. But security is also the reason that file system access is so limited when you're using a Web browser as a Java interpreter. And with good reason--we wouldn't want anybody to be able to read and write to files on our system, let alone our Web server.

Unfortunately, this is why it is so hard to write an applet that is able to read from and write to a fileƒeven a file on the same server that originally served the applet. Yet there seems to be an endless amount of reasons for wanting to do so. So how can we accomplish that task? By using what we have available: CGI and Java.

With the security systems of today's Web browsers, if you want your applet to be able to write to a file you have two choices (not that these are the only methods for accomplishing the taskƒthere are always myriad ways of accomplishing a task).

The first choice is obvious--use a combination of Java and CGI. The second is almost as obvious--write a server application in Java and let your applet communicate with that. That way the Java server actually writes to the file in question.

We can also use a combination of the two; a Java applet that communicates with a CGI program or shell script (the wrapper) that starts the Java server application that writes to the server. We'll cover each of the three methods in this column. We hope to hear some more methods from you, the real Java experts out there.

The ABCs

With Java, first we must learn to read, then we'll get to writing. Java's built-in security makes it difficult for us to read a file on the server directly, but we can get it to think that what it's reading is a URL. By passing the applet a URL as a parameter:
 String myurl = getParameter("URL"); String url = myurl; try { this.theURL = new URL(url); } catch ( MalformedURLException e) { System.out.println("Bad URL: " + theURL); } 
We are later able to access and read the information from that URL by opening a URL connection:
 public void run() { URLConnection conn = null; DataInputStream data = null; String line; StringBuffer buf = new StringBuffer(); try { conn = this.theURL.openConnection(); conn.connect(); ta.setText("Connection opened..."); data = new DataInputStream(new BufferedInputStream( conn.getInputStream())); ta.setText("Reading data..."); while ((line = data.readLine()) != null) { buf.append(line + "\n"); } ta.setText(buf.toString()); data.close(); } catch (IOException e) { System.out.println("IO Error:" + e.getMessage()); } } 
We read the data into a StringBuffer and then dump the buffer into the text area ta. Essentially that's all there is to reading from a file on the server. If you forget to use a complete URL in the applet parameter, you will quickly be reminded, as it won't work without it. Of course the URL could very easily have been hard-coded into the applet, but our method allows a bit more freedom. When you get to writing the CGI portion of the applet, the name of the file that is to be written into is hard-coded in the CGI itself.

Java/CGI...A Partnership

Many of you may be asking yourself, "Why create an applet if I have to use CGI anyway?" The answer lies in the fact that although CGI is indeed involved, it is a very small part of the overall picture, and only performs a small function: the simple action of writing the information passed from the applet to a file on the server. As such, the CGI can be written in just about any programming language you wish, as long as it runs on your server. The example below uses Perl 5, but could have been written using a shell script just as easily:
 #!/usr/bin/perl # wdwrite # this is the CGI that will take the # applet info and write it to a file open(OUT, "> /public_html/opinion.txt"); print "content-type: text/plain\n\n"; while (<>) { print OUT $_; print $_; } close (OUT); exit 0; 
The CGI program must be on the same server as the applet, and must be set to be executable (i.e. chmod 755). This is just a very basic example that shows how to take the data and write it to a file. It simply opens a file, and writes to that file using the data that is passed to it by the applet. Encoding and decoding could easily be added later (and would then have to be added to the applet as well). Note that this same CGI can be used by a standard HTML form to write to the file, but unless the source for the applet is made available, the CGI's name remains unknown. The CGI is as secure as any other CGI programs that reside on your server, and additional security measures can be added to the CGI without hampering its effectiveness.

WriteIt Up

Writing to the file isn't much harder than reading from the file. Basically what we're doing opening a new URL (to the CGI program) and we're sending the data from the applet to the CGI using URLConnection and getOutputStream():
 // Writeit.class import java.applet.Applet; import java.net.*; import java.io.*; import java.awt.*; public class Writeit extends Applet { Panel center; GridBagLayout gbl; GridBagConstraints gbs; TextArea info; Button send; public void init() { setLayout(new BorderLayout()); setBackground(Color.white); gbl = new GridBagLayout(); center = new Panel(); center.setLayout(gbl); gbs = new GridBagConstraints(); gbs.fill = GridBagConstraints.NONE; gbs.gridwidth = GridBagConstraints.REMAINDER; gbs.weightx = 1.0; showApp(); validate(); } 
All we're doing in the code above is to set the form display. This could be done in a myriad of ways, and is merely a matter of preference. Now we'll handle the click event that will send the data to the URL:
 public boolean action(Event e, Object o) { if (e.target.equals(send)) { try { writeMessage(); } catch (Exception e1) { } } return true; } public void writeMessage() throws Exception { String data; data = info.getText(); SendData(data); } 
The data is retrieved and sent to the CGI file. On the client side, the data is written into the form element named "info". The getText function gets the data from the form element info. The data is then sent to the CGI via the SendData function.
 public void showApp() { gbs.anchor = GridBagConstraints.WEST; center.add(info = addTextArea(3,50)); gbs.anchor = GridBagConstraints.CENTER; center.add(send = new Button("Write it!")); add("Center", center); } public TextArea addTextArea(int rows, int cols) { TextArea ta = new TextArea(rows, cols); gbl.setConstraints(ta, gbs); ta.setBackground(Color.white); return ta; } public void SendData(String data) throws Exception { URL url = new URL("http","www.yourdomain.com", "/cgi-bin/wdwrite"); URLConnection con = url.openConnection(); con.setDoOutput(true); con.setDoInput(true); con.setUseCaches(false); con.setRequestProperty("Content-type", "text/plain"); con.setRequestProperty("Content-length", data.length()+""); 
Once again, we have opened the URL using openConnection(). As this is using a CGI POST to send the data (as opposed to a GET in which the data would be appended to the end of the URL i.e. http://www.yourdomain.com/cgi-bin/writeit?myinfo), we are defining the Content-type to be text/plain.
 PrintStream out = new PrintStream(con.getOutputStream()); out.print(data); out.flush(); out.close(); DataInputStream in = new DataInputStream(con.getInputStream()); String s; while ((s = in.readLine()) != null) { } in.close(); } } 
We use a new DataInputStream() to get the data, and we read it in until the data set is null, and pass it to the CGI via the open URL connection.

In these examples (see figure), we have shown how it is possible to use Java to both read the data from a file on the server and send the edited data to a CGI program that writes the data to a file on the server. These applets could be the basis for a Web message board (it is very fast!), a "real-time" online HTML editor, a "leave-a-quote" applet, a "real-time" chat system, or a type of INI file that would allow for the personalization of Web sites or Java applets. The possibilities are endless!

As we previously stated, it is also possible to have the applet communicate with a server written in Java that resides on the same machine as the Web server, and have it do all the dirty work of reading, writingƒeven deleting files. Personally, I'm not going to take on the task of writing a Java server, since that enormous task has already been done, and quite well at that, by a generous Netizen (Jamie Cameron) that has freely given the server and source to the Web public.

Jamie Cameron's JFS (Java File Server; www.focus-asia.com/java/jfs/) allows developers to provide NFS-like file and print services for Java applets. The JFS allows applets to read and write files, create and delete directories (and files), print files, send email and even open connections to servers other than the one the applet came from! The JFS uses a fairly simple name and password scheme, and the developer makes a connection to the server after passing the name of the JFS server to the applet's constructor. This is done using the JFSclient class. The only "catch" to using the JFS filesystem is that is a Java application, and as such, has to be executed and ran on the same machine as the Web server, specifically on a Unix operating system (although Java is multi-platform, Jamie designed this filesystem to be run on Unix).

This brings up another question--how could you start the JFS server (or any other Java application) using CGI? If you can do this, your applet can simply call the CGI program and the CGI program will start the Java application. Basically, a CGI wrapper or shell script needs to call the Java interpreter like this:

 java -jit javaapplication 
Of course, using CGI means that the environment variables such as REMOTE_HOST must be somehow sent to the CGI wrapper to pass to the application. The Java interpreter allows us to define system properties using the "-D" option on the command line, i.e.
 java -jit -DREMOTE_HOST=yourdomain.com javaapplet 
Marc Balmer has written a CGI wrapper script that passes environment variables to the application in just such a manner (http://hb9cgb.eunet.ch/hb9ssb/java-for-cgi.html). Using a CGI program such as Marc's wrapper, Java applications can be executed much the same way binaries are excecuted, (you could even write CGI programs in Java that could be executed by a CGI wrapper), using a URL such as http://www.yourdomain.com/cgi-bin/startJava. If it is not already included on the server machine, the CLASSPATH also must be set, e.g:
When your applet calls the CGI, as in the Writeit example above, the CGI starts the Java application, which then communicates with your applet. The possibilities are only limited by your imagination. By experimenting with the JFS Java server and Marc's wrapper, you can get an idea of exactly how to implement applet to application communications. Many people are using the applet/application partnership to create some truly unique Web applications. Another great resource for Java/CGI wrappers is CGI Programming in Java (www.meangene.com/notes/javacgi.html), which gives examples of CGI/Java wrappers, URLs for more info, and source code.

For future reference, you can view and try out the Readit/Writeit applets (http://porthos.phoenixat.com/~warreng/WDemo.html) along with their full source code. I couldn't have written this column without you, the readers of Web Developer® magazine.

My thanks go out to Blair Hamilton for his gracious help with the Readit.class applet. Keep sending your comments, thoughts, source code, suggestions, and of course your best Java tips and tricks to me at sclark@jupitermedia.com. Till next time.

HTML5 Development Center

Recent Articles