Administrative console - ARCAD-Software/AFS GitHub Wiki
The administrative console, is a service offered by the AFS bundle com.arcadsoftware.server.restful.console. It publish three set of web-services related to the OSGi Configuration Admin service (but not only):
- /config/ allowing to access to "public" properties from the server configuration.
- /admin/config/ offer a direct interface to the complete configuration (for authorized user).
- /remote/console/ offer a structured interface to the configuration.
Each Configuration Dictionary from the OSGi configuration admin service may include a property named "public.system.parameters" this property will list the names of other properties form this same dictionary, separated by a white space, which will be published by the /config/ services. These service are only accessible through a GET method. No authentication is required to access to them.
-
/config/
list the Permanent ID (PID) of all configuration dictionary currently containing the "public.system.parameters" property. -
/config/{pid}
list the public properties of the given configuration dictionary. Note that properties not explicitly stored in the configuration are not listed here. -
/config/{pid}/{property}
return the current value of the given property in the given configuration dictionary.
All of these services may return XML, XSD or JSON responses.
User owning the following access rights can respectively remotely read or modify the OSGi Configuration:
- Server configuration parameters consultation (Access Right number 6)
- Server configuration parameters modification (Access Right number 7)
Theses access right give an access to the following web-services:
-
/admin/config/
list all PID of the currently declared OSGi configuration dictionaries. -
/admin/config/{pid}
List, or allow to set the given OSGi configuration dictionary. This service may be acceded through POST, PUT or DELETE methods the payload for POST and PUT method may use WWW-URL Encoded Form, XML or JSON.
All of these services may return XML, XSD or JSON responses.
This latest set of configuration related services is more versatile than the previous ones. They allow to present the server configuration as sets of configuration forms, called "sections". Each section may be declared in a XML file or associated to an OSGi service implemented on the server. This may allow to access to the OSGi configuration dictionary in a more convenient way but also to propose more extended services related to the configuration, and based on a Form a-like presentation.
These services are accessible to any authenticated user with the "Administrative Console access" right (Access Right number 2).
-
/remote/console/
list all sections of the administrative console, grouped by categories. This list is ordered by the server code. -
/remote/console/{sid}
return the content of a section of the administrative console, according to its Section IDentifier. -
/remote/console/{sid}/{aid}
perform the execution of an action defined by the given section. Each section define at least one default action named "save". Each action execution is performed through a POST method with an WWW-URL Encoded Form, including the whole content of the section.
There is two kind sections, the declarative ones and the Java implemented ones, which are declared as OSGi services. From a client perspective both section are identical. A section is identifier by a unique name, called here as the Section IDentifier, or SID. The content of a section, served as an XML of a JSON document, may content the following elements:
- text: Represent a simple text message to be printed on screen for the user information.
- property: Represent a value presentation which may be edited by the user, and must be returned in the result for the execution of any action.
- set: Represent the beginning of a new group of coherent properties.
- message: Represent an informational message, which should be associated to a message box.
- action: Represent an action which may be executed from this section.
Each of these element possess a particular set of properties, including a "label" to present to the end user and for the "property" object the value to be edited. This presentation is really similar to simple HTML Form presentations.
The web-services may also serve an XSD document describing this content.
Two different kind of declarative section may be included in any bundle the declaration is done in an XML file called consoles.xml, in the META-INF folder. this files may contain a set of "configuration" or "section" object. The first one is a section attached to a OSGi Configuration admin dictionary. It may arrange the presentation of the properties contained in the configuration. The second "section" type is associated to a groovy screen which will be executed when the corresponding action is selected. It allow a more elaborated management without the need to create an OSGi service section.
The most common declarative section are the configuration ones. In that case the XML "configuration" object must define some attributes but all of them are optional:
- id: define the Section unique Identifier, by default it is equal to the pid attribute value.
- pid: define the Persistent Identifier of the OGSi configuration dictionary, by default it is bid attribute value.
- bid: define the bundle symbolic name which correspond to this configuration, if this bunlde is not present the section will be disabled, by default it is equal to the current bundle Symbolic Name.
- order: is an positive integer which define a relative order used to sort the sections.
- messages: define the path to a properties file containing translation of all the section GUI message. There is a lot of default rule which rely on the properties found in this resource. By default the messages properties file is assumed to be found in the same folder of the "consoles.xml" file and named "messages.properties".
- label, title, category and help: define the value of the textual representation of the corresponding element, or they may define the key used in the "messages" properties file to translate them, by default the messages properties: console.label, console.title, console.category and console.help will by loaded from the messages properties file.
- keywords: define a set of topic names which may be used to filter the sections.
The XML "configuration" object will mainly contain a set of "property" declaration, each one of these object will correspond to configuration properties which will be exposed in the console section, the attributes of this object are:
- id: the corresponding configuration property name. This parameter is the only required one.
- default: define the default value of this property. This value is not required, it defaults to an empty string.
- type: define the type of the property value, By default the type of the default value is used (e.g. if a default value is define to "1" the type is assumed to be a number), if there is no other way to guess it the default type is "string". Supported types values are: string, number, enum, boolean, password, float, date, time, positive (i.e. positive number), path, url, text (i.e. multi-line string).
- password: is a boolean value, if true, the value is assumed to be from type "password" and will encrypted before to be stored into the configuration. Its default value is false.
- readonly: is a boolean value, if true the value will be presented in the section but no modification will be accepted. Its default value is false.
- hidden: is a boolean value too, if true this property will be sent to the client but should not be presented to the end user, its value must be sent back to the action executed from this section. Its default value is false.
- label: define the key un the messages properties file, or by default the actual user readable name of this property, by default the id of this property is used as a key in the messages.properties file.
- help: define a short description of this property, again its value may be the actual description or a key in the message properties file, and by default a by id.help key will be seek in the messages properties file.
The "property" XML object may also content a set of <string>...</string>
objects, in that case its type is assumed to be "enum".
Here is an sample of a declaration of a configuration liked section:
<?xml version="1.0" encoding="UTF-8"?>
<sections xmlns="http://xml.arcadsoftware.com/1.0.0/console.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xml.arcadsoftware.com/1.0.0/console.xsd http://xml.arcadsoftware.com/1.0.0/console.xsd">
<configuration order="744">
<property id="hostname" />
<property id="port" default="0" />
<property id="forward" default="false" />
<property id="keystore" />
<property id="keystorePassword" password="true" />
</configuration>
</sections>
This section SID, the PID of the corresponding configuration dictionnary are equal to the Symbolic name of the bundle containing this xml file. We can assume that this is its configuration. A message.properties file should be present in the same folder with, for instance, the following content (for an English translation):
console.label = Remote Sample Server Configuration console.category = Samples console.help = This section is just a fake configuration sample for testing purposes. hostname = Host name hostname.help = The remote server name. port = Port Number ...
The OSGi service to be implemented to represent a section is based on the interface: com.arcadsoftware.rest.console.IRestConsoleSection
This service may also implement the interface com.arcadsoftware.rest.console.IActivableConsoleNode if this section may be disabled by the bundle at any time.
This service will generate the section Form, according to the client language, and will be called each time an action is executed.
Here is an example of a simple "hello world!" console section:
/**
* This class implement a "hello world" console section.
*
* @author ARCAD Software
*/
public class SampleConsoleSection implements IRestConsoleSection {
private final MultiLanguageMessages messages;
public SystemInfoConsoleSection() {
// This MultiLanguageMessages is optional but it will be used to
// translate the GUI message in the required client Language.
messages = new MultiLanguageMessages(
SampleConsoleSection.class.getPackage() + ".messages",
SampleConsoleSection.class.getClassLoader());
}
@Override
public String getId() {
// This is unique Section IDentifier.
return "sample";
// The SID will be used a URL fragment, it must be a
// single, simple, word.
}
@Override
public String getLabel(Language language) {
// The label is the user visible name of the section.
return messages.get("samplesection.label", language);
}
@Override
public String getCategory(Language language) {
// Define the section category.
return messages.get("samplesection.category", language);
// Note that categories names are translatable identifier.
}
@Override
public String getHelp(Language language) {
// this "help" message is a short description on the section.
return messages.get("samplesection.help",language);
}
@Override
public String getKeywords() {
// Keywords are options topic name which may be used to filter
//the console sections.
return null;
}
@Override
public int getOrder() {
// This value is used to sort the sections
return 66666;
}
@Override
public int getIcon() {
// This depend on the interface but each number is associated to a
// unique icon.
return 0;
}
@Override
public List<ConsoleField> getForm(Language language) {
// Build the content of the section...
final ArrayList<ConsoleField> form = new ArrayList<ConsoleField>();
// This section just print
form.add(new ConsoleText(messages.get("samplesection.helloworld_text", language)));
return form;
}
@Override
public List<ConsoleField> performAction(String actionId, Language language, Form params) {
// Even if this section does not declare any action in its form it may asume
// that a "save" action is sent from the client.
return null;
// Any way "null" response assume that the action is correctly performed without any
// more information.
}
}
This section must be registered as an OSGi service, for instance like this:
public class Activator extends AbstractActivator {
@Override
public void start(BundleContext bundleContext) throws Exception {
super.start(bundleContext);
registerService(IRestConsoleSection.class, new SampleConsoleSection());
}
}
Any section, declared in an consoles.xml file or with a java OSGi service, may be extended by new action, by implementing an OSGi service with the interface: com.arcadsoftware.rest.console.IConsoleActionService (use the abstract class AbstractConsoleActionService from the same package, this class offer a set of utility method to generate the action response). This service must be associated to a service property "com.arcadsoftware.console.sections" (use the constant IConsoleActionService.PROP_SECTIONIDS). The value of this property must be a list of section identifier (SID) separated by space characters.
An action registered this way will be automatically added to the corresponding sections.
/**
* This sample class declare a console action, which return a simple
* "Hello World!" message.
*
* @author ARCAD Software
*/
public class SampleConsoleAction extends AbstractConsoleActionService {
public SampleConsoleAction() {
// This will create a MultiLanguageMessages allowing to
// manage the response message according to the client Language.
super(SampleConsoleAction.class.getPackage().getName() + ".message",
SampleConsoleAction.class.getClassLoader());
// the properties file messages.properties is assumed to
// contain two properties "hello" and "hello.help" (using the code
// as identifier) which will be used to translate, respectively,
// the action label and description.
}
@Override
public String getCode() {
// This Action code must be unique in the forms where this action
// will be added.
return "hello";
// The Action code will be used a URL fragment, it must be a
// single, simple, word.
}
@SuppressWarnings("rawtypes")
@Override
public List<ConsoleField> run(String section, Language language,
Dictionary currentConf, Dictionary properties) {
// Perform the execution of the action...
return infoForm("hello_title", "hello_message", "", language);
// The inforForm method will use the messages.propreties file to get
// the correct translation of the response message and title.
}
}
This action must be registered as an OSGi service, for instance to extend the previous "sample" section:
public class Activator extends AbstractActivator {
@Override
public void start(BundleContext bundleContext) throws Exception {
super.start(bundleContext);
registerService(IConsoleActionService.class, new SampleConsoleAction(),
IConsoleActionService.PROP_SECTIONIDS, "sample");
}
}