Thursday Sep 26, 2013

How-To: Start a CMSDK Node in a custom application

With the removal of the DomainController concept in CMSDK 9.0.4.6, it is important to know that the CMSDK Node itself now manages the Service, Servers and possible failovers to another Node.

Recently I have encountered a number of customers that have never ran a CMSDK Node in the past. That is somehow worrisome, as a CMSDK Node plays a key role in the whole CMSDK architecture. Although CMSDK is an SDK, there are some required background processes running as Agents, Servers and Handlers. These Agents and Handlers are responsible for cleanup tasks, lifecycle management, and among others, the underlying event system.

The whole Node management in CMSDK 9.0.4.6 might be a blog topic of its own, but I would like to give at least an example of how to run a CMSDK Node within your own custom application, so you can take advantage of a real managed CMSDK environment.

This custom Node does not replace the CMSDK Node that you create when you deploy the cmsdk.ear file, which is mandatory. It furthermore extends the environment and helps your application to take advantage of the built-in Node management.

  1. First create a custom NodeConfiguration, as we don't want to run all servers and agents by default in our custom Node. This can be done by executing a script. An example can be found at $CMSDK_HOME/install/config/CreateNodeConfiguration.def.
    The minimum required agents needed to run inside any custom Node are:
    • EventHandlerAgent using IFS.SERVER.EventHandlerAgentConfiguration
    • StatisticsAgent using IFS.SERVER.StatisticsAgentConfiguration

    To only inherit those from the SuperNodeConfiguration you can insert the following line after line

    ; inherit all the servers

    m += addDefinitionStringArrayProperty  defTag  IFS.NODE.EnabledInheritedServerNames "{EventHandlerAgent, StatisticsAgent}"

    You should create your own .def that contains the custom NodeConfiguration. To execute that script run the
    following command:

    $CMSDK_HOME/bin/scriptrunner.sh CustomNodeConfiguration.def

  2. Make sure that your custom application contains a web.xml. This is required for the following instructions.
    If a web.xml is not possible to add, you need to follow different instructions. Let me know if this is the case and I will publish the other instructions as well (might be a rare case, though).

  3. Register a new Servlet Context Listener to your custom application, by adding the following entries to the web.xml. If listeners are already part of the web.xml make sure that the new one will be listed first.

    <listener>
      <description>Starts and Stops the Node in this JVM</description>
      <display-name>NodeManager</display-name>
      <listener-class>oracle.ifs.core.runtime.NodeManager</listener-class>
    </listener>

  4. The new Servlet Context Listener makes use of several configuration parameters that you need to specify in the web.xml as well. You can use the defaults for most of them, but should make sure that the corresponding param-values for

    • IFS.NODE.DataSourceName
    • IFS.NODE.Service
    • IFS.NODE.NodeConfigurationName
    • IFS.NODE.ServiceConfigurationName

    match your specific configuration.

    Add the following context-params to your web.xml:

    <context-param>
      <description>The name of the DataSource for the CMSDK repository</description>
      <param-name>IFS.NODE.DataSourceName</param-name>
      <param-value>jdbc/OracleDS</param-value>
    </context-param>

    <context-param>
      <description>The class name of CMSDK Node instance running in this JVM</description>
      <param-name>IFS.NODE.Class</param-name>
      <param-value>oracle.ifs.core.runtime.Node</param-value>
    </context-param>

    <context-param>
      <description>The unique name of CMSDK Node running in this JVM</description>
      <param-name>IFS.NODE.NodeName</param-name>
      <param-value>DefaultNode</param-value>
    </context-param>

    <context-param>
      <description>The name of the Service this Node is running with</description>
      <param-name>IFS.NODE.Service</param-name>
      <param-value>DefaultService</param-value>
    </context-param>

    <context-param>
      <description>The name of the node configuration for this CMSDK Node</description>
      <param-name>IFS.NODE.NodeConfigurationName</param-name>
      <param-value>IFS.NODE.DefaultNodeConfiguration</param-value>
    </context-param>

    <context-param>
      <description>The name of the service configuration the service is running with</description>
      <param-name>IFS.NODE.ServiceConfigurationName</param-name>
      <param-value>IFS.SERVICE.SmallServiceConfiguration</param-value>
    </context-param>

    <context-param>
      <description>Time in seconds the shutdown process should wait for the service to disappear.</description>
      <param-name>IFS.NODE.ShutdownWaitTime</param-name>
      <param-value>30</param-value>
    </context-param>

    <context-param>
      <!-- Options: OFF, SEVERE, WARNING, INFO (default), CONFIG, FINE, FINER, FINEST, ALL -->
      <description>The overall LogLevel of the Node.</description>
      <param-name>LogLevel</param-name>
      <param-value>INFO</param-value>
    </context-param>

    <context-param>
      <description>The filename of the logfile for this Node.</description>
      <param-name>LogFileName</param-name>
      <param-value>DefaultNode.log</param-value>
    </context-param>

    <!-- Optional, per default the logfile will be written to your runtime directory
    <context-param>
      <description>The absolute path of the logfile location for this Node.</description>
      <param-name>LogFilePath</param-name>
      <param-value>/tmp</param-value>
    </context-param>
    -->

    <context-param>
      <!-- Options: Defines the top level package name for logging  -->
      <description>The name of the root logger.</description>
      <param-name>RootLoggerName</param-name>
      <param-value>oracle.ifs</param-value>
    </context-param>

    <context-param>
      <!-- Options: text (default), xml -->
      <description>The format of the logfile for this Node.</description>
      <param-name>LogFileFormat</param-name>
      <param-value>text</param-value>
    </context-param>

    <context-param>
      <!-- Options: true, false (default) -->
      <description>Routes logging to console (stdout) AND to a logfile.</description>
      <param-name>LogToConsole</param-name>
      <param-value>false</param-value>
    </context-param>

    <context-param>
      <!-- Options: 5MB (default), 0 means no limit, other number in bytes -->
      <description>Defines the maximum size in bytes of a logfile before creating the next one.</description>
      <param-name>MaxLogFileSize</param-name>
      <param-value>5242880</param-value>
    </context-param>

    <context-param>
      <description>Defines the maximum number of logfiles to keep before overwriting the oldest one.</description>
      <param-name>MaxLogFileCount</param-name>
      <param-value>30</param-value>
    </context-param>

    <context-param>
      <!-- Options: 1d (default), 0 indicates no time based rotation
       Allowed values are a number followed by either D (days), H (hours), M (minutes) and S (seconds)
       If no postfix is specified the provided number is assumed to be in milliseconds.
       Examples are: 12H = 12 hours; 3D = 3 days; 35M = 35 minutes; 86400000 = 86,400,000 milliseconds
      -->
      <description>Defines the log period in milliseconds before rotating the logfile.</description>
      <param-name>LogFileRotationPeriod</param-name>
      <param-value>1d</param-value>
    </context-param>

    <context-param>
      <!--
       Syntax: oracle.ifs.examples : FINE, oracle.ifs.core.runtime.NodeManager : INFO
       The list of overrides should be seperated by a comma ','
       The override is defined as 'class/package : LogLevel'
      -->
      <description>Implements LogLevel overrides at class or package level</description>
      <param-name>LogLevelOverrides</param-name>
      <param-value></param-value>
    </context-param>

    NOTE: Each CMSDK should have a unique name. So make sure that the param-value for IFS.NODE.NodeName is different in each web.xml if you are planning to run a multi-Node environment.

  5. In your code you can now use the following way of connecting to CMSDK via a managed service:

    if(LibraryService.isServiceStarted(SERVICE_NAME))
    {
      service = LibraryService.findService(SERVICE_NAME);
    }
    else
    {
      // This should not be necessary, as the Node should have already started the Service by now.
      // Just in case he didn't, we can start a Service the old fashion way as unmanaged. The Node will
      // find it later and manage it from then on.
      service = LibraryService.startService(SERVICE_NAME, CMSDK_SCHEMA_PWD, SERVICE_CONFIG_NAME, DOMAIN_URL);
    }
    ...
    LibrarySession session = service.connect(credentials, null);
About

My name is Frank Closheim. I lead Development for CMSDK at Oracle and want to share the latest news, best practices, examples and product updates about CMSDK with the Blogsphere.

Search

Archives
« September 2013 »
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
27
28
29
30
     
       
Today