You may want to add some flexibility to your application by changing a property without needing to recompile the code or restarting the server. This way you can distribute the same WAR file of your web application to different places. You can think at the following situations:
A file location may differ on the computers on which you want to deploy your application.
The location of a database may differ depending on whether you want to test your application or deploy it in a production environment.
A username/password which you don't know the value and should be entered by the administrator.
A link to another XINS service, in case of a distributed environment.
You would like to adjust settings that influence performances.
You would like to adjust the debugging level.
The properties for your APIs are defined in the runtime properties
file often named xins.properties
. This file location
is passed to the application server with the system property
org.xins.server.config
.
To start the WAR file using the XINS servlet container, just execute
xins -Dorg.xins.server.config=xins.properties
run-myproject. You can also set the location of the
xins.properties
in the
build.properties
and then execute xins
run-myproject.
If you want to run the example in tomcat, you need to add in the
file tomcat\conf\catalina.properties
the line
org.xins.server.config=c:\\Program\
Files\\xins\\demo\\xins.properties
.
Example of runtime properties file:
#_____________________________________________________________________________ # General XINS properties # Check configuration file every 60 seconds org.xins.server.config.reload=60 # Access rules org.xins.server.acl=allow 127.0.0.1 *; # Logging properties org.xins.logdoc.locale=en_US
An example is also provided in the
demo\xins.properties
file.
It's also possible to define a different runtime property file for each API you are running on the servlet container. To define a specific runtime property file for an API, use org.xins.server.config.<api name> instead of org.xins.server.config.
Some properties defined in this file are already interpreted by the system:
Table 2. xins.properties runtime properties
Property name | Required | Description | Example |
org.xins.server.config.reload | no, defaults to 60. | Interval in seconds for check the xins.properties file for any changes. | org.xins.server.config.reload=60 |
org.xins.server.acl | no, defaults to localhost. | Access rules for the functions | org.xins.server.acl=allow 127.0.0.1 *; \ allow 192.168.0.0/24 MyFunction |
org.xins.server.acl.<api name> | no | Access rules for the functions of the specified API. The specified rules are executed before the generic one. | org.xins.server.acl.myproject=allow 127.0.0.1 *; \ deny 192.168.0.0/24 MyFunction |
org.xins.server.config.include | no | A comma separated list of runtime property files to include. The files should use relative paths. | org.xins.server.config.include=../default-xins.properties |
org.xins.logdoc.locale | no, defaults to en_US. | The locale to be used for the logging messages. | org.xins.logdoc.locale=en_US |
org.xins.server.jmx | no, false by default. | Enables the management of the API using JMX (Java Management eXtension). | org.xins.server.jmx=true |
org.xins.server.contextID.filter | no, all types of context ID are accepted by default. | The regular expression pattern for the expected format of the context ID. If the context ID is invalid, a new one will be generated. | org.xins.server.contextID.filter=[a-zA-Z]{5} |
org.xins.server.logging.init | no, true by default | Initialize the logdoc logging | org.xins.server.logging.init=false |
org.xins.server.contextID.push | no, true by default | Push the contextID to the NDC | org.xins.server.contextID.push=false |
org.xins.logdoc.stackTraceAtMessageLevel | no, defaults to false meaning that the stack traces are logged at DEBUG level. | Flag indicating that the exception stack trace should be logged at the same level as the message. | org.xins.logdoc.stackTraceAtMessageLevel=true |
log4j.* | no, defaults to console. | Logging properties used to adapt the debug level, formatting or output to your needs. | log4j.rootLogger=DEBUG, console |
log4j.<api name>.rootLogger | no, defaults to log4j.rootLogger. | Root logger for the specified API. | log4j.myproject.rootLogger=INFO, logfile_myproject |
Now we will adapt the xins.properties
for the
MyFunction
implementation by adding the following
lines:
# Salutation message for the person salutation=Hello
We now need to change the implementation to read and use the
property. Note that the property should be able to be changed at
runtime. Add the following code to
MyFunctionImpl.java
import org.xins.common.collections.MissingRequiredPropertyException; import org.xins.common.collections.InvalidPropertyValueException; import org.xins.common.manageable.BootstrapException; import org.xins.common.manageable.InitializationException; ... /** * The salutation message. */ private String _salutation; protected void initImpl(Map<String, String> properties) throws MissingRequiredPropertyException, InvalidPropertyValueException, InitializationException { // Get the salutation _salutation = properties.get("salutation"); if (_salutation == null || _salutation.trim().equals("")) { throw new MissingRequiredPropertyException("salutation"); } // Here you can also chack the value and throw an // InvalidPropertyValueException if needed } public final Result call(Request request) throws Throwable { ... result.setMessage(_salutation + " " + nomination + " " + request.getPersonLastName()); return result; }
Now recompile your code, restart the server, execute the function,
change the value in xins.properties
to Hi, wait for
the server to reload the properties file and execute the function
again.
The API class defines a deinitImpl()
method. This method is used to release resources when you stop the
API.
When the xins.properties file has changed, only the
initImpl()
method is invoked. The
deinitImpl()
is called only when you stop
the servlet container.
The API class has a bootstrapImpl2(Map<String,
String> buildSettings)
method that is called the API is
started. The buildSettings passed as parameters are the properties
stored in the web.xml
file included in the
deployment war file.
The API class has a reinitializeImpl()
method. This method can be invoked in your implementation to ask the
framework to reinitialize the API.
XINS 1.3.0 includes a new system that allows to define runtime
properties that you will use in your API in the
impl.xml
file. In this file you define the name of
the property, its description, its type and whether is property is
required or optional. The value of the property still needs to be
defined in the xins.properties
file.
Example:
<impl> <runtime-properties> <property name="myproject.eurodollar.rate" type="_float32" required="true"> <description>The price in dollars of 1 euro.</description> </property> </runtime-properties> </impl>
Now when the specification documentation is generated, a new page is available containing the list of the runtimes properties used by the API along with their description, their type and whether the property is required or optional. This page makes it easier to deploy an API with the correct runtime properties set.
Another advantage of defining the properties this way is that you
don't need to implement the initImpl
method to
retreive the property values. A class is generated that checks and
retreives the properties. If the value of a property is incorrect or a
required property is missing then the API will fail with a description
of the problem. The getAPI().getProperties()
method can also be called from the initImpl
method of your function, if you want for example initialize another
object based on a runtime property.
Example on how to use the generated class:
// No imports needed, no initImpl method needed public final Result call(Request request) throws Throwable { SuccessfulResult result = new SuccessfulResult(); result.setPriceInEuro(request.getPriceInDollar() / ((RuntimeProperties) getAPI().getProperties()).getMyprojectEurodollarRate()); return result; }
If the property was optional, a
java.lang.Float
object would have been
returned.