пятница, 31 июля 2015 г.

J2EE. Logging in application

Logging is an cross-cutting concern in the application.

It is tedious to write every time

Logger log = LogManager.getLogger(getClass()); 

To speed up one can copy this string from one class to another.
Not very expressive way. Well, it is more code to read.
Nowadays we have annotations, we have EJB, we have CDI.

We can improve the logging code in two ways:
  1. implement the logging as a cross-cutting concern with a CDI interceptor
  2. if we need more logging it would be much simpler to inject logger

четверг, 30 июля 2015 г.

Get info about user in WebSphere Application Server 8.5.5

Sometimes you should get info about user in WebSphere Application Server. WAS is connected to ldap. I have to find out the full name of a user. How to do it?

One can use the VMM - the subsystem for user management in WAS.

To compile the VMM code following jars have to be in the classpath:
  <WAS_HOME>\plugins\com.ibm.ws.runtime.jar
  <WAS_HOME>\plugins\com.ibm.ws.runtime.wim.base.jar
  <WAS_HOME>\plugins\org.eclipse.emf.commonj.sdo.jar
  <WAS_HOME>\lib\j2ee.jar

Here is the code to get the user name:

import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.ibm.websphere.wim.SchemaConstants;
import com.ibm.websphere.wim.Service;
import com.ibm.websphere.wim.client.LocalServiceProvider;
import com.ibm.websphere.wim.ras.WIMTraceHelper;
import com.ibm.websphere.wim.util.SDOHelper;
import commonj.sdo.DataObject;

class VMMRealm  {
    private static Logger log = LogManager.getLogger(VMMRealm.class);
    // Virtual member manager service that is used to make API calls
    static Service service = null;
    static {
        service = locateService();
    }

 
   @SuppressWarnings("unchecked")
    public UserInfo getUserData(String login) throws UserStoreAccessException {
        UserInfo userInfo = null;
        DataObject root = null;
        try {
            root = SDOHelper.createRootDataObject();
            DataObject searchCtrl = SDOHelper.createControlDataObject(root,
                    null, SchemaConstants.DO_SEARCH_CONTROL);
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("sn");
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("uid");
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("cn");
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES).add(
                    "telephoneNumber");
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES).add(
                    "createTimestamp");
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES)
                    .add("givenName");
            searchCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("title");
            searchCtrl.setString(SchemaConstants.PROP_SEARCH_EXPRESSION, String
                    .format("@xsi:type='PersonAccount' and uid='%s'", login));

            log.trace(printDO(root));
            root = service.search(root);
            log.trace(printDO(root));
            userInfo = new UserInfo();
            convertDataObjectToUserInfo(root, userInfo);
        } catch (Exception e) {
            throw new UserStoreAccessException("Error getting user", e);
        }
        return userInfo;
    }

    /**
     * Convert data object to user info
     *
     * @param root
     * @param info
     */
    private void convertDataObjectToUserInfo(DataObject root, UserInfo info) {
        List entities = root.getList(SchemaConstants.DO_ENTITIES);
        for (int i = 0; i < entities.size(); i++) {
            DataObject ent = (DataObject) entities.get(i);
            info.setCn(ent.getString("cn"));
            info.setUid(ent.getString("uid"));
        }
    }

    /**
     * Loop through the entities in the DataObject and print its uniqueName
     *
     * @param root
     *            input DataObject
     */
    public static void printIdentifiers(DataObject root) throws Exception {
        // Get all entities in the DataObject
        List entities = root.getList(SchemaConstants.DO_ENTITIES);
        for (int i = 0; i < entities.size(); i++) {
            DataObject ent = (DataObject) entities.get(i);
            // Get the entity Identifier
            DataObject id = ent.getDataObject(SchemaConstants.DO_IDENTIFIER);
            if (id != null) {
                String uniqueName = id
                        .getString(SchemaConstants.PROP_UNIQUE_NAME);
                log.debug("UniqueName is  -> " + uniqueName);
            } else {
                log.debug("Missing Identifier");
            }
        }
    }

    /**
     * Locates virtual member manager service in local JVM
     **/
    private static Service locateService() {
        try {
            // Local access virtual member manager Service
            return new LocalServiceProvider(null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return null;
    }

    public static String printDO(DataObject obj) {
        return WIMTraceHelper.printDataObject(obj);
    }
}

To get info about the user call getUserData method.

J2EE6. CDI qualifier convenient injection

When you have an interface reference in a class and this interface has more than 1 implementation you have to specify somehow the injected implementation.

CDI offers you the qualifiers mechanism (annotations) to resolve this issue. For example you can create one annotation for PROD version and another annotation for TEST version of the implementation. Two annotations for such a thing are too much.

We can simplify it.

Here is our qualifier:
@Qualifier
@Retention(RUNTIME)
@Target({ FIELD, TYPE, METHOD })
public @interface ConnectionFactory {
    ConnectionFactoryType value();
}

Here is the example of ConnectionFactoryType:
 public enum ConnectionFactoryType {
    PROD, TEST
}

 Here is how how the implementation of the CDI bean looks like:
@ConnectionFactory(ConnectionFactoryType.PROD)
@ApplicationScoped
public class ProdConnectionFactory implements IConnectionFactory {}



Here is how you inject the bean:
@Inject
@ConnectionFactory(ConnectionFactoryType.PROD)
private IConnectionFactory connectionFactory;

What we got here is:
1) we created one annotation for different connection implementations.
2) We can specify the implementation by specifying the enum value.
3) This is reusable and better then creating one annotation per implementation.


четверг, 23 июля 2015 г.

Singleton pattern in java

Currently I'm interested in software patterns. I'm reading the classic book: "Design patterns. Elements of reusable object-oriented software".

One of the patterns described is singleton. This is a popular pattern in java. So, how could you develop it java?

class Singleton{
private static Singleton singleton;
private Singleton{}
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
 return instance; 
 }
}

But, how about this?

public enum Singleton{
INSTANCE;
public void yourBusinessMethod(){}
}

A single-element enum type is the best way to implement a singleton. This is stated in "Effective Java".

What are the pros of this solution?
  1. no serialization problems
  2. guarantee against multiple instantiation
  3. easy to read (less) code
If you are afraid of using enum one can implement the interface for the enum. This means you can use the enum and object in method which expects the interface.