Skip to main content

APP DEVELOPERS! -- Guidelines regarding separation of OCAP extension code

8 replies [Last post]
greg80303
Offline
Joined: 2008-07-03
Points: 0

When authoring applications designed to be deployed on a variety of devices supporting different combinations of OCAP extensions (DVR, HomeNetworking, FrontPanel, etc), it is important to structure your app code in a way that will not cause class loading errors. There is no perfect solution to this problem because the Java Virtual Machine specification gives implementers the freedom to perform classloading as aggressively as they wish. However, it seems likely that most embedded VM implementations will try to be as lazy as possible with regard to classloading to avoid the speed and memory implications of loading classes that will never be used.

There is, however, one aspect of classloading that can not be avoided -- class file "verification". Any class that is loaded by the JVM must be verified as described in Section 4.9 of the JVM Specification (http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html). One step of the verification process is known as "data-flow analysis". This process checks the byte code for every method defined in the class for things like stack overflow/underflow, valid local variable assignments, and valid JVM instruction codes. For our purposes, we must focus on the "valid local variable assigment" task.

We will use the OCAP DVR extension for the purposes of this discussion. On devices that do not support DVR functionality, the OCAP DVR classfiles will most likely not be present in the classpath and any attempt by an application to classload a DVR class file will result in a NoClassDefFoundError being thrown. The OCAP specification indicates that application shall rely on the presence of the "ocap.api.option.dvr" Java system property to determine whether or not a given OCAP extension is present at runtime. Applications that use a common code base to deploy on both DVR and non-DVR devices should take care to structure the code so as to avoid incidental classloading of DVR classes during the data-flow analysis phase of class file verification. Take a look at this example:



interface A
{
    public void foo();
}
class B implements A
{
    public void foo() {}
}
class C implements A, org.ocap.shared.dvr.RecordedService
{
    public void foo() {}
    // RecordedService method implementations here...
}
class MyApp
{
    private A m_a;
    public void test()
    {
        A a = new B();      // B is classloaded during verification
                            // of MyApp because types on each side
                            // of the assignment are different, but B
                            // itself is not verified until this code
                            // is actually executed
        if (isDVRAvailable)
        {
            A dvr_a = new C();  // C is classloaded during verification
                                // of MyApp because types on each side of
                                // the assignment are different.  Fails to
                                // load RecordedService DVR class
        }
        B b = new B()       // B would not be classloaded during
                            // verification of MyApp because types
                            // on each side of the assignment are the same
        if (isDVRAvailable)
        {
            m_a = new C();      // C would not be classloaded during verification
                                // of MyApp because only local variable
                                // assignments are checked
        }
    }
}

All of the verification indicated above takes place during classloading of class MyApp which is a class that is used for both DVR and non-DVR devices. As you can see, depending on your use of assignments to local variables, you can accidentally trigger a classload of a DVR class even though the code will never actually get executed.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
greg80303
Offline
Joined: 2008-07-03
Points: 0

bump

greg80303
Offline
Joined: 2008-07-03
Points: 0

I have also added this information to our public Wiki here:
https://community.cablelabs.com/wiki/display/OCORI/Separating+extension+...

suntec
Offline
Joined: 2010-10-13
Points: 0

It's good to know for me because I have been experiencing the NoClassDefFoundError for LightweightTriggerHandler class since the early version of Buckeye because I build the RI stack using the separate build (ie. build.ocap.DVR_ENABLED=false, build.ocap.HN_ENABLED=true).
Without a clear solution for this boot-up issue, we introduced the work-around to add the DVR stub classes in the JVM's class path.
Now I got to know this is not a stack issue but a application issue.
In fact, there is another reason why we introduced the above work-around.
I'd like to add this issue to the guidelines also.
I found some applications tries to load or use "org.davic.media.MediaTimeEvent/MediaTimeEventControl/MediaTimeEventListener" classes without determining whether the DVR extension is supported. Even though the name space "org.davic.media" does not include any DVR-releated keyword, these classes should be defined only in the DVR extension. (for details, refer to OCAP DVR spec 7.2.1.3 OCAP DVR API)
During using OCAP RI stack, some mismatched configuration regarding these classes is found.
These three MediaTimeEvent related classes are included in dvr.filelist which is correct, but the ocap-base-stub.jar instead of the ocap-dvr-stub.jar contains the stub classes which is not correct.

cpratt
Offline
Joined: 2008-12-18
Points: 0

Regarding the org.davic.media files and stubs:

While it's true that there are no non-DVR/HN use cases for org.davic.media.MediaTimeEvent/MediaTimeEventControl/MediaTimeEventListener, and section 7.2.1.3 of DVR I06 mentions org.davic.media.MediaTimeEventControl by name, all of org.davic.media is included with base OCAP (see section 13.4.7/"DAVIC 1.4.1, Part 9 Packages" of the OCAP 1.1.3 specification). So it's correct that these stubs are present in the base stub file in the RI (ocap-base-stub.jar) and the OCAP base stubs within the ocap_114_060310_final_src.zip distributed at http://www.cablelabs.com/opencable/ocap/opencable_platform_downloads.html).

Presumably, it's desired that DAVIC incorporation is done at the package level. And since some of the classes/interfaces in org.davic.media are necessary for base OCAP (AudioLanguageControl, MediaLocator, etc), the whole package is incorporated into the base specification.

As is always the case, applications should not depend upon class loading to determine if an extension is present. The presence of ocap.api.option.dvr determines if the extension is present and the value of ocap.api.option.dvr and ocap.api.option.dvr.update determines which version is present (e.g. "1.0"/"I06").

suntec
Offline
Joined: 2010-10-13
Points: 0

I think that section 13.4.7 is just informative and what classes in the package are include/excluded OR extended/modified should be refered by MHP/GEM spec.
According to MHP 1.0.3 section 11.4.2.5.4, it defines the required media controls for broadcast profile but does not include org.davic.media.MediaTimeEventControl.
Instead ETSI TS 102 817 (GEM Recording Ext) section 7.2 defines the required JMF controls to present the recordable streams which includes MediaTimeEventControl.
In general, the stubs are considered as the dummy classes representing the real implemented classes. In this aspect, I think the stubs should contain the class list corresponding to the requirement.

cpratt
Offline
Joined: 2008-12-18
Points: 0

True - this is an informative section, and the MediaTimeEventControl is only mentioned in ETSI TS 102 817. I will try to bring this up with the Cablelabs spec team to see if they want to modify the stub distribution.

I guess what I want to ensure is that there isn't a goal to determine the presence (or non-presence) of an extension based on the presence of classes. e.g. an OCAP implementation may very well contain org.ocap.dvr and org.ocap.shared.dvr classes but not define ocap.api.option.dvr and ocap.api.option.dvr.update. An implementation shouldn't draw any conclusions from the presence of these classes (or particular DAVIC classes).

howardteece
Offline
Joined: 2010-06-17
Points: 0

Can you make this sticky and of high importance?
Also can you change the title, or add a bit, as this really answers the 'Why do I get a Class Not Defined exception when I don't even use the class?' question that crops up every two or three months.
Thanks for the answer, by the way.

greg80303
Offline
Joined: 2008-07-03
Points: 0

Unfortunately, this forum does not allow us to make "sticky" posts :(

I'll try to bump this post occasionally to keep it near the top