Hello to all, I did not know how to entitle this post,since it is more of a logical problem,but it's connected to the writing of my objects to a file. So, my server expects connections from multiple clients. The clients vote for the candidates offered to them by a menu, then the server stores the votes in local integer variables which I later add to an object which is then added to a LinkedList and the whole list is written to a file. This way, I will be able to later read the file, grab the list and show each element of that list as a separate object to the clients, so they would be able to preview former voting results. Now, my problem is that I call the method that does all of the above in each of the cases(switch() is used to handle the menu), and the switch() statement is wrapped inside a while(true) loop,so that the server can handle multiple clients. Now this causes the following: let's say 3 clients are connected this session - my code will thus write down to the list 3 separate objects and in one writing to the file I will write 3 objects and will have a list that contains 3 elements instead of one. I've handled the incrementing, so that e.g. if all of the clients vote for the first case,the first element added to the list will have values: 1 0 0 0 0 (5 cases,the first is voted for so it is incremented to 1, all of the others are 0), then the second element 2 0 0 0 0 etc... So I have no idea if my code so far is capable of being extended so it can overcome these problems, since I have no clue how to do it. If I call the method in main(),after the server's start() I get all zeros, nothing is properly set. Here is a snippet, if you could think this could be managed,please give me some instructions, if not - I'm afraid I'll have to start it all over again...

The server's run method:

public void run(){
		try {
			while(true){
			 socket1 = s.accept();
			 
		
/**Getting input from the client and storing it in an integer variable */			 
			BufferedReader userInput = new BufferedReader(new InputStreamReader(socket1.getInputStream()));
			String readInput = userInput.readLine();
			int var = Integer.parseInt(readInput);
/**Selection based on the user's input */			
			switch(var){
			case 1:
				chooseBand();
				
				writeStream();
				break;
			case 2:
				chooseGuitarist();
				break;
			case 3:
				chooseAlbum();
				break;
			case 4:
				chooseFilm();
				break;
			case 5:
				chooseActor();
					break;
			}
			
			
		}
			
			
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

An example of the methods called inside the cases,since they're all similar:

public void chooseBand() throws IOException{
		/**Asking the client another question */				
				PrintWriter out = new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));
				out.println("What is, in your opinion, the best rock band ever? \n 1.Led Zeppelin \n 2.The Rolling Stones \n 3.Pink Floyd \n 4.Deep Purple \n 5.AC/DC \n#");
				out.flush();
		/**Getting the new user input and converting it to an integer*/				
				BufferedReader userInput1 = new BufferedReader(new InputStreamReader(socket1.getInputStream()));
				String readInput1 = userInput1.readLine();
				int var1 = Integer.parseInt(readInput1);
				
		/**Selection based on the new input by the user*/				
				switch(var1){
				case 1:
		/**Sending the results to the client */		
					PrintWriter out1 = new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));
					out1.println("Zeppelin");
					out1.flush();
					zepp++;
					break;
				case 2:
		/**Sending the results to the client */			
					PrintWriter out2 = new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));
					out2.println("Stones");
					out2.flush();
					stones++;
					break;
				case 3:
		/**Sending the results to the client */			
					PrintWriter out3 = new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));
					out3.println("Floyd");
					out3.flush();
					floyd++;
					break;
				case 4:
		/**Sending the results to the client */
					PrintWriter out4 = new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));
					out4.println("Purple");
					out4.flush();
					purple++;
					break;
				case 5:
		/**Sending the results to the client */
					PrintWriter out5 = new PrintWriter(new OutputStreamWriter(socket1.getOutputStream()));
					out5.println("AC/DC");
					out5.flush();
					acDc++;
					break;
				}
				
				System.out.println("Zeppelin: " + zepp);
				System.out.println("Stones: " + stones);
				System.out.println("Floyd: " + floyd);
				System.out.println("Purple: " + purple);
				System.out.println("AC/DC: " + acDc);
				
				
				result.addBand(zepp, stones, floyd, purple, acDc);
				//System.out.println("Result vo case:" + result.toString());
				
			}

The writeStream() method is a little messy with all of the catch() clauses, but I'll handle it later:

public void writeStream(){
		System.out.println("Inside writestream()");
		ObjectInputStream inputStream = null;
		ObjectOutputStream stream = null;
		try{
		inputStream = new ObjectInputStream(new FileInputStream("votingResults.txt"));
		}catch(EOFException e){
			System.out.println("End of file reached");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//		if(inputStream == null ){
//			results = new LinkedList<Result>();
//			initial = true;
//		}
		
		//if(initial == false){
		try {
			results = (LinkedList<Result>) inputStream.readObject();
			inputStream.close();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//}
		
		results.add(result);
		System.out.println(result.toString());
		
		
		try {
			stream = new ObjectOutputStream(new FileOutputStream("votingResults.txt"));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			stream.writeObject(results);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			stream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		
		
		
		
	}

My main() method:

public static void main(String[] args) {
		Server s;
		s = new Server();
		s.start();
		//Ako ja povikam vo case vnatre dobivam tripati zapisano,inaku dobivam nuli s.writeStream();
		
		System.out.println("Citam");
		s.readStream();
		
		
		
	}

Unless there are privacy issues, maybe its a good idea to keep all the data instead of a summary, ie for each vote cast add a record to the list showing who voted/when voted/what voted for. That way each record is unique and never updated. Then derive the summary statistics on the fly or (if that turns out to be slow) build them when you read the data at startup and increment it as you go, but don't save it.
If multiple clients can increment a set of shared counters then you also have to get very serious about Thread issues.

OK, let's say I keep records of all the votes separately - as you said - each vote as a separate element of the list. Then the teacher requires to see voting summary per session,i.e. the voting results of the every voting session, he does not care who voted how,but he wanna see who the winner is. So how do I know which elements to pull from the list,how do I know how many clients connected to the server in each session?

OK, include a session identifier (eg new Date() when session starts) as part of the data for each vote.

Edited 6 Years Ago by JamesCherrill: n/a

So I experimented a little with both Date and Calendar classes, and it's fine. But then I ran the program and got InvalidClassException. Here it is:

java.io.InvalidClassException: server.Result; local class incompatible: stream classdesc serialVersionUID = 6156913789833124645, local class serialVersionUID = 1
	at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
	at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
	at java.io.ObjectInputStream.readClassDesc(Unknown Source)
	at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at java.util.LinkedList.readObject(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)
	at java.io.ObjectInputStream.readSerialData(Unknown Source)
	at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at server.Server.writeStream(Server.java:402)
	at server.Server.run(Server.java:73)
java.lang.NullPointerException
	at server.Server.writeStream(Server.java:413)
	at server.Server.run(Server.java:73)

Edited 6 Years Ago by robertmacedonia: n/a

Did you mix an old version with the newer one?

Excuse me, I do not fully understand which version you are referring to. This is my Date object,converted to a String which I then pass to the Result object "result" which is then added to the LinkedList object "results". It is passed to the Result class as a String.
Here it is constructed, in the "Server" class:

Date dateNow = new Date();
SimpleDateFormat dateformatYYYYMMDD = new SimpleDateFormat("yyyyMMdd");
StringBuilder nowYYYYMMDD = new StringBuilder( dateformatYYYYMMDD.format(dateNow) );
String date = nowYYYYMMDD.toString();

result.addBand(zepp, stones, floyd, purple, acDc, date);

Here it is accepted in another class "Result":

public void addBand(int zepp, int stones, int floyd, int purple, int acDc, String date){
		 this.zepp = zepp;
		 this.stones = stones;
		 this.floyd = floyd;
		 this.purple = purple;
		 this.acDc = acDc;
		 this.date = date;
	 }

I was referring to files written with older versions of your code. They wouldn't be compatible with your new class definitions.

Edited 6 Years Ago by NormR1: n/a

Oh yes, I see. It was so foolish of me. Anyway, this worked and now I have each client's vote as a separate element of the list. I still do not get to know which elements belong to which session, I can only compare the differences in their date&time seconds values,which is not good. Do you think I should write a value to each element of a particular session, then when another session starts I should read the last value,increment it by one and write it down again?

I suggested the date/time when the session starts as the unique session identifier. This is easier & safer than trying to create your own unique int.
The Date/time of the actual vote may, or may not, be useful.
ps There's no need to covert Dates to Strings - you can just store the raw Date in your results if you want. There's no reason to convert Date to String via StringBuilder in this case, SB is used when you want to concatenate a whole load os String values into one. Converting the Date to YYYYMMDD loses the time, so two sessions on the same day an't be distinguished - is this what you intended?

Oh, OK. I did that - now I'm creating a new Date object in the constructor of the server, so that each client connected to a particular session will be identified by the same time. Here's my output:

Zepp: 1
Stones: 0
Floyd: 0
Purple: 0
ACDC: 0
Date created: Sat Sep 11 13:20:40 CEST 2010
Zepp: 1
Stones: 1
Floyd: 0
Purple: 0
ACDC: 0
Date created: Sat Sep 11 13:20:40 CEST 2010
Zepp: 1
Stones: 2
Floyd: 0
Purple: 0
ACDC: 0
Date created: Sat Sep 11 13:20:40 CEST 2010
Zepp: 0
Stones: 0
Floyd: 1
Purple: 0
ACDC: 0
Date created: Sat Sep 11 13:21:32 CEST 2010
Zepp: 0
Stones: 0
Floyd: 2
Purple: 0
ACDC: 0
Date created: Sat Sep 11 13:21:32 CEST 2010
Zepp: 0
Stones: 0
Floyd: 3
Purple: 0
ACDC: 0
Date created: Sat Sep 11 13:21:32 CEST 2010

What about those summaries? You think I can manage to calculate the summary by getting only the elements of a particular session? How would I choose which session I want to get? I cannot know the exact written date and time. Maybe some kind of looping through the list...

Once you've read this in its easy to loop thru all the entries & build an arraylist of unique session dates - which you can then display in an list box for user selection.
What kind of data volumes are you expecting?

Edited 6 Years Ago by JamesCherrill: n/a

Well not much, when I will be testing it in front of the teachers, they may ask me to run a couple of clients, bot nothing big. Did you mean something like looping through this and something like - "if date of i+1 == date of i add to the list, else start a new list"?

Yes, or:

sessions = new collection of Dates
for each vote
  if sessions does not contain this vote's session date 
      add session to sessions

This kind of in-memory processing should be safe and v v fast for thousands of votes, but maybe not millions.

Yes, it did work. I continued developing the project and got into some more errors, but I think I can handle them on my own. Thanks a lot for the help, I think it's time to mark this one as solved. Regards

This question has already been answered. Start a new discussion instead.