Question

I'm programming a game applet that saves data to a CSV file and got a few methods that may read and write to same .csv file. And somehow I need to lock the file while each of my methods has a open writer stream to the file so the file content can't be changed until I close the write stream, but I want to allow read access only.

Is it possible?

Or if it can be done without any access to the file at all it will be fine too.

EDIT: My computer will be the server that serves the online game applet and the csv file is only on my computer. To play the gave you'll have to login to my website and all account information (username, password, total wins, total losses etc) stores into the csv file on my computer (the server). So i have several methods that will change the file. Therefore i need to lock it in every methods while writing to the file, If it theoretically, would be a few players playing at same time.

Reason why i store information to a csv file is that im educating to a javadeveloper and only programmed 4 months, we will learn us about databases first in a couple of months.

This is a schoolwork, thats why im making an applet. The only user that will connect to my computer (that will serve the applet through a simple servlet and webpage) are my teacher. So there are no security threats.

Here's the code for player objects:

public class Player {
    private String userName;
    private String passWord;
    private int currentWins;
    private int currentLosses;
    private int totalWins;
    private int totalLosses;
    private boolean isLoggedIn = false;
    private String playerId; 
    public Player(String playerId, String userName, String passWord, int totalWins, int totalLosses) { 
        this.playerId = playerId;
        this.userName = userName;
        this.passWord = passWord;
        this.totalWins = totalWins;
        this.totalLosses = totalLosses;
        this.currentWins = 0;
        this.currentLosses = 0;
        }
    public Player(String userName, String passWord, int totalWins, int totalLosses) {
        this.userName = userName;
        this.passWord = passWord;
        this.totalWins = totalWins;
        this.totalLosses = totalLosses;
        this.currentWins = 0;
        this.currentLosses = 0;
        this.playerId = UUID.randomUUID().toString();
    }
    public void incrementWins()
    {
        currentWins++;
        totalWins++;
    }
    public void incrementLosses()
    {
        currentLosses++;
        totalLosses++;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return passWord;
    }
    public void setPassword(String passWord) {
        this.passWord = passWord;
    }
    public boolean isLoggedIn() {
        return isLoggedIn;
    }
    public void setLoggedIn(boolean isLoggedIn) {
        this.isLoggedIn = isLoggedIn;
    }
    public int getTotalWins()
    {
        return this.totalWins;
    }
    public void setTotalWins(int totalWins)
    {
        this.totalWins = totalWins;
    }
    public int getTotalLoss()
    {
        return this.totalLosses;
    }
    public void setTotalLoss(int totalLoss)
    {
        this.totalLosses = totalLoss;
    }
    public int getCurrentWins()
    {
        return this.currentWins;
    }
    public void setCurrentWins(int currentWins)
    {
        this.currentWins = currentWins;
    }
    public int getCurrentLoss()
    {
        return this.currentLosses;
    }
    public void setCurrentLoss(int currentLosses)
    {
        this.currentLosses = currentLosses;
    }
    public String getPlayerId() {
        return playerId;
    }
    public void setPlayerId(UUID playerId) {
        this.playerId = playerId.toString();
    }   
}

Here the playermanager code:

public class PlayerManager {
    private final File file = new File("Players.csv");
    public PlayerManager() throws IOException
    {
        if (!file.exists())
            file.createNewFile();
    }

    public Player getPlayer(String playerId) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));

        String line;

        while((line = reader.readLine()) != null) {
            if(line.equalsIgnoreCase("PlayerID;Username;Password;Total Wins;Total Losses"))
                continue;

            String[] playerInfo = line.split(";");
            String existingPlayerID = playerInfo[0];
            String userName = playerInfo[1];
            String password = playerInfo[2];
            int totalWins = Integer.parseInt(playerInfo[3]);
            int totalLoss = Integer.parseInt(playerInfo[4]);

            if(existingPlayerID.equals(playerId)) {
                reader.close();
                return new Player(existingPlayerID,userName, password, totalWins, totalLoss);
            }
        }

        reader.close();
        return null;
    }
    public ArrayList<Player> getAllPlayers() throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
        ArrayList<Player> players = new ArrayList<Player>();
        String line;
        while((line = reader.readLine()) != null)
        {
            if(line.equalsIgnoreCase("PlayerID;Username;Password;Total Wins;Total Losses"))
                continue;
            String[] playerInfo = line.split(";");
            String playerID = playerInfo[0];
            String userName = playerInfo[1];
            String password = playerInfo[2];
            int totalWins = Integer.parseInt(playerInfo[3]);
            int totalLoss = Integer.parseInt(playerInfo[4]);
            players.add(new Player(playerID,userName, password, totalWins, totalLoss));
        }
        reader.close();
        return players;
    }
    public void savePlayer(Player player) throws IOException {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), "utf-8"));
        if(file.length() == 0) {
            writer.write("PlayerID;Username;Password;Total Wins;Total Losses");
            writer.newLine();
            writer.flush();
        }
        if(playerExists(player)) {
            writer.close();
            updatePlayer(player);
            return;
        }
        writer.write(player.getPlayerId() + ";" + player.getUserName() + ";" + player.getPassword() + ";" + 
                player.getTotalWins() + ";" + player.getTotalLoss());
        writer.newLine();
        writer.flush();
        writer.close();
    }
    public Player loginPlayer(String userName, String passWord) throws IOException {

        for(Player p : getAllPlayers()) {
            if(p.isLoggedIn())
                return p;

            if(p.getUserName().equals(userName) && p.getPassword().equals(passWord)) {
                p.setLoggedIn(true); 
                return p;
            }
        }
        return null;
    }
    private void updatePlayer(Player player) {

        try
        {
            ArrayList<Player> players = getAllPlayers();
            for(Player p : players) {
                if(p.getPlayerId().equals(player.getPlayerId())) {
                    p.setUserName(player.getUserName());
                    p.setPassword(player.getPassword());
                    p.setCurrentWins(player.getCurrentWins());
                    p.setCurrentLoss(player.getCurrentLoss());
                    p.setLoggedIn(player.isLoggedIn());
                    p.setTotalWins(player.getTotalWins());
                    p.setTotalLoss(player.getTotalLoss());
                    break;
                }
            }
            File tempFile = new File("Players.csv.bak");
            if (!tempFile.exists())
                tempFile.createNewFile();
            else
            {
                tempFile.delete();
                tempFile.createNewFile();
            }
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tempFile), "utf-8"));

            if(tempFile.length() == 0) {
                writer.write("PlayerID;Username;Password;Total Wins;Total Losses");
                writer.newLine();
                writer.flush();
            }
            for(Player p : players) {
                writer.write(p.getPlayerId() + ";" + p.getUserName() + ";" + p.getPassword() + ";" + 
                        p.getTotalWins() + ";" + p.getTotalLoss());
                writer.newLine();
            }
            writer.flush();
            writer.close();
            this.file.delete();
            tempFile.renameTo(this.file);
        }
        catch(Exception ex)
        {
        }
    }
    private boolean playerExists(Player player) throws IOException {
        Player p = getPlayer(player.getPlayerId());

        if(p != null && p.getPlayerId().equals(player.getPlayerId()))
            return true;
        return false;
    }
} 

Here's the servlet (not done yet):

public class TickTackToeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private boolean newUser = true;

    public String getLoginForm() throws IOException {
        File loginForm = new File("login.html");
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(loginForm)));
        StringBuilder str = new StringBuilder();

        String line;
        while((line = reader.readLine()) != null) {
            str.append(line);
        }

        reader.close();
        return str.toString();
    }

    public String displayGamePage() {
        return null;
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html; charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        Writer writer = response.getWriter();

        String loginForm = getLoginForm();

        writer.write(loginForm);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setContentType("text/html; charset=utf-8");
        Writer writer = response.getWriter();

        String userName = request.getParameter("username");
        String passWord = request.getParameter("password");

        if(userName == null || passWord == null) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            writer.write("<h1>You forgot to enter username/password. Please refresh to try again.</h1>");
            writer.write(getLoginForm());
            return;
        }

        PlayerManager playerManager = new PlayerManager();
        playerManager.loginPlayer(userName, passWord);

        Player player = new Player(userName, passWord, 0 , 0);
        if(!player.isLoggedIn()) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            writer.write("<h1>Bad username or password. Please refresh to try again.</h1>");
            return;
        }

        HttpSession session = request.getSession(true);

        if(session.getAttribute(userName) == null || session.getAttribute(passWord) == null) {
            session.setAttribute("username", userName);
            session.setAttribute("password", passWord);
        }

        response.setStatus(HttpServletResponse.SC_OK);
        response.sendRedirect(request.getParameter("url"));

    }

    public static void main(String... args) throws Exception {
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.addServlet(TickTackToeServlet.class, "/");

        Server server = new Server(8080);
        server.setHandler(context);
        server.start();
        server.join();
    }

}

Here's the applet (not done yet):

public class TickTackToeApplet extends JApplet implements ActionListener {
    private static final long serialVersionUID = 1L;
    private ArrayList<JButton> buttons = new ArrayList<JButton>();

    private JPanel panel = new JPanel();
    private Game game;
    private Player player1;
    private Player player2;
    private int numberOfPlacedOutChars = 0;

    public TickTackToeApplet() {}


    public TickTackToeApplet(int gameBoardSize, Player player1, Player player2) {
        createGUI(gameBoardSize);

        game = new Game(gameBoardSize);
        this.player1 = player1;
        this.player2 = player2;

        if(!player1.isLoggedIn() && !player2.isLoggedIn()) {
            try {
                PlayerManager playerManager = new PlayerManager();

                playerManager.loginPlayer(player1.getUserName(), player1.getPassword());
                playerManager.loginPlayer(player2.getUserName(), player1.getPassword());
            } catch (IllegalArgumentException e) {
                JOptionPane.showMessageDialog(this, "Couldn't login player, please enter correct username & password!");
            } catch (IOException e) {
                JOptionPane.showMessageDialog(this, "Server error...");
                e.printStackTrace();
            }
        }
    }

    //  public void init() {
    //      new TickTackToeApplet(4, "Henrik", "temp123");
    //  }

    public void CreateButtons(int gameBoardSize)
    {
        for(int x=0; x<gameBoardSize; x++)
        {
            for(int y=0; y<gameBoardSize; y++)
            {
                JButton btn = new JButton("");
                btn.setFont(new Font("Tahoma", Font.PLAIN, 32));
                btn.setName(x + ";" + y);
                btn.addActionListener(this);
                buttons.add(btn);
            }
        }
    }

    public void PlaceOutButtons()
    {
        for(JButton btn : buttons)
            panel.add(btn);
    }

    public void createGUI(int gameBoardSize) {

        panel.setSize(gameBoardSize*25, gameBoardSize*25);
        panel.setBackground(Color.BLACK);
        getContentPane().add(panel, BorderLayout.CENTER);
        panel.setLayout(new GridLayout(gameBoardSize, gameBoardSize));

        CreateButtons(gameBoardSize);
        PlaceOutButtons();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JButton buttonClicked = (JButton)e.getSource();
        String coordinates = buttonClicked.getName();
        String[] strArr = coordinates.split(";");
        int x = Integer.parseInt(strArr[0]);
        int y = Integer.parseInt(strArr[1]);

        if (numberOfPlacedOutChars % 2 == 0) {
            game.placeChar('X', x, y);
            buttonClicked.setText("X");
            buttonClicked.setEnabled(false);
        }
        else {
            game.placeChar('O', x, y);
            buttonClicked.setText("O");
            buttonClicked.setEnabled(false);
        }

        numberOfPlacedOutChars++;

        boolean win = game.checkWin();

        if(win == true) {
            player1.incrementWins();
            try {
                PlayerManager playerManager = new PlayerManager();
                playerManager.savePlayer(player1);
            } catch (IllegalArgumentException | IOException e1) {
                JOptionPane.showMessageDialog(this, "Couldn't update player info!");
            } 

            for(JButton btn : buttons) {
                btn.setEnabled(false);
            }

            int choice = JOptionPane.showConfirmDialog(this, "Winner is: " + player1.getUserName() + ", play again?", "WE GOT A WINNER", JOptionPane.YES_NO_OPTION);

            if(choice == 0) {
                for(JButton btn : buttons) {
                    btn.setEnabled(true);
                    btn.setText("");
                }
            }
        }
    }

}
Was it helpful?

Solution

With Java.NIO you can do this with a class called FileLock. Here is an example taken from an article on JavaBeat:

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class FileLockTest {
  public static void main(String[] args) throws Exception {
    RandomAccessFile file = null;
    FileLock fileLock = null;
    try {
      file = new RandomAccessFile("FileToBeLocked", "rw");
      FileChannel fileChannel = file.getChannel();

      fileLock = fileChannel.tryLock();
      if (fileLock != null){
        System.out.println("File is locked");
        accessTheLockedFile();
      }
    } finally {
      if (fileLock != null) {
        fileLock.release();
      }
    }
  }

  static void accessTheLockedFile() {
    try {
      FileInputStream input = new FileInputStream("FileToBeLocked");
      int data = input.read();
      System.out.println(data);
    } catch (Exception exception) {
      exception.printStackTrace();
    }
  }
}

Al because this involves the File System you will need a.policy file and you will need to sign the applet. This policy should work though you should read up on this:

grant {
  permission java.io.FilePermission "<<ALL FILES>>","write";
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top