Pages

Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

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

March 14, 2014

Basic Architectural Design of Service for Enterprise Applications with Class Diagram and Sequence Diagram

Basic requirements for a service implementation are transaction, logging, authorization and of course business rules with service operations. When you think deeply you will see that these requirements are cross cut concerns. It means transaction, logging, security and business rule engine can be thought aspects, infrastructural requirements. These are independent from business domain.


Why transactional ?
It is important for the integrity and consistency of data.

Why log ?
It is important to observe performance, security, errors, statistics.

Why authorization ?
It is important to achieve that any client uses service, can call only operations which it has rights to call.

Why business rule engine ?
Any service operation has some business rules and it is important to cover them with a modern approach.

About Class Diagram of Service
  • The service is designed modular, each module can be thought a service or services, when a module is dependent to an other module, interaction between modules must be using service interfaces.These are important for high cohesion.
  • A Service implementation has data access objects to achieve database operations. 
  • Both service, data access objects and of course service client uses entities to do operations.
  • All service operations must be transactional. It means when a service method is called, all operations, all data access object operations must be in same transaction. So if service call succeed all database changes must be applied to the databases, but if it is failed none of them must be applied.
  • Transaction, business rule engine, log and authorization can be implemented as java interceptors or decorators. Because these are all aspects and independent from business domain.
About Sequence Diagram of Service
  • When a service method is called, transaction is started by the transaction manager.
  • Log Service is used to log that operation is called and other logs for example performance considerations.
  • Authorization Service is used for checking that client has access grants to call service method.
  • Business Rule Engine is used to execute domain specific business rules.
*Log Service and Authorization Service can be seperated from business transaction. The order of service call can be changed according to the different approaches.


Service Class Diagram.vsd, Service Sequence Diagram.vsd



March 2, 2014

How To Implement Session Expired Alert using JSF, PrimeFaces and Java Script

You have to handle this issue at client side, because any solution that uses server side scripts initiates session time again. We can use java script for solving this issue.

Basically the solution has four steps.
1. After user logs into the system, a timer equals to the session time is set and count down is started.
2. Each server request the server side session time is restarted, so count down is restarted.
3. When the count down is close to 0, system shows additional time dialog to the user.
4. At the end of the count down, user is redirected to the exit page.

The implementation and demo is below. Java script code is placed in .xhtml document at this implementation but if you use a .js file you can paste the code in it.


Important code lines and explanations.

1.
if (document.getElementById('loggedInUserId') == null) {
  return;
}

With this code line we check the logged user info in rendered xhtml. So we sure that user logged in and ready for count down.
2.
<p:ajaxStatus onstart="statusDialog.show();" 
    onsuccess="statusDialog.hide();countDownInit();" />
With this code line we restart count down again with any ajax request. Because in each server request the server side session time is restarted.
3.
if (0 > minute) {
  exit();
  return;
}

At the end of the count down, we redirect current page to the exit page.
4.
<p:commandButton value="Yes" process="@this" 
    update="@none" oncomplete="additionalTimeDialog.hide();" />
<p:commandButton value="No" type="button" onclick="exit();" />

If the user clicks yes button to get extra time we send an ajax request using command button and close the additional time dialog. So with this request server side session time will be restarted.

If the use clikcs no button, we simply redirect user to the exit page.

index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.org/ui"
  xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>Facelet Title2</title>
  <script type="text/javascript">
    var countDownTime; //in miliseconds
    var sessionTime = 61000; //in miliseconds
    var whenToShowAdditionalTimeDialog = 60000; //in miliseconds 
    var isAdditionalTimeDialogShowed = false;
    var countDownStarted = false;
    var minute;
    var second;
    function countDownInit() {
      countDownTime = (new Date()).getTime();
      minute = 1;
      second = 00;
      countDownStarted = false;
    }
    function checkCountDown() {
      if (document.getElementById('loggedInUserId') == null) {
        return;
      }
      var now = (new Date()).getTime();
      if (now - countDownTime > (sessionTime - whenToShowAdditionalTimeDialog)) {
        additionalTimeDialog.show();
        countDownStarted = true;
      }
      if (countDownStarted) {
        second = second - 1;
        if (0 > second) {
          second = 59;
          minute = minute - 1;
        }
        if (0 > minute) {
          exit();
          return;
        }
        document.getElementById('additionalTimeDialog:minuteOutput').innerHTML = minute;
        document.getElementById('additionalTimeDialog:secondOutput').innerHTML = second;
      }
    } 
    function exit() {
      document.location.href = '/projectname/eng/loggedout.xhtml';
    }
    window.setInterval(checkCountDown, 1000);
    </script>
  </h:head>

  <h:body>
    <p:ajaxStatus onstart="statusDialog.show();" 
        onsuccess="statusDialog.hide();countDownInit();" />
    <p:dialog modal="true" widgetVar="statusDialog" header="Status" 
        draggable="false" closable="false">
      <p:graphicImage value="/image/ajaxloadingbar.gif" />
    </p:dialog>
    <p:dialog modal="true" widgetVar="additionalTimeDialog" header="Alert" 
         draggable="false" closable="false">
      <h:form id="additionalTimeDialog"> Your session time will be expired in 
        <h:outputText id="minuteOutput" /> : <h:outputText id="secondOutput" /> . 
            Do you want extra time ?
        <p:commandButton value="Yes" process="@this" update="@none" 
            oncomplete="additionalTimeDialog.hide();" />
        <p:commandButton value="No" type="button" onclick="exit();" />
      </h:form>
    </p:dialog>
    <h:form id="form" prependId="false">
      <p:remoteCommand name="sendRequest" update="@none" process="@this" />
      <h:panelGrid id="userform">
        <p:panelGrid columns="2" rendered="#{not testManagedBean.userLogged}">
          <h:outputLabel value="Name" />
          <p:inputText value="#{testManagedBean.name}" />
          <h:outputLabel value="Password" />
          <p:inputText value="#{testManagedBean.passWord}" />
          <p:separator />
          <p:commandButton value="Log in" action="#{testManagedBean.login}" 
                process=":form:userform" update=":form:userform" />
        </p:panelGrid>
        <p:panelGrid columns="2" rendered="#{testManagedBean.userLogged}">
          <h:outputLabel value="Name" />
          <h:outputText id="loggedInUserId" value="#{testManagedBean.name}" />
        </p:panelGrid>
        </h:panelGrid>
      </h:form>
  </h:body>
</html>
loggedout.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.org/ui"
  xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>LoggedOut.xhtml</title>
  </h:head>
  <h:body>
    Logged out.
  </h:body>
</html>

Test.java
package controlleryonetici;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean(name = "testManagedBean")
@ViewScoped
public class Test {
  private String name;
  private String passWord;
  private boolean userLogged = false;
  public String getPassWord() {
    return this.passWord;
  }
  public void setPassWord(final String passWord) {
    this.passWord = passWord;
  }
  public String getName() {
    return this.name;
  }
  public void setName(final String name) {
    this.name = name;
  }
  public void login() {
    if ("admin".equals(this.name) && "admin".equals(this.passWord))
      this.userLogged = true;
    }
    public boolean getUserLogged() {
      return this.userLogged;
    }
    public void setUserLogged(final boolean isUserLogged) {
      this.userLogged = isUserLogged;
  }
}
Demo

1. log in



2. alert



3. log out