Tuesday, February 3, 2015

Active MQ getting started -1: Producer/Consumer(Sender/Receiver)

Before ActiveMQ, I worked with JMS only on Application Servers such as Weblogic and Glassfish.
When I started my work with ActiveM, I was surprised, how easy is to work with it.

At this post I'm going to show how to use ActiveMQ in simple application : point-to-point message exchange :  Produces/Consumer(Sender/Receiver).

Theoretical information.

JMS : http://en.wikipedia.org/wiki/Java_Message_Service
The Java Message Service (JMS) API is a Java Message Oriented Middleware (MOM) API[1] for sending messages between two or more clients. JMS is a part of the Java Platform, Enterprise Edition, and is defined by a specification developed under the Java Community Process as JSR 914.[2] It is a messaging standard that allows application components based on the Java Enterprise Edition (Java EE) to create, send, receive, and read messages. It allows the communication between different components of adistributed application to be loosely coupled, reliable, and asynchronous.[3]

ActiveMQ: http://en.wikipedia.org/wiki/Apache_ActiveMQ
Apache ActiveMQ is an open source message broker written in Java together with a full Java Message Service (JMS) client. It provides "Enterprise Features" which in this case means fostering the communication from more than one client or server. Supported clients include Java via JMS 1.1 as well as several other "cross language" clients.[1] The communication is managed with features such as computer clustering and ability to use any database as a JMS persistence provider besides virtual memory, cache, andjournal persistency.[2]

Point-to-point model(from JMS wiki)

In point-to-point messaging system, messages are routed to an individual consumer which maintains a queue of "incoming" messages. This messaging type is built on the concept of message queues, senders, and receivers. Each message is addressed to a specific queue, and the receiving clients extract messages from the queues established to hold their messages. While any number of producers can send messages to the queue, each message is guaranteed to be delivered, and consumed by one consumer. Queues retain all messages sent to them until the messages are consumed or until the messages expire. If no consumers are registered to consume the messages, the queue holds them until a consumer registers to consume them.


Let's now create application(actually it will be 2 applications) to try how it(activeMQ) works.  

1. ActiveMQ message broker. 

First of all, before creating our application, we need to run message broker : ActiveMQ "server".
Let's create folder for that : mroker.
Next step - file mbroker/pom.xml :
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.demien.amq</groupId>
  <artifactId>mbroker</artifactId>
  <packaging>jar</packaging>
  <version>0.1</version>
  <name>mbroker</name>
  <url>http://maven.apache.org</url>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.activemq.tooling</groupId>
        <artifactId>maven-activemq-plugin</artifactId>
        <version>5.1</version>
        <configuration>
          <configUri>xbean:file:./conf/activemq.xml</configUri>
          <fork>false</fork>
          <systemProperties>
            <property>
              <name>javax.net.ssl.keyStorePassword</name>
              <value>password</value>
            </property>
            <property>
              <name>org.apache.activemq.default.directory.prefix</name>
              <value>./target/</value>
            </property>
          </systemProperties>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>2.5.5</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</project>

Also we need configuration file : mbroker/conf/activemq.xml
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:amq="http://activemq.apache.org/schema/core"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  http://activemq.apache.org/schema/core
  http://activemq.apache.org/schema/core/activemq-core.xsd
  ">
  <broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="./data">
    <!-- The transport connectors ActiveMQ will listen to -->
    <transportConnectors>
      <transportConnector name="openwire" uri="tcp://localhost:61616"/>
    </transportConnectors>
  </broker>
</beans>

Now we can run our message broker by command : 
mvn org.apache.activemq.tooling:maven-activemq-plugin:5.2.0:run


2. Test application. 

Now, when our message broker up and running, let's create our test application: 
Create directory test-app and place inside it next pom.xml file: 
test-app/pom.xml: 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.demien.amq</groupId>
  <artifactId>consumer</artifactId>
  <packaging>jar</packaging>
  <version>0.1</version>
  <name>consumer</name>
  <url>http://maven.apache.org</url>
  <dependencies>
   <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>javax.jms</groupId>
      <artifactId>jms</artifactId>
      <version>1.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.activemq</groupId>
     <artifactId>activemq-core</artifactId>
      <version>5.2.0</version>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>jboss</id>
      <url>http://repository.jboss.com/maven2</url>
      <releases>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
</project>



3. Producer.

For puplishing our message into message broker we have to create Producer class in testapp/src/main/java/com/demien/amq/

package com.demien.amq;
import javax.jms.*;
import java.io.Serializable;

public class Producer<T extends Serializable> {
    private Connection connection;
    private Session session;
    private MessageProducer producer;

    public Producer(ConnectionFactory factory, String queueName) throws JMSException {
        connection = factory.createConnection();
        connection.start();
        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination destination = session.createQueue(queueName);
        producer = session.createProducer(destination);
    }

    public void postObjectMessage(T object) throws JMSException {
        Message message = session.createObjectMessage(object);
        producer.send(message);
    }

    public void close() throws JMSException {
        if (connection != null) {
            connection.close();
        }
    }
}


4. Consumer

Consumer class will receive our messages from message broker and store them in local storage(ArrayList).
testapp/src/main/java/com/demien/amq/

package com.demien.amq;

import org.apache.activemq.command.ActiveMQObjectMessage;

import javax.jms.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Consumer<T extends Serializable> implements MessageListener {

    private Connection connection;
    private Session session;
    private MessageConsumer consumer;

    private List<T> messages = new ArrayList<T>();

    public Consumer(ConnectionFactory factory, String queueName) throws JMSException {
        connection = factory.createConnection();
        connection.start();
        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination destination = session.createQueue(queueName);
        consumer = session.createConsumer(destination);
        consumer.setMessageListener(this);
    }

    public List<T> getMessages() {
        return messages;
    }

    public void onMessage(Message message) {
        try {
            if (message instanceof ObjectMessage) {
                messages.add((T)((ActiveMQObjectMessage) message).getObject());
            } else {
                System.out.println("Invalid message received.");
            }
        } catch (Exception e) {
            System.out.println("Caught:" + e);
            e.printStackTrace();
        }
    }
}

5. Simple test object class, for using in tests.

Now we can create simple class for testing in our message exchange: 

package com.demien.amq;
import java.io.Serializable;

public class TestObject implements Serializable {
    public Long id;
    public String name;
}

6.Test itself.

In our test, we will try to post data into our query using producer and to read them using consumer.


package com.demien.amq;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import java.util.List;
import static org.junit.Assert.*;

public class AppTest  {

    public static String brokerURL = "tcp://localhost:61616";
    private final ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
    private final String queueName="TestQueue";

    Producer producer;
    Consumer consumer;

    @Before
    public void init() throws JMSException {
        producer=new Producer<TestObject>(factory, queueName);
        consumer=new Consumer<TestObject>(factory, queueName);
    }

    @After
    public void finish() throws JMSException {
        producer.close();
    }

    @Test
    public void singleMessageTest() throws JMSException, InterruptedException {
        Long TEST_ID=-1L;
        String TEST_NAME="test name";

        TestObject testObject=new TestObject();
        testObject.id=new Long(TEST_ID);
        testObject.name=new String(TEST_NAME);

        //post message
        producer.postObjectMessage(testObject);
        Thread.sleep(1000);

        //receive message
        List<TestObject> messages=consumer.getMessages();
        assertTrue(messages.size()>0);
        TestObject received=messages.get(0);
        assertTrue(received.name.equals(TEST_NAME));
        assertTrue(received.id.equals(TEST_ID));
    }
}

It message broker was started before running of test - it should run successfully. 

Full sources can be downloaded from here.

Wednesday, September 17, 2014

Active record domain model in Java with Spring and Hibernate

1. Goal.

As a developer, I want to create ability to use just entity object for performing base CRUD operation in DB, like:
myObject.save()
myObject.update()
myObject.delete()

2. Problem. 

The main problem here is obvious: transaction management. What it we are executing in one transaction:
object1.save();
object2.save();
and after that we have to rollback our transaction ? In case of anemic domain model business logic located at another(service) level:

@Transactional
pubic void doSomething(Object1 object1, Object2 object2) {
       Session session=sessionFactory.getCurrentSession();
       service1.save();
       service2.save();
       session.rollback();
}

Using anemic mode, at service level we can just mark method as @Transactional,  execute whole list of operations and after that  - commit or rollback transaction.
Using rich domain model, we have to think about transaction management.

3. Application context file.

In application context file we have to define data source bean(with connection to H2 database), session factory(with one domain class) bean and  abstract model bean - main(parent) class for our rich domain model.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd>">

    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.h2.Driver" />
        <property name="url" value="jdbc:h2:~/test" />
        <property name="username" value="sa" />
        <property name="password" value="sa" />
    </bean>

    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- Don't forget to list all your entity classes here -->
        <property name="annotatedClasses">
            <list>
                <value>com.demien.richdomain.model.User</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
            </props>
        </property>
    </bean>

    <bean id="AbstractModel" class="com.demien.richdomain.model.AbstractModel">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

</beans>

4. Abstract model

This class could be much simpler, but because of logic related with transactions I added few more procedures: setAutoCommit, setSession, checkAndStartTransaction, checkAndCommitTransaction.

package com.demien.richdomain.model;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class AbstractModel<T, PK extends Serializable> {

    protected static SessionFactory sessionFactory;
    protected Session session;
    protected boolean autoCommit=true;

    private Class<T> cl;

    public AbstractModel() {
    }

    public AbstractModel(Class<T> cl) {
        this.cl=cl;
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void setSessionFactory(SessionFactory sessionFactory) {
        AbstractModel.sessionFactory = sessionFactory;
    }

    protected Session getCurrentSession() {

        try {
            session=getSessionFactory().getCurrentSession();
        } catch (Exception e ) {

        }
        if (session == null) {
            session = getSessionFactory().openSession();
        }
        return session;
    }

    public Session getNewSession() {
        return getSessionFactory().openSession();
    }

    protected void setSession(Session session) {
        this.session=session;
    }

    protected void setAutoCommit(boolean autoCommit) {
        this.autoCommit=autoCommit;
    }

    public void checkAndStartTransaction() {
        if (autoCommit) {
            Session session = getCurrentSession();
            session.beginTransaction();
        }
    }

    public void checkAndCommitTransaction() {
        if (autoCommit) {
            session.getTransaction().commit();
        }
    }

    public T get(PK id) {
        Session session = getCurrentSession();
        checkAndStartTransaction();
        T element = (T) session.get(cl, id);
        checkAndCommitTransaction();
        return element;
    }

    public PK save() {
        Session session = getCurrentSession();
        checkAndStartTransaction();
        PK result=(PK)session.save(this);
        checkAndCommitTransaction();
        return result;
    }

    public void update() {
        Session session = getCurrentSession();
        checkAndStartTransaction();
        session.update(this);
        checkAndCommitTransaction();
    }

    public void delete() {
        Session session = getCurrentSession();
        checkAndStartTransaction();
        session.delete(this);
        checkAndCommitTransaction();
    }

    public List<T> query(String hsql, Map<String, Object> params) {

        Session session = getCurrentSession();
        checkAndStartTransaction();

        Query query = session.createQuery(hsql);
        if (params != null) {
            for (String i : params.keySet()) {
                query.setParameter(i, params.get(i));
            }
        }

        List<T> result = null;
        if ((hsql.toUpperCase().indexOf("DELETE") == -1)
                && (hsql.toUpperCase().indexOf("UPDATE") == -1)
                && (hsql.toUpperCase().indexOf("INSERT") == -1)) {
            result = query.list();
        } else {
            query.executeUpdate();
        }
        checkAndCommitTransaction();
        return result;
    }


    public List<T> getAll() {
        return query("from "+cl.getName(), null);
    }

    public void deleteAll() {
        query("delete from "+cl.getName(),null);

    }

}

Now we can just extend from this class: all child classes will have ability to work with database. 

5.Domain class which extends AbstactModel

It's just a POJO class which extends AbstractModel.

package com.demien.richdomain.model;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity(name = "USER")
public class User extends AbstractModel<User, Integer> implements Serializable {

    private static final long serialVersionUID = -7022793569839517729L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID")
    private Integer id;
    
    @Column(name = "LOGIN")
    private String login;
    
    @Column(name = "PASSWORD")
    private String password;
    

    public User() {
        super(User.class);
    }
    
    public User(String login, String password) {
        this();
        this.setLogin(login);
        this.setPassword(password);
    }
    
    public User(Integer id, String login, String password) {
        this();
        this.setId(id);
        this.setLogin(login);
        this.setPassword(password);
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    
    @Override
    public boolean equals(Object object) {
        if (!(object instanceof User)) {
            return false;
        } else {
            User user = (User) object;
            if (user.getId().equals(this.getId())
                    && user.getLogin().equals(this.getLogin())
                    && user.getPassword().equals(this.getPassword())) {
                return true;
            }
            return false;
        }
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", login=" + login + ", password=" + password
                + "]";
    }

}

6. Test with "simple transaction"

Let's test our class with "simple transaction": just one object associated with transaction.
    @Test
    public void simpleTest() {
        User user=new User("login", "password");
        int cnt0=user.getAll().size();

        Integer id=user.save();

        int cnt1=user.getAll().size();
        Assert.assertEquals(cnt0+1, cnt1);

        User user1=user.get(id);
        Assert.assertEquals(user, user1);

        user.setLogin("login_updated");
        user.update();

        user1.get(id);
        Assert.assertEquals("login_updated", user1.getLogin());
    }

So far, so good: it's very simple and easy to work with database by our object. 


7. Tests with "complex transaction"

If we want to use several objects associated with transaction logic is becoming much more complicated. We have to turn off transaction start(setAutoCommit method) in every object and also we have to provide all transaction object with one session object(setSession method).

  
    @Test
    public void transactionRollbackTest() {
        User user1=new User("login1","password1");
        User user2=new User("login2","password2");
        int cnt0=user1.getAll().size();

        user1.setAutoCommit(false);
        user2.setAutoCommit(false);

        Session session=user1.getNewSession();
        user1.setSession(session);
        user2.setSession(session);

        session.beginTransaction();
        user1.save();
        user2.save();
        session.getTransaction().rollback();

        int cnt1=user1.getAll().size();
        Assert.assertEquals(cnt0, cnt1);

    }

    @Test
    public void transactionCommitTest() {
        User user1=new User("login1","password1");
        User user2=new User("login2","password2");
        int cnt0=user1.getAll().size();

        user1.setAutoCommit(false);
        user2.setAutoCommit(false);

        Session session=user1.getNewSession();
        user1.setSession(session);
        user2.setSession(session);

        session.beginTransaction();
        user1.save();
        user2.save();
        session.getTransaction().commit();

        int cnt1=user1.getAll().size();
        Assert.assertEquals(cnt0+2, cnt1);

    }

8. Conclusion

As for me, active record model can be used in projects with simple transactions. But if there are a lot of complex transaction it's better to use anemic model with logic at service(not domain) level.  

Source code can be downloaded from here.

Sunday, September 7, 2014

Behavioral patterns in Java - Part 2

From Wikipedia, the free encyclopedia

In software engineering, behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.


1. Observer

Actors:
 1. event source(observable) - class which has method for registering (adding) observers
 2. event handler(observer) - class which has method for reacting on event
Goal: event source is notifying observers objects

Main class:

public class Observer {
    
    StringBuilder log=new StringBuilder();
    
    public String getLog() {
        return log.toString();
    }
    
    public interface EventHandler {
        void onEvent(String event);
    }
    
    public class FirstHandler implements EventHandler {
        @Override
        public void onEvent(String event) {
            log.append("first:"+event+";");         
        }       
    }
    
    public class SecondHandler implements EventHandler {
        @Override
        public void onEvent(String event) {
            log.append("second:"+event+";");            
        }       
    }   
    
    public class EventSource {
        List<EventHandler> eventHandlers=new ArrayList<EventHandler>();
        
        public void addEventHandler(EventHandler handler) {
            eventHandlers.add(handler);
        }
        
        public void createEvent(String event) {
            for (EventHandler eventHandler: eventHandlers) {
                eventHandler.onEvent(event);
            }
        }
    }
    

}

Test class:

public class ObserverTest {

    @Test
    public void test() {
        Observer observer=new Observer();
        Observer.FirstHandler firstHandler=observer. new FirstHandler();
        Observer.SecondHandler secondHandler=observer. new SecondHandler();
        Observer.EventSource eventSource=observer. new EventSource();
        eventSource.addEventHandler(firstHandler);
        eventSource.addEventHandler(secondHandler);
        eventSource.createEvent("test");
        assertEquals("first:test;second:test;", observer.getLog());
        
    }

}

2. State

Actors: 
 1. set of state objects 
 2. object which can be in different states(with different assignments of state object)
 Goal: object behavior depends on it state (state object) 

Main class:

public class State {

    public interface ShapeState {
        String executeAction();
    }

    public class CreateShapeState implements ShapeState {

        @Override
        public String executeAction() {
            return "create";
        }

    }

    public class DrawShapeState implements ShapeState {

        @Override
        public String executeAction() {
            return "draw";
        }

    }

    public class Shape {
        private ShapeState state;

        public ShapeState getState() {
            return state;
        }

        public void setState(ShapeState state) {
            this.state = state;
        }

        public String executeAction() {
            return state.executeAction();
        }
    }

}

Test class:

public class StateTest {

    @Test
    public void test() {
        State state=new State();
        
        State.Shape shape=state. new Shape();
        shape.setState(state. new CreateShapeState() );
        
        assertEquals("create", shape.executeAction());
        
        shape.setState(state. new DrawShapeState() );
        
        assertEquals("draw", shape.executeAction());

    }

}

3. Strategy

Actors: 
 1. Strategy object 
 2. Context object which have Strategy object 
 Goal: context execute action using strategy object so execution is based on strategy


Main class:



public class Strategy {
    
    interface DrawStrategy {
        String draw();
    }
    
    public class FastDrawStrategy implements DrawStrategy {
        @Override
        public String draw() {
            return "fast draw";
        }       
    }

    public class SlowDrawStrategy implements DrawStrategy {
        @Override
        public String draw() {
            return "slow draw";
        }       
    }   
    
    public class Context {
        DrawStrategy strategy;
                
        public void setStrategy(DrawStrategy strategy) {
            this.strategy=strategy;
        }
        
        public String executeStrategy() {
            return strategy.draw();
        }
    }
    
}

Test class:

public class StrategyTest {

    @Test
    public void test() {
        Strategy strategy=new Strategy();
        Strategy.FastDrawStrategy fastDrawStrategy=strategy. new FastDrawStrategy();
        Strategy.SlowDrawStrategy slowDrawStrategy=strategy. new SlowDrawStrategy();
        Strategy.Context context=strategy. new Context();

        context.setStrategy(fastDrawStrategy);
        assertEquals("fast draw", context.executeStrategy());

        context.setStrategy(slowDrawStrategy);
        assertEquals("slow draw", context.executeStrategy());
        
    }

}

4. Template

Actors: 1. template class: one method of it can not be overriden - it is a TEMPLATE method 2. subclasses of template class Goal: strictly defined template of logic execution. detail of execution can be different for subclasses, by overriding non template methods

Main class:


public class Template {

    public abstract class ShapeTemplate {
        public abstract String create();

        public abstract String draw();

        public String createAndDraw() {
            return create() + "." + draw();
        }
    }

    public class FastShape extends ShapeTemplate {

        @Override
        public String create() {
            return "fast create";
        }

        @Override
        public String draw() {
            return "fast draw";
        }
    }

    public class SlowShape extends ShapeTemplate {

        @Override
        public String create() {
            return "slow create";
        }

        @Override
        public String draw() {
            return "slow draw";
        }
    }
}

Test class:

public class TemplateTest {

    @Test
    public void test() {
        Template template=new Template();
        Template.FastShape fastShape=template. new FastShape();
        Template.SlowShape slowShape=template. new SlowShape();
        //
        String result="";
        result=fastShape.createAndDraw();
        assertEquals("fast create.fast draw", result);
        result=slowShape.createAndDraw();
        assertEquals("slow create.slow draw", result);
        
    }

}

5. Visitor

 Actors:
 1. Visitor. several visit(Element) - for every subclass of Element.
 2.Element. Element has accept(Visitor) method.
 Goal: logic separation: element calls visitor's method, which calls element's method

Main class:

public class Visitor {

    public interface ShapeVisitor {
        public String visit(Circle element);
        public String visit(Square element);
    }

    public abstract class Shape {
        public abstract void accept(ShapeVisitor visitor);

        public String draw() {
            return "drawing";
        };
    }

    public class Circle extends Shape {

        @Override
        public void accept(ShapeVisitor visitor) {
            visitor.visit(this);
        }

    }

    public class Square extends Shape {

        @Override
        public void accept(ShapeVisitor visitor) {
            visitor.visit(this);
        }

    }

    public class FastShapeVisitor implements ShapeVisitor {

        @Override
        public String visit(Circle element) {
            return "fast circle "+element.draw();
        }

        @Override
        public String visit(Square element) {
            return "fast square "+element.draw();
        }
    }
}


Test class:


public class VisitorTest {

    @Test
    public void visitorTest() {
        Visitor visitor=new Visitor();
        Visitor.FastShapeVisitor fastShapeVisitor=visitor. new FastShapeVisitor();
        Visitor.Circle circle=visitor.new Circle();
        Visitor.Square square=visitor. new Square();
        String result="";
        result=fastShapeVisitor.visit(circle);
        Assert.assertEquals("fast circle drawing", result);
        result=fastShapeVisitor.visit(square);
        Assert.assertEquals("fast square drawing", result);

    }

}