Hot questions for Using Applets in windows

Question:

I'm writing a sort of web applet emulator. I read a web page, find the applet parameters, download the applet and run it. It is very important that the applet runs in its own process (i.e. not the emulator process). It should, however, render in the emulator process window.

How does the Java plugin do it? When the separate_jvm flag is set, the plugin loads the applet in a separate JVM process but the applet still appears in the same browser panel.

I've made some progress by creating a loader class that, on another JVM, adds the target Applet to an undecorated, invisible frame and messages the frame's window handle to the emulator JVM. The latter binds it to a Canvas instance with user32.SetParent via JNA, and the display works perfectly.

However, only mouse events are being sent: keyboard input is not forwarded. The applet reports Component#isFocusOwner as false, and requestFocusInWindow does not make it the focus owner, returning false. How can I pass keyboard focus to the Applet window handle? My current approach involves a server (the emulator), which receives window handles from the client (the applet). Only mouse events appear to work, since the Applet cannot gain focus.

The server class handles the display of the applet.

import com.sun.jna.*;
import com.sun.jna.platform.win32.User32;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import static com.sun.jna.platform.win32.User32.*;

public class Loader {
    private static final String APPLET_DIRECTORY = ""; // TODO: Set this to the directory containing the compiled applet

    private static ServerSocket serverSocket;
    private static JFrame frame;
    private static Canvas nativeDisplayCanvas;

    public static void main(String[] argv) throws Exception {
        nativeDisplayCanvas = new Canvas();
        frame = new JFrame("Frame redirect");
        frame.setLayout(new BorderLayout());
        frame.add(nativeDisplayCanvas, BorderLayout.CENTER);
        frame.setSize(300, 200);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        (new Thread() {
            public void run() {
                try {
                    serve();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

        spawnAltJVM(APPLET_DIRECTORY, "AppletDemo");
    }

    public static void serve() throws Exception {
        serverSocket = new ServerSocket(6067);
        serverSocket.setSoTimeout(10000);

        while (true) {
            try {
                System.out.println("Waiting for applet on port " + serverSocket.getLocalPort() + "...");
                Socket server = serverSocket.accept();
                System.out.println("Connected to " + server.getRemoteSocketAddress());
                BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
                DataOutputStream out = new DataOutputStream(server.getOutputStream());
                while (true) {
                    String msg = in.readLine();
                    if (msg != null && msg.startsWith("child_hwnd")) {
                        windowCreatedHandler(msg);
                        out.writeUTF("hwnd_recv\n");
                        out.flush();
                    }
                }
            } catch (IOException ex) {
                System.out.println("Something happened to the socket...");
                break;
            }
        }
    }

    public static void windowCreatedHandler(String message) {
        String[] tokens = message.split(":");
        final User32 user32 = User32.INSTANCE;
        HWND child_applet = new HWND(Pointer.createConstant(Long.parseLong(tokens[1])));
        final HWND child_frame = new HWND(Pointer.createConstant(Long.parseLong(tokens[2])));

        frame.addComponentListener(
                new ComponentAdapter() {
                    @Override
                    public void componentResized(ComponentEvent e) {
                        user32.SetWindowPos(child_frame, new HWND(Pointer.NULL), 0, 0, frame.getWidth(), frame.getHeight(), 0);
                    }
                }
        );
        HWND parent = new HWND(Native.getComponentPointer(nativeDisplayCanvas));

        user32.SetParent(child_applet, parent);

        int style = user32.GetWindowLong(child_frame, GWL_STYLE) & ~WS_POPUP | (WS_CHILD | WS_VISIBLE);
        user32.SetWindowLong(child_applet, GWL_STYLE, style);
        user32.SetWindowPos(child_applet, new HWND(Pointer.NULL), 0, 0, nativeDisplayCanvas.getWidth(), nativeDisplayCanvas.getHeight(), 0);
    }

    public static void spawnAltJVM(String cp, String clazz) throws IOException, InterruptedException, ClassNotFoundException {
        ProcessBuilder processBuilder = new ProcessBuilder(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java", "-cp", cp, clazz);
        Process applet = processBuilder.start();
        final BufferedReader in = new BufferedReader(new InputStreamReader(applet.getInputStream()));
        final BufferedReader err = new BufferedReader(new InputStreamReader(applet.getErrorStream()));
        (new Thread() {
            public void run() {
                while (true) {
                    try {
                        System.out.println("[client] " + in.readLine());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

Meanwhile, the client class just instantiates and messages the handles.

import sun.awt.windows.WComponentPeer;
import javax.swing.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingDeque;

public class AppletDemo extends Applet {
    private Canvas canvas;
    private static Color backgroundColor = Color.RED;

    public AppletDemo() {
        setLayout(new BorderLayout());
        canvas = new Canvas();
        add(canvas, BorderLayout.CENTER);
        setBackground(Color.CYAN);
        canvas.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                refreshColors();
            }
        });
        canvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                refreshColors();
            }
        });
    }

    private void refreshColors() {
        SwingUtilities.invokeLater(
                new Runnable() {
                    @Override
                    public void run() {
                        backgroundColor = (backgroundColor == Color.RED ? Color.GREEN : Color.RED);
                        canvas.setBackground(backgroundColor);
                    }
                }
        );
    }

    public static void main(String[] argv) throws Exception {
        System.setErr(System.out);

        final AppletDemo app = new AppletDemo();
        Frame frame = new Frame("AppletViewer");
        frame.setLayout(new BorderLayout());
        frame.add(app, BorderLayout.CENTER);
        frame.setUndecorated(true);
        frame.pack(); // Create the native peers
        frame.setSize(300, 200);

        final Socket client = new Socket("localhost", 6067);
        final LinkedBlockingDeque<String> messageQueue = new LinkedBlockingDeque<>();
        final DataOutputStream out = new DataOutputStream(client.getOutputStream());
        final BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        (new Thread() {
            public void run() {
                while (true) {
                    try {
                        out.writeBytes(messageQueue.take() + "\n");
                        out.flush();
                    } catch (IOException | InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }).start();
        (new Thread() {
            public void run() {
                while (true) {
                    try {
                        if ("hwnd_recv".equals(in.readLine())) {
                            // Attempt to grab focus in the other process' frame
                            System.out.println("Trying to request focus...");
                            System.out.println(app.requestFocusInWindow());
                        }
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }).start();

        messageQueue.add("child_hwnd:" + ((WComponentPeer) app.getPeer()).getHWnd() + ":" + ((WComponentPeer) frame.getPeer()).getHWnd());
    }
}

They're both a bit lengthy because they require some socket work, but they are compilable and should demonstrate the issue. They require JNA to compile. I've shortened them as much as possible at the cost of some good practices.

When Loader is ran, a window redirecting the AppletDemo's canvas should appear. Mouse events are sent: the canvas toggles between red and green on a mouse press. Ideally, the same behavior should occur for keystrokes too.

I've used WinSpy to get the handles of a notepad.exe window and text pane, and hardcoding the handles into Loader. Keyboard focus works perfectly with the multiline edit control, but not with the toplevel window itself. Why? Is this related to the issue I'm having?

I opened up a Chrome window running an applet in WinSpy, and found that the plugin creates no dummy Frame — the applet canvas is directly set as a child of Chrome. However, I haven't been able to create a native peer for the Applet, since it seems to require it to be displayable.

I've read about the dangers of cross-process parent/child or owner/owned window relationship, but I can't think of a better way to graft the child applet into the emulator.


Answer:

Since what you really want is to create the applet as a child window, the easy solution would be to convince the applet to be your children, not forcefully adopting it, and working against both Windows and the JVM.

Luckily, the Sun/Oracle Java VM comes with a class called WComponentFrame (Windows-only as implied from the name). It can constructed from an hwnd, which you can send from your parent process. The applet can then be added as a child of your window.

import sun.awt.windows.WComponentPeer;

frame = new WEmbeddedFrame(hwnd);
frame.setLayout(new BorderLayout());
frame.add(applet, BorderLayout.CENTER);

Question:

I have developed an applet, it require lots of libraries (around 5mb in .jar files), I know exactly in what pcs it will run, can I put these jars into the system in order to avoid to be downloaded each time the applet is oppened?

The system runs Windows.

The main idea for store these libs in the pc is low bandwidth.

I have tried using proguard in order to compress and reduce code size but it doesn't reduce enough, I need only to download the applet and store all libraries locally.

Thanks.

UPDATE

Tomasz Szuba answer is exactly what I was looking for.

Put all jars into jre/lib/ext/

Thanks.


Answer:

It would probably be best to just rely on Java applet caching. If you specify your applet object with multiple jars, ones that are not changed won't be redownloaded. For example:

<applet codebase ="." code="com.applet.class"
        archive="applet.jar,lib.jar,anotherlib.jar"/>

This way if lib.jar and anotherlib.jar are not changed they won't be redownloaded.

If you really must distributed those libs earlier then:

  1. Omit those lib from archive attribute
  2. Put those libs to extensions library folders. Instructions

Other tutorial provides way to automatically instal extension by applet an using one in it: http://docs.oracle.com/javase/tutorial/ext/basics/download.html

Question:

I am developing java applet which should be able to read certificates from Windows-MY instance. This is the part that I am able to do and is working fine. My problem is when I enter PIN code (provided via edit text control), Windows certificate manager after that asks me again for the same PIN code.

So, I have few question and will be very thankful if you are able to help me.

  1. What am I doing wrong in my code, why it is not using my PIN provided via EditText control? How to accomplish that?
  2. If that is not possible, please if you can tell me, do PKCS#12 Digital Certificates are behaving in the same way like PKCS#11 Smart Card Certificates? To be precise, do they asking for PIN in the same manner like PKCS#11? If it so, I should be able to remove my field for PIN and leave Windows to do that part of the job.

Here is part of the code used in my applet:

keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
keystore.load(null,_PIN);

String aliass = (String) aliasses.nextElement();
X509Certificate oPublicCertificate = (X509Certificate) keystore.getCertificate(alias);
PrivateKey oPrivateKey = (PrivateKey) keystore.getKey(alias,null);
if(oPrivateKey == null) continue;
if(aliass != alias) continue;

System.out.println("Sign with alias:"+aliass);
System.out.println("gettype:"+oPublicCertificate.getType());
System.out.println("serial:"+oPublicCertificate.getSerialNumber());
System.out.println("Public Key:"+oPublicCertificate.getPublicKey());
 _PK = Base64Utils.base64Encode(oPublicCertificate.getPublicKey().getEncoded());
System.out.println("Public Key:"+_PK);

Provider p = keystore.getProvider();
// data to sign
byte[] data ="Data for signing".getBytes();
// Signing the data
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initSign(oPrivateKey);

sig.update(data);

byte[] signature = sig.sign();  //<--- Here asks for PIN second time.

System.out.println("Signature.sign():" + signature);

Signature verifier = Signature.getInstance("SHA1withRSA", p);
verifier.initVerify(oPublicCertificate);
verifier.update(data);
boolean isValidSignature = verifier.verify(signature);
System.out.println("the verification result "+ isValidSignature);

I am open for different approaches to solve this problem.


Answer:

You need to implement a callback handler please check this

as this example copied from the mentioned reference which override the callbacks handling

public void handle(Callback[] callbacks)
 throws IOException, UnsupportedCallbackException {

   for (int i = 0; i < callbacks.length; i++) {
      if (callbacks[i] instanceof PasswordCallback) {

          // prompt the user for sensitive information
          PasswordCallback pc = (PasswordCallback)callbacks[i];
          System.err.print(pc.getPrompt());
          System.err.flush();
          pc.setPassword(readPassword(System.in));

      } 
   }
 }

then you can use your callback

CallbackHandler callBackHandler = new yourImplementedHandler();
KeyStore.ProtectionParameter protection = new KeyStore.CallbackHandlerProtection(callBackHandler);
Provider provider = Security.getProvider("SunMSCAPI");
KeyStore.Builder keystoreBuilder = KeyStore.Builder.newInstance("Windows-MY",
                                                                provider, 
                                                                protection);
KeyStore keystore = keystoreBuilder.getKeyStore();

I hope this could help.

Question:

According to my understanding of documentation there should be possbile to access Microsoft Windows KeyStore by service "Windows-MY".

When I load PrivateKey from keyStore I get null for privateKey.getEncoded().

How can I properly access PrivateKey from Windows keystore?

Trying to access it with:

KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null);
PrivateKey privateKey = (PrivateKey) ks.getKey("myKeyAlias", null);
System.out.println("privateKey:" + privateKey));
System.out.println("getEncoded:" + privateKey.getEncoded());

Output I'm getting:

privateKey:RSAPrivateKey [size=2048 bits, type=Exchange, container=myKeyAlias]
getEncoded:null

Using JRE 1.8 and tested with Win7 and 8.1


Answer:

The MSCAPI does not seem to support private key export.

First of all the Key.getEncoded() javadoc specifies:

Returns the key in its primary encoding format, or null if this key does not support encoding.

And if you look at the source code of the Java crypto provider for MSCAPI, the getEncoded() method actually returns null in all cases.

Question:

I have been following a tutorial online on making a 2D game but hope to expand on it. Everything has been working up to the point when I try moving items around in an inventory. I can successfully pick up items and place them back down onto the invBar, but it will not allow me to place them into the inventory invBag. I have followed everything that he went over but for some reason he did not get the error.

I am a beginning coder and so far I understand that this error is created by the array going "out of bounds" (as the title of the error obviously mentions) but I do not understand "how" it is going out of bounds.

Edit: GAWD I am an idiot... for some reason I have been typing 1 instead of i for some dum reason, and apparently that was the problem.

Code for Inventory:

package y.m.m //to protect project name

import java.awt.*;
import java.awt.event.*;

public class Inventory {
public static Cell[] invBar = new Cell[Tile.invLength];
public static Cell[] invBag = new Cell[Tile.invLength * Tile.invHeight];

public static boolean isOpen = false;
public static boolean isHolding = false;

public static int selected = 0;
public static int[] holdingID = Tile.air;
public static int holdingCount = 0;

public Inventory() {
    for(int i = 0; i < invBar.length; i++) {
        invBar[i] = new Cell(new Rectangle((Component.pixel.width / 2) - ((Tile.invLength * (Tile.invCellSize + Tile.invCellSpace))/2) + (i * (Tile.invCellSize + Tile.invCellSpace)), Component.pixel.height - (Tile.invCellSize + Tile.invBorderSpace), Tile.invCellSize, Tile.invCellSize), Tile.air);
    }

    int x = 0, y = 0;
    for(int i = 0; i < invBag.length; i++) {
        invBag[i] = new Cell(new Rectangle((Component.pixel.width / 2) - ((Tile.invLength * (Tile.invCellSize + Tile.invCellSpace))/2) + (x * (Tile.invCellSize + Tile.invCellSpace)), Component.pixel.height - (Tile.invCellSize + Tile.invBorderSpace) - (Tile.invHeight * (Tile.invCellSize + Tile.invCellSpace)) + (y * (Tile.invCellSize + Tile.invCellSpace)), Tile.invCellSize, Tile.invCellSize), Tile.air);

        x++;
        if(x == Tile.invLength) {
            x = 0;
            y++;
        }
    }

    invBar[0].id = Tile.sand;
    invBar[1].id = Tile.grass;
    invBar[2].id = Tile.dirt;
    invBar[3].id = Tile.bush;
}

public static void click(MouseEvent e) {
    if(e.getButton() == 1) {
        if(isOpen) {
            for(int i = 0; 1 < invBar.length; i++) {
            Line 43 > if(invBar[i].contains(new Point(Component.mse.x / Component.pixelSize, Component.mse.y / Component.pixelSize))) {
                    if(invBar[i].id != Tile.air && !isHolding) {
                        holdingID = invBar[i].id;
                        invBar[i].id = Tile.air;

                        isHolding = true;
                    } else if(isHolding && invBar[i].id == Tile.air) {
                        invBar[i].id = holdingID;

                        isHolding = false;
                    } else if(isHolding && invBar[i].id != Tile.air) {
                        int[] con = invBar[i].id;
                        invBar[i].id = holdingID;
                        holdingID = con;
                    }
                }
            }


            for(int i = 0; 1 < invBag.length; i++) {
                if(invBag[i].contains(new Point(Component.mse.x / Component.pixelSize, Component.mse.y / Component.pixelSize))) {
                    if(invBag[i].id != Tile.air && !isHolding) {
                        holdingID = invBag[i].id;
                        invBag[i].id = Tile.air;    

                        isHolding = true;
                    } else if(isHolding && invBag[i].id == Tile.air) {
                        invBag[i].id = holdingID;   

                        isHolding = false;
                    } else if(isHolding && invBag[i].id != Tile.air) {
                        int[] con = invBag[i].id;

                        invBag[i].id = holdingID;
                        holdingID = con;
                    }
                }
            }
        }
    }
}

public void render(Graphics g) {
    for(int i = 0; i < invBar.length; i++) {
        boolean isSelected = false;
        if(i == selected) {
            isSelected = true;
        }

        invBar[i].render(g, isSelected);
    }

    if(isOpen) {
        //g.fillRect(0, 0, 100, 100);
        for(int i = 0;i < invBag.length; i++) {
            invBag[i].render(g, false);
        }
    }

    if(isHolding) {
        // [- (Tile.invCellSize / 2)] centers item to mouse
        g.drawImage(Tile.tileset_terrain, (Component.mse.x / Component.pixelSize) - (Tile.invCellSize / 2) + Tile.invItemBorder, (Component.mse.y / Component.pixelSize) - (Tile.invCellSize / 2) + Tile.invItemBorder, (Component.mse.x / Component.pixelSize) - (Tile.invCellSize / 2) + Tile.invCellSize - Tile.invItemBorder, (Component.mse.y / Component.pixelSize) - (Tile.invCellSize / 2) + Tile.invCellSize - Tile.invItemBorder, holdingID[0] * Tile.tileSize, holdingID[1] * Tile.tileSize, holdingID[0] * Tile.tileSize + Tile.tileSize, holdingID[1] * Tile.tileSize + Tile.tileSize, null);
    }
}
}

Chunk from Listening that is mentioned:

public void mousePressed(MouseEvent e) {
    if(e.getButton() == MouseEvent.BUTTON1) {
        Component.isMseLeft = true;
    } else if(e.getButton() == MouseEvent.BUTTON3) {
        Component.isMseRight = true;
    }

Line 158 > Inventory.click(e);
}

The error that is generated:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at y.m.m.Inventory.click(Inventory.java:43)
at y.m.m.Listening.mousePressed(Listening.java:158)
at java.awt.Component.processMouseEvent(Component.java:6502)
at java.awt.Component.processEvent(Component.java:6270)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:708)
at java.awt.EventQueue$4.run(EventQueue.java:706)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Answer:

In your for loop you have

int i = 0; 1 < invBag.length; i++

since 1 < invBag.length is always true , Hence IndexOutOfBoundException

Question:

I'm trying to make a simple JDialog, which asks the user for input in the form of 3 text fields, and it displays correctly and its PropertyListener works perfectly fine, I haven't assigned a parent for the JDialog in it's constructor, so I'm guessing by default the parent is set to be the ancestor of all the components in my applet. However, when I change from the applet to, say a firefox window and when I click back on my applet, the JDialog has disappeared. Would I need to set a certain property to the JDialog to make sure it stays even when I switch windows. The starnge thing is that I think the dialog is still up, but invisible, because when another dialog appears after the first has disappeared, both dialog appear at once(the first dialog reappearing). MY code for the JDialog is just below:

private void addQuestion() {
        questionTextField = new TextField(50);

        Object[] componentsArray = {"Question:", questionTextField, "MQLYes:", mqlYesTextField, "MQLNo:", mqlNoTextField};
        Object[] options = {"Enter", "Cancel"};
        addQuestionDialog = new JDialog(new JFrame(),"Add question");
        addQuestionPane = new JOptionPane(componentsArray, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null, options, options[0]);

        int x = getX() + getWidth()/2, y = getY() + getHeight()/2;

        addQuestionDialog.setContentPane(addQuestionPane);
        addQuestionDialog.setResizable(false);
        addQuestionDialog.setSize(300,210);
        addQuestionDialog.setVisible(true);
        addQuestionDialog.setLocation(x, y);
        addQuestionDialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);

        addQuestionPane.addPropertyChangeListener(this);
    }

public void propertyChange(PropertyChangeEvent e) {
    String prop = e.getPropertyName();

    if (addQuestionDialog.isVisible() && (e.getSource() == addQuestionPane) && (JOptionPane.VALUE_PROPERTY.equals(prop) || JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
        Object value = addQuestionPane.getValue();

        if (value == JOptionPane.UNINITIALIZED_VALUE) {
            //ignore reset
            return;
        }

        //Reset the JOptionPane's value.
        //If you don't do this, then if the user
        //presses the same button next time, no
        //property change event will be fired.
        addQuestionPane.setValue(
            JOptionPane.UNINITIALIZED_VALUE);

        if (value.equals("Enter")) {
            String questionTypedText = questionTextField.getText();
            String mqlYesTypedText = mqlYesTextField.getText();
            String mqlNoTypedText = mqlNoTextField.getText();

            sqlModel.addQuestion(questionTypedText, mqlYesTypedText, mqlNoTypedText);
            questionTextField.setText("");
            mqlYesTextField.setText("");
            mqlNoTextField.setText("");
        } else { //user closed dialog or clicked cancel
            addQuestionDialog.setVisible(false);
        }
    }
}

I've checked the code several time and I don't see any issues with it, and the dialogs do what they're supposed to do, so I'm guessing there's a special addQuestion.set...(Object setValue) method which I should be adding in.


Answer:

Would I need to set a certain property to the JDialog to make sure it stays even when I switch windows.

Yes.

I haven't assigned a parent for the JDialog in it's constructor,

and that would be the problem. The dialog will be visible whenever the owner of the dialog is visible, so you need to specify the owner JFrame.