Tuesday, February 24, 2009

Bit Syntax for Java (I)

Erlang's bit syntax is pretty cool. Now, Preon is aiming to provide something with similar ease of use. Which one is easier? You decide.

One of the examples in the excellent Erlang book shows how to decode an MPEG header, using Erlang's bit syntax. This is what it looks like:

decode_header(<<2#11111111111:11,B:2,C:2,_D:1,E:4,F:2,G:1,Bits:9>>) ->
Vsn = case B of
0 -> {2,5};
1 -> exit(badVsn);
2 -> 2;
3 -> 1
end,
Layer = case C of
0 -> exit(badLayer);
1 -> 3;
2 -> 2;
3 -> 1
end,
%% Protection = D,
BitRate = bitrate(Vsn, Layer, E) * 1000,
SampleRate = samplerate(Vsn, F),
Padding = G,
FrameLength = framelength(Layer, BitRate, SampleRate, Padding),
if
FrameLength < 21 ->
exit(frameSize);
true ->
{ok, FrameLength, {Layer,BitRate,SampleRate,Vsn,Bits}}
end;
decode_header(_) ->
exit(badHeader).

This is the same code, but then in Java, using Preon:

public class MpegHeader {

@BoundNumber(size="11", match="0b11111111111")
private int frameSync;

@BoundNumber(size="2")
private int mpegAudioVersionId;

@BoundNumber(size="2")
private int layerDescription;

@Bound
private boolean crcProtected;

@BoundNumber(size="4")
private int bitRateIndex;

@BoundNumber(size="2")
private int sampleRateFrequencyIndex;

@Bound
private boolean padded;

@Bound
private boolean privateBit;

@BoundNumber(size="2")
private int channelMode;

@BoundNumber(size="2")
private int modeExtension;

@Bound
private boolean copyright;

@Bound
private boolean original;

@BoundNumber(size="2")
private int emphasis;

}

Codec codec = new Codecs.create(MpegHeader.class);
Codecs.decode(codec, buffer);

Now, there are obviously a lot of differences. The Erlang example also includes calls to functions defined elsewhere to determine the bitrate and frame lenght. The Preon example does not have that. If you would need it, you could imagine implementing it as methods of the MpegHeader class.

Also note that the example does match on the first 11 bits, expecting them to be ones only, similar to the Erlang example. The notation @BoundNumber(size="11", match="0b11111111111") basically says that this field will be decoded from 11 input bits, as long as it matches the bit pattern "11111111111". Or to be more precise, as long as it matches the numeric value of 11 "1" bits, interpreted as an integer. If that criterion isn't met, the Codec will throw a DecodingException.

I will try to work the other examples into Java with Preon examples as well, but it's interesting to see how the two approaches compare. What would you prefer? And why?

Sunday, February 22, 2009

Spring ME Supporting Map Configuration

As you may or may not know, Spring ME is aiming to be compliant with classic Spring. That is, a Spring ME configuration file is expected to work with classic Spring as well. However, it does remain a subset of classic Spring. There are some things not supported, and there are some things that will never be supported. One of the things missing so far was support for <map/> configuration. So, configuration files like these:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

<bean id="indexHolder" class="me.springframework.di.spring.CourseIndexHolder">
<property name="index">
<map>
<entry key="coding">
<bean class="me.springframework.di.spring.Course">
<property name="topic" value="C++"/>
</bean>
</entry>
<entry key="modeling">
<bean class="me.springframework.di.spring.Course">
<property name="topic" value="UML"/>
</bean>
</entry>
</map>
</property>
</bean>

</beans>
...would fail. But the good news is: support for map configuration is has just been added to the trunk. So the above is perfectly valid if you happen to be using the version of the trunk.

Note that it is already compliant with classic Spring in many ways. So it does allow you to use keys based on beans instead of String literals, as an example. (See SPRINGME-4.)

Friday, February 20, 2009

Spring ME on Java Card???

There's nothing like a fever to think outside the box. While my body is fighting a virus that has been messing with it for a week now, the fever is - I have to say - very stimulating to the brain. Most of the things the brain is producing now don't make any sense at all, but that's ok - I will enjoy it while it lasts.

One of the things suggested by the memes five minutes ago is to use Spring ME on Java Card. (Trust me, this makes perfect sense compared to the other things it suggests.) I could not resist checking if that would actually work. So I dragged myself to the attic to search for the unread copy of "Java Card Technology for Smart Cards" book.

I'm now paging through appendix A, which covers the subset of Java SE covered by Java Card. Interesting read. It turns out it doesn't even support int. Doh. This puts the limitations CLDC imposes in a completely new perspective. Looking at the cover, it turns out my book is from 2000. I have little doubt that the latest incarnation of the spec supports a much wider subset of Java SE then this early edition.

Anyhow, while reading through the appendix, I'm beginning to think this could actually work. Now, it's obviously questionable if it would make a lot of sense, but it's doable, I think. If I ever have the time, I will give it a try. I have the good old Java ring, a fine piece of jewelry, so it would even possible to prototype this for real. (That is, if I find a way to connect my MacBook with a serial cable...) I filed a paper on Spring ME for JavaONE 2009. This could be nice case study. What do you think?

Sunday, February 15, 2009

Fluent Interface for Wicket

Last week I learned Wicket. This week, I am looking at Wicket 1.4rc2. I remember having looked at what would have been Wicket 2.0 in the past. Wicket 1.4 introduces Generics again.

Now, the first time I saw the angle brackets appearing in our source code, I was in shock. Then I started to think... This could actually be good.

Now, looking at a simple example of how all of this work, you probably don't get all that excited. Admittedly, having the IDE and compiler helping you to add the proper type of validators is sort of ok, if you like that kind of thing. (I do!) But then again, the amount of brackets (type parameters) appearing in your code is not really cool. Especially for a framework that is proud of it's limited use of angle brackets. (XML, that is.)

Here's an example:
  form.add(new TextField<Date>("whatever", new PropertyModel<Date>(event, "date"))
.add(DateValidator.maximum(new Date())));
While I was thinking about this, I started to wonder if a fluent interface would be able to take care of all of this through type inference. And I think it does. I quickly prototyped a fluent FormBuilder, and this is what the above example looks alike now:
addTextField("whatever")
.forModelOfType(Date.class)
.validatedBy(DateValidator.maximum(new Date()))
.forProperty("date").of(event)
.to(form);
And all the brackets are magically gone again... Now don't be fooled by the simplicity here. The compiler and IDE will support you in exactly the same way as in the first code example. You will not be able to add an IValidator type of validator, as the screenshot below illustrates. 

Now, I have to say that the current incarnation of this fluent API is less than great. One of the things I should have done already - but haven't done yet - is to be able to drop .forModelOfType(...) in case you pass the property type in the forProperty(...) construct. So something like this: .forProperty("date").ofType(Date.class).of(event). But that's details. In general, I think this could work. What do you think?

Tuesday, February 10, 2009

Portlets vs. Social Container


Portals are... peculiar. I am a little conflicted about them though. First, what I like about them. I think portals in way are the SOA dream come true. Basically, it's all about composition of existing smaller services. Admittedly, the level of integration is not very intimate, but that's actually a good thing. Think of portlets as objects that have their own lifecycle and state. And instead of exposing all of their state to the rest of the world - which would be very MVC, but very not OO, because it breaks the encapsulation, they basically control themselves how humans interact with them. Very much like the visual proxy ideas laid out in this article 10 years ago.

So yes, I kind a like them. Ultimately, I don't believe in partitioning systems horizontally. I believe in partitioning systems vertically. Have systems that are capable of doing some particular in a very decent way, and offering several interfaces and type of endpoints to interact with it.

But at the same time, I don't really like portals. And that largely has to do with the fact that portals do the composition on the server, and you wonder why. Especially in today's world, where many things are essentially getting mashed up on the client. It just doesn't scale very nice. (Well, I can tell you why, but you have to promise not to tell anyone else... It's a conspiracy. Hardware vendors make you think you need it, and then it turns out it requires a lot of processing power.)

Now, on the plus side, I think portals probably paved the way for client side social container technology. And it seems to me that if you happen to have an investment in portal technology, it should eventually not be all that hard to turn that into a social container type of solution, in which the composition is done where it needs to be done: on the client. (And then we can also forget about edge side includes and all of that. You ain't gonna need it.) Once it's on the client, it will scale just fine. 

I had a hunch that there would be something out there that would leverage the portlet programming model to move the composition to the client. And it turns out, there is something out there. It's called Light Portal, and it's doing exactly what you might expect. Have AJAX portlet type of components call into JSR 168 portlets. Sweet. I am not sure if it would be as robust as you would like, but you got to at least appreciate the attempt. 

Monday, February 9, 2009

RelaxNG Grammar for Maven settings.xml

I have to admit, I was really really tempted to write a plugin for generating RelaxNG from Modello, just to be sure that I would always have my nxml-mode set up correctly whenever the guys behind Maven would come up with yet another XML format, but I managed to resist. 

Instead I just ran some tools on the settings-1.0.0.xsd file, to turn it into RelaxNG, and to turn it into RNC afterwards. This is what I produced from the XSD file. I forgot the tool I used, and I had to modify some of the content in order to get it working, but it sort of works:


<rng:grammar xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://maven.apache.org/SETTINGS/1.0.0" ns="http://maven.apache.org/SETTINGS/1.0.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<rng:start>
<rng:ref name="settings"/>
</rng:start>
<rng:define name="settings">
<rng:element name="settings">
<rng:ref name="Settings"/>
<a:documentation>
1.0.0

Root element of the user configuration file.

</a:documentation>
</rng:element>
</rng:define>
<rng:define name="Settings">
<a:documentation>
1.0.0

Root element of the user configuration file.

</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="localRepository">
<rng:data type="string">
<a:documentation>
1.0.0


The local repository.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : true</a:documentation>
<rng:element name="interactiveMode">
<rng:data type="boolean">
<a:documentation>
1.0.0


Whether Maven should attempt to interact with the user for input.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : false</a:documentation>
<rng:element name="usePluginRegistry">
<rng:data type="boolean">
<a:documentation>
1.0.0


Whether Maven should use the plugin-registry.xml file to manage plugin versions.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : false</a:documentation>
<rng:element name="offline">
<rng:data type="boolean">
<a:documentation>
1.0.0


Indicate whether maven should operate in offline mode full-time.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="proxies">
<a:documentation>
1.0.0


Configuration for different proxy profiles. Multiple proxy profiles
might come in handy for anyone working from a notebook or other
mobile platform, to enable easy switching of entire proxy
configurations by simply specifying the profile id, again either from
the command line or from the defaults section below.


</a:documentation>


<rng:zeroOrMore>
<rng:element name="proxy">
<rng:ref name="Proxy"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="servers">
<a:documentation>
1.0.0


Configuration of server-specific settings, mainly authentication
method. This allows configuration of authentication on a per-server
basis.


</a:documentation>


<rng:zeroOrMore>
<rng:element name="server">
<rng:ref name="Server"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="mirrors">
<a:documentation>
1.0.0

Configuration of download mirrors for repositories.

</a:documentation>


<rng:zeroOrMore>
<rng:element name="mirror">
<rng:ref name="Mirror"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="profiles">
<a:documentation>
1.0.0


Configuration of build profiles for adjusting the build
according to environmental parameters.


</a:documentation>


<rng:zeroOrMore>
<rng:element name="profile">
<rng:ref name="Profile"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="activeProfiles">
<a:documentation>
1.0.0


List of manually-activated build profiles, specified in the order in which
they should be applied.


</a:documentation>


<rng:zeroOrMore>
<rng:element name="activeProfile">
<rng:data type="string"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="pluginGroups">
<a:documentation>
1.0.0

List of groupIds to search for a plugin when that plugin
groupId is not explicitly provided.

</a:documentation>


<rng:zeroOrMore>
<rng:element name="pluginGroup">
<rng:data type="string"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="Mirror">
<a:documentation>
1.0.0

A download mirror for a given repository.

</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="mirrorOf">
<rng:data type="string">
<a:documentation>
1.0.0

The server ID of the repository being mirrored, eg
"central". This MUST NOT match the mirror id.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="name">
<rng:data type="string">
<a:documentation>
1.0.0

The optional name that describes the mirror.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="url">
<rng:data type="string">
<a:documentation>
1.0.0
The URL of the mirror repository.
</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="id">
<rng:data type="string">
<a:documentation>
1.0.0
</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="Proxy">
<a:documentation>
1.0.0


The <code>&lt;proxy&gt;</code> element contains informations required to a proxy settings.

</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : false</a:documentation>
<rng:element name="active">
<rng:data type="boolean">
<a:documentation>
1.0.0


Whether this proxy configuration is the active one.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : http</a:documentation>
<rng:element name="protocol">
<rng:data type="string">
<a:documentation>
1.0.0


The proxy protocol.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="username">
<rng:data type="string">
<a:documentation>
1.0.0


The proxy user.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="password">
<rng:data type="string">
<a:documentation>
1.0.0


The proxy password.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : 8080</a:documentation>
<rng:element name="port">
<rng:data type="int">
<a:documentation>
1.0.0


The proxy port.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="host">
<rng:data type="string">
<a:documentation>
1.0.0


The proxy host.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="nonProxyHosts">
<rng:data type="string">
<a:documentation>
1.0.0


The list of non-proxied hosts (delimited by |).


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="id">
<rng:data type="string">
<a:documentation>
1.0.0
</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="Server">
<a:documentation>
1.0.0


The <code>&lt;server&gt;</code> element contains informations required to a server settings.

</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="username">
<rng:data type="string">
<a:documentation>
1.0.0


The username used to authenticate.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="password">
<rng:data type="string">
<a:documentation>
1.0.0


The password used in conjunction with the username to authenticate.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="privateKey">
<rng:data type="string">
<a:documentation>
1.0.0


The private key location used to authenticate.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="passphrase">
<rng:data type="string">
<a:documentation>
1.0.0


The passphrase used in conjunction with the privateKey to authenticate.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="filePermissions">
<rng:data type="string">
<a:documentation>
1.0.0


The permissions for files when they are created.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="directoryPermissions">
<rng:data type="string">
<a:documentation>
1.0.0


The permissions for directories when they are created.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="configuration">
<a:documentation>
0.0.0+


Extra configuration for the transport layer.


</a:documentation>


<rng:zeroOrMore>
<rng:element>
<rng:anyName/>
<rng:text/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="id">
<rng:data type="string">
<a:documentation>
1.0.0
</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="Profile">
<a:documentation>
1.0.0


Modifications to the build process which is keyed on some
sort of environmental parameter.


</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="activation">
<rng:ref name="Activation"/>
<a:documentation>
1.0.0


The conditional logic which will automatically
trigger the inclusion of this profile.


</a:documentation>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="properties">
<a:documentation>
0.0.0+

Extended configuration specific to this profile goes here.
Contents take the form of
<property.name>property.value</property.name>

</a:documentation>


<rng:zeroOrMore>
<rng:element>
<rng:anyName/>
<rng:text/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="repositories">
<a:documentation>
1.0.0


The lists of the remote repositories.


</a:documentation>


<rng:zeroOrMore>
<rng:element name="repository">
<rng:ref name="Repository"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="pluginRepositories">
<a:documentation>
1.0.0


The lists of the remote repositories for discovering plugins.


</a:documentation>


<rng:zeroOrMore>
<rng:element name="pluginRepository">
<rng:ref name="Repository"/>
</rng:element>
</rng:zeroOrMore>


</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="id">
<rng:data type="string">
<a:documentation>
1.0.0
</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="Repository">
<a:documentation>
1.0.0

Repository contains the information needed for establishing
connections with remote repoistory

</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="releases">
<rng:ref name="RepositoryPolicy"/>
<a:documentation>
1.0.0

How to handle downloading of releases from this repository

</a:documentation>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="snapshots">
<rng:ref name="RepositoryPolicy"/>
<a:documentation>
1.0.0

How to handle downloading of snapshots from this repository

</a:documentation>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="id">
<rng:data type="string">
<a:documentation>
1.0.0


A unique identifier for a repository.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="name">
<rng:data type="string">
<a:documentation>
1.0.0


Human readable name of the repository.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="url">
<rng:data type="string">
<a:documentation>
1.0.0


The url of the repository.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : default</a:documentation>
<rng:element name="layout">
<rng:data type="string">
<a:documentation>
1.0.0

The type of layout this repository uses for locating and
storing artifacts - can be "legacy" or "default".

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="RepositoryPolicy">
<a:documentation>
1.0.0
Download policy
</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : true</a:documentation>
<rng:element name="enabled">
<rng:data type="boolean">
<a:documentation>
1.0.0

Whether to use this repository for downloading this type of
artifact.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="updatePolicy">
<rng:data type="string">
<a:documentation>
1.0.0

The frequency for downloading updates - can be "always",
"daily" (default), "interval:XXX" (in minutes) or "never"
(only if it doesn't exist locally).

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="checksumPolicy">
<rng:data type="string">
<a:documentation>
1.0.0

What to do when verification of an artifact checksum fails -
warn, fail, etc. Valid values are "fail" or "warn".

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="Activation">
<a:documentation>
1.0.0


The conditions within the build runtime environment which will trigger
the automatic inclusion of the parent build profile.


</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<a:documentation>
default value is : false</a:documentation>
<rng:element name="activeByDefault">
<rng:data type="boolean">
<a:documentation>
1.0.0

Flag specifying whether this profile is active as a default.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="jdk">
<rng:data type="string">
<a:documentation>
1.0.0


Specifies that this profile will be activated when a matching JDK is detected.


</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="os">
<rng:ref name="ActivationOS"/>
<a:documentation>
1.0.0


Specifies that this profile will be activated when matching OS attributes are detected.


</a:documentation>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="property">
<rng:ref name="ActivationProperty"/>
<a:documentation>
1.0.0


Specifies that this profile will be activated when this System property is specified.


</a:documentation>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="file">
<rng:ref name="ActivationFile"/>
<a:documentation>
1.0.0


Specifies that this profile will be activated based on existence of a file.


</a:documentation>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="ActivationFile">
<a:documentation>
1.0.0


This is the file specification used to activate a profile. The missing value will be a the location
of a file that needs to exist, and if it doesn't the profile must run. On the other hand exists will test
for the existence of the file and if it is there will run the profile.


</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="missing">
<rng:data type="string">
<a:documentation>
1.0.0

The name of the file that should be missing to activate a
profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="exists">
<rng:data type="string">
<a:documentation>
1.0.0

The name of the file that should exist to activate a profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="ActivationOS">
<a:documentation>
1.0.0


This is an activator which will detect an operating system's attributes in order to activate
its profile.


</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="name">
<rng:data type="string">
<a:documentation>
1.0.0

The name of the OS to be used to activate a profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="family">
<rng:data type="string">
<a:documentation>
1.0.0

The general family of the OS to be used to activate a
profile (e.g. 'windows')

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="arch">
<rng:data type="string">
<a:documentation>
1.0.0

The architecture of the OS to be used to activate a profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="version">
<rng:data type="string">
<a:documentation>
1.0.0

The version of the OS to be used to activate a profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
<rng:define name="ActivationProperty">
<a:documentation>
1.0.0


This is the property specification used to activate a profile. If the value field is empty,
then the existence of the named property will activate the profile, otherwise it does a case-sensitive
match against the property value as well.


</a:documentation>
<rng:interleave>
<rng:optional>
<rng:optional>
<rng:element name="name">
<rng:data type="string">
<a:documentation>
1.0.0

The name of the property to be used to activate a profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
<rng:optional>
<rng:optional>
<rng:element name="value">
<rng:data type="string">
<a:documentation>
1.0.0

The value of the property to be used to activate a profile.

</a:documentation>
</rng:data>
</rng:element>
</rng:optional>
</rng:optional>
</rng:interleave>
</rng:define>
</rng:grammar>