I am learning Server Sent events in java and for that I am using a simple example. I am using Windows 7, Java 1.7, Tomcat 7, Eclipse Indigo. I have created a servlet (SseServer.java), the code for this servlet is as follows:
package sse;
import java.io.IOException; <br/>
import java.io.PrintWriter;<br/>
import java.util.Date;<br/>
import javax.servlet.ServletException;<br/>
import javax.servlet.annotation.WebServlet;<br/>
import javax.servlet.http.HttpServlet;<br/>
import javax.servlet.http.HttpServletRequest;<br/>
import javax.servlet.http.HttpServletResponse;<br/>
#WebServlet("/SseServer")<br/>
public class SseServer extends HttpServlet {<br/>
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Besides "text/event-stream;", Chrome also needs charset, otherwise
// does not work
// "text/event-stream;charset=UTF-8"
response.setContentType("text/event-stream;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive");
PrintWriter out = response.getWriter();
while (true) {
out.print("id: " + "ServerTime" + "\n");
out.print("data: " + new Date().toLocaleString() + "\n\n");
out.flush();
// out.close(); //Do not close the writer!
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And I am displaying the results in an html, SSE.html, the code for this is as shown below:
<!DOCTYPE html>
<html>
<body>
<h1>Current Server Time : </h1>
<div id="ServerTime"></div>
<script>
if (typeof (EventSource) !== "undefined") {
var source = new EventSource("http://localhost:8080/SSE/SseServer");
// http://eastern1.j.layershift.co.uk
//var source = new EventSource("http://eastern1.j.layershift.co.uk/SSE/SseServer");
source.onmessage = function(event) {
document.getElementById("ServerTime").innerHTML += event.data
+ "<br><br>";
};
} else {
document.getElementById("ServerTime").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>
</body>
</html>
When I run this code locally after every one second I am able to see the current time. I have also checked it on several browsers like chrome, firefox etc.
Since this code is working fine I decided to deploy this on cloud so I chose Jelastic.com. I created a war file and deployed it on Jelastic and tried running my sample application. But when I run the application from cloud, I can only see
Current Server Time :
I do not see the time. Can someone please tell me why this is happening? Is there something I need to change in my code? If yes then can someone please advice what it should be? Or should I change some other file/settings in eclipse while creating a war file?
Any help is much appreciated.
You had used absolute link, It's a bad practice. Try to use relative link.
Your mistake was that link not corresponding to path on server
var source = new EventSource("/SseServer");
Related
I want to build an embedded Java WebSocket Server using Jetty. I am using Jetty 9.2.6.
My Client is a HTML javascript client.
With Google Chrome(39, WebSocket Version 13) I can establish a connection and send data bidirectional.
When i use Firefox (34, WebSocket Version 13), the connection closes directly after the connection is established. In my SocketListenerClass the onWebSocketConnect event is called, immediately the onWebSocketClose event is called.
I tried 3 versions for my Socket. Implementing the WebSocketListener, extends the WebSocketAdapter and using Annotations. Everywhere the same.
I get the close reason number 1005 (CLOSE_NO_STATUS) but sometimes 1001.
Here is my code:
Server:
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public static void main(String[] args)
{
Server server = new Server(80);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
context.addServlet(new ServletHolder(new MyServlet()), "/*");
try
{
server.start();
server.join();
}
catch (Exception e)
{
e.printStackTrace();
}
}
Servlet:
import javax.servlet.annotation.WebServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
#SuppressWarnings("serial")
#WebServlet(name = "MyEcho WebSocket Servlet", urlPatterns = { "/egal" })
public class MyServlet extends WebSocketServlet
{
#Override
public void configure(WebSocketServletFactory factory) {
factory.register(MyEchoSocketWithListener.class);
}
}
Socket:
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketListener;
public class MyEchoSocketWithListener implements WebSocketListener
{
private Session outbound;
public void onWebSocketClose(int statusCode, String reason)
{
this.outbound = null;
System.out.println("Session has been closed. Reason: +"+statusCode + " , "+reason);
}
public void onWebSocketConnect(Session session)
{
this.outbound = session;
System.out.println("New Connection established...");
}
public void onWebSocketError(Throwable cause)
{
cause.printStackTrace(System.err);
}
public void onWebSocketText(String message)
{
if ((outbound != null) && (outbound.isOpen()))
{
System.out.printf("Echoing back message [%s]%n \n", message);
outbound.getRemote().sendString("Server-Echo: " + message, null);
}
}
The JavaScript Client:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>page title</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>WebSocket Test</h1>
<section id="content"></section>
<script>
var ws;
setTimeout(function (){initWebsocket();}, 3000);
function initWebsocket()
{
ws = new WebSocket("ws://127.0.0.1:80/egal");
window.onbeforeunload = function ()
{
ws.onclose = function ()
{
}; // disable onclose handler first
ws.close()
};
ws.onopen = function ()
{
document.write("WebSocket opened <br>");
ws.send("Hello Server");
document.write("Hello Message sent... <br>");
};
ws.onmessage = function (evt)
{
document.write("Message: " + evt.data + "<br>");
};
ws.onclose = function ()
{
document.write("<br>WebSocket closed<br>");
};
ws.onerror = function (err)
{
document.write("Error: " + err);
};
}
</script>
</body>
</html>
Servers output:
New Connection established...
Session has been closed. Reason: +1005 , null
Why does it work on chrome and not on FF? They are using the same websocket version 13. I also tried Jetty 9.2.5, and a new Mozilla Nightly and an older Firefox Version. No difference here.
Change
context.addServlet(new ServletHolder(new MyServlet()), "/*");
to
context.addServlet(new ServletHolder(new MyServlet()), "/egal");
This is minor, and isn't the root cause of your issue.
Firefox is handling the close properly, its just closing before you get the response back from the server.
Close code 1005 just means the close occurred without a close code being passed.
If you change your onbeforeunload() implementation to use ws.close(1000) you'll see that your own javascript is closing the connection. Comment out that line and you'll see the response message.
Went ahead and mocked up the 5 different ways you can create a websocket in embedded jetty at the following github project.
https://github.com/jetty-project/embedded-websocket-echo-examples
Each demo loads an HTML + JavaScript to demonstrate connect / hello world / close
They all work with Chrome and Firefox
thanks for your answers.
I solved the problem, it was caused by another stupid bug.
In my HTML client i was using the script tag inside the body. Also i was using document.write() in my websocket events. the document.write() method overrides the whole body content. So my javascript code is deleted at this moment.
Very stupid bug... sorry for that. :-)
I am asking myself, why it worked in Chrome anyway. :-)
i have a simple ResourceHandler on my Java/jetty application, jetty is serving a 2 simple files, one is a html5 page and the other is my video.mp4 video file.
<!DOCTYPE html>
<html>
<head><title>TEST</title></head>
<body>
<video style="width: 400px; height: 300px" src="video.mp4" autoplay="autoplay" loop="loop" preload="auto"></video>
</body>
</html>
The problem is... when i open the html page for first time the video is downloaded and cached, and stops playing after first playback and just stay frozen, if i do a refresh of the page the loop plays as i expected (forever continuous playback).
The java/jetty code is following
ResourceHandler om = new ResourceHandler();
om.setDirectoriesListed(true);
om.setResourceBase(BASE_PATH);
handlers.setHandlers(new Handler[] { om });
The question is, anyone knows why html5 video served by jetty 9.2.3 plays only first loop and then freezes on chrome 3.7.0... or give some guidance to avoid the freeze of the video after first playback when is served by jetty?
This works with Jetty 9.2.3.v20140905
package org.eclipse.jetty.demo;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class VideoServerMain
{
#SuppressWarnings("serial")
public class IndexerServlet extends HttpServlet
{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html><head><title>Videos</title></head>");
out.println("<body>");
for (File file : baseDir.listFiles())
{
if (file.isFile() && file.getName().endsWith(".mp4"))
{
String encodedFilename = URLEncoder.encode(file.getName(), "UTF-8");
out.println("<video style=\"width: 400px; height: 300px\" controls loop>");
out.printf(" <source src=\"%s\" type=\"video/mp4\">%n",encodedFilename);
out.println("</video>");
out.printf("<p>%s</p>%n",file.getName());
out.println("<hr/>");
}
}
out.println("</body>");
out.println("</html>");
}
}
public static void main(String[] args)
{
if (args.length != 1)
{
System.err.printf("ERROR: Usage %s [videos-dir]%n",VideoServerMain.class.getName());
System.exit(-1);
}
File baseDir = new File(args[0]);
if (!baseDir.exists() || !baseDir.isDirectory())
{
System.err.printf("ERROR: not a valid directory: %s%n",baseDir);
System.exit(-1);
}
try
{
new VideoServerMain(baseDir).start();
}
catch (Throwable t)
{
t.printStackTrace(System.err);
}
}
private final File baseDir;
public VideoServerMain(File baseDir)
{
this.baseDir = baseDir;
}
public void start() throws Exception
{
Server server = new Server(8080);
// Establish Scratch directory for the servlet context (used by JSP compilation)
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File scratchDir = new File(tempDir.toString(),"embedded-jetty-html5-vide-server");
if (!scratchDir.exists())
{
if (!scratchDir.mkdirs())
{
throw new IOException("Unable to create scratch directory: " + scratchDir);
}
}
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.setAttribute("javax.servlet.context.tempdir",scratchDir);
context.setResourceBase(baseDir.toURI().toASCIIString());
// Add servlet to present html for found videos
ServletHolder holderIndexer = new ServletHolder(new IndexerServlet());
context.addServlet(holderIndexer,"/indexer");
// Make sure that our welcome-file is the indexer servlet
context.setWelcomeFiles(new String[]{ "indexer" });
// Allow static file serving of videos themselves, via DefaultServlet
// Add Default Servlet (must be named "default")
ServletHolder holderDefault = new ServletHolder("default",DefaultServlet.class);
holderDefault.setInitParameter("resourceBase",baseDir.getAbsolutePath());
holderDefault.setInitParameter("dirAllowed","true");
holderDefault.setInitParameter("welcomeServlets","true");
holderDefault.setInitParameter("redirectWelcome","true");
context.addServlet(holderDefault,"/");
server.setHandler(context);
server.start();
server.join();
}
}
There seems to be 2 issues for you.
The ResourceHandler is too simple for the demands that the browser puts on it.
The browser seems to do a lot of partial requests, long duration requests, and recovery when needed. These kinds of requests are best done with the DefaultServlet
The HTML you are using for the video tag didn't work, but when I changed it to the following it worked fine.
<video style="width: 400px; height: 300px" controls loop=>
<source src="VID_20130822.mp4" type="video/mp4">
</video>
then chrome seemed to be happy again.
I am trying a slideshow using a servlet . Though the photos are loaded but is not a slideshow. What i get is a series of images.
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class PhotoCollection extends HttpServlet{
private String array[] = {"first.jpg","second.jpg","third.jpg","fourth.jpg"};
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<head>");
writer.println("<title>");
writer.println("SlideShow");
writer.println("</title>");
writer.println("</head>");
writer.println("<body>");
writer.println("<table>");
writer.println("<tr>");
try {
for(int i=0;i<=3;i++) {
writer.println("<td>");
writer.println("<img src=" + array[i] + " height=100 width=110>");
writer.println("</td>");
Thread.sleep(1000);
}
}catch(Exception exc) {
writer.println("<br />" + exc + "<br />");
}
writer.println("</tr>");
writer.println("</table>");
writer.println("</body>");
writer.println("</html>");
}
}
I have made the thread sleep 1 second but that doesn't affect the loading. How can i do a slideshow using it ? What changes do i have to make in the above servlet ?
You should use jQuery plugins for displaying it on browser pretty, use servlet just to serve image
Note : adding sleep in doGet doesn't make sense here, out put is sent once the method is executed so it would pause the execution
An intranet site has a search form which uses AJAX to call a servlet on a different domain for search suggestions.
This works in Internet Explorer with the intranet domain being a "trusted site" and with cross-domain requests enabled for trusted sites, but doesn't work in Firefox.
I have tried to work around the problem by creating a servlet on the intranet server, so there's a JS call to my servlet on the same domain, then my servlet calls the suggestions servlet on the other domain. The cross-domain call is server-side, so it should work regardless of browser settings.
The AJAX call and my servlet's call to the other servlet both use a HTTP POST request with arguments in the URL and empty request-content.
The reason I'm sticking with POST requests is that the JS code is all in files on the search server, which I can't modify, and that code uses POST requests.
I've tried calling the customer's existing suggestions servlet with a GET request, and it produces a 404 error.
The problem is that the result is inconsistent.
I've used System.out.println calls to show the full URL and size of the result on the server log.
The output first seemed to change depending on the calling browser and/or website, but now seems to change even between sessions of the same browser.
E.g. entering "g" in the search box, I got this output from the first few tries on the Development environment using Firefox:
Search suggestion URL: http://searchdev.companyname.com.au/suggest?q=g&max=10&site=All&client=ie&access=p&format=rich
Search suggestion result length: 64
Initial tries with Firefox on the Test environment (different intranet server but same search server) produced a result length of 0 for the same search URL.
Initial tries with Internet Explorer produced a result length of 0 in both environments.
Then I tried searching for different letters, and found that "t" produced a result in IE when "g" hadn't.
After closing the browsers and leaving it for a while, I tried again and got different results.
E.g. Using Firefox and trying "g" in the Development environment now produces no result when it was previously producing one.
The inconsistency makes me think something is wrong with my servlet code, which is shown below. What could be causing the problem?
I think the search suggestions are being provided by a Google Search Appliance, and the JS files on the search server all seem to have come from Google.
The actual AJAX call is this line in one file:
XH_XmlHttpPOST(xmlhttp, url, '', handler);
The XH_XmlHttpPOST function is as follows in another file:
function XH_XmlHttpPOST(xmlHttp, url, data, handler) {
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handler;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length",
/** #type {string} */ (data.length));
XH_XmlHttpSend(xmlHttp, data);
}
Here is my servlet code:
package com.companyname.theme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class suggest extends HttpServlet {
Properties props=null;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String result = "";
String args = req.getQueryString();
String baseURL = props.getProperty("searchFormBaseURL");
String urlStr = baseURL + "/suggest?" + args;
System.out.println("Search suggestion URL: " + urlStr);
try {
int avail, rCount;
int totalCount = 0;
byte[] ba = null;
byte[] bCopy;
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write("".getBytes());
os.close();
InputStream is = conn.getInputStream();
while ((avail = is.available()) > 0) {
if (ba == null) ba = new byte[avail];
else if (totalCount + avail > ba.length) {
// Resize ba if there's more data available.
bCopy = new byte[totalCount + avail];
System.arraycopy(ba, 0, bCopy, 0, totalCount);
ba = bCopy;
bCopy = null;
}
rCount = is.read(ba, totalCount, avail);
if (rCount < 0) break;
totalCount += rCount;
}
is.close();
conn.disconnect();
result = (ba == null ? "" : new String(ba));
System.out.println("Search suggestion result length: " + Integer.toString(result.length()));
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
PrintWriter pw = resp.getWriter();
pw.print(result);
}
#Override
public void init() throws ServletException {
super.init();
InputStream stream = this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties");
props = new Properties();
try {
props.load(stream);
stream.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
Solution: don't rely on InputStream.available().
The JavaDoc for that method says it always returns 0.
HttpURLConnection.getInputStream() actually returns a HttpInputStream, in which available() seems to work but apparently sometimes returns 0 when there is more data.
I changed my read loop to not use available() at all, and now it consistently returns the expected results.
The working servlet is below.
package com.integral.ie.theme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class suggest extends HttpServlet implements
javax.servlet.Servlet {
Properties props=null;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//super.doPost(req, resp);
final int maxRead=200;
String result="";
String args=req.getQueryString();
String baseURL=props.getProperty("searchFormBaseURL");
String urlStr=baseURL+"/suggest?"+args;
//System.out.println("Search suggestion URL: "+urlStr);
try {
int rCount=0;
int totalCount=0;
int baLen=maxRead;
byte[] ba=null;
byte[] bCopy;
URL url=new URL(urlStr);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
// Setting these properties may be unnecessary - just did it
// because the GSA javascript does it.
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length","0");
InputStream is=conn.getInputStream();
ba=new byte[baLen];
while (rCount>=0) {
try {
rCount=is.read(ba,totalCount,baLen-totalCount);
if (rCount>0) {
totalCount+=rCount;
if (totalCount>=baLen) {
baLen+=maxRead;
bCopy=new byte[baLen];
System.arraycopy(ba,0,bCopy,0,totalCount);
ba=bCopy;
bCopy=null;
}
}
} catch(IOException e) {
// IOException while reading - allow the method to return
// anything we've read so far.
}
}
is.close();
conn.disconnect();
result=(totalCount==0?"":new String(ba,0,totalCount));
//System.out.println("Search suggestion result length: "
//+Integer.toString(result.length()));
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
PrintWriter pw=resp.getWriter();
pw.print(result);
}
#Override
public void init() throws ServletException {
super.init();
InputStream stream=this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties");
props=new Properties();
try {
props.load(stream);
stream.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
Start with a unit test. Servlets are pretty straightforward to unit test and HttpUnit has worked for us.
Debugging Servlet code in a browser and with println calls will cost more time in the long run and it's difficult for someone on SO to digest all of that information to help you.
Also, consider using a JavaScript framework such as JQuery for your AJAX calls. In my opinion there's little reason to touch an xmlHttp object directly now that frameworks will hide that for you.
out.println("<tr><td><FORM ENCTYPE='multipart/form-data'"+
"method='POST' action='ProcessUpload' ></td>"+
"<td><INPUT TYPE='file' NAME='mptest'></td>"+
"<td><INPUT TYPE='submit' VALUE='upload'></td>"+
"</FORM></tr>");
This codes can help me upload file but the problem is after I click upload, I cant save the uploaded file in particular directory.Anyone can give some suggestion?
The code above simply outputs the HTML for an upload button. It does not do anything with any upload requests that form might start.
May I ask why you don't want to use Apache Commons FileUpload? To not use it will mean that you will need to implement RFC 1867. A lot of time and effort wasted when an implementation already exists.
You have to write another servlet (or some CGI, jsp ...etc.) to retrieve the file from the request and save it to wherever you like:
http://www.frontiernet.net/~Imaging/FileUploadServlet.html
Apache Commons FileUpload is the way to go as others suggested. If you don't want use that for any reason, you can also look at this class,
http://metatemplate.googlecode.com/svn/trunk/metatemplate/java-app-framework/tomcat-adapter/src/com/oreilly/servlet/MultipartRequest.java
This is not as robust as FileUpload but it works fine for simple file upload.
If you want to use Multipart request you need to write your processUpload servlet to handle this eg:
private String fileSavePath;
public void init(){
fileSavePath = getServletContext().getRealPath("/") + "data";
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException{
MultipartRequest mpr = new MultipartRequest(request, fileSavePath);
}
And I really wouldn't output pure html from a servlet as in your question - try dispatching to a jsp - even better if nothing else is required just use plain html.
The COS libary http://servlets.com/cos/ (not apache)
I second mlk's suggestion and think reading the Users Guide to Commons FileUpload will help you get started. It will handle receiving the file, but you still have to tell it "where" to store it. From your description, sounds like you want the user to choose "where" to store the file. You will have to write this portion yourself.
I hacked together a quick lister in a servlet. All the other comments are correct. Not a good idea to write html in a servlet, but this sounds like a good learning experience.
package somepackage;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DirectoryChooserServlet extends HttpServlet {
public DirectoryChooserServlet() {
super();
}
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Writer w = response.getWriter();
w.write("<html><body>");
String action = request.getParameter("action");
String directory = request.getParameter("directory");
String startDirectory = "/private";
if ("list".equals(action)) {
startDirectory = directory;
}
File dir = new File(startDirectory);
if (dir != null) {
w.write("..<br/>");
for(File f: dir.listFiles()) {
if(f.isDirectory()) {
w.write("" + f.getName() + "<br/>");
}
}
}
w.write("</body></html>");
}
}