Client-Server Code causes Nifty to throw a Concurrent Modification Exception

Hello,

I am trying to write code for a sever and client that would add a custom panel onto the screen when the client connects to the server. The current setup is that the server broadcasts its name to the client when the client connects, and the client sends back its own name to the server so the server can broadcast the client’s name to any other clients on the network. However when the names are passed around, jmonkey throws out an java.util.ConcurrentModificationException. Here is the error log:

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at de.lessvoid.nifty.elements.Element.initControls(Element.java:2023)
at de.lessvoid.nifty.screen.Screen.bindControls(Screen.java:842)
at de.lessvoid.nifty.screen.Screen.startScreen(Screen.java:206)
at de.lessvoid.nifty.Nifty.gotoScreenInternal(Nifty.java:678)
at de.lessvoid.nifty.Nifty.access$400(Nifty.java:77)
at de.lessvoid.nifty.Nifty$1.perform(Nifty.java:635)
at de.lessvoid.nifty.elements.EndOfFrameElementAction.perform(EndOfFrameElementAction.java:22)
at de.lessvoid.nifty.Nifty.executeEndOfFrameElementActions(Nifty.java:439)
at de.lessvoid.nifty.Nifty.handleDynamicElements(Nifty.java:358)
at de.lessvoid.nifty.Nifty.access$1700(Nifty.java:77)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processEvent(Nifty.java:1374)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processMouseEvent(Nifty.java:1329)
at com.jme3.niftygui.InputSystemJme.handleMouseEvent(InputSystemJme.java:124)
at com.jme3.niftygui.InputSystemJme.onMouseButtonEventQueued(InputSystemJme.java:232)
at com.jme3.niftygui.InputSystemJme.forwardEvents(InputSystemJme.java:296)
at de.lessvoid.nifty.Nifty.update(Nifty.java:288)
at com.jme3.niftygui.InputSystemJme.endInput(InputSystemJme.java:113)
at com.jme3.input.InputManager.processQueue(InputManager.java:819)
Layer: Layer_ID (de.lessvoid.nifty.elements.Element@3df47239)
at com.jme3.input.InputManager.update(InputManager.java:883)
at com.jme3.app.Application.update(Application.java:604)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:231)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)

After some digging I came across this thread: Concurrent Modification exception!, but it doesn’t seem like there was a solution provided. Is there a solution to the problem? It looks like Nifty is trying to modify the same screen at the same time. I have tried Semaphores with no success.

Here is my server code:

public void initLobby()
    {
        Main.getNifty().loadStyleFile("nifty-default-styles.xml");
        Main.getNifty().loadControlFile("nifty-default-controls.xml");
        Main.getNifty().registerScreenController(this);
        
    // <screen>
    Main.getNifty().addScreen("Screen_ID", new ScreenBuilder("Hello Nifty Screen"){{
        controller(ServerAppState.this); // Screen properties       

        // <layer>
        layer(new LayerBuilder("Layer_ID") {{
            childLayoutVertical(); // layer properties, add more...

            }});
        // </layer>
    }}.build(Main.getNifty()));
    // </screen>

    screen = Main.getNifty().getScreen("Screen_ID");
    layer = screen.findElementByName("Layer_ID");

    ButtonBuilder b = new ButtonBuilder("Hello Nifty");
    b.alignCenter();
    b.valignCenter();
    b.text("Start Game");
    b.textVAlignCenter();
    b.height("5%");
    b.width("15%");
    b.interactOnClick("startGame()");
    b.build(Main.getNifty(), screen, layer);

    Main.getNifty().gotoScreen("Screen_ID");
    
    
}


public void createUserPanel(String username)
{   
    Main.getNifty().registerScreenController(this);
    System.out.println("Hello Panel");
    System.out.println("Layer: "+this.layer);
    //Creates the panel
    PanelCreator createPanel = new PanelCreator();
    createPanel.setHeight("5%");
    createPanel.setWidth("100%");
    createPanel.setBackgroundColor("#737ca1");
    createPanel.setChildLayout("horizontal");
    Element newPanel = createPanel.create(Main.getNifty(), this.screen, this.layer);
            
    //Creates a label for username
    ControlBuilder cb = new LabelBuilder("label_username");
    cb.text(username);
    cb.valignCenter();
    cb.build(Main.getNifty(), this.screen, newPanel);
    
    //Creates a dropdown for team selection
    ControlBuilder cb1 = new DropDownBuilder("dropDown_teamSelection");
    cb1.valignCenter();
    Element e = cb1.build(Main.getNifty(), this.screen, newPanel);
    DropDown dropDown = e.getNiftyControl(DropDown.class);

    //Creats a checkbox we have to constantly check
    ControlBuilder cb2 = new CheckboxBuilder("checkBox_ready");
    cb2.valignCenter();
    cb2.build(Main.getNifty(), this.screen, newPanel);

    //Creates a textfield as a filler for now
    ControlBuilder cb3 = new TextFieldBuilder("tf");
    cb3.text("Filler for progress bar");
    cb3.valignCenter();
    cb3.build(Main.getNifty(), this.screen, newPanel);
    System.out.println("Goodbye Panel");
}

public void connectionAdded(Server server, HostedConnection conn) {
    System.out.println("Connection Recieved");
    
    InitJoinMessage ijm = new InitJoinMessage(this.usrname);
    server.broadcast(Filters.in(conn), ijm);
    
}

/**
 * Receives messages that come in from outside clients.
 * 
 * @param source
 * @param msg 
 */
public void messageReceived(HostedConnection source, Message msg) 
{
    if(msg instanceof InitJoinMessage)
    {
        createUserPanel(msg.toString());
        server.broadcast(msg);
    }
}

This is my client code:

public void messageReceived(Client source, Message m) {
        if(m instanceof InitJoinMessage)
        {
            try
            {
                lobbySemaphore.acquire();
                System.out.println("message received");
                createUserPanel(m.toString());
                
            }
            catch (InterruptedException ex) {
                Logger.getLogger(ClientAppState.class.getName()).log(Level.SEVERE, null, ex);
            }            
            finally
            {
                lobbySemaphore.release();
            }
        }
    }

It been a long time since i worked with Spidermonkey so I don’t know the code.
You are probably modifying the UI from the wrong thread.
Semaphores won’t help you because Nifty will not use them.
In general don’t use locks in game programming, they don’t work together with an update loop.
You can use app.enqueue() to execute code on the render thread from another thread.
As always good java knowledge will make game programming in jmonkey way easier.