BUG Community

Welcome! Log In

Forums BUG SDK Basic Structure of an Application...

Subscribe to Basic Structure of an Application...  16 posts, 4 voices

Log in to reply to this topic
 
May 20, 2008 7:13pm
Img_missing_medium afritz 24 posts

Just received my bug today...

I'm an experience java developer and I usually work in IntelliJ so I apologize if the answer to any of my questions is Eclipse related. Working with Eclipse for this REALLY makes me appreciate how awsome IntelliJ is...

My main question is, what is the basic structure of a *REAL* application for the bug. The trivial examples in the wiki are all fine and dandy, but I'm having almost no luck extending them or combining them. I can't find anything that explains in detail the life cycle of a Bug app. Does such a document exist?

As a secondary question, I'm getting class def not found on bug sdk classes when I try to run in the virtual bug. For example I get:
java.lang.NoClassDefFoundError: com/buglabs/application/AbstractServiceTracker
on the testing app I'm trying to create now. I have:
import com.buglabs.application.AbstractServiceTracker;
at the top of my class. I basically copied that part from the One Button demo app. What am I missing? Is there some project setting needed to include the basic bug libs? I created the project using the "New Bug Project" button.

Thanks in advance to anyone that can set me right...
May 20, 2008 11:56pm
Medium Bug Labs team finsprings 268 posts

You need to list the dependencies of your application in its manifest (METE-INF/MANIFEST.MF). When you create an app via the wizard (and choose Dragonfly) you can pick the services you want then, providing you click on a real or virtual bug to populate the list.

Often you don’t know at that point which services you’re going to use though. Fortunately you can edit the MANIFEST.MF file whenever and add them in later. When you click on the MANIFEST.MF file in Eclipse you’ll get a tabbed window, the second tab of which is Dependencies. You can also go to the last tab on the right and just hand-edit it if you like.

In your specific example it complained about AbstractServiceTracker. The full name is com.buglabs.application.AbstractServiceTracker, so you must have com.buglabs.application in your manifest for it to be found at runtime of your app. Similarly if you use the camera you’ll need to add a dependency on com.buglabs.bug.module.camera.pub so that you can make use of the com.buglabs.bug.module.camera.pub.ICameraDevice interface.

May 21, 2008 8:22am
Medium Bug Labs team kschultz 107 posts

Finsprings is right, you CAN edit the manifest file to import the packages – but stuff like the AbstractServiceTracker will be included for you if you select the services in the new Project dialog box. Start up a virtual BUG, plug in some modules and then check the boxes. Such as for the LCD Module you click IModuleDisplay, AbstractServiceTracker will be included by default once you start using modules.

May 21, 2008 8:41am
Img_missing_medium afritz 24 posts

Ok, that is helpful.

I think the project I was using I had just created a new virtual bug and then pressed "Enter" which resulted in finish and not going to the dependency dialog. That’s my fault.

Is there any quantitative reason not to just include everything? I mean, I assume it will increase the size of the resulting jar a bit, but frankly MMC cards are dirt cheap so I couldn’t care less, at least during the development phases. I can always remove unused libs down the road.

May 21, 2008 9:01am
Medium Bug Labs team kschultz 107 posts

Yes, because the app depends on them, not in the import/#include sense but in the lifecycle sense. The services followed by the AbstractServiceTracker are needed to start the program.

If your app need A, B, and C – only when all 3 are present will it boot up. If you include all the services, it will never have them all, and will never run.

Generally the services you need to include are the ones that line up with the modules. Though in the future modules may provide more than one service, for now they all provide one main service. For example the GPS has the IPositionProvider service, and the LCD has the IModuleDisplay. So when you plug in the modules to the virtual BUG, those will be added to the list in the new Project wizard. Check off those two and then the AbstractServiceTracker will wait for those two modules to be put in before it runs.

If you have no dependencies, the app will startup immediately, but generally the only things I write that have no dependencies are new services, I imagine all the applications would have to consume at least one service to be of any use.

May 21, 2008 11:17am
Medium Bug Labs team jconnolly 285 posts

afritz
Ok, that is helpful.

I think the project I was using I had just created a new virtual bug and then pressed "Enter" which resulted in finish and not going to the dependency dialog. That's my fault.

Is there any quantitative reason not to just include everything? I mean, I assume it will increase the size of the resulting jar a bit, but frankly MMC cards are dirt cheap so I couldn't care less, at least during the development phases. I can always remove unused libs down the road.


Andrew,

This is due to the fact that Concierge OSGi is the BUG's application interface with the Java VM running on the bug. Applications are started and stopped according to the availability of resources that the application requires. This is a core OSGi concept and it took a little while to wrap my head around it myself.

For a little background, the original use-case for OSGi was as a communication gateway for househould devices and smart appliances. Applications that require, say, a telephone and a refrigerator are only really relevant if a refrigerator and telephone are available in the home environment. Similarly, in the case of the BUG, applications that require only the BUGview and BUGcam only make sense running when these two modules are available. The use-case for OSGi has since mushroomed, (IMHO) because of its ability dynamically load applications (in the form of bundles), while providing an important layer of abstraction between the VM and the actual Runtime environment, among many other features. If you're interested in furthering your understanding of OSGi, the wikipedia entry on OSGi links to some excellent references:

http://en.wikipedia.org/wiki/OSGi

Sorry if that's a cop out. :wink: I'll try to dig up some more documentation.
May 21, 2008 11:21am
Img_missing_medium afritz 24 posts

No problem. I’ll start there. I’ve always been in an enterprise/web environment so the mobile world is not as familiar as it could be. I look forward to more docs if they become available.

I think part of my frustration is woes with my bug hardware that I’m hopefully working out. But that is the cost of being an early adopter!

May 21, 2008 12:04pm
Img_missing_medium afritz 24 posts

So, I think I understand the basic model.

Is it possible to create an app that optionally uses a service but will still start if the optional service is not available.

A concrete example will help:

My first real app will be a race car telemetry app. This really doesn’t need the display, but IF the display is present I’d like to display the information real time.

I suppose you could separate these two function into two apps and make the base app an OSGi service provider. Is there a better way to do it or is that the OSGi way?

Andrew

May 21, 2008 12:28pm
Img_missing_medium afritz 24 posts

Hmm…. Or to counter my last statement, imagine the same applications. You have a OSGi service provider providing acceleration data converted all nicely for display. You have another OSGi service providing throttle position information (say based on the whatever module – can’t remember its name).

A desirable behavior for the front end is to figure out what telementry is available and display it. In this scenario, if a screen is available, the front end should start. It will depend on several back end components. If the A/D module isn’t available, that’s fine. I still want to start with the Acceleration module’s data being shown.

Thoughts?

May 21, 2008 12:55pm
Medium Bug Labs team kschultz 107 posts

I really want to explore that avenue as well, it didn’t come up over the winter when I was really writing my apps but I have since though of a lot of things that I could use it for.

My original idea was, the program should be aware of what other services are available and then decide what to run, in my case if there is a screen present log some stuff on the screen, if not just continue on.

However I think the more OSGi way of doing things would be to write the application you want, assuming it doesn’t have a display (or other optional modules you may or may not want), and then publish a service from your application exposing access to the data. So now you write a 2nd application, that requires the LCD module and your 1st application. The 1st application is running, and then you plug in an LCD module and the 2nd application starts up, granting you access to the extra features you wanted only when the LCD was plugging in. This also reduces the size of the 1st application, so only when the LCD is plugged in do you have the extra overhead.

I’m going to explore the first way eventually, but I have succesfully done the 2nd way already, if you look at the GPSUtilities app, it consumes some services and publishes new ones, and an example user of it is the GPSAlarmClock app. If you want help with that route I’d be glad to.

May 21, 2008 2:18pm
Medium Bug Labs team jconnolly 285 posts

afritz

I suppose you could separate these two function into two apps and make the base app an OSGi service provider. Is there a better way to do it or is that the OSGi way?


Great question. The answer is (thankfully) yes. To do this, you'll need to override the canStart() method in your XXXServiceTracker class (which extends AbstractServiceTracker).

The current implementation is "dumb" in that it only starts your bundle once each and every service dependency is satisfied. Check it out (in eclipse Ctrl+Shift+T, type in AbstractServiceTracker, Enter), lines 157 to 177:

/**
* Determines if the application can be started.
*
* @returns true when the application is not running and there's a handle
* for each service.
*/
protected boolean canStart() {
if (hasStarted()) {
return false;
}

Iterator servicesIter = services.iterator();

while (servicesIter.hasNext()) {
if (servicesMap.get((String) servicesIter.next()) == null) {
return false;
}
}

return true;
}


It checks to make sure each service is not null, then starts your bundle. You can override the canStart method to be much smarter, but you'll have to check to make sure the services you want are not null before you use them (or handle the NullPointerException in a smart manner). I think I may write an app that does just this, perhaps modifying the MotherBUGTweetNTwitch app to be headless if no LCD, and prompt for login credentials otherwise.

Great point! :D
May 21, 2008 4:09pm
Medium Bug Labs team jconnolly 285 posts

jconnolly

It checks to make sure each service is not null, then starts your bundle. You can override the canStart method to be much smarter, but you'll have to check to make sure the services you want are not null before you use them (or handle the NullPointerException in a smart manner).


Unfortunately, this is not quite true. Overriding the canStart() method inherited from the AbstractServiceTracker class is not enough to get your desired result, no matter how it is implemented.

There is the problem within the bundle Activator, and its ServiceTracker Filter. I've tried fooling the ServiceTracker Filter to give it null, empty Filter, etc, to no avail. The alternative is to track your services by hand, which is essentially what we want to do anyway.

The way the Dragonfly Plugin for Eclipse works by default is to give you service tracking functionality automagically. This happens if you select services required for your Application in the App Creation Wizard. You can either delete the generated service tracker, or manually specify which services you're concerned with.

This means little without the code, which I'll reply with once I get an application working that does exactly what we're talking about. :idea:
May 21, 2008 4:13pm
Img_missing_medium afritz 24 posts

Well, on the way to lunch something else occurred to me…

Unless I’ve missed something, there is nothing to stop my from building a generic java app, building a jar, SCPing it over and then launching it manually (or via the init process, or via a OSGi app that just starts it from the menu, etc… you get the idea). Said program should be able to consume OSGi services without being an OSGi service itself so it could use the bug, but would exist outside the OSGi lifecycle (which would be nice – I’m weary of frameworks – I’ve been burned/locked in one to many times in my life).

I like this approach much better from a dedicated appliance point of view (my target in the end). It gives you alot more direct control over start up, shutdown and watchdog. Maybe OSGi has a way to handle those scenarios?

May 21, 2008 4:27pm
Medium Bug Labs team jconnolly 285 posts

afritz
Well, on the way to lunch something else occurred to me...

Unless I've missed something, there is nothing to stop my from building a generic java app, building a jar, SCPing it over and then launching it manually (or via the init process, or via a OSGi app that just starts it from the menu, etc... you get the idea). Said program should be able to consume OSGi services without being an OSGi service itself so it could use the bug, but would exist outside the OSGi lifecycle (which would be nice - I'm weary of frameworks - I've been burned/locked in one to many times in my life).

I like this approach much better from a dedicated appliance point of view (my target in the end). It gives you alot more direct control over start up, shutdown and watchdog. Maybe OSGi has a way to handle those scenarios?


Nothing at all to stop you! The OSGi runtime and BUG APIs are intended as a matter of convenience, to ease into using the hardware. But you are in no way confined to using our implementation. The JNI code is there (on CVS) to interact with the driver, and you can pick which portions of the BUG API that would be applicable to your particular standalone application. In fact, you can find an ARM distribution of J2SE or compile it from source. That is, if Java is the language you even wish to choose.

Anyway, there are tons of things you can do with the hardware, but IMHO abandoning OSGi as your Application manager may have its advantages and disadvantages. For one, many of the applications written for the bug up on BUGnet are in the form of OSGi bundles. You could use the code as a starting point for your own standalone apps, but it would be tedious.

Your BUG is your own though, and the rootfs including OSGi, BUG API, JNI and all the other bells and whistles may be rewritten to your MMC card very easily. I know I look forward to hacking around, both inside and outside the framework, and it's nice to know that I can return to factory features with a few fdisk and tar commands.
May 21, 2008 6:08pm
Medium Bug Labs team jconnolly 285 posts

jconnolly
This means little without the code, which I'll reply with once I get an application working that does exactly what we're talking about. :idea:


Ok, I've whipped something together that does what we've discussed. Namely, if it gets an LCD module and the com.buglabs.bug.module.lcd.pub.IModuleDisplay service is available, it will render the output to a GUI, otherwise it just prints to console. The code is below, and it's a bit lengthy. I'll talk to our sysadmin and web-dev team about getting some syntax highlighting together to make this stuff more readable.

I'm going to write up a wiki and fully comment the code and upload it to BUGNet for a good reference point. I have a feeling that this type of selective service referencing will be useful to our community in the near future.

For now, to test this, simply create a new BUG Project, do not select any services required for the application (resulting in a Dragonfly project with only an Activator class generated). Replace the contents of your Activator class with that below.

Try running the app first with the Virtual BUG without any modules attached. Among the verbose OSGi output, you should see the time outputted:
...
STARTING file:/home/jconnolly/localapps/dev/eclipse/plugins/com.buglabs.dragonfly.bug.kernel_1.0.0.5/kernel/com.buglabs.bug.emulator.base.jar
Tracker found service: com.buglabs.bug.base.pub.ITimeProvider
Time: 080521-16_52_35
...


Then try adding the LCD module and a GUI will pop up with the date/time in a Label on the Frame. Simple, but it demonstrates how to handle services as they become available on the fly from OSGi.

Enjoy, and I'll update this thread when more detailed documentation is available.


package test;

import java.awt.Frame;
import java.awt.Label;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import com.buglabs.bug.base.pub.ITimeProvider;
import com.buglabs.bug.module.lcd.pub.IModuleDisplay;
import com.buglabs.util.ServiceFilterGenerator;

/*
* This Activator was automatically generated by the Dragonfly SDK provided by BugLabs.
* Only the start and stop methods are
*/
public class Activator implements BundleActivator, ServiceTrackerCustomizer {

/*
* A handle to this Bundles OSGi context
*/
private BundleContext context;

/*
* A handle to the IModuleDisplay service, should it become available.
*/
private IModuleDisplay display;

/*
* A handle to the IModuleDisplay service, should it become available.
* The ITimeProvider service is made available as part of the BUGbase
* bundles, so this should always be available.
*/
private ITimeProvider timeProv;

/*
* A Filter by which the addingService method will be called,
* according to the class names present in the Filter.
*/
private Filter filter;

/*
* Simple data structure to hold the services that may
* be required for this application bundle.
*/
private ArrayList serviceList = new ArrayList();

private ServiceTracker st;

/*
* Default methods required to be overridden for BundleActivator
*
*
*/

/**
* Called when bundle is set to active by OSGi
* @param context provided by OSGi
*/
public void start(BundleContext context) throws Exception {
this.context = context;
System.out.println("Application test in start");
initServices();
filter = context.createFilter(ServiceFilterGenerator
.generateServiceFilter(serviceList));
st = new ServiceTracker(context, filter, this);
st.open();

}

/**
* Called when bundle is set to inactive (stopped) by OSGi
* @param context provided by OSGi
*/
public void stop(BundleContext context) throws Exception {
st.close();

}

/*
* Methods to be overridden for ServiceTrackerCustomizer class
*
*
*
*/

/**
* Called when a service matching something in the Filter for this Activator's
* ServiceTracker object is made available by OSGi
*
* @param reference is a reference to the service that was made available
* when this method is called
*/
public Object addingService(ServiceReference reference) {
//get handle to services I'm interested in

String objClassName = ((String[]) reference
.getProperty(Constants.OBJECTCLASS))[0];

System.out.println(" Tracker found service: " + objClassName);
if (objClassName.endsWith("ITimeProvider")) {
timeProv = (ITimeProvider) context.getService(reference);
doHeadlessStuff();
}

if (objClassName.endsWith("IModuleDisplay") && timeProv != null) {
display = (IModuleDisplay) context.getService(reference);
createGUI();

}

return null;

}

/**
* Called by OSGi Framework when a service matching something in the Filter for this Activator's
* ServiceTracker object is modified in some way
*
* @param reference is a reference to the service that was modified
* when this method is called
*/
public void modifiedService(ServiceReference reference, Object service) {
// TODO Auto-generated method stub

}

/**
* Called by OSGi Framework when a service matching something in the Filter for this Activator's
* ServiceTracker object is modified in some way
*
* @param reference is a reference to the service that was modified
* when this method is called
*/
public void removedService(ServiceReference reference, Object service) {
System.out.println("Service became unavailable: "
+ reference.getBundle().getLocation());

}

/*
*
*
* My own logic
*
*
*/

/**
* Creates a Frame GUI. Called when the IModuleDisplay service becomes available
* as determined in the addingService method. The GUI just prints the time (once)
* when the IModuleDisplay service is available.
*/
private void createGUI() {
Frame frame = display.getFrame();
SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd-HH_mm_ss");
frame.add(new Label(formatter.format(timeProv.getTime())));
frame.setSize(400, 400);
frame.setVisible(true);

}

/**
* Prints out time to console, demonstrating some logic for when the IModuleDisplay
* isn't (or even IS) available.
*/
private void doHeadlessStuff() {
SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd-HH_mm_ss");
String time = formatter.format(timeProv.getTime());
System.out.println("Time: " + time);

}

/**
*
* @return a List of the Services that may be used by this bundle.
*/
public ArrayList getServiceList() {
return serviceList;
}

/**
* Adds the fully-qualified class name for each of the Services that this bundle
* may require.
*/
void initServices() {
getServiceList().add("com.buglabs.bug.module.lcd.pub.IModuleDisplay");
getServiceList().add("com.buglabs.bug.base.pub.ITimeProvider");

}

}
May 22, 2008 10:33am
Medium Bug Labs team jconnolly 285 posts

jconnolly
Enjoy, and I'll update this thread when more detailed documentation is available.


Wow,syntax highlighting would be really handy. That post fell down the ugly tree and hit every branch on the way down.

http://bugcommunity.com/bugzilla/show_bug.cgi?id=184
Log in to reply to this topic
Forums BUG SDK Basic Structure of an Application...

Powered by Community Engine