Wednesday, December 30, 2009

java.sql.SQLException: No suitable driver

Since I've been re-building my pc since a blue screen of death last week, I got to spend a frustrating morning trying to figure out why i was getting the following exception in my Java app when making a connection to a 2005 SQL Server using the Microsoft jdbc drive SQLJDBC4 sqljsbc4.jar


java.sql.SQLException: No suitable driver
at java.sql.DriverManager.getConnection(DriverManager.java:545)
at java.sql.DriverManager.getConnection(DriverManager.java:193)
at com.medrisk.collections.server.DataServiceImpl.MRConn(DataServiceImpl.java:61)
at com.medrisk.collections.server.DataServiceImpl.getCaseWorkerList(DataServiceImpl.java:149)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)

A lot of postings out there on news groups all reprimand the poor developer who hits this message that either is class path is wrong, the jar is not in the path, or the connection URL is wrong. Developers howl that this is not the case... any they may be right! The matter-of-fact responses out there insist that this error only comes from the class path or url, but a hint on the Microsoft doc hints at another problem - your version of java.

First Step for you is to read that doc!

Here is what i had to do to fix this problem on my pc running eclipse 3.5

Open a command prompt and type

 java -version.

This will be your first clue, but also try typing:

C:\windows\system32\java -version

Note if the responses are different. We're trying to get version 6 of java installed and everything pointing to it.

Here was my response before i fixed it


C:\Documents and Settings\bsautner>java -version
java version "1.5.0_15"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_15-b04)
Java HotSpot(TM) Client VM (build 1.5.0_15-b04, mixed mode)


C:\Documents and Settings\bsautner>C:\windows\system32\java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)



turns out there was a java install on my pc when it was given back to me after the crash.

According to the Microsoft doc, you need to Java Version 6 or higher to use sqljdbc4.jar.

Download the latest version of the Java JDK to your pc and install it. As of this posting, here is where i got it:

http://java.sun.com/javase/downloads/index.jsp

Try running the java command above but from the install directory like this:

C:\Program Files\Java\jre6\bin\java -version

note if you got a higher version than before. You may now have the right version to use sqljdbc4.jar

Next, open eclipse and tell it to use that version of java by selecting the Window Menu - then Preferences. Expand Java And click on Installed JREs. Click Add and browse to C:\Program Files\Java\jre6.  Click finish and make sure jre6 is checked.

I'm hopeing that since you found this blog, you already have the jar files and connection classes, and i hope this solved your problem.

More samples and resources on using sqljdbc are available here

http://msdn.microsoft.com/en-us/library/aa342339.aspx

Wednesday, December 23, 2009

Authenticating an Android App to Google App Engine.

8/23/2010 update: This is a little out of date now. It works, but it makes you get a user id and password from your user. A lot of this code is now obsolete if you use account sync functions on android 2.2 and higher where you can get an auth token using the phone's credentials.

I posted an update to this article that has the code for using the phone's credentials here: http://javagwt.blogspot.com/2010/08/authenticating-android-to-app-engine.html



So you have a google app engine project running on myapp.appspot.com with all of your users data, and REST web services available so other apps can download xml from it over http - but now you want to download that XML to an app running on an android based phone AND provide google account credentials so users will download their data just like they're logged into your app.


I spent the last two days trying to put together samples of how to do this from all over the web. The challenge here is to have an Android Application call REST web services hosted on Google App Engine but to provide login account credentials so the App Engine code considers the request as logged in. If that makes sense to you, then you've come to the right place. I'm not sure if this is the most secure way to work with your app data, so please continue at your own risk. No warranty etc!

There are quite a few other people out there blogging about the same thing here, i found that each one of their posts were missing one critical piece of information. I'm posting here a class that is as straight forward as possible, you create an object with a username and password and from there you can load a URL from app engine with the authentication credentials you need.

The act of making http requests to an app engine site and providing credentials along with the request is to first get an auth token from google, which is a temporary string, then passing that token to the login page of your app, which in turn gives you an authentication cookie. Then add that cookie to the header of all of your future http requests.

Sounds simple enough....

I did learn that if you try to run this code using the android SDK in a plain java application with a reference to the SDK in your build path, you will get an error: Stub! whatever that means - what it means is that code using the android SDK needs to be ran in an android emulator.

I want to post the entire class for this in one piece, so please find it all at the bottom of this post. You can Create a new Android Project In eclipse, add a class called GoogleAuthentication and paste what i have below verbatim. Change the final string gaeAppBaseUrl at the top to point to your own app url yourapp.appspot.com

when you create an instance of the class, you pass the email and password to the constructor which gets the authkey and cookie. Sample of that is at the bottom of this post.

The GetLoggedIn() function is the only function here you don't need, but is an example of calling a REST web service URL that corosponds to a servelet running this code on the App Engine program Nimbits Data Historian.  When you load the url  http://app.nimbits.com/nimbits/Service/user  it returns false because you are not logged in when this code fires on the app engine:

public static User getUser() {
com.google.appengine.api.users.UserService u = UserServiceFactory.getUserService();
return u.getCurrentUser();
}

public static void checkLoggedIn() throws NotLoggedInException {
if (getUser() == null) {
throw new NotLoggedInException("False");
}
}


Our mission is to provide make the http request provide the header cookie so the above call returns true, and we have access to the serServiceFactory.getUserService();

If you look at the GetLoggedIn() function below, you'll see how i'm making the http request to that URL but adding the auth cookie needed in the header of the request that was created on contruction of the object.

Ok, here is the code:




import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;

public class GoogleAuthentication {
private final String gaeAppBaseUrl = "http://nimbits1.appspot.com/";
private final String gaeAppLoginUrl = gaeAppBaseUrl + "_ah/login";
private final String googleLoginUrl = "https://www.google.com/accounts/ClientLogin";
private final String service = "ah";
private Cookie authCookie = null;


//sample function that makes an http request and downloads
//the result providing the auth cookie.
public String GetLoggedIn() throws IOException
{

String result;
String destUrl = "http://app.nimbits.com/nimbits/Service/user";
URL url = new URL(destUrl);
URLConnection conn = url.openConnection ();
conn.addRequestProperty("Cookie",authCookie.getName() + "=" + authCookie.getValue());
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = rd.readLine()) != null)
{
sb.append(line);
}
rd.close();
result = sb.toString();
return result;
}

//Constructor creates the cookie
public GoogleAuthentication(String googleAccount, String googlePassword)
{
if (authCookie == null)
{

try {
String authToken = GetToken(googleAccount,googlePassword);
authCookie = getAuthCookie(authToken);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}


private String GetToken(String googleAccount, String googlePassword) throws MalformedURLException, ProtocolException, UnsupportedEncodingException, IOException
{
String token = null;
HttpURLConnection h = GetConnection(googleAccount,googlePassword);
token= extractAuthTokenFromResponse(h);
return token;
}


private Cookie getAuthCookie(String authToken) throws ClientProtocolException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
Cookie retObj = null;
String cookieUrl = gaeAppLoginUrl + "?continue="
+ URLEncoder.encode(gaeAppBaseUrl,"UTF-8") + "&auth=" + URLEncoder.encode
(authToken,"UTF-8");
HttpGet httpget = new HttpGet(cookieUrl);
HttpResponse response = httpClient.execute(httpget);
if (response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK ||
response.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_NO_CONTENT) {

if (httpClient.getCookieStore().getCookies().size() > 0) {
retObj= httpClient.getCookieStore().getCookies().get(0);
}

}
return retObj;

}

private HttpURLConnection GetConnection(String username, String password)
throws MalformedURLException, IOException, ProtocolException,
UnsupportedEncodingException {
HttpURLConnection urlConnection;
URL url = new URL(googleLoginUrl);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
StringBuilder content = new StringBuilder();
content.append("Email=").append(username);
content.append("&Passwd=").append(password);
content.append("&service=").append(service);

OutputStream outputStream = urlConnection.getOutputStream();
outputStream.write(content.toString().getBytes("UTF-8"));
outputStream.close();
return urlConnection;
}
private String extractAuthTokenFromResponse(HttpURLConnection urlConnection)
throws IOException {
int responseCode = urlConnection.getResponseCode();
System.out.println(responseCode);
StringBuffer resp = new StringBuffer();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = urlConnection.getInputStream();

BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream));
String line;


while ((line = rd.readLine()) != null) {

if(line.startsWith("Auth="))
{
resp.append(line.substring(5));

}

}

rd.close();


}
return resp.toString();
}
}


here is is the code in the main android class that makes the request and displays the result on the screen



public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String result = null;
TextView tv = new TextView(this);
GoogleAuthentication G;
try {
G = new GoogleAuthentication("email@gmail.com", "secretpassword");
result = G.GetLoggedIn();
} catch (IOException e) {
result = e.getMessage();
}

tv.setText(result);

setContentView(tv);
}


and voila

Thursday, December 3, 2009

Converting a Java Unix Epoch Time to a C# Date

I do a lot of coding that involves passing serialized objects between C# and Java based applications. When in Java I tend to work with dates as a long. In Java, a date can be represented as a long that is the number of milliseconds since the unix epoch which is defined as:

"Unix time, or POSIX time, is a system for describing points in time, defined as the number of seconds elapsed since midnight proleptic Coordinated Universal Time (UTC) of January 1, 1970, not counting leap seconds." (http://en.wikipedia.org/wiki/Unix_time)

If you have a date object in java, you just call the date.GetTime() function to return that value.

.Net does not work well with this and I just found myself coding happily along until i hit this and realized i had to write this handy little C# function i now share with the world:


  DateTime ConvertEpochToDate(long epochMS)
        {
            DateTime disco = new System.DateTime(1970, 01, 01, 00, 00, 00, 00);
            return disco.AddMilliseconds(Timestamp);
        }


You can see, we add the milliseconds i have to a new datetime object that has been initialized to the unix epoch


Thursday, November 19, 2009

Convert a Serializable Object to a Byte Array

Today's challenge is to take an object that  implements Serializable  (java.io.Serializable) and converts it to a byte array so it can be stored either in a table, file or sent over the wire. Not to hard, the whole idea is to make sure the object implements Serializable and the magic happens on the WriteObject call.


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;


public class util {
public static byte[] SerializeObject(Object o)
{
  byte [] buffer = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
buffer = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
  }

}

Web Services On Google App Engine



i've learned that adding a web service to your
app engine based java app is very easy using restlet and this tutorial
(coming from the .net world - rest is very cool!)
*
http://wiki*.*restlet*.org/docs_1.2/13-*restlet*/275-*restlet*/*252*-*restlet*.pdf


the rest of my question deals with how to provide the correct information
when calling a rest web service to correctly identify the user.

 When an outside app sends data in, or requests data out - they would need to
securely and correctly provide the google account the data is going to
belong to which would go into buidling a call to the user service on the app
engine side, so persistant data can be read and written to on the users
behalf.  In other words, persistant stored object with a app engine user
services user object stored in it would need to be accessed with a jdo query
providing a "user == u" param. If a user loggs in interactivly via the web
site on AE that's a no brainer since we make them log in to their google
account and use the user service.

My best solution so far is to provide users who register on my app engine
site several long key codes and say - ok if you pass me these codes my app
will figure out your gmail account from there inside the app engine code -
but i'd rather they just authenticate with some token the generate on their
end.


i completly agree i don't want to recreate any level of  
authentication - i want users to authenticate via google. Instead of trying  
to descibe what i'm developing - I think the stockwatcher sample is a great  
example for what i'm trying to do since my app will have many users each  
with their own persistant data. The users have logged into a web ui running  
on the app engine and used the web interface to add some data after logging  
in with their google account, just like the tutorial where the  
stockwatchter is modified to use the user service
http://code.google.com/webtoolkit/tutorials/1.6/appengine.html
I'd need to expose something like the AddStock Function in  
StockServiceImpl.java as a web method so other applications can add a stock  
to a users persistant datastore:
public void addStock(String symbol) throws NotLoggedInException {
checkLoggedIn();
PersistenceManager pm = getPersistenceManager();
try {
pm.makePersistent(new Stock(getUser(), symbol));

} finally {
pm.close();
}
}

The next step for me would be to allow other applications (other .net java  
etc) running on a pc, or web server etc to consume web services hosted on  
the app engine and, in our analogy, add a stock. Users need a way to insert  
data into persistant data stores connected to their google accounts from an  
app running outside the app engine environment. If i used Restlet to expose  
the above function as a REST Web Service, i don't see how getUser()  
function would work, or how the calling app would provide credentials in  
the code even if the user provided them in their client app.

Really, i'm ok with all User Interfaces i develop running on the app engine  
and users logging in normally, but my users will need things like schedule  
tasks, windows services etc all feeding records into my app and my  
direction was to have users send that data into their own persistant data  
store. Maybe that is the wrong direction, i could create a data structure  
where users are issued a key code that uniquly identified them to the app -  
i'd like users to be isolated from eachother using the app engine user  
service.