Saturday, March 31, 2012

Confluence 3.x and com.atlassian.confluence.content.render.xhtml

com.atlassian.confluence.content.render.xhtml is a package from Confluence 4, responsible for rendering new XHTML macro. If you compile your plugin for Confluence 4 and your plugin has <xhtml-macro/>, then you will get an import of com.atlassian.confluence.content.render.xhtml in your MANIFEST.MF. Something like this:

com.atlassian.confluence.content.render.xhtml;version="0.0"

So far, so good. But what happens, if you try to install your plugin in confluence 3.x?


org.osgi.framework.BundleException: Unresolved constraint in bundle com.skype.confluence.skype-bth [72]: Unable to resolve 72.0: missing requirement [72.0] package; (&(package=com.atlassian.confluence.content.render.xhtml)(version>=0.0.0))


The reason is obvious, com.atlassian.confluence.content.render.xhtml is missing in confluence 3.x, but we are asking for it. Even though, we are not going to use it. We might have separate <macro/> definition, that does not need XHTML.

Solution is to tell Felix, that com.atlassian.confluence.content.render.xhtml is optional:

<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-confluence-plugin</artifactId>
<version>3.8</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
com.atlassian.confluence.content.render.xhtml;resolution:=optional;version="0.0.0",
*;version="0.0"
</Import-Package>
</instructions>
</configuration>
</plugin>
view raw pom.xml hosted with ❤ by GitHub


Friday, March 30, 2012

JNDI datasource in confluence plugin

It appears, that Confluence dev documentation completely lacks information, regarding accessing third party databases.

The only example I could find is the source of SQL Plugin. However, it seemed to be too low level and I would prefer to use Spring to handle it. Here comes my solution:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd"
default-autowire="autodetect">
<jee:jndi-lookup
id="bthDatasource"
jndi-name="java:comp/env/jdbc/bthDatasource"
proxy-interface="javax.sql.DataSource"
lookup-on-startup="false" />
<bean id="bthJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="bthDatasource"/>
</bean>
</beans>
view raw bean.xml hosted with ❤ by GitHub


You can see here, that I'm using lazy look up with proxy interface. I had to do it, because otherwise look up happens when plugin is installed or activated and for some reason, JNDI datasource that I defined was not visible to that thread.

Unfortunately, OSGI bundle makes it a bit tricky, as some required classes will be missing and you have to instruct Felix to import them:

<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-confluence-plugin</artifactId>
<version>3.8</version>
<extensions>true</extensions>
<configuration>
<productVersion>${confluence.version}</productVersion>
<productDataVersion>${confluence.data.version}</productDataVersion>
<instructions>
<Import-Package>
org.springframework.aop;version="0.0.0",
org.springframework.aop.framework;version="0.0.0",
org.aopalliance.aop;version="1.0",
javax.sql;version="0.0.0",
*;version="0.0"
</Import-Package>
</instructions>
</configuration>
</plugin>
view raw pom.xml hosted with ❤ by GitHub

Wednesday, February 29, 2012

Populating Oracle v$session in Spring web app

Our project heavily relies on Oracle PL/SQL procedures. Those procedures are used by different applications and database developers always wanted to know two things:

1) Which application is calling the procedure
2) Who is currently logged into the application

After investigating the topic a bit, I've found OracleConnection.setEndToEndMetrics method in oracle JDBC driver. Using this method, you can populate some fields in v$session view, including v$session.client_identifier and v$session.module. In our case, logged in user goes to client_identifier and calling application to module.

There are already some samples of setting client identifier using this method, but I found most of them incomplete. Here comes another one:

package my.package;
import static oracle.jdbc.OracleConnection.END_TO_END_CLIENTID_INDEX;
import static oracle.jdbc.OracleConnection.END_TO_END_MODULE_INDEX;
import static oracle.jdbc.OracleConnection.END_TO_END_STATE_INDEX_MAX;
import static org.springframework.util.StringUtils.hasText;
import oracle.jdbc.OracleConnection;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.SQLException;
@Aspect
@Component
public class OracleConnectionMetricsSettingAspect {
private static final String APPLICATION_NAME = "MY_APP";
private SecurityContext securityContext;
@AfterReturning(
pointcut = "execution(* javax.sql.DataSource.getConnection(..))",
returning = "connection")
public void setMetrics(Connection connection) throws SQLException {
Connection metaDataConnection = connection.getMetaData().getConnection();
if (!(metaDataConnection instanceof OracleConnection)) {
return;
}
String[] metrics = new String[END_TO_END_STATE_INDEX_MAX];
if (hasText(getLoggedInUser())) {
metrics[END_TO_END_CLIENTID_INDEX] = getLoggedInUser();
}
metrics[END_TO_END_MODULE_INDEX] = APPLICATION_NAME;
((OracleConnection) metaDataConnection).setEndToEndMetrics(metrics, (short) 0);
}
private String getLoggedInUser() {
Authentication authentication = securityContext.getAuthentication();
if (authentication == null) {
return null;
}
return authentication.getName();
}
@Autowired
public void setSecurityContext(SecurityContext securityContext) {
this.securityContext = securityContext;
}
}


You can see here, that we are using AOP to intercept javax.sql.DataSource.getConnection() methods and populate all connections with logged in user from Spring security SecurityContext. Module is just a constant.

Tuesday, December 20, 2011

Are static fields initialized before constructor is called?

I've encountered this while debugging one very strange issue in third party library. Decompiled code made this case even more interesting and not so obvious.

How do you think, what is the output for following program?

public class AreStaticFieldsInitializedBeforeConstructorIsCalled {
public static void main(String[] args) {
new A();
}
}
class A {
static A a = new A();
static String staticField = "1";
static final String CONSTANT = "2";
public A() {
System.out.println(staticField);
System.out.println(CONSTANT);
}
}


Output is:

null
2
1
2

Constructor is called before "staticField" is initialized.