Tuesday, March 31, 2009

Weblogic and Oracle RAC

The suggested solution for high availability is using a Multi Data Source with load balancing.

It turns out that Oracle RAC is very sensitive to the version of JDBC driver you are using:


Automatic database connection failover and load balancing with global transactions (XA) in a highly-available (HA) DBMS architecture is supported with the following Oracle RAC versions and drivers:

Oracle Thin/XA Driver 10g

(which is oracle.jdbc.xa.client.OracleXADataSource, versus weblogic.jdbcx.oracle.OracleDataSource which is the Weblogic Oracle driver)

If you try using the Weblogic Type 4 JDBC driver (weblogic.jdbcx.oracle.OracleDataSource) you will encounter deadlock problems:

"[ACTIVE] ExecuteThread: '398' for queue: 'weblogic.kernel.Default (self-tuning)'" waiting for lock weblogic.jdbcx.base.BaseXAConnection@2923410e BLOCKED
weblogic.jdbcx.base.BaseXAResource.end(Unknown Source)
weblogic.jdbc.jta.DataSource.end(DataSource.java:803)
weblogic.transaction.internal.XAServerResourceInfo.end(XAServerResourceInfo.java:1232)
weblogic.transaction.internal.XAServerResourceInfo.internalDelist(XAServerResourceInfo.java:404)
weblogic.transaction.internal.XAServerResourceInfo.delist(XAServerResourceInfo.java:326)
weblogic.transaction.internal.ServerTransactionImpl.delistAll(ServerTransactionImpl.java:1624)
weblogic.transaction.internal.ServerTransactionImpl.localRollback(ServerTransactionImpl.java:2012)
weblogic.transaction.internal.ServerTransactionImpl.globalRetryRollback(ServerTransactionImpl.java:3020)
weblogic.transaction.internal.ServerTransactionImpl.access$100(ServerTransactionImpl.java:66)
weblogic.transaction.internal.ServerTransactionImpl$1.run(ServerTransactionImpl.java:3252)
weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
weblogic.work.ExecuteThread.run(ExecuteThread.java:181)


Highly recommended is this:

http://e-docs.bea.com/wls/docs100/jdbc_admin/oracle_rac.html

More specifically for ALBPM:
http://edocs.bea.com/albsi/docs60/installguide/index.html?t=installation/c_Required_Databases.html


Friday, March 20, 2009

Java and Shutdown

you can add a shutdown handler:

Runtime.getRuntime().addShutdownHook(sh);

where sh is a Thread

Problem is, in Unix it works only with CTRL-C, not witk kill -9 or kill -8 (abort).

In Windows, if I terminate my JVM with Eclipse's "terminate" button, the hook is not executed.

Thread Dumps and WLST

you can read WLST output into a String, so instead of into a file you can redirect some commands into a String:

String connect = "connect('weblogic', 'weblogic', 't3://bcdev07:5210')";
WLST.ensureInterpreter();

WLSTInterpreter interpreter = WLST.getWLSTInterpreter();
interpreter.exec(connect);
while (true) {
OutputStream os = new ByteArrayOutputStream();
interpreter.setOut(os);
interpreter.exec("threadDump('false')");
System.out.println("buffer="  + os.toString());
TestingUtilities.sleep(100);
}



Thursday, March 12, 2009

Logging Return Value and Method Arguments with Spring AOP

as in the previous example, but use this:


<aop:after-returning method="logExitAfterReturn" ref="loggingPointcut" returning="retVal"></aop:after-returning>


and the method becomes:

public void logExitAfterReturn(final JoinPoint joinPoint, Object retVal)

{
log( "Exiting method (after return) " + joinPoint.getSignature().getName() + ", retValue = " + retVal + ".");
}


while the logEntry becomes:

public void logEntry(final JoinPoint joinPoint)

{

StringBuilder arguments = new StringBuilder();

arguments.append(" args= ");

for (Object arg : joinPoint.getArgs()) {

arguments.append(arg).append(", ");

}

log("Entering method " + joinPoint.getSignature().getName() + arguments.toString() + "...");

}


Wednesday, March 11, 2009

Logging with Spring AOP

The bean to intercept:

package com.pierre.aop;

public class ExampleBeanClass implements IExampleBeanClass {
public String getMessage() {
return "ciao";
}
}



and its interface:

package com.pierre.aop;

public interface IExampleBeanClass {
String getMessage();
}


The interceptor:

package com.pierre.aop;

import org.aspectj.lang.JoinPoint;

/**
 * Aspect class for the Spring/AspectJ Logging example shown in the blog
 * 
 * @author vernetto
 */
public class LoggingAspect
{
/**
* Log method entry.
* @param joinPoint
*/
public void logEntry(final JoinPoint joinPoint)
{
log("Entering method " + joinPoint.getSignature().getName() + "...");
}

/**
* Log method exit.
* @param joinPoint
*/
public void logExit(final JoinPoint joinPoint)
{
log("Exiting method " + joinPoint.getSignature().getName() + ".");
}

/**
* Log method exit after returning.
* @param joinPoint
*/
public void logExitAfterReturn(final JoinPoint joinPoint)
{
log( "Exiting method (after return) "
+ joinPoint.getSignature().getName() + ".");
}

/**
* "Log" the provided String.
* @param messageToLog String to be logged.
*/
public static void log(final String messageToLog)
{
System.err.println(messageToLog);
}
}



the Main:

package com.pierre.aop;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
public static void main(String[] args) {
final ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("spring-aop-logging-context.xml");
final IExampleBeanClass example =
(IExampleBeanClass) context.getBean("exampleBean");
System.out.println(example.getMessage());
context.close();
}
}



and, at last, the XML:

<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<!-- Normal Spring-exposed bean. -->
<bean id="exampleBean" class="com.pierre.aop.ExampleBeanClass">
</bean>
<!-- The Aspect itself. -->
<bean id="exampleLoggingAspect" class="com.pierre.aop.LoggingAspect" />

<aop:config>
<!-- The Pointcut(s). -->
<aop:pointcut id="loggingPointcut" expression="within(com.pierre.aop.ExampleBeanClass)" />
<!-- The Advice(s). -->
<aop:aspect id="loggingAspect" ref="exampleLoggingAspect">
<aop:before pointcut-ref="loggingPointcut" method="logEntry" />
<aop:after pointcut-ref="loggingPointcut" method="logExit" />
<aop:after-returning pointcut-ref="loggingPointcut" method="logExitAfterReturn" />
</aop:aspect>

</aop:config>

</beans>

Tuesday, March 10, 2009

JMS, quick example

before you run it, create a Queue ""scavazza_SAFImportedDestinationsscavazza_localSAFQueue_0"
(in my case, it was a SAF destination)

package com.pierre.jms;

import java.util.Date;

import javax.jms.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;


/**
 * Add these jars:
 * javax.jms_1.1.jar
 * wls-api.jar
 * 
 * @author vernetto
 *
 */
public class JMSSender {
public static void main(String[] args) throws NamingException, JMSException {
send();
}

private static void send() throws NamingException, JMSException {
String url = "t3://localhost:7001";
InitialContext ctx = JNDIHelper.getInitialContext(url);

QueueConnectionFactory qConFactory = (QueueConnectionFactory)ctx.lookup("javax/jms/QueueConnectionFactory");
QueueConnection qConnection = qConFactory.createQueueConnection();
QueueSession qSession    = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue)ctx.lookup("scavazza_SAFImportedDestinationsscavazza_localSAFQueue_0");
QueueSender qSender  = qSession.createSender(queue);
TextMessage msg = qSession.createTextMessage();
msg.setJMSCorrelationID("iamanidagains");
msg.setIntProperty("sonoscemo", 27);
msg.setJMSPriority(7);
qConnection.start();
msg.setText("Hello this is Pierre " + new Date());
qSender.send(msg);
qSender.setDeliveryMode(DeliveryMode.PERSISTENT);
qSender.close();
qSession.close();
qConnection.close();
System.out.println("done");
}
}

Friday, March 6, 2009

Accessing resources in a WAR file

you can easily read the content of a directory in Java, even if this directory is in the classpath:

Here is a useful method to load only the resources:

public static List getDirContent(String dir, boolean throwExceptionIfNotFound) throws IOException {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
URL configDir = contextClassLoader.getResource(dir);
if (configDir == null && throwExceptionIfNotFound) throw new IllegalArgumentException("Unable to locate directory " + dir);
List result = new ArrayList();
if (configDir != null) {
URLConnection openConnection = configDir.openConnection();
openConnection.connect();
InputStream is = openConnection.getInputStream();
String content = NuonFileUtils.convertStreamToString(is);
String[] resources = content.split("\n");
for (String resource : resources) {
URL resurl = Thread.currentThread().getContextClassLoader().getResource(resource);
result.add(resurl);
}
}
return result;
}


the content of the resource can be read with a URL using its InputStream.
This method doesn't work in a WAR file, since the classloader's resource locator can't introspect the WAR file. The solution is to use the ServletContext and ServletConfig pattern:

in a JSP, you can do:

String path = ""/WEB-INF/config";
java.net.URL url = config.getServletContext().getResource(path);

and it works beautyfully!

The more elegant way is to have a ServletContextListener intercepting your servlet's initialization, and loading the resources:

public void contextInitialized(ServletContextEvent sce) {
String path = "/WEB-INF/classes";
try {
sce.getServletContext().getResource(path);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}