On 1/4/11 11:02 AM, David M. Lloyd wrote:
This commentary is in reference to version 2 of the detyped API
document
at:
http://community.jboss.org/wiki/AS7DetypedManagementAPI/version/2
<snip/>
========
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
OK. These will just clutter the API and bring little value.
+ Date - no, let's use long for now, and revisit once
JSR-310 is
done. Date is basically worthless.
+1
+ 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
Yeah; the current CollectionValue in jboss-meta requires all elements to
be of the same MetaType, which in practice makes the equivalent to
List<Object> or List<Number> impossible. That's annoying. And it kind of
works the opposite of generics -- it doesn't catch any errors at compile
time but will at runtime. So, agreed, a list of any type is better.
* MapValue - No, we don't need any map key type other than
strings
Agreed. I did a fair amount of work with the AS 5 detyped stuff and
can't recall using anything but a string as a key.
* 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
The basic question is whether there's any value in shipping complex
metatype information along with a value. I'm starting to think there
really isn't, so I'm with you here. People either know the metatype or
we can provide a separate operation to let them find it.
* TableMetaValue - too complex
Haha; that one was just in there temporarily to spark discussion in case
someone can *really* justify it. I agree, it needs to go.
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.
Yes, that's the way it's meant to work.
There are 2 key differences in what I see you describing vs the client
side view of a ManagedResource described on the wiki article:
1) A ModelNode sent from the server to the client (e.g. via your "read"
operation below) would not include any complex metainformation -- no
equivalent to MBeanAttributeInfo, MBeanOperationInfo, etc. Instead, a
user interested in that kind of metainformation would execute a
different operation to get it.
I think that's good.
2) There's no distinction between an "attribute" and another entity
that's in a parent-child relationship. What that means in practical
terms is the "read" operation you describe executed with address
"base=domain" would pull down the whole model, with no simple way to
just pull down the attributes of the parent and not the
separately-addressable children.
Thinking about it though, that's probably ok. People are almost always
going to want to read a single attribute or a whole subtree.
Some operations (like
"read") would be generic and would apply to any node path, where some
(like the example above) would be highly specific.
We'll have to have rules for this such that there is no ambiguity about
what operation is meant (i.e. there can't be a "read" operation
associated with some subsystem address.) I think that means a limited
set of operations like "read" that are global to all addresses and whose
names are reserved. Everything else is like your example above.
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.
Yep. That's nice.
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.
Sure. The set of operations was always meant to be separate from the
model data. Really the only tie is the addressing scheme -- for *some*
operations there needs to be a consistent way to walk the data tree to
get the data associated with a particular address. For other operations,
the model data might not be needed at all.
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,
Do you mean "a special value for representing a value type"? What you
describe below looks like an ordinary value with a well-known structure.
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.
--
Brian Stansberry
Principal Software Engineer
JBoss by Red Hat