Will new instance of JVM or reflection help in this case - java

I had a problem that I posted before but got no clear solution
How to prevent JFrame from closing.
So I am posting a SSCCE may be this might help in better understanding the problem being faced
package myApp;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import App2.Applic2;
public class MYApp {
#SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String arg[]){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Application frame 1");
f.setSize(200,200);
f.setVisible(true);
Class cls = Applic2.class;
Object[] actuals = { new String[] { "" } };
Method m = null;
try {
m=cls.getMethod("main", new Class[] { String[].class } );
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
m.invoke(null,actuals);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
second package
package App2;
import javax.swing.JFrame;
public class Applic2 {
#SuppressWarnings("unused")
public static void main(String args[]){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200,200);
f.setVisible(true);
f.setTitle("This needs not to be changed");
NewFrame3 Frame3 = new NewFrame3();
}
}
Second class of App2 package.
package App2;
import javax.swing.JFrame;
public class NewFrame3 {
public NewFrame3(){
JFrame f = new JFrame();
f.setTitle("f3");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200,200);
f.setLocation(200, 200);
f.setVisible(true);
}
}
MYAPP invokes instance of Applic2 which further invokes instance of NewFrame3. Like we can see if I close instance of 'NewFrame3' or instance of Applic2 the entire program closes (due to EXIT_ON_CLOSE) statement.
I want a solution in which MYAPP should not close on closing Applic2 or NewFrame3.
I cannot make any changes to APPlic2 or NewFrame3. via reflection If we try to turn EXIT_ON_CLOSE to DISPOSE_ON_CLOSE How do we access these frames and their setDefaultCloseOperation() when we do not have our classes extended JFrames ?
In another solution as mentioned a new JVM instance should be created and Applic2 should be executed in a new process on this new JVM instance. but then I encountered that runtime.exec takes Java commands as input and not Java statements like method.invoke().
I have access to the Applic2 via loader that loaded Applic2 I can only access the class files of Applic2 in memory so no way I can use jar to run in runtime.exec(). Now how do I solve it?
Adding these statements to MYApp classensures that on clicking close button of a frame nothing happens but this does not seem the be the case
Frame[] f2 = JFrame.getFrames();
for(Frame fx: f2){
System.out.println(fx.getTitle());
fx.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
}
});
and this code needs to be added to the last frame that was instantiated else it does returns all frames. i.e, if this frame is added to JFrame3 class all instantiated frames are returned if added to MyApp JFrame in MyApp is returned and if added Applic2 then frames instantiated in MYApp and Applic2 are returned. Why this behaviour ??

You could use JFrame.getFrames() which returns an array of Frame (you could also getWindows() for a much lower level list of those windows created within the current application context).
Then, you need to walk through, checking each frame to see if it meets your requirements. After, that, you don't need reflection, you gain direct access to the frames
The only only way to communicate with other JVM's is via socket comms (such as RMI).
UPDATE WITH EXAMPLE
Frame[] listOfFrames = JFrame.getFrames();
for (Frame : listOfFrames) {
if (frame instanceof JFrame) {
JFrame aFrame = (JFrame)frame;
}
}

Cross Process Communications is not a simple thing. Basically, each process you want to talk to needs to have a ServerSocket with which it can accept incoming requests. If you want to perform two way communication, each process would need to have it's own ServerSocket, this will allow ANY process to start the communications.
This raises issues with port numbers and the like, but you could actually do a muticast to over come that (basically, "hay everybody, I'm here, come talk to me") which could be used to determine who's available or not - take a look at Broadcasting to Multiple Recipients for an example.
So. When you're ready, you would open a socket connection to the process in question (localhost/127.0.0.1) on it's port and start chatting.
Now. The problem I see with what you've described, is the fact that in order to get this to run, you're going to need some kind of launcher that can create the server socket and then execute the existing program (as you've already described), which raises the question of why? If you're only goal is to get these frames to stop closing your application, simply launching the program in a new JVM achieves that goal. Obviously, if you still need more information from them, then that's a reasonable excuse for all the hard work.
Now, the good news, you can serialize objects across sockets (that is, you can send Java objects via the socket connection), check Discover the secrets of the Java Serialization API for more info.
Now, if that hasn't scared you off, check out All About Sockets for more information.
And finally, the big question of "how" to execute a new JVM, check out Java ProcessBuilder, it actually describes a means by which you can execute a new JVM!!

So have completed the solution with the help provided by MadProgrammer amd mKorbel and here is the updated MYApp class
package myApp;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import App2.Applic2;
public class MYApp {
#SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String arg[]){
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Application frame 1");
f.setSize(200,200);
f.setVisible(true);
Class cls = Applic2.class;
Object[] actuals = { new String[] { "" } };
Method m = null;
try {
m=cls.getMethod("main", new Class[] { String[].class } );
Method[] m1 =Frame.class.getDeclaredMethods();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
m.invoke(null,actuals);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Frame[] f2 = JFrame.getFrames();
// Window[] f23= JFrame.getFrames();
for(Frame fx: f2){
System.out.println(fx.getTitle());
// fx.setVisible(false);
if (fx instanceof JFrame) {
JFrame aFrame = (JFrame)fx;
aFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
}
}
}

Related

Creating Connection Method Within The Class Is Valid or Not in Java

I am developing an application using Swing, so before starting up I need to know a few basics regarding working with Connection. In many tutorials, I have seen that we need to create a connection Class and get the connection within the project using getConnection().
But I have created a connectionMethod is it possible to get the connection in my entire project by creating object of the connection class and using the connection?
This is my code:
package ncl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Test {
Connection connection=null;
public void connectionMethod() {
try {
Class.forName("org.h2.Driver");
connection=DriverManager.getConnection("jdbc:h2:~/test","sa", "");
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
new Test().connectionMethod();
try {
// DO STUFF HERE
} catch (Exception e) {
// TODO: handle exception
}finally {
try {
new Test().connection.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
}
}
I want to know whether this approach is good or not.
This totally depends on the practitioner that how he/she wants to code. Ideally we should follow Design Patterns in implementation to achieve many properties like Low Coupling, High Cohesion etc.
You told that in many tutorials, they make separate class which only provides connection. It is a good practice to avoid the problem of dependency and we can allocate responsibility to the classes in more efficient way. So you should also do it by creating new class which only provides the connection.
For the mentioned code, you have made some mistakes. You have first taken an instance of Test class which has connection and you didn't assign it to any variable. So you can't use it further when you need the connection. Another mistake is that you try to close the connection by creating another instance of Test class which obviously doesn't have started connection.
So, you can make appropriate suggested changes.
ConnectionFactory.java :
This will provide the connection objects.
package ncl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionFactory {
Connection connection=null;
public void connectionMethod() {
try {
Class.forName("org.h2.Driver");
connection=DriverManager.getConnection("jdbc:h2:~/test","sa", "");
} catch (ClassNotFoundException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Test.java :
Write the actual code here.
package ncl;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
ConnectionFactory connectionObject = new ConnectionFactory();
connectionObject.connectionMethod();
try {
// DO STUFF HERE
} catch (Exception e) {
// TODO: handle exception
}finally {
try {
connectionObject.connection.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
}
}
You can use below utility class :
public class MyConnection {
private Connection con = null;
public Connection getConnection() {
try {
if (con == null) {
Class.forName("org.h2.Driver");
con = DriverManager.getConnection("jdbc:h2:~/test", "sa", "");
}
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
}
For getting connection you can call MyConnection().getConnection();
For example :
If you want to get connection in any class then do the following :
Connection con = new MyConnection().getConnection();

Using multithreading get response from different urls

I am making an ajax call to a Java servlet which gets response from different urls and manipulate the data before sending back. Now as there are many urls, to speed up the process rather than sequential processing I have used CountDownLatch and made a class for each url response(which I will use for multithreading). I am not able to understand how to send data back from each response class to the main servlet so that I can manipulate and send back the data to ajax call.
Here's the doget() of my servlet which is called through ajax call.
private static CountDownLatch _latch;
private static int N = 2;
_latch = new CountDownLatch(N);
try {
new Thread(new FirstUrl(_latch)).start();
new Thread(new SecondUrl(_latch)).start();
_latch.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
Here are the url response classes.
public class SecondUrl implements Runnable {
private CountDownLatch _latch = null;
public SecondUrl(CountDownLatch _latch) {
this._latch = _latch;
}
public void run() {
URI uri;
try {
uri = new URI("http://url1.com");
JSONTokener tokener = new JSONTokener(uri.toURL().openStream());
JSONObject root = new JSONObject(tokener);
_latch.countDown();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Similarly, there is another class with a different url. How to send the JSONObject result back to servlet, so that I can manipulate it.
I am new to multithreading so I might be wrong about any approach. Feel free to point out. Thanks.
Make use of the Callable instead of Runnable. Look at Future interface.
One (of the many) way (to pass result back from your threads) is to pass to your threads a reference to a ArrayBlockingQueue that is initialized in your main thread. The result can be added to the queue. In the main thread, you can either process as the data becomes available or process at the end (after you finish you _latch.await()).
try using a synchronized method to 'join' result in each individual thread, Using Runnable is fine.
And you don't need a second class for SecondUrl. you can use a single class and you can pass the url as a parameter to the class.

How to create a java application which can be run as window service?

I need your advice on creating a Java application which can be used to run as a service. I am using Java service wrapper to install and run it as a service in windows.
I have 2 classes ServiceApp.java & RMIService.java. ServiceApp has main method and RMIService will be a server running to accept connection from client..
Now here is my problem. From my main method, as soon as I create RMIService, the main thread will exit and application halts which is correct. Since I wanted to block the main thread to run it as a service, I created a SocketServer and Socket object and called Socket.accept(). This works fine and service is running as main thread gets blocked but I am not convinced that this is the correct approach. Please provide me the right way to do this . Here is a code snippet :
public class ServiceApp {
public static void main(String[] args) {
System.out.println("Starting RMI server");
{
RMIService rmiService;
try {
rmiService = new RemoteServerService();
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("RMIServer", rmiService);
System.out.println("RMI server running");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket( 7000 );
while ( true )
{
socket = serverSocket.accept(); //This will block the main thread
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
try {
if (socket != null)
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
PS : I had searched Stackoverflow on these questions but couldn't find any that matched with my requirement.
When you export any remote object, including the Registry, one or more non-daemon listener threads are created to listen to the port(s) concerned. These will prevent the process from exiting. You don't need to do anything further, and you certainly don't need an otherwise pointless ServerSocket.
However you do need to prevent the exported remote objects from being garbage-collected, which will unexport them. You need to keep static references to both the Registry and your own remote object(s).
Here is the modified code to make it working. Thanks to EJP for the solution.
ServiceApp.java
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class ServiceApp {
public static RMIService rmiService;
public static Registry registry;
public static void main(String[] args) {
System.out.println("Starting RMI server");
{
try {
rmiService = new RMIService();
registry = LocateRegistry.createRegistry(1099);
registry.rebind("RMIServer", rmiService);
System.out.println("RMI server running");
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
RMIService.java
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class RMIService extends UnicastRemoteObject implements IRemoteServerService
{
private static final long serialVersionUID = 1L;
public RMIService() throws RemoteException {
super();
// Install a security manager.
System.setSecurityManager(new RMISecurityManager());
}
public String pingTest()
{
return "Server says hi";
}
#Override
public boolean resetService() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
}
IRemoteServerService
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IRemoteServerService extends Remote {
boolean resetService() throws RemoteException;
String pingTest() throws RemoteException;
}
Correct me if i'm wrong, but when you bind RMIService to the registry you don't need to block main as the rmiservice gets daemonized. So you just don't need to block the main thread.

Java Threads - Getting ServerSocket input to update Swing

I first asked this question, which I figured out how the EDT works and started reading more on swing and worker threads by reading this. I started to get an understanding of how they work and got my code fixed to where it would run. Now I'm trying to get the information from my worker thread (the server) to update my GUI. I run into a problem though I can't seem to work my way around. The problem is I need to keep listening for new client (As the server is suppose to handle multiple clients) but because that is in a while loop I never hit the return of my worker thread. I can't see any other way to set it up either. Could someone take a look at my code and suggest a way I might be able to get this to work?
Main.class
package com.sever.core;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Main {
private SocketManager network;
private Window window;
public static void main(String[] args){
Main main = new Main();
main.runGUI();
main.runServer();
}
private void runGUI(){
//Runs the swing components in the EDT.
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
window = new Window();
window.setVisible(true);
}
});
}
private void runServer(){
//Runs the Server process on a worker thread.
SwingWorker<String, String> server = new SwingWorker(){
#Override
protected Object doInBackground() throws Exception {
network = new SocketManager(25595);
/*
* Here is the problem. I need to keep running this code so,
* that I can let multiple clients connect. However,
* it then never reaches the return.
*/
while(true){
try {
network.setSocket(network.getServerSocket().accept());
addUser(network.getSocket());
} catch (Exception e) {
System.out.println("Failed to connect.");
}
}
return network.getMessage();
}
#Override
protected void done(){
try {
window.updateChat(get().toString());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
server.run();
}
private void addUser(Socket s){
try {
Scanner input = new Scanner(s.getInputStream());
network.addUser(input.nextLine());
} catch (Exception e) {
}
}
}
From Java Tutorials
Server
public class Server {
public static void main(String[] args) {
ServerSocket server = new ServerSocket(4444);
while(true) {
new ServerThread(server.accept()).start();
}
}
}
Server Thread
public class ServerThread implements Runnable {
private InputStream in;
private OutputStream out;
public ServerThread(Socket client) {
in = client.getInputStream();
out = client.getOutputStream();
}
public void run() {
// do your socket things
}
}

JFrame serialisation with LookAndFeel

I am trying to serialize a JFrame containing a JDesktopPane with several JInternalFrames.
I encountered a problem with the LookAndFeel because for any reason it is not possible to serialize a Swing component with a to the CrossPlatform LnF different one.
So I wrote this test program in order to figure out my possibilites:
public static void main(String[] args) {
try {
JFrame f = new JFrame();
f.setBounds(200,200,200,200);
JTree tree = new JTree();
f.add(tree);
f.setVisible(true);
UIManager.setLookAndFeel(
UIManager.getCrossPlatformLookAndFeelClassName());
SwingUtilities.updateComponentTreeUI(f);
ObjectOutputStream oop = new ObjectOutputStream(
new FileOutputStream(new File("test.serialized")));
oop.writeObject(f);
} catch(IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This didn't work for two reasons:
I am not able to serialize the frame and the contained tree. Just the tree is fine but just when
I set the LookAndFeel to cross platform in the first place and create my tree afterwards.
Any idea how to fix this?
EDIT:
Sorry for making this not clear:
I am NOT trying to serialize the LnF or something like that.
The LnF doesnt want me to serialize the Frame.
java.io.NotSerializableException: com.apple.laf.AquaTreeUI
And on top of that i am not able to serialize a Frame that contains a Tree.
Exception in thread "AWT-EventQueue-0" java.lang.InternalError: incorrect component
What you are trying is not possible. When you serialize the JFrame object, the LnF is not serialized in any way. That is because the JFrame keeps no memory of this. What LnF is used is stored elsewhere...
What I would do is wrap the JFrame in another object, let's say MyGUI. Inside that, I would store the LnF (as a String for example) in a private field. In the end, serialize MyGUI and, at deserialization, you have the LnF nice and intact and you can set it again.
Check this. Is the implementation proposed by #SoboLAN.

Categories