bloritsch 01/10/30 06:01:18
Modified: src/documentation/xdocs/developing implementing.xml
Log:
remove tabs
Revision Changes Path
1.5 +476 -476
jakarta-avalon/src/documentation/xdocs/developing/implementing.xml
Index: implementing.xml
===================================================================
RCS file:
/home/cvs/jakarta-avalon/src/documentation/xdocs/developing/implementing.xml,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- implementing.xml 2001/10/29 13:32:04 1.4
+++ implementing.xml 2001/10/30 14:01:18 1.5
@@ -41,51 +41,51 @@
<title>Choosing the Concern Areas</title>
<para>
We have already defined the Role and the Interface for our
- DocumentRepository Component in the last chapter, we are ready to
- create the implementation. Because the interface for the
- DocumentRepository only defines one method, we have an opportunity to
- create a thread-safe Component. This is the most desired type of
- component because it allows for the least amount of resource
- utilization. In order for our implementation to be thread-safe, we do
- need to be careful about how we implement the Component. Since all of
- our documents are stored in a database, and we desire to use an
- external Guardian Component, we will need access to other Components.
- As responsible developers, we will want to log messages that will help
- us debug our component, and track down what is going on internally.
- The beauty of the Avalon Framework is that you only implement the
- interfaces you need, and ignore the ones you don't. This is where
- Separation of Concerns pays off. As you find you need a new concern
- area addressed, you merely implement the associated interface, and
- incorporate the new functionality. To the client of your Component,
- there is no difference.
+ DocumentRepository Component in the last chapter, we are ready to
+ create the implementation. Because the interface for the
+ DocumentRepository only defines one method, we have an opportunity to
+ create a thread-safe Component. This is the most desired type of
+ component because it allows for the least amount of resource
+ utilization. In order for our implementation to be thread-safe, we
do
+ need to be careful about how we implement the Component. Since all
of
+ our documents are stored in a database, and we desire to use an
+ external Guardian Component, we will need access to other Components.
+ As responsible developers, we will want to log messages that will
help
+ us debug our component, and track down what is going on internally.
+ The beauty of the Avalon Framework is that you only implement the
+ interfaces you need, and ignore the ones you don't. This is where
+ Separation of Concerns pays off. As you find you need a new concern
+ area addressed, you merely implement the associated interface, and
+ incorporate the new functionality. To the client of your Component,
+ there is no difference.
</para>
<para>
Since it is a design goal to be thread-safe, we already know that we
- need to implement the ThreadSafe interface. The DocumentRepository
- interface only has one method, so the use of the Component's work
- interface is compatible with that requirement. Furthermore, we know
- that a Component will not be used before it is fully initialized, nor
- will it be used once it is destroyed.
+ need to implement the ThreadSafe interface. The DocumentRepository
+ interface only has one method, so the use of the Component's work
+ interface is compatible with that requirement. Furthermore, we know
+ that a Component will not be used before it is fully initialized, nor
+ will it be used once it is destroyed.
</para>
<para>
There are a couple of implicit interfaces that we need to implement
to
- accomplish the design. We want our solution to be as secure as
- possible and explicitly track whether the Component is fully
- initialized or not. To accomplish this goal, we will implement the
- Initializable and Disposable interfaces. Since specific information
- about our environment may change, or may need to be customized, we need
- to make our DocumentRepository Configurable. Our Component makes use
- of other Components, and they method that Avalon provides to get
- instances of the required Component is by using a ComponentManager. We
- will need to implement the Composable interface to get an instance of
- the ComponentManager.
+ accomplish the design. We want our solution to be as secure as
+ possible and explicitly track whether the Component is fully
+ initialized or not. To accomplish this goal, we will implement the
+ Initializable and Disposable interfaces. Since specific information
+ about our environment may change, or may need to be customized, we
need
+ to make our DocumentRepository Configurable. Our Component makes use
+ of other Components, and they method that Avalon provides to get
+ instances of the required Component is by using a ComponentManager.
We
+ will need to implement the Composable interface to get an instance of
+ the ComponentManager.
</para>
<para>
Because the DocumentRepository accesses the documents in the
database,
- we need to make a decision. Do we want to take advantage of the Avalon
- Excalibur DataSourceComponent, or do we want to implement our own
- Connection management code. For the sake of this paper, we will use
- the DataSourceComponent.
+ we need to make a decision. Do we want to take advantage of the
Avalon
+ Excalibur DataSourceComponent, or do we want to implement our own
+ Connection management code. For the sake of this paper, we will use
+ the DataSourceComponent.
</para>
<para>
At this point, our skeleton class looks like this:
@@ -116,12 +116,12 @@
public final void configure(Configuration conf)
throws ConfigurationException {
if (initialized || disposed) {
-
+
throw new IllegalStateException ("Illegal call");
}
if (null == this.dbResource) {
- this.dbResource = conf.getChild("dbpool").getValue();
+ this.dbResource = conf.getChild("dbpool").getValue();
getLogger().debug("Using database pool: " + this.dbResource);
// Notice the getLogger()? This is from AbstractLoggable
// which I extend for just about all my components.
@@ -145,11 +145,11 @@
}
public final void initialize() throws Exception {
- if (null == this.manager) throw new IllegalStateException("Not
Composed");
+ if (null == this.manager) throw new IllegalStateException("Not
Composed");
if (null == this.dbResource)
- throw new IllegalStateException("Not Configured");
+ throw new IllegalStateException("Not Configured");
- if (disposed) throw new IllegalStateException("Already
disposed");
+ if (disposed) throw new IllegalStateException("Already
disposed");
this.initialized = true;
}
@@ -170,56 +170,56 @@
</programlisting>
<para>
You will notice some constructs in the above code. When you are
- designing with security in mind, you should explicitly enforce every
- contract on your Component. Security is only as strong as the weakest
- link. You should only use a Component when you are certain it is fully
- initialized, and never use it when it is disposed of. I placed the
- logic that you would need in this skeleton class because that way you
- can adopt the same practices in classes that you write.
+ designing with security in mind, you should explicitly enforce every
+ contract on your Component. Security is only as strong as the
weakest
+ link. You should only use a Component when you are certain it is
fully
+ initialized, and never use it when it is disposed of. I placed the
+ logic that you would need in this skeleton class because that way you
+ can adopt the same practices in classes that you write.
</para>
</section>
<section>
<title>Instantiating and Managing Components</title>
<para>
In order for you to understand how the Container/Component
relationship
- works, we will first discuss the manual method of managing Components.
- Next, we will discuss how Avalon's Excalibur Component infrastructure
- hides the complexity from you. You will still find times when you
- would rather manage components yourself. Most of the time the power
- and flexibility of Excalibur is just what you need.
+ works, we will first discuss the manual method of managing
Components.
+ Next, we will discuss how Avalon's Excalibur Component infrastructure
+ hides the complexity from you. You will still find times when you
+ would rather manage components yourself. Most of the time the power
+ and flexibility of Excalibur is just what you need.
</para>
<section>
<title>The Manual Method</title>
- <para>
- All of Avalon's Components are created somewhere. The code that
- creates the Component is that Component's Container. The Container
- is responsible for managing the Component's lifecycle from
- construction through destruction. A Container can be the static
- "main" method called from a command line, or it can be another
- Component. Remember the Inversion of Control pattern when you
- design your Containers. Information and method calls should only
- flow from the Container to the Component.
- </para>
- <warning>
- <title>Subversion of Control</title>
- <para>
- Subversion of Control is the anti-pattern to Inversion of Control.
- Subversion of control is done when you pass a reference to a
- Component's Container to the Component. It is also done when you
- have a Component manage it's own lifecycle. Code that operates in
- this manner should be considered defective. The interactions that
- happen when you confuse the Container/Component relationship make
- the system harder to debug and security harder to audit.
- </para>
- </warning>
- <para>
- In order to manage the child Components, you need to keep a reference
- to them for their entire lifetime. Before the Container or any other
- Component can use the child Component, it must go through the
- initialization phase of its lifecycle. For our DocumentRepository,
- the code will look something like the following:
- </para>
- <programlisting>
+ <para>
+ All of Avalon's Components are created somewhere. The code that
+ creates the Component is that Component's Container. The Container
+ is responsible for managing the Component's lifecycle from
+ construction through destruction. A Container can be the static
+ "main" method called from a command line, or it can be another
+ Component. Remember the Inversion of Control pattern when you
+ design your Containers. Information and method calls should only
+ flow from the Container to the Component.
+ </para>
+ <warning>
+ <title>Subversion of Control</title>
+ <para>
+ Subversion of Control is the anti-pattern to Inversion of
Control.
+ Subversion of control is done when you pass a reference to a
+ Component's Container to the Component. It is also done when you
+ have a Component manage it's own lifecycle. Code that operates
in
+ this manner should be considered defective. The interactions
that
+ happen when you confuse the Container/Component relationship make
+ the system harder to debug and security harder to audit.
+ </para>
+ </warning>
+ <para>
+ In order to manage the child Components, you need to keep a
reference
+ to them for their entire lifetime. Before the Container or any
other
+ Component can use the child Component, it must go through the
+ initialization phase of its lifecycle. For our DocumentRepository,
+ the code will look something like the following:
+ </para>
+ <programlisting>
<![CDATA[
class ContainerComponent implements Component, Initializable, Disposable {
DocumentRepository docs = new DatabaseDocumentRepository();
@@ -251,136 +251,136 @@
}
}
]]>
- </programlisting>
- <para>
- For the sake of brevity, I removed all the explicit checking from the
- above code. You can see that manually creating and managing
- Components is very detailed. If you forget to do one step in the
- life of a Component, you will see bugs. This also requires intimate
- knowledge of the Components you are instantiating. An alternate
- approach would be to add a couple methods to the above
- ContainerComponent that handles the initialization of the components
- dynamically.
- </para>
+ </programlisting>
+ <para>
+ For the sake of brevity, I removed all the explicit checking from
the
+ above code. You can see that manually creating and managing
+ Components is very detailed. If you forget to do one step in the
+ life of a Component, you will see bugs. This also requires
intimate
+ knowledge of the Components you are instantiating. An alternate
+ approach would be to add a couple methods to the above
+ ContainerComponent that handles the initialization of the
components
+ dynamically.
+ </para>
</section>
<section>
<title>Automated Autonomy</title>
- <para>
- Developer's are naturally lazy, so they would spend the time to write
- a specialized ComponentManager that became the Container for all of
- their Components in the system. That way they would not have to be
- bothered with intimately knowing the interfaces of all the Components
- in a system. That can be a daunting task. The Avalon developers
- have created just such a beast. Avalon Excalibur's Component
- architecture includes a ComponentManager that is controlled by
- configuration files written in XML.
- </para>
- <para>
- There is a tradeoff when you relinquish the responsibility of
- managing a Component to Excalibur's ComponentManager. You relinquish
- the fine control over what Components are included in the
- ComponentManager. However, if you have a large system, you will find
- that manual control is a daunting task. In that case, it is better
- for the stability of the system for one entity to centrally manage
- all the Components in a system.
- </para>
- <para>
- Since there are varying levels of integration you want to achieve
- with Excalibur's Component Architecture, we will start with the
- lowest level. Excalibur has a group of ComponentHandler objects that
- act as individual Containers for one type of Component. They manage
- the complete life of your Component. Let me introduce the concept of
- lifestyle interfaces. A lifestyle interface describes how the system
- treats a Component. Since the lifestyle of a component has impact on
- the running of a system, we need to discuss the implications of the
- current lifestyle interfaces:
- </para>
- <itemizedlist>
- <listitem>
- <para>org.apache.avalon.framework.thread.SingleThreaded</para>
- <itemizedlist>
- <listitem>
- <para>
- Not thread-safe or reusable.
- </para>
- </listitem>
- <listitem>
- <para>
- When no lifestyle interface is supplied, this is assumed.
- </para>
- </listitem>
- <listitem>
- <para>
- A brand new instance is created every time the Component is
- requested.
- </para>
- </listitem>
- <listitem>
- <para>
- Creation and initialization is delayed until you request the
- Component.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>org.apache.avalon.framework.thread.Threadsafe</para>
- <itemizedlist>
- <listitem>
- <para>
- Component is fully reentrant, and complies with all
- principles of thread safety.
- </para>
- </listitem>
- <listitem>
- <para>
- One instance is created and shared with all Composables that
- request it.
- </para>
- </listitem>
- <listitem>
- <para>
- Creation and initialization is done when
ComponentHandler is
- created.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- <listitem>
- <para>org.apache.avalon.excalibur.pool.Poolable</para>
- <itemizedlist>
- <listitem>
- <para>
- Not thread-safe, but is fully reusable.
- </para>
- </listitem>
- <listitem>
- <para>
- A pool of instances is created and the free instances are
- returned to Composables that request it.
- </para>
- </listitem>
- <listitem>
- <para>
- Creation and initialization is done when
ComponentHandler is
- created.
- </para>
- </listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- <para>
- The ComponentHandler interface is very simple to deal with. You
- initialize the Constructor with the Java class, the Configuration
- object, the ConfigurationManager, a Context object, and a
- RoleManager. If you know that your Component will not need any of
- the aforementioned items, you can pass a null in its place. After
- that, when you need a reference to the Component, you call the "get"
- method. After you are done with it, you call the "put" method and
- pass the Component back to the ComponentHandler. The following code
- will make it easier to understand.
- </para>
- <programlisting>
+ <para>
+ Developer's are naturally lazy, so they would spend the time to
write
+ a specialized ComponentManager that became the Container for all of
+ their Components in the system. That way they would not have to be
+ bothered with intimately knowing the interfaces of all the
Components
+ in a system. That can be a daunting task. The Avalon developers
+ have created just such a beast. Avalon Excalibur's Component
+ architecture includes a ComponentManager that is controlled by
+ configuration files written in XML.
+ </para>
+ <para>
+ There is a tradeoff when you relinquish the responsibility of
+ managing a Component to Excalibur's ComponentManager. You
relinquish
+ the fine control over what Components are included in the
+ ComponentManager. However, if you have a large system, you will
find
+ that manual control is a daunting task. In that case, it is better
+ for the stability of the system for one entity to centrally manage
+ all the Components in a system.
+ </para>
+ <para>
+ Since there are varying levels of integration you want to achieve
+ with Excalibur's Component Architecture, we will start with the
+ lowest level. Excalibur has a group of ComponentHandler objects
that
+ act as individual Containers for one type of Component. They
manage
+ the complete life of your Component. Let me introduce the concept
of
+ lifestyle interfaces. A lifestyle interface describes how the
system
+ treats a Component. Since the lifestyle of a component has impact
on
+ the running of a system, we need to discuss the implications of the
+ current lifestyle interfaces:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>org.apache.avalon.framework.thread.SingleThreaded</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Not thread-safe or reusable.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When no lifestyle interface is supplied, this is assumed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A brand new instance is created every time the Component is
+ requested.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Creation and initialization is delayed until you request
the
+ Component.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>org.apache.avalon.framework.thread.Threadsafe</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Component is fully reentrant, and complies with all
+ principles of thread safety.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ One instance is created and shared with all Composables
that
+ request it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Creation and initialization is done when
ComponentHandler is
+ created.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>org.apache.avalon.excalibur.pool.Poolable</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Not thread-safe, but is fully reusable.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A pool of instances is created and the free instances are
+ returned to Composables that request it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Creation and initialization is done when
ComponentHandler is
+ created.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ <para>
+ The ComponentHandler interface is very simple to deal with. You
+ initialize the Constructor with the Java class, the Configuration
+ object, the ConfigurationManager, a Context object, and a
+ RoleManager. If you know that your Component will not need any of
+ the aforementioned items, you can pass a null in its place. After
+ that, when you need a reference to the Component, you call the
"get"
+ method. After you are done with it, you call the "put" method and
+ pass the Component back to the ComponentHandler. The following
code
+ will make it easier to understand.
+ </para>
+ <programlisting>
<![CDATA[
class ContainerComponent implements Component, Initializable, Disposable {
ComponentHandler docs = null;
@@ -417,20 +417,20 @@
}
}
]]>
- </programlisting>
- <para>
- At this point, we only saved ourselves a few lines of code. We still
- manually created our Configuration object, we still had to set the
- Logger, and we still had to initialize and dispose of the
- ComponentHandler objects. What we did at this point is simply protect
- ourselves from changing interfaces. You may find it better for your
- code to use this approach. Excalibur went further though. Most
- complex systems have configuration files, and they allow an
- administrator to alter vital Configuration information. Excalibur
- can read a configuration file in the following format, and build the
- Components in a system from it.
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ At this point, we only saved ourselves a few lines of code. We
still
+ manually created our Configuration object, we still had to set the
+ Logger, and we still had to initialize and dispose of the
+ ComponentHandler objects. What we did at this point is simply
protect
+ ourselves from changing interfaces. You may find it better for
your
+ code to use this approach. Excalibur went further though. Most
+ complex systems have configuration files, and they allow an
+ administrator to alter vital Configuration information. Excalibur
+ can read a configuration file in the following format, and build
the
+ Components in a system from it.
+ </para>
+ <programlisting>
<![CDATA[
<my-system>
<component
@@ -440,7 +440,7 @@
class="org.apache.avalon.excalibur.datasource.JdbcDataSource">
<pool-controller min="5" max="10"/>
<auto-commit>false</auto-commit>
- <driver>org.mysql.MySqlDriver</driver>
+ <driver>org.mysql.MySqlDriver</driver>
<dburl>jdbc:mysql:localhost/mydb</dburl>
<user>test</user>
<password>test</password>
@@ -449,7 +449,7 @@
class="org.apache.avalon.excalibur.datasource.JdbcDataSource">
<pool-controller min="5" max="10"/>
<auto-commit>false</auto-commit>
- <driver>org.mysql.MySqlDriver</driver>
+ <driver>org.mysql.MySqlDriver</driver>
<dburl>jdbc:mysql:localhost/myotherdb</dburl>
<user>test</user>
<password>test</password>
@@ -468,32 +468,32 @@
</component>
</my-system>
]]>
- </programlisting>
- <para>
- The root element can be anything you want. You will notice that we
- now have several Components defined. We have our familiar
- DocumentRepository class and GuardianComponent class, as well as a
- couple of Excalibur DataSourceComponent classes. In addition, now we
- have some specific configuration information for our Guardian
- Component. In order to read that information into your system,
- Avalon Framework provides some conveniences for you:
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ The root element can be anything you want. You will notice that we
+ now have several Components defined. We have our familiar
+ DocumentRepository class and GuardianComponent class, as well as a
+ couple of Excalibur DataSourceComponent classes. In addition, now
we
+ have some specific configuration information for our Guardian
+ Component. In order to read that information into your system,
+ Avalon Framework provides some conveniences for you:
+ </para>
+ <programlisting>
<![CDATA[
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
Configuration systemConf = builder.buildFromFile("/path/to/file.xconf");
]]>
- </programlisting>
- <para>
- This does simplify all the code we had for hand-building the
- Configuration element earlier, and it limits the amount of
- information we need to implicitly know right away. We will take one
- last look at our Container class and see if we really have some
- savings. Keep in mind that we have five components specified (a
- ComponentSelector counts as a Component), and configurations for
- each of them.
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ This does simplify all the code we had for hand-building the
+ Configuration element earlier, and it limits the amount of
+ information we need to implicitly know right away. We will take
one
+ last look at our Container class and see if we really have some
+ savings. Keep in mind that we have five components specified (a
+ ComponentSelector counts as a Component), and configurations for
+ each of them.
+ </para>
+ <programlisting>
<![CDATA[
class ContainerComponent implements Component, Initializable, Disposable {
ExcaliburComponentManager manager = new ExcaliburComponentManager();
@@ -514,38 +514,38 @@
}
}
]]>
- </programlisting>
- <para>
- Isn't this amazing? We have more than twice the number Components
- initialized and ready for use with less than half the code (six lines
- of code instead of thirteen lines of code). There is the drawback of
- the Configuration file looking somewhat crazy, but it minimizes the
- amount of code you have to write.
- </para>
- <para>
- There is a lot of activity happening under the hood of the
- ExcaliburComponentManager. For each "component" element in the
- configuration file, Excalibur creates a ComponentHandler for each
- class entry and maps it to the role entry. The "component" element
- and all it's child elements are used for the Configuration of the
- Component. When the Component is an ExcaliburComponentSelector, the
- Excalibur reads each "component-instance" element and performs the
- same type of operation as before-this time mapping to the hint entry.
- </para>
- <section>
- <title>Making the Configuration Pretty</title>
- <para>
- We can manage the configuration file's appearance with the use of
- aliases. Excalibur uses a RoleManager to provide aliases for the
- configuration system. A RoleManager can either be a dedicated
- class that you create, or you can use the DefaultRoleManager and
- pass in a Configuration object. If I use the DefaultRoleManager, I
- will hide the role configuration file inside the jar with the rest
- of the system. This is because the role configuration file is only
- going to be altered by developers. Below is the interface for the
- RoleManager:
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ Isn't this amazing? We have more than twice the number Components
+ initialized and ready for use with less than half the code (six
lines
+ of code instead of thirteen lines of code). There is the drawback
of
+ the Configuration file looking somewhat crazy, but it minimizes the
+ amount of code you have to write.
+ </para>
+ <para>
+ There is a lot of activity happening under the hood of the
+ ExcaliburComponentManager. For each "component" element in the
+ configuration file, Excalibur creates a ComponentHandler for each
+ class entry and maps it to the role entry. The "component" element
+ and all it's child elements are used for the Configuration of the
+ Component. When the Component is an ExcaliburComponentSelector,
the
+ Excalibur reads each "component-instance" element and performs the
+ same type of operation as before-this time mapping to the hint
entry.
+ </para>
+ <section>
+ <title>Making the Configuration Pretty</title>
+ <para>
+ We can manage the configuration file's appearance with the use of
+ aliases. Excalibur uses a RoleManager to provide aliases for the
+ configuration system. A RoleManager can either be a dedicated
+ class that you create, or you can use the DefaultRoleManager and
+ pass in a Configuration object. If I use the
DefaultRoleManager, I
+ will hide the role configuration file inside the jar with the
rest
+ of the system. This is because the role configuration file is
only
+ going to be altered by developers. Below is the interface for
the
+ RoleManager:
+ </para>
+ <programlisting>
<![CDATA[
interface RoleManager {
String getRoleForName( String shorthandName );
@@ -553,26 +553,26 @@
String getDefaultClassNameForHint( String hint, String shorthand );
}
]]>
- </programlisting>
- <para>
- Let's take a look at how Excalibur uses the RoleManager in our
- scheme. First, Excalibur will cycle through all the elements that
- are direct children of the root element. This includes all
- "component" elements like before, but this time when Excalibur
- doesn't recognize an element name, it asks the RoleManager which
- role we should use for this Component. If the RoleManager returns
- null, the element and all it's child elements are ignored. Next,
- Excalibur derives the class name from the role name. The last
- method is to dynamically map a class name to a ComponentSelector's
- child type.
- </para>
- <para>
- Excalibur provides a default implementation of the RoleManager that
- is configured with an XML configuration file. The markup is very
- simple, and it hides all the extra information you don't want your
- administrator to see.
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ Let's take a look at how Excalibur uses the RoleManager in our
+ scheme. First, Excalibur will cycle through all the elements
that
+ are direct children of the root element. This includes all
+ "component" elements like before, but this time when Excalibur
+ doesn't recognize an element name, it asks the RoleManager which
+ role we should use for this Component. If the RoleManager
returns
+ null, the element and all it's child elements are ignored. Next,
+ Excalibur derives the class name from the role name. The last
+ method is to dynamically map a class name to a
ComponentSelector's
+ child type.
+ </para>
+ <para>
+ Excalibur provides a default implementation of the RoleManager
that
+ is configured with an XML configuration file. The markup is very
+ simple, and it hides all the extra information you don't want
your
+ administrator to see.
+ </para>
+ <programlisting>
<![CDATA[
<role-list>
<role
@@ -594,18 +594,18 @@
"org.apache.bizserver.docs.DocumentGuardianComponent"/>
</role-list>
]]>
- </programlisting>
- <para>
- In order to use the RoleManager, you do need to alter the
- "initialize" method of our Container class. You are using the
- configuration builder to build a Configuration tree from this
- file. Please remember, if you are going to use a RoleManager, you
- must call the "setRoleManager" method <emphasis>before</emphasis>
- the "configure" method. To demonstrate how you would retrieve this
- XML file from the class loader, I will demonstrate the technique
- below:
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ In order to use the RoleManager, you do need to alter the
+ "initialize" method of our Container class. You are using the
+ configuration builder to build a Configuration tree from this
+ file. Please remember, if you are going to use a RoleManager,
you
+ must call the "setRoleManager" method <emphasis>before</emphasis>
+ the "configure" method. To demonstrate how you would retrieve
this
+ XML file from the class loader, I will demonstrate the technique
+ below:
+ </para>
+ <programlisting>
<![CDATA[
DefaultConfigurationBuilder builder =
new DefaultConfigurationBuilder();
@@ -624,12 +624,12 @@
this.manager.configure(sysConfig);
this.manager.initialize();
]]>
- </programlisting>
- <para>
- Since we added six more lines of code, we need to see what it
- bought us. Our final configuration file can be written like this:
- </para>
- <programlisting>
+ </programlisting>
+ <para>
+ Since we added six more lines of code, we need to see what it
+ bought us. Our final configuration file can be written like
this:
+ </para>
+ <programlisting>
<![CDATA[
<my-system>
<datasources>
@@ -657,13 +657,13 @@
</guardian>
</my-system>
]]>
- </programlisting>
- <para>
- As you can see, this is much more readable than how we started.
- Now we can add any number of components to our system, and we won't
- have to write any more code to support them.
- </para>
- </section>
+ </programlisting>
+ <para>
+ As you can see, this is much more readable than how we started.
+ Now we can add any number of components to our system, and we
won't
+ have to write any more code to support them.
+ </para>
+ </section>
</section>
</section>
</section>
@@ -683,25 +683,25 @@
<title>Rules for Using the Component Management Infrastructure</title>
<para>
The Component management infrastructure requires that you release any
- Component for which you have obtained a reference. The reason for this
- restriction is so that the Component's resources can be properly
- managed. A ComponentManager is designed for instances when you have
- multiple types of Components with distinct roles. A ComponentSelector
- is designed for instances when you have multiple types of Components
- with the same role. Another unique aspect of the ComponentSelector is
- that it is a Component by design. This enables us to get a
- ComponentSelector from a ComponentManager.
+ Component for which you have obtained a reference. The reason for
this
+ restriction is so that the Component's resources can be properly
+ managed. A ComponentManager is designed for instances when you have
+ multiple types of Components with distinct roles. A
ComponentSelector
+ is designed for instances when you have multiple types of Components
+ with the same role. Another unique aspect of the ComponentSelector
is
+ that it is a Component by design. This enables us to get a
+ ComponentSelector from a ComponentManager.
</para>
<para>
There are two valid approaches for handling references to external
- Components. You can obtain your references during initialization, and
- release them during disposal. You may also encapsulate the Component
- handling in a try/catch/finally block. Each has its advantages and
- disadvantages.
+ Components. You can obtain your references during initialization,
and
+ release them during disposal. You may also encapsulate the Component
+ handling in a try/catch/finally block. Each has its advantages and
+ disadvantages.
</para>
<section>
<title>Initialization and Disposal Approach</title>
- <programlisting>
+ <programlisting>
<![CDATA[
class MyClass implements Component, Composable, Disposable {
ComponentManager manager;
@@ -736,44 +736,44 @@
}
}
]]>
- </programlisting>
- <para>
- As you can see by the sample code, this is easy to follow. The
- object gets a reference to a Guardian Component when it first
- receives the ComponentManager. If you could be guaranteed that the
- Guardian Component was ThreadSafe, then this is all that is
- necessary. Unfortunately, you cannot guarantee this for the long
- term. To properly manage resources, we must release the Component
- when we are done with it. That's why we kept a reference to the
- ComponentManager.
- </para>
- <para>
- The main disadvantage of this approach comes into play when you are
- dealing with pooled Components. The reference of the Component is
- kept for the life of this object. It might not be a problem if the
- object had a short life span, but if it was a Component managed by
- the Excalibur component management architecture, its life span is as
- long as the Component whose reference it has. What this means is
- that we are essentially turning the Component's pool into a Factory.
- </para>
- <para>
- The main advantage of this approach is that the code is very clear on
- how a Component is obtained and released. You don't have to have any
- understanding of exception handling.
- </para>
- <para>
- One other nuance is that you are tying the existence of the Guardian
- to the ability to initialize this object. Once an Exception is
- thrown during the initialization phase of an object, you must assume
- that the object is not valid. Sometimes you want to fail if a
- required Component does not exist so this is not a problem. You do
- need to be aware of this implication when you are designing your
- Components though.
- </para>
+ </programlisting>
+ <para>
+ As you can see by the sample code, this is easy to follow. The
+ object gets a reference to a Guardian Component when it first
+ receives the ComponentManager. If you could be guaranteed that the
+ Guardian Component was ThreadSafe, then this is all that is
+ necessary. Unfortunately, you cannot guarantee this for the long
+ term. To properly manage resources, we must release the Component
+ when we are done with it. That's why we kept a reference to the
+ ComponentManager.
+ </para>
+ <para>
+ The main disadvantage of this approach comes into play when you are
+ dealing with pooled Components. The reference of the Component is
+ kept for the life of this object. It might not be a problem if the
+ object had a short life span, but if it was a Component managed by
+ the Excalibur component management architecture, its life span is
as
+ long as the Component whose reference it has. What this means is
+ that we are essentially turning the Component's pool into a
Factory.
+ </para>
+ <para>
+ The main advantage of this approach is that the code is very clear
on
+ how a Component is obtained and released. You don't have to have
any
+ understanding of exception handling.
+ </para>
+ <para>
+ One other nuance is that you are tying the existence of the
Guardian
+ to the ability to initialize this object. Once an Exception is
+ thrown during the initialization phase of an object, you must
assume
+ that the object is not valid. Sometimes you want to fail if a
+ required Component does not exist so this is not a problem. You do
+ need to be aware of this implication when you are designing your
+ Components though.
+ </para>
</section>
<section>
<title>Exception Handling Approach</title>
- <programlisting>
+ <programlisting>
<![CDATA[
class MyClass implements Composable, Disposable {
ComponentManager manager;
@@ -816,72 +816,72 @@
}
}
]]>
- </programlisting>
- <para>
- As you can see, the code is a bit more complex. In order to
- understand it, you have to understand Exception handling. This is
- not necessarily a problem, because most Java developers know how to
- handle them. You don't have to worry so much about the Component
- life style with this approach, because we are releasing it as soon
- as we no longer need it.
- </para>
- <para>
- The main disadvantage of this approach is the added complexity of the
- exception handling code. In order to minimize the complexity and
- make the code more maintainable, we extracted the working code into
- another method. Keep in mind that we can get the reference to as
- many Components as we possibly want inside the try block.
- </para>
- <para>
- The main advantage of this approach is that you are managing your
- Component references more efficiently. Again, there is no real
- difference if you are using ThreadSafe Components, but it makes a
- real difference when you have pooled Components. There is a slight
- overhead dealing with getting a new reference every time you use a
- Component, but the likelihood of being forced to create a new
- instance of the Component is minimized.
- </para>
- <para>
- Just like the Initialization and Disposal Approach, you have to
- understand a subtle nuance. The Exception Handling Approach does not
- fail on initialization if the Component is missing from the manager.
- As mentioned before, this is not entirely bad. Many times, you want
- an object to exist, but it is not a failure if a required Component
- is missing.
- </para>
+ </programlisting>
+ <para>
+ As you can see, the code is a bit more complex. In order to
+ understand it, you have to understand Exception handling. This is
+ not necessarily a problem, because most Java developers know how to
+ handle them. You don't have to worry so much about the Component
+ life style with this approach, because we are releasing it as soon
+ as we no longer need it.
+ </para>
+ <para>
+ The main disadvantage of this approach is the added complexity of
the
+ exception handling code. In order to minimize the complexity and
+ make the code more maintainable, we extracted the working code into
+ another method. Keep in mind that we can get the reference to as
+ many Components as we possibly want inside the try block.
+ </para>
+ <para>
+ The main advantage of this approach is that you are managing your
+ Component references more efficiently. Again, there is no real
+ difference if you are using ThreadSafe Components, but it makes a
+ real difference when you have pooled Components. There is a slight
+ overhead dealing with getting a new reference every time you use a
+ Component, but the likelihood of being forced to create a new
+ instance of the Component is minimized.
+ </para>
+ <para>
+ Just like the Initialization and Disposal Approach, you have to
+ understand a subtle nuance. The Exception Handling Approach does
not
+ fail on initialization if the Component is missing from the
manager.
+ As mentioned before, this is not entirely bad. Many times, you
want
+ an object to exist, but it is not a failure if a required Component
+ is missing.
+ </para>
</section>
</section>
<section>
<title>Getting Components from a ComponentSelector</title>
<para>
For most operations, you will only need the ComponentManager. Since
we
- decided that we needed multiple instances of the DataSourceComponent,
- we need to know how to get the instance we want. ComponentSelectors
- are a little trickier than ComponentManagers because we are dealing
- with hints to get the reference we need. A Component has a specific
- Role, and this contract is well documented. However, sometimes we need
- to select one of many Components for a Role. A ComponentSelector uses
- an arbitrary object for the hint. Most of the time, the object is a
- String, although you might want to use a Locale object to get a proper
- internationalization Component.
+ decided that we needed multiple instances of the DataSourceComponent,
+ we need to know how to get the instance we want. ComponentSelectors
+ are a little trickier than ComponentManagers because we are dealing
+ with hints to get the reference we need. A Component has a specific
+ Role, and this contract is well documented. However, sometimes we
need
+ to select one of many Components for a Role. A ComponentSelector
uses
+ an arbitrary object for the hint. Most of the time, the object is a
+ String, although you might want to use a Locale object to get a
proper
+ internationalization Component.
</para>
<para>
In our system we have set up, we chose to use Strings to select the
- correct instance of the DataSourceComponent. We even gave ourselves a
- Configuration element that references the exact string we need to get
- the right Component. This is a good practice to follow, as it makes it
- easier on administrators of a system. It is easier for an
- administrator to see a reference to another Component than it is for
- them to remember magic values for the configuration.
+ correct instance of the DataSourceComponent. We even gave ourselves
a
+ Configuration element that references the exact string we need to get
+ the right Component. This is a good practice to follow, as it makes
it
+ easier on administrators of a system. It is easier for an
+ administrator to see a reference to another Component than it is for
+ them to remember magic values for the configuration.
</para>
<para>
Conceptually, getting a Component from a ComponentSelector is no
- different than getting a Component from a ComponentManager. You just
- have one more step. Remember that a ComponentSelector is a Component.
- The ComponentManager will be set up to return the ComponentSelector
- when you lookup its role. You then need to select the component from
- the selector. To demonstrate, I will extend the code from the
- Exception Handling Approach discussed previously.
+ different than getting a Component from a ComponentManager. You just
+ have one more step. Remember that a ComponentSelector is a
Component.
+ The ComponentManager will be set up to return the ComponentSelector
+ when you lookup its role. You then need to select the component from
+ the selector. To demonstrate, I will extend the code from the
+ Exception Handling Approach discussed previously.
</para>
<programlisting>
<![CDATA[
@@ -911,17 +911,17 @@
</programlisting>
<para>
As you can see, we got the reference to the ComponentSelector using
the
- Role specified for the Component. We followed the Role naming
- guidelines outlined in a previous chapter by adding the "Selector"
- suffix to the Role name. It is also perfectly acceptable to use a
- static interface for all the Role names in your system to minimize the
- number of String concatenation in your code.
+ Role specified for the Component. We followed the Role naming
+ guidelines outlined in a previous chapter by adding the "Selector"
+ suffix to the Role name. It is also perfectly acceptable to use a
+ static interface for all the Role names in your system to minimize
the
+ number of String concatenation in your code.
</para>
<para>
Next, we obtained the reference to the DataSourceComponent from the
- ComponentSelector. Our sample code assumed that we had already pulled
- the required information from the Configuration object and placed it in
- a class variable named "useDb".
+ ComponentSelector. Our sample code assumed that we had already
pulled
+ the required information from the Configuration object and placed it
in
+ a class variable named "useDb".
</para>
</section>
</section>
@@ -940,90 +940,90 @@
<title>Command Line Interface (CLI)</title>
<para>
The CLI utilities are used by a number of projects including Avalon
- Phoenix and Apache Cocoon to process command line arguments. It
- provides facilities to print help responses, and to process options by
- either a short name or a long name.
+ Phoenix and Apache Cocoon to process command line arguments. It
+ provides facilities to print help responses, and to process options
by
+ either a short name or a long name.
</para>
</section>
<section>
<title>Collection Utilities</title>
<para>
The collection utilities provide some enhancements to the
- <trademark>Java</trademark> Collections API. Among them is the ability
- to find the intersections between two lists and a
- <classname>PriorityQueue</classname> that is an enhancement to
- <classname>Stack</classname> to allow the priority of objects override
- the simple first in/last out <classname>Stack</classname>
- implementation.
+ <trademark>Java</trademark> Collections API. Among them is the
ability
+ to find the intersections between two lists and a
+ <classname>PriorityQueue</classname> that is an enhancement to
+ <classname>Stack</classname> to allow the priority of objects
override
+ the simple first in/last out <classname>Stack</classname>
+ implementation.
</para>
</section>
<section>
<title>Component Management</title>
<para>
We already discussed the use of this in the previous section. This
is
- Excalibur's most complex beast, but it provides a lot of functionality
- in just a few classes. It will make one distinction more than simple
- <classname>SingleThreaded</classname> or
- <classname>ThreadSafe</classname> for managing a component type:
- <classname>Poolable</classname>. If a Component implements Excalibur's
- <classname>Poolable</classname> interface instead of the
- <classname>SingleThreaded</classname> interface, it will maintain a
- pool of Components and reuse instances. Most of the time this works
- great. For those last remaining times where a Component cannot be
- reused, use the <classname>SingleThreaded</classname> interface.
+ Excalibur's most complex beast, but it provides a lot of
functionality
+ in just a few classes. It will make one distinction more than simple
+ <classname>SingleThreaded</classname> or
+ <classname>ThreadSafe</classname> for managing a component type:
+ <classname>Poolable</classname>. If a Component implements
Excalibur's
+ <classname>Poolable</classname> interface instead of the
+ <classname>SingleThreaded</classname> interface, it will maintain a
+ pool of Components and reuse instances. Most of the time this works
+ great. For those last remaining times where a Component cannot be
+ reused, use the <classname>SingleThreaded</classname> interface.
</para>
</section>
<section>
<title>Thread Utilities</title>
<para>
The <emphasis>concurrent</emphasis> package contains several classes
- to assist in multithreaded programming: <classname>Lock</classname>
- (a mutex implementation), <classname>DjikstraSemaphore</classname>,
- <classname>ConditionalEvent</classname>, and
- <classname>ThreadBarrier</classname>.
+ to assist in multithreaded programming: <classname>Lock</classname>
+ (a mutex implementation), <classname>DjikstraSemaphore</classname>,
+ <classname>ConditionalEvent</classname>, and
+ <classname>ThreadBarrier</classname>.
</para>
</section>
<section>
<title>Datasources</title>
<para>
This is modeled after the <classname>javax.sql.DataSource</classname>
- class, but simplified. There are two implementations of the
- <classname>DataSourceComponent</classname>: one that pools JDBC
- connections explicitly, and one that uses a J2EE application server's
- <classname>javax.sql.DataSource</classname> class.
+ class, but simplified. There are two implementations of the
+ <classname>DataSourceComponent</classname>: one that pools JDBC
+ connections explicitly, and one that uses a J2EE application server's
+ <classname>javax.sql.DataSource</classname> class.
</para>
</section>
<section>
<title>Input/Output (IO) Utilities</title>
<para>
The IO utilties provide a number of
<classname>FileFilter</classname>s
- and other <classname>File</classname> and IO specific utilities.
+ and other <classname>File</classname> and IO specific utilities.
</para>
</section>
<section>
<title>Pool Implementations</title>
<para>
The Pool implementations provide a <classname>Pool</classname> for
- every occasion. You have an implementation that is blazingly fast, but
- only usable in one thread—which should be ok for implementing a
- FlyWeight pattern. You also have <classname>DefaultPool</classname>,
- which does not manage the number of objects in its pool.
- <classname>SoftResourceManagingPool</classname> decommissions objects
- that exceed a threshold when they are returned. Lastly,
- <classname>HardResourceManagingPool</classname> throws an exception
- when you have reached the maximum number of objects. The last three
- pools are all <classname>ThreadSafe</classname>.
+ every occasion. You have an implementation that is blazingly fast,
but
+ only usable in one thread—which should be ok for implementing a
+ FlyWeight pattern. You also have <classname>DefaultPool</classname>,
+ which does not manage the number of objects in its pool.
+ <classname>SoftResourceManagingPool</classname> decommissions objects
+ that exceed a threshold when they are returned. Lastly,
+ <classname>HardResourceManagingPool</classname> throws an exception
+ when you have reached the maximum number of objects. The last three
+ pools are all <classname>ThreadSafe</classname>.
</para>
</section>
<section>
<title>Property Utilities</title>
<para>
The property utilities are used in conjunction with Context objects.
- They give you the ability to expand "variables" in your
- <classname>Resolvable</classname> object. It works like this:
- <parameter>"${resource}"</parameter> will look for a Context value
- named <parameter>"resource"</parameter> and substitute its value
- for the symbol.
+ They give you the ability to expand "variables" in your
+ <classname>Resolvable</classname> object. It works like this:
+ <parameter>"${resource}"</parameter> will look for a Context value
+ named <parameter>"resource"</parameter> and substitute its value
+ for the symbol.
</para>
</section>
</section>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>