What does the future hold when we have billions of users with personal smart phones? Like the PCs automating the office, smart phones will transform our social life. The Stanford MobiSocial Computing Laboratory focuses on creating novel user experience, system architecture, infrastructure design, development frameworks, and security protocols for the programmable open mobile internet (POMI) by year 2020.



Junction Documentation for Application Developers

Last updated: Dec 09, 2016



About Junction

Junction is a platform for creating programs that work across multiple devices. For example, you can create a multiplayer game played on two or more phones or a remote control application between a phone and a web browser.

To see demonstrations of what you can build with Junction, see our list of demo applications (including source code).

Developers write one or more applications that work together to form a Junction activity. Each application contains an actor that takes on one or more roles in an activity. For example, a game of poker may be composed of a "player", "dealer," and "table" role intended to run on different devices.

An activity is run in an activity session. This session is represented by a URI that can be shared between participants. A junction URI looks like:

  junction://my.jxswitchboard.com/mySecretSession


Hello, Junction!

We now discuss how to write a basic application on Junction. You can download the full source code here.

One of the simplest applications for Junction is a simple chat program. We will write clients in both Javascript and Java, and the resulting programs will be able to talk to each other in an activity session.

Javascript

The core functionality a developer writes for an activity is contained in an "actor". Actors are objects that interact in an activity session. They take on one or more role in that session, and can respond to messages as well as send them. In our Javascript example, we write the actor using Javascript's object notation:

  var chat_client = {
    roles: ["client"],
    onMessageReceived: function(msg, header) {
      $('#messages').append(msg.text);
    }
  };

The actor has a single role ("client"). It also defines the method that gets triggered when a message is received. Here, we simply append the contents of the message to an HTML element with id 'messages' (note that we use JQuery to make accessing the DOM easier).

With the actor defined, it remains to attach the actor to an activity session. We will hard-code a session identifier "sampleChatSession" running on the switchboard at "prpl.stanford.edu":

  var jx_session = "junction://prpl.stanford.edu/sampleChatSession";

Finally, we use the JunctionMaker object to bind the activity to the specified session:

  var jm = JunctionMaker.getInstance();
  jm.newJunction(jx_session,chat_client);

This is enough to have a client display inbound messages. We extend our code into a full chat application by allowing messages to be sent. Again, we use JQuery to access the DOM, and we send a message when a button is pressed:

  $('#send_button').click(
    function(){ 
      chat_client.sendMessageToSession(
            {text:$('#compose').value()}
      ) 
    }
  );

Java

We now write a compatible client in Java, and connect it to the same session. The code is similar in structure, but with obvious modifications to fit into the Java language. Now, JunctionActor is an abstract class, and we override the appropriate methods:

public class ChatClient extends JunctionActor {

  @Override 
  ChatClient() {
    super("client");
  }

  @Override
  public void onMessageReceived(MessageHeader header, JSONObject msg) {
    System.out.println(msg.getString("text"));
  }

Finally, we add a main method to this class so it can actually be run. This main method binds the actor to the same activity session as in our Javascript demo:

  public static void main(String[] args) {
    SwitchboardConfig config = new XMPPSwitchboardConfig("prpl.stanford.edu");
    ChatClient client = new ChatClient();
    URI jxSession = new URI("junction://prpl.stanford.edu/sampleChatSession");

    Junction jx = JunctionMaker.getInstance(config).newJunction(jxSession,client);
  }
}


Supporting Multiple Sessions

The above example works by hard-coding an activity session in each program. This may work for activities that run with a global session. In general, activity sessions run in isolation from other activity sessions (likely, not all users will want to chat in the same chatroom). Junction integrates this functionality directly into the platform.

A Junction session is hosted on a switchboard. The switchboard is a generic piece of infrastructure to help run multi-party applications. Any switchboard can be used to run any given activity, and any activity can be run on any available switchboard.

We modify the above applications in two ways. First, rather than hard-coding a URI with session information in it, we specify an activity script that contains some details about the activity. This script is represented in the JSON format:

var activity_script = { 
    ad: "edu.stanford.junction.chat",
   friendlyName: "Junction Chat"
};

Now, the Junction platform will create an activity session when a user instantiates the activity. However, we need to know the location of a switchboard on which the activity session can be run. We do so by passing the switchboard's configuration details to the JunctionMaker object: var jm = JunctionMaker.getInstance('prpl.stanford.edu'); With these changes, each program will join its own unique session. This would make a chat application pretty lonely! We combine our first approach (of hard-coding a session ID) and our second approach (of always generating a unique session) by allowing the session's URI to be retrieved at runtime. We now have a "session initiator" and a "session joiner". We retrieve the URI in Javascript as:

var jx = jm.newJunction(activity_script, client);
var session_uri = jx.getInvitationURI();

Sharing activity sessions is a common need of all Junction activities, and Junction supports several ways of doing so directly in the platform. We discuss these in a later section.


Cross-Platform Activities

Junction activities are made up of roles, and Junction allows a developer to write code for a role for multiple platforms. For example, a "player" in a game of poker may be available for Android and the iPhone natively, and additionally there may be a web version as well.

Junction handles these details in the activity script. This script specifies the details about where the code can be found for a given platform. In our poker example, we have:

var activity_script = {
    ad: "edu.stanford.junction.poker",
    friendlyName: "weHold'Em",
    roles: {
        player: {
            platforms: {
                android: { ... },
                web: { ... }
            }
        }
    }
}

The Junction platform has an additional component to make use of this information: the Activity Director. The director allows a user to join any activity, even if they have not joined that activity before. Like a web browser, the director finds and loads the appropriate code for the platform given a URI, and unlike the browser, this code can be written in different languages, supporting different platforms.


Sharing Activity Sessions

An activity session can be shared by passing along a Junction URI. Thus, an activity session can be shared in any way that text can be shared. The sharing experience is important for the usability of Junction activities, and so Junction integrates several sharing techniques directly into the platform. We call these shared URIs invitations.

Outbound invitations can be integrated into your Junction activity in two ways. First, you may add sharing functionality directly into your program. On a phone, for example, you may have a button to share the activity via SMS. Second, you may allow the user to choose from a variety of ways to share the activity. This is done by delegating the sharing task to the activity director, which exposes a number of sharing methods to the user.

Similarly, inbound invitations can be handled directly in your application, perhaps by allowing the user to enter a URI directly. Or, the director application may be used to bootstrap the application. A Junction URI that is handled by the director will indicate which code to launch to join the activity.

The methods for sharing activity sessions are platform-dependent. For example, a Junction URI can be shared using a two-dimensional barcode called a QR code. This barcode can be generated on any device with a screen, however reading the code requires a camera. Thus, phones can read QR codes, but web browsers cannot.


Junction API

Browse the Junction Javadocs:

On an object-oriented platform, the Junction API consists of the following objects and methods:

JunctionMaker
    newJunction

Actor
    sendMessageToSession
    sendMessageToRole
    sendMessageToActor
    onMessageReceived
    onActivityJoin
    onActivityCreate
    getJunction
    getActorID
    leave

Junction
    getInvitationURI

Messaging

Messages in Junction are transmitted as JSON objects. JSON is well-supported on most object oriented platforms, making it ideal for marshalling objects between devices. JSON supports several commonly used primitives, including strings, numbers, arrays, and maps. A JSON object itself is simply a map from string-based keys to other JSON primitives.

Debugging Junction Activities

Junction uses a standard XMPP chatroom as its switchboard implementation. This makes debugging Junction activities relatively easy. You can use a standard XMPP client (such as Pidgin) to connect to your activity to watch the messages each actor sends.


Getting Junction

For Developers

There are several ways to start working with Junction. For getting started on the Java and Android platforms, we recommend using Maven to manage dependencies and versioning.

Source

Junction is an open source project, and uses SVN for revision control. You may browse the repository on the web here. To checkout all Junction-related code, including libraries and demo applications, you can use the following command:

svn co http://prpl.stanford.edu/svn/prpl/junction junction

Binaries

You can download version 0.7.0 of the JavaJunction library including all dependencies here.

You can get version 0.7.0 of the Android libary (which includes the Java library as a dependency) here.

Maven

For the Java and Android platforms, Junction makes use of the Maven build system. Maven helps manage dependencies across Java applications, and helps manage versioned binaries for your projects. Sonatype has a free and comprehensive online book for working with maven.

You can include Junction in your own Maven project by adding the following to your project's pom.xml file:

<dependencies>
   ... 
    <dependency>
      <groupId>edu.stanford.prpl.junction</groupId>
      <artifactId>JAVAJunction</artifactId>
      <version>0.7.0</version>
    </dependency>
  </dependencies>

  <repositories>
    ...
    <repository>
      <id>prpl-public</id>
      <name>PrPl Public Files</name>
      <url>http://prpl.stanford.edu:8081/nexus/content/groups/public</url>
    </repository>
  </repositories>

POM Builder

We have also created a basic POM Builder to help generate a pom.xml file for use with Junction. It will create a basic POM file for your project, including Junction as a dependency.

For Users

Boxee

We have created a Boxee plugin, which can be downloaded here. Unzip the contents into your apps director for your Boxee installation.

Working with Junction

Switchboard

While developing activities, you can make use of our switchboard, which supports anonymous connections and is available at prpl.stanford.edu. For production applications, you may run your own switchboard, which is simply an XMPP server supporting the Multi-User Chat extension.

Web

You can check out the latest version of the Junction Javascript library as:

svn co http://prpl.stanford.edu/svn/prpl/junction/lib/JSJunction
There are several scripts you must include in your web page to get Junction working. Future releases will consolidate many of these files, but for now you can use the following as a guide. Note that this will reference against our internally-used libraries, and you should modify the references for a production system.

<html>
<!-- A quickstart example for using JSJunction: -->
  <head>
    <script type="text/javascript" 
               src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>    

    <script language='javascript' type='text/javascript' 
               src='http://openjunction.github.com/JSJunction/json2.js'></script>
<script language='javascript' type='text/javascript' 
           src='http://openjunction.github.com/JSJunction/strophejs/1.0.1/strophe.js'></script>
<script language='javascript' type='text/javascript' 
           src='http://openjunction.github.com/JSJunction/junction/0.6.8/junction.js'></script>
    
<script type="text/javascript">

var activity = {ad:"my.test.app"};
var actor = {
  onMessageReceived: function(msg) { alert("got a message: " + msg.text); }
  , onActivityJoin: function() { alert("joined!"); this.sendMessageToSession({text: "first post!"}); }
};
JX.getInstance("sb.openjunction.org").newJunction(activity,actor);

</script>    
</head>
<body>
</body>
</html>

Dealing with Cross-Domain Restrictions

Typically, Junction webapps are not run on the same host as the switchboard they use. If this is the case, you must use some technique to get around cross-site scripting restrictions. To this end, we have bundled the Flash workaround flXHR. Unfortunately, this hurts both performance and compatibility, and so should only be used when required.

A restriction of using flXHR is that flash objects by default cannot be loaded when a file is accessed locally (via file://...). You may allow explicitly allow objects to be loaded, and this allowance is platform-specific.

Instead, you can make use of an XMPP server that supports CORS. You can download our modified implementation of OpenFire.

Java

The most familiar way to get up and running with Junction may be to download the .jar file and include it in your project. However, we recommend using Maven to configure your project. With maven, if Junction undergoes a version change, you can use the latest code with a simple edit of the pom.xml file. You can also depend on an earlier version of Junction as you wish, or stay on the bleeding edge by depending on our latest snapshot. More information can be found in the Getting Junction guide.

If you are using Maven with our POM Builder, you can easily build an executable .jar file with all dependencies included. First, edit the pom.xml to point to your main class, and then issue:

mvn assembly:assembly
java -jar target/your-project-version-with-dependencies.jar

Android

As with Java, you can work with a .jar file, or you can rely on Maven to manage dependencies, which we recommend. The recommended order for creating a new Android project using Junction is:

  1. Start a new Android project
  2. Add your pom.xml file
  3. Add your project to a code repository as desired
You may use the POM Builder to help generate your pom.xml file.

To build and install your project from the command line using Maven, use something similar to:

  mvn install # builds the project
  adb install -r target/my-project.apk # install to android device or emulator

Learning Android

Note that Android is a complete platform in itself, and should be learned before attempting to run Junction in the Android environment. See the official Android site for more details.

Specifically, you will need to at least understand the following:

  • Activities and the activity lifecycle
  • Intents
  • Logging in Android via android.util.Log and Logcat
  • Permissions (Junction requires permission to use the internet in your AndroidManifest.xml)

Integrating with Intents

Your application may make use of other Android Activities to instantiate a Junction session. For example, if you are integrating with the Activity Director, an Intent is used to hook into your code.

To make this work, you will need an Intent Filter in your AndroidManifest.xml to handle the Intent:

<manifest ...>
  <application ...>
    ...
    <activity android:name=".YourActivity">
      <intent-filter>
        <action android:name="junction.intent.action.JOIN" />
        <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>
Then, in code:
public class YourActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    // is the intent used to create this activity a Junction invitation?
    if (AndroidJunctionMaker.isJoinable(this)) {
      XMPPSwitchboardConfig config = new XMPPSwitchboardConfig("prpl.stanford.edu");
      AndroidJunctionMaker maker = AndroidJunctionMaker.getInstance(config);
      // Join the intent's activity session:
      maker.newJunction(this, myJunctionActor);
    }
  }
}

Handling Messages

In Android, computationally expensive tasks must be handled off of the main. Furthermore, threads that are not the GUI thread may not alter GUI state directly. Since Junction messages are received asynchronously in a thread that is not the GUI thread, you may need to use a Handler to send GUI-related commands from the thread that listens for messages to the GUI thread.

Using Eclipse

The toolchain used in developing and working with Junction for Android and Java integrates well with the Eclipse IDE. For best results, you may wish to install the subclipse and m2eclipse plugins.

M2eclipse will automatically manage the dependencies between your pom.xml file and your eclipse project. If you add a pom.xml file to an existing project, you can right click that project and choose "Maven => Enable Dependency Management" to automatically download your required files.

An important note: The m2eclipse plugin requries that your Eclipse be launched using a VM from a JDK, and not a JRE. This is the VM used to launch eclipse, not just the compiler used to build your projects. To set this, edit your eclipse.ini, and add something like the following: (the linebreak is requried)

-vm
C:\Program Files\Java\jdk1.6.0_19\bin\javaw
More details on this issue can be found here.

There is an additional plugin for working with maven, eclipse, and android: m2eclipse-android-integration. Otherwise, you may find it easier to build the project from the command line. If you are using a Windows machine, we recommend installing Cygwin for an improved shell experience (and puttycyg for an even better one!)

  cd my/project/dir
  mvn install

Tips and Tricks

Click here for some tips and tricks for using Junction.


Sample Applications

  There are several applications you can check out to help you understand and use Junction. First, we have two versions of a simple "Hello World" application:

Our more involved applications can be found here.