Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 

Applies To: Jdk 1.5 and onwards, CE 7.3/7.4

Author(s):      Biplab Ray

Company:      Tata Consultancy Services

Created on:    20th February 2015

Author Bio:

Biplab Ray is working for Tata Consultancy Services as an Assistant Consultant and development of SAP EP, composite applications using CAF, BPM, BRM, WebDynpro for Java. He also works in technologies like Java/J2EE and has depth understanding on eSOA, Webservice, Enterprise Service, XML.


Requirement:

  1. In normal j2ee, if we want to modify the any value of property file then we have to touch the file and build the application and deploy and then only the new value would take effect.
  2. To solve the issue SAP introduce new concept of sap.application.global.properties file is that, without touching the code we could modify values via NWA and the changes would take effect without restart the server.
  3. To read the file we have to do a j2ee project.

Implementation:

  1. Create a J2EE project including ejb and ear module.
  2. Create one Ejb via which application would read the keys of the property file and return value.
  3. Create one normal java class which should implement the ApplicationPropertiesChangeListener.
  4. Add one DC: tc/je/appconfiguration/api under Software Component: ENGFACADE to ejb module of the J2EE project.
  5. Create a file named “sap.application.global.properties” under META-INF folder of EAR module of J2EE project.


Few words about the property file:

Description:  Descriptions can be short or long. They are used by adding a prefix (## for short and # for long) and the description itself, in a line within the property file.

Meta-flags : Some meta-flags like meta-flags for specifying a property as secure, onlinemodifiable, parameterized, computed, propertylinked and final, are used by adding a prefix #? and the flag name-value pair, in a line within the sap.application.global.properties file, e.g:, #? onlinemodifiable = true. A property with a meta-flag onlinemodifiable = true means that property can be modified by NWA. If a property has a meta-flag onlinemodifiable = false then it cannot be modified by NWA.

Other meta-flags like meta-flags for specifying the type, range and visibility of a property are used by adding a prefix #% and the flag name-value pair, in a line within the property file e.g : #% type = STRING. This means the data type of the property would be interpreted as a string.

Below is one example of the entry of key-value pair in the property file.

## Test Information

#? onlinemodifiable = true

#% type = STRING

key-test = Test Information

Note: At the time of entry each set of above data into property file please make sure enter should be pressed.

We have to modify the application-j2ee.xml under META-INF folder of ear module of j2ee project.

We have to enter below xml tag to add a hard reference.

<reference reference-type=”hard”>

<reference-target target-type=”service”>tc~je~appconfiguration~app</reference-target>

</reference>

Now we have to implement the below java class.

ApplicationPropertiesHandler

package com.example;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import javax.naming.Context;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import com.sap.engine.services.configuration.appconfiguration.ApplicationPropertiesAccess;

import com.sap.engine.services.configuration.appconfiguration.ApplicationPropertiesChangeListener;

import com.sap.tc.logging.Location;

/**

* @author Biplab Ray

*

*/

public class ApplicationPropertiesHandler implements ApplicationPropertiesChangeListener{

      /**

        * The logging/tracing <code>Location</code>.

        */

        private static final Location location = Location.getLocation(ApplicationPropertiesHandler.class);

               

        /**

         * JNDI name of the configuration service.

         */

        private static final String JNDI_NAME_APPLICATION_CONFIGURATION = "ApplicationConfiguration";

       

        /**

         * The singleton instance.

         */

        private static ApplicationPropertiesHandler singleton = null;

       

        /**

         * The application properties.

         */

        private Properties properties = null;   

       

        private Map indexedProperties = null;   

       

       

        /**

         * Static initializer --> no synchronisation necessary on getInstance()

         */

        static

        {

            singleton = getInstance();

        }

        /**

         * Returns the one and only <code>ApplicationPropertiesHandler</code> instance.

         *

         * @return The singleton instance

         */

        public static ApplicationPropertiesHandler getInstance()

        {   

            if (singleton == null)

            {

                singleton = new ApplicationPropertiesHandler();

            }

            return singleton;

        }

        /**

         * Private constructor

         */

        private ApplicationPropertiesHandler()

        {

            this.registerListener();

            this.loadProperties();

        }

       

        /**

         * Returns a String representation of the property value

         * for the passed in property key.

         * An IllegalArgumentException is thrown in case a null argument is passed in

         * or in case that a property key is configured without a corresponding property value.

         *

         * @Param aPropertyKey - The property key

         * @return The String representation of the property value

         * @throws IllegalArgumentException - In case of an error

         */

        public String getStringValue(String aPropertyKey)

        {

            String METHOD = "getStringValue()";

           

            if(location.bePath())

            {  

                location.entering(METHOD, new Object[] { aPropertyKey });

            }

           

            checkMethodParameter(aPropertyKey);

           

            String retVal = null;

            retVal = this.properties.getProperty(aPropertyKey);

            this.checkPropertyValueForNull(retVal);

           

            if( location.bePath() )

            {

                location.exiting( METHOD, retVal );

            }

           

            return retVal;       

        }

        /**

         * Retrieves the properties from the JNDI.

         *

         */

        final private void loadProperties() 

        {

            String METHOD = "loadProperties()";

           

            if(location.bePath())

            {  

                location.entering(METHOD, new Object[]{});

            }

           

            Context ctx = null;

            try

            {   

                ctx = new InitialContext();

                ApplicationPropertiesAccess cfgFactory = (ApplicationPropertiesAccess) ctx.lookup(JNDI_NAME_APPLICATION_CONFIGURATION);

                this.properties = cfgFactory.getApplicationProperties();

                loadIndexedProperties();

            }

            catch (NamingException ne)

            {

                String message = "a JNDI naming problem occured while loading the application properties";

                location.errorT(message);

                throw new RuntimeException(message, ne);

            }

            if(location.bePath())

            {

                location.exiting(METHOD, null);

            }

         }   

        /**

         * Registers a listener for the application properties.

         *

         */

        final private void registerListener()  

        {

            String METHOD = "registerListener()";

           

            if(location.bePath())

            {  

                location.entering(METHOD, new Object[]{});

            }

           

            Context ctx = null;

            try

            {   

                ctx = new InitialContext();

                ApplicationPropertiesAccess cfgFactory = (ApplicationPropertiesAccess) ctx.lookup(JNDI_NAME_APPLICATION_CONFIGURATION);

                cfgFactory.addApplicationPropertiesChangedListener(this);

            }

            catch (NamingException ne)

            {

                String message = "a JNDI naming problem occured while registering a listener for the application properties";

                location.errorT(message);

                throw new RuntimeException(message, ne);

            }

           

            if(location.bePath())

            {

                location.exiting(METHOD, null);

            }

         }

       

        /*

         * @see com.sap.engine.services.configuration.appconfiguration.ApplicationPropertiesChangeListener#propertiesChanged()

         */

        public void propertiesChanged()

        {

            String METHOD = "propertiesChanged()";

           

            if(location.bePath())

            {  

                location.entering( METHOD, new Object[]{} );

            }

            this.loadProperties();

           

            if(location.bePath())

            {

                location.exiting( METHOD, null );

            }

        }

       

        /**

         * Checks if a passed in parameter is valid, i.e. is not null

         * and has a size > 0.<br>

         * In case the passed in parameter is not valid is an <code>IllegalArgumentException</code> thrown

         * with a corresponding message.

         *

         * @Param aParameter

         */

        private void checkMethodParameter(String aParameter)

        {

            String METHOD = "checkMethodParameter()";

           

            if(location.bePath())

            {  

                location.entering(METHOD, new Object[] { aParameter });

            }

           

            if (aParameter == null)

            {

                String message = "the passed in parameter is null";

                location.errorT(message);

                throw new IllegalArgumentException(message);

            }

            if(aParameter.length() == 0)

            {

                String message = "the passed in parameter has the lengh 0";

                location.errorT(message);

                throw new IllegalArgumentException(message);

            }

            if(location.bePath())

            {

                location.exiting( METHOD, null );

            }

        }

        /**

         * Verifies that the property value is not null, i.e.

         * verifies if there is a property value configured for the

         * passed in property key.<br>

         * In case the property value is null is an <code>IllegalArgumentException</code> thrown.

         *

         * @Param aParameter

         */

        private void checkPropertyValueForNull(String aParameter)

        {

            String METHOD = "checkPropertyValue()";

            if(location.bePath())

            {  

                location.entering(METHOD, new Object[] { aParameter });

            }

           

            if (aParameter == null)

            {

                String message = "there is no message configured for the property key";

                location.errorT(message);

                throw new IllegalArgumentException(message);                                

            }

           

            if(location.bePath())

            {

                location.exiting(METHOD, null);

            }           

        }

       

        /**

         * Retrieves indexed properties from previously loaded plain properties.

         *

         */

        private void loadIndexedProperties(){

            String METHOD = "loadIndexedProperties()";

           

            if(location.bePath())

            {  

                location.entering(METHOD, new Object[]{});

            }

           

            this.indexedProperties = new HashMap();

           

    

            // check for keys that end with a . followed by one or more digits

            String regex = ".*\\.\\d+";

           

            for (Iterator iter = this.properties.keySet().iterator(); iter.hasNext();)

            {

                String key = (String) iter.next();

                String value = getStringValue(key);

                String[] split = value.split(",");

                if (split.length > 1)          

                {

                    List values = (List) this.indexedProperties.get(key);

                    if (values == null)

                    {

                        values = new ArrayList();

                        for (int i = 0; i < split.length; i++)

                        {

                            values.add(split[i]);

                        }

                        this.indexedProperties.put(key, values);

                    }

                }

            }

           

        }

}

Create one EJB under the same package com.example and write the business method as below.

public String getTheValueOfProperty(String stringKeyOfProperty) {

             

                  return ApplicationPropertiesHandler.getInstance().getStringValue(stringKeyOfProperty);

      }

And expose the ejb as webservice and test via ws navigator.

And if you want to modify the value , then please go to the NWA and then configuration management -> infrastructure -> java system properties then select the instance of the server and under the application tab search the project name and in the below table it would display the name of the application ear.

Select the ear and one more table would show the name –value pair which was entered into the property file. Now if any one want to set any custom value then have to set value into the custom value field this feature only applicable those was set as onlinemodifiable as true only.

5 Comments
Labels in this area