Custom Configuration  Locate

Overview  Locate

Service instances, service endpoints, interceptors, serializations, etc, all of which are specified by the deployment descriptor, form a default configuration, which is persistent. ( Please see Deployment Descriptors for more details.) What we are considering here are additional parameters to the configuration that you set yourself. The service may need such an extended configuration for its initialization. This part of the configuration is available via an extensible WSO2 SOA Enablement Server configuration framework that can be easily used by Web service developers for data persistence. Such a custom configuration may be either persistent or transient, set at runtime.

Persistent Configuration  Locate

Persistent configuration, as its name implies, is stored on the disk and is permanent until you change it (see Runtime Configuration for comparison). It is contained in the deployment descriptor and is available via an extensible WSO2 SOA Enablement Server configuration framework that can be easily used by Web service developers for data persistence.

For example, we have a service that uses JDBC to connect to relational databases and look up other services. You need to set the necessary properties to connect to particular databases and to look up other services. The deployment descriptor of such a package is shown in Example 37. Note the databaseConfiguration and serviceConfiguration elements of this deployment descriptor. (See also Extended Configuration.)

[Note]Note

Extended configuration elements must be in different namespaces than the package namespace. This is shown in Example 37 .

Example 37. Deployment Descriptor with Extended Configuration

<?xml version="1.0" encoding="UTF-8"?>
<package name="ConfigurableService"
    targetNamespace="http://wso2.com/package/example/basics/webservices"
    version="1.0"
    xmlns="http://wso2.com/wasp/package/1.2
    xmlns:ns0="http://wso2.com/wsdl/example/basics/webservices/"
    xmlns:tns="http://wso2.com/package/example/basics/webservices"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xsd:schemaLocation="http://wso2.com/wasp/package/1.2">
    <license>http://wso2.com</license>
    <location>http://wso2.com</location>
    <!-- ConfigurableService endpoint -->
    <service-endpoint name="ConfigurableService"
        path="/ConfigurableService/"
        processing="tns:ConfigurableService_processing"
        service-instance="tns:ConfigurableService_inst"
        type="java">
        <wsdl service="ns0:JavaService" uri="ConfigurableService.wsdl"/>
    </service-endpoint>
    <!-- ConfigurableService instance -->
    <service-instance name="ConfigurableService_inst"
        implementation-class="example.basics.webservices.ConfigurableService">
    <!-- ConfigurableService configuration -->
        <databaseConfiguration xmlns="http://my.org">
            <connection connectString="jdbc:mysql://venus/data"
                 driver="org.gjt.mm.mysql.Driver"
                 password="nothing"
                 user="nothing"
                 connectionCount="5"/>
            <connection connectString="jdbc:postgresql://mercury:5432/data"
               driver="org.postgresql.Driver"
               password="nothing"
               user="nothing"
               connectionCount="5"/>
        </databaseConfiguration>
        <serviceConfiguration xmlns="http://my.org>
            <service wsdlUrl="http://localhost:9093/BugzillaService/"
               lookup="true"/>
            <service wsdlUrl="http://localhost:9090/MessengerService/"
               lookup="false"/>
        </serviceConfiguration>
    </service-instance>
    <!-- ConfigurableService processing -->
    <processing name="ConfigurableService_processing"/>
</package>

The configuration framework is accessed via a static class, org.idoox.config.Configurator , and an interface, org.idoox.config.Configurable .

Configurator represents the entire WSO2 SOA Enablement Server configuration (including the configuration of all services) and generates proxy access to the config interfaces.

Configurable represents the configuration of a particular area (for example one service or part of such a service).

Configurator produces an instance of Configurable for a particular part of the configuration. To access the configuration from Configurable, it is necessary to create an interface that contains the bean-pattern getters/setters for the data you want to access, and then narrow the Configurable to your interface. After the narrowing, just call the appropriate methods to get/set/add/new the configuration.

Example 38 shows the interface that describes the data stored in the configuration section in the deployment descriptor in the previous example.

Example 38. MyServiceConfiguration Interface

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.basics.webservices;


/**
 * Whole service configuration
 */
public interface MyServiceConfiguration {
    /**
     * Getter and setter for DatabaseConfiguration
     */
    DatabaseConfiguration getDatabaseConfiguration();

    void setDatabaseConfiguration(DatabaseConfiguration configuration);

    /**
     * Creates new DatabaseConfiguration
     */
    DatabaseConfiguration newDatabaseConfiguration();

    /**
     * Getter and setter for ServiceConfiguration
     */
    ServiceConfiguration getServiceConfiguration();

    void setServiceConfiguration(ServiceConfiguration configuration);

    /**
     *  Interface for DatabaseConfiguration element
     */
    public interface DatabaseConfiguration {
        /**
         * Getter and setter for Connections
         */
        Connection[] getConnection();

        void setConnection(Connection[] connections);

        /**
         * Gets new Conntection
         */
        Connection newConnection();

        /**
         * Adds Conntection
         */
        void addConnection(Connection newConnection);

        /**
         * Interface for Connection element
         */
        public interface Connection {
            /**
             * Getter and setter for connectString attribute
             */
            String getConnectString();

            void setConnectString(String connect);

            /**
             * Getter and setter for driver attribute
             */
            String getDriver();

            void setDriver(String driver);

            /**
             * Getter and setter for password attribute
             */
            String getPassword();

            void setPassword(String password);

            /**
             * Getter and setter for user attribute
             */
            String getUser();

            void setUser(String user);

            /**
             * Getter and setter for connectionCount attribute
             */
            int getConnectionCount();

            void setConnectionCount(int count);
        }
    }

    /**
     * Interface for ServiceConfiguration element
     */
    public interface ServiceConfiguration {
        /**
         * Getter and setter for Services
         */
        Service[] getService();

        void setService(Service[] service);

        /**
         * Gets new Service
         */
        Service newService();

        /**
         * Adds Conntection
         */
        void addService(Service newService);

        /**
         * Interface for Service element
         */
        public interface Service {
            /**
             * Getter and setter for wsdlUrl attribute
             */
            String getWsdlUrl();

            void setWsdlUrl(String url);

            /**
             * Getter and setter for lookup attribute
             */
            boolean isLookup();

            void setLookup(boolean lookup);
        }
    }
}

For the service to get its configuration, it implements the interface org.systinet.wasp.webservice.Initializable. The org.idoox.config.Configurable of the configuration is obtained by using the getConfigurable() method of the ServiceInstance, which is accessible from the init(ServiceInstance) method.

Example 39 demonstrates this situation.

[Note]Note

Under the current WSO2 SOA Enablement Server implementation, it is not possible for two services to bind each other (or get each other's WSDL file) in both of their init(...).

Example 39. Configurable Service

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.basics.webservices;

import example.basics.webservices.MyServiceConfiguration;
import example.basics.webservices.MyServiceConfiguration.DatabaseConfiguration;
import example.basics.webservices.MyServiceConfiguration
       .DatabaseConfiguration.Connection;
import example.basics.webservices.MyServiceConfiguration.ServiceConfiguration;

import org.idoox.config.Configurable;

import org.systinet.wasp.webservice.Initializable;
import org.systinet.wasp.webservice.ServiceInstanceContext;


public class ConfigurableService implements Initializable {
    public void init(ServiceInstance serviceInstance) {
        // gets the service configurable
        Configurable configurable = serviceInstance.getConfigurable();

        // narrows configurable to MyServiceConfiguration interface
        MyServiceConfiguration cfg =
            (MyServiceConfiguration) 
            configurable.narrow(MyServiceConfiguration.class);

        if (cfg != null) {
            // gets database configuration
            DatabaseConfiguration databaseConfiguration =
                cfg.getDatabaseConfiguration();

            // gets connections
            Connection[] connections = databaseConfiguration.getConnection();

            // iterates elements of connections
            for (int i = 0; i < connections.length; i++) {
                Connection connection = connections[i];
                System.out.println(connection.getConnectString());
                System.out.println(connection.getDriver());

                // ....
            }

            // creates new connection and sets attribute
            Connection newConnection = databaseConfiguration.newConnection();
            newConnection.setConnectString("jdbc:mysql://sun");
            newConnection.setDriver("org.gjt.mm.mysql.Driver");
            newConnection.setConnectionCount(5);

            // ....
            // adds created connection
            databaseConfiguration.addConnection(newConnection);

            // gets service configuration
            ServiceConfiguration serviceConfiguration =
                cfg.getServiceConfiguration();

            // ...
        }
    }

    public void destroy() {
        // nothing
    }
}

The service's initial configuration is stored in the deployment descriptor. During the deployment process, this deployment descriptor is converted into the WSO2 SOA Enablement Server configuration file wasp.xml in the WASP-INF directory of the deployed service (WASP_HOME/app/ServiceName/WASP-INF). All changes to the configuration which are made by the configuration framework are reflected in this file.

To make the changes persistent, you do not have to write any extra code. WSO2 SOA Enablement Server is started with the ConfigStore module, which periodically flushes changes on configuration. The default period value is 2000ms and can be modified in the WASP_HOME/conf/serverconf.xml file. If you want to flush explicitly, call the flush() method of org.idoox.config.Configurator .

An instance of Configurator is obtained from the org.idoox.wasp.Context under the key Context.CONFIGURATOR (((Configurator)Context.getInstance(Context.CONFIGURATOR)).flush()).

Unique name Attribute  Locate

Configuration elements that contain the attribute name have to be unique throughout all WSO2 SOA Enablement Server configuration files. The reason for this requrement is that, if there are any custom configurations in package.xml files, our configuration framework iterates the whole tree of these custom configurations and searches for all elements containing the name attribute. All such elements are then stored internally in a hash map to be accessible to all packages, as a key generated from name_of_tag:value_of_name_attribute. Each hash map key must be unique, and thus every name_of_tag:value_of_name_attribute value pair must be unique.

This can lead to a problem if there is more than one custom configuration with the same element containing the same name attribute value, either in the same package or in different packages on the same WSO2 SOA Enablement Server. If a configuration element containing a name attribute of a given value, such as serializationConfiguration ... name="QuoteSerializing", is used for more than one configuration, java.lang.RuntimeException or java.lang.IllegalArgumentException is thrown.

There are several ways to avoid or work around this requirement. The simplest, and the one we recommend, is to not use name attributes in custom configuration elements. If you already have custom configuration elements with name attributes, you can rename all but one of the attributes to something like name2 or package-name. Lastly, adding the tag name of the repeated element or its ancestor into a new ignoredSection element of the configuration files clientconf.xml and serverconf.xml results in the element not being registered for duplicity checking. For example, if you have created a custom element named SerializationConfiguration, adding the following line into the configuration files prevents any element in the tree of SerializationConfiguration from being checked for duplicate name attributes:

<ignoredSection>SerializationConfiguration</ignoredSection>
[Caution]Caution

We do not recommend using the name attribute in custom configuration extensibility elements or their subelements.

Runtime Configuration  Locate

It is now possible to alter the configuration of a Web service transiently, that is, at runtime. This can be useful if you want to publish a Web service that requires configuration for proper initialization, but you want the configuration to revert afterward. It is also useful for overriding some of the properties of a configuration in runtime.

Runtime Configuration is conducted by creating an org.idoox.config.Configurable interface, as you would with persistent configuration. This interface is created by a special method of the static class org.idoox.config.Configurator , newRuntimeConfigurable(). A runtime Configurable is used the same way as a Configurable for a persistent configuration, as shown in Example 40 .

Example 40. Runtime Configuration

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.basics.webservices;

import example.basics.webservices.MyServiceConfiguration.
       DatabaseConfiguration.Connection;

import org.idoox.config.Configurable;
import org.idoox.config.Configurator;

import org.systinet.wasp.Wasp;
import org.systinet.wasp.webservice.Registry;
import org.systinet.wasp.webservice.ServiceEndpoint;
import org.systinet.wasp.webservice.ServiceInstance;

import java.util.HashMap;


public class RuntimeConfiguration {
    public static final void main(String[] args) throws Exception {
        HashMap properties = new HashMap();
        properties.put("wasp.location",
            "PUT HERE LOCATION OF WASP e.g. c:\\wasp");
        Wasp.init(properties);
        Wasp.startServer("http://localhost:6060");
        System.out.println("Server started");

        // creates new instance of ConfigurableService
        ConfigurableService service = new ConfigurableService();

        // creates new empty runtime configuration
        Configurable runtimeConfiguration =
            Configurator.newRuntimeConfigurable();

        // narrows configurable to MyServiceConfiguration interface
        MyServiceConfiguration myConfiguration =
            (MyServiceConfiguration) runtimeConfiguration.narrow(
            MyServiceConfiguration.class);

        // creates new DatabaseConfiguration
        MyServiceConfiguration.DatabaseConfiguration database =
            myConfiguration.newDatabaseConfiguration();

        // creates new connection
        Connection connection = database.newConnection();

        // setup connection
        connection.setConnectString("jdbc:mysql://venus/data");
        connection.setDriver("org.gjt.mm.mysql.Driver");
        connection.setPassword("nothing");
        connection.setConnectionCount(5);

        // sets connection to the DatabaseConfiguration
        database.setConnection(new Connection[] { connection });

        // sets DatabaseConfiguration to the runtime configuration
        myConfiguration.setDatabaseConfiguration(database);
        System.out.println("Configuration created");

        ServiceInstance serviceInstance = ServiceInstance.create(service);
        serviceInstance.setConfigurable(runtimeConfiguration);

        // now service is properly initialized and we can publish it
        Registry.publish(
            ServiceEndpoint.create("/myService/", serviceInstance));
        System.out.println("Service published");

        // let service live 3 seconds
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
        }

        // destroy server
        Wasp.destroy();
        System.out.println("Done.");
    }
}
InfoPath in Runtime Configuration  Locate

In order to use Microsoft's InfoPath with WSO2 SOA Enablement Server for Java, it is necessary to unset SSJ's namespace optimization flag. For a WSO2 SOA Enablement Server embedded in an application, this can be done by configuring the service binding, normally hidden from users. The necessary code to add to the interface is shown in Example 41.

Example 41. Runtime Configuration for Using InfoPath

import com.idoox.wasp.server.config.ServiceBindingConfig;
 ...
                    
 ServiceEndpointImpl serviceEndpoint =... 
 ...
 // Create new runtime configuration
 Configurable configurable = Configurator.newRuntimeConfigurable();
 
 // Set up Service Binding Configuration
 ServiceBindingConfig conf =
 (ServiceBindingConfig)configurable.narrow(ServiceBindingConfig.class);
 conf.setNamespaceOptimization(Boolean.FALSE);
                    
 // Set prepared configuration to the endpoint
 serviceEndpoint.setServiceBindingConfig(conf);

It is also possible to turn off namespace optimization persistently for a service in a standalone WSO2 SOA Enablement Server. Please see Using InfoPath on a Standalone WSO2 SOA Enablement Server.

To turn off namespace optimization globally for all services and clients on an instance of WSO2 SOA Enablement Server, set the wasp.soap.caching property to false, as described in WSO2 SOA Enablement Server Configuration.