GlassFish V3.1 RESTful API Camel Case Name Proposal 1.2. Name(s) and e-mail address of Document Author(s)/Supplier:
- Jason Lee: jdlee@java.net
- Ludovic Champenois: ludovic.champenois
- Mitesh Meswani: mm110999@java.net
1.3. Date of This Document 05/18/2010 2. Problem Summary 2.1. Problem Area Currently, the REST API returns key names in a couple of different formats: a XML-like dashed name (this-is-an-example) or all lower case (thisisanotherexample). This inconsistency unnecessarily increases the burden on application developers as they have to know what format to expect where, as well as maintaining distinct blocks of code to handle each of the "formats." Additionally, the second format loses any information that might indicate word breaks, making generated code less ready (e.g., the getter in, say, a Python client for this-is-an-example would be getThisIsAnExample, whereas thisisanotherexample would be getThisisanotherexample). 2.2. Justification Having slightly different but mostly similar blocks of code, whose sole difference is the case/format of key names in Maps, is undesirable. A common, consistent format then, must be decided upon to reduce the amount of work needed to interact with the API. Similarly, to make the API even more useful, it is desirable to present the key names in a manner that is as flexible and meaningful to consuming code, whether it's an actual client or a client/wrapper generator. After some discussion with Jerome and Ludo, camel-cased names was decided upon as the preferred way to present the key names to any consuming code. Camel-cased names in JSON/JavaScript is the defacto standard to name properties. 3. Technical Description 3.1 The Current Situation In the current code base (as of early May 2010), the parameter names exposed by the REST API come from one of two places, ConfigBeans for GET (Read) and PUT (Update) and sometimes CommandModels (for DELETE (delete-* commands), and POST (create-* commands)). Depending on the requested operation (ConfigBeans for read/GET, or, oftern ModelCommands for create/POST or update/POST), the REST service will scan the object in question and interrogate either the @Attribute (and related field) or @Param. For @Attributes, the field name is converted to dash-separated words (HK2 does that when saving the real domain.xml file), while for @Params, the name attribute is returned. There is no real mapping today between a ConfigBeans attribute name and a CLI param of a command which many times corresponds to a ConfigBean attribute. (There are some cases of CLI params that do not correspond to ConfigBeans attribute, for example the --force param of the redeploy command). 3.2 The Proposed Solution Since the REST API leverages the CLI classes for at least some of the create, delete and update operations, these CLI commands must be modified in some way to return the proper casing. The proposed solution is to modify the @Param annotation, adding the camelCaseName attribute:
@Param(name="steadypoolsize", camelCaseName = "steadyPoolSize", optional=true)
String steadypoolsize = "8";
The existing Attribute of the ConfigBeans is untouched, as:
@Attribute (defaultValue="8") @Min(value=0) @Max(value=Integer.MAX_VALUE)
String getSteadyPoolSize();
Another use case for this new attribute is name consistency for the any client (including REST) of the CLI framework. For example:
@Param(name="maxwait", camelCaseName = "maxWaitTimeInMillis", optional=true)
String maxwait = "60000";
While the published CLI param name is "maxwait", it will be easier and consistent to use "maxWaitTimeInMillis" in a JSON document to refer to both the CLI parameter and the JdbcConnectionPool ConfigBean attribute:
@Attribute (defaultValue="60000") @Min(value=0) @Max(value=Integer.MAX_VALUE)
String getMaxWaitTimeInMillis();
The REST service will then be modified to use this value, if it is present, when creating the parameter list:
String parameterName = (paramModel.getParam().primary())?"id":paramModel.getName();
String parameterCamelCasedName = paramModel.getParam().camelCaseName();
if(parameterCamelCasedName == null || parameterCamelCasedName.isEmpty()) {
parameterCamelCasedName = parameterName;
}
(Note: the code above should/will ultimately move to the ParamModel class...) The reverse mapping must be done when the POST/PUT command is received. The prototype of this code does this work:
CommandRunner cr = habitat.getComponent(CommandRunner.class);
CommandModel cm = cr.getModel(commandName, logger);
Collection<CommandModel.ParamModel> paramModels = cm.getParameters();
HashMap<String, String> translatedMap = new HashMap<String, String>();
for (CommandModel.ParamModel paramModel : paramModels) {
Param param = paramModel.getParam();
String camelCaseName = param.camelCaseName();
if(sourceMap.containsKey(camelCaseName)) {
String paramValue = sourceMap.remove(camelCaseName);
translatedMap.put(paramModel.getName(), paramValue);
}
}
//Copy over the remaining values from sourceMap
translatedMap.putAll(sourceMap);
return translatedMap;
3.3 The Prototype Some of this code is already in the REST module, though, as of 18-May-2010, has not been checked in. The client to consume these changes is currently under development under the admingui module (v3/admingui/prototype). Basic create functionality on the REST side has been confirmed through Jersey client-based test code, but a more robust solution, modeled after the current production AMX code in the console is being developed by Jason Lee and Ken Paulsen. 3.4 Next Steps Assuming the proposal is accepted and the prototype does not uncover show stopping problems, each CLI command in the system must be touched to add this new attribute (where appropriate, i.e mostly on only the create-XXX commands used by the REST POST layer). The REST module team has it as an AI to determine the owner of each command and work with that team to insure that each command is updated as necessary.
|