Browse files

Initial import of Java library, Hello World\!

  • Loading branch information...
1 parent 1be98ce commit 12c0fbba88a46a83f8a23efe7200f2dea9ddca75 Jim Cortez committed May 23, 2012
Showing with 10,054 additions and 0 deletions.
  1. +32 −0 LICENSE
  2. +57 −0 README.txt
  3. +20 −0 build.properties
  4. +216 −0 examples/AppChatExample/AppChatExample.java
  5. +7 −0 examples/AppChatExample/README
  6. +7 −0 examples/SimpleNavigationExample/README
  7. +191 −0 examples/SimpleNavigationExample/SimpleExample.java
  8. +7 −0 examples/VideoListExample/README
  9. +242 −0 examples/VideoListExample/VideoListExample.java
  10. +96 −0 pom.xml
  11. +264 −0 src/com/yahoo/connectedtv/ycommand/AbstractCommand.java
  12. +68 −0 src/com/yahoo/connectedtv/ycommand/AbstractInputCommand.java
  13. +170 −0 src/com/yahoo/connectedtv/ycommand/AbstractMethodCommand.java
  14. +68 −0 src/com/yahoo/connectedtv/ycommand/AbstractServiceCommand.java
  15. +68 −0 src/com/yahoo/connectedtv/ycommand/AbstractSessionCommand.java
  16. +186 −0 src/com/yahoo/connectedtv/ycommand/AuthSessionCommand.java
  17. +2,202 −0 src/com/yahoo/connectedtv/ycommand/Base64.java
  18. +62 −0 src/com/yahoo/connectedtv/ycommand/CommandParseException.java
  19. +96 −0 src/com/yahoo/connectedtv/ycommand/CommandParser.java
  20. +259 −0 src/com/yahoo/connectedtv/ycommand/CommandRouter.java
  21. +276 −0 src/com/yahoo/connectedtv/ycommand/CommandSchema.java
  22. +562 −0 src/com/yahoo/connectedtv/ycommand/Connection.java
  23. +209 −0 src/com/yahoo/connectedtv/ycommand/CreateSessionCommand.java
  24. +82 −0 src/com/yahoo/connectedtv/ycommand/EasyX509TrustManager.java
  25. +132 −0 src/com/yahoo/connectedtv/ycommand/ErrorCommand.java
  26. +99 −0 src/com/yahoo/connectedtv/ycommand/GrantedSessionCommand.java
  27. +56 −0 src/com/yahoo/connectedtv/ycommand/ICommandSubscriber.java
  28. +66 −0 src/com/yahoo/connectedtv/ycommand/IConnectionHandler.java
  29. +168 −0 src/com/yahoo/connectedtv/ycommand/IPCodeResolver.java
  30. +473 −0 src/com/yahoo/connectedtv/ycommand/KeyboardInputCommand.java
  31. +336 −0 src/com/yahoo/connectedtv/ycommand/MediaControlInputCommand.java
  32. +204 −0 src/com/yahoo/connectedtv/ycommand/MediaLaunchServiceCommand.java
  33. +228 −0 src/com/yahoo/connectedtv/ycommand/NavigationInputCommand.java
  34. +89 −0 src/com/yahoo/connectedtv/ycommand/ResetSessionCommand.java
  35. +118 −0 src/com/yahoo/connectedtv/ycommand/StatusSessionCommand.java
  36. +90 −0 src/com/yahoo/connectedtv/ycommand/SubscribedCommand.java
  37. +85 −0 src/com/yahoo/connectedtv/ycommand/UnsubscribedCommand.java
  38. +123 −0 src/com/yahoo/connectedtv/ycommand/Utilities.java
  39. +285 −0 src/com/yahoo/connectedtv/ycommand/VideolLaunchMethodCommand.java
  40. +167 −0 src/com/yahoo/connectedtv/ycommand/WidgetCommand.java
  41. +151 −0 src/com/yahoo/connectedtv/ycommand/WidgetLaunchMethodCommand.java
  42. +181 −0 src/com/yahoo/connectedtv/ycommand/WidgetListServiceCommand.java
  43. +104 −0 src/com/yahoo/connectedtv/ycommand/WidgetMethodCommand.java
  44. +14 −0 src/com/yahoo/connectedtv/ycommand/package.html
  45. +99 −0 tests/com/yahoo/connectedtv/ycommand/AuthSessionCommandTest.java
  46. +94 −0 tests/com/yahoo/connectedtv/ycommand/CommandParserTest.java
  47. +93 −0 tests/com/yahoo/connectedtv/ycommand/CommandSchemaTest.java
  48. +73 −0 tests/com/yahoo/connectedtv/ycommand/CreateSessionCommandTest.java
  49. +59 −0 tests/com/yahoo/connectedtv/ycommand/ErrorCommandTest.java
  50. +108 −0 tests/com/yahoo/connectedtv/ycommand/IPCodeResolverTest.java
  51. +133 −0 tests/com/yahoo/connectedtv/ycommand/KeyboardInputCommandTest.java
  52. +104 −0 tests/com/yahoo/connectedtv/ycommand/MediaControlInputCommandTest.java
  53. +66 −0 tests/com/yahoo/connectedtv/ycommand/MediaLaunchServiceCommandTest.java
  54. +91 −0 tests/com/yahoo/connectedtv/ycommand/NavigationInputCommandTest.java
  55. +79 −0 tests/com/yahoo/connectedtv/ycommand/SubscribedCommandTest.java
  56. +80 −0 tests/com/yahoo/connectedtv/ycommand/UnsubscribedCommandTest.java
  57. +110 −0 tests/com/yahoo/connectedtv/ycommand/VideolLaunchMethodCommandTest.java
  58. +67 −0 tests/com/yahoo/connectedtv/ycommand/WidgetCommandTest.java
  59. +119 −0 tests/com/yahoo/connectedtv/ycommand/WidgetLaunchMethodCommandTest.java
  60. +63 −0 tests/com/yahoo/connectedtv/ycommand/WidgetListCommandTest.java
View
32 LICENSE
@@ -0,0 +1,32 @@
+Copyright (c) 2011, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior
+ written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
57 README.txt
@@ -0,0 +1,57 @@
+OVERVIEW
+********
+The Yahoo! Connected TV Device Communication Java Library uses several 3rd party open source libraries and tools. This file summarizes the tools used, their purpose, and the licenses under which they are released. This file also explains how to build the jar file and generate Javadoc documentation.
+
+BUILD
+*****
+To create a jar for this library use Maven (http://maven.apache.org/). Use the command:
+
+ mvn package
+
+This will download all dependencies and create the jar file "target/device-control-<version>.jar".
+
+DOCUMENTATION
+*************
+If you wish to create documentation from the source use this command:
+
+ mvn "javadoc:javadoc"
+
+Generated documentation will be created in the doc/ folder. Open the doc/index.html file in your web browser.
+
+LIBRARIES
+*********
+Except as specifically stated below, the 3rd party software packages are not distributed as part of this project, but instead are separately downloaded from their respective provider and built on the developer's machine prior to building the library.
+
+* JmDNS version 3.4.0 (Apache 2.0 license)
+(A mDNS client library)
+http://jmdns.sourceforge.net/
+
+* org.json version 20090211
+(Java JSON Library)
+http://json.org/java/
+
+For unit tests:
+* Junit version 4.8.2
+(Java testing library)
+http://junit.sourceforge.net/
+
+* Hamcrest version 1.3.RC2
+(Java unit test helper library)
+http://code.google.com/p/hamcrest/
+
+LICENSE
+*******
+The Yahoo! Connected TV Device Communication Java Library is licensed under the following BSD License.
+
+Software License Agreement (BSD License)
+Copyright c 2011 Yahoo! Inc. All rights reserved.
+
+Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of Yahoo! Connected TV's contributors may be used to endorse or promote products derived from this software without specific prior written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
20 build.properties
@@ -0,0 +1,20 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+# 'source.dir' for the location of your java source folder and
+# 'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+# 'key.store' for the location of your keystore and
+# 'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+# The name of your application package as defined in the manifest.
+# Used by the 'uninstall' rule.
+application.package=com.yahoo.connectedtv.ycommand
View
216 examples/AppChatExample/AppChatExample.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+/***
+ * This example demonstrates how to communicate with a specific TV app. It allows an IM-type message passing. Type in
+ * the console and your message will be printed on the TV screen. Type something on the TV and it will show up in the
+ * console.
+ */
+
+import com.yahoo.connectedtv.ycommand.*;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class AppChatExample {
+ public static String HOST = "localhost";
+ public static int PORT = 8099;
+ public static String APP_NAME = "AppChatExample";
+ public final static String APP_ID = "0xeTgF3c";
+ public final static String CONSUMER_KEY = "dj0yJmk9T1Y0MmVIWWEzWVc3JmQ9WVdrOU1IaGxWR2RHTTJNbWNHbzlNVEUzTkRFM09ERTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0yNA--";
+ public final static String SECRET = "1b8f0feb4d8d468676293caa769e19958bf36843";
+
+ public static String WIDGET_ID = "com.yahoo.connectedtv.examples.appchat.widget";
+
+ public Connection conn;
+
+ private CommandRouter router;
+
+ public AppChatExample(String host, int port) {
+ // Set up our router object, this is responsible for routing incoming
+ // and outgoing messages
+ router = new CommandRouter();
+ try {
+ // setup our socket connection to the tv, but don't connect yet
+ conn = new Connection(InetAddress.getByName(host), port, router);
+
+ // Tell out router which network connection to use
+ router.setConnection(conn);
+
+ // setup a handler for incoming GrantedSessionCommand message
+ // objects
+ router.registerCommandSubscriber(new CommandSubscriber(), GrantedSessionCommand.class);
+
+ // Establish a connection
+ conn.establish();
+ // Since this is the first time we are connecting, we must
+ // create a new session
+ router.publishCommand(new CreateSessionCommand(APP_ID, CONSUMER_KEY, SECRET, APP_NAME));
+
+ String message = this.getUserInput("Code: ");
+
+ router.publishCommand(new AuthSessionCommand(message, conn.getPeerCertificate()));
+ } catch (UnknownHostException e) {
+ this.exitWithError("Error resolving " + host);
+ } catch (IOException e) {
+ this.exitWithError("Problem writing to the network connection");
+ } catch (InterruptedException e) {
+ this.exitWithError("Problem writing to the network connection");
+ }
+ }
+
+ private String getUserInput(String prompt) {
+ System.out.print(prompt);
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ try {
+ return br.readLine().trim();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private class CommandSubscriber implements ICommandSubscriber {
+ public void onCommandReceived(AbstractCommand command) {
+ // Filter out the messages we care about
+ if (command instanceof GrantedSessionCommand) {
+ // Print our our unique key, this will be used for
+ // subsequent connections
+ Utilities.log("Your instanceId is " + ((GrantedSessionCommand) command).getInstanceId());
+
+ try {
+ router.registerCommandSubscriber(this, WidgetCommand.class, WIDGET_ID);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ AppChatExample.this.startUserInput();
+
+ //Launch widget
+ try {
+ AppChatExample.this.router.publishCommand(new WidgetLaunchMethodCommand("callid-launch-" + WIDGET_ID, WIDGET_ID));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else if (command instanceof WidgetCommand) {
+ // handle incoming message from a widget
+ try {
+ JSONObject payload = new JSONObject(command.getPayload());
+ String username = payload.getString("username");
+ String message = payload.getString("message");
+ Utilities.log(username + ": " + message);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ } else { // print out the others for educational purposes
+ Utilities.log("Received: " + command.toString());
+ }
+ }
+
+ public void onConnectionLost(Connection conn) {
+ Utilities.log("Connection Lost!");
+ // AppChatExample.this.closeConnectionAndExit();
+
+ synchronized (AppChatExample.this.conn) {
+ AppChatExample.this.conn.notifyAll();
+ }
+ }
+ }
+
+ private void startUserInput() {
+ (new Thread() {
+ public void run() {
+ try {
+ while (true) {
+ String message = AppChatExample.this.getUserInput("Message: ");
+
+ if (message == null || message.equals("")) {
+ continue;
+ } else if (message.equals("q") || message.equals("quit")) {
+ break;
+ }
+
+ JSONObject msgObj = new JSONObject();
+ msgObj.put("message", message);
+ msgObj.put("username", "You");
+ AppChatExample.this.router.publishCommand(new WidgetCommand(WIDGET_ID, msgObj));
+ }
+ AppChatExample.this.closeConnectionAndExit();
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }).start();
+ }
+
+ private void closeConnectionAndExit() {
+ this.conn.close();
+
+ // Notify the main thread that everything we wanted to
+ // do is done.
+ synchronized (this.conn) {
+ this.conn.notifyAll();
+ }
+ }
+
+ private void exitWithError(String message) {
+ Utilities.log(message);
+ System.exit(-1);
+ }
+
+ public static void main(String[] args) {
+ AppChatExample chatExample = new AppChatExample(HOST, PORT);
+
+ // Let's wait until everything is done. This thread will get
+ // notified once we are ready to clean up
+ synchronized (chatExample.conn) {
+ try {
+ chatExample.conn.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ System.exit(1);
+ }
+}
View
7 examples/AppChatExample/README
@@ -0,0 +1,7 @@
+This example opens a connection, then starts an IM-like dialog with the Chat example.
+
+Java:
+compiling:
+javac -cp <path_to_library_jar> AppChatExample
+running:
+java -cp "<path_to_library_jar>:<path_to_org.json.jar>" AppChatExample
View
7 examples/SimpleNavigationExample/README
@@ -0,0 +1,7 @@
+This example opens a connection, issues a command to navigate right, then closes.
+
+Java:
+compiling:
+javac -cp <path_to_library_jar> SimpleExample
+running:
+java -cp "<path_to_library_jar>:<path_to_org.json.jar>" SimpleExample
View
191 examples/SimpleNavigationExample/SimpleExample.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+import com.yahoo.connectedtv.ycommand.CommandRouter;
+
+/***
+ * This Example is very simple. It establishes a connection to the TV, then sends a series of navigation commands
+ * that makes the application dock do a little dance.
+ */
+
+import com.yahoo.connectedtv.ycommand.*;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.UnknownHostException;
+
+public class SimpleExample {
+ public static String HOST = "localhost";
+ public static int PORT = 8099;
+ public static String APP_NAME = "SimpleExample";
+ public final static String APP_ID = "0xeTgF3c";
+ public final static String CONSUMER_KEY = "dj0yJmk9T1Y0MmVIWWEzWVc3JmQ9WVdrOU1IaGxWR2RHTTJNbWNHbzlNVEUzTkRFM09ERTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0yNA--";
+ public final static String SECRET = "1b8f0feb4d8d468676293caa769e19958bf36843";
+
+ public static CommandRouter router;
+ public static Connection conn;
+
+ public static void main(String[] args) {
+ // Set up our router object, this is responsible for routing incoming
+ // and outgoing messages
+ router = new CommandRouter();
+ try {
+ // setup our socket connection to the tv, but don't connect yet
+ conn = new Connection(HOST, PORT, router);
+
+ // Tell out router which network connection to use
+ router.setConnection(conn);
+
+ // setup a handler for incoming GrantedSessionCommand message
+ // objects
+ try {
+ router.registerCommandSubscriber(new ICommandSubscriber() {
+ public void onCommandReceived(AbstractCommand command) {
+ // Filter out the messages we care about
+ if (command instanceof GrantedSessionCommand) {
+ // Print our our unique key, this will be used for
+ // subsequent connections
+ Utilities.log("Your instanceId is " + ((GrantedSessionCommand) command).getInstanceId());
+
+
+ try {
+ //let's make the dock show up on the TV
+ router.publishCommand(new NavigationInputCommand("press_yahoo"));
+
+ Thread.sleep(2000); //sleep for 2 seconds so the animation to dock finishes
+
+ // Lets do something cool, like tell the TV to navigate to the right. Then do a little dance
+ // This is the same as pressing "right" on your remote
+ router.publishCommand(new NavigationInputCommand("press_right"));
+
+ Thread.sleep(1000);
+
+ // slide to the left
+ router.publishCommand(new NavigationInputCommand("press_left"));
+
+ Thread.sleep(1000);
+
+ //slide to the right
+ router.publishCommand(new NavigationInputCommand("press_right"));
+
+ Thread.sleep(1000);
+
+ //take it back now, y'all
+ router.publishCommand(new NavigationInputCommand("press_left"));
+
+ //cha cha cha
+ router.publishCommand(new NavigationInputCommand("press_up"));
+ Thread.sleep(1000);
+ router.publishCommand(new NavigationInputCommand("press_down"));
+ Thread.sleep(1000);
+ router.publishCommand(new NavigationInputCommand("press_up"));
+ Thread.sleep(1000);
+ router.publishCommand(new NavigationInputCommand("press_down"));
+ } catch (InterruptedException e) {
+ Utilities.log("Problem writing to the network connection");
+ conn.close();
+ System.exit(-1);
+ }
+
+ // Notify the main thread that everything we wanted to
+ // do is done.
+ synchronized (conn) {
+ conn.notifyAll();
+ }
+ } else { // print out the others for educational purposes
+ Utilities.log("Received: " + command.toString());
+ }
+ }
+
+ public void onConnectionLost(Connection conn) {
+ Utilities.log("Connection Lost!");
+ }
+ }, GrantedSessionCommand.class);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ // Establish a connection
+ conn.establish();
+ // Since this is the first time we are connecting, we must
+ // create a new session
+ router.publishCommand(new CreateSessionCommand(APP_ID, CONSUMER_KEY, SECRET, APP_NAME));
+
+ String message = getUserInput("Code: ");
+ router.publishCommand(new AuthSessionCommand(message, conn.getPeerCertificate()));
+
+ // Let's wait until everything is done. This thread will get
+ // notified once we are ready to clean up
+ try {
+ synchronized (conn) {
+ conn.wait();
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } catch (IOException ioe) {
+ Utilities.log("Error establishing connection to " + HOST + ":" + PORT);
+ } catch (InterruptedException e) {
+ Utilities.log("Error establishing connection to " + HOST + ":" + PORT);
+ }
+
+ // It is always good practice to clean up after yourself
+ conn.close();
+
+ } catch (UnknownHostException e) {
+ Utilities.log("Error resolving " + HOST);
+ System.exit(-1);
+ } catch (IOException e) {
+ Utilities.log("Problem writing to the network connection");
+ e.printStackTrace();
+ System.exit(-1);
+ }
+
+ System.exit(1);
+ }
+
+ private static String getUserInput(String prompt) {
+ System.out.print(prompt);
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ try {
+ return br.readLine().trim();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
View
7 examples/VideoListExample/README
@@ -0,0 +1,7 @@
+This example opens a connection, queries the VideoListExample widget for a list of videos, then prompts the user to enter a URL.
+
+Java:
+compiling:
+javac -cp <path_to_library_jar> VideoListExample
+running:
+java -cp "<path_to_library_jar>:<path_to_org.json.jar>" VideoListExample
View
242 examples/VideoListExample/VideoListExample.java
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+/***
+ * This example demonstrates how to build in video playing handling. It pairs up with the "App<->Device Video List"
+ * example that can be found in the simulator store. Once connected, it fetches a list of videos from the app and lists
+ * them out. You can enter in any URL and it will play the video in the simulator.
+ */
+
+import com.yahoo.connectedtv.ycommand.*;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class VideoListExample {
+ public static String HOST = "localhost";
+ public static int PORT = 8099;
+ public static String APP_NAME = "SimpleExample";
+ public final static String APP_ID = "0xeTgF3c";
+ public final static String CONSUMER_KEY = "dj0yJmk9T1Y0MmVIWWEzWVc3JmQ9WVdrOU1IaGxWR2RHTTJNbWNHbzlNVEUzTkRFM09ERTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0yNA--";
+ public final static String SECRET = "1b8f0feb4d8d468676293caa769e19958bf36843";
+
+ public static String WIDGET_ID = "com.yahoo.connectedtv.examples.dcvideolist";
+ public static String METHOD_NAME = "fetchVideos";
+ public static String CALL_ID = "ireallyshouldbeunique";
+
+ public Connection conn;
+
+ private CommandRouter router;
+
+ private CommandSubscriber commandHandler;
+
+ public VideoListExample(String host, int port) {
+ // Set up our router object, this is responsible for routing incoming
+ // and outgoing messages
+ router = new CommandRouter();
+ try {
+ // setup our socket connection to the tv, but don't connect yet
+ conn = new Connection(InetAddress.getByName(host), port, router);
+
+ // Tell out router which network connection to use
+ router.setConnection(conn);
+
+ // setup a handler for incoming GrantedSessionCommand message
+ // objects
+ this.commandHandler = new CommandSubscriber();
+ router.registerCommandSubscriber(this.commandHandler, GrantedSessionCommand.class);
+
+ // Establish a connection
+ conn.establish();
+ // Since this is the first time we are connecting, we must
+ // create a new session
+ router.publishCommand(new CreateSessionCommand(APP_ID, CONSUMER_KEY, SECRET, APP_NAME));
+
+ // type in the 4 digit code on the screen
+ String message = this.getUserInput("Code: ");
+
+ AuthSessionCommand asc = new AuthSessionCommand(message, conn.getPeerCertificate());
+
+ router.publishCommand(asc);
+ } catch (UnknownHostException e) {
+ this.exitWithError("Error resolving " + HOST);
+ } catch (IOException e) {
+ this.exitWithError("Problem writing to the network connection");
+ } catch (InterruptedException e) {
+ this.exitWithError("Problem writing to the network connection");
+ }
+ }
+
+ private String getUserInput(String prompt) {
+ System.out.print(prompt);
+ InputStreamReader in = new InputStreamReader(System.in);
+ BufferedReader br = new BufferedReader(in);
+ try {
+ return br.readLine().trim();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private class CommandSubscriber implements ICommandSubscriber {
+ public void onCommandReceived(AbstractCommand command) {
+ // Filter out the messages we care about
+ if (command instanceof GrantedSessionCommand) {
+ // Print our our unique key, this will be used for subsequent connections
+ Utilities.log("Your instanceId is " + ((GrantedSessionCommand) command).getInstanceId());
+
+ //register for commands from the widget
+ try {
+ router.registerCommandSubscriber(VideoListExample.this.commandHandler, WidgetCommand.class, WIDGET_ID);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ VideoListExample.this.startUserInput();
+ } else if (command instanceof WidgetCommand) {
+ // handle incoming message from a widget
+ VideoListExample.this.handleWidgetMessage((WidgetCommand) command);
+ } else if (command instanceof WidgetMethodCommand) {
+ try {
+ JSONArray videos = new JSONArray(command.getPayload());
+ for (int i = 0; i < videos.length(); i++) {
+ JSONObject video = videos.getJSONObject(i);
+ System.out.println(i + ". Video: " + video.getString("title"));
+ System.out.println("\tdescription: " + video.getString("description"));
+ System.out.println("\tthumbnail: " + video.getString("thumbnail"));
+ System.out.println("\turl: " + video.getString("url"));
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void onConnectionLost(Connection conn) {
+ Utilities.log("Connection Lost!");
+
+ synchronized (VideoListExample.this.conn) {
+ VideoListExample.this.conn.notifyAll();
+ }
+ }
+ }
+
+ private void startUserInput() {
+ router.registerRMCCommandSubscriber(WIDGET_ID, METHOD_NAME, CALL_ID, this.commandHandler);
+
+ try {
+ this.router.publishCommand(new WidgetMethodCommand(AbstractCommand.METHOD_CALL, METHOD_NAME, CALL_ID, WIDGET_ID, null));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ (new Thread() {
+ public void run() {
+ try {
+ while (true) {
+ String url = VideoListExample.this.getUserInput("URL to play (q to quit): ");
+
+ if (url == null || url.equals("")) {
+ continue;
+ } else if (url.equals("q") || url.equals("quit")) {
+ break;
+ }
+
+ JSONObject msgObj = new JSONObject();
+ msgObj.put("url", url);
+ msgObj.put("method", "launchvideo");
+ VideoListExample.this.router.publishCommand(new WidgetLaunchMethodCommand("callid-" + url, WIDGET_ID, msgObj.toString()));
+ }
+ VideoListExample.this.closeConnectionAndExit();
+
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ }).start();
+
+ }
+
+ private void handleWidgetMessage(WidgetCommand command) {
+ try {
+ JSONObject payload = new JSONObject(command.getPayload());
+ String username = payload.getString("username");
+ String message = payload.getString("message");
+ Utilities.log(username + ": " + message);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void closeConnectionAndExit() {
+ this.conn.close();
+
+ // Notify the main thread that everything we wanted to
+ // do is done.
+ synchronized (this.conn) {
+ this.conn.notifyAll();
+ }
+ }
+
+ private void exitWithError(String message) {
+ Utilities.log(message);
+ System.exit(-1);
+ }
+
+ public static void main(String[] args) {
+ VideoListExample chatExample = new VideoListExample(HOST, PORT);
+
+ // Let's wait until everything is done. This thread will get
+ // notified once we are ready to clean up
+ try {
+ synchronized (chatExample.conn) {
+ chatExample.conn.wait();
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ System.exit(1);
+ }
+}
View
96 pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.yahoo.connectedtv</groupId>
+ <artifactId>device-control</artifactId>
+ <name>Yahoo! Connected TV Device Control</name>
+ <version>1001.1.17</version>
+ <url>http://connectedtv.yahoo.com</url>
+ <inceptionYear>2011</inceptionYear>
+ <developers>
+ <developer>
+ <id>jecortez</id>
+ <name>Jim Cortez</name>
+ <email>tvwidgets@yahoo.com</email>
+ <url>http://connectedtv.yahoo.com</url>
+ <organization>Yahoo!</organization>
+ <organizationUrl>http://yahoo.com</organizationUrl>
+ <timezone>(GMT-08:00) Pacific Time(US &amp; Canada)</timezone>
+ <roles>
+ <role></role>
+ </roles>
+ </developer>
+ </developers>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <testSourceDirectory>tests</testSourceDirectory>
+ <finalName>device-control</finalName>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <reportOutputDirectory>${basedir}</reportOutputDirectory>
+ <destDir>doc</destDir>
+ <overview>${basedir}/src/overview.html</overview>
+ <author>false</author>
+ <bottom> <![CDATA[Copyright 2011, <a href="
+ http: /
+ www.yahoo.com ">
+ Yahoo!, Inc.
+ <a>
+ ]]>
+ </bottom>
+ <detectLinks>true</detectLinks>
+ <links>
+ <link>http://download.oracle.com/javase/6/docs/api/</link>
+ <link>http://www.json.org/javadoc/</link>
+ </links>
+ </configuration>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20090211</version>
+ <optional>false</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-core</artifactId>
+ <version>1.3.RC2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit-dep</artifactId>
+ <version>4.8.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-core</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+</project>
View
264 src/com/yahoo/connectedtv/ycommand/AbstractCommand.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+package com.yahoo.connectedtv.ycommand;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/**
+ * Base Command class.
+ *
+ * @author jecortez
+ *
+ * @version $Revision: 1.0 $
+ */
+public abstract class AbstractCommand implements Serializable {
+ /**
+ * Field serialVersionUID.
+ * (value is 1)
+ */
+ private static final long serialVersionUID = 1L; // must be overridden
+ /**
+ * Field METHOD_PUBLISH.
+ * (value is ""PUBLISH"")
+ */
+ public final static String METHOD_PUBLISH = "PUBLISH";
+ /**
+ * Field METHOD_SUBSCRIBE.
+ * (value is ""SUBSCRIBE"")
+ */
+ public final static String METHOD_SUBSCRIBE = "SUBSCRIBE";
+ /**
+ * Field METHOD_SUBSCRIBED.
+ * (value is ""SUBSCRIBED"")
+ */
+ public final static String METHOD_SUBSCRIBED = "SUBSCRIBED";
+ /**
+ * Field METHOD_UNSUBSCRIBE.
+ * (value is ""UNSUBSCRIBE"")
+ */
+ public final static String METHOD_UNSUBSCRIBE = "UNSUBSCRIBE";
+ /**
+ * Field METHOD_UNSUBSCRIBED.
+ * (value is ""UNSUBSCRIBED"")
+ */
+ public final static String METHOD_UNSUBSCRIBED = "UNSUBSCRIBED";
+ /**
+ * Field METHOD_CALL.
+ * (value is ""CALL"")
+ */
+ public final static String METHOD_CALL = "CALL";
+ /**
+ * Field METHOD_RETURN.
+ * (value is ""RETURN"")
+ */
+ public final static String METHOD_RETURN = "RETURN";
+ /**
+ * Field TYPE_INPUT.
+ * (value is ""INPUT"")
+ */
+ public final static String TYPE_INPUT = "INPUT";
+ /**
+ * Field TYPE_WIDGET.
+ * (value is ""WIDGET"")
+ */
+ public final static String TYPE_WIDGET = "WIDGET";
+ /**
+ * Field TYPE_SERVICE.
+ * (value is ""SERVICE"")
+ */
+ public final static String TYPE_SERVICE = "SERVICE";
+
+ /**
+ * Field DIRECTIVE_SESSION.
+ * (value is ""SESSION"")
+ */
+ public final static String DIRECTIVE_SESSION = "SESSION";
+ /**
+ * Field DIRECTIVE_ERROR.
+ * (value is ""ERROR"")
+ */
+ public final static String DIRECTIVE_ERROR = "ERROR";
+
+ /**
+ * Field method.
+ */
+ protected String method;
+ /**
+ * Field type.
+ */
+ protected String type;
+ /**
+ * Field subject.
+ */
+ protected String subject;
+
+ /**
+ * create a command from an already-tokenized command
+ *
+ * @param tokenizedCommand
+ * a tokenized command (typically from command Parser)
+
+ * @throws CommandParseException */
+ public AbstractCommand(String[] tokenizedCommand) throws CommandParseException {
+ if (tokenizedCommand != null
+ && tokenizedCommand.length > 0
+ && (tokenizedCommand[0].equals(AbstractCommand.METHOD_PUBLISH)
+ || tokenizedCommand[0].equals(AbstractCommand.METHOD_SUBSCRIBE)
+ || tokenizedCommand[0].equals(AbstractCommand.METHOD_SUBSCRIBED)
+ || tokenizedCommand[0].equals(AbstractCommand.METHOD_UNSUBSCRIBE)
+ || tokenizedCommand[0].equals(AbstractCommand.METHOD_UNSUBSCRIBED)
+ || tokenizedCommand[0].equals(AbstractCommand.METHOD_CALL)
+ || tokenizedCommand[0].equals(AbstractCommand.METHOD_RETURN)
+ || tokenizedCommand[0].equals(AbstractCommand.DIRECTIVE_SESSION) || tokenizedCommand[0]
+ .equals(AbstractCommand.DIRECTIVE_ERROR))) {
+ this.method = tokenizedCommand[0];
+ } else {
+ throw new CommandParseException("unknown event");
+ }
+
+ }
+
+ /**
+ * A bare-bones command
+ *
+ * @param method
+ */
+ public AbstractCommand(String method) {
+ this.method = method;
+ }
+
+ /**
+ * Method toCommandString.
+ * @return String
+ */
+ public abstract String toCommandString();
+
+ /**
+ * Method toCommandString.
+ * @return String
+ */
+ public abstract String getPayload();
+
+ /**
+ * Method parseJSONObject.
+ * @param payload String
+ * @return JSONObject
+ */
+ protected JSONObject parseJSONObject(String payload) {
+ try {
+ return new JSONObject(payload);
+ } catch (JSONException je) {
+ Utilities.log("could not parse json");
+ Utilities.log(payload);
+ return null;
+ }
+ }
+
+ /**
+ * Method getMethod.
+ * @return String
+ */
+ public String getMethod() {
+ return method;
+ }
+
+ /**
+ * Method setMethod.
+ * @param method String
+ */
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ /**
+ * Method getType.
+ * @return String
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Method setType.
+ * @param type String
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Method getSubject.
+ * @return String
+ */
+ public String getSubject() {
+ return subject;
+ }
+
+ /**
+ * Method setSubject.
+ * @param subject String
+ */
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
+ /**
+ * Method writeObject.
+ * @param out ObjectOutputStream
+ * @throws IOException
+ */
+ protected void writeObject(ObjectOutputStream out) throws IOException {
+ // perform the default serialization for all non-transient, non-static
+ // fields
+ out.defaultWriteObject();
+ }
+
+ /**
+ * Method readObject.
+ * @param in ObjectInputStream
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
+ protected void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ // always perform the default de-serialization first
+ in.defaultReadObject();
+ }
+}
View
68 src/com/yahoo/connectedtv/ycommand/AbstractInputCommand.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+package com.yahoo.connectedtv.ycommand;
+
+/**
+ * Abstract class that all Input protocol commands inherit from
+ *
+ * @author jecortez
+ *
+ * @version $Revision: 1.0 $
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractInputCommand extends AbstractCommand {
+ /**
+ * Constructor for AbstractInputCommand.
+ * @param tokenizedCommand String[]
+ * @throws CommandParseException
+ */
+ public AbstractInputCommand(String[] tokenizedCommand) throws CommandParseException {
+ super(tokenizedCommand);
+ if (tokenizedCommand.length > 2 && tokenizedCommand[1].equals(AbstractCommand.TYPE_INPUT)) {
+ this.type = AbstractCommand.TYPE_INPUT;
+ } else {
+ throw new CommandParseException("invalid event");
+ }
+ }
+
+ /**
+ * Constructor for AbstractInputCommand.
+ */
+ public AbstractInputCommand() {
+ super("PUBLISH");
+ this.type = AbstractCommand.TYPE_INPUT;
+ }
+
+}
View
170 src/com/yahoo/connectedtv/ycommand/AbstractMethodCommand.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+package com.yahoo.connectedtv.ycommand;
+
+/**
+ * Abstract class that all Method Call protocol commands inherit from
+ *
+ * @author jecortez
+ *
+ * @version $Revision: 1.0 $
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractMethodCommand extends AbstractCommand {
+ /**
+ * Field callId.
+ */
+ protected String callId;
+ /**
+ * Field widgetId.
+ */
+ protected String widgetId;
+
+ /**
+ * Constructor for AbstractMethodCommand.
+ *
+ * @param method
+ * String
+ * @param widgetId
+ * String
+ * @param category
+ * String
+ * @param callId
+ * String
+ */
+ public AbstractMethodCommand(String method, String widgetId, String category, String callId) {
+ super(method);
+ assert (method.equals(AbstractCommand.METHOD_CALL) || method.equals(AbstractCommand.METHOD_RETURN));
+ this.widgetId = widgetId;
+ this.subject = category;
+ this.callId = callId;
+ }
+
+ /**
+ * Constructor for AbstractMethodCommand.
+ *
+ * @param tokenizedCommand
+ * String[]
+ * @throws CommandParseException
+ */
+ public AbstractMethodCommand(String[] tokenizedCommand) throws CommandParseException {
+ super(tokenizedCommand);
+ this.subject = tokenizedCommand[1];
+ this.widgetId = tokenizedCommand[2];
+
+ this.callId = tokenizedCommand[3];
+ }
+
+ /**
+ * Method toCommandString.
+ *
+ * @param payload
+ * String
+ * @return String
+ */
+ public String toCommandString(String payload) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(this.method);
+ sb.append('|');
+ sb.append(this.subject);
+ sb.append('|');
+ sb.append(this.widgetId == null ? "null" : this.widgetId);
+ sb.append('|');
+ sb.append((payload == null || payload.trim().equals("")) ? "null" : payload);
+ sb.append('|');
+ sb.append(this.callId);
+ sb.append("|END");
+
+ return sb.toString();
+ }
+
+ /**
+ * Method getCallId.
+ *
+ * @return String
+ */
+ public String getCallId() {
+ return callId;
+ }
+
+ /**
+ * Method setCallId.
+ *
+ * @param callId
+ * String
+ */
+ public void setCallId(String callId) {
+ this.callId = callId;
+ }
+
+ /**
+ * Method getWidgetID.
+ *
+ * @return String
+ */
+ public String getWidgetID() {
+ return widgetId;
+ }
+
+ /**
+ * Method setWidgetID.
+ *
+ * @param widgetId
+ * String
+ */
+ public void setWidgetID(String widgetId) {
+ this.widgetId = widgetId;
+ }
+
+ /**
+ * Method getName.
+ *
+ * @return String
+ */
+ public String getName() {
+ return subject;
+ }
+
+ /**
+ * Method setName.
+ *
+ * @param name
+ * String
+ */
+ public void setName(String name) {
+ this.subject = name;
+ }
+
+}
View
68 src/com/yahoo/connectedtv/ycommand/AbstractServiceCommand.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+package com.yahoo.connectedtv.ycommand;
+
+/**
+ * Abstract class that all Service protocol commands inherit from
+ *
+ * @author jecortez
+ *
+ * @version $Revision: 1.0 $
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractServiceCommand extends AbstractCommand {
+ /**
+ * Constructor for AbstractServiceCommand.
+ * @param tokenizedCommand String[]
+ * @throws CommandParseException
+ */
+ public AbstractServiceCommand(String[] tokenizedCommand) throws CommandParseException {
+ super(tokenizedCommand);
+ if (tokenizedCommand.length > 2 && tokenizedCommand[1].equals(AbstractCommand.TYPE_SERVICE)) {
+ this.type = AbstractCommand.TYPE_SERVICE;
+ } else {
+ throw new CommandParseException("invalid event");
+ }
+ }
+
+ /**
+ * Constructor for AbstractServiceCommand.
+ */
+ public AbstractServiceCommand() {
+ super("PUBLISH");
+ this.type = AbstractCommand.TYPE_SERVICE;
+ }
+
+}
View
68 src/com/yahoo/connectedtv/ycommand/AbstractSessionCommand.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+package com.yahoo.connectedtv.ycommand;
+
+/**
+ * Abstract class that all Session protocol commands inherit from
+ *
+ * @author jecortez
+ *
+ * @version $Revision: 1.0 $
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractSessionCommand extends AbstractCommand {
+ /**
+ * Constructor for AbstractSessionCommand.
+ * @param tokenizedCommand String[]
+ * @throws CommandParseException
+ */
+ public AbstractSessionCommand(String[] tokenizedCommand) throws CommandParseException {
+ super(tokenizedCommand);
+ if (tokenizedCommand.length > 2 && tokenizedCommand[0].equals(AbstractCommand.DIRECTIVE_SESSION)) {
+ this.type = AbstractCommand.DIRECTIVE_SESSION;
+ } else {
+ throw new CommandParseException("invalid event");
+ }
+ }
+
+ /**
+ * Constructor for AbstractSessionCommand.
+ * @param method String
+ */
+ public AbstractSessionCommand(String method) {
+ super(method);
+ this.type = AbstractCommand.DIRECTIVE_SESSION;
+ }
+}
View
186 src/com/yahoo/connectedtv/ycommand/AuthSessionCommand.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2011, Yahoo! Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * * Neither the name of Yahoo! Inc. nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior
+ * written permission of Yahoo! Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+package com.yahoo.connectedtv.ycommand;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.logging.Level;
+
+/**
+ * Wraps an protocol authorize session command
+ * <p>
+ * Example Command:
+ *
+ * <pre>
+ * {@literal
+ * SESSION|AUTH|a44520388013d49fcdb16a6b7129bffb4e54ce99|END
+ * }
+ * </pre>
+ *
+ * </p>
+ *
+ * @author jecortez
+ *
+ * @version $Revision: 1.0 $
+ */
+public class AuthSessionCommand extends AbstractSessionCommand {
+ /**
+ * Field serialVersionUID.
+ * (value is -8967152467731112563)
+ */
+ private static final long serialVersionUID = -8967152467731112563L;
+ /**
+ * Field userCode.
+ */
+ private String userCode;
+ /**
+ * Field cert.
+ */
+ private String cert;
+
+ /**
+ * @param code
+ * code the user has inputed on screen
+
+ * @param certificate String
+ */
+ public AuthSessionCommand(String code, String certificate) {
+ super("SESSION");
+ this.userCode = code;
+ this.cert = certificate;
+ }
+
+ /**
+ * Method generateSignature.
+ * @return String
+ */
+ private String generateSignature() {
+ if (this.cert.equals("") || this.cert == null) {
+ Utilities.log(Level.SEVERE, "NO CERTIFICATE FOUND!");
+ }
+ // generate a SHA1-HMAC signature
+ String sig = "";
+ try {
+ SecretKeySpec key = new SecretKeySpec(this.userCode.getBytes("UTF-8"), "HmacSHA1");
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(key);
+
+ sig = this.byteArrayToHex(mac.doFinal(this.cert.getBytes("UTF-8")));
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ return sig;
+ }
+
+ /**
+ * Method byteArrayToHex.
+ * @param a byte[]
+ * @return String
+ */
+ private String byteArrayToHex(byte[] a) {
+ int hn, ln, cx;
+ String hexDigitChars = "0123456789abcdef";
+ StringBuffer buf = new StringBuffer(a.length * 2);
+ for (cx = 0; cx < a.length; cx++) {
+ hn = ((int) (a[cx]) & 0x00ff) / 16;
+ ln = ((int) (a[cx]) & 0x000f);
+ buf.append(hexDigitChars.charAt(hn));
+ buf.append(hexDigitChars.charAt(ln));
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Method toCommandString.
+ * @return String
+ */
+ @Override
+ public String toCommandString() {
+ return String.format("SESSION|AUTH|%s|END", this.generateSignature());
+ }
+
+ @Override
+ public String getPayload() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ /**
+ * Method getUserCode.
+ * @return String
+ */
+ public String getUserCode() {
+ return userCode;
+ }
+
+ /**
+ * Method setUserCode.
+ * @param userCode String
+ */
+ public void setUserCode(String userCode) {
+ this.userCode = userCode;
+ }
+
+ /**
+ * Method getSignature.
+ * @return String
+ */
+ public String getSignature() {
+ return this.generateSignature();
+ }
+
+ /**
+ * Method getCert.
+ * @return String
+ */
+ public String getCert() {
+ return cert;
+ }
+
+ /**
+ * Method setCert.
+ * @param cert String
+ */
+ public void setCert(String cert) {
+ this.cert = cert;
+ }
+}
View
2,202 src/com/yahoo/connectedtv/ycommand/Base64.java
@@ -0,0 +1,2202 @@
+package com.yahoo.connectedtv.ycommand;
+
+/**
+ * <p>
+ * Encodes and decodes to and from Base64 notation.
+ * </p>
+ * <p>
+ * Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.
+ * </p>
+ *
+ * <p>
+ * Example:
+ * </p>
+ *
+ * <code>String encoded = Base64.encode( myByteArray );</code> <br />
+ * <code>byte[] myByteArray = Base64.decode( encoded );</code>
+ *
+ * <p>
+ * The <tt>options</tt> parameter, which appears in a few places, is used to
+ * pass several pieces of information to the encoder. In the "higher level"
+ * methods such as encodeBytes( bytes, options ) the options parameter can be
+ * used to indicate such things as first gzipping the bytes before encoding
+ * them, not inserting linefeeds, and encoding using the URL-safe and Ordered
+ * dialects.
+ * </p>
+ *
+ * <p>
+ * Note, according to <a
+ * href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>, Section 2.1,
+ * implementations should not add line feeds unless explicitly told to do so.
+ * I've got Base64 set to this behavior now, although earlier versions broke
+ * lines by default.
+ * </p>
+ *
+ * <p>
+ * The constants defined in Base64 can be OR-ed together to combine options, so
+ * you might make a call like this:
+ * </p>
+ *
+ * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
+ * <p>
+ * to compress the data before encoding it and then making the output have
+ * newline characters.
+ * </p>
+ * <p>
+ * Also...
+ * </p>
+ * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
+ *
+ *
+ *
+ * <p>
+ * Change Log:
+ * </p>
+ * <ul>
+ * <li>v2.3.7 - Fixed subtle bug when base 64 input stream contained the value
+ * 01111111, which is an invalid base 64 character but should not throw an
+ * ArrayIndexOutOfBoundsException either. Led to discovery of mishandling (or
+ * potential for better handling) of other bad input characters. You should now
+ * get an IOException if you try decoding something that has bad characters in
+ * it.</li>
+ * <li>v2.3.6 - Fixed bug when breaking lines and the final byte of the encoded
+ * string ended in the last column; the buffer was not properly shrunk and
+ * contained an extra (null) byte that made it into the string.</li>
+ * <li>v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size
+ * was wrong for files of size 31, 34, and 37 bytes.</li>
+ * <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing the
+ * Base64.OutputStream closed the Base64 encoding (by padding with equals signs)
+ * too soon. Also added an option to suppress the automatic decoding of gzipped
+ * streams. Also added experimental support for specifying a class loader when
+ * using the
+ * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)} method.
+ * </li>
+ * <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the
+ * internal Java footprint with its CharEncoders and so forth. Fixed some
+ * javadocs that were inconsistent. Removed imports and specified things like
+ * java.io.IOException explicitly inline.</li>
+ * <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how
+ * big the final encoded data will be so that the code doesn't have to create
+ * two output arrays: an oversized initial one and then a final, exact-sized
+ * one. Big win when using the {@link #encodeBytesToBytes(byte[])} family of
+ * methods (and not using the gzip options which uses a different mechanism with
+ * streams and stuff).</li>
+ * <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and
+ * some similar helper methods to be more efficient with memory by not returning
+ * a String but just a byte array.</li>
+ * <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two
+ * years of comments and bug fixes queued up and finally executed. Thanks to
+ * everyone who sent me stuff, and I'm sorry I wasn't able to distribute your
+ * fixes to everyone else. Much bad coding was cleaned up including throwing
+ * exceptions where necessary instead of returning null values or something
+ * similar. Here are some changes that may affect you:
+ * <ul>
+ * <li><em>Does not break lines, by default.</em> This is to keep in compliance
+ * with <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
+ * <li><em>Throws exceptions instead of returning null values.</em> Because some
+ * operations (especially those that may permit the GZIP option) use IO streams,
+ * there is a possiblity of an java.io.IOException being thrown. After some
+ * discussion and thought, I've changed the behavior of the methods to throw
+ * java.io.IOExceptions rather than return null if ever there's an error. I
+ * think this is more appropriate, though it will require some changes to your
+ * code. Sorry, it should have been done this way to begin with.</li>
+ * <li><em>Removed all references to System.out, System.err, and the like.</em>
+ * Shame on me. All I can say is sorry they were ever there.</li>
+ * <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as
+ * needed such as when passed arrays are null or offsets are invalid.</li>
+ * <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings. This
+ * was especially annoying before for people who were thorough in their own
+ * projects and then had gobs of javadoc warnings on this file.</li>
+ * </ul>
+ * <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug when
+ * using very small files (~&lt; 40 bytes).</li>
+ * <li>v2.2 - Added some helper methods for encoding/decoding directly from one
+ * file to the next. Also added a main() method to support command line
+ * encoding/decoding from one file to the next. Also added these Base64
+ * dialects:
+ * <ol>
+ * <li>The default is RFC3548 format.</li>
+ * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
+ * URL and file name friendly format as described in Section 4 of RFC3548.
+ * http://www.faqs.org/rfcs/rfc3548.html</li>
+ * <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
+ * URL and file name friendly format that preserves lexical ordering as
+ * described in http://www.faqs.org/qa/rfcc-1940.html</li>
+ * </ol>
+ * Special thanks to Jim Kellerman at <a
+ * href="http://www.powerset.com/">http://www.powerset.com/</a> for contributing
+ * the new Base64 dialects.</li>
+ *
+ * <li>v2.1 - Cleaned up javadoc comments and unused variables and methods.
+ * Added some convenience methods for reading and writing to and from files.</li>
+ * <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on
+ * systems with other encodings (like EBCDIC).</li>
+ * <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
+ * encoded data was a single byte.</li>
+ * <li>v2.0 - I got rid of methods that used booleans to set options. Now
+ * everything is more consolidated and cleaner. The code now detects when data
+ * that's being decoded is gzip-compressed and will decompress it automatically.
+ * Generally things are cleaner. You'll probably have to change some method
+ * calls that you were making to support the new options format (<tt>int</tt>s
+ * that you "OR" together).</li>
+ * <li>v1.5.1 - Fixed bug when decompressing and decoding to a byte[] using
+ * <tt>decode( String s, boolean gzipCompressed )</tt>. Added the ability to
+ * "suspend" encoding in the Output Stream so you can turn on and off the
+ * encoding if you need to embed base64 data in an otherwise "normal" stream
+ * (like an XML file).</li>
+ * <li>v1.5 - Output stream pases on flush() command but doesn't do anything
+ * itself. This helps when using GZIP streams. Added the ability to
+ * GZip-compress objects before encoding them.</li>
+ * <li>v1.4 - Added helper methods to read/write files.</li>
+ * <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
+ * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input
+ * stream where last buffer being read, if not completely full, was not
+ * returned.</li>
+ * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the
+ * wrong time.</li>
+ * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
+ * </ul>
+ *
+ * <p>
+ * I am placing this code in the Public Domain. Do with it as you will. This
+ * software comes with no guarantees or warranties but with plenty of
+ * well-wishing instead! Please visit <a
+ * href="http://iharder.net/base64">http://iharder.net/base64</a> periodically
+ * to check for updates or to contribute improvements.
+ * </p>
+ *
+ * @author Robert Harder
+ * @author rob@iharder.net
+ * @version 2.3.7
+ */
+public class Base64 {
+
+ /* ******** P U B L I C F I E L D S ******** */
+
+ /** No options specified. Value is zero. */
+ public final static int NO_OPTIONS = 0;
+
+ /** Specify encoding in first bit. Value is one. */
+ public final static int ENCODE = 1;
+
+ /** Specify decoding in first bit. Value is zero. */
+ public final static int DECODE = 0;
+
+ /** Specify that data should be gzip-compressed in second bit. Value is two. */
+ public final static int GZIP = 2;
+
+ /**
+ * Specify that gzipped data should <em>not</em> be automatically gunzipped.
+ */
+ public final static int DONT_GUNZIP = 4;
+
+ /** Do break lines when encoding. Value is 8. */
+ public final static int DO_BREAK_LINES = 8;
+
+ /**
+ * Encode using Base64-like encoding that is URL- and Filename-safe as
+ * described in Section 4 of RFC3548: <a
+ * href="http://www.faqs.org/rfcs/rfc3548.html"
+ * >http://www.faqs.org/rfcs/rfc3548.html</a>. It is important to note that
+ * data encoded this way is <em>not</em> officially valid Base64, or at the
+ * very least should not be called Base64 without also specifying that is
+ * was encoded using the URL- and Filename-safe dialect.
+ */
+ public final static int URL_SAFE = 16;
+
+ /**
+ * Encode using the special "ordered" dialect of Base64 described here: <a
+ * href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-
+ * 1940.html</a>.
+ */
+ public final static int ORDERED = 32;
+
+ /* ******** P R I V A T E F I E L D S ******** */
+
+ /** Maximum line length (76) of Base64 output. */
+ private final static int MAX_LINE_LENGTH = 76;
+
+ /** The equals sign (=) as a byte. */
+ private final static byte EQUALS_SIGN = (byte) '=';
+
+ /** The new line character (\n) as a byte. */
+ private final static byte NEW_LINE = (byte) '\n';
+
+ /** Preferred encoding. */
+ private final static String PREFERRED_ENCODING = "US-ASCII";
+
+ private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in
+ // encoding
+ private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in
+ // encoding
+
+ /* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */
+
+ /** The 64 valid Base64 values. */
+ /*
+ * Host platform me be something funny like EBCDIC, so we hardcode these
+ * values.
+ */
+ private final static byte[] _STANDARD_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
+ (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
+ (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
+ (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
+ (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
+ (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
+ (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' };
+
+ /**
+ * Translates a Base64 value to either its 6-bit reconstruction value or a
+ * negative number indicating some other meaning.
+ **/
+ private final static byte[] _STANDARD_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal
+ // 0
+ // -
+ // 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 -
+ // 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ 62, // Plus sign at decimal 43
+ -9, -9, -9, // Decimal 44 - 46
+ 63, // Slash at decimal 47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through
+ // 'N'
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O'
+ // through 'Z'
+ -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a'
+ // through 'm'
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n'
+ // through 'z'
+ -9, -9, -9, -9, -9 // Decimal 123 - 127
+ , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 -
+ // 139
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 -
+ // 152
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 -
+ // 165
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 -
+ // 178
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 -
+ // 191
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 -
+ // 204
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 -
+ // 217
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 -
+ // 230
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 -
+ // 243
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
+ };
+
+ /* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * Used in the URL- and Filename-safe dialect described in Section 4 of
+ * RFC3548: <a
+ * href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org
+ * /rfcs/rfc3548.html</a>. Notice that the last two bytes become "hyphen"
+ * and "underscore" instead of "plus" and "slash."
+ */
+ private final static byte[] _URL_SAFE_ALPHABET = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E',
+ (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
+ (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W',
+ (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
+ (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o',
+ (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x',
+ (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
+ (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' };
+
+ /**
+ * Used in decoding URL- and Filename-safe dialects of Base64.
+ */
+ private final static byte[] _URL_SAFE_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal
+ // 0
+ // -
+ // 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 -
+ // 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 62, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through
+ // 'N'
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O'
+ // through 'Z'
+ -9, -9, -9, -9, // Decimal 91 - 94
+ 63, // Underscore at decimal 95
+ -9, // Decimal 96
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a'
+ // through 'm'
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n'
+ // through 'z'
+ -9, -9, -9, -9, -9 // Decimal 123 - 127
+ , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128 -
+ // 139
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 -
+ // 152
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 -
+ // 165
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 -
+ // 178
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 -
+ // 191
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 -
+ // 204
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 -
+ // 217
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 -
+ // 230
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 -
+ // 243
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
+ };
+
+ /* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */
+
+ /**
+ * I don't get the point of this technique, but someone requested it, and it
+ * is described here: <a
+ * href="http://www.faqs.org/qa/rfcc-1940.html">http://
+ * www.faqs.org/qa/rfcc-1940.html</a>.
+ */
+ private final static byte[] _ORDERED_ALPHABET = { (byte) '-', (byte) '0', (byte) '1', (byte) '2', (byte) '3',
+ (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'A', (byte) 'B', (byte) 'C',
+ (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L',
+ (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
+ (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) '_', (byte) 'a', (byte) 'b', (byte) 'c',
+ (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l',
+ (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
+ (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z' };
+
+ /**
+ * Used in decoding the "ordered" dialect of Base64.
+ */
+ private final static byte[] _ORDERED_DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal
+ // 0
+ // -
+ // 8
+ -5, -5, // Whitespace: Tab and Linefeed
+ -9, -9, // Decimal 11 - 12
+ -5, // Whitespace: Carriage Return
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 -
+ // 26
+ -9, -9, -9, -9, -9, // Decimal 27 - 31
+ -5, // Whitespace: Space
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
+ -9, // Plus sign at decimal 43
+ -9, // Decimal 44
+ 0, // Minus sign at decimal 45
+ -9, // Decimal 46
+ -9, // Slash at decimal 47
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine
+ -9, -9, -9, // Decimal 58 - 60
+ -1, // Equals sign at decimal 61
+ -9, -9, -9, // Decimal 62 - 64
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A'
+ // through 'M'
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N'
+ // through 'Z'
+ -9, -9, -9, -9, // Decimal 91 - 94
+ 37, // Underscore at decimal 95
+ -9, // Decimal 96
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a'
+ // through 'm'
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n'
+ // through 'z'
+ -9, -9, -9, -9, -9 // Decimal 123 - 127
+ , -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 128
+ // - 139
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 140 -
+ // 152
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 153 -
+ // 165
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 166 -
+ // 178
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 179 -
+ // 191
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 192 -
+ // 204
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 205 -
+ // 217
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 218 -
+ // 230
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 231 -
+ // 243
+ -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9 // Decimal 244 - 255
+ };
+
+ /* ******** D E T E R M I N E W H I C H A L H A B E T ******** */
+
+ /**
+ * Returns one of the _SOMETHING_ALPHABET byte arrays depending on the
+ * options specified. It's possible, though silly, to specify ORDERED
+ * <b>and</b> URLSAFE in which case one of them will be picked, though there
+ * is no guarantee as to which one will be picked.