Brian Stansberry [
http://community.jboss.org/people/bstansberry%40jboss.com] modified the
document:
"AS 7 "Detyped" Management API"
To view the document, visit:
http://community.jboss.org/docs/DOC-16235
--------------------------------------------------------------
+*This document is currently a draft, and is subject to considerable modification.*+
This document is meant to describe the design of the management API of an AS 7 domain and
of a single AS 7 server instance running in standalone mode.
The API is described as "detyped" to reflect the fact that the API only exposes
a small number of types besides JDK classes.
The goals are to:
* Define a Java-based API that can be consumed by a remote java client that requires only
a small number of types besides JDK classes to be on the client classpath. Any complex
types involved in the API are expressed in terms of a fixed set of general purpose
classes. The types needed on the client classpath are:* A library containing the small set
of general purpose types (see discussion of MetaValue, MetaType below), plus some helper
utilities (e.g. Builder classes) to assist in building up objects of those types.
* 4 interface classes, each of which describes the methods exposed by one of the server
side "controllers". The parameters and return types in these interfaces should
be expressed in terms of the general purpose types. The methods in these interfaces will
be limited and general purpose in nature, i.e. there will not be a myriad of detailed
methods like "setHttpPort(int port)". The 4 types of "controllers"
are:* DomainController. Primary management point for an AS 7 domain. Responsible for all
configurations in the domain.xml file. The DomainController is also intended to function
as the central management point for all hosts and servers in the domain, delegating to
internal APIs exposed by the HostControllers or ServerControllers as necessary. However, a
running AS 7 domain does not require a running DomainController, so the HostControllers
and ServerControllers will also expose a management API.
* HostController. Responsible for controlling one or more AS 7 server instances on a
physical or virtual host. Responsible for all configurations in the host.xml file for that
host. Will also expose some host-specific management operations, e.g. start/stop/restart a
server.
* ServerController (domain mode): Provides a read-only view of an individual server's
configuration. Provides access to any metrics exposed by the server. Provides access to
any non-configuration-related management operations exposed by the server (e.g. remove
message X from JMS queue Y.) Does not expose any ability to update the server's
persistent configuration, as all aspects of a server's persistent configuration are
the responsibility of either the DomainController or the host's HostController.
* ServerController (standalone mode): Sole management point for a standalone AS 7 server
instance.
* Internal implementation classes related to the protocol for communicating with the
"controllers". These are not part of the API but need to be on the client
classpath.
* On the server side, provide a straightforward mapping of the core detyped Java API to
JMX. The intent is that most (hopefully all) attributes and operations exposed via the
core API will be available via JMX.
* On the server side, provide a straightforward mapping of the core detyped Java API to
REST. The intent is that most (hopefully all) attributes and operations exposed via the
core API will be available via REST.
* Handle different types of management actions:* Reads of persistent configuration
attributes
* Writes of persistent configuration attributes
* Reads of server level runtime state (i.e. metrics/statistics)
* Updates to server level runtime state that do not impact persistent configuration
* Discovery of what the manageable resources exposed by the system are, and what
attributes and operations are supported by those resources.
* Provide clean handling for operations that inherently impact multiple servers (i.e.
updates to the domain.xml configuration model and any host.xml configuration.) Allow the
end user to specify how those changes are applied to various server groups and the servers
within those groups in a "management operation plan". After the operation is
executed, provide detailed information on how the operation was executed on the various
controllers and servers involved.* For management operation plans involving updates to
persistent configuration, the plan will include information on what should happen in case
the update cannot be applied successfully to one or more servers; i.e. whether the update
should be applied to other servers where it has not yet been attempted or rolled back on
servers where it has successfully been applied.
* Hide some of the API complexity involved in the above by having a default update plan
that concurrently applies the operation to all relevant server groups and all servers
within the domain.
* Management operation plans should include support for multiple operations that update
persistent configuration that are to be performed as an atomic unit.
* +TODO: is it necessary to support plans with multiple operations that are *not* atomic;
i.e. where failure of one operation will not cause the others to be rolled back? We
currently do, but this adds conceptual complexity and clutters the API a bit.
+
* Provide the ability to target operations that are not inherently multi-server in nature
against a particular server. Such operations are:
* Reads of persistent configuration attributes
* Reads of server level runtime state (i.e. metrics/statistics)
* Updates to server level runtime state that do not impact persistent configuration
Other goals include:
* Support for notifications. The detyped Java management API should include a general
mechanism by which managed resources can advertise the availability of notifications. The
detyped Java API should include a generic mechanism by which clients register a listener
for notifications. This implies a persistent connection between the client and the
server.
* Ability to get progress events as multi-server operations are executed. Some operations
may take a considerable amount of time to execute across the domain (e.g. a large, complex
deployment applied to many servers); allowing callers to register a listener for progress
events would be nice. The AS 7 Alpha1 domain deployment plan handling had a prototype of
that kind of capability.
h3. MetaValues
Method parameters and return types in the detyped API are expressed in terms of a limited
number of general purpose classes known as "MetaValues". The types of MetaValues
are:
* SimpleValue -- a simple wrapper around one of a fixed list of JDK types (String,
primitive wrapper types, Date, BigDecimal, BigInteger.
* ArrayValue -- an array of other meta values, all of which are of the same type.
* CollectionValue -- a collection of other meta values, all of which are of the same
type.
* MapValue -- a Map<MetaValue,MetaValue>.
* CompositeValue -- a sort of Map<String, MetaValue> where the type of the MetaValue
associated with a given key is fixed, but different keys can have values of different
types. This type is used to model complex Java types, where each key/value pair in the map
is analogous to a field in an ordinary Java type.
* TableMetaValue -- a table where each row is a CompositeValue with an identical mapping
of allowed keys and value types. The table definition includes an ordered list of which
which keys are "index fields". A particular CompositeValue can be retrieved from
the table by providing a list of MetaValues, each of which corresponds to one field in the
index.
In practice, the most commonly used types are SimpleValue, CollectionValue and
CompositeValue.
h3. MetaTypes
A MetaValue includes a read-only property of type "MetaType". Accessing a
MetaValue's MetaType allows the caller to determine information about the value's
type, in an analogue to how using reflection can determine information about an ordinary
java object. A MetaType can also be used to validate a MetaValue; i.e. the MetaType can
check that the value's composition is consistent with the MetaType's definition.
+An important problem to solve is making MetaTypes easy to use for end users. See below
for more on this issue.+
Each of the value types described above has a corresponding MetaType.
* SimpleValue exposes a SimpleMetaType. SimpleMetaType just exposes the class name of the
wrapped value (java.lang.String, java.util.Date etc). There is a constant value (e.g.
SimpleMetaType.STRING) for each of the legal types.
* CollectionMetaType exposes the (single) MetaType of the MetaValues that comprise a
CollectionValue.
* ArrayMetaType exposes the (single) MetaType of the MetaValues that comprise an
ArrayValue.
* CompositeMetaType defines what the valid keys are in a CompositeValue, as well as what
the MetaType must be for each key's value. It also includes a text description of each
key. (+Note: I think it should also expose whether a given key/value pair is optional.+)
* TableMetaType defines what the (single) CompositeMetaType is for the rows in a
TableValue, along with what keys comprise the index.
As mentioned above, an important problem to solve is making MetaTypes easy to use for end
users. There are a number of requirements that need to be met:
1. Every MetaValue emitted by the server must have a valid MetaType associated with it.
Clients should be able to use the MetaType to introspect the value.
2. Clients should not have to have a reference to a MetaType in order to construct a
MetaValue. For example, say a particular operation exposed by a managed resource takes a
parameter named "socket" whose type is a CompositeValue, and that value's
MetaType defines a key named "name" that requires a String value, a key named
"port" that requires an int value and an optional (nillable) key named
"properties" that requires a Map<String, String>. A client should be able
to construct a valid value simply by indicating that a CompositeValue is needed and by
assigning appropriate values to "name" and "port". They should not
need to provide the MetaType. There are a couple possible ways this might be handled:1.
Don't require MetaValue to expose MetaType. Have a separate interface/class hierarchy,
e.g. TypedMetaValue that exposes the MetaType. Servers always produce
TypedMetaValue's, but clients can construct objects of a simpler MetaValue class
hierarchy that don't expose (or require) the MetaType. This approach is conceptually
complex though and breaks down in cases like TableValue, whose semantics require type
information.
2. Provide a sort of DSL/builder pattern to create MetaValues. The builder accumulates the
information to create the MetaType at the same time it accumulates the information to
compose the value. In the build() operation it actually constructs the MetaType and passes
it to the constructor of the MetaValue. Emanuel Muckenhuber is exploring this approach.
3. Clients (and the server) should be able to validate MetaValues they create against the
expected MetaType. This validation should not overly rely on an exact match of MetaTypes
(e.g. value.getMetaType().equals(anotherMetaType)). It should account for the possibility
that the value's MetaType may not include optional information. For example, a client
may create a CompositeValue to act as the "socket" parameter described above.
The MetaType for that CompositeValue may not include information about the optional
"properties" key. A validation of that value against the full formal definition
of the parameter should not fail, since "properties" is optional. A missing
"name" however should result in a validation failure.
h3. Managed Resources
The API exposed by each controller (DomainController, HostController, domain-mode or
standalone ServerController) is expressed in terms of attributes and operations exposed by
a set of ManagedResources. A ManagedResource is conceptually similar to a JMX MBean, with
the significant difference that ManagedResources are organized in a tree structure,
whereas MBean need not have any inherent organization.
ManagedResources expose a set of read-only attributes and a set of operations. Attributes
expose the persistent configuration of the resource. Operations can be read-only (e.g. a
metric), write-only, or read-write. Unlike in JMX, attributes are not read-write. The
value of some attributes may be mutable, but can only be mutated via an operation. (The
operation to mutate attribute "foo" may be named "setFoo", but
it's still an operation.) Attributes are not used for metrics; they are only used to
represent the persistent configuration of the resource. Metrics are retrieved using
operations. (The operation to retrieve a metric "threadCount" may be called
"getThreadCount" and not take any parameters, but it is still an operation.)
Each resource also exposes meta-information about itself that clients can use to discover
what attributes and operations are exposed by the resource. This meta-information is
encapsulated in a ManagedResourceInfo object. A ManagedResourceInfo object is conceptually
very similar to a javax.management.MBeanInfo.
ManagedResources are organized in a tree structure. Each ManagedResource (except root
resources; see below) must expose an attribute whose value is of some SimpleMetaType that
acts as the unique identifier for the resource compared to all similar resources under the
resource's parent resource. (+TODO: consider requiring this value to be of
SimpleMetaType.STRING.+) The name of this attribute is arbitrary. The name of the
attribute must be exposed via the resource's ManagedResourceInfo object, via the
getIdAttributeName() method.
Each controller (DomainController, HostController, domain-mode or standalone
ServerController) is responsible for managing a resource tree. Each resource tree is
rooted in a root ManagedResource. A ManagedResource exposes an isRoot()method that must
return true for the root resource and false for all others. For a root resource, the
ManagedResourceInfo.getIdAttributeName() method must return null, as a root resource does
not require a unique identifier.
Besides attributes and operations, a ManagedResource offers a read-only view of the child
resources organized under it in the tree. Child resources are organized by type, with all
resources of a given type exposing ManagedResourceInfo objects that are equal to each
other. For each child resource type, the parent resource maintains a simple string
identifier that represents the collection of resources of that type. For example, a
ManagedResource representing a JBoss Web web server subsystem might have child resources
that represent JBoss Web connectors, and would use the string "connectors" as
the identifier for that collection of resources.
The ManagedResourceInfo for a resource includes metadata about what types are child
resources are available, what the name of the identifier is the parent uses for the
collection of each type of child, and the cardinality of the relationship (typically 0..1
or 0..*). The lower limit *must be zero* otherwise a parent resource cannot exist without
children, yet child resources cannot exist without a parent. (+TODO there may be ways
around this if it proves to be a problem.+)
Adding and removing child resources is accomplished by invoking operations on the parent.
(+TODO: another possibility is the (Domain/Host/Server)Controller API expose special
"add" methods.+)
h4. Addressing a ManagedResource
From the above, a fairly simple scheme for addressing any resource in
the tree becomes apparent. An address for a resource is an array or List of simple string
pairs. The first string in the pair is the identifier the parent uses for the collection
of child resources of the child's type. The second string is the value of whatever
attribute the child resource identifies as its "id attribute".
So, for example, the address of the resource representing an HTTP connector in the domain
model might be expressed as:
{profiles/web},{subsystems/web},{connectors/http}
It's easy to see how that cold easily be mapped to a REST resource URL:
http://127.0.0.1/domain/profiles/web/subsystems/web/connectors/http
(
http://some.host.com/domain/profiles/web/subsystems/web/connectors/http)
It also maps readily to a JMX ObjectName, where each ManagedResource is exposed in JMX as
an MBean:
jboss.as.domain:profiles=web,subsystems=web,connectors=http
A not so nice thing in the above is an English issue where the plural form of a property
name is not the same as its singular form, and in some contexts the singular form is more
natural, e.g. in a key/value pair
jboss.as.domain:profile=web,subsystem=web,connector=http
There are a couple possibilities here; one is to always use the singular form, on the
theory that a singular form in a REST URL is less unnatural than a plural form in an
ObjectName. Another possibility is to have the ManagedResourceInfo metadata that describes
the parent/child relationship include information about both the singular and plural
forms. Different addressing systems would use the more "natural" form; parents
can resolve children using either form.
h4. Client-side View of a ManagedResource
The management API provides a read-only view of the current state of a
ManagedResource's attributes. This is via the ManagedResource class in the detyped
API library. The ManagedResource class is simply another type of MetaValue. The
ManagedResourceInfo object it exposes is another type of MetaType.
h3. Reading Attributes
Directly via *Controller API:
EntityAddress address =
EntityAddress.fromString("profile/web/subsystem/web/connnector/http");
MetaValue m = domainController.getAttribute(address, "socket");
String socketName = (String) ((SimpleValue) m).getValue(); // yuck! how about
SimpleMetaType.STRING.getValue(m);
(+TODO: quite likely EntityAddress can be replaced with a simple String+).
Indirectly via ManagedResource:
EntityAddress address =
EntityAddress.fromString("profile/web/subsystem/web/connnector/http");
ManagedResource connector = domainController.getManagedResource(address);
MetaValue m = connector.getAttribute("socket");
String socketName = (String) ((SimpleValue) m).getValue(); // yuck! how about
SimpleMetaType.STRING.getValue(m);
h3. Invoking Operations
The operations exposed by a resource are described in its ManagedResourceInfo, via the
ManagedResourceOperationInfo objects returned by its getOperations() method. The main
information provided by a ManagedResourceOperationInfo object is the name of the operation
and a description of the metatype of the parameters the operation takes.
Invoking an operation consists of creating MetaValues for the parameters, and passing
them, along with the name of the operation and the address of the target resource, to the
invoke method.
EntityAddress address =
EntityAddress.fromString("profile/web/subsystem/foobar");
MetaValue foo = createFooMetaValue();
MetaValue bar = createFooMetaValue();
domainController.invokeOnDomain("setFooBar", address, foo, bar);
(+TODO: clarify why I said "invokeOnDomain" above vs a more general
"invoke" -- basically we need to distinguish operations that affect the domain,
vs those that effect a single host, vs those that effect a single server, as the structure
of the result varies. The "invokeOnDomain" is a nod in that direction.+)
The return type of the invocation depends on whether the operation targets the domain, a
host or a single server. All operations have a core return type of some MetaValue; the
MetaType of that MetaValue varies from one operation to another and is described in the
ManagedResourceOperationInfo object that describes the operation. However, for operations
that impact more than a single server, the core return value from each server needs to be
encapsulated in a larger data structure that describes the overall impact of the operation
across the domain.
For example, an operation that effects a domain level resource would be executed by the
DomainController as follows:
* Handle the operation on the DomainController itself. For example, update the DC's
copy of the domain configuration.
* Ask all registered HostControllers to handle the operation (e.g. update their copy of
the domain configuration) and reply with the list of servers that would be affected by the
operation.
* Execute tasks asking the HostControllers to instruct individual servers to execute the
operation and reply with any return value.
As a result, the return value provided by the DC would need to include the following
information:
* Failure information describing any failure to apply the operation on the domain
controller. (TBD: just a String or some exception type. My inclination is to use a String,
which loses stack trace information, but avoids all issues with server exception types
leaking to the client. Stack traces can be logged on the server side, where they are more
relevant.)
* Failure information describing any failure to roll back the operation on the domain
controller. (The rollback would occur following a successful application on the DC, but a
failure on a HostController or server.)
* Map<String, failure information> describing any failures to handle the operation
on a HostController.
* Map<String, failure information> describing any failures to roll back the
operation on a HostController. (The rollback would occur following a successful
application on the HostController, but a failure on another HostController or a server.)
* Results by server
* Identity of the server* name
* host name (to allow correlation of results by host)
* server group name (to allow correlation of results by server group)
* Failure information describing any failure to handle the operation on the server
* Failure information describing any failure to roll back the operation on the server
* The return value of the operation.
A similar process applies to operations that affect a host's configuration. Return
values would include:
* Failure information describing any failure to apply the operation on the
HostController.
* Failure information describing any failure to roll back the operation on the
HostController. (The rollback would occur following a successful application on the
HostController, but a failure on a server.)
* Results by server
* Identity of the server* name
* host name (to allow correlation of results by host)
* server group name (to allow correlation of results by server group)
* Failure information describing any failure to handle the operation on the server
* Failure information describing any failure to roll back the operation on the server
* The return value of the operation.
An operation targetted at a single server would have a simpler return type:
* Failure information describing any failure to handle the operation on the server
* Failure information describing any failure to roll back the operation on the server
* The return value of the operation.
+TODO: decide how to represent all of the above. The domain-client module currently has a
class for this for domain level deployment operations that could be adapted for general
use. It can all be represented in a complex detyped object as well (CompositeValues and
CollectionValues nested in other CompositeValues). That's painful for the end user,
but reduces the number of client-side classes. For now the assumption is they will become
complex detyped objects.+
h3. Management Operations Plans++
+TODO+
h3. Notifications++
+TODO
+
--------------------------------------------------------------
Comment by going to Community
[
http://community.jboss.org/docs/DOC-16235]
Create a new document in JBoss AS7 Development at Community
[
http://community.jboss.org/choose-container!input.jspa?contentType=102&am...]