Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

27 November 2010

Send SMS Text Message from Java/Groovy - via Twitter

Writing code to send an SMS text message is fairly easy on a smart phone like an Android.  But from a desktop, sending texts is still a mess, not always free, and/or requires a phone connected to your server.

I simply want to send a message to my phone when my app receives some data.  I don't need a complex library with lots of setup nor do I want to sign up for a pay service.

Now this isn't the cleanest solution to text from an app but Twitter can send messages to your phone when people you follow update their status, when someone mentions or replies to you, or when you get a direct message.

My last two write-ups, "Send a Simple Tweet with OAuth and Groovy" and "Send a Direct Message Tweet with Groovy" showed how easy it is to use Java/Groovy and the Twitter4J library to send messages to your own Twitter account or a message to anyone else.

By sending a tweet to an account that you follow or a Direct Message to your own account, Twitter can be setup to forward that message to a phone that you associate with your account.

Simply go to your Twitter account, Settings, Mobile and follow the easy instruction. Then use one of the sample apps from my previous posts and tweet-text away!

Note:
  • This only allows you to tweet-text to phones that have been setup to follow accounts. 
  • This does not allow you to send a text to a cell phone not registered with Twitter.
  • This works for what I need.
  • Do you know a better/easier, free method?  Write a comment!


What do you think? Leave a comment.

Sending a Simple Tweet with OAuth and Java/Groovy

Come on, man!  What used to a be a simple task to send a tweet is now a OAuth nightmare.

A year or so ago, I built that tweet-a-w/e thing that sniffed XBee chirps and sent them to a twitter account that kindly routed them to my cell phone.

I have a need now to receive an XML stream, parse out a few tidbits and then send the results out as a SMS text message.  Remembering that tweet-a-w/e app, I thought that I would again leverage Twitter to send the text message.  All I need to do is send a tweet via a Twitter API and have my account set up to send the content to a phone number.

This time my XML receiver is in Java/Groovy, so I grabbed the latest Twitter4J, glanced at the UpdateStatus example and tried a quick test with Groovy.
import twitter4j.Twitter  
import twitter4j.TwitterFactory  
import twitter4j.Status  
    
Twitter twitter = new TwitterFactory().getInstance("myAcct","myPassword");  
Status status = twitter.updateStatus("from Groovy");  
System.out.println("Successfully updated the status to [" + status.getText() + "].");  
Did that work?  Of course not.  Authentication FAIL.

Caught: 401:Authentication credentials were missing or incorrect.
{"errors":[{"code":53,"message":"Basic authentication is not supported"}]}
TwitterException{exceptionCode=[15bb6564-00e5bee0], statusCode=401, retryAfter=0, rateLimitStatus=null, version=2.1.7}

What the heck?  Basic Authentication is not supported?  Darn it, what is this stupid OAuth thing about?  Here's the Twitter page "Authenticating Requests with OAuth" that looks real interesting to read.  Arghhhhh.  I just want to send a flippin' tweet, I really don't have time to research this at Hueniverse.

After some more quick Googling, this isn't as bad as it first looks.It boils down to getting a key and secret pair.  The steps are:
  • Goto Twitter and register your app.
  • You'll get a consumer key and secret which are similar to the public and private keys used in protocols such as ssh. 
  • Use the key and secret to sign every request you make to the Twitter API
import twitter4j.Twitter  
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.Status
import twitter4j.http.AccessToken
import twitter4j.http.RequestToken
import java.io.BufferedReader

try{

   Twitter twitter = new TwitterFactory().getInstance();

   // set key and secret that you get from Twitter app registeration at:
   //     http://dev.twitter.com/pages/auth#register
   twitter.setOAuthConsumer("Your Consumer key", "Your Consumer secret");

   // get the URL to request access to Twitter acct
   RequestToken requestToken = twitter.getOAuthRequestToken();
   String authUrl = requestToken.getAuthorizationURL()
   System.out.println("Open the following URL and grant access to your account:");
   System.out.println(authUrl);

   // take the PIN and get access token
   System.out.print("Enter the PIN:");
   BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
   String pin = ""
   pin = br.readLine();
   AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, pin);

   String message = "from Groovy w/ pin" + pin
   Status status = twitter.updateStatus(message);
   System.out.println("Successfully sent " + message);

} catch (Exception e) {
   e.printStackTrace();
} 

Ok, so that works.  But every time you run the program, you need to go and fetch the darn token.  According to Twitter, the token doesn't expire, so let's persist the thing.

I like using XStream to serialize Java/Groovy objects to/from XML.  A quick update to the code above lets us save an XML file that we can reload as needed.
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.Status
import twitter4j.http.AccessToken
import twitter4j.http.RequestToken
import java.io.BufferedReader
import com.thoughtworks.xstream.XStream

try{

   Twitter twitter = new TwitterFactory().getInstance();

   // set key and secret that you get from Twitter app registeration at:
   //     http://dev.twitter.com/pages/auth#register
   twitter.setOAuthConsumer("Your Consumer key", "Your Consumer secret");

   // load access token if it exists
   AccessToken accessToken = null
   def tokenFile = new File("accessToken.xml")

   if (tokenFile.exists()) {
      def xstream = new XStream()
      tokenFile.withInputStream { ins -> accessToken = xstream.fromXML(ins) }
      twitter.setOAuthAccessToken(accessToken)
   } 

   else {

     // get the URL to request access to Twitter acct
     RequestToken requestToken = twitter.getOAuthRequestToken();
     String authUrl = requestToken.getAuthorizationURL()
     System.out.println("Open the following URL and grant access to your account:");
     System.out.println(authUrl);

     // take the PIN and get access token
     System.out.print("Enter the PIN:");
     BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     String pin = ""
     pin = br.readLine();
     accessToken = twitter.getOAuthAccessToken(requestToken, pin);

     // persist token
     def xstream = new XStream()
     xstream.classLoader = getClass().classLoader
     new File("accessToken.xml").withOutputStream { out -> xstream.toXML(accessToken, out) }
   }

   String message = "from Groovy w/ token" + accessToken.getToken()
   Status status = twitter.updateStatus(message);
   System.out.println("Successfully sent " + message);

} catch (Exception e) {
   e.printStackTrace();
}

The serialized Access Token looks like this:


  5555555-AbCdEF
  1oKiOlOlOlOl
  
    oauth_token=5555555-AbCdEF
    oauth_token_secret=1oKiOlOlOlOl
    user_id=007
    screen_name=bond

  
  bond
  007

Notes:

For the above examples, I used:
  • Groovy Version: 1.7.0 JVM: 1.6.0_22
  • Twitter4J 2.1.7  For this, I copied only the twitter4j-core-2.1.7.jar into the Groovy lib folder.  On Linux, this is /usr/share/Groovy/lib
  • XStream 1.3.1  For this, I copied the xstream-1.3.1.jar and xpp3_min-1.1.4c.jar into the Groovy lib
What do you think? Leave a comment.

31 January 2009

Grid Computing with GridGain

Similar to the famous "one word - Plastics" scene in "The Graduate", a senior engineer took me aside on the weekend of the Columbia explosion and said "Grid Computing". We were working long hours for a proposal that was insane at best. At the time, I had heard of SETI@home but never really had spent any time on the subject. Tim was pretty excited about the topic. He had just read an article in some Hype-of-the-Day rag and was sure that Grid Computing was going to be the solution we needed for our proposal.

We ended up winning the job which is a really big deal. I think we're up to around $400M now over the past few years. The app is a distributed system (not a web app) but doesn't use Grid Computing and never will. It's tied into the customer's crazy network dreams and their infrastructure framework that locks our applications to theirs. Actually, it's brilliant in a business way. Our apps can't ever be used for anything other than for their original purposes.

For the past few months, I've been following the blog @Gridify Cloud Computing via Google Reader. Honestly I don't know why. I must have stumbled on an interesting entry one day and added then to the reader for future ref. This weekend, I was scanning the blogs and I saw a GridGain blog that started with:
When executing tasks and jobs on the grid you may be faced with the question: "How do I make sure that tasks from other users are not executed on nodes started by me?"
We're asking ourselves the same question on my project so the entry piqued my interest. The GridGain solution can't help me in anyway but it got me to their website where I started to poke around. I watched a few short videos on GridGain installation and creating an app in 15 minutes. Ok, I'm interested, let's do this.

Installation is pretty easy, just go to the downloads page and grab the installer for your OS. I'm using linux, so I got the GUI installer gridgain-unix-2.1.0.sh and ran it like this:
sh ./gridgain-unix-2.1.0.sh
Pretty easy. I decided to install under my projects folder so next I setup environment variables for GRIDGAIN_HOME in ~/.bashrc like this:
export GRIDGAIN_HOME=~/projects/gridgain-2.1.0
I haven't used Java much lately and was happy to see that GridGain had Groovy examples. I attempted to run the examples and immediately ran into difficulties. First was my fault. I un-installed Groovy a bit ago and needed to get the latest distribution. I did:
sudo apt-get install groovy
And presto, groovy was re-installed. A quick sanity check verified that it was installed:
groovy -v
This reveals that groovy 1.5.2 was installed. Hmmm, I swore that a newer version was out but 1.5.2 should be good for the GridGain demos, right? Right.

I stepped up to the first example compileGridify.sh. It immediately complained that GROOVY_HOME wasn't set. Back to ~/.bashrc and I added this line:
export GROOVY_HOME=/usr/share/groovy
Then the script started to complain that class Gridify couldn't be found. This is GridGain's own example, the thing should run almost out-of-the-box. Durn it! A little more digging reveals the the compile example referenced gridgain.jar in the classpath when the actual jar is called gridgain-2.1.0.jar. I started to edit the file and realized that there were probably other scripts in the GridGain install that may have the same error. Rather than go on an edit-fest, I simply created a soft link in GRIDGAIN_HOME like this:
ln -s gridgain-2.1.0.jar gridgain.jar
Yeah! it compiled. Now to the run script. The runGridify.sh complained that it couldn't find the groovy.lang.GroovyObject class. Kinda weird cause that's the momma groovy class. Sounds like another classpath issue. And it was. The run script references embeddable/groovy-all-1.5.7.jar. Problem is that not only did I have version 1.5.2, that version doesn't even include a groovy-all.jar. I wonder why? I then went to groovy home and looked around. Version 1.5.6 has a Debian package but the newest 1.5.7 doesn't. Sounds like 1.5.6 is the next to try. After installation, I looked at GROOVY_HOME and yes!! It has an embeddable folder and a groovy-all-1.5.6.jar. Now a quick edit to the runGridify.sh file and back in business.

The gridify example starts up a default configuration and prints out "Hello World" on a remote node. Nothing too exciting but impressive if you look at all that really is happening in the background.

The other example compileHelloWorld.sh and runHelloWorld.sh have the exact same issues with classpath jars. This example is similar to Gridify but prints "Hello" on one node and "World" on another. To do this, start another node in a terminal before running runHelloWorld.sh :
./gridgain.sh
There's many cool things that can be done with GridGain. One interesting thing is running JUnit tests after a build in a parallel manner. The GridGain guy claims that running their test on a single box takes about 3 hours. Gridifying the Ant task reduces that to about 20 minutes.

Take a look at the videos and other stuff on the website to get started. As well, DZone has a pile of hits. Search DZone for gridgain

I reported these version probs to the GridGain user forum. They made the fix and updated the wiki the next day. Nice.

http://www.gridgainsystems.com/wiki/display/GG15UG/Groovy+Configuration+And+Setup

03 January 2009

GPS and Twitter

Early last year I created a twitter account. Not really sure why I did. I guess no one wants to be left behind in the micro blogging world. Other than announcing that I wrote another entry on this blog, I never did anything with twitter.

Later, I stumbled on JTwitter which is a small Java library to the Twitter API. It lets you set/get your Twitter status, manage your network of friends, message friends, etc. I goofed with it for a few minutes. Example usage:
// Make a Twitter object
Twitter twitter = new Twitter("my-name","my-password");
// Print Daniel Winterstein's status
System.out.println(twitter.getStatus("winterstein"));
// Set my status
twitter.updateStatus("Messing about in Java");
Interesting. But I have no app in mind for Twitter, so JTwitter was bookmarked on Delicious for later. Today I saw on Make a cool project where a washing machine sends a message to Twitter when it's done. Pretty neat but if I hacked into my wife's LG, I'd be dead meat.

Because of Arduinos and Xbees, I've been spending lots of time on ladyada's site either buying stuff at adafruit or trying to get smarter by lurking in the forums. Ladyada seems to be alright but she has weird hair. She's pretty quick on answering forum questions and builds decent stuff. I really like her Xbee Adapter Kit.

Chris Anderson is an editor for Wired magazine. He also has a website for DIY UAVs at http://diydrones.com. Last year, I spent lots of time at his site 'cause that's something else that I want to build some day. After I read that Washing Machine Twitter thing, I read a blurb about Chris' new business model for an open source robotics startup. He says:

I'm ok with that business model but the reason I'm spinning this long story is that Chris spilled those beans via Twitter. Oh, I didn't know he had a Twitter account. I wonder what else he writes about? He writes about life and stuff. I wonder who he follows on twitter? He's the editor for Wired mag, probably follows some interesting people, huh? Sure enough, Tim O'Reilly, Phillip Torrone (Make mag), Brad Stone (NY Times), Steven Levy (found Einstein's brain, wrote Hackers, etc), and others. And Ladyada.

Ladyada's twitter status hadn't been updated in quite awhile but it was filled with entries such as:
That looked interesting as I recognized the entries as GPS strings. The National Marine Electronics Association (NMEA) has developed a specification that defines a GPS interface for the various hardware devices. NMEA also has its own version of essential GPS pvt (position, velocity, time) data. It is called RMC, the Recommended Minimum. These strings are prefaced with $GPRMC. Read all about it here.

Adafruit has a Botanicalls Twitter kit that allows plants to ask for human help via a Twitter message like "water me please" and "you over watered me". But plants don't have GPS, so I'm guessing that ladayada was messing with her Arduino GPS Shield and was logging position updates to Twitter.

I wonder where that pvt data points to? Using JTwitter, I grabbed ladayada's last status:


// Make a Twitter object
Twitter twitter = new Twitter("twitter-username","twitter-password");
// Print the lady's status
System.out.println(twitter.getStatus("ladyada"));
As expected, out pops:

$GPRMC,045519.000,A,4042.5917,N,0 7400.5417,W,0.68,290.51,160808,,* 17


In that string, the latitude is 4042.5917N. The longitude is 7400.5417W. Where is the hell is that?

Another Google search led me to a an interesting article on Sun's website, Working with Bluetooth and GPS. I grabbed the source code and parsed ladayada's string:


gps.datatypes.Record record = new gps.datatypes.Record();
System.out.println("recordtype="+
gps.parser.Parser.parse(twitter.getStatus("ladyada").getText(), record));
System.out.println("recordlat="+record.lattitude);
System.out.println("recordlon="+record.longitude);


And out pops:

recordlat=40.70986
recordlon=-74.009026

Ok, that's more like it. Somewhere in the good 'ol USA, NorthEast area. Stuff it into Google maps and sure enough, ladyada was stomping around in New York City.


What can I do with this new knowledge? I still have no app in mind but I have a few more tools to think about. And stick 'em in the shed for later use. That old shed is getting pretty full of tools for later. I better start oiling 'em before they all get rusty.

The src that I ref'd above needed some tweaking to convert the lat/lon strings to decimal degrees. I found another spot for the same code but was slightly diff in the parsing for GPRMC: Simple J2ME NMEA parser. Neither Parser was just what I needed, so I combined the two into the method below. This code is owned by Dominik Schmidt, I just modified it some.

/**
* NMEA-0183 Parser. Parses data sent by GPS receiver. As data is being
* transfered via XML to server, parsing consists in most cases of separating
* fields.
*
* @author Dominik Schmidt
*
* Copyright (C) 2006 Media Informatics Group (http://www.mimuc.de),
* University of Munich, Contact person: Enrico Rukzio
* (Enrico.Rukzio@ifi.lmu.de)
**/
public static int parse(String s, Record record)
throws UnsupportedTypeException, ParseException {

// Tokenizer to separate tokens
Tokenizer tokenizer = new Tokenizer(s);

// Type of record
int type;

try {
String token = tokenizer.next();

if (token.equals("$GPRMC")) {
type = TYPE_GPRMC;

token = tokenizer.next();
record.dateTimeOfFix = token.substring(0, 2) + ":"
+ token.substring(2, 4) + ":" + token.substring(4, 6);

record.warning = tokenizer.next().equals(Record.WARNING);

// orig version just stored lat/lon strings

// record.lattitude = tokenizer.next();
// record.lattitudeDirection = tokenizer.next();

// record.longitude = tokenizer.next();
// record.longitudeDirection = tokenizer.next();

// I used a pieces from second src to convert lat/long to decimal degrees

// Latitude
String raw_lat = tokenizer.next();
String lat_deg = raw_lat.substring(0, 2);
String lat_min1 = raw_lat.substring(2, 4);
String lat_min2 = raw_lat.substring(5);
String lat_min3 = "0." + lat_min1 + lat_min2;
float lat_dec = Float.parseFloat(lat_min3)/.6f;
float lat_val = Float.parseFloat(lat_deg) + lat_dec;

// Latitude direction
record.lattitudeDirection = tokenizer.next();

if(record.lattitudeDirection.equals("N")){
// do nothing
} else {
lat_val = lat_val * -1;
}

record.lattitude = lat_val + "";

// Longitude
String raw_lon = tokenizer.next();
String lon_deg = raw_lon.substring(0, 3);
String lon_min1 = raw_lon.substring(3, 5);
String lon_min2 = raw_lon.substring(6);
String lon_min3 = "0." + lon_min1 + lon_min2;
float lon_dec = Float.parseFloat(lon_min3)/.6f;
float lon_val = Float.parseFloat(lon_deg) + lon_dec;

// Longitude direction
record.longitudeDirection = tokenizer.next();

if(record.longitudeDirection.equals("E")){
// do nothing
} else {
lon_val = lon_val * -1;
}

record.longitude = lon_val + "";

record.groundSpeed = tokenizer.next();
record.courseMadeGood = tokenizer.next();

token = tokenizer.next();

record.dateTimeOfFix += "/" + token.substring(0, 2) + "."
+ token.substring(2, 4) + "." + token.substring(4, 6);

record.magneticVariation = tokenizer.next();

} else if (token.equals("$GPGGA")) {
type = TYPE_GPGGA;

// Time of fix
tokenizer.next();

// Lattitude
tokenizer.next();

// Lattitude direction
tokenizer.next();

// Longitude
tokenizer.next();

// Longitude direction
tokenizer.next();
record.quality = tokenizer.next();
record.satelliteCount = tokenizer.next();

// Ignore rest
}

// Type is not supported.
else {
throw new UnsupportedTypeException("Type " + token
+ " is not supported.");
}
}

// Parsing exception.
catch (NoSuchElementException e) {
throw new ParseException("Unexpected end of input.");
}
return type;
}

07 February 2008

BeanShell 01

I first ran across BeanShell (bsh) in early 2006 while looking for a way to better automate an Ant build. For the first few months, it was pure love. I couldn't get enough and I drove everyone at work nuts with my constant white board examples and endless emails. JSR 274 "The BeanShell Scripting Language" had recently been passed and I was sure that everyone would soon be loving Beany. Wikipedia says "BeanShell is an open source project and has been incorporated into many applications, such as OpenOffice.org, Apache Ant, BEA WebLogic Application Server, jEdit, and many others". Unfortunately, I haven't seen anything new written about bsh. The developer of BeanShell, Pat Niemeyer, hasn't updated the website not made a new release forever. I've sent Pat a few emails to ask about status but haven't received a reply. I guess the project is dead which is too bad because they're some really cool things that you can do with bsh.

So... what cool things can be done you ask? Patience grasshopper. Let's first get it installed. It'd be great if you'd review the "Getting Started" section of the bsh manual, but in a nutshell:

Grab the latest bsh jar which is currently 2.0b4. Either drop the BeanShell JAR file into your Java extensions folder or add it to your classpath:

Install as an extension. Place the bsh.jar file in your
    $JAVA_HOME/jre/lib/ext folder
Or add BeanShell to your classpath like this:
   nix: export CLASSPATH=$CLASSPATH:bsh-xx.jar
   windows: set classpath %classpath%;bsh-xx.jar

You can then run BeanShell in either a GUI or command line mode:
    java bsh.Console // run the GUI
or
    java bsh.Interpreter // run as text-only on the command line
or
    java bsh.Interpreter filename [ args ] // run a script file

It's also possible to call bsh from within native Java applications, to reach it in a remote server mode for debugging (very cool), to use it as a servlet, or even in an applet.

Let's check that it's installed and do some basic stuff. From a cmd line, type java bsh.Console and you should see the GUI start up and then have a workspace like the picture to the right. If not, check your classpath and try again.

I'm a hacker at heart so one of the first things that I did was to fire up the class browser (in the workshop, type classBrowser(); ) and started explorer classes in my classpath. This simple tool has helped me understand APIs and undocumented methods for many classes. Just select a package and then class and the browser will reveal the constructor(s), method(s), and field(s). Plus you can see the file system path of the class which has helped me several times when I had classes loaded multiple times.



There's much more to talk about but this entry is getting long. Next time, I'll discuss more Console commands and some bsh examples. In the mean time, download bsh and read thru the manual. I think you'll agree - BeanShell has so much potential.