Java tutorial
/* * Copyright (C) 2010 Stanford University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.stanford.junction.director; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.reflect.Method; import java.net.URI; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONObject; import edu.stanford.junction.Junction; import edu.stanford.junction.JunctionMaker; import edu.stanford.junction.JunctionException; import edu.stanford.junction.SwitchboardConfig; import edu.stanford.junction.api.activity.ActivityScript; import edu.stanford.junction.api.activity.JunctionActor; import edu.stanford.junction.api.activity.JunctionService; import edu.stanford.junction.api.messaging.MessageHeader; import edu.stanford.junction.provider.xmpp.XMPPSwitchboardConfig; /** * This is a Director written for the JAVA platform. * It is capable of launching .JAR actors, as well as web-based actors. * The director activity also allows a user to see what's running on this machine. * * TODO: * support properties for the director: directorSessionID, platformHints, security/access control * * @author Ben * */ public class JAVADirector extends JunctionActor { public static final String DIRECTOR_SESSION = "jxservice"; // null will auto-generate private static final SwitchboardConfig mSbConfig = new XMPPSwitchboardConfig("prpl.stanford.edu"); private static final JunctionMaker mMaker = JunctionMaker.getInstance(mSbConfig); private List<Activity> mActivities; public JAVADirector() { super("director"); mActivities = new ArrayList<Activity>(); } @Override public void onMessageReceived(MessageHeader header, JSONObject message) { try { if (message.has("action")) { String action = message.getString("action"); if ("list".equals(action)) { JSONArray procs = new JSONArray(); for (int i = mActivities.size() - 1; i >= 0; i--) { Activity activity = mActivities.get(i); try { activity.process.exitValue(); // If we get this far, the process is terminated. System.out.println("exit value " + activity.process.exitValue()); mActivities.remove(i); } catch (Exception e) { // No exit value means its still running. JSONObject obj = new JSONObject(); obj.put("activity", activity.uri.toString()); procs.put(obj); } } JSONObject msg = new JSONObject(); msg.put("activities", procs); header.getReplyTarget().sendMessage(msg); } else if ("info".equals(action)) { // return Junction version, platform(s), and "hints" (headless, bigscreen, etc) // also a nickname. // maybe other known directors? owner info? // HINTS: // headless ~ server // bigscreen ~ TV or monitor attached // mobile ~ phone // nouser ~ no direct user input (bigscreen / headless) // keyboard? mouse? } else if ("cast".equals(action)) { String activityString = message.getString("activity"); URI activityURI = new URI(activityString); // TODO: clean this up. ActivityScript script = mMaker.getActivityScript(activityURI); int p = activityString.indexOf("role="); if (p < 0) { System.out.println("Invitation does not specify a role."); return; } String role = activityString.substring(p + 5); if (role.contains("&")) { int q = role.indexOf("&"); role = role.substring(0, q); } JSONObject spec = script.getRoleSpec(role); JSONObject platforms = spec.getJSONObject("platforms"); if (platforms.has("java")) { JSONObject javaplat = platforms.getJSONObject("java"); if (javaplat.has("jar")) { URL jarURL = new URL(javaplat.getString("jar")); Process proc = launchJAR(jarURL, activityURI); if (proc != null) { mActivities.add(new Activity(activityURI, proc)); InputStream is = proc.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; while ((line = br.readLine()) != null) { System.out.println(line); } } } else { System.out.println("Warning: JAVA platform specified but no JAR found."); } } else if (platforms.has("web")) { // TODO: make sure this director isn't 'headless' // (add these properties) JSONObject webplat = platforms.getJSONObject("web"); String webURL = webplat.getString("url"); if (webURL.contains("?")) { webURL = webURL + "&"; } else { webURL = webURL + "?"; } webURL += "jxinvite=" + URLEncoder.encode(activityString, "UTF-8"); Process proc = BrowserControl.openUrl(webURL); if (proc != null) { mActivities.add(new Activity(activityURI, proc)); } } else if (message.has("serviceName")) { String className = message.getString("serviceName"); launchService(activityURI, script, className); } else { System.out.println("No action taken for " + message); } } } } catch (Exception e) { e.printStackTrace(); } } private Process launchJAR(URL jarURL, URI activityURI) { final String JAR_PATH = "jars/"; String jarName = JAR_PATH + "/" + jarURL.getPath().substring(1).replace("/", "-"); File jarFile = new File(jarName); File tmpFile = new File(jarName + ".tmp"); if (!jarFile.exists() && !tmpFile.exists()) { try { FileOutputStream out = new FileOutputStream(tmpFile); InputStream in = jarURL.openStream(); byte[] buf = new byte[4 * 1024]; int bytesRead; while ((bytesRead = in.read(buf)) != -1) { out.write(buf, 0, bytesRead); } in.close(); out.close(); boolean res = tmpFile.renameTo(jarFile); if (!res) { throw new Exception("Could not rename file."); } } catch (Exception e) { e.printStackTrace(); return null; } } if (!jarFile.exists()) { System.out.println("Failed to get JAR file " + jarFile.getName()); return null; } // Launch the new JVM try { List<String> command = new ArrayList<String>(); command.add("java"); command.add("-jar"); command.add(jarFile.getAbsolutePath()); command.add(activityURI.toString()); System.out.println("Executing: " + command.toString()); ProcessBuilder pb = new ProcessBuilder(command); pb.directory(jarFile.getParentFile()); pb.redirectErrorStream(true); Process p = pb.start(); // TODO: make sure it worked return p; } catch (Exception e) { System.out.println("failed to launch JAR."); e.printStackTrace(); } return null; } private void launchService(URI activityURI, ActivityScript script, String className) { Class c = null; try { c = Class.forName(className); } catch (Exception e) { System.out.println("Could not find class for service " + className + "."); } JunctionService service = null; Method method = null; try { method = c.getMethod("newInstance"); service = (JunctionService) method.invoke(null); } catch (Exception e) { System.out.println("No newInstance method found for " + c + "."); } String queryPart = activityURI.getQuery(); System.out.println("query part is " + queryPart); String localRole = "Unknown"; int i; if ((i = queryPart.indexOf("role=")) >= 0) { localRole = queryPart.substring(i + 14); if ((i = localRole.indexOf("&")) > 0) { localRole = localRole.substring(0, i); } } System.out.println("Setting service role to " + localRole); service.setRole(localRole); System.out.println("service actorID is " + service.getActorID()); try { mMaker.newJunction(activityURI, script, service); } catch (JunctionException e) { e.printStackTrace(); } } public static void main(String[] argv) { ActivityScript script = new ActivityScript(); script.setActivityID(JunctionMaker.DIRECTOR_ACTIVITY); //script.addRolePlatform("director", "java", null); //script.addRolePlatform("director","web", null); // script.setFriendlyName("Activity Director"); // TODO: These should be in a "carrier" field // ( carrier; implementation; provider; ... ) script.setSessionID(DIRECTOR_SESSION); JunctionActor director = new JAVADirector(); try { Junction jx = mMaker.newJunction(URI.create("junction://prpl.stanford.edu/jxservice"), director); System.out.println("Launched director on " + jx.getInvitationURI()); synchronized (director) { try { director.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (JunctionException e) { e.printStackTrace(System.err); } } } class Activity { public URI uri; public Process process; public Activity(URI uri, Process process) { this.uri = uri; this.process = process; } } /** * * http://javaxden.blogspot.com/2007/09/launch-web-browser-through-java.html * */ class BrowserControl { /** * Method to Open the Browser with Given URL * @param url */ public static Process openUrl(String url) { String os = System.getProperty("os.name"); Runtime runtime = Runtime.getRuntime(); try { // Block for Windows Platform if (os.startsWith("Windows")) { String cmd = "rundll32 url.dll,FileProtocolHandler " + url; Process p = runtime.exec(cmd); return p; } //Block for Mac OS else if (os.startsWith("Mac OS")) { Class fileMgr = Class.forName("com.apple.eio.FileManager"); Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class }); openURL.invoke(null, new Object[] { url }); return null; // TODO find a better way } //Block for UNIX Platform else { String[] browsers = { "firefox", "chrome", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; String browser = null; for (int count = 0; count < browsers.length && browser == null; count++) if (runtime.exec(new String[] { "which", browsers[count] }).waitFor() == 0) browser = browsers[count]; if (browser == null) throw new Exception("Could not find web browser"); else return runtime.exec(new String[] { browser, url }); } } catch (Exception x) { System.err.println("Exception occurd while invoking Browser!"); x.printStackTrace(); return null; } } }