JavaCardPlatformIntegration

Contents

Java Card Modules Architecture and Integration

The Java Card modules work with the Java Card Reference Implementation[1] (RI). They are designed to make it relatively simple to integrate other Java Card SDKs which deploy to physical cards. This document discusses the architecture of these modules, and what needs to be done to integrate a new SDK/device.

Important: As of NetBeans 6.9, all APIs in the Java Card modules are 'friend' APIs. While no large backward-incompatible changes are anticipated, they are not yet official APIs.

Overall Design

The Java Card modules provide the following things:

  • An API for installed Java Card Platforms. JavacardPlatform extends the Java Project API's JavaPlatform [2] class with a few Java Card specific extensions, mainly
    • A method which can take a projects kind (see below) and return a different boot-classpath (used for code completion and compilation) depending on the kind of project
    • A Cards object which is a factory for Card objects. A Card is a device associated with a platform/SDK.
    • Validity - a Java Card platform can specify that it is not valid - i.e. misconfigured
  • A Java Card project-type - an implementation of Project[3] specific to Java Card. As with other projects, most relevant objects are found in the Project's Lookup (e.g. ClassPathProvider). The one object that may be needed by an SDK is the Project's kind, represented by the enum ProjectKind, which may be, as defined by the Java Card specification
    • CLASSIC_APPLET
    • CLASSIC_LIBRARY
    • EXTENDED_APPLET
    • EXTENDSION_LIBRARY
    • WEB

Some Java Card SDKs can only run certain kinds of projects. A Java Card platform can specify this by returning the set of supported project kinds from JavacardPlatform.supportedProjectKinds(). Note that for many integration cases, you do not need to implement JavacardPlatform directly, but simply list the supported project kinds in a properties file.

  • An implementation of JavacardPlatform for the Java Card RI, which is based on a simple system by which platforms and cards are represented in NetBeans' internal configuration (the system filesystem[4]) as properties-format (key/value pair) files. Most SDK integrations can simply reuse this properties-file based integration, layering their own factories for the list of available Cards, actions available on the platform and card, etc.
    • JavacardPlatform's themselves also have a kind property. This is an ad-hoc string (typically a vendor name) which serves as a name used for looking up functionality associated with a particular vendor's SDK, such as a custom factory for Card instances (which might, for example, poll a socket to determine if a device was connected to the local machine).
  • A User Interface (UI) for visualizing installed Java Card platforms and cards in the Services tab of the IDE's main window.

Levels of Integration

A Java Card SDK can be integrated into NetBeans in a variety of ways, depending on how much flexibility is needed. The API is designed to enable most vendors to do an integration with only a few Java classes and configuration files. However, it is also possible to implement JavacardPlatform and its associated classes completely from scratch if needed.

The following are the integration strategies available:

  1. Wrap the Java Card RI, reusing its infrastructure. This means
    • You do not directly implement JavacardPlatform
    • Your SDK integration requires that a copy of the Java Card RI be installed and registered in order to function
    • You can replace, append or prepend to, all the properties of the Java Card RI (such as the boot classpath, Ant task JARs, etc.)
    • You only need to specify those properties which differ from the Java Card RI's (perhaps custom JARs for proprietary APIs built into the device)
    • You can provide factories which will be used by the infrastructure, to
      • Provide the list of available devices
      • Provide the list of actions available on the platform and card nodes
      • Specify the capabilities of Cards for your SDK (functionality like Start, Stop, Profile, Debug)
      • Provide customizers user-interfaces for your platform and cards
  1. Implement JavacardPlatform directly. This is a somewhat more complicated approach, but offers complete flexibility of implementation, user interface, etc. This means
    • You implement a file type (DataLoader[5]), which uses properties-file format with a unique (with NetBeans) file extension. Your module/loader will be a factory for DataObjects[6] with this extension.
    • DataObjects for your file type shall have a JavacardPlatform in their Node's lookup (per the Java Project API) and their own Lookup. That will make them available for the user to select as the platform to deploy their project to.
    • You will implement JavacardPlatform for these files, along with Cards, Card and other associated classes necessary to integration
    • (If necessary) You will implement JavacardPlatformLocator to create a factory that can recognize folders on disk which represent an installed copy of your SDK, and can provide the additional setup steps to install your a Java Card Platform for your SDK
      • On installation, your module will register the name and absolute path to a copy of your SDK in the global build.properties[7] file used by all Ant projects in the IDE.

Properties Files

The Java Card integration uses Properties files heavily. Properties files are well supported, simple to read and write, and most importantly, readable and usable directly in an Ant task.

At a bare minimum, even if you implement JavacardPlatform directly, that file must be in properties-format, because it will be directly included at build-time by the project Ant scripts.

The Java Card RI integration uses properties files (with the custom file extensions .jcplatform and .jcard) internally to represent both platforms and cards. The Nodes visible in the Services tab for platforms and cards are the nodes for files with these extensions; the customizers for both are simply user-friendly editors for those files, and both are included in the build script.

SDK implementations that talk to hardware devices will probably omit implementing Card a file, and rather, provide their own subclass of Cards which in some way talks to the actual hardware to discover attached devices.

Properties files are also used by the (wrappable/reusable) Java Card RI integration module. A potential Java Card SDK is recognized as a directory containing a file named "platform.properties". This file contains a number of well-known properties (see the constants class JavacardPlatformPropertyNames for all) that specify the classpath, kind and other information needed by the implementation. This file is a prototype for the properties file that will represent the platform in NetBeans internal configuration. At installation time it is copied, with some translation (relative paths to absolute, platform-specific paths) and additions (user-specified display name, other properties used by the internal implementation) into NetBeans system filesystem. This file may also contain prototype properties for the default Card, which is also created at install time.

Simple integrations of new SDKs will reuse these properties and files.

Below is an example of such a properties file, as it might be in the Java Card 3.0.2 RI SDK (before translation into a local configuration file by the IDE). Most of the property names are fairly self-explanatory:

javacard.name=Java Card Platform
javacard.vendor=Sun Microsystems 
javacard.version=3.0.2
javacard.java.majorVersion=1
javacard.java.minorVersion=6
javacard.edition=connected
javacard.distribution.scope=domestic
javacard.home=./
javacard.emulator=bin/cjcre.exe
javacard.bootclasspath=lib/api_connected.jar
javacard.classic.bootclasspath=lib/api_classic.jar
javacard.classpath=
javacard.javadocpath=docs/api/
javacard.sourcepath=src/api/
javacard.toolClassPath=lib/tools.jar:lib/ant-contrib-1.0b3.jar:lib/bcel-5.2.jar:\
 lib/commons-cli-1.0.jar:lib/commons-codec-1.3.jar:lib/\
 commons-httpclient-3.0.jar:lib/commons-logging-1.1.jar
javacard.nbtasksClassPath=lib/nbtasks.jar:lib/nbutils.jar

# These two properties determine where NetBeans will look for factories for 
# Card objects and Actions over cards, etc. in the SFS
javacard.platform.kind=RI
javacard.device.file.extension=jcard

javacard.runtime.name=Java Card Runtime Environment
javacard.specification.version=3.0.1
javacard.specification.vendor=Sun Microsystems Inc.
javacard.referenceimplementation.version=3.0.2
javacard.referenceimplementation.vendor=Sun Microsystems Inc.
javacard.referenceimplementation.httpPort=yes
javacard.referenceimplementation.contactedPort=yes
javacard.referenceimplementation.contactlessPort=yes
#Supported project flavors - same constants used in Java Card MANIFEST.MF files
javacard.platform.supported.project.kinds=web,extended-applet,classic-applet,\
 extension-lib,classic-lib

#Ant task classes provided by JARs on javacard.toolClassPath
javacard.apdutoolClass=com.sun.javacard.apdutool.Main
javacard.tasks.packTaskClass=com.sun.javacard.nbtasks.PackTask
javacard.tasks.signTaskClass=com.sun.javacard.nbtasks.SignTask
javacard.tasks.proxyTaskClass=com.sun.javacard.nbtasks.ProxyTask
javacard.tasks.loadTaskClass=com.sun.javacard.nbtasks.LoadTask
javacard.tasks.createTaskClass=com.sun.javacard.nbtasks.CreateTask
javacard.tasks.deleteTaskClass=com.sun.javacard.nbtasks.DeleteTask
javacard.tasks.unloadTaskClass=com.sun.javacard.nbtasks.UnloadTask
javacard.tasks.browseTaskClass=com.sun.javacard.nbtasks.OpenBrowserTask
#Values for the default card, and defaults for new user-created cards
prototype.javacard.device.name=${devicename}
prototype.javacard.device.host=localhost
prototype.javacard.device.secureMode=true
prototype.javacard.device.e2pSize=8M
prototype.javacard.device.corSize=4K
prototype.javacard.device.proxy2idePort=7020
prototype.javacard.device.contactedPort=9025
prototype.javacard.device.contactedProtocol=T=1
prototype.javacard.device.apdutool.contactedProtocol=-t0
prototype.javacard.device.ramSize=1M
prototype.javacard.device.httpPort=8019
prototype.javacard.device.proxy2cjcrePort=7019
prototype.javacard.device.loggerLevel=debug
prototype.javacard.device.contactlessPort=9026
prototype.javacard.device.cardmanagerurl=http://${prototype.javacard.device.host}:\
 ${prototype.javacard.device.httpPort}/cardmanager
prototype.javacard.device.serverurl=http://${prototype.javacard.device.host}:\
 ${prototype.javacard.device.httpPort}
prototype.javacard.device.nosuspend=true
prototype.javacard.device.eprom.file=${javacard.device.eeprom.folder}\
 ${file.separator}${javacard.device.name}.eprom
prototype.javacard.device.debugger.cmdline=${java.home}/bin/java \
 -classpath ${javacard.debug.proxy.classpath} {{{-Djc.home=${javacard.ri.home}}}}\
  com.sun.javacard.debugproxy.Main {{{debug}}} --listen \
  ${javacard.device.proxy2idePort}\
   --remote ${javacard.device.host}:${javacard.device.proxy2cjcrePort}\
   --classpath ${class.path}
prototype.javacard.device.start.cmdline=${javacard.emulator} -debug ${debug}\
  -suspend ${suspend} -ramsize ${javacard.device.ramSize}\
  -e2psize ${javacard.device.e2pSize} -corsize ${javacard.device.corSize}\
  -e2pfile ${javacard.device.eprom.file}\
  -loggerlevel ${javacard.device.loggerLevel} -httpport ${javacard.device.httpPort}\
  -contactedport ${javacard.device.contactedPort} -contactedprotocol\
  ${javacard.device.apdutool.contactedProtocol}\
  -contactlessport ${javacard.device.contactlessPort}
prototype.javacard.device.resume.cmdline=${javacard.emulator} -resume -debug\
  ${debug} -suspend ${suspend} -e2pfile ${prototype.javacard.device.eprom.file}
prototype.javacard.device.capabilities=START,STOP,RESUME,DEBUG,EPROM_FILE,\
 CLEAR_EPROM,CONTENTS,CUSTOMIZER,INTERCEPTOR,PORTS,URL,DELETE
prototype.javacard.device.nosuspend=true

(remember that a trailing \ in a properties file, plus a space at the beginning of the next line means that the next line is a continuation of the previous)

The main things of interest, which may not be obvious at first glance are that:

  • In the platform.properties file in an SDK, all paths are unix-style relative paths, relative to the directory where the platform.properties file is (on installation, the IDE will copy these properties, translating them into platform-specific, absolute paths usable by an Ant script)
  • Some properties specify the actual command-line used to run the Java Card RI emulator and debugger proxy. Because some of the variables referenced refer to file paths which are unknown at distribution-time, these command-lines may contain spaces. Elements which must be treated as a single argument to Runtime.exec() are delimited by {{ and }} characters.
  • A few of the values (generally those not prefixed by "javacard.") are provided by the IDE at runtime. Examples are
    • devicename - this is substituted with the user-entered display name in the copy of the platform.properties installed in the IDE's configuration directory (the actual file in the SDK is never modified by the IDE)
    • debug, suspend - these are provided on the fly by the IDE when it starts an external process.
  • The list of capabilities defined under prototype.javacard.device.capabilities corresponds to a list of actual classes which are available from a Card's getCapability() method. These constants and their corresponding Java classes are enumerated in the enum DeclarableCapabilities.
  • Probably the most influential property which you do not see here is javacard.wrap.ri=true. That property is used to create a platform with an only partially-defined platform.properties, where all undefined and not overridden properties are provided by the installed copy of the RI. The next section will show an example of how this is used.

The result of all of this is that many SDKs can simply use their own version of platform.properties, and in many cases providing this, custom Ant tasks and a NetBeans module with only a few classes and files is enough to integrate another SDK.

The Card class

I have mentioned the class Card several times, and used the term capabilities along with it. The Card interface is fairly simple, and uses the common NetBeans Lookup[8] idiom - you pass a Class object and are returned an instance of that class or null. Below is the full signature of Card:

public interface Card extends Lookup.Provider {
   public <T extends ICardCapability> T getCapability(Class<T> type);
   public Set<Class<? extends ICardCapability>> getSupportedCapabilities();
   public Set<Class<? extends ICardCapability>> getEnabledCapabilities();
   public boolean isCapabilityEnabled (Class<? extends ICardCapability> type);
   public boolean isCapabilitySupported (Class<? extends ICardCapability> type);
   public CardState getState();
   public void addCardStateObserver (CardStateObserver obs);
   public void removeCardStateObserver (CardStateObserver obs);
   public JavacardPlatform getPlatform();
   public String getSystemId();
   public boolean isValid();
}

Essentially, Card has

  • A set of capabilities (subclasses of the marker interface ICardCapability)
  • A state (running, not running, running in debug mode, and several transitional states used by virtual cards to indicate a process is being started but has not yet initialized, or similar)
  • A string ID (unique to the platform the Card belongs to)
  • Validity - whether or not the card is configured in such a way that the IDE can use it

Most implementations will want to subclass AbstractCard, which

  • Has protected addCapability() and removeCapability() methods, and implements all of the capability-related methods in the Card interface
  • Centralizes registration of external running processes which should be shut down on VM exit
  • Handles state management, including replanning all state change events to the AWT Event Thread
  • Provides a default implementation of isValid() based on the validity of the owning platform, which can be overridden if necessary
  • Implementations will typically simply override onBeforeFirstLookup() to initialize the set of capabilities available on this card, and implement those capability interfaces

or go even further and subclass BaseCard, which provides even more built-in implementation, including

  • protected create*() methods for creating all predefined capabilities in the API, which return null by default, and may be overridden to return a specific implementation

The following are the defined subclasses of ICardCapability which a Card may have in its lookup/set-of-capabilities:

  • AntTargetInterceptor - called when a the user invokes Run, Debug, Instantiate, Load, Profile, Uninstantiate or Unload actions on a project. By default these actions will simply invoke the corresponding Ant target in the project's build script. An AntTargetInterceptor can run code before and after the Ant target executes, or it can completely override the Ant target, causing it not to be invoked at all (for example, if an implementation wants to provide its own in-IDE way of uploading bits to a device)
  • CapabilitiesProvider - used by subclasses of BaseCard to determine their list of available capabilities at construction time (for example, to parse a list of enum constants such as the START,STOP,RESUME,DEBUG,EPROM_FILE example above
  • CardContentsProvider - provides a subtree for a Card that shows the applets/applications on that card and possibly information about individual instances of those applets/applications. Provide if you are able somehow to query the card for this information.
  • CardCustomizerProvider - provides a UI which can be shown in a dialog, for customizing settings of the card
  • CardInfo - mandatory - provides UI specific information about the card, such as icon and localized display name
  • ClearEpromCapability - allows the IDE to wipe the memory of the card
  • DebugCapability - marker interface indicating that a debugger can be attached to the card, and the Debug action should be enabled for projects using this card
  • DeleteCapability - allows the card to be deleted (meaningful for virtual cards, probably useless for physical devices)
  • EpromFileCapability - provides a way to fetch the memory contents of the card as a file (possibly to delete, possibly to visualize it somehow)
  • PortProvider - provides port numbers for cards which communicate via HTTP. Also used by the RI to find unused port numbers for new virtual card definitions.
  • ProfileCapability - Marker interface indicating that this Java Card SDK implements JVMTI and can be profiled by the NetBeans profiler (Note: Currently Java Card projects do not support profiling)
  • ResumeCapability - Ability to restart a virtual card without wiping its memory, in the same state it was in when previously shut down. Meaningless for physical cards.
  • StartCapability - Ability to start a virtual card, wiping its memory in the process
  • StopCapability - Ability to stop a running virtual card
  • UrlCapability - provider for URLs for communicating with Cards that use HTTP to deploy or otherwise interact with users' computers.

Java Card Integration - reusing the Reference Implementation's Infrastructure

For a practical example, the following is a tour of the Java Card implementation for Oberthur smart cards. The code for this module can be found in the folder javacard.oberthur in NetBeans source code. The Oberthur module takes the approach described above, of relying on a copy of the RI to provide some JARs and folders, and overriding or replacing small amounts of functionality to customize Java Card support for Oberthur. Note that Oberthur also provides their own Ant tasks JAR which differs from the one provided by the IDE.

The first thing to look at is the platform.properties file in the Oberthur SDK:

javacard.name=Oberthur Technologies - USB Token
javacard.vendor=Oberthur Technologies
javacard.version=3.0.2
javacard.java.majorVersion=1
javacard.java.minorVersion=6
javacard.edition=connected
javacard.distribution.scope=global
javacard.home=./
javacard.bootclasspath=lib/api_connected.jar
javacard.classic.bootclasspath=lib/api_classic.jar
javacard.toolClassPath=lib/tools.jar:lib/commons-httpclient-3.0.1.jar:\
 lib/commons-cli-1.0.jar:lib/bcel-5.2.jar
javacard.nbtasksClassPath=lib/nbtasks.jar:lib/nbutils.jar:lib/tools.jar:\
 lib/commons-httpclient-3.0.1.jar:lib/commons-logging-1.1.jar:\
 lib/commons-codec-1.3.jar:${javacard.ri.home}/lib /nbtasks.jar
javacard.platform.kind=oberthur
javacard.device.file.extension=jcard
javacard.wrap.ri=true
javacard.runtime.name=Oberthur Java Card SDK
javacard.specification.version=3.0.1
javacard.specification.vendor=Sun Microsystems Inc.
javacard.referenceimplementation.version=3.0.1
javacard.referenceimplementation.vendor=Sun Microsystems Inc.
javacard.referenceimplementation.httpPort=yes
javacard.referenceimplementation.contactedPort=yes
javacard.referenceimplementation.contactlessPort=yes
javacard.supported.project.kinds=web
javacard.build.no.device.file=true
javacard.device.host=smartcard
javacard.device.httpPort=80
javacard.device.cardmanagerurl=http://smartcard:80/SysInfo/getData
javacard.device.serverurl=http://smartcard:80
javacard.device.capabilities=CONTENTS,CUSTOMIZER,PORTS,URL
javacard.device.is.remotehost=true
javacard.device.name=Oberthur Smart Card
javacard.device.ramSize=8M

There are a few things to notice here:

  1. There are a lot fewer properties than in the Java Card RI's platform.properties - because any undefined properties are taken from the Java Card RI's platform.properties
  2. There are a few properties that do not appear in the Java Card RI's platform.properties - specifically
  • javacard.supported.project.kinds=web - this tells NetBeans that this platform can only be used for web projects - Java Card 2.0 classic applets and Java Card 3.0 extended applets are not supported
  • javacard.build.no.device.file=true - this tells the project build scripts that they do not need to look for a separate properties file defining the device - all device-related properties are embedded in the platform definition (since we are talking about a physical card, there is no need for memory size settings, etc.).
  • javacard.platform.kind=oberthur - this tells NetBeans where in the system filesystem to look for factories for card instances, customizers, etc. for Oberthur Java Card platforms.
  • javacard.wrap.ri=true javacard.wrap.ri=true this is what instructs the wizard in Tools > Platforms to register this Java Card platform as a wrapper for the Java Card RI. If you were writing a Java Card platform, and did not want to ship your own api_classic.jar, you could just omit that property. If you wanted to include the copy of api_classic.jar from the Java Card RI on the project boot classpath, but also needed to add your own library, you could write append.javacard.bootclasspath=foo/myApi.jar or preend.javacard.bootclasspath=foo/myApi.jar to append or prepend your JAR to the boot classpath, while keeping all the JARs from the Java Card RI.

Note that, for any of the path-like properties, this platform could actually reuse JARs from the Java Card RI. To just reuse them, simply omit the property - if you don't want to ship your own copy of api_classic.jar, just leave out javacard.bootclasspath. You can also prepend and append to classpaths defined in the RI's platform.properties. To append a JAR to the boot classpath, simply add append.javacard.bootclasspath=foo/myApi.jar. To prepend a JAR to the boot classpath (perhaps you want to replace a few classes from a JAR later on the classpath, but the rest are fine), simply include prepend.javacard.bootclasspath=foo/myApi.jar

Integration Classes

Only a six Java source files are needed in the Oberthur smart card support module, to create a decent IDE integration with these specific cards. These classes do the following things:

  • CardImpl - A subclass of AbstractCard which provides implementations of
    • PortProvider to list TCP/IP ports used by the card, the host name (Oberthur card drivers act as a network interface that talks to a single host called "smartcard")
    • UrlCapability to provide URLs for deploying and otherwise communicating with the card
    • CardInfo to supply a custom display name and icon for the card
  • CardsFactoryImpl - this is registered in the system filesystem on the path org-netbeans-modules-javacard-spi/kinds/oberthur. It is a very small class that is factory for Card objects for platforms who specify (in their platform.properties) a value of oberthur for the key javacard.platform.kind
  • CardsImpl - Also very little code here - this is a container for all Card instances belonging to any JavacardPlatform of the kind oberthur - of which there will be, at most, one at any given time
  • RefreshStatusAction - An action added to the popup menu of Oberthur card nodes in the Services window, which allows the user to update the connected status of the card immediately (i.e. if they have just plugged it into their computer). This action is registered in the system filesystem in the folder org-netbeans-modules-javacard-spi/kinds/oberthur/Actions.
  • StateUpdaterCallback - this is a subclass of org.netbeans.modules.javacard.spi.ConnectionWatchdog.Callback, a convenience class that allows the IDE to poll the connected state of the card every so often, on a timer. It correctly handles shutting down polling if the Card instance is garbage collected, and disabling polling when the IDE is not the active application (so repeated polling does not cause the IDE to be swapped back into memory and, say, slow down the user's email client)

=Implementing Card

The most complex class in the Oberthur module is CardImpl - in fact, it is the only one that contains a significant amount of code.

Most of the features of a Card are defined as capabilities which you fetch by calling Card.getCapability(Class<ICardCapability> type).

final class CardImpl extends AbstractCard {
  public static final String SINGLE_CARD_ID = "card"; //NOI18N
  private static final String POLL_URL = "http://smartcard:80/SysInfo/getData"; //NOI18N
  private static final String HOST = "smartcard"; //NOI18N

All of the above are constants defined by Oberthur's drivers

  private volatile boolean connected;
  private final ConnectionWatchdog<CardImpl> watchdog = 
          new ConnectionWatchdog<CardImpl>(this, new StateUpdaterCallback());

Above we have created a callback that will poll the URL for the card, to find out if it is connected and can be deployed to or not (we will implement StateUpdaterCallback below)

  CardImpl(JavacardPlatform pform) {
    super(pform, SINGLE_CARD_ID);
  }

  URL getPollUrl() throws MalformedURLException {
    return new URL(POLL_URL);
  }

  @Override
  protected void onBeforeFirstLookup() {
    initCapabilities(new Ports(), new Info(), new Caps(), new Urls());
  }

Here we initialize the capabilities of our card. AbstractCard takes care of the plumbing to make them available to external callers.

  @Override
  public boolean isValid() {
    return true;
  }

A card may be valid or not (no method that returns a Card object should ever return null). In our case there is no such thing as an invalid card.

  void setConnected(boolean connected) {
    if (this.connected != connected) {
      this.connected = connected;
      connected &= super.isValid();
      setState(connected ? CardState.RUNNING : CardState.NOT_RUNNING);
    }
  }

  void refreshStatus() {
    watchdog.refreshNow();
  }

These two methods involve polling the URL for the card to see if it is connected and ready to use or not. Our implementation of StatusUpdaterCallback will call setConnected() with true or false depending on whether it successfully connected or not.

refreshStatus is called by the popup menu action we registered, so the user can force an update of the card's state.

The remainder of the classes are fairly straightforward implementations of capabilities:

  private final class Ports implements PortProvider {

    public Set<Integer> getClaimedPorts() {
      return Collections.singleton(80);
    }

This gets the list of all TCP/IP ports this card is using. It is used by the infrastructure, to ensure that a user setting up a new card instance doesn't try to use the same port as the existing one.

    public Set<Integer> getPortsInUse() {
      return connected ? getPortsInUse() : Collections.<Integer>emptySet();
    }

Similar to getClaimedPorts, this gets the list of all TCP/IP ports this card is actively using at the time of the call.


    public String getHost() {
      return HOST;
    }

    public int getPort(PortKind role) {
      switch (role) {
        case HTTP:
          return 80;
        default:
          return -1;
      }
    }
  }

The rest is fairly straightforward - there are a few other PortKinds, for attaching a debugger or a console to talk to the card, which are not supported for Oberthur cards.

  private final class Info implements CardInfo {

    public String getSystemId() {
      return SINGLE_CARD_ID;
    }

    public String getDisplayName() {
      return NbBundle.getMessage(Info.class, "CARD_DISPLAY_NAME"); //NOI18N
    }

    public Image getIcon() {
      return ImageUtilities.loadImage(
         "org/netbeans/modules/javacard/oberthur/otcard.png"); //NOI18N
    }

    public String getDescription() {
      PortProvider p = getCapability(PortProvider.class);
      return NbBundle.getMessage(Info.class, "CARD_DESCRIPTION", //NOI18N
         p.getHost(), p.getClaimedPorts().iterator().next(),
         getPlatform().getDisplayName());
    }
  }

  private final class Urls implements UrlCapability {

    public ContactedProtocol getContactedProtocol() {
      return null;
    }

    public String getURL() {
      return "http://smartcard/";
    }

    public String getManagerURL() {
      return POLL_URL;
    }

    public String getListURL() {
      return null;
    }
  }
}

The above classes are probably self-explanatory.

  private final class Caps implements CapabilitiesProvider {

    public Set<Class<? extends ICardCapability>> getSupportedCapabilityTypes() {
      Set<Class<? extends ICardCapability>> result = 
              new HashSet<Class<? extends ICardCapability>>();
      result.add(CardInfo.class);
      result.add(PortProvider.class);
      result.add(CapabilitiesProvider.class);
      result.add(UrlCapability.class);
      return result;
    }
  }

This last class simply is required by AbstractCard, so that it knows what capabilities are and are not supported without instantiating them until they are needed.

Providing Cards for a Java Card Platform

The Java Card RI uses properties-format (.jcard) files to define devices. The user can define new devices, and new such files are written to disk.

A physical card, of course, has a fixed set of characteristics, and the user cannot invent new ones. So we will provide our own code to define a single Card instance for an Oberthur SDK platform.

Two classes are used to define the cards. The first is a factory that just accepts a DataObject for the platform in question:

public final class CardsFactoryImpl extends CardsFactory {
  @Override
  protected Cards createCards(Lookup.Provider source) {
    DataObject platformDob = source.getLookup().lookup(DataObject.class);
    return new CardsImpl(platformDob);
  }
}

The second is another layer of indirection, which involves some complexity in the RI or any platform that can have multiple attached devices at once, but is quite simple in this case. All it really needs to do is provide an instance of Card in its Lookup:

final class CardsImpl extends Cards implements Lookup.Provider {
  private final DataObject dob;
  private Lookup lkp;

  public CardsImpl(DataObject platformDob) {
    this.dob = platformDob;
  }

  @Override
  public List<? extends Provider> getCardSources() {
    return Collections.singletonList(this);
  }

  public synchronized Lookup getLookup() {
    if (lkp == null) {
      JavacardPlatform pform = dob.getLookup().lookup(JavacardPlatform.class);
      if (pform != null) { //file possibly deleted?
        CardImpl theCard = new CardImpl(pform);
        lkp = Lookups.fixed(theCard);
      } else {
        lkp = Lookup.EMPTY;
      }
    }
    return lkp;
  }
}

Tracking Card State

The remaining two classes are just about figuring out if a card is connected, and graying out the icon of the card if it is not attached (and disabling attempts to deploy to it when it is not present):

public class RefreshStatusAction extends Single<CardImpl> {

  public RefreshStatusAction() {
    super(CardImpl.class, NbBundle.getMessage(RefreshStatusAction.class,
       "ACTION_REFRESH_STATUS"), null);
  }

  @Override
  protected void actionPerformed(CardImpl target) {
    target.refreshStatus();
  }
}

This action is registered in the system filesystem, and appears on the popup menu of Card objects. Single is an action subclass from the not-yet-official-API spi.actions module that makes it simple to write a context sensitive action.

final class StateUpdaterCallback implements
   ConnectionWatchdog.Callback<CardImpl> {

  private static final Logger LOGGER = Logger.getLogger(StateUpdaterCallback.class.
     getName());

  public void poll(CardImpl card) throws Exception {
    URL url = card.getPollUrl();
    if (LOGGER.isLoggable(Level.FINE)) {
      LOGGER.log(Level.FINE, this + " update card status"); //NOI18N
    }
    try {
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.setConnectTimeout(200);
      conn.setUseCaches(false);
      conn.setReadTimeout(200);
      conn.setRequestMethod("GET"); //NOI18N
      conn.setDoOutput(false);
      int code = conn.getResponseCode();
      if (LOGGER.isLoggable(Level.FINE)) {
        LOGGER.log(Level.FINE, this + " got response code " + //NOI18N
           code);
      }
      card.setConnected(code == HttpURLConnection.HTTP_OK);
    } catch (IOException ex) {
      LOGGER.log(
         Level.FINEST, "Could not connect to " + url, ex); //NOI18N
      card.setConnected(false);
    }
  }
}

This last bit is just boilerplate HTTP connection code. The poll() method will be called automatically, on a timer, when the IDE is active, if there is a reachable instance of Card. All we have to do is update the state of the Card object based on the result of the attempt to connect.

Layer Registration for the Oberthur Java Card Platform Module

The last bit of the module is to declaratively register a few objects. Everything we are registering is based on the string kind of the Oberthur module. To add another SDK, we would simply use a different path in the system filesystem, and provide the same name for javacard.platform.kind in our SDK's platform.properties, or (if implementing JavacardPlatform directly), JavacardPlatform.getKind():

<filesystem>
    <folder name="Actions">
        <folder name="JavaCard3">
            <file name="org-netbeans-modules-javacard-oberthur-RefreshStatusAction.instance">
                <attr name="position" intvalue="2001"/>
            </file>
        </folder>
    </folder>
    <folder name="org-netbeans-modules-javacard-spi">
        <folder name="kinds">
            <folder name="oberthur">
                <file name="org-netbeans-modules-javacard-oberthur-CardsFactoryImpl.instance"/>
                <folder name="Actions">
                    <file name="org-netbeans-modules-javacard-oberthur-RefreshStatusAction.shadow">
                        <attr name="originalFile" stringvalue="Actions/JavaCard3/org-netbeans-modules-javacard-oberthur-RefreshStatusAction.instance"/>
                        <attr name="position" intvalue="0"/>
                    </file>
                </folder>
            </folder>
        </folder>
    </folder>
</filesystem>

Ant Tasks

Part of integrating with NetBeans is providing Ant tasks. The Ant tasks used by the Java Card RI are open source and are hosted at http://kenai.com/projects/javacard[9]. This project is also open to hosting Ant tasks belonging to other vendors.

These tasks have two dependencies that are NetBeans-related:

  1. They expect certain properties to be set, namely those defined in JavacardPlatformKeyNames and JavacardDeviceKeyNames - the same key names you see in the platform.properties example above
  2. They use the JAR of the javacard.filemodels module as a library, to parse and build models for various javacard-specific files, such as applets.xml. While it is not required that you use this library to parse these files in your own Ant tasks, it is useful to be sure that both the IDE and Ant tasks are using exactly the same code to read (and write) these files.


Java Card Modules With APIs

The following modules in the NetBeans source base have APIs which may or may not be

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo