0

While reading this book about servlets i came across an example that uses FileWriter class to save a persistent state of a servlet before it gets destroyed. Tested the example and works fine, this is the code:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class InitDestroyCounter extends HttpServlet {

  int count;

  public void init(ServletConfig config) throws ServletException {
    // Always call super.init(config) first  (servlet mantra #1)
    super.init(config);

    // Try to load the initial count from our saved persistent state
    try {
      FileReader fileReader = new FileReader("InitDestroyCounter.initial");
      BufferedReader bufferedReader = new BufferedReader(fileReader);
      String initial = bufferedReader.readLine();
      count = Integer.parseInt(initial);
      return;
    }
    catch (FileNotFoundException ignored) { }  // no saved state
    catch (IOException ignored) { }            // problem during read
    catch (NumberFormatException ignored) { }  // corrupt saved state

    // No luck with the saved state, check for an init parameter
    String initial = getInitParameter("initial");
    try {
      count = Integer.parseInt(initial);
      return;
    }
    catch (NumberFormatException ignored) { }  // null or non-integer value

    // Default to an initial count of "0"
    count = 0;
  }

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
                               throws ServletException, IOException {
    res.setContentType("text/plain");
    PrintWriter out = res.getWriter();
    count++;
    out.println("Since the beginning, this servlet has been accessed " +
                count + " times.");
  }

  public void destroy() {
    saveState();
  }

  public void saveState() {
    // Try to save the accumulated count
    try {
      FileWriter fileWriter = new FileWriter("InitDestroyCounter.initial");
      String initial = Integer.toString(count);
      fileWriter.write(initial, 0, initial.length());
      fileWriter.close();
      return;
    }
    catch (IOException e) {  // problem during write
      // Log the exception.
    }
  }
}

After stoping glassfish server, i copy/paste the war file from the deploy folder, unjar it and look for "InitDestroyCounter.initial" file, but cant be found in there so it got me wondering where does glassfish save this created file?

Shikatsu
  • 197
  • 1
  • 1
  • 13
  • 1
    Printing `new File(".").getAbsolutePath()` will give you the current working directory. On an related note: http://stackoverflow.com/questions/2161054/where-to-place-configuration-properties-files-in-a-jsp-servlet-web-application and http://stackoverflow.com/questions/2308188/getresourceasstream-vs-fileinputstream – BalusC Jan 27 '13 at 20:07
  • @BalusC this works, can you post your answer to be accepted? – Shikatsu Jan 30 '13 at 22:48

5 Answers5

2

(Not an answer, but too long for a legible comment.)

  1. You can't save a file into a war.1

  2. You should be writing to a known file location by writing to an absolute path. This can be defined via JNDI, init context param, startup param, environment variable, etc.

  3. IMO you shouldn't write into a web app even if it isn't a war, because your files will be at the mercy of your deployment mechanism, and could get wiped out.

1 Yeah yeah, you could. Don't.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
2

All the others are right regarding WAR modification, but for the code above:

This

FileWriter fileWriter = new FileWriter("InitDestroyCounter.initial");

is a shortcut for

File f = new File("InitDestroyCounter.initial");
FileWriter fileWriter = new FileWriter(f);

so feel free to ask the File object for its absolut location:

System.out.println(f.getAbsolutePath());

All in all your code above will use JVM's current/working directory to store and read the file to/from. Please keep in mind, that I/O access should be avoided as per Java EE spec:Java EE programmers do not write to files

Community
  • 1
  • 1
Sebastian J.
  • 762
  • 9
  • 29
1

In any java web/app server you should not expect that modification would be done directly in your deployed archive. Rather it would write file in the current working directory.

If you're in linux, I've found a place ( http://www.java.net/forum/topic/glassfish/glassfish/paths-glassfish ) where they claim you can retrieve current working dir using command:

asadmin generate-jvm-report | grep "user.dir" 

So you can see what it says.

However as far as I got it, it should be config directory of the server. So maybe have a look there for a file.

Peter Butkovic
  • 11,143
  • 10
  • 57
  • 81
1

GlassFish absolutely guarantees that the current working directory will always be the 'config' directory of the domain. E.g. in the default case:

/domains/domain1/config

The guarantee only applies if GlassFish is started using asadmin.

Note: I wrote the code so I know for sure!

codeplumber
  • 469
  • 2
  • 11
0

From the answers and tests i have made all of this can point to the path:

System.getProperty("user.dir")

new File(".").getAbsolutePath()

getAbsolutePath();

As you can see here:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class InitDestroyCounter extends HttpServlet
{
    int Cnt;

    String FR_File_Str;

    @Override
    public void init(ServletConfig ServlConf) throws ServletException
    {
        // Always call super.init(ServletConfig) first;
        super.init(ServlConf);

        // Try to load the initial Cnt from our saved persistent state;
        try
        {
            File FR_File = new File("InitDestCounter.init");
            FileReader FR = new FileReader(FR_File);

            BufferedReader BR = new BufferedReader(FR);

            String Initial_str = BR.readLine();

            Cnt = Integer.parseInt(Initial_str);

            FR_File_Str = FR_File.getAbsolutePath();

            return;
        }
        catch(FileNotFoundException Ignored){} // No saved state;
        catch(IOException Ignored){} // Problem during read;
        catch(NumberFormatException Ignored){} // Corrupted saved state;

        // No luck with the saved state, check for and init parameter;
        String Initial_str = getInitParameter("initial_cnt");

        try
        {
            Cnt = Integer.parseInt(Initial_str);
            return;
        }
        // Null or non-integer value;
        catch(NumberFormatException NFE){}

        // Default, if non of the above worked;
        Cnt = 0;
    }

    @Override
    public void doGet(HttpServletRequest  Request,
                      HttpServletResponse Response)
                      throws ServletException, IOException
    {
        Response.setContentType("text/html");

        PrintWriter PW = Response.getWriter();

        Cnt++;

        PW.println("<H4>Since the beginning this servlet had been "+
                   "accessed "+Cnt+" times.</H4>");
        PW.println("<H4>"+System.getProperty("user.dir")+"</H4>");
        PW.println("<H4>"+new File(".").getAbsolutePath()+"</H4>");
        PW.println("<H4>FR_File_Str = "+FR_File_Str+"</H4>");
    }

    public void SaveState()
    {
        // Try to save the accumulated count;
        try
        {
            FileWriter FW = new FileWriter("InitDestCounter.init");

            String Initial_str = Integer.toString(Cnt);

            FW.write(Initial_str, 0, Initial_str.length());

            FW.close();

            return;
        }
        catch(IOException IOE){} // Problem during write;
    }

    @Override
    public void destroy()
    {
        SaveState();
    }
}

For the sake of courtesy i won't be accepting my own answer. Thanks everyone for your answers and comments.

Shikatsu
  • 197
  • 1
  • 1
  • 13