[jboss-as7-dev] Detyped API document feedback
David M. Lloyd
david.lloyd at redhat.com
Tue Jan 4 12:02:03 EST 2011
This commentary is in reference to version 2 of the detyped API document
at: http://community.jboss.org/wiki/AS7DetypedManagementAPI/version/2
========
Goals
> * 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.
Right on
> 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.
OK
> 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:
I agree on the lack of detailed methods. However I strongly disagree on
having a method for each controller type. There is no reason why we
cannot have a single protocol where the target object is distinguished
by address. This allows users more code reuse because all they have to
change is the target address of what they're modifying.
We should be able to use a generic RPC mechanism like Remoting to send a
standard request type to a single protocol listener.
<trim>
> * On the server side, provide a straightforward mapping of the core
> detyped Java API to JMX / REST...
<trim>
> * Handle different types of management actions:
This brings up a good point. So far on ServerController, the sole
interaction method is handleUpdate(), however updates are only one of
the things supported there. So the method should be renamed to
something more generic, like handleRequest() or something. Of course
the *Update classes are going away so we don't have to bother renaming
those.
<trim>
> * 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.
<snip>
> * 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.
On the model level, no. Either the whole update is applied or none of it.
At runtime, I think that any part of a multi-step ("composite") update
failing is equivalent to the whole update failing. Also, any update, be
it simple or composite, should only have one single plan which applies
to the whole works (in other words, the plan for application and/or
rollback may only be present on the top-most update entity which was
submitted to the controller).
This simplifies the whole issue. I can say, "Run these 3 updates. If
they fail (at runtime), just keep it in there and I'll inspect and/or
fix it by hand.", or "If they fail, roll them all back". These are the
only two sensible actions I can think of.
<more trimming, until we get to...>
========
MetaValues
I agree with some of these types but not others:
* SimpleValue
+ String - yes
+ primitives - some; maybe just boolean/int/long/float/double but
not byte/short/char for example
+ Date - no, let's use long for now, and revisit once JSR-310 is
done. Date is basically worthless.
+ BigDecimal/BigInteger - yes
* CollectionValue/ArrayValue - No, I'd rather see byte[] added to the
above list and otherwise have a list value type, each element of which
can be whatever type
* MapValue - No, we don't need any map key type other than strings
* CompositeValue - too much work, why not just use a simple map of
Strings to values? By making the type dependent on the key it's
basically impossible to use without metatype info
* TableMetaValue - too complex
I'd rather do something more dynamic where you can start with a node and
just build up whatever you want from it:
node = new ModelNode();
node.get("operation").set("change-bind-port"); // string
node.get("address").add("base, "domain"); // a list
node.get("address").add("profile", "web");
node.get("address").add("subsystem", "web");
node.get("address").add("connector", "ssl");
node.get("bind-port").set(8433); // int
result = connection.execute(node); // goes over remoting
System.out.println("Result is: " + result);
// nicely formatted, JSON-style (but with more possible types)
I wipped up a demo of this style of API at:
https://github.com/dmlloyd/jboss-dmr
Notice there's only one public class and one type enum. (The Validation
class isn't anything, just an experiment.)
The main point to this API is that things like Map and List are
*completely inadequate* by themselves to define a detyped API. The
reason that languages like Perl, PHP, Python, Ruby, and JS are so good
at this kind of thing is because they can take advantage of dynamic
typing in a way that Java normally can't. So the best solution in my
view is to layer a simple dynamic-type layer on top of the static types
we're used to dealing with.
========
MetaTypes
I gotta be honest, I'm not liking this API. I don't see this as
something users will consider to be a huge advantage over JMX. I know
there are notes in here about improving user-friendliness but I do not
believe this is something that can be added in later; it has to be built
in from the ground up.
If we want a real differentiator from JMX (i.e. a much lower barrier to
entry), the first step is making requests easy to build.
I'd consider it a logical progression to use the same dynamic
representation given above to represent the actual model data. Instead
of mirroring JMX with management entities combining operations and data,
we should have a pure-data view of the model itself.
The registry of operations should be external to the model itself; it
would be a map with a key that corresponds to the operation name plus a
"path" specification to the applicable node type. Some operations (like
"read") would be generic and would apply to any node path, where some
(like the example above) would be highly specific.
Querying a model element amounts to copying a chunk of this data
verbatim, which is why more generic operations like "read" can work.
This means that we don't need to replicate common operations. To look
at it from a JMX perspective, we can dynamically build the mbean
operation sets off of all the operations which can apply to the given
model node. Thus every mbean could automatically get a "read" method
which can yield the model data.
This is also important because the whole set of all operable entities
encapsulates more than the model in even the simplest scenarios. Thus
operations have to be able to reach outside of the model to do things
like query runtime state and so on.
Of course this bypasses the other half of the problem which is
describing the model and available the operations. But, by having a
special value type for representing a value type, this kind of dynamic
representation can be fully self-describing:
{
"operation-name" => "change-bind-port",
"address" => [
("base"=>"domain"),
("profile"=>"*"),
("subsystem"=>"web"),
("connector"=>"*"),
],
"request-properties" => {
"bind-port" => {
type => INTEGER,
required => true,
min-value => 0,
max-value => 65535,
}
},
"reply-properties" => {}
}
Thus we can have an operation whose purpose is itself to describe
operations. This also enables our domain controller to automatically
remap server- and host-level operations to the domain level by adding
address discrimination without having to replicate the code for these
operations.
This means we can perform validation generically, if we want - even on
the client side, optionally. This should help reduce the "bogeyman
effect" that may be associated with dynamic type systems.
========
In conclusion - I think if you look at the primary use case for this
API, the thing it will be used for more than anything else is going to
be custom scripting and special-purpose client programming. A dynamic
model is perfect for this use case because it has the absolute minimum
barrier of entry possible for a detyped API. Users already know what is
valid, they just want to put in the properties and run it.
--
- DML
More information about the jboss-as7-dev
mailing list