Skip Navigation Links | |
Exit Print View | |
Oracle GlassFish Server 3.1 Add-On Component Development Guide |
1. Introduction to the Development Environment for GlassFish Server Add-On Components
3. Extending the Administration Console
4. Extending the asadmin Utility
About the Administrative Command Infrastructure of GlassFish Server
Representing an asadmin Subcommand as a Java Class
Specifying the Name of an asadmin Subcommand
Ensuring That an AdminCommand Implementation Is Stateless
Example of Adding an asadmin Subcommand
Adding Parameters to an asadmin Subcommand
Representing a Parameter of an asadmin Subcommand
Identifying a Parameter of an asadmin Subcommand
Specifying Whether a Parameter Is an Option or an Operand
Specifying the Name of an Option
Specifying the Long Form of an Option Name
Specifying the Short Form of an Option Name
Specifying the Acceptable Values of a Parameter
Specifying the Default Value of a Parameter
Specifying Whether a Parameter Is Required or Optional
Example of Adding Parameters to an asadmin Subcommand
Making asadmin Subcommands Cluster-Aware
Specifying asadmin Subcommand Execution
Subcommand Preprocessing and Postprocessing
Running a Command from Another Command
Adding Message Text Strings to an asadmin Subcommand
Enabling an asadmin Subcommand to Run
Setting the Context of an asadmin Subcommand
Changing the Brand in the GlassFish Server CLI
Examples of Extending the asadmin Utility
5. Adding Monitoring Capabilities
6. Adding Configuration Data for a Component
7. Adding Container Capabilities
8. Creating a Session Persistence Module
9. Packaging, Integrating, and Delivering an Add-On Component
Many asadmin subcommands simply create, delete, or list objects in the configuration. Such code is repetitive to write and error prone. To simplify the writing of these asadmin commands, GlassFish Server supports annotations that can create, delete, and list configuration objects from a command invocation. Unless attributes or properties are set to non-default values or extra actions are required, no writing of code is needed.
The following topics are addressed here:
Create command pattern. The most basic create commands are implemented in the following pattern:
Retrieve the parent configuration object instance to which the child will be added. For example, the parent could be a Clusters object and the child a Cluster object.
Start a transaction on the parent instance.
Create the child configuration object instance.
Set the attributes and properties of the newly created child instance.
Add the child to the parent using one of the following accessor methods:
void setChild(ChildType child)
Used when there can be zero or one children of a single type associated with one parent instance.
List<ChildType> getChildren()
Used when there can be zero or more children of a single type associated with one parent instance.
You cannot retrieve a set of children of the same type from the same parent using two different accessor methods.
Commit the transaction.
A generic create command implementation can do most of these tasks if the following information is provided:
A way to resolve the identity of the parent instance.
The type of the child instance.
A mapping between command options and child attributes.
The accessor method for adding the child to the parent.
Delete command pattern. The most basic delete commands are implemented in the following pattern:
Retrieve the configuration object instance to be deleted.
Start a transaction on the parent instance.
Delete the child by removing it from the list or calling setXXX(null).
Commit the transaction.
A generic delete command implementation can do most of these tasks if the following information is provided:
A way to resolve the identity of the child instance.
The accessor method for deleting the child.
List command pattern. The most basic list commands simply retrieve all configuration object instances of a given type.
A resolver retrieves a configuration object instance of a particular type. For a create command, it retrieves the parent of the object to be created. For a delete command, it retrieves the object to be deleted. A resolver implements the CrudResolver interface:
package org.glassfish.config.support; /** * A config resolver is responsible for finding the target object of a specified * type on which a creation command invocation will be processed. * * Implementation of these interfaces can be injected with the command invocation * parameters in order to determine which object should be returned */ @Contract public interface CrudResolver { /** * Retrieves the existing configuration object a command invocation is * intented to mutate. * @param context the command invocation context * @param type the type of the expected instance * @return the instance or null if not found */ <T extends ConfigBeanProxy> T resolve(AdminCommandContext context, Class<T> type); }
Given an AdminCommandContext, plus injection with the asadmin command line parameters (or any other HK2 services if necessary), the resolver should be able to determine the particular configuration object on which to act.
The following resolvers are provided in the org.glassfish.config.support package:
TargetBasedResolver — Uses the --target option and the expected return type to retrieve the configuration object instance.
TargetAndNameBasedResolver — Uses the --target option to look up a Config object and a name to retrieve one of the Config object's children.
TypeAndNameResolver — Uses the requested type and asadmin command name operand to find the configuration object instance. This is useful for a configuration that uses the @Index annotation, which registers instances under names.
TypeResolver — Uses the requested type to find the configuration object instance. This is the default resolver.
By placing the org.glassfish.config.support.Create annotation on a method, you provide the following information:
The value element of the @Create annotation is the name of the asadmin subcommand that creates the configuration object.
The method's class is the type of the parent.
The method's return type or parameter type is the type of the child.
The method is the accessor method that adds a child of the specified type to the parent.
The only additional information needed is the resolver to use.
The following example specifies a create-cluster subcommand:
@Configured public interface Clusters extends ConfigBeanProxy, Injectable { /** * Return the list of clusters currently configured * * @return list of {@link Cluster } */ @Element @Create(value="create-cluster") public List<Cluster> getCluster(); }
Because there is only one instance of the parent type, Clusters, in the configuration, this example uses the default resolver to retrieve it. Therefore, no resolver needs to be specified.
By placing the org.glassfish.config.support.Delete annotation on a method, you provide the following information:
The value element of the @Delete annotation is the name of the asadmin subcommand that deletes the configuration object.
The method's class is the type of the parent.
The method's return type or parameter type is the type of the child.
The method is the accessor method that deletes a child of the specified type from the parent.
The only additional information needed is the resolver to use.
The following example specifies a delete-cluster subcommand:
@Configured public interface Clusters extends ConfigBeanProxy, Injectable { /** * Return the list of clusters currently configured * * @return list of {@link Cluster } */ @Element @Delete(value="delete-cluster", resolver=TypeAndNameResolver.class) public List<Cluster> getCluster(); }
The TypeAndNameResolver uses the child type and the name operand passed through the command line to retrieve the specific cluster instance to be deleted.
By placing the org.glassfish.config.support.Listing annotation on a method, you provide the following information:
The value element of the @Listing annotation is the name of the asadmin subcommand that lists the configuration objects.
The method's class is the type of the parent.
The method's return type is the type of the children to be listed.
The method is always the following accessor method:
List<ChildType> getChildren()
The default resolver retrieves all of the children of the specified type. Therefore, no resolver needs to be specified for a list command.
The following example specifies a list-clusters subcommand:
@Configured public interface Clusters extends ConfigBeanProxy, Injectable { /** * Return the list of clusters currently configured * * @return list of {@link Cluster } */ @Element @Listing(value="list-clusters") public List<Cluster> getCluster(); }
Most create commands must do more than create a single configuration object instance with default attribute values. For example, most create commands allow the user to specify non-default attribute values through command options. For another example, the create-cluster subcommand creates children of the Cluster object and copies a referenced Config object. A creation decorator provides the code necessary to perform such additional operations.
The interface that a creation decorator must implement is as follows:
@Scoped(PerLookup.class) public interface CreationDecorator<T extends ConfigBeanProxy> { /** * The element instance has been created and added to the parent, it can be * customized. This method is called within a * {@link org.jvnet.hk2.config.Transaction} * and instance is therefore a writeable view on the configuration component. * * @param context administration command context * @param instance newly created configuration element * @throws TransactionFailure if the transaction should be rollbacked * @throws PropertyVetoException if one of the listener of <T> is throwing * a veto exception */ public void decorate(AdminCommandContext context, T instance) throws TransactionFailure, PropertyVetoException; /** * Default implementation of a decorator that does nothing. */ @Service public class NoDecoration implements CreationDecorator<ConfigBeanProxy> { @Override public void decorate(AdminCommandContext context, ConfigBeanProxy instance) throws TransactionFailure, PropertyVetoException { // do nothing } } }
The CreationDecorator interface is in the org.glassfish.config.support package.
A @Create annotation specifies a creation decorator using a decorator element. For example:
@Configured public interface Clusters extends ConfigBeanProxy, Injectable { /** * Return the list of clusters currently configured * * @return list of {@link Cluster } */ @Element @Create(value="create-cluster", decorator=Cluster.Decorator.class) public List<Cluster> getCluster(); }
The @Create annotation is on a method of the parent class. However, the referenced creation decorator class is associated with the child class. For example:
@Configured public interface Cluster extends ConfigBeanProxy, ... { ... @Service @Scoped(PerLookup.class) class Decorator implements CreationDecorator<Cluster> { @Param(name="config", optional=true) String configRef=null; @Inject Domain domain; @Override public void decorate(AdminCommandContext context, final Cluster instance) throws TransactionFailure, PropertyVetoException { ... } } }
The decorator class can optionally be an inner class of the child class. You can inject command options using the @Param annotation. You can also inject HK2 services or configuration instances.
Some delete commands must do more than delete a single configuration object instance. For example, the delete-cluster subcommand deletes the referenced Config object if no other Cluster or Instance objects reference it. A deletion decorator provides the code necessary to perform such additional operations.
The interface that a deletion decorator must implement is as follows:
/** * A decorator for acting upon a configuration element deletion. * * @param <T> the deleted element parent type * @param <U> the deleted element */ @Scoped(PerLookup.class) public interface DeletionDecorator<T extends ConfigBeanProxy, U extends ConfigBeanProxy> { /** * notification of a configuration element of type U deletion. * * Note that this notification is called within the boundaries of the * configuration transaction, therefore the parent instance is a * writable copy and further changes to the parent can be made without * enrolling it inside a transaction. * * @param context the command context to lead to the element deletion * @param parent the parent instance the element was removed from * @param child the deleted instance */ public void decorate(AdminCommandContext context, T parent, U child); }
The DeletionDecorator interface is in the org.glassfish.config.support package.
A @Delete annotation specifies a deletion decorator using a decorator element. For example:
@Configured public interface Clusters extends ConfigBeanProxy, Injectable { /** * Return the list of clusters currently configured * * @return list of {@link Cluster } */ @Element @Delete(value="delete-cluster", resolver= TypeAndNameResolver.class, decorator=Cluster.DeleteDecorator.class) public List<Cluster> getCluster(); }
The @Delete annotation is on a method of the parent class. However, the referenced deletion decorator class is associated with the child class. For example:
@Configured public interface Cluster extends ConfigBeanProxy, ... { .. @Service @Scoped(PerLookup.class) class DeleteDecorator implements DeletionDecorator<Clusters, Cluster> { .... } }
The decorator class can optionally be an inner class of the child class. You can inject command options using the @Param annotation. You can also inject HK2 services or configuration instances.
Commands specified with the @Create, @Delete, and @Listing annotations can use the @ExecuteOn annotation. The @ExecuteOn annotation specifies whether the command runs on the DAS, on server instances, or both (the default). For more information, see Specifying asadmin Subcommand Execution.
To add an @ExecuteOn annotation to a @Create or @Delete annotation, use the cluster element. For example:
@Create(value="create-instance", resolver=TypeResolver.class, decorator=Server.CreateDecorator.class, cluster=@org.glassfish.api.admin.ExecuteOn(value=RuntimeType.DAS))
You can specify multiple command annotations on the same method. The following example combines create, delete, and list commands for clusters:
@Configured public interface Clusters extends ConfigBeanProxy, Injectable { /** * Return the list of clusters currently configured * * @return list of {@link Cluster } */ @Element @Create(value="create-cluster", decorator=Cluster.Decorator.class) @Delete(value="delete-cluster", resolver= TypeAndNameResolver.class, decorator=Cluster.DeleteDecorator.class) @Listing(value="list-clusters") public List<Cluster> getCluster(); }
You can also specify multiple create or delete command annotations for the same configuration object type using the @Creates or @Deletes annotation (both in the org.glassfish.config.support package). For example:
@Element @Creates( @Create(value="create-something", decorator=CreateSomething.Decorator) @Create(value="create-something-else", decorator=CreateSomethingElse.Decorator) List<Something> getSomethings(); )
These commands create configuration object instances of the same type. Differences in the decorators and resolvers can produce differences in the options each command takes. The @Param annotated attributes of the created type define a superset of options for both commands.