Search This Blog

Friday, April 24, 2009

Browsing Weblogic JMS Distrubuted Queues

On of the interesting features of Weblogic is that when javax.jms.QueueBrowsers are created, they are pinned to a particular physical member of a distributed destination. What that means is that a QueueBrowser created for a distributed destination will only be able to browse messages on the member it gets pinned to and not the whole queue.

One can try to create X number of queue browsers based of the number of servers in the provider URL, for example, "t3://localhost:8002, localhost:8003", and hope that no two queue browsers will pin to the same destination, i.e., at the mercy of Weblogic round robin if possible. Even if we do manage to do that, one still needs to iterate over X separate enumerations in order to manage the message. Consider an integration test where one sends a message to a distributed destination and would have to create X queue browsers to determine whether or not the message is present.

What would be really nice is if the Weblogic runtime gave us a QueueBrowser that provided an enumeration of enumerations of the physical members of a distributed queue. That however is not present. So, I decided to create a simple example that would help me with the same. At the same time, I am interested in understanding the JMX capabilities of Weblogic.

The example will create a QueueBrowser and obtain an enumeration from each of the physical members of the distributed destination and provide back an enumeration of the respective enumerations. In the case of uniformly created distributed destinations, the JNDI name of the physical members will be of the format JMSServerName@JNDIName. If one knows the JMSServerName thats great. However, one should not have to rely on the same as JMSServers might be added/removed. It would be nice if the distributed member JNDI names could be located on the fly by using Weblogic's JMX capabilities and thats what I intend to do. Note that the enumerations obtained in Weblogic are snapshots of the current state of the queue and are not dynamic, i.e., new messages added being dynamically reflected in the enumeration. Finally, I am providing a java.util.Enumeration for the JMS messages instead of an java.util.Iterator as Enumeration does not have a "remove" method and I hate putting an "UnsupportedOperationException" in the Iterator and also I would like to be true to the JMS API.

So first obtaining the JNDI name of physical members of a distributed queue. Weblogic JMX is a tree for objects. Once we obtain the ServerRuntimeMBean information, we can obtain information about the JMSRuntimeMBeans and then the different JMSServers and finally the JNDI names of the JMS Servers as shown below:



public class WeblogicMBeanHelper {
private final MBeanServerConnection connection;

private final JMXConnector connector;

private final ObjectName service;

public WeblogicMBeanHelper(String url, String userName, String password) {

try {
service = new ObjectName(
"com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean");

}
catch (MalformedObjectNameException e) {
throw new AssertionError(e.getMessage());

}
......
......
JMXServiceURL serviceURL;

try {
serviceURL = new JMXServiceURL("t3", hostName, Integer.valueOf(port), jndiroot + mserver);

Hashtable<String, String> h = new Hashtable<String, String>();

h.put(Context.SECURITY_PRINCIPAL, userName);
h.put(Context.SECURITY_CREDENTIALS, password);

h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");
connector = JMXConnectorFactory.connect(serviceURL, h);

connection = connector.getMBeanServerConnection();
}
catch (Exception e) {

throw new RuntimeException(e);
}
}

public Iterable<String> getDistributedMemberJndiNames(String distributedDestJndiName) {
Iterable<String> serverNames = getJmsServerNames();

Set<String> distributedDestNames = new TreeSet<String>();

for (String serverName : serverNames) {
distributedDestNames.add(serverName + "@" + distributedDestJndiName);

}

return distributedDestNames;
}

public Iterable<String> getJmsServerNames() {

.....
}

public Iterable<ObjectName> getJMSServers() {

....
}

public Iterable<ObjectName> getJMSRuntimes() {

....
}

public List<ObjectName> getServerRuntimeMBeans() {

try {
return Arrays.asList((ObjectName[]) connection.getAttribute(service, "ServerRuntimes"));

}
catch (Exception e) {
throw new RuntimeException("Error obtaining Server Runtime Information", e);

}
}

public void close() {

// Close the connector
....
}
}





public class WeblogicMBeanHelper {
private final MBeanServerConnection connection;

private final JMXConnector connector;

private final ObjectName service;

public WeblogicMBeanHelper(String url, String userName, String password) {

try {
service = new ObjectName(
"com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean");

}
catch (MalformedObjectNameException e) {
throw new AssertionError(e.getMessage());

}
......
......
JMXServiceURL serviceURL;

try {
serviceURL = new JMXServiceURL("t3", hostName, Integer.valueOf(port), jndiroot + mserver);

Hashtable<String, String> h = new Hashtable<String, String>();

h.put(Context.SECURITY_PRINCIPAL, userName);
h.put(Context.SECURITY_CREDENTIALS, password);

h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");
connector = JMXConnectorFactory.connect(serviceURL, h);

connection = connector.getMBeanServerConnection();
}
catch (Exception e) {

throw new RuntimeException(e);
}
}

public Iterable<String> getDistributedMemberJndiNames(String distributedDestJndiName) {
Iterable<String> serverNames = getJmsServerNames();

Set<String> distributedDestNames = new TreeSet<String>();

for (String serverName : serverNames) {
distributedDestNames.add(serverName + "@" + distributedDestJndiName);

}

return distributedDestNames;
}

public Iterable<String> getJmsServerNames() {

.....
}

public Iterable<ObjectName> getJMSServers() {

....
}

public Iterable<ObjectName> getJMSRuntimes() {

....
}

public List<ObjectName> getServerRuntimeMBeans() {

try {
return Arrays.asList((ObjectName[]) connection.getAttribute(service, "ServerRuntimes"));

}
catch (Exception e) {
throw new RuntimeException("Error obtaining Server Runtime Information", e);

}
}

public void close() {

// Close the connector
....
}
}




Now that we have a way of obtaining the distributed members, the following represents the QueueBrowser that enumerates over the different members and consolidating the same into a single enumeration. I have a second enumeration that provides information regarding the JMServer that hosts the given message:



public class DistribuedQueueBrowser {
...
private final Iterable<String> queueNames;

public DistribuedQueueBrowser(String adminUrl, String providerUrl,
String distributedDestinationName, String userName, String password) throws Exception {

ctx = getInitialContext(providerUrl, userName, password);
WeblogicMBeanHelper helper = null;

try {
helper = new WeblogicMBeanHelper(adminUrl, userName, password);

queueNames = helper.getDistributedMemberJndiNames(distributedDestinationName);
}
finally {

if (helper != null) {
helper.close();

}
}

// Set up connection/session..
....
}

private InitialContext getInitialContext(String providerUrl, String userName, String password) throws Exception {

....
}

// Retrun an Enumeration of Messages only
public Enumeration<Message> getEnumeration() throws JMSException, NamingException {

return new JmsMessageEnumeration(getMessageEnumeratorMap());
}

@SuppressWarnings("unchecked") private Map<String, Enumeration<Message>> getMessageEnumeratorMap() throws JMSException,
NamingException {

Map<String, Enumeration<Message>> serverMessageMap = new HashMap<String, Enumeration<Message>>();

for (String queueName : queueNames) {
String serverDq[] = StringUtils.split(queueName, "@");

Queue queue = (Queue) ctx.lookup(queueName);

javax.jms.QueueBrowser qb = session.createBrowser(queue);

serverMessageMap.put(serverDq[0], qb.getEnumeration());

}

return serverMessageMap;
}

// Return an enumeration of ServerLocatedMessage that contains the
// the jms server that houses the message

public Enumeration<ServerLocatedMessage> getServerLocatedEnumeration() throws JMSException,
NamingException {

return new ServerLocatedMessageEnumeration(getMessageEnumeratorMap());
}

public static class ServerLocatedMessage {
private final Message message;

private final String jmsServerName;

public ServerLocatedMessage(String jmsServerName, Message message) {

this.message = message;
this.jmsServerName = jmsServerName;

}
...
}

private static abstract class AbstractMessageEnumeration<T> implements Enumeration<T> {

Map.Entry<String, Enumeration<Message>> current;
private Enumeration<Message> currMessageEnumer;

private final Iterator<Map.Entry<String, Enumeration<Message>>> iterator;

public AbstractMessageEnumeration(Map<String, Enumeration<Message>> map) {

iterator = map.entrySet().iterator();
current = iterator.hasNext()

? iterator.next()
: null;
currMessageEnumer = current != null

? current.getValue()
: new Enumeration<Message>() {

public boolean hasMoreElements() {
return false;

}

public Message nextElement() {
throw new NoSuchElementException();

}
};
}

Enumeration<Message> getEnumeration() {

if (current == null || currMessageEnumer.hasMoreElements()) {

return currMessageEnumer;
}

while (iterator.hasNext()) {

current = iterator.next();
currMessageEnumer = current.getValue();

if (currMessageEnumer.hasMoreElements()) {
return currMessageEnumer;

}
}

return currMessageEnumer;
}

public boolean hasMoreElements() {
return getEnumeration().hasMoreElements();

}
}

// Wraps the JMS Message within a ServerLocatedMessage object
// which contains the server name along with the message
private static class ServerLocatedMessageEnumeration extends

AbstractMessageEnumeration<ServerLocatedMessage> {

public ServerLocatedMessageEnumeration(Map<String, Enumeration<Message>> map) {

super(map);
}

public ServerLocatedMessage nextElement() {

Message message = getEnumeration().nextElement();
return new ServerLocatedMessage(current.getKey(), message);

}
}

private static class JmsMessageEnumeration extends AbstractMessageEnumeration<Message> {

public JmsMessageEnumeration(Map<String, Enumeration<Message>> map) {
super(map);

}

public Message nextElement() {
return getEnumeration().nextElement();

}
}

public void close() {

......
}
}



Using this QueueBrowser is rather straight forward and can be done via:



// Note that the first argument is the admin url and the second is the
// managed server url.
DistribuedQueueBrowser qb = new DistribuedQueueBrowser("t3://localhost:7001",
"t3://localhost:8001",
"test_queue", "weblogic", "weblogic");

Enumeration<Message> i = qb.getEnumeration();
while (i.hasMoreElements()) {

Message m = i.nextElement();
System.out.println("Message:" + m);

}

Enumeration<ServerLocatedMessage> sli = qb.getServerLocatedEnumeration();

while (sli.hasMoreElements()) {
ServerLocatedMessage m = sli.nextElement();

System.out.println(m);
}
}



The code for the same is available HERE. The zip file contains only the JAVA files. One would need to compile the same with weblogic's client jar's and then use them. Let me know if you have problems running the code or if you have any tips regarding the code.
Later...

Saturday, April 18, 2009

Aspect J Maven and Logging

At my earlier job, I had looked at Aspect Oriented programming with Spring. I used the same for transactions. I wanted to use it for Logging method enter/exits as well but abandoned the same as one would need to use Spring's native AspectJ weaving. I was not ready to take that on at the time. Another option was to use AspectJ compile-time weaving, again, not something I had the time for and simply settled on Transactional support with Spring Aspects.

So what am I upto? I wanted to play with AspectJ and how compile time weaving on maven project would help me eliminate the logging.

Enter and exit of methods are quite useful, especially when debugging. Another use case of debugging would be to trace the method arguments passed to a method. In addition, performance of profiling method executions has its benefits. In an earlier blog post I had investigated the use of Java Instrumentation to assist with profiling.

So I start by creating a logging Aspect. If the logging level is set as DEBUG, it will LOG entry and exit of a method. If the level is set as TRACE, then the time for method execution is also logged along with the method arguments to the method. The following represents the Aspect:



import org.aspectj.lang.*;
import org.apache.log4j.*;

public aspect LoggingAspect {

Logger LOG = Logger.getLogger("trace");

// Execute on all methods except this Logging Aspect

pointcut traceMethods()
: execution(* *.*(..)) && !within(LoggingAspect);

// Around each method do the following
Object around() : traceMethods() {

Signature sig = thisJoinPointStaticPart.getSignature();

String baseEnterMessage = "Enter [" + sig.getDeclaringType().getName() + "." + sig.getName() + "] ";


if (LOG.isTraceEnabled()) {
Object[] args = thisJoinPoint.getArgs();


if (args.length > 0) {
StringBuilder argsBuilder = new StringBuilder(20);

argsBuilder.append(baseEnterMessage).append(" Args :");

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

argsBuilder.append("{Index [" + i + "], Value [" + args[i] + "]}");

if (i != args.length - 1) {

argsBuilder.append(",");
}
}
argsBuilder.append("}");


LOG.trace(argsBuilder.toString());
}
else {

LOG.trace(baseEnterMessage);
}
}
else if (LOG.isDebugEnabled()) {

// Print base debug without arguments
LOG.debug(baseEnterMessage);
}

long start = System.currentTimeMillis();


try {
Object result = proceed();
return result;

} finally {
String baseMessage = "Exiting [" + sig.getDeclaringType().getName() + "." + sig.getName() + "].";


if (LOG.isTraceEnabled()) {
// If trace is enabled, print the time for execution.
long end = System.currentTimeMillis();

LOG.trace(baseMessage + "Completed in:" + (end - start) + " millis");

} else if (LOG.isDebugEnabled()) {
LOG.debug(baseMessage);

}
}
}



Another nice use of Aspects is to be able to enforce compile time standard checks. Maybe Find Bugs has a way to already do this. Not sure. Anyway, say for example, we want to detect when there are System.out.println() calls in the code or maybe the code in question is using some Class/Framework that we do not approve of, with Aspects and compile time checking there is a nice way out. I quite liked reading the blog by Jacob Matute on the compile time enforcement of standards. What I envision is the inclusion of a simple jar in project that can/will enforce the standards one desires. I think this might be preferable over depending on IDE based configuration of plugins.

What about method invocations where checks are performed? For example in many methods we repeat code that checks if an argument is null and throws some exception? What if one could declare an annotation on the method and an aspect check for the annotation to handle the same for you? The code becomes cleaner IMO. I think Java 7 will have this feature. Till then one can create an @NotNull annotation on a parameter and have aspects handle the exception throwing part for you across your entire code base. Andy Clement's blog discusses the same very nicely.

As I used maven for all my projects, there is a plugin from codehaus, for integrating AspectJ into maven.

For the sake of demonstration, I have a simple, fictional and potentially farcical objects that would undergo the tests of the Aspects:



public class Order {
private final Long id;

private final String userName;
private final Random random = new Random();


public Order(Long id, String userName) {
this.id = id;

this.userName = userName;
}

public String getUserName() { return userName; }


public int getTotalCost(int range) {
System.out.println("Calculating Cost...");

try {
Thread.sleep(2000L);
} catch (InterruptedException e) {}

return getRandom(range);
}

private int getRandom(int range) { return random.nextInt(range);}

}



An even trivial use of the Order object which is not even a unit test is shown below:



@Test
public void testOrderModel() {

Order order = new Order(23L, "Foo");

System.out.println("Order UserName:" + order.getUserName());

System.out.println("Order Total cost:" + order.getTotalCost(113));

System.out.println(Util.concatName("Sanjay", "Acharya"));

}



When I run "mvn install", I notice the following depending on the logging level I have setup in my log4j.properties, i.e., DEBUG or TRACE:



-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.welflex.model.ModelTest
Enter [com.welflex.model.Order.getUserName]
Exiting [com.welflex.model.Order.getUserName].Completed in:0 millis
Order UserName:Foo
Enter [com.welflex.model.Order.getTotalCost] Args :{Index [0], Value [113]}}
Calculating Cost...
Enter [com.welflex.model.Order.getRandom] Args :{Index [0], Value [113]}}
Exiting [com.welflex.model.Order.getRandom].Completed in:0 millis
Exiting [com.welflex.model.Order.getTotalCost].Completed in:2000 millis
Order Total cost:40
Enter [com.welflex.model.Util.concatName] Args :{Index [0], Value [Sanjay]},{Index [1], Value [Acharya]}}
Exiting [com.welflex.model.Util.concatName].Completed in:1000 millis
SanjayAcharya
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.12 sec



Parting Thoughts:
I think Aspects are rather powerful. There is plugin support for Aspects as well. For cross cutting concerns, use of Aspects is the way to go IMHO. Finally, although this is a maven project using JDK 1.5, there is no reason why this applies to maven only or cannot be used on previous versions of the JDK.

A maven project that demonstrates the above is available for download HERE
. One problem that I faced was getting the maven-aspectj plugin to install correctly. If you do install the same, you might want to add the codehaus repository to the pom.xml to ensure that the plugin is downloaded. To execute the project, from your command line, issue a "mvn install". There is a log4j.properties file in the project whose logging level you can tweak to see differences.

Enjoy :-)!

Saturday, April 11, 2009

Weblogic JMS Standalone Multi-threaded Client Security

I have been building a helper library that provides some convenience functionalities and all of a sudden it started failing with authentication exceptions. Not on obtaining Jms artifacts but during the send of a message. Jeez! One part of me says let go, deal with it on Monday, the other part is hungry to find out why. No prizes for guessing which part of me won :-)
Weblogic client runtime stores credentials in a ThreadLocal of the Thread that creates an InitialContext to obtain a jms resource, i.e., equivalent of saying the thread that has the credentials can execute privileged operations on certain JMS resource but as other threads do not have the credentials and thus, they cannot. Weblogic's security will obtain the information from the ThreadLocal and use the credentials therein for send/receive operations.
Now, in a Jms environment, one would like to create multiple javax.jms.Session, javax.jms.MessageProducer and use multi-threading where appropriate, sharing the same JMS connection. Think of a Servlet container that has multiple threads. If Jms artifacts (Connection factories, Destinations) are obtained only once using a Singleton by one of the Container's thread's, then it is only this thread that can send/receive messages from a JMS destination if the destination has security enabled on the same. The operation of creating a Context places a javax.security.auth.Subject in the ThreadLocal of the thread creating the Context. If the context is closed, the Subject is removed.
Consider the following example where the jms artifacts are obtained in a single thread of execution and a message is sent in the same thread:

public void sameThreadCreateSend() throws Exception {
    InitialContext ctx = getInitialContext();
    ConnectionFactory connectionFactory = (ConnectionFactory) ctx
        .lookup("Connectionfactory");
    Destination destination = (Destination) ctx.lookup("test_queue");

    // Closing the context causes the send authentication exception
    ctx.close();

    Connection connection = connectionFactory.createConnection();

    connection.start();
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    MessageProducer producer = session.createProducer(destination);

    // Fails to send message as closing of the context removes the security information

    // from the Thread local. If the context is kept open, then it works great.
    producer.send(session.createTextMessage());
    System.out.println("Sent message when send was called on thread that created context...");
}

In the above example, the message gets sent successfully, What about a case where the Jms artifacts are created on one thread and a thread created from the creator thread tries to send a message? Will the permissions get propagated to the child thread? Look at the code below:

public void testInheritableThreadSend() throws Exception {
    InitialContext ctx = getInitialContext();

    // Current Thread has the security information
    final ConnectionFactory connectionFactory = (ConnectionFactory) ctx
        .lookup("connectionfactory");

    final Destination destination = (Destination) ctx.lookup("test_queue");

    // This thread will have the security as well due to Inheritable thread local
    Thread t = new Thread() {

      @Override public void run() {
        try {
          final Connection connection = connectionFactory.createConnection();
          connection.start();
          Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          MessageProducer producer = session.createProducer(destination);
          producer.send(session.createTextMessage());
          System.out.println("Sent message using inheritable thread local...");
        }
        catch (Exception e) {
          e.printStackTrace();
        }
      }
    };

    t.start();
    t.join();
}

Yes the above code sent a message successfully as the credentials in the parent are propagated to the child thread via Inheritable thread local.
Now what about a case where the creation of the Jms artifacts are created on a thread that is not the parent of the thread that sends the message using those artifacts? Look at the sample below:

public void createOnSeparateThread() throws Exception {
    // First thread opens a context and had the credentials
    ResourceCreator c = new ResourceCreator();

    c.start();
    c.join();

    // Second thread is not a child of the first, thus does not have the security
    NonCreatorThreadRunner n = new NonCreatorThreadRunner(c);
    n.start();
    n.join();
  }

  private class ResourceCreator extends Thread {
    InitialContext ctx;
    Destination destination;
    Connection connection;

    @Override public void run() {
      try {
        ctx = Example.this.getInitialContext();
        connection = ((ConnectionFactory) ctx.lookup("connectionfactory"))
            .createConnection();
        destination = (Destination) ctx.lookup("test_queue");
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  private class NonCreatorThreadRunner extends Thread {
    private final ResourceCreator resourceCreator;

    public NonCreatorThreadRunner(ResourceCreator resourceCreator) {
      this.resourceCreator = resourceCreator;
    }

    @Override public void run() {
      try {
        resourceCreator.connection.start();
        Session session = resourceCreator.connection.createSession(false,
          Session.AUTO_ACKNOWLEDGE);
        MessageProducer producer = session.createProducer(resourceCreator.destination);
        producer.send(session.createTextMessage());
        System.out.println("Sent message when context was created on a separate thread...huh ???");
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
 }

So the above send operation failed. Why? Because the second thread does not have the security credentials in its ThreadLocal. Now what if we could use the security information from the first thread on the second thread? We can, using weblogic security classes and using the javax.security.auth.Subject to execute a javax.security.PrivilidgedAction.

 private class SubjectHoldingResourceCreator extends ResourceCreator {
    Subject subject;

     // Obtain the Subject from the thread
    @Override 
    public void run() {
      super.run();
      subject = weblogic.security.Security.getCurrentSubject();
    }
  }

  private class SubjectUsingNonCreatorThreadRunner extends Thread {

    private final SubjectHoldingResourceCreator creator;
    public SubjectUsingNonCreatorThreadRunner(SubjectHoldingResourceCreator creator) {
      this.creator = creator;
    }

    @Override public void run() {
      try {
        final Session session = creator.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        final MessageProducer producer = session.createProducer(creator.destination);
        // Execute a secure action using the Subject from the previous thread.
        weblogic.security.Security.runAs(creator.subject, new PrivilegedAction<Void>() {
          public Void run() {
            try {
              producer.send(session.createTextMessage());
              System.out.println("Sent using Subject created on separate thread....");
            }
            catch (JMSException e) {
              e.printStackTrace();
            }
            return null;
          }
        });
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
}

And a test for the same:

public void testCreationOnSeparateUsingSubject() throws Exception {
    SubjectHoldingResourceCreator c = new SubjectHoldingResourceCreator();
    c.start();
    c.join();
    SubjectUsingNonCreatorThreadRunner r = new SubjectUsingNonCreatorThreadRunner(c);

    r.start();
    r.join();
}

The above example worked and sent the message. I have seen others facing a similar issue when using Spring classes such as JmsTemplate and DefaultMessageListenerContainer with Weblogic where this security issue bites them. Some folks have taken the route of initializing the Context before every send/receive of a message. This is clearly not optimal as the creation of an InitialContext is not cheap and can lead to degradation of performance.
My recommendation is to use the Proxy Pattern and have proxied versions of javax.jms.MessageProducer(s) and javax.jms.MessageConsumer(s) which ensure that calls to send/receive are executed within a PrivilidgedAction.
Look at my posting on Weblogic Jms Template to see how Proxies can be used.
The javax.security.auth.Subject can be obtained once in a multi-threaded environment for a particular user authenticator (userName/pass) and then be held for use by all the threads in the environment.
public Subject createSingleSubject(String providerUrl, String userName, String passsword) {
    Subject subject = new Subject();
    // Weblogic env class
    Environment env = new Environment();

    env.setProviderUrl(providerUrl);
    env.setSecurityPrincipal(userName);
    env.setSecurityCredentials(password);

    try {
      // Weblogic Authenticate class will populate and Seal the subject 
      // Always use the same subject in further calls, regardless of thread
      Authenticate.authenticate(env, subject);

      return subject;
    }
    catch (LoginException e) {
      throw new RuntimeException("Unable to Authenticate User", e);
    }
    catch (Exception e) {
      throw new RuntimeException("Error authenticating user", e);
    }
}

If the above method is invoked once to set up a Subject, then the same Subject can be used by Proxies to invoke PrivilidgedActions.
One thing I don't like is that on closing of the obtained Context, the ThreadLocal object is not cleared of all allocated permission related objects. It is only the Subject that is detached. I am looking for a way prevent the caching of security information in the ThreadLocal by WebLogic.
Some Links:
1. Spring JIRA
2. Weblogic Security Documentation

Wednesday, April 1, 2009

Liking Emma and FindBugs Eclipse Plugins

I have found myself liking two helpers as I continue to develop, Code Coverage and Finding Bugs. I usually use plugins in maven reporting to help me find issues and coverage information after issuing a "mvn site".

I however prefer to catch the same without having to generate the maven site though and in my IDE. I see two nice eclipse plugins for the same. For the Code Coverage part, I quite like the Emma Eclipse plugin which allows me to run my unit tests in "Coverage" mode and helps me determine the amount of code coverage my unit tests are providing. The coloring is pretty good, green for fully covered code, red for missed code and yellow for partially covered code. Trying to be green...

I have also started to use the Find Bugs eclipse plugin. Professional "Hara Kiri" here but I often get pleasantly surprised by what the utility finds for me :-). It would have been nice if the "Problems" tab in Eclipse showed the issues found by "Find Bugs" via a different icon. Also I am refraining from showing results of either plugin here for obvious reasons :-))))