A long road indeed.

Came across this blog post from last year. Found the stack trace mesmerizing, and more than a little disturbing.

The stack trace for a J2EE web app call — from the initial web server request to the final database call.

Just look at it! And that’s just the one way trip.

jtrac-callstack1

Introducing Antair Headers

Today, we released a new tool for BlackBerry users. We call it Antair Headers, and it allows you to view the full e-mail headers of any e-mail message on your BlackBerry.

We’re making this application free of charge for everyone. Compliments of Antair. Enjoy.

headers

Heavy Rain

heavyrain

Heavy Rain, from Quantic Dream, is, quite simply, the best video game ever made.

The visuals are absolutely stunning.

The control scheme and interaction is perfectly fluid; throwing everything that came before out of the window.

The attention to detail, from character gestures to interior design, is superb.

The amount of influence your choices have on the flow of the story is unprecedented in an adventure game.

Most importantly, the story is very deep, extremely emotionally engaging, and, without compromise, written for adults. This isn’t a game for the little ones. Firstly, they won’t get anything out of it, and secondly, there’s some nudity and other adult themes. But the adults will love it. Parents with small kids will especially feel the impact of the story line.

Forget “good for a video game”. Calling it a video game would be an insult. It is a brilliant, engaging, completely satisfying experience.

Heavy Rain is what all future adventure games should strive to be. Anything less is no longer adequate.

Debugging BlackBerry Applications: A Simple Debug Console Class

Debugging a BlackBerry application can be done on a simulator, when the bug permits that sort of thing, or on the device itself. If you’re in a situation where you must debug your code while it runs on a real device, your can sometimes take advantage of the tethering debugger provided by the JDE; connecting the device to the PC via a USB cable, and then hoping everything is stable enough for you to catch a breakpoint and find your bug.

This is all fine and good, but there are times when you find yourself in a situation where neither of these techniques gives good results.

At Antair, during development of our BlackBerry applications, we often include a debug console in the dev builds of our apps.

With the debug console, all debug output hits the output screen when the dev build is running in the simulator, and when the dev build runs on a physical test device, the debug output is automatically persisted and is available to view on a dedicated screen that can be pulled up via a menu option or button.

The code below is a stripped-down version of the debug console we use at our company.

Using the console is easy. Include the code in your project, fill out the PERSISTENCE_GUID for your application, set the TAGID string to identify your application name in the debug logs, and when you want to output a debug statement, simply call Debug.print(“Something happened here…“);

Each line of the debug output, both in the output window when running in a simulator, and in the debug console screen when viewed on a device, will contain your debug message, the thread number on which the call was made (useful for thread/ui debugging), and the date/time of the log statement, with a millisecond timestamp for performance profiling.

To view the debug console on a real device, simple put in a call to pushScreen(new AntairLogScreen()). The screen has a built-in menu item to clear the persisted log messages, and will dismiss itself like a regular application screen.

If you’re running the RIM compiler preprocessor to switch between development, QA, and production builds, you can simply put in a call to set Debug.ENABLED = false for everything but the development builds, and the debug console will be there when you need to debug and go away quietly when you don’t need it.

The code is below.

Cheers!

Andrey.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// -----------------------------------------------------------------------------
//
// Antair Debug Log (for the BlackBerry API)
// Copyright (c) 2005 - 2010, Antair Corporation. All Rights Reserved.
// http://www.antair.com
//
// BlackBerry is a registered trademark of Research in Motion.
//
// -----------------------------------------------------------------------------
 
package com.antair.examples.debug;
 
import net.rim.device.api.i18n.SimpleDateFormat;
import java.util.Date;
import net.rim.device.api.collection.util.BigVector;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.Persistable;
 
final class Debug implements Persistable
{
    final static boolean ENABLED = true;
    final static String TAGID = "MY_PROJECT";
    final static long PERSISTENCE_GUID = /* YOUR OWN PERSISTENCE GUID */;
 
    private BigVector _messages = new BigVector();
 
    static String print(String str)
    {
        if ( Debug.ENABLED )
        {
            StringBuffer sb = new StringBuffer();
            sb.append(TAGID);
	    sb.append("\n");
            sb.append(Thread.currentThread().toString());
	    sb.append("\n");
            sb.append(new SimpleDateFormat("MM/dd/yy HH:mm:ss:SSS").format(new Date()));
	    sb.append("\n");
            sb.append(str); sb.append("\n");
            str = sb.toString();
 
            System.out.println(str);
            System.out.flush();
 
            Debug d = load();
            d._messages.addElement(str);
            save(d);
        }
 
        return str;
    }
 
    static BigVector getPersistedMessages()
    {
        return load()._messages;
    }
 
    static void clearPersistedMessages()
    {
        save(new Debug());
    }
 
    private static Debug load()
    {
        Debug d = null;
 
        try
        {
            PersistentObject po = PersistentStore.getPersistentObject(Debug.PERSISTENCE_GUID);
 
            synchronized(po)
            {
                Object obj = po.getContents();
                d = (obj == null) ? new Debug() : (Debug)obj;
            }
        }
 
        catch ( Exception e )
        {
            d = new Debug();
        }
 
        return d;
    }
 
    private static void save(Debug d)
    {
        try
        {
            PersistentObject po = PersistentStore.getPersistentObject(Debug.PERSISTENCE_GUID);
 
            synchronized(po)
            {
                po.setContents(d);
                po.commit();
            }
        }
        catch ( Exception e )
        {
        }
    }
}
 
final class ClearAntairLogScreenMenuItem extends MenuItem
{
    ClearAntairLogScreenMenuItem(int position)
    {
        super("Clear Log", position, 0);
    }
 
    public void run()
    {
        Debug.clearPersistedMessages();
    }
}
 
final class AntairLogScreen extends MainScreen
{
    AntairLogScreen()
    {
        super(MainScreen.DEFAULT_CLOSE|MainScreen.DEFAULT_MENU);
 
        StringBuffer text = new StringBuffer();
 
        BigVector logItems = Debug.getPersistedMessages();
 
        for ( int i = 0 ; i < logItems.size() ; ++i )
        {
            text.append((String)logItems.elementAt(i) + "\n");
        }
 
        add(new RichTextField(text.toString()));
    }
 
    protected void makeMenu ( Menu menu, int instance )
    {
        menu.add(new ClearAntairLogScreenMenuItem(100000));
    }
}