Normally we have been reading the property files ourselves or used spring property-holder feature or even cm-properties. In all these cases update to the property file are not visible.
You can now use the managed-properties under Configuration Admin and have the values updated in your bean automatically whenever you change the property file. You just drop a property file inside pickup directory and under the bean definition specify the persistent-id as follows:
// Have a property file with name myPropertyFile
<osgix:cm-properties id="config" persistent-id="myPropertyFile"/>
//declare a property place holder config with id of osgi:cm
<context:property-placeholder properties-ref="config"/>
//bean definition using teh property file
<bean id="configTest" class="com.test.ConfigTest">
<osgix:managed-properties persistent-id="myPropertyFile" update-strategy="container-managed" /> <property name="propertyValue" value="${propertyValue}"></property>
</bean>
Now first add the property file to the pick up folder and start the DM server. The setPropertyValue() setter will be called and the value will be initialized when application bundle is dropped.
[There are multiple calls to this setter because of the osgi configuration admin]
Now when the property file in changed in the pickup directory , the setter method will be called and new value will be set into the bean.
Incase you want to manage the updates yourself you can change the update-strategy and provide the update-method in the bean. In this case all the key/values are provided to the method in form of a Map.
<bean id="configTest" class="com.test.ConfigTest">
<osgix:managed-properties persistent-id="myPropertyFile"
update-strategy="bean-managed" update-method="refresh" />
<property name="propertyValue" value="${propertyValue}"></property>
</bean>
The ConfigTest class is as follows
public class ConfigTest {
private int propertyValue;
public void setPropertyValue(int propertyValue) {
System.out.println("setter called for property"+propertyValue);
this.propertyValue = propertyValue;
}
public void refresh(Map <String,String> keyVals)
{
System.out.println("referhs called with value"+keyVals);
}
}
PS:
Do not share the same persistent-id (PID) between multiple bundles or definitions, as only one of them will receive notifications. managed-properties relies on org.osgi.service.cm.ManagedService contract which mandates that each ManagedService instance must be identified with its own unique PID.
Hence the best option in a service model is to have a configuration service reading the property file and giving notifications to required bundles.
Saturday, December 12, 2009
OSGi -Spring - Configuration Admin - Dynamic Property file changes
Sunday, November 15, 2009
Configuring Component based logging in OSGi using Log4j
Initialize reading of the log4j xml in any of the core bundles. Ensure that this bundle doesnt get bounced often.Configure the values to include log4j xml and reload delay.The init method can look something similar to the one below.
public void initialize() {
try {
try {
String logConfig = "D://temp//poc_log_config.xml";
long configReloadDelay = (long) (1 * 30 * 1000);
if (logConfig != null && (new java.io.File(logConfig).exists())) {
if (logConfig.endsWith("xml")) {
org.apache.log4j.xml.DOMConfigurator.configureAndWatch(
logConfig, configReloadDelay);
} else {
org.apache.log4j.PropertyConfigurator
.configureAndWatch(logConfig, configReloadDelay);
}
} else {
org.apache.log4j.BasicConfigurator.configure();
}
} catch (Exception initErr) {
initErr.printStackTrace();
}
} catch (Exception err) {
}
}
The log4j xml will look as follows
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="PRODUCT1" class="com.test.anyappender">
<param name="File" value="D:\\temp\\product1\\product1log.log"/>
<param name="MaxFileSize" value="100000000"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} - %m%n"/>
</layout>
<param name="Threshold" value="DEBUG"/>
</appender>
<appender name="PRODUCT2" class="com.test.anyAppender">
<param name="File" value="D:\\temp\\product2\\product2.log"/>
<param name="MaxFileSize" value="100000000"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} - %m%n"/>
</layout>
<param name="Threshold" value="DEBUG"/>
</appender>
<root>
<level value="OFF" />
</root>
<logger name="test1">
<appender-ref ref="PRODUCT1"/>
<level value="INFO" />
</logger>
<logger name="test2">
<appender-ref ref="PRODUCT2"/>
<level value="DEBUG" />
</logger>
</log4j:configuration>
Now in any bundle code you can access any component logger as follows
static final Logger TEST_LOGGER = Logger.getLogger("test1");
use TEST_LOGGER.debug("any debug message");
By the above approach we can just have a single log4j bundle in the repository and not only avoid issues occuring from static variables but also can take full benefit of log4j API's.
Thursday, March 5, 2009
Log4j Slf4j issues in Spring Dm
If you try to use log4j in any application under Spring DM we may get some ClassNotFound exceptions . The issue could be the following
com.springsource.slf4j.org.apache.log4j-1.5.6.jar - is present in
springsource-dm-server-ee-1.0.2.RELEASE\repository\bundles\ext directory and it shares a package org.apache.log4j
Now when you put your log4j jar into repository\bundles\usr - it also shares the same package
org.apache.log4j .
Hence one in the repository is resolved first . So all requests to classes in the log4j jar within package org/apache/log4j will give ClassNotFound Exceptions as it looks for these classes in slf4j jar .
The easiest way i resolved this was by deleting com.springsource.slf4j.org.apache.log4j-1.5.6.ja from the repository . This change did not affect any logging of the spring Dm server.
Another way to solve this is
Import-Package: org.apache.log4j;bundle-symbolic-name="com.springsource.org.apache.log4j"
http://forum.springsource.org/showthread.php?t=73354
Log4j/Struts Behaviour in OSGi
Log4j/Struts behaves weird if the these jar are put under repository, because this single static instance inside these jars are shared by all other bundles.
Example: Struts(struts properties),log4j(log4/properties)
All the properties are written into static members.Since the single instance is shared by both the bundles applications, the value of static references will be overridden and both the application will use the same settings.
This case is not specific to spring Dm , it will also occur when common configuration object
is put under common lib in tomcat.
Example: log4j/struts jar in tomcat common lib
Friday, August 1, 2008
Simplest way to Configure Logging using Log4j
Ensure the log4j.jar & log4j.properties are in the classpath
Add the following into the required classes where logging is needed , so that log shows file name for each logger statement .
private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger([classname].class);
folowed by logger.[info,debug,error,fatal etc]("logger message");
Contents in Log 4j.properties
log4j.rootLogger=ON, ROOT[enabling the root logger]
log4j.appender.ROOT=org.apache.log4j.DailyRollingFileAppender[saving logs on the daily basis with date appended]
log4j.appender.ROOT.File=/a/b/c.log[root log file path]
log4j.appender.ROOT.layout=org.apache.log4j.PatternLayout
log4j.appender.ROOT.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss } %-5p [%t] %c{2} - %m%n [pattern for display in each line]
#FILE APPENDER [another logger file ]
log4j.appender.F2=org.apache.log4j.DailyRollingFileAppender
log4j.appender.F2.File=/a/b/d.log
log4j.appender.F2.layout=org.apache.log4j.PatternLayout
log4j.appender.F2.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss } %-5p [%t] %c{2} - %m%n
log4j.logger.org.apache=ERROR[apache specific errors to be shown on both logger files]
log4j.logger.com.example=DEBUG,F2[for com.example modules debug status messages to be shown in second logger file]
For Log4j debugging
Append -Dlog4j.debug in JAVA_OPTS in catalina.sh which will enable detailed logs in catalina.out showing the logger configerations.
Wednesday, July 23, 2008
Adding Logger interceptor in Struts
When i had a requirement to add user name and session id to every logger statement for debugging purposes i did not think it would be so easy. I came across sites which suggested adding some extra modules and configurations into the log4j.
But i realized there was a much simpler way which was to modify the thread name appending application specific user name and session id into it. As anyways log4j will print the thread name at every logger statement . Thus with minimal changes my cause was served. I added this functionality into every request by making it as a interceptor and adding it into the basic stack.
I have attached the interceptor code for reference.
Tasks get easy when seen for different perspectives.
.jpg)