1

To run my code, just copy and paste it into your IDE - everything is there. This is a flight monitoring program which uses the Observer-Observable design pattern. FlightStautsMonitor is the Observer which monitors the flight status (an integer) of a Flight. FlightStatusChangeEvent is a class which notes the change of status of a flight. Demo is the driver class, or class with main.

My problem is that I am not sure if I am using the Observer and Observable API. I am getting an output with runtime error -

Old flight status
F:1, S: 0
F:2, S: 0
F:3, S: 0
F:4, S: 0
F:5, S: 0
Exception in thread "main" java.lang.StackOverflowError
at java.util.Vector.toArray(Unknown Source)
at java.util.Observable.notifyObservers(Unknown Source)
at demo.Flight.updateStatus(Demo.java:40)
at demo.FlightStatusMonitor.update(Demo.java:91)
at java.util.Observable.notifyObservers(Unknown Source)

What is the reason for the problem and how do i fix this code ?

//package demo;

import java.util.*;

class FlightStatusChangeEvent{

int status;
Flight flight;

FlightStatusChangeEvent(int statusCode, Flight flight){

    this.status = statusCode;
    this.flight = flight;

}

public int getStatus(){return this.status;}

public Flight getFlight(){return this.flight;}


}

class Flight extends Observable{

int status;// 0 = on time, -1 = late, +1 = before scheduled time
String flightCode;

Flight(String flightCode){

    this.flightCode = flightCode;

}

public void updateStatus(int statusCode){

    this.status = statusCode;
    FlightStatusChangeEvent fsce = new FlightStatusChangeEvent(status, this);
    setChanged();
    notifyObservers(fsce);

}


public String getFlightCode(){return this.flightCode;}

public String toString(){return "F:" + flightCode + ", S: " + status;}

}


 class FlightStatusMonitor implements Observer{

public static ArrayList<Flight> flights = new ArrayList<Flight>();

static{

    for(int i = 1; i < 6; i++){

        Flight ff = new Flight("" + i);
        flights.add(ff);        
    }

}

//keep calling this method every 10 sec to get latest flight status
public static void displayStatusOfFlights(){

    //print all flight statuses in array list - flights
    for(Flight fl : flights){
        System.out.println(fl);

    }

}

public void update(Observable flight, Object flightStatusEvent){

    FlightStatusChangeEvent fsce = (FlightStatusChangeEvent) flightStatusEvent;     
    Flight fl = fsce.getFlight();
    String code = fl.getFlightCode();
    int status = fsce.getStatus();

    //find the flight in array flights and then update its status
    for(int i = 0; i < flights.size(); i++){

        Flight fli = flights.get(i);
        String flCode = fli.getFlightCode();

        if(flCode.equals(code)){
            fli.updateStatus(status);
            System.out.print("Flight status updated !");

            break;

        }

    }


}

}


 public class Demo{

public static void main(String[]args){

    FlightStatusMonitor fsm = new FlightStatusMonitor();
    System.out.println("Old flight status");
    ArrayList<Flight> fllist = fsm.flights;
    fsm.displayStatusOfFlights();

    for(Flight fl : fllist ){

        fl.addObserver(fsm);

    }

    fsm.flights.get(1).updateStatus(-1);
    System.out.println("New flight status");        
    fsm.displayStatusOfFlights();

}


}
david blaine
  • 5,683
  • 12
  • 46
  • 55
  • This error means that somehow you're calling methods and the stack can't hold them. Maybe some method is called recursively infinite times or you're calling too many methods in chain (of course the last one is harder to find). – Luiggi Mendoza Mar 24 '13 at 04:36
  • @chm052 - Its there already. look at the question carefully – david blaine Mar 24 '13 at 04:38
  • Debugger. Basically, if you are running on Windows (and probably Linux) or Mac with Java 7, you can step into the Java source itself – MadProgrammer Mar 24 '13 at 04:38
  • @MadProgrammer - I don't know how to use a debugger. What do you mean by step into the java source itself ? – david blaine Mar 24 '13 at 04:40
  • 2
    @davidblaine What IDE are you using? Netbeans and Ecllipse both have debugger capabilities that let you stop the code execution and step over or into methods so you can see there execution process – MadProgrammer Mar 24 '13 at 04:45
  • possible duplicate of [What is a stack overflow error?](http://stackoverflow.com/questions/214741/what-is-a-stack-overflow-error) –  Mar 27 '14 at 05:44

2 Answers2

3

Flight.updateStatus is calling notifyObersevers

FlightStatusMonitor#update is calling flights.get(x).updateStatus...start end less.

Not update the state of you objects within the event notification received from said objects...

Here is the critical section of the stack trace:

Exception in thread "main" java.lang.StackOverflowError
    at java.util.Arrays.copyOf(Arrays.java:2219)
    at java.util.Vector.toArray(Vector.java:687)
    at java.util.Observable.notifyObservers(Observable.java:154)
    at teststackoverflow.Demo$Flight.updateStatus(Demo.java:73)
    at teststackoverflow.Demo$FlightStatusMonitor.update(Demo.java:125)
    at java.util.Observable.notifyObservers(Observable.java:159)
    at teststackoverflow.Demo$Flight.updateStatus(Demo.java:73)
    at teststackoverflow.Demo$FlightStatusMonitor.update(Demo.java:125)

You can (starting at the bottom), FlightStatusMonitor.update is calling Flight#updateStatus, which is calling Observable.notifyObservers which is calling FlightStatusMonitor.update

I would also be advisable for you to compile your code with the debug flag set to true (javac -g)

Updated with possible fix

So, I THINK, what you need to do is not only compare the flight code, but also the flight status of each flight and only change those whose status don't match

public void update(Observable flight, Object flightStatusEvent) {

    FlightStatusChangeEvent fsce = (FlightStatusChangeEvent) flightStatusEvent;
    Flight fl = fsce.getFlight();
    String code = fl.getFlightCode();
    int status = fsce.getStatus();

    //find the flight in array flights and then update its status
    for (int i = 0; i < flights.size(); i++) {

        Flight fli = flights.get(i);
        String flCode = fli.getFlightCode();

        if (flCode.equals(code)) {
            //** Possible Fix **//
            if (fli.status != fl.status) {
                fli.updateStatus(status);
                System.out.print("Flight status updated !");
            }
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • MadProgrammer - can you show me how to fix my code ? I am not able to understand your answer properly. – david blaine Mar 24 '13 at 04:54
  • 1
    This line `fli.updateStatus(status);` in the `update` method of your `FlightStatusMonitor` class is the problem point. It's causing a never ending loop which will cause a stack overflow error. Without know what it is trying to do, I can't help you further – MadProgrammer Mar 24 '13 at 04:56
  • What I can't figure out is why you're updating the status inside the `update` method anyway, the status should have already changed by the time this method is called. This method is responding to change in the status of the flight anyway?? – MadProgrammer Mar 24 '13 at 04:59
  • Ok. This is my aim - whenever a flight status is updated by some class like Pilot(not shown in above code) using the updateStatus(int) method, the FlightMonitorClass (FMC) should be notified. FMC will update the status of the correct flight in its array list of flights. – david blaine Mar 24 '13 at 05:03
  • 1
    But what's happening is you updating the flight that is changing, cause an infinite loop... – MadProgrammer Mar 24 '13 at 05:04
  • I changed the code to make it work. Removed the class FlightStatusChangeEvent and added a new method setStatus(int statusCode){} to fix the code. I still don't know if I should be using the Observer-Observable design pattern here. It looks like my code has bad design – david blaine Mar 24 '13 at 05:13
  • What I would focus on is who cares about the change. For example, only the next flight really cares. If each flight has 0 or 1 flight in its chain, then you only need the next flight to monitor it. You'll get a chain of events flowing on – MadProgrammer Mar 24 '13 at 07:02
3

StackOverflowError is thrown when a stack overflow occurs because an application recurses too deeply.

Your problem is in update method. You're call updateStatus method and the updateStatus method will call update again. Remove fli.updateStatus(status); will solve your problem.

public void update(Observable flight, Object flightStatusEvent) {

        FlightStatusChangeEvent fsce = (FlightStatusChangeEvent) flightStatusEvent;
        Flight fl = fsce.getFlight();
        String code = fl.getFlightCode();
        int status = fsce.getStatus();

        // find the flight in array flights and then update its status
        for (int i = 0; i < flights.size(); i++) {

            Flight fli = flights.get(i);
            String flCode = fli.getFlightCode();

            if (flCode.equals(code)) {
                // THIS WILL CAUSE STACKOVERFLOWERROR
                fli.updateStatus(status);
                System.out.print("Flight status updated !");

                break;

            }

        }

    }
Iswanto San
  • 18,263
  • 13
  • 58
  • 79