Building Components 1-2-3 | |
Author: Chris Herron (cherron at sapient.com) Version: $Revision: 1.6 $($Author: dvoet $ / $Date: 2003/04/29 21:21:51 $) Created: January 2002
|
| |
This document is a short tutorial on how to build a simple
Carbon Component. It will give you some understanding of:
- What parts make up a Carbon Component.
- How these parts fit together.
- How to use (obtain and call) a Carbon Component.
- How a Carbon Component uses another Carbon Component (configured references)
|
You have successfully obtained and compiled the Carbon source
tree. See the build document for instructions on how to do this.
|
|
| |
A Carbon Component is comprised of these parts:
- Functional Interface
- The Functional Interface is a Java interface that defines the methods the
Component will expose to its clients. It should extend
org.sape.carbon.core.component.FunctionalInterface
(or some subclass of it).
- Functional Implementation
- The Functional Implementation is a Java class that implements the Functional
Interface. It may also implement other Carbon interfaces to take advantage of
Carbon's Configuration and Lifecycle services.
- Configuration Interface (optional)
- The Configuration Interface is a Java interface that describes the configurable
attributes of the Component. Carbon's Configuration service can create a class
at runtime that implements this interface, and retrieves the actual configuration
data from some physical source (e.g. an XML file). Providing the Component implements
the
Configurable interface, it will be automatically provided with
its configuration on creation, and when reconfigured.
- Configuration Data (required)
- The Configuration Data provides Carbon with information about how to instantiate
and configure the Component. Currently Carbon supports XML based Configuration
Data. This Data is stored in a tree hierarchy, where each configuration file describes
a 'logical Component'. Since a Component's Configuration can contain references
to other logical Components, the structure of an entire system/application can
be described completely using config.
|
| |
As a simple demonstration, we will build a simple Component
called HelloWorld.
Related files
HelloWorld Component Parts:
Functional Interface:
<workdir>/org/examples/HelloWorld.java
Functional Implementation:
<workdir>/org/examples/HelloWorldImpl.java
Configuration Interface:
(not needed for this example)
Configuration Data:
<configdir>/examples/HelloWorld.xml
Other Files:
<workdir>/org/examples/test/HelloWorldTest.java
|
|
1.1 Create the HelloWorld interface. |
This interface should expose the method
String sayHelloWorld() and must extend the marker
interface FuntionalInterface.
<workdir>/org/examples/HelloWorld.java
package org.examples;
/*
* Import the FunctionalInterface interface.
* This does not define any methods, it is used as only
* as a marker so that Carbon may recognize component
* interfaces and their implementations.
*/
import org.sape.carbon.core.component.FunctionalInterface
public interface HelloWorld extends FunctionalInterface {
String sayHelloWorld();
}
|
|
|
1.2 Write the code to define the HelloWorldImpl class. |
This is the implementation class that provides the
functionality of your component. It must implement the interface that was
created above.
<workdir>/org/examples/HelloWorldImpl.java
package org.examples;
public class HelloWorldImpl implements HelloWorld {
public String sayHelloWorld() {
return "Hello World!";
}
}
|
|
|
1.3 Create the Configuration file. |
This is the basic component configuration file containing
the least amount of configuration necessary to create a working Carbon
Component.
Note: Configuration files are
case-sensitive and all class references must me fully-qualified.
<configdir>/org/examples/HelloWorld.xml
<Configuration
ConfigurationInterface="org.sape.carbon.core.component.ComponentConfiguration">
<FunctionalInterface>
org.examples.HelloWorld
</FunctionalInterface>
<FunctionalImplementationClass>
org.examples.HelloWorldImpl
</FunctionalImplementationClass>
</Configuration>
|
|
|
1.4 Create a test class for your component. |
This test will be used to retrieve the component you've
just built from the Carbon Component Service. As a result of making this first
call to the Lookup Service, the Core Carbon will bootstrap the system.
<workdir>/org/examples/test/HelloWorldTest.java
package org.examples;
import org.sape.carbon.core.component.Lookup;
public class HelloWorldTest {
public static void main(String [] arguments) {
/*
Lookup the logical Component instance "/examples/HelloWorld",
which is described by config file:
<configdir>/examples/HelloWorld.xml.
Behind the scenes, Carbon instantiates the implementation
and returns a 'proxy' that implements the Functional Interface,
which in this case is 'HelloWorld'.
*/
HelloWorld helloWorld =
(HelloWorld) Lookup.getInstance().fetchComponent("/examples/HelloWorld");
System.out.println( helloWorld.sayHelloWorld() );
}
}
// TODO GH: insert the command line for running this
|
|
This demonstrates one Component using another, where the 'client' Component is configured
automatically with a reference to the Component it needs to use. This
HelloWorldService
component has a Configuration interface, and will utilize a different logical instance
of the HelloWorld component. This example gives less guidance for the parts you
have already learned from example #1. HelloWorldService Component Parts:
Related files
Functional Interface:
<workdir>/code/org/examples/HelloWorldService.java
Functional Implementation:
<workdir>/code/org/examples/HelloWorldServiceImpl.java
Configuration Interface:
<workdir>/code/org/examples/HelloWorldServiceConfiguration.java Configuration
Data:
<configdir>/examples/HelloWorldService.xml
Configuration Data File:
<configdir>/examples/AnotherHelloWorld.xml
(to provide another instance of the HelloWorld Component)
Configuration Data File:
<workdir>/org/examples/test/HelloWorldServiceTest.java
|
|
|
2.1 Create the HelloWorldService interface |
Define a method String performService() .
|
|
|
2.2 Create the HelloWorldServiceConfiguration
interface. |
Define the accessor for property "MyDependency":
HelloWorld getMyDependency() . This will give the component easy and
configurable access to the referenced component. This reference may be
changed, without recompiling, by simply altering the configuration.
<workdir>/org/examples/HelloWorldServiceConfiguration.java
package org.examples;
import org.sape.carbon.core.component.ComponentConfiguration;
public interface HelloWorldServiceConfiguration
extends ComponentConfiguration {
// This describes a property of type HelloWorld
// The configuration data will point to a logical instance
// of a HelloWorld Component
HelloWorld getMyDependency();
// This is the setter method for MyDependency
// Added for programatic changes to configuration
void setMyDependency(HelloWorld myDependency);
}
|
|
|
2.3 Create the HelloWorldServiceImpl class. |
This is the implementation for the
HelloWorldService.
<workdir>/org/examples/HelloWorldServiceImpl.java
package org.examples;
/*
ComponentConfiguration is the parent for Components'
Configuration interfaces import org.sape.carbon.core.component.ComponentConfiguration;
Configurable is the Lifecycle interface that (if implemented)
is used by Carbon to provide a Component with its configuration
*/
import org.sape.carbon.core.component.lifecycle.Configurable;
public class HelloWorldServiceImpl implements HelloWorldService, Configurable {
private HelloWorld helloWorld = null;
/**
* The configure method is called when the Component
* is created (and reconfigured)
*/
public void configure(ComponentConfiguration config) {
helloWorld = ((HelloWorldServiceConfiguration) config).getMyDependency();
}
/**
* Implements the service method
*/
public String performService() {
String result = helloWorld.sayHelloWorld();
return "Service Result: " + result;
}
}
|
|
|
2.4 Create the Configuration data file. |
Create the Configuration data file for HelloWorldService.
Notice the way the data for the component reference is created using the
"ref:///" URI starter.
<configdir>/examples/HelloWorldService.xml
<!-- Note that the Configuration Interface is now HelloWorldServiceConfiguration -->
<Configuration
ConfigurationInterface="org.examples.HelloWorldServiceConfiguration">
<functionalInterface>
org.examples.HelloWorldService
</functionalInterface>
<FunctionalImplementationClass>
org.examples.HelloWorldServiceImpl
</FunctionalImplementationClass>
<!-- This is the logical location of another Component
that HelloWorldService is going to use -->
<MyDependency>ref:///examples/AnotherHelloWorld<MyDependency>
</Configuration>
|
|
|
2.5 Create the Configuration data file. |
This is to demonstrate reuse
through configuration - HelloWorldService uses a separately configured instance
of the HelloWorld Component.
<configdir>/org/examples/AnotherHelloWorld.xml
<Configuration
ConfigurationInterface="org.sape.carbon.core.component.ComponentConfiguration">
<FunctionalInterface>
org.examples.HelloWorld
</FunctionalInterface>
<FunctionalImplementationClass>
org.examples.HelloWorldImpl
</FunctionalImplementationClass>
</Configuration>
|
|
|
2.6 Create a class to run as a test |
This is a simple class that will make a request to retrieve
the an instance of your new HelloWoldService.
<workdir>/org/examples/test/HelloWorldServiceTest.java
package org.examples;
import org.sape.carbon.core.component.Lookup;
import org.examples.HelloWorld;
public class HelloWorldServiceTest {
public static void main(String [] arguments) {
// Lookup the logical Component instance "/examples/HelloWorldService",
// which is described by config file:
// <configdir>/examples/HelloWorldService.xml.
// Behind the scenes, Carbon instantiates the implementation
// and returns a 'proxy' that implements the Functional Interface,
// which in this case is 'HelloWorldService'. Additionally it will configure
// the component with its dependency, Component "/examples/AnotherHelloWorld"
HelloWorldService helloWorldService =
(HelloWorldService)
Lookup.getInstance().fetchComponent(
"/examples/HelloWorldService");
System.out.println( helloWorldService.performService() );
}
}
|
|
|