53

I'm looking to develop two separate (but related) Java desktop applications.

I want the ability for one application to trigger the other, passing in data that can then be edited and passed back, i.e. the communication will be two way. If the other application is already running I want them to just communicate, i.e. I dont want to just pass arguments over the command line, etc.

Generally speaking, what strategies/techniques should I be looking at in order to achieve this?

yms
  • 10,361
  • 3
  • 38
  • 68
William
  • 13,332
  • 13
  • 60
  • 73

12 Answers12

23

To show how easy it is to let two applications communicate with each other, check out this network-clipboard demo using JGroups. Just start two instances and begin dropping files into one of them. The second instance will instantly show the same files.

import java.io.Serializable;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import org.jgroups.*;

public class JGroupsTest {

    public static void main(String[] args) throws Exception {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setSize(500, 300);
        final DefaultListModel listModel = new DefaultListModel();
        final JList panel = new JList(listModel);
        panel.setBackground(new Color(128, 0, 40));
        panel.setForeground(new Color(240, 240, 240));
        frame.add(panel);
        System.setProperty("java.net.preferIPv4Stack", "true");
        final JChannel channel = new JChannel("udp.xml");
        channel.connect("networkclipboard");
        channel.setReceiver(new ReceiverAdapter() {
            @Override
            public void viewAccepted(View newView) {
                frame.setTitle("Network Clipboard - " + channel.getLocalAddress());
            }

            @Override
            public void receive(Message msg) {
                listModel.addElement(msg.getObject());
            }
        });

        panel.setTransferHandler(new TransferHandler() {
            @Override
            public boolean importData(JComponent comp, Transferable t) {
                DataFlavor[] transferDataFlavors = t.getTransferDataFlavors();
                for (DataFlavor flavor : transferDataFlavors) {
                    try {
                        Object data = t.getTransferData(flavor);
                        if (data instanceof Serializable) {
                            Serializable serializable = (Serializable) data;
                            Message msg = new Message();
                            msg.setObject(serializable);
                            channel.send(msg);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return super.importData(comp, t);
            }

            @Override
            public boolean canImport(TransferSupport support) {
                return true;
            }

            @Override
            public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
                return true;
            }

        });
    }

}
mhaller
  • 14,122
  • 1
  • 42
  • 61
  • Hi @mhaller I wanted to know is there any specific reason why you have used `throws` in `main` method as `main` method is a specific method we surround it with `try catch`. Please elaborate. – Vishrant Feb 28 '14 at 09:26
  • @Vishrant - i was just being lazy. it is allowed to use `throws` for the main method, doesn't make a difference. i also often declare `throws Exception` for unit tests, so I do not have to handle all checked exceptions individually. – mhaller Mar 06 '14 at 15:07
  • thanks for replying, I mainly use `throws` keyword when there is some container like in `struts` but while I writing `main` method in my application (which is a specific method not common method) I use `try catch` block to handle `Exception` in my own way. Yes using `throws` in `main` method makes a difference if any `Exception` occurs in `main` method it will be thrown to `JVM` and your program will stop, also `JVM` handles thrown `Exception` in its own way. `throws` is a concept of `re-throwing Exception` which is used in `Common Methods` (methods which are used by many classes). – Vishrant Mar 06 '14 at 15:40
22

It depends how would you like to communicate those 2 programs:

  • If you need only inter-process semaphores, create a file somewhere in /tmp and lock it.

  • If you need only inter-process synchronous messaging (remote procedure call), RMI should be easiest.

  • If you need asynchronous interprocess messaging, JMS should be easiest.

  • If you need inter-process shared memory, use mapped files.

  • If you need all the above, Terracotta (http://www.terracotta.org/ ) is the easiest way: Java programs on different JVMs on the same or even different computers see each other as if they were executed inside one JVM on one machine. Splitting one program into a few doesn't even require any code changes - it's enough to write an XML config file.

iirekm
  • 8,890
  • 5
  • 36
  • 46
19

They could each listen on a Socket. This tutorial is good to get started.

Simon
  • 4,103
  • 7
  • 28
  • 53
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Is this the usual way to do it or RMI ? Or rather, what's the difference? – Pacerier Feb 12 '12 at 05:54
  • @Pacerier - Sockets are a way to stream bytes off to a network stack. RMI allows for calling methods of objects that exist in a different JVM, the data exchange is opaque to RMI though still can use sockets underneath. – Jé Queue Feb 15 '12 at 23:42
  • Ic, so sockets are the best then since its simple and fast – Pacerier Feb 16 '12 at 10:09
10

You should also consider good ol' classic RMI.

Jé Queue
  • 10,359
  • 13
  • 53
  • 61
  • Is this usually the approach when I want to have two different processes? – Pacerier Feb 12 '12 at 02:12
  • It is the elementary way of either passing Java objects back and forth between JVMs (often as different processes). You can also share object references to act on remote objects in the other JVM. Of course the whole EJB thing and frameworks failingly try to abstract away RMI, but it is a true approach to shared multi-JVM shared objects. To be fair, it is a way to invoke remote methods, but most methods return or are passed objects anyway. – Jé Queue Feb 15 '12 at 23:41
6

Have a look at JavaGroups, it will solve your communication problem and also help you to detect if the other app is running. If the app isn't running you will have to launch a new JVM for it with java.lang.Runtime.exec()...

pgras
  • 12,614
  • 4
  • 38
  • 46
  • 1
    +1 for JGroups, i love it. FYI you know that this page is 10 years old and that same code has been adopted by JBoss for years now? See jgroups.org – mhaller Nov 05 '09 at 15:06
4

Try to communicate with SocketCommunication, even if the application are in the same machine.

Here can find more info about how to do it (Sun/Java documentation).

osanchezmon
  • 544
  • 1
  • 4
  • 18
4
  • The "Enterprise" way to go would be to run these apps in a Java EE server or at least in a Spring framework. It's also probably vastly overkill.

  • If a bunch of data needs to be communicated, then RMI will do it.

  • If you're not afraid to hack your own protocol, data structure and error handling, you can set up server and client sockets and communicate through those.

  • I think there's a certain crude appeal to the alternative of communicating via a file in a common directory (setting up your own protocol of who writes or erases the file when), or via a shared database. Low-tech, not extremely fast, but very simple and reliable. And it's fairly easy to monitor "communication" from the outside.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
2

To keep things simple why not just use plain TCP sockets?

Mark
  • 28,783
  • 8
  • 63
  • 92
  • Plain TCP sockets don't define a protocol, serialize objects or offer any error recovery, among other things. You have to take care of everything yourself. Not that RMI is much better, of course! – Carl Smotricz Nov 05 '09 at 14:31
  • But if the data is simple it's not a big deal to handle this and you don't have to bother extra configuration of things like RMI registrys. – Mark Nov 05 '09 at 14:58
  • @Mark what other low level alternatives are there? Or is tcp/ip the only way to transfer data between two programs in the **same** machine? – Pacerier Feb 12 '12 at 13:11
  • @Pacerier - Same machine opens loads of options like shared memory, local message queues, files, domain sockets. &c &c. Putting a protocol atop a network stack (e.g. TCP or UDP) lets you expand the reach off the OS instance, easily. – Jé Queue Feb 15 '12 at 23:46
1

I second Socket communication and RMI. RMI is a little more involved but is more intuitive to a programmer. It depends on what type of information you are sending though. Pushing raw bytes over to another machine might make more sense then running the RMI server and dealing with all that jazz...

0x808080
  • 158
  • 1
  • 7
1

It depends what kind of communication you want to do between the 2 apps. If you use sockets or RMI for example, both applications need to be up in order for the communication to happen. If the kind of communication you want to do can be more asynchronous then you can use more of a messaging based approach.

For example, ZooKeeper allows you to implement pretty much anything you want on top of very simple yet powerful primitives. This page (http://hadoop.apache.org/zookeeper/docs/current/recipes.html) explains how to build higher level constructs with ZooKeeper.

The drawback is that you need another system. If you use JGroups for example then you don't.

Hope this helps

0

Depending on what style of communication you're looking for (high latency, lots of data, etc.) and whether or not this system may expand past simply 2 java systems, a possibility could be a messaging system using a middleware solution such as Tibco SmartSockets.

Any more info on your setup and expectations would help.

tinkertime
  • 2,972
  • 4
  • 30
  • 45
0

The easiest is to use RMI without standalone rmiregistry.

Server creates a local registry:

ServerImpl extends UnicastRemoteObject implements Server

rmiRegistry = LocateRegistry.createRegistry(2020);
rmiRegistry.bind("server", aServerImpl);

Client looks it up with an rmi url (similar to corbaloc:)

String url = "rmi://localhost:2020/server";
Server server = (Server) Naming.lookup(url);

I got 1000 calls in under 500 ms in a loop over the same open connection. Yes, that is milliseconds.

Idea and sample from here: https://www.censhare.com/us/resources/blog/article/file-streaming-using-java-rmi

weberjn
  • 1,840
  • 20
  • 24