|
Warrior Platform as an API
This page explains how to use Warrior as an XML UI Framework,
without having to run the Warrior platform self-extracting
installer.
Possible uses of Warrior as an API are the following:
- Customizable GUIs.- Existing Swing applications
that need to be extended with a customizable mechanism
for defining additional GUIs, particularly GUI specifications
served over HTTP (with security considerations) can include
the Warrior platform for that purpose.
- New GUI applications.- The Warrior platform may
be used in new Java applications that need a high-productivity
mechanism for defining GUIs. In our own experience, using
XAMJ is much easier than writing Swing code.
- Browser for a new content type.- The Warrior
platform can be customized to handle new content types.
Warrior is not only a XAMJ platform. For example, authors
of other XML UI languages could deploy
Warrior with clientlet selectors for those languages.
The platform takes care of HTTP requests and navigation.
Requirements
The Warrior Platform requires Java 5 (JDK 1.5+). XAMJ
APIs rely on Java 5 features such as generics.
Library Files
The JAR files needed are available in files
named warrior*-files.zip (version 0.93.2
or newer) which you
will find in our archive.
(They are also available in the directory created
by the self-extracting installer.) Yes, you
will need all the JARs shipped with a release. They include
warrior.jar (the Warrior Platform), xamj.jar (the
XAMJ APIs), security.jar (Warrior security policy),
plus open source externals used
for logging, XML parsing, Java compilation, etc.
Note that XAMJ invokes the JDT compiler with the
default assumption that xamj.jar and warrior.jar
are in the same directory as the first entry in your classpath.
This will be the case, for example, if your application is an
executable JAR file and Warrior JARs are in the same directory.
In order to override this, you may define the path
to xamj.jar with property xamj.clientlet.class.path
and the path to warrior.jar with property xamj.engine.class.path.
Warrior is released under a BSD licence.
Please check the file named ACKNOWLEDGMENTS for
licensing of external libraries.
API Documentation
Check the Javadoc-generated Warrior Platform API Documentation. Note that XAMJ documents don't have access to this API. Their access is restricted to the XAMJ DOM and Clientlet API.
Access to your Code by XAMJ Documents
The primary mechanism for having XAMJ documents
link a JAR file or directory by default is that
of defining the
xamj.clientlet.class.path property
in the application that invokes Warrior.
The value of this property has CLASSPATH format,
and it must include the location of xamj.jar.
XAMJ documents can also include one or more archive
elements below the head element, which specify
relative or absolute URLs to JAR files to be linked during
compilation and loaded by
the runtime.
An internal URL protocol, res,
may be used to access resources in the application's classpath, such
as images and XAMJ documents included with your application.
It could also be used to load JAR files included as resources
(i.e. JAR files within your classpath JARs or directories --- which
is not the same as JARs in your classpath.)
XAMJ code could then look as follows:
<xamj>
<head>
<archive>res:/path/to/file.jar</archive>
<import>my.package.*</import>
</head>
...
</xamj>
Platform API Overview
You will need to instantiate the PlatformAccess
singleton as follows:
import org.xamjwg.platform.*;
import org.xamjwg.event.*;
import org.xamjwg.clientlet.*;
import org.xamjwg.dom.*;
import org.xamjwg.io.*;
...
PlatformAccess warrior = PlatformAccess.getInstance();
In order to initialize the platform with a security
policy and default Look & Feel, call:
warrior.initPlatform();
This is an optional step in applications that are
(1) not concerned with security or that (2) wish to install
their own security policy. The former is not recommended
because XAMJ documents easily served via HTTP would
have full access to the system running your application,
but this up to you. In the latter scenario,
check method createHostPermission which
is necessary for managed stores to work.
To launch a XAMJ document in a platform window or
browser (depending on document disposition) use:
warrior.launchLocal(new String[] { "http://path/to/document.xamj" });
If instead you prefer to embed a Warrior browser frame
in your own Swing/AWT component, your code should look
as follows:
XFrameElement frame = warrior.createFrame();
Component frameComponent = warrior.getComponent(frame);
// Add frameComponent to your Swing code
frame.navigate("http://path/to/document.xamj");
The addXamjListener method can be helpful
in receiving frame on-progress events or
on-property-change events for the href
property of a frame.
Alternatively, you can request a lightweight component
asynchronously from a XAMJ document URL.
AsyncResult<java.awt.Component> asyncResult = warrior.requestComponent("http://path/to/document.xamj");
final PlatformAccess finalWarrior = warrior;
asyncResult.addResultListener(new AsyncResultListener<XDocument>() {
public void resultReceived(AsyncResultEvent<XDocument> event) {
// This is invoked in the Warrior event dispatch thread,
// which happens to be the same as the AWT thread.
java.awt.Component component = event.getResult();
// Now you can add component to your Swing application.
// Note that invalidating the parent may be necessary.
}
public void exceptionReceived(AsyncResultEvent<Throwable> event) {
// Handle web response error: event.getResult()
}
});
The main difference between frames and widgets requested
asynchronously is that navigation can occur in frames.
Custom Content Types
The Warrior Platform can be extended to handle additional
content types by adding clientlet selectors. A
clientlet is an interface that is implemented to
process a web request response. A clientlet
selector is set up by calling addClientletSelector
as follows:
import org.xamjwg.platform.*;
import org.xamjwg.event.*;
import org.xamjwg.clientlet.*;
import org.xamjwg.dom.*;
import org.xamjwg.io.*;
...
PlatformAccess warrior = PlatformAccess.getInstance();
warrior.addClientletSelector(new MyClientletSelector());
warrior.launch();
Let's say the clientlet selector MyClientletSelector
only cares about mime type application/x-text. You can
start by writing it as follows:
import org.xamjwg.platform.*;
import org.xamjwg.clientlet.*;
public class MyClientletSelector implements ClientletSelector {
public Clientlet select(ClientletRequest request, ClientletResponse response) {
String mimeType = response.getMimeType();
if("application/x-text".equals(mimeType)) {
return MyTextClientlet();
}
else {
return SKIP;
}
}
}
Now you need to write the clientlet referred in the
code above, MyTextClientlet. This clientlet
needs to convert the web response content into something
renderable by Warrior. In this example, we will convert
the response into a Swing JTextArea component.
import org.xamjwg.clientlet.*;
import javax.swing.*;
public class MyTextClientlet implements Clientlet {
public void process(ClientletContext context) throws ClientletException {
try {
InputStream in = context.getResponse().getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer textBuffer = new StringBuffer();
while((String line = reader.readLine()) != null) {
textBuffer.append(line);
textBuffer.append("\r\n");
}
JTextArea textArea = new JTextArea(textBuffer.toString());
ClientletContent content = context.createComponentContent(textArea);
content.setTitle("My Text Document");
context.setContent(content);
} catch(IOException ioe) {
throw new ClientletException(ioe);
}
}
}
The ClientletContext interface contains methods
that allow clientlets to navigate to other documents, to
asynchronously request files such as images, and so on.
Note that any security requirements of custom content
handlers added this way are the responsibility of each
clientlet implementation. For example, if the clientlet
allows arbitrary Java code to be executed, the clientlet
should use a secure class loader with an appropriate
security policy. (Calling defineClass with
a proper CodeSource will work well most
of the time, as it will use Warrior's primary policy.)
|