Always Challenge Your Assumptions

Always Challenge Your Assumptions

I spent the better part of the weekend trying to fix a bug that was perplexing me and arresting my progress on a new Blackberry project.

Not that you particularly care, but it had to do with how Blackberry creates “tunnels” (connections) to communicate over the internet. There are about a dozen different ways to connect (BIS, BES, Direct/TCP, WiFi, WAP, WAP2, in HTTP and Sockets variations), and if you don’t hold your tongue ** just right ** your connections won’t happen.

Anyway, almost all of my connections were working perfectly. After all, this wasn’t my first Blackberry project and I was using a library I had developed and used on other projects.

But I had one call that was failing every time I tried to run it on a real device (and maddeningly, working perfectly under the simulator).

What was going on? I mean, I’ve used the library before with no issues whatsoever.

But I hadn’t used it in ** just ** the way I was now using it; and there was the rub.

As it turned out, I was using a call in the library that I had never used before.

And because of this, there was a place in the code where I had neglected to correctly determine the type of connection I needed to make (again with the BIS, BES, Direct/TCP, yada, yada, yada) and so my connections were failing on a real device.

It only took me two days to realize that I needed to challenge my assumptions that the library was right… and if I had done what I should have done originally (namely, examine directly the call in question) I would have had more time to myself and my family this weekend.

For the more technically inclined, I present the code I usually use to create internet connections for Blackberry apps below:

public static final int CONNECTION_DEFAULT = 0;
public static final int CONNECTION_BIS = 1;
public static final int CONNECTION_BES = 2;
public static final int CONNECTION_TCPIP = 3;
public static final int CONNECTION_WIFI = 4;
public static final int CONNECTION_WAP = 5;
public static final int CONNECTION_WAP2 = 6;

public static HttpConnection makeHttpConnection(String url,
HttpHeaders requestHeaders,
byte[] postData,
int connType,
String requestMethod,
boolean uploadData)
{
HttpConnection conn = null;
OutputStream out = null;

if (StringUtilities.startsWithIgnoreCase(url, "www.")) {
url = "http://" + url;
}

try {
if (url.indexOf(";deviceside=") == -1) {
switch (connType) {
case CONNECTION_BES:
url = url + ";deviceside=false";
break;
case CONNECTION_BIS:
url = url + ";deviceside=false;connectiontype=mds-public";
break;
case CONNECTION_TCPIP:
url = url + ";deviceside=true";
break;
case CONNECTION_WIFI:
url = url + ";interface=wifi";
break;
case CONNECTION_WAP2:
url = buildWAP2(url);
break;
}
System.out.print("\n****\nThis is what we're trying to open: " + url);
}

conn = (HttpConnection) Connector.open(url, Connector.READ_WRITE);
try {
if (1==0) {
ConnectionFactory connFact = new ConnectionFactory();
TransportDescriptor[] transports = TransportInfo.getAvailableTransports();
System.out.println( "Available transports: " + transports.length );
for ( int i = 0; i < transports.length; i++ ) { TransportDescriptor t = transports[ i ]; int type = t.getTransportType(); boolean hasCoverage = TransportInfo.hasSufficientCoverage( type ); System.out.println( "Type: " + TransportInfo.getTransportTypeName( type ) ); System.out.println( "Coverage: " + hasCoverage ); System.out.println( "Cid: " + t.getCid() ); System.out.println( "Uid: " + t.getUid() ); System.out.println( "\n" ); } int preferredTransportTypes[] = {TransportInfo.TRANSPORT_BIS_B, TransportInfo.TRANSPORT_TCP_WIFI, TransportInfo.TRANSPORT_MDS, TransportInfo.TRANSPORT_WAP2, TransportInfo.TRANSPORT_TCP_CELLULAR,}; ConnectionDescriptor connDesc; connFact.setPreferredTransportTypes(preferredTransportTypes); connDesc = connFact.getConnection("http://myserver.gr"); if (connDesc != null) { conn = (HttpConnection) connDesc.getConnection(); final int code = conn.getResponseCode(); System.out.println("Code: " + code); } else { System.out.println("No connection"); } } } catch (Exception e) { System.out.println("Exception: " + e.getClass().toString() + " -> " + e.getMessage());
}

if (requestHeaders != null) {
String referer = requestHeaders.getPropertyValue("referer");

boolean sendReferrer = true;

if (referer != null &&

StringUtilities.startsWithIgnoreCase(referer, "https:") &&

!StringUtilities.startsWithIgnoreCase(url, "https:"))
{
sendReferrer = false;
}

int size = requestHeaders.size();
for (int i = 0; i < size;) {
String header = requestHeaders.getPropertyKey(i);
if (!sendReferrer && header.equals("referer")) {
requestHeaders.removeProperty(i);
--size;
continue;
}

String value = requestHeaders.getPropertyValue(i++);
if (value != null) {
conn.setRequestProperty(header, value);
}
}
}

conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
conn.setRequestMethod(requestMethod);

if (requestMethod.equalsIgnoreCase("PUT") || requestMethod.equalsIgnoreCase("POST")) {

if (postData!=null) {
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, String.valueOf(postData.length));
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
out = conn.openOutputStream();
out.write(postData);
out.flush();
}
}
}
catch (IOException e1) {
System.out.println("makeHttpConnection: " + e1.toString());
close(conn, null); // Close the connection
conn = null;
}
finally {
close(null, out); // Close the output, but keep connection open
}

return conn;
}

public static int getCoverageBasedConnectionType() {
int preferredTransportTypes[] = {TransportInfo.TRANSPORT_BIS_B, TransportInfo.TRANSPORT_TCP_WIFI, TransportInfo.TRANSPORT_MDS, TransportInfo.TRANSPORT_WAP2, TransportInfo.TRANSPORT_TCP_CELLULAR,};
ConnectionFactory cf = new ConnectionFactory();
cf.setPreferredTransportTypes(preferredTransportTypes);
ConnectionDescriptor cd = cf.getConnection("http://www.google.com");
if (cd!=null) {
TransportDescriptor transportUsed = cd.getTransportDescriptor();
int _transportMode = transportUsed.getTransportType();
System.out.println("\n\n_____\n\nTransportType: " + _transportMode + "\n\n_____\n\n");
switch (_transportMode) {
case TransportInfo.TRANSPORT_BIS_B:
System.out.println("Transport: BIS");
return CONNECTION_BIS;
case TransportInfo.TRANSPORT_MDS:
System.out.println("Transport: MDS");
return CONNECTION_BES;
case TransportInfo.TRANSPORT_TCP_CELLULAR:
System.out.println("Transport: Cell (Direct TCP)");
return CONNECTION_TCPIP;
case TransportInfo.TRANSPORT_TCP_WIFI:
System.out.println("Transport: Wi-Fi");
return CONNECTION_WIFI;
case TransportInfo.TRANSPORT_WAP:
System.out.println("Transport: WAP");
return CONNECTION_WAP;
case TransportInfo.TRANSPORT_WAP2:
System.out.println("Transport: WAP2");
return CONNECTION_WAP2;
default:
System.out.println("Transport: WAP");
return CONNECTION_TCPIP;
}
}

return CONNECTION_TCPIP;
}

static String buildWAP2(String url) {
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.findRecordsByCid("WPTCP");
String uid = null;

for(int i=0; i < records.length; i++)
{
//Search through all service records to find the
//valid non-Wi-Fi and non-MMS
//WAP 2.0 Gateway Service Record.
if (records[i].isValid() && !records[i].isDisabled())
{

if (records[i].getUid() != null && records[i].getUid().length() != 0)
{
if ((records[i].getUid().toLowerCase().indexOf("wifi") == -1) &&
(records[i].getUid().toLowerCase().indexOf("mms") == -1))
{
uid = records[i].getUid();
break;
}
}
}
}

if (uid != null)
{

//open a WAP 2 connection
return url + ";ConnectionUID=" + uid;
}
else
{return "";}
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s