blob: dd296180f330e748f39eb940b7ca54212b80d998 [file] [log] [blame]
type=page
status=published
title=Extending the asadmin Utility
next=adding-monitoring-capabilities.html
prev=extending-the-admin-console.html
~~~~~~
= Extending the asadmin Utility
[[GSACG00004]][[ghmrd]]
[[extending-the-asadmin-utility]]
== Extending the `asadmin` Utility
The `asadmin` utility is a command-line tool for configuring and
administering {productName}. Extending the `asadmin` utility enables
you to provide administrative interfaces for an add-on component that
are consistent with the interfaces of other {productName} components.
A user can run `asadmin` subcommands either from a command prompt or
from a script. For more information about the `asadmin` utility, see the
link:reference-manual/asadmin.html#GSRFM00263[`asadmin`(1M)] man page.
The following topics are addressed here:
* link:#ghpuj[About the Administrative Command Infrastructure of {productName}]
* link:#ghpwe[Adding an `asadmin` Subcommand]
* link:#ghpwa[Adding Parameters to an `asadmin` Subcommand]
* link:#gkygt[Making `asadmin` Subcommands Cluster-Aware]
* link:#ghptw[Adding Message Text Strings to an `asadmin` Subcommand]
* link:#ghpvn[Enabling an `asadmin` Subcommand to Run]
* link:#ghpvq[Setting the Context of an `asadmin` Subcommand]
* link:#ghpwn[Changing the Brand in the {productName} CLI]
* link:#ghmza[Examples of Extending the `asadmin` Utility]
* link:#gkzlq[Implementing Create, Delete, and List Commands Using
Annotations]
[[ghpuj]][[GSACG00105]][[about-the-administrative-command-infrastructure-of-glassfish-server]]
=== About the Administrative Command Infrastructure of {productName}
To enable multiple containers to be independently packaged and loaded,
the administrative command infrastructure of {productName} provides
the following features:
* Location independence. Administration subcommands can be loaded from
any add-on component that is known to {productName}.
* Extensibility. Administrative subcommands that are available to
{productName} are discovered on demand and not obtained from a preset
list of subcommands.
* Support for the HK2 architecture. Subcommands can use injection to
express their dependencies, and extraction to provide results to a user.
For more information, see link:writing-hk2-components.html#ghmna[Writing
HK2 Components].
[[ghpwe]][[GSACG00107]][[adding-an-asadmin-subcommand]]
=== Adding an `asadmin` Subcommand
An `asadmin` subcommand identifies the operation or task that a user is
to perform. Adding an `asadmin` subcommand enables the user to perform
these tasks and operations through the `asadmin` utility.
The following topics are addressed here:
* link:#ghrqj[Representing an `asadmin` Subcommand as a Java Class]
* link:#ghrpm[Specifying the Name of an `asadmin` Subcommand]
* link:#ghrng[Ensuring That an `AdminCommand` Implementation Is
Stateless]
* link:#ghrqx[Example of Adding an `asadmin` Subcommand]
[[ghrqj]][[GSACG00194]][[representing-an-asadmin-subcommand-as-a-java-class]]
==== Representing an `asadmin` Subcommand as a Java Class
Each `asadmin` subcommand that you are adding must be represented as a
Java class. To represent an `asadmin` subcommand as a Java class, write
a Java class that implements the `org.glassfish.api.admin.AdminCommand`
interface. Write one class for each subcommand that you are adding. Do
not represent multiple `asadmin` subcommands in a single class.
Annotate the declaration of your implementations of the `AdminCommand`
interface with the `org.jvnet.hk2.annotations.Service` annotation. The
`@Service` annotation ensures that the following requirements for your
implementations are met:
* The implementations are eligible for resource injection and resource extraction.
* The implementations are location independent, provided that the
component that contains them is made known to the {productName} runtime.
+
For information about how to make a component known to the {productName} runtime, see
link:packaging-integrating-delivering.html#ghmne[Integrating an Add-On Component With {productName}].
[[ghrpm]][[GSACG00195]][[specifying-the-name-of-an-asadmin-subcommand]]
==== Specifying the Name of an `asadmin` Subcommand
To specify the name of the subcommand, set the `name` element of the
`@Service` annotation to the name.
[NOTE]
====
Subcommand names are case-sensitive.
====
Subcommands that are supplied in {productName} distributions
typically create, delete, and list objects of a particular type. For
consistency with the names of subcommands that are supplied in {productName} distributions, follow these conventions when specifying the name
of a subcommand:
* For subcommands that create an object of a particular type, use the name `create-`object`.`
* For subcommands that delete an object of a particular type, use the name `delete-`object`.`
* For subcommands that list all objects of a particular type, use the name `list-`objects`.`
For example, {productName} provides the following subcommands for
creating, deleting, and listing HTTP listeners:
* `create-http-listener`
* `delete-http-listener`
* `list-http-listeners`
You must also ensure that the name of your subcommand is unique.
To obtain a complete list of the names of all `asadmin` subcommands that
are installed, use the
link:reference-manual/list-commands.html#GSRFM00154[`list-commands`] subcommand.
For a complete list of `asadmin` subcommands that are supplied in
{productName} distributions, see the
link:reference-manual.html#GSRFM[{productName} Reference Manual].
[[ghrng]][[GSACG00196]][[ensuring-that-an-admincommand-implementation-is-stateless]]
==== Ensuring That an `AdminCommand` Implementation Is Stateless
To enable multiple clients to run a subcommand simultaneously, ensure
that the implementation of the `AdminCommand` interface for the
subcommand is stateless. To ensure that the implementation of the
`AdminCommand` interface is stateless, annotate the declaration of your
implementation with the `org.jvnet.hk2.annotations.Scoped` annotation.
In the `@Scoped` annotation, set the scope as follows:
* To instantiate the subcommand for each lookup, set the scope to `PerLookup.class`.
* To instantiate the subcommand only once for each session, set the scope to `Singleton`.
[[ghrqx]][[GSACG00197]][[example-of-adding-an-asadmin-subcommand]]
==== Example of Adding an `asadmin` Subcommand
[[GSACG00034]][[ghrqq]]
Example 4-1 Adding an `asadmin` Subcommand
This example shows the declaration of the class `CreateMycontainer` that
represents an `asadmin` subcommand that is named `create-mycontainer`.
The subcommand is instantiated for each lookup.
[source,java]
----
package com.example.mycontainer;
import org.glassfish.api.admin.AdminCommand;
...
import org.jvnet.hk2.annotations.Service;
...
import org.jvnet.hk2.annotations.Scoped;
import org.jvnet.hk2.component.PerLookup;
/**
* Sample subcommand
*/
@Service(name="create-mycontainer")
@Scoped(PerLookup.class)
public Class CreateMycontainer implements AdminCommand {
}
----
[[ghpwa]][[GSACG00108]][[adding-parameters-to-an-asadmin-subcommand]]
=== Adding Parameters to an `asadmin` Subcommand
The parameters of an `asadmin` subcommand are the options and operands
of the subcommand.
* Options control how the `asadmin` utility performs a subcommand.
* Operands are the objects on which a subcommand acts. For example, the
operand of the link:reference-manual/start-domain.html#GSRFM00235[`start-domain`] subcommand is the domain
that is to be started.
The following topics are addressed here:
* link:#ghpvh[Representing a Parameter of an `asadmin` Subcommand]
* link:#ghptx[Identifying a Parameter of an `asadmin` Subcommand]
* link:#ghpxp[Specifying Whether a Parameter Is an Option or an Operand]
* link:#ghpxj[Specifying the Name of an Option]
* link:#ghpxl[Specifying the Acceptable Values of a Parameter]
* link:#ghrgt[Specifying the Default Value of a Parameter]
* link:#ghpuk[Specifying Whether a Parameter Is Required or Optional]
* link:#CDCFAJDG[Specifying Whether a Parameter Can Be Used Multiple
Times on the Command Line]
* link:#ghpxd[Example of Adding Parameters to an `asadmin` Subcommand]
[[ghpvh]][[GSACG00198]][[representing-a-parameter-of-an-asadmin-subcommand]]
==== Representing a Parameter of an `asadmin` Subcommand
Represent each parameter of a subcommand in your implementation as a
field or as the property of a JavaBeans specification setter method. Use
the property of a setter method for the following reasons:
* To provide data encapsulation for the parameter
* To add code for validating the parameter before the property is set
[[ghptx]][[GSACG00199]][[identifying-a-parameter-of-an-asadmin-subcommand]]
==== Identifying a Parameter of an `asadmin` Subcommand
Identifying a parameter of an `asadmin` subcommand enables {productName} to perform the following operations at runtime on the parameter:
* Validation. The {productName} determines whether all required
parameters are specified and returns an error if any required parameter
is omitted.
* Injection. Before the subcommand runs, the {productName} injects
each parameter into the required field or method before the subcommand
is run.
* Usage message generation. The {productName} uses reflection to
obtain the list of parameters for a subcommand and to generate the usage
message from this list.
* Localized string display. If the subcommand supports
internationalization and if localized strings are available, the
{productName} can automatically obtain the localized strings for a
subcommand and display them to the user.
To identify a parameter of a subcommand, annotate the declaration of the
item that is associated with the parameter with the
`org.glassfish.api.Param` annotation. This item is either the field or
setter method that is associated with the parameter.
To specify the properties of the parameter, use the elements of the
`@Param` annotation as explained in the sections that follow.
[[ghpxp]][[GSACG00200]][[specifying-whether-a-parameter-is-an-option-or-an-operand]]
==== Specifying Whether a Parameter Is an Option or an Operand
Whether a parameter is an option or an operand determines how a user
must specify the parameter when running the subcommand:
* If the parameter is an option, the user must specify the option with
the parameter name.
* If the parameter is an operand, the user may omit the parameter name.
To specify whether a parameter is an option or an operand, set the
`primary` element of the `@Param` annotation as follows:
* If the parameter is an option, set the `primary` element to `false`.
This value is the default.
* If the parameter is an operand, set the `primary` element to `true`.
[[ghpxj]][[GSACG00201]][[specifying-the-name-of-an-option]]
==== Specifying the Name of an Option
The name of an option is the name that a user must type on the command
line to specify the option when running the subcommand.
The name of each option that you add in your implementation of an
`asadmin` subcommand can have a long form and a short form. When running
the subcommand, the user specifies the long form and the short form as
follows:
* The short form of an option name has a single dash (`-`) followed by a
single character.
* The long form of an option name has two dashes (`--`) followed by an
option word.
For example, the short form and the long form of the name of the option
for specifying terse output are as follows:
* Short form: `-m`
* Long form: `--monitor`
[NOTE]
====
Option names are case-sensitive.
====
[[ghpvy]][[GSACG00163]][[specifying-the-long-form-of-an-option-name]]
===== Specifying the Long Form of an Option Name
To specify the long form of an option name, set the `name` element of
the `@Param` annotation to a string that specifies the name. If you do
not set this element, the default name depends on how you represent the
option.
* If you represent the option as a field, the default name is the field
name.
* If you represent the option as the property of a JavaBeans
specification setter method, the default name is the property name from
the setter method name. For example, if the setter method `setPassword`
is associated with an option, the property name and the option name are
both `password`.
[[sthref5]][[specifying-the-short-form-of-an-option-name]]
===== Specifying the Short Form of an Option Name
[[ghpvi]]
To specify the short form of an option name, set the `shortName` element
of the `@Param` annotation to a single character that specifies the
short form of the parameter. The user can specify this character instead
of the full parameter name, for example `-m` instead of `--monitor`. If
you do not set this element, the option has no short form.
[[ghpxl]][[GSACG00202]][[specifying-the-acceptable-values-of-a-parameter]]
==== Specifying the Acceptable Values of a Parameter
When a user runs the subcommand, the {productName} validates option
arguments and operands against the acceptable values that you specify in
your implementation.
To specify the acceptable values of a parameter, set the
`acceptableValues` element of the `@Param` annotation to a string that
contains a comma-separated list of acceptable values. If you do not set
this element, any string of characters is acceptable.
[[ghrgt]][[GSACG00203]][[specifying-the-default-value-of-a-parameter]]
==== Specifying the Default Value of a Parameter
The default value of a parameter is the value that is applied if a user
omits the parameter when running the subcommand.
To specify the default value of a parameter, set the `defaultValue`
element of the `@Param` annotation to a string that contains the default
value. You can also compute the default value dynamically by extending
the `ParamDefaultCalculator` class and setting the `defaultCalculator`
element of the `@Param` annotation to this class. If these elements are
not set, the parameter has no default value.
[[ghpuk]][[GSACG00204]][[specifying-whether-a-parameter-is-required-or-optional]]
==== Specifying Whether a Parameter Is Required or Optional
Whether a parameter is required or optional determines how a subcommand
responds if a user omits the parameter when running the subcommand:
* If the parameter is required, the subcommand returns an error.
* If the parameter is optional, the subcommand runs successfully.
To specify whether a parameter is optional or required, set the
`optional` element of the `@Param` annotation as follows:
* If the parameter is required, set the `optional` element to `false`.
This value is the default.
* If the parameter is optional, set the `optional` element to `true`.
[[CDCFAJDG]][[specifying-whether-a-parameter-can-be-used-multiple-times-on-the-command-line]]
Specifying Whether a Parameter Can Be Used Multiple Times on the Command
==== Line
By default, each parameter can be used once on the command line. To use
the parameter multiple times, set the `multiple` element of the `@Param`
annotation to `true`. The type of the annotated parameter must be an
array.
[[ghpxd]][[GSACG00205]][[example-of-adding-parameters-to-an-asadmin-subcommand]]
==== Example of Adding Parameters to an `asadmin` Subcommand
[[GSACG00035]][[ghpuh]]
Example 4-2 Adding Parameters to an `asadmin` Subcommand
This example shows the code for adding parameters to an `asadmin`
subcommand with the properties as shown in the table.
|===
|Name |Represented As |Acceptable Values |Default Value |Optional or
Required |Short Name |Option or Operand
|`--originator` |A field that is named `originator` |Any character
string |None defined |Required |None |Option
|`--description` |A field that is named `mycontainerDescription` |Any
character string |None defined |Optional |None |Option
|`--enabled` |A field that is named `enabled` |`true` or `false`
|`false` |Optional |None |Option
|`--containername` |A field that is named `containername` |Any character
string |None defined |Required |None |Operand
|===
[source,java]
----
...
import org.glassfish.api.Param;
...
{
//…
@Param
String originator;
@Param(name="description", optional=true)
//…
String mycontainerDescription
@Param (acceptableValues="true,false", defaultValue="false", optional=true)
String enabled
@Param(primary=true)
String containername;
//…
}
----
[[gkygt]][[GSACG00109]][[making-asadmin-subcommands-cluster-aware]]
=== Making `asadmin` Subcommands Cluster-Aware
The {productName} `asadmin` command framework provides support for
making `asadmin` subcommands work properly in a clustered environment or
with standalone server instances. A command that changes a configuration
is first executed on the domain administration server (DAS) and then
executed on each of the server instances affected by the change.
Annotations provided by the framework determine the instances on which
the command should be replicated and executed. Commands that do not
change a configuration need not be executed on the DAS at all, but only
on the necessary instances. The framework provides support for
collecting the output from the instances and sending a report back to
the user.
Subcommands in a multi-instance environment can accept a `--target`
option to specify the cluster or instance on which the command acts.
From within the command, the `Target` utility allows the command to
determine information about where it is running. For some commands, it
may be desirable to have a main command that runs on the DAS and
supplemental preprocessing or postprocessing commands that run on the
instances.
The following topics are addressed here:
* link:#gkyjk[Specifying Allowed Targets]
* link:#gkykm[The `Target` Utility]
* link:#gkyfv[Specifying `asadmin` Subcommand Execution]
* link:#gkyjs[Subcommand Preprocessing and Postprocessing]
* link:#gkyit[Running a Command from Another Command]
[[gkyjk]][[GSACG00206]][[specifying-allowed-targets]]
==== Specifying Allowed Targets
When you define a `--target` option by using the `@Param` annotation in
the `org.glassfish.api` package, possible targets are as follows:
* `domain` — The entire domain
* `server` — The domain administration server, or DAS
* cluster — A homogeneous set of server instances that function as a
unit
* standalone instance — A server instance that isn't part of a cluster
* clustered instance — A server instance that is part of a cluster
* config — A configuration for a cluster or standalone server instance
These possible targets are represented by the following `CommandTarget`
elements of the `@TargetType` annotation in the
`org.glassfish.config.support` package:
* `CommandTarget.DOMAIN`
* `CommandTarget.DAS`
* `CommandTarget.CLUSTER`
* `CommandTarget.STANDALONE_SERVER`
* `CommandTarget.CLUSTERED_INSTANCE`
* `CommandTarget.CONFIG`
By default, the allowed targets are `server` (the DAS), standalone
server instances, clusters, and configurations. Not specifying a
`@TargetType` annotation is equivalent to specifying the following
`@TargetType` annotation:
[source,java]
----
@TargetType(CommandTarget.DAS,CommandTarget.STANDALONE_SERVER,CommandTarget.CLUSTER,CommandTarget.CONFIG)
----
Subcommands that support other combinations of targets must specify
`@TargetType` annotations. For example, the `create-http-lb` subcommand
supports only standalone server instance and cluster targets. Its
`@TargetType` annotation is as follows:
[source,java]
----
@TargetType(CommandTarget.STANDALONE_SERVER,CommandTarget.CLUSTER)
----
Most subcommands do not act on server instances that are part of a
cluster. This ensures that all server instances in a cluster remain
synchronized. Thus, the `CommandTarget.CLUSTERED_INSTANCE` element of
the `@TargetType` annotation is rarely used.
An example exception is the `enable` subcommand. To perform a rolling
upgrade of an application deployed to a cluster, you must be able to
enable the new application (which automatically disables the old) on one
clustered instance at a time. The `@TargetType` annotation for the
`enable` subcommand is as follows, all on one line:
[source,java]
----
@TargetType(CommandTarget.DAS,CommandTarget.STANDALONE_INSTANCE,CommandTarget.CLUSTER,
CommandTarget.CLUSTERED_INSTANCE)
----
Note that the `CommandTarget.CLUSTERED_INSTANCE` element is specified.
The target name specified in the command line is injected into the
subcommand implementation if the following annotation is present:
[source,java]
----
@Param(optional=true,defaultValue=SystemPropertyConstants.DEFAULT_SERVER_INSTANCE_NAME)
String target;
----
[[gkykm]][[GSACG00207]][[the-target-utility]]
==== The `Target` Utility
The `Target` utility is a service, present in the `internal-api` module,
`org.glassfish.internal.api` package, which a command implementation can
obtain by using the following annotation:
[source,java]
----
@Inject Target targetUtil;
----
You can use this utility to avoid writing boiler plate code for actions
such as getting the list of server instances for a cluster or checking
if a server instance is part of a cluster. For example, here is an
example of using the utility to obtain the configuration for a target
cluster or server instance:
[source,java]
----
Config c = targetUtil.getConfig(target);
----
The `Target` utility is packaged in the
as-install``/modules/internal-api.jar`` file. Its methods are documented
with comments.
[[gkyfv]][[GSACG00208]][[specifying-asadmin-subcommand-execution]]
==== Specifying `asadmin` Subcommand Execution
By default, all `asadmin` subcommands are automatically replicated and
run on the DAS and all {productName} instances specified in the
`--target` option. To run a subcommand only on the DAS, use the
following `@ExecuteOn` annotation in the `org.glassfish.api.admin` package:
[source,java]
----
@ExecuteOn(RuntimeType.DAS)
----
The `stop-domain` subcommand and subcommands that list information are
examples of subcommands that execute only on the DAS.
To run a subcommand only on applicable server instances, use the
following `@ExecuteOn` annotation:
[source,java]
----
@ExecuteOn(RuntimeType.INSTANCE)
----
Not specifying an `@ExecuteOn` annotation is equivalent to specifying
the following `@ExecuteOn` annotation:
[source,java]
----
@ExecuteOn(RuntimeType.DAS,RuntimeType.INSTANCE)
----
In addition to `RuntimeType`, you can specify the following additional
elements with the `@ExecuteOn` annotation:
* `ifFailure` — By default, if errors occur during execution of a
subcommand on a server instance, command execution is considered to have
failed and further execution is stopped. However, you can choose to
ignore the failure or warn the user rather than stopping further command
execution. Specify the `ifFailure` element and set it to
`FailurePolicy.Ignore` or `FailurePolicy.Warn`. For example:
+
[source,java]
----
@ExecuteOn(value={RuntimeType.DAS}, ifFailure=FailurePolicy.Warn)
----
* `ifOffline` — By default, if a server instance is found to be offline
during the command replication process, command execution is considered
to have failed and further execution is stopped. However, you can choose
to ignore the failure or warn the user rather than stopping further
command execution. Specify the `ifOffline` element and set it to
`FailurePolicy.Ignore` or `FailurePolicy.Warn`. For example:
+
[source,java]
----
@ExecuteOn(value={RuntimeType.DAS}, ifOffline=FailurePolicy.Ignore)
----
[[gkyjs]][[GSACG00209]][[subcommand-preprocessing-and-postprocessing]]
==== Subcommand Preprocessing and Postprocessing
Some `asadmin` subcommands may require preprocessing or postprocessing.
For example, after an application is deployed to the DAS, references are
created in all applicable server instances, which synchronize with the
DAS. As another example, Message Queue or load balancer settings may
have to be reconfigured whenever a server instance is added to a
cluster.
For such cases, the command replication framework provides the
`@Supplemental` annotation (in the `org.glassfish.api.admin` package).
An implementation must use the `value` element of the `@Supplemental`
annotation to express the supplemented command. This value is the name
of the command as defined by the supplemented command's `@Service`
annotation (in the `org.jvnet.hk2.annotations` package).
For example, the `deploy` subcommand requires postprocessing. The
deployment command implementation looks like this:
[source,java]
----
@Service(name="deploy")
@ExecuteOn(RuntimeType.DAS)
public DeployCommand implements AdminCommand {
// Do Actual Deployment
}
----
A supplemental command that is run after every successful deployment
looks like this:
[source,java]
----
@Service(name="DeploymentSupplementalCommand")
@Supplemental("deploy")
@ExecuteOn(RuntimeType.INSTANCE)
public DeploymentSupplementalCommand implements AdminCommand {
// Do logic that happens after deployment has been done
}
----
As another example, a subcommand to create a local server instance might
look like this:
[source,java]
----
@Service(name = "create-local-instance")
@Scoped(PerLookup.class)
public final class CreateLocalInstanceCommand implements AdminCommand {
// Do local instance creation
}
----
A supplemental command to change Message Queue or load balancer settings
after local instance creation might look like this:
[source,java]
----
@Service(name="CreateLocalInstanceSupplementalCommand")
@Supplemental("create-local-instance")
public CreateLocalInstanceSupplementalCommand implements AdminCommand {
// Change MQ/LB properties here
}
----
A supplemental command implements AdminCommand, thus it can use the
`@Param` annotation and expect the corresponding `asadmin` command
parameters to be injected at runtime. The parameter values available for
injection are the same ones provided for the original command with which
the supplemental command is associated. For example, the
`DeploymentSupplementalCommand` has access to the parameter values
available to the `DeployCommand` invocation.
An `asadmin` subcommand can be supplemented with multiple supplemental
commands. In this case, all supplemental commands are run after
completion of the main command but without any guarantee of the order in
which they run.
To specify that a supplemental command is run before the main command,
set the `on` element of the `@Supplemental` annotation to
`Supplemental.Timing.Before`. For example:
[source,java]
----
@Supplemental(value="mycommand", on=Supplemental.Timing.Before)
----
Supplemental commands can use the `@ExecuteOn` annotation as described
in link:#gkyfv[Specifying `asadmin` Subcommand Execution].
[[gkyit]][[GSACG00210]][[running-a-command-from-another-command]]
==== Running a Command from Another Command
An `asadmin` subcommand or supplemental command might need to run
another subcommand. For example, a subcommand running on the DAS might
need to run a different subcommand on one or more server instances. Such
invocations might use the `ClusterExecutor` class (in the
`org.glassfish.api.admin` package), which accepts a `ParameterMap`, to
pass parameters and their values to the invoked command.
The `ParameterMapExtractor` utility is a service, present in the
`common-util` module, `org.glassfish.common.util.admin` package, which
creates a new `ParameterMap` populated using the parameters and values
of another `AdminCommand` that has already been injected.
To list parameter names you want excluded from the `ParameterMap`, pass
the following:
[source,java]
----
Set<String>
----
This is optional.
[[ghptw]][[GSACG00110]][[adding-message-text-strings-to-an-asadmin-subcommand]]
=== Adding Message Text Strings to an `asadmin` Subcommand
A message text string provides useful information to the user about an
`asadmin` subcommand or a parameter.
To provide internationalization support for the text string of a
subcommand or parameter, annotate the declaration of the subcommand or
parameter with the `org.glassfish.api.I18n` annotation. The `@I18n`
annotation identifies the resource from the resource bundle that is
associated with your implementation.
To add message text strings to an `asadmin` subcommand, create a plain
text file that is named `LocalStrings.properties` to contain the
strings. Define each string on a separate line of the file as follows:
[source]
----
key=string
----
key::
A key that maps the string to a subcommand or a parameter. The format
to use for key depends on the target to which the key applies and
whether the target is annotated with the `@I18n` annotation. See the
following table.
+
[width="100%",cols="<36%,<64%",options="header",]
|===
|Target |Format
|Subcommand or parameter with the `@I18n` annotation
|`subcommand-name.command.resource-name`
|Subcommand without the `@I18n` annotation
|`subcommand-name.command`
|Parameter without the `@I18n` annotation
|`subcommand-name.command.param-name`
|===
+
The replaceable parts of these formats are as follows:
+
subcommand-name;;
The name of the subcommand.
resource-name;;
The name of the resource that is specified in the`@I18n` annotation.
param-name;;
The name of the parameter.
string::
A string without quotes that contains the text of the message.
[NOTE]
====
To display the message strings to users, you must provide code in your
implementation of the `execute` method to display the text. For more
information about implementing the `execute` method, see
link:#ghpvn[Enabling an `asadmin` Subcommand to Run].
====
[[GSACG00036]][[ghpvm]]
Example 4-3 Adding Message Strings to an `asadmin` Subcommand
This example shows the code for adding message strings to the
`create-mycontainer` subcommand as follows:
* The `create-mycontainer` subcommand is associated with the message
`Creates a custom container`. No internationalization support is
provided for this message.
* The `--originator` parameter is associated with the message
`The originator of the container`. No internationalization support is
provided for this message.
* The `--description` parameter is associated with the message that is
contained in the resource `mydesc`, for which internationalization is
provided. This resource contains the message text
`A description of the container`.
* The `--enabled` parameter is associated with the message
`Whether the container is enabled or disabled`.
No internationalization support is provided for this message.
* The `--containername` parameter is associated with the message
`The container name`. No internationalization support is provided for this message.
The addition of the parameters `originator`, `description`, `enabled`
and `containername` to the subcommand is shown in link:#ghpuh[Example 4-2].
[source,java]
----
package com.example.mycontainer;
import org.glassfish.api.admin.AdminCommand;
import org.glassfish.api.I18n;
import org.glassfish.api.Param;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.annotations.Scoped;
import org.jvnet.hk2.component.PerLookup;
//...
/**
* Sample subcommand
*/
@Service(name="create-mycontainer")
@Scoped(PerLookup.class)
public Class CreateMycontainer implements AdminCommand {
@Param
String originator;
@Param(name="description", optional=true)
@I18n("mydesc")
String mycontainerDescription
@Param (acceptableValues="true,false", defaultValue="false", optional=true)
String enabled
@Param(primary=true)
String containername;
//...
}
----
The following message text strings are defined in the file
`LocalStrings.properties` for use by the subcommand:
[source]
----
create-mycontainer.command=Creates a custom container
create-mycontainer.command.originator=The originator of the container
create-mycontainer.command.mydesc=A description of the container
create-mycontainer.command.enabled=Whether the container is enabled or disabled
create-mycontainer.command.containername=The container name
----
[[ghpvn]][[GSACG00111]][[enabling-an-asadmin-subcommand-to-run]]
=== Enabling an `asadmin` Subcommand to Run
To enable an `asadmin` subcommand to run, implement the `execute` method
in your implementation of the `AdminCommand` interface. The declaration
of the `execute` method in your implementation must be as follows.
[source,java]
----
public void execute(AdminCommandContext context);
----
Pass each parameter of the subcommand as a property to your
implementation of the `execute` method. Set the key of the property to
the parameter name and set the value of the property to the parameter's
value.
In the body of the `execute` method, provide the code for performing the
operation that the command was designed to perform. For examples, see
link:#ghrsi[Example 4-6] and link:#gkbdf[Example 4-7].
[[ghpvq]][[GSACG00112]][[setting-the-context-of-an-asadmin-subcommand]]
=== Setting the Context of an `asadmin` Subcommand
The `org.glassfish.api.admin.AdminCommandContext` class provides the
following services to an `asadmin` subcommand:
* Access to the parameters of the subcommand
* Logging
* Reporting
To set the context of an `asadmin` subcommand, pass an
`AdminCommandContext` object to the `execute` method of your
implementation.
[[ghpwn]][[GSACG00113]][[changing-the-brand-in-the-glassfish-server-cli]]
=== Changing the Brand in the {productName} CLI
The brand in the {productName} command-line interface (CLI) consists
of the product name and release information that are displayed in the
following locations:
* In the string that the link:reference-manual/version.html#GSRFM00261[`version`] subcommand displays
* In each entry in the `server.log` file
If you are incorporating {productName} into a new product with an
external vendor's own brand name, change the brand in the {productName} CLI.
To change the brand in the {productName} CLI, create an OSGi fragment
bundle that contains a plain text file that is named
`src/main/resources/BrandingVersion.properties`.
In the `BrandingVersion.properties` file, define the following
keyword-value pairs:
[source]
----
product_name=product-name
abbrev_product_name=abbrev-product-name
major_version=major-version
minor_version=minor-version
build_id=build-id
version_prefix=version-prefix
version_suffix=version-suffix
----
Define each keyword-value pair on a separate line of the file. Each
value is a text string without quotes.
The meaning of each keyword-value pair is as follows:
`product_name=`product-name::
Specifies the full product name without any release information, for
example,
`name="ProductNameFullPlain" content="{productName}"`.
`abbrev_product_name=`abbrev-product-name::
Specifies an abbreviated form of the product name without any release
information, for example,
`name="ProductNamePlain" content="{productName}"`.
`major_version=`major-version::
Returns the product major version, for example, `6`
`minor_version=`minor-version::
Specifies the product minor version, for example, `0`.
`build_id=`build-id::
Specifies the build version, for example, `build 17`.
`version_prefix=`version-prefix::
Specifies a prefix for the product version, for example, `v`.
`version_suffix=`version-suffix::
Specifies a suffix for the product version, for example, `Beta`.
[[GSACG00037]][[ghrfh]]
Example 4-4 `BrandingVersion.properties` File for Changing the Brand in
the {productName} CLI
This example shows the content of the `BrandingVersion.properties` for
defining the product name and release information of {productName} 6.0.0, build 17. The abbreviated product name is
`glassfish-server`.
[source]
----
product_name=Eclipse GlassFish
abbrev_product_name=glassfish-server
major_version=6
minor_version=0.0
build_id=build 17
----
To enable the display of OEM-specific information, the following
properties might also be required:
[source]
----
LEGAL_COPYRIGHT "Copyright 2020"
LEGAL_COMPANY_NAME "Eclipse Foundation"
LEGAL_RIGHTS "All rights reserved."
SIMPLE_COMPANY_NAME "Eclipse"
COMPANY_CONTACT_URL "http://www.glassfish.org"
PRODUCT_TRADEMARKS "GlassFish is a trademark of the Eclipse Foundation"
----
[[ghmza]][[GSACG00114]][[examples-of-extending-the-asadmin-utility]]
=== Examples of Extending the `asadmin` Utility
[[GSACG00038]][[ghrnt]]
Example 4-5 `asadmin` Subcommand With Empty `execute` Method
This example shows a class that represents the `asadmin` subcommand
`create-mycontainer`.
The usage statement for this subcommand is as follows:
[source]
----
asadmin create-mycontainer --originator any-character-string
[--description any-character-string]
[--enabled {true|false}] any-character-string
----
This subcommand uses injection to specify that a running domain is
required.
[source,java]
----
package com.example.mycontainer;
import org.glassfish.api.admin.AdminCommand;
import org.glassfish.api.admin.AdminCommandContext;
import org.glassfish.api.I18n;
import org.glassfish.api.Param;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.annotations.Inject;
import org.jvnet.hk2.annotations.Scoped;
import org.jvnet.hk2.component.PerLookup;
/**
* Sample subcommand
*/
@Service(name="create-mycontainer")
@Scoped(PerLookup.class)
public Class CreateMycontainer implements AdminCommand {
@Inject
Domain domain;
@Param
String originator;
@Param(name="description", optional=true)
@I18n("mydesc")
String mycontainerDescription
@Param (acceptableValues="true,false", defaultValue="false", optional=true)
String enabled
@Param(primary=true)
String containername;
/**
* Executes the subcommand with the subcommand parameters passed as Properties
* where the keys are the paramter names and the values the parameter values
* @param context information
*/
public void execute(AdminCommandContext context) {
// domain and originator are not null
// mycontainerDescription can be null.
}
}
----
The following message text strings are defined in the file
`LocalStrings.properties` for use by the subcommand:
[source]
----
create-mycontainer.command=Creates a custom container
create-mycontainer.command.originator=The originator of the container
create-mycontainer.command.mydesc=A description of the container
create-mycontainer.command.enabled=Whether the container is enabled or disabled
create-mycontainer.command.containername=The container name
----
[[GSACG00039]][[ghrsi]]
Example 4-6 `asadmin` Subcommand for Retrieving and Displaying Information
This example shows a class that represents the `asadmin` subcommand
`list-runtime-environment`. The subcommand determines the operating
system or runtime information for {productName}.
The usage statement for this subcommand is as follows:
[source]
----
asadmin list-runtime-environment{runtime|os}
----
[source,java]
----
package com.example.env.cli;
import org.glassfish.api.admin.AdminCommand;
import org.glassfish.api.admin.AdminCommandContext;
import org.glassfish.api.ActionReport;
import org.glassfish.api.I18n;
import org.glassfish.api.ActionReport.ExitCode;
import org.glassfish.api.Param;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.annotations.Inject;
import org.jvnet.hk2.annotations.Scoped;
import org.jvnet.hk2.component.PerLookup;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
/**
* Demos asadmin CLI extension
*/
@Service(name="list-runtime-environment")
@Scoped(PerLookup.class)
public class ListRuntimeEnvironmentCommand implements AdminCommand {
// this value can be either runtime or os for our demo
@Param(primary=true)
String inParam;
public void execute(AdminCommandContext context) {
ActionReport report = context.getActionReport();
report.setActionExitCode(ExitCode.SUCCESS);
// If the inParam is 'os' then this subcommand returns operating system
// info and if the inParam is 'runtime' then it returns runtime info.
// Both of the above are based on mxbeans.
if ("os".equals(inParam)) {
OperatingSystemMXBean osmb = ManagementFactory.getOperatingSystemMXBean();
report.setMessage("Your machine operating system name = " + osmb.getName());
} else if ("runtime".equals(inParam)) {
RuntimeMXBean rtmb = ManagementFactory.getRuntimeMXBean();
report.setMessage("Your JVM name = " + rtmb.getVmName());
} else {
report.setActionExitCode(ExitCode.FAILURE);
report.setMessage("operand should be either 'os' or 'runtime'");
}
}
}
----
[[GSACG00040]][[gkbdf]]
Example 4-7 `asadmin` Subcommand for Updating Configuration Data
This example shows a class that represents the `asadmin` subcommand
`configure-greeter-container`. The subcommand performs a transaction to
update configuration data for a container component. For more
information about such transactions, see
link:adding-configuration-data.html#gjrcz[Creating a Transaction to
Update Configuration Data].
The usage statement for this subcommand is as follows:
[source]
----
asadmin configure-greeter-container --instances instances [--language language] [--style style]
----
The acceptable values and default value of each option of the subcommand
are shown in the following table. The table also indicates whether each
option is optional or required.
[width="100%",cols="<25%,<25%,<25%,<25%",options="header",]
|===
|Option |Acceptable Values |Default value |Optional or Required
|`--instances` |An integer in the range 1-10 |5 |Required
|`--language` |`english`, `norsk`, or `francais` |`norsk` |Optional
|`--style` |`formal`, `casual`, or `expansive` |`formal` |Optional
|===
Code for the container component is shown in
link:adding-container-capabilities.html#gkane[Example of Adding Container
Capabilities].
Code that defines the configuration data for the container component is
shown in link:adding-configuration-data.html#gkaal[Examples of Adding
Configuration Data for a Component].
[source,java]
----
package org.glassfish.examples.extension.greeter.config;
import org.glassfish.api.admin.AdminCommand;
import org.glassfish.api.admin.AdminCommandContext;
import org.glassfish.api.Param;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.annotations.Inject;
import org.jvnet.hk2.config.Transactions;
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.SingleConfigCode;
import org.jvnet.hk2.config.TransactionFailure;
import java.beans.PropertyVetoException;
@Service(name = "configure-greeter-container")
public class ConfigureGreeterContainerCommand implements AdminCommand {
@Param(acceptableValues = "1,2,3,4,5,6,7,8,9,10", defaultValue = "5")
String instances;
@Param(acceptableValues = "english,norsk,francais", defaultValue = "norsk",
optional = true)
String language;
@Param(acceptableValues = "formal,casual,expansive", defaultValue = "formal",
optional = true)
String style;
@Inject
GreeterContainerConfig config;
public void execute(AdminCommandContext adminCommandContext) {
try {
ConfigSupport.apply(new SingleConfigCode<GreeterContainerConfig>() {
public Object run(GreeterContainerConfig greeterContainerConfig)
throws PropertyVetoException, TransactionFailure {
greeterContainerConfig.setNumberOfInstances(instances);
greeterContainerConfig.setLanguage(language);
greeterContainerConfig.setStyle(style);
return null;
}
}, config);
} catch (TransactionFailure e) {
}
}
}
----
[[gkzlq]][[GSACG00115]][[implementing-create-delete-and-list-commands-using-annotations]]
=== Implementing Create, Delete, and List Commands Using Annotations
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, {productName}
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:
* link:#gkzkc[Command Patterns]
* link:#gkzle[Resolvers]
* link:#gkzoy[The `@Create` Annotation]
* link:#gkzoo[The `@Delete` Annotation]
* link:#gkzpl[The `@Listing` Annotation]
* link:#gkznf[Create Command Decorators]
* link:#gkznx[Delete Command Decorators]
* link:#gkzmu[Specifying Command Execution]
* link:#gkznd[Using Multiple Command Annotations]
[[gkzkc]][[GSACG00211]][[command-patterns]]
==== Command Patterns
Create command pattern. The most basic create commands are implemented
in the following pattern:
1. 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.
2. Start a transaction on the parent instance.
3. Create the child configuration object instance.
4. Set the attributes and properties of the newly created child instance.
5. Add the child to the parent using one of the following accessor
methods:
+
[source,java]
----
void setChild(ChildType child)
----
Used when there can be zero or one children of a single type associated
with one parent instance.
+
[source,java]
----
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.
6. 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:
1. Retrieve the configuration object instance to be deleted.
2. Start a transaction on the parent instance.
3. Delete the child by removing it from the list or calling `setXXX(null)`.
4. 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.
[[gkzle]][[GSACG00212]][[resolvers]]
==== Resolvers
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:
[source,java]
----
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.
[[gkzoy]][[GSACG00213]][[the-create-annotation]]
==== The `@Create` Annotation
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:
[source,java]
----
@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.
[[gkzoo]][[GSACG00214]][[the-delete-annotation]]
==== The `@Delete` Annotation
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:
[source,java]
----
@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.
[[gkzpl]][[GSACG00215]][[the-listing-annotation]]
==== The `@Listing` Annotation
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:
+
[source,java]
----
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:
[source,java]
----
@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();
}
----
[[gkznf]][[GSACG00216]][[create-command-decorators]]
==== Create Command Decorators
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:
[source,java]
----
@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:
[source,java]
----
@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:
[source,java]
----
@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.
[[gkznx]][[GSACG00217]][[delete-command-decorators]]
==== Delete Command Decorators
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:
[source,java]
----
/**
* 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:
[source,java]
----
@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:
[source,java]
----
@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.
[[gkzmu]][[GSACG00218]][[specifying-command-execution]]
==== Specifying Command Execution
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
link:#gkyfv[Specifying `asadmin` Subcommand Execution].
To add an `@ExecuteOn` annotation to a `@Create` or `@Delete`
annotation, use the `cluster` element. For example:
[source,java]
----
@Create(value="create-instance", resolver=TypeResolver.class,
decorator=Server.CreateDecorator.class,
cluster=@org.glassfish.api.admin.ExecuteOn(value=RuntimeType.DAS))
----
[[gkznd]][[GSACG00219]][[using-multiple-command-annotations]]
==== Using Multiple Command Annotations
You can specify multiple command annotations on the same method. The
following example combines create, delete, and list commands for
clusters:
[source,java]
----
@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:
[source,java]
----
@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.