Pages

March 15, 2014

How to use Proxy Pattern To Implement Service's Aspects Funcionality such as Logging, Authorization, Transaction.

Proxy pattern is used to add some extra operations, checks, controls before and after wrapped subject's operation. 

  As you can see on figure, client uses Subject interface and Proxy implementation, and when a service method is called, Proxy delegates call to Real Subject. At this point you can add some more operations before and after delegation.









Code sample is below, you can download eclipse project as .rar file from here.

Package Structure

proxy pattern uml diagram
package client;

import proxypattern.IService;
import proxypattern.ServiceProxy;

public class Main {
  public static void main (String[] args) {
    IService service = new ServiceProxy();
    service.method1();
  }
}
package proxypattern.authorization;

import proxypattern.User;

public class AuthorizationService implements IAuthorizationService {
  public boolean isUserAuthorizedToCallServiceMethod (String methodName, User user) {
    System.out.println(user + " has access rights to do " + methodName);
    return true;
  }
}
package proxypattern.authorization;

import proxypattern.User;

public interface IAuthorizationService {
  boolean isUserAuthorizedToCallServiceMethod (String methodName, User user);
}
package proxypattern.log;

public interface ILogService {
  void log (String log);
}
package proxypattern.log;

public class LogService implements ILogService {
  public void log (String log) {
    System.out.println(log);
  }
}
package proxypattern.transaction;

public interface ITransactionService {
  Session getSession ();
}
package proxypattern.transaction;

public class Session {
  public void beginTransaction () {
    System.out.println("transaction started.");
  }
  public void close () {
    System.out.println("session closed.");
  }
  public void commit () {
    System.out.println("transaction committed.");
  }
  public void executeQuery (String query) {
    System.out.println(query + " executed.");
  }
  public void open () {
    System.out.println("session opened.");
  }
  public void rollback () {
    System.out.println("transaction rollbacked.");
  }
}
package proxypattern.transaction;

public class TransactionService implements ITransactionService {
  public Session getSession () {
    return new Session(); // for example you can use hibernate session factory to get a session.
  }
}
package proxypattern;

import proxypattern.authorization.AuthorizationService;
import proxypattern.authorization.IAuthorizationService;
import proxypattern.log.ILogService;
import proxypattern.log.LogService;
import proxypattern.transaction.ITransactionService;
import proxypattern.transaction.Session;
import proxypattern.transaction.TransactionService;

// this class is used for all cross cut concerns such as authorization, log, transaction.
abstract class AbstractServiceMethodCall {
  private ILogService logService = new LogService();
  private IAuthorizationService authorizatiService = new AuthorizationService();
  private ITransactionService transactionService = new TransactionService();
  protected Session session;
  public void afterDelegation (String methodName, User user) {
    this.session.commit();
    this.session.close();
    this.logService.log(methodName + " operation complete successfully");
  }
  public void beforeDelegation (String methodName, User user) throws IllegalAccessException {
    this.logService.log(methodName + " is called by " + user.toString());
    if (!this.authorizatiService.isUserAuthorizedToCallServiceMethod(methodName, user)) {
      throw new IllegalAccessException();
    }
    this.session = this.transactionService.getSession();
    this.session.open();
    this.session.beginTransaction();
  }
  public void executeOperation (String methodName, User user) {
    try {
      this.beforeDelegation("method1", user);
      this.serviceOperation(this.session);
      this.afterDelegation("method1", user);
    }
    catch (IllegalAccessException e) {
      this.operationFailed("method1", user);
    }
  }
  public void operationFailed (String string, User user) {
    this.session.rollback();
    this.session.close();
  }
  public abstract void serviceOperation (Session session);
}
package proxypattern;

class ServiceImp implements IService {
  public void method1 () {
    System.out.println("method1 of " + this.getClass().getSimpleName() + " called.");
  }
}
package proxypattern;

import proxypattern.transaction.Session;

// this class is not thread safe you have to create a new instance before using
public class ServiceProxy implements IService {
  private IService delegated = new ServiceImp();

  public void method1 () {
    new AbstractServiceMethodCall() {
      
@Override
      public void serviceOperation (Session session) {
        ServiceProxy.this.delegated.method1();
      }
    }.executeOperation("method1", new User());
  }
}
package proxypattern;

public class User {
  @Override
  public String toString () {
    return "userId";
  }
}
As you can see in ServiceProxy .java we add log, authorization and transaction operations before and after actual service method call.

Output :
method1 is called by userId //log service
userId has access rights to do method1 //authorization service
session opened. //transaction service
transaction started. //transaction service
method1 of ServiceImp called. //actual service call service
transaction committed. //transaction service
session closed. //transaction service
method1 operation complete successfully //log service

No comments:

Post a Comment