Proxy Pattern Application

“In computer programming, the proxy pattern is a software design pattern. A proxy, in its most general form, is a class functioning as an interface to something else.” – Wikipedia
In other words, particularly in java programming language practice, you can use java.lang.reflect.Proxy class to construct instance of an interface.

When and why do you want to adopt Proxy pattern?

In a fashion of loosely coupled design, it is possible to get a set of interfaces without their concrete classes because there’s no multiple inheritance in java. If you want the entities to inherit from a base, there is no way of using concrete classes to bridge the persistence layer and presentation layer. To store and carry data to the persistence layer which is invisible to the presentation layer, you can either build another set of concrete classes or use proxy pattern. There are different concerns for both routes. I used the traditional one for my demo project looseCoupling branch. Whereas, for the EAR project assignment, I got the code following the proxy pattern.
From my study, I found if you want use MOXy, you can only parse XML. Other frameworks don’t support proxy pattern. Thus, if you need to use JSON, the traditional way is what you probably should go for.

A practice on Proxy pattern in parsing XML

In order to do XML binding with a proxy pattern. There are 3 steps to do it:

  1. Setup JAXBContextFactory;
  2. Build an ObjectFactory;
  3. Implement MessageBodyReader and MessageBodyWriter.

1. Setup JAXBContextFactory

To use MOXy, you need to add it into the project library. For maven, add the following to the pom.xml:
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.moxy</artifactId>
    <version>2.6.4</version>
</dependency>

Define javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory in jaxb.properties and place this file along with your Models or ObjectFactory.

Build an ObjectFactory

Before building the ObjectFactory class, you should have some interfaces like IUser to be manipulated against:

@javax.xml.bind.annotation.XmlRootElement
public interface IUser extends IModel {
    String getName();
    void setName(String name);
}

There are several ways to create an instance out of the interface, here is the route of using Proxy with an InvocationHandler. In this way, the instance to be generated will have a class signature something like this (example for IUser): public class Proxy$1 extends Proxy implements IUser. To implement the InvocationHandler interface, do the following:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
class InterfaceInvocationHandler implements InvocationHandler {
    private Map values = new HashMap();
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if(methodName.startsWith("get"))
            return values.get(methodName.substring(3));
        else
            values.put(methodName.substring(3), args[0]);
        return null;
    }
}

This implementation basically performs/mocks getters and setters of the properties and stores the values in a HashMap.

import java.lang.reflect.Proxy;
@javax.xml.bind.annotation.XmlRegistry
public class ObjectFactory {
    public User createUser() {
        return createInstance(User.class);
    }
    private <T> T createInstance(Class<T> anInterface) {
        return (T) Proxy.newProxyInstance(anInterface.getClassLoader(), new Class[] {anInterface}, new InterfaceInvocationHandler());
    }
}

In the ObjectFactory, you can list as many models as you need. Although, they have to fit for your InterfaceInvocationHandler.

Implement MessageBodyReader and MessageBodyWriter

Based on my study, when building a REST service, there is no actual need for implementing the MessageBodyWriter because the out going message can retrieve data from the interface models. As long as you specified @Consumes(MediaType.APPLICATION_XML) annotation to ether the method or class level of your REST service, JAX-B will automatically perform marshaling for the models. However, you do need to implement the MessageBodyReader and let it help processing the in coming message.
As mentioned in above sections, since the Proxy class is the direct ancestor of the interface, you should let MessageBodyReader capture Proxy class (instead of doing it for each model classes) and do the parsing/unmarshaling before the message reach the certain REST method. It’s like an implicit interceptor to be enabled for the method once you annotate @Consumes(MediaType.APPLICATION_XML) on the REST service method or class.
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

@Provider
@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public class ProxyMessageBodyReader implements MessageBodyReader {
 @Override
 public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
  return type.getClass().isInstance(IModel.class);// the ancestor of IUser
 }
 @Override
 public Proxy readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
  try {
   JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
   final Unmarshaller unMarshaller = jaxbContext.createUnmarshaller();
   return (Proxy) unMarshaller.unmarshal(entityStream);
  } catch (final JAXBException ex) {
   LOG.error(ex.getMessage(), ex);
   throw new WebApplicationException(ex.getMessage(), Status.INTERNAL_SERVER_ERROR);
  }
 }
}

If you look closer to this code and the one in my assignment I linked to, you can see a slight difference on instantiating the JAXBContext. Unlike this one, it uses CDI. However, they are doing the same thing.

This blog may not be up to date. Please see the original post from Blogger http://ift.tt/2g0OS3o
via IFTTT.

Advertisements