Java Standalone & Socket Application with Spring Framework + JPA + Hibernate + c3p0 + MySQL!

This is going to be quite long!

I am running the sample Sakila database that MySQL provides.
  • Spring Profiles in Action!
  • Proper Model-View-Controller implementation! (I think..)
  • Single Threaded - Console View Option!
  • Multi Threaded - Network View Option!
  • MySQL DB - c3p0 Connection Pool - JPA with Hibernate implementation!
  • Small classes, smaller methods!
  • Downloadable from this link!

Directory Layout

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
    <packaging>jar</packaging>
 
    <groupId>biz.tugay</groupId>
    <artifactId>sakilaconsole</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <dependencies>
 
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.1</version>
        </dependency>
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.0.5.RELEASE</version>
        </dependency>
 
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>javax.persistence</artifactId>
            <version>2.1.1</version>
        </dependency>
 
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.1.0.Final</version>
            <scope>runtime</scope>
        </dependency>
 
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.1.0.Final</version>
            <scope>runtime</scope>
        </dependency>
 
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>5.1.0.Final</version>
            <scope>runtime</scope>
        </dependency>
 
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
            <scope>runtime</scope>
        </dependency>
 
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.5.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <executable>mvn</executable>
                    <mainClass>biz.tugay.sakilaconsole.AppBootstrap</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="sakiladb" transaction-type="RESOURCE_LOCAL">
        <properties/>
    </persistence-unit>
</persistence>

hibernate.properties
# suppress inspection "UnusedProperty" for whole file
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/sakila
hibernate.connection.username=root
hibernate.connection.password=root
hibernate.connection.useUnicode=true
hibernate.connection.characterEncoding=utf-8
hibernate.connection.useSSL=false
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update
 
hibernate.c3p0.min_size=2
hibernate.c3p0.max_size=3
hibernate.c3p0.timeout=300
hibernate.c3p0.max_statements=5
hibernate.c3p0.unreturnedConnectionTimeout=2

Model Layer

BaseModel.java
package biz.tugay.sakilaconsole.model.entity;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/7/2016
 * Time: 9:56 PM
 */
public abstract class BaseModel {
    public abstract Integer getId();
    public abstract String getText();
}

Actor.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.*;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 9:49 AM
 */
 
@Entity
public class Actor extends BaseModel {
 
    private Integer id;
    private String firstname;
    private String lastname;
 
    private List<FilmActor> filmActors;
 
    @Id
    @Column(name = "actor_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer actor_id) {
        this.id = actor_id;
    }
 
    @Basic
    @Column(name = "first_name")
    public String getFirstname() {
        return firstname;
    }
 
    public void setFirstname(String first_name) {
        this.firstname = first_name;
    }
 
    @Basic
    @Column(name = "last_name")
    public String getLastname() {
        return lastname;
    }
 
    public void setLastname(String last_name) {
        this.lastname = last_name;
    }
 
    @OneToMany(mappedBy = "actor")
    public List<FilmActor> getFilmActors() {
        return filmActors;
    }
 
    public void setFilmActors(List<FilmActor> filmActors) {
        this.filmActors = filmActors;
    }
 
    @Override
    @Transient
    public String getText() {
        return firstname + " " + lastname;
    }
}

Film.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.*;
import java.util.Collection;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 10:03 AM
 */
 
@Entity
public class Film extends BaseModel {
 
    private Integer id;
    private String title;
    private String rating;
 
    private Collection<FilmActor> filmActors;
    private Collection<FilmCategory> filmCategories;
 
    @Id
    @Column(name = "film_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    @Basic
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    @Basic
    public String getRating() {
        return rating;
    }
 
    public void setRating(String rating) {
        this.rating = rating;
    }
 
    @OneToMany(mappedBy = "film")
    public Collection<FilmActor> getFilmActors() {
        return filmActors;
    }
 
    public void setFilmActors(Collection<FilmActor> filmActors) {
        this.filmActors = filmActors;
    }
 
    @OneToMany(mappedBy = "film")
    public Collection<FilmCategory> getFilmCategories() {
        return filmCategories;
    }
 
    public void setFilmCategories(Collection<FilmCategory> filmCategories) {
        this.filmCategories = filmCategories;
    }
 
    @Override
    @Transient
    public String getText() {
        return title + "(" + rating + ")";
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
 
        Film film = (Film) o;
 
        if (!id.equals(film.id)) return false;
        if (!title.equals(film.title)) return false;
 
        return true;
    }
 
    @Override
    public int hashCode() {
        int result = id.hashCode();
        result = 31 * result + title.hashCode();
        return result;
    }
}

Category.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.*;
import java.util.Collection;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/1/2016
 * Time: 7:55 PM
 */
 
@Entity
public class Category extends BaseModel {
 
    private Integer id;
 
    private String name;
    private Collection<FilmCategory> filmCategories;
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "category_id")
    public Integer getId() {
        return id;
    }
 
    @Override
    @Transient
    public String getText() {
        return name;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    @Basic
    @Column(name = "name", length = 25)
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @OneToMany(mappedBy = "category")
    public Collection<FilmCategory> getFilmCategories() {
        return filmCategories;
    }
 
    public void setFilmCategories(Collection<FilmCategory> filmCategories) {
        this.filmCategories = filmCategories;
    }
}

FilmActorPK.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/2/2016
 * Time: 5:59 PM
 */
 
@Embeddable
public class FilmActorPK implements Serializable {
 
    private int actorId;
    private int filmId;
 
    @Column(name = "actor_id")
    public int getActorId() {
        return actorId;
    }
 
    public void setActorId(int actorId) {
        this.actorId = actorId;
    }
 
    @Column(name = "film_id")
    public int getFilmId() {
        return filmId;
    }
 
    public void setFilmId(int filmId) {
        this.filmId = filmId;
    }
}

FilmActor.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.*;
import java.sql.Timestamp;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/2/2016
 * Time: 5:52 PM
 */
 
@SuppressWarnings("unused")
@Entity
@Table(name = "film_actor")
public class FilmActor {
 
    private FilmActorPK id;
 
    private Film film;
    private Actor actor;
    private Timestamp lastUpdate;
 
    @EmbeddedId
    public FilmActorPK getId() {
        return id;
    }
 
    public void setId(FilmActorPK id) {
        this.id = id;
    }
 
    @ManyToOne
    @MapsId("film")
    @JoinColumn(name = "film_id")
    public Film getFilm() {
        return film;
    }
 
    public void setFilm(Film film) {
        this.film = film;
    }
 
    @ManyToOne
    @MapsId("actor")
    @JoinColumn(name = "actor_id")
    public Actor getActor() {
        return actor;
    }
 
    public void setActor(Actor actor) {
        this.actor = actor;
    }
 
    @Column(name = "last_update")
    public Timestamp getLastUpdate() {
        return lastUpdate;
    }
 
    public void setLastUpdate(Timestamp lastUpdate) {
        this.lastUpdate = lastUpdate;
    }
}

FilmCategoryPK.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/9/2016
 * Time: 7:29 PM
 */
 
@Embeddable
public class FilmCategoryPK implements Serializable {
 
    private int categoryId;
    private int filmId;
 
    @Column(name = "category_id")
    public int getCategoryId() {
        return categoryId;
    }
 
    public void setCategoryId(int categoryId) {
        this.categoryId = categoryId;
    }
 
    @Column(name = "film_id")
    public int getFilmId() {
        return filmId;
    }
 
    public void setFilmId(int filmId) {
        this.filmId = filmId;
    }
}

FilmCategory.java
package biz.tugay.sakilaconsole.model.entity;
 
import javax.persistence.*;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/9/2016
 * Time: 7:28 PM
 */
 
@SuppressWarnings("unused")
@Entity
@Table(name = "film_category")
public class FilmCategory {
 
    private FilmCategoryPK filmCategoryPK;
    private Film film;
    private Category category;
 
    @EmbeddedId
    public FilmCategoryPK getFilmCategoryPK() {
        return filmCategoryPK;
    }
 
    public void setFilmCategoryPK(FilmCategoryPK filmCategoryPK) {
        this.filmCategoryPK = filmCategoryPK;
    }
 
    @ManyToOne
    @MapsId("film")
    @JoinColumn(name = "film_id")
    public Film getFilm() {
        return film;
    }
 
    public void setFilm(Film film) {
        this.film = film;
    }
 
    @ManyToOne
    @MapsId("category")
    @JoinColumn(name = "category_id")
    public Category getCategory() {
        return category;
    }
 
    public void setCategory(Category category) {
        this.category = category;
    }
}

PersistenceUtil.java
package biz.tugay.sakilaconsole.model.persistence;
 
import javax.persistence.EntityManager;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 12:49 PM
 */
public interface PersistenceUtil {
    EntityManager getEntityManager();
    void closeFactory();
}

PersistenceUtilImpl.java
package biz.tugay.sakilaconsole.model.persistence;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/16/2016
 * Time: 4:06 PM
 */
public final class PersistenceUtilImpl implements PersistenceUtil {
 
    private EntityManagerFactory entityManagerFactory;
 
    public PersistenceUtilImpl(final String persistenceUnit) {
        entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnit);
    }
 
    public EntityManager getEntityManager() {
        final EntityManager entityManager = entityManagerFactory.createEntityManager();
        return entityManager;
    }
 
    public void closeFactory() {
        entityManagerFactory.close();
    }
}

ActorService.java
package biz.tugay.sakilaconsole.model.service;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
import biz.tugay.sakilaconsole.model.entity.Film;
 
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 1:40 PM
 */
public interface ActorService {
    List<Actor> allActors();
    List<Actor> actorsLimitBy(int limit);
    Actor getActorById(int actorId);
    List<Actor> getActorsOfFilm(Film film);
}

ActorServiceImpl.java
package biz.tugay.sakilaconsole.model.service.impl;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
import biz.tugay.sakilaconsole.model.entity.Film;
import biz.tugay.sakilaconsole.model.entity.FilmActor;
import biz.tugay.sakilaconsole.model.persistence.PersistenceUtil;
import biz.tugay.sakilaconsole.model.service.ActorService;
 
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 12:03 PM
 */
public final class ActorServiceImpl implements ActorService {
 
    private final PersistenceUtil persistenceUtil;
 
    public ActorServiceImpl(PersistenceUtil persistenceUtil) {
        this.persistenceUtil = persistenceUtil;
    }
 
    @Override
    public List<Actor> allActors() {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final TypedQuery<Actor> query = entityManager.createQuery("SELECT a FROM Actor a", Actor.class);
        final List<Actor> allActors = query.getResultList();
        entityManager.close();
        return allActors;
    }
 
    @Override
    public List<Actor> actorsLimitBy(int limit) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final TypedQuery<Actor> query = entityManager.createQuery("SELECT a FROM Actor a", Actor.class);
        query.setMaxResults(limit);
        final List<Actor> actorsLimitBy = query.getResultList();
        entityManager.close();
        return actorsLimitBy;
    }
 
    @Override
    public Actor getActorById(int actorId) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final Actor actor = entityManager.find(Actor.class, actorId);
        entityManager.close();
        return actor;
    }
 
    @Override
    public List<Actor> getActorsOfFilm(Film film) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final Film persistFilm = entityManager.find(Film.class, film.getId());
        // Load lazy fetched Actors of the film..
        final ArrayList<Actor> actors = new ArrayList<Actor>();
        final Collection<FilmActor> filmActors = persistFilm.getFilmActors();
        for (FilmActor filmActor : filmActors) {
            actors.add(filmActor.getActor());
        }
        entityManager.close();
        return actors;
    }
}

FilmService.java
package biz.tugay.sakilaconsole.model.service;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
import biz.tugay.sakilaconsole.model.entity.Category;
import biz.tugay.sakilaconsole.model.entity.Film;
 
import java.util.Collection;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 1:40 PM
 */
public interface FilmService {
    List<Film> allFilms();
    Film filmById(int filmId);
    List<Film> filmsOfActor(Actor actor);
    Collection<Film> filmsActorsTogether(Actor a, Actor b);
    Collection<Film> filmsByCategory(Category category);
}

FilmServiceImpl.java
package biz.tugay.sakilaconsole.model.service.impl;
 
import biz.tugay.sakilaconsole.model.entity.*;
import biz.tugay.sakilaconsole.model.persistence.PersistenceUtil;
import biz.tugay.sakilaconsole.model.service.FilmService;
import org.apache.commons.collections4.CollectionUtils;
 
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 12:40 PM
 */
public final class FilmServiceImpl implements FilmService {
 
    private final PersistenceUtil persistenceUtil;
 
    public FilmServiceImpl(final PersistenceUtil persistenceUtil) {
        this.persistenceUtil = persistenceUtil;
    }
 
    @Override
    public List<Film> allFilms() {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final TypedQuery<Film> query = entityManager.createQuery("SELECT f FROM Film f", Film.class);
        final List<Film> allFilms = query.getResultList();
        entityManager.close();
        return allFilms;
    }
 
    @Override
    public Film filmById(int filmId) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final Film film = entityManager.find(Film.class, filmId);
        entityManager.close();
        return film;
    }
 
    @Override
    public List<Film> filmsOfActor(Actor actor) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final Actor persistentActor = entityManager.find(Actor.class, actor.getId());
        final ArrayList<Film> films = new ArrayList<Film>();
        for (FilmActor filmActor : persistentActor.getFilmActors()) {
            films.add(filmActor.getFilm());
        }
        entityManager.close();
        return films;
    }
 
    @Override
    public Collection<Film> filmsActorsTogether(Actor a, Actor b) {
        final List<Film> filmsOfActorA = filmsOfActor(a);
        final List<Film> filmsOfActorB = filmsOfActor(b);
        final Collection<Film> intersection = CollectionUtils.intersection(filmsOfActorA, filmsOfActorB);
        return intersection;
    }
 
    @Override
    public Collection<Film> filmsByCategory(Category category) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        category = entityManager.find(Category.class, category.getId());
        final ArrayList<Film> films = new ArrayList<Film>();
        for (FilmCategory filmCategory : category.getFilmCategories()) {
            films.add(filmCategory.getFilm());
        }
        entityManager.close();
        return films;
    }
}

CategoryService.java
package biz.tugay.sakilaconsole.model.service;
 
import biz.tugay.sakilaconsole.model.entity.Category;
 
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/1/2016
 * Time: 7:57 PM
 */
public interface CategoryService {
    List<Category> allCategories();
    Category byId(int categoryId);
}

CategoryServiceImpl.java
package biz.tugay.sakilaconsole.model.service.impl;
 
import biz.tugay.sakilaconsole.model.entity.Category;
import biz.tugay.sakilaconsole.model.persistence.PersistenceUtil;
import biz.tugay.sakilaconsole.model.service.CategoryService;
 
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/1/2016
 * Time: 7:58 PM
 */
public final class CategoryServiceImpl implements CategoryService {
 
    private final PersistenceUtil persistenceUtil;
 
    public CategoryServiceImpl(PersistenceUtil persistenceUtil) {
        this.persistenceUtil = persistenceUtil;
    }
 
    @Override
    public List<Category> allCategories() {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final TypedQuery<Category> query = entityManager.createQuery("SELECT c FROM Category c", Category.class);
        final List<Category> allCategories = query.getResultList();
        entityManager.close();
        return allCategories;
    }
 
    @Override
    public Category byId(int categoryId) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final Category category = entityManager.find(Category.class, categoryId);
        entityManager.close();
        return category;
    }
}

FilmActorService.java
package biz.tugay.sakilaconsole.model.service;
 
import biz.tugay.sakilaconsole.model.entity.FilmActor;
 
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/2/2016
 * Time: 6:23 PM
 */
public interface FilmActorService {
    List<FilmActor> filmActorsLastUpdatedSince(int year);
}

FilmActorServiceImpl.java
package biz.tugay.sakilaconsole.model.service.impl;
 
import biz.tugay.sakilaconsole.model.entity.FilmActor;
import biz.tugay.sakilaconsole.model.persistence.PersistenceUtil;
import biz.tugay.sakilaconsole.model.service.FilmActorService;
 
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Calendar;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/2/2016
 * Time: 6:28 PM
 */
public class FilmActorServiceImpl implements FilmActorService {
 
    private final PersistenceUtil persistenceUtil;
 
    public FilmActorServiceImpl(PersistenceUtil persistenceUtil) {
        this.persistenceUtil = persistenceUtil;
    }
 
    @Override
    public List<FilmActor> filmActorsLastUpdatedSince(int year) {
        final EntityManager entityManager = persistenceUtil.getEntityManager();
        final TypedQuery<FilmActor> query = entityManager.createQuery("SELECT fa FROM FilmActor fa WHERE fa.lastUpdate > :lastUpdate", FilmActor.class);
        final Calendar instance = Calendar.getInstance();
        instance.set(Calendar.YEAR, year);
        query.setParameter("lastUpdate", instance.getTime());
        final List<FilmActor> filmActors = query.getResultList();
        entityManager.close();
        return filmActors;
    }
}

View Layer

View.java
package biz.tugay.sakilaconsole.view;
 
import biz.tugay.sakilaconsole.model.entity.BaseModel;
 
import java.util.Collection;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/7/2016
 * Time: 9:55 PM
 */
public interface View<T extends BaseModel> {
    void print(Collection<T> list);
    int askForId();
}

AbstractViewImpl.java
package biz.tugay.sakilaconsole.view.impl;
 
import biz.tugay.sakilaconsole.model.entity.BaseModel;
import biz.tugay.sakilaconsole.view.helper.IOResolver;
import biz.tugay.sakilaconsole.view.View;
import org.springframework.beans.factory.annotation.Required;
 
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Scanner;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/7/2016
 * Time: 9:57 PM
 */
public abstract class AbstractViewImpl<T extends BaseModel> implements View<T> {
 
    protected IOResolver ioResolver;
 
    @Override
    public void print(Collection<T> collection) {
        final PrintWriter writer = ioResolver.writer(Thread.currentThread());
        writer.println("== Printing" + getClass().getSimpleName() + " ==");
        for (T t : collection) {
            writer.println(t.getId() + "\t" + t.getText());
        }
        writer.flush();
    }
 
    public int askForId() {
        final PrintWriter writer = ioResolver.writer(Thread.currentThread());
        writer.println("Please enter " + getClass().getSimpleName() + " ID:");
        writer.flush();
        final Scanner scanner = new Scanner(ioResolver.inputStream(Thread.currentThread()));
        int id = scanner.nextInt();
        return id;
    }
 
    @Required
    public void setIoResolver(IOResolver ioResolver) {
        this.ioResolver = ioResolver;
    }
}

MainMenuView.java
package biz.tugay.sakilaconsole.view;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 21:32 PM
 */
public interface MainMenuView {
    void greetUser();
    int getUserInput();
}

MainMenuViewImpl.java
package biz.tugay.sakilaconsole.view.impl;
 
import biz.tugay.sakilaconsole.controller.AppOption;
import biz.tugay.sakilaconsole.view.MainMenuView;
import biz.tugay.sakilaconsole.view.helper.IOResolver;
 
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Scanner;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 17:47 PM
 */
public class MainMenuViewImpl implements MainMenuView {
 
    protected final IOResolver ioResolver;
 
    public MainMenuViewImpl(IOResolver ioResolver) {
        this.ioResolver = ioResolver;
    }
 
    @Override
    public void greetUser() {
        final PrintWriter writer = ioResolver.writer(Thread.currentThread());
        writer.println("Please select:");
        final AppOption[] appOptions = AppOption.values();
        for (AppOption appOption : appOptions) {
            writer.println(appOption.getKey() + " - " + appOption.getValue());
        }
        writer.flush();
    }
 
    @Override
    public int getUserInput() {
        final InputStream inputStream = ioResolver.inputStream(Thread.currentThread());
        final Scanner scanner = new Scanner(inputStream);
        final int userSelection = scanner.nextInt();
        return userSelection;
    }
}

ActorView.java
package biz.tugay.sakilaconsole.view;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 2:17 PM
 */
public interface ActorView extends View<Actor> {
}

ActorViewImpl.java
package biz.tugay.sakilaconsole.view.impl;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
import biz.tugay.sakilaconsole.view.ActorView;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 12:11 PM
 */
public class ActorViewImpl extends AbstractViewImpl<Actor> implements ActorView {
}

FilmView.java
package biz.tugay.sakilaconsole.view;
 
import biz.tugay.sakilaconsole.model.entity.Film;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 2:19 PM
 */
public interface FilmView extends View<Film> {
}

FilmViewImpl.java
package biz.tugay.sakilaconsole.view.impl;
 
import biz.tugay.sakilaconsole.model.entity.Film;
import biz.tugay.sakilaconsole.view.FilmView;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 12:41 PM
 */
public class FilmViewImpl extends AbstractViewImpl<Film> implements FilmView {
}

CategoryView.java
package biz.tugay.sakilaconsole.view;
 
import biz.tugay.sakilaconsole.model.entity.Category;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/9/2016
 * Time: 7:50 PM
 */
public interface CategoryView extends View<Category> {
}

CategoryViewImpl.java
package biz.tugay.sakilaconsole.view.impl;
 
import biz.tugay.sakilaconsole.model.entity.Category;
import biz.tugay.sakilaconsole.view.CategoryView;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/9/2016
 * Time: 7:51 PM
 */
public class CategoryViewImpl extends AbstractViewImpl<Category> implements CategoryView {
}

IOResolver.java
package biz.tugay.sakilaconsole.view.helper;
 
import java.io.InputStream;
import java.io.PrintWriter;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 16:41 PM
 */
public interface IOResolver {
 
    InputStream inputStream(Thread thread);
    PrintWriter writer(Thread thread);
}

ConsoleIOResolverImpl.java
package biz.tugay.sakilaconsole.view.helper.impl;
 
import biz.tugay.sakilaconsole.view.helper.IOResolver;
 
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 16:42 PM
 */
public final class ConsoleIOResolverImpl implements IOResolver {
 
    public InputStream inputStream(Thread thread) {
        final InputStream in = System.in;
        return in;
    }
 
    public PrintWriter writer(Thread thread) {
        final PrintStream out = System.out;
        final PrintWriter writer = new PrintWriter(out);
        return writer;
    }
}

NetworkIOResolverImpl.java
package biz.tugay.sakilaconsole.view.helper.impl;
 
import biz.tugay.sakilaconsole.view.helper.IOResolver;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 16:47 PM
 */
public class NetworkIOResolverImpl implements IOResolver {
 
    private Map<Thread, Socket> threadSocketMap = new HashMap<Thread, Socket>();
 
    @Override
    public InputStream inputStream(Thread thread) {
        try {
            final Socket socket = threadSocketMap.get(thread);
            final InputStream inputStream = socket.getInputStream();
            return inputStream;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
 
    @Override
    public PrintWriter writer(Thread thread) {
        try {
            final Socket socket = threadSocketMap.get(thread);
            final OutputStream outputStream = socket.getOutputStream();
            final PrintWriter writer = new PrintWriter(outputStream);
            return writer;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
 
    public void add(Thread thread, Socket socket) {
        threadSocketMap.put(thread, socket);
    }
 
    public Socket socketFor(Thread thread) {
        final Socket socket = threadSocketMap.get(thread);
        return socket;
    }
}

Controller Layer

MainMenuController.java
package biz.tugay.sakilaconsole.controller;
 
import biz.tugay.sakilaconsole.controller.helper.AppOptionProcessor;
import biz.tugay.sakilaconsole.view.MainMenuView;
import org.springframework.beans.factory.annotation.Required;
 
import java.io.IOException;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 2:26 PM
 */
public class MainMenuController {
 
    private final MainMenuView mainMenuView;
    private List<AppOptionProcessor> appOptionProcessorList;
 
    public MainMenuController(MainMenuView mainMenuView) {
        this.mainMenuView = mainMenuView;
    }
 
    public void showMainMenu() throws IOException, InterruptedException {
        mainMenuView.greetUser();
        final int userInput = mainMenuView.getUserInput();
        if (userInput != -1) {
            processUserInput(userInput);
            showMainMenu();
        }
    }
 
    private void processUserInput(int userInput) {
        final AppOption appOption = AppOption.byKey(userInput);
        for (AppOptionProcessor appOptionProcessor : appOptionProcessorList) {
            appOptionProcessor.processAppOption(appOption);
        }
    }
 
    @Required
    public void setAppOptionProcessorList(List<AppOptionProcessor> appOptionProcessorList) {
        this.appOptionProcessorList = appOptionProcessorList;
    }
}

ActorController.java
package biz.tugay.sakilaconsole.controller;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
import biz.tugay.sakilaconsole.model.entity.Film;
import biz.tugay.sakilaconsole.model.service.ActorService;
import biz.tugay.sakilaconsole.view.ActorView;
 
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 2:44 PM
 */
public final class ActorController {
 
    private final ActorView actorView;
    private final ActorService actorService;
 
    public ActorController(ActorView actorView, ActorService actorService) {
        this.actorView = actorView;
        this.actorService = actorService;
    }
 
    public void listAllActors() {
        final List<Actor> actors = actorService.allActors();
        actorView.print(actors);
    }
 
    public Actor askForActorId() {
        int actorId = actorView.askForId();
        final Actor actor = actorService.getActorById(actorId);
        return actor;
    }
 
    public void printActorsOfFilm(Film film) {
        final List<Actor> actors = actorService.getActorsOfFilm(film);
        actorView.print(actors);
    }
}

FilmController.java
package biz.tugay.sakilaconsole.controller;
 
import biz.tugay.sakilaconsole.model.entity.Actor;
import biz.tugay.sakilaconsole.model.entity.Category;
import biz.tugay.sakilaconsole.model.entity.Film;
import biz.tugay.sakilaconsole.model.service.FilmService;
import biz.tugay.sakilaconsole.view.FilmView;
 
import java.util.Collection;
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 2:51 PM
 */
public class FilmController {
 
    private final FilmService filmService;
    private final FilmView filmView;
 
    public FilmController(FilmService filmService, FilmView filmView) {
        this.filmService = filmService;
        this.filmView = filmView;
    }
 
    public void printFilmsOfActor(Actor actor) {
        final List<Film> films = filmService.filmsOfActor(actor);
        filmView.print(films);
    }
 
    public void listAllFilms() {
        final List<Film> films = filmService.allFilms();
        filmView.print(films);
    }
 
    public Film askForFilmById() {
        final int filmId = filmView.askForId();
        final Film film = filmService.filmById(filmId);
        return film;
    }
 
    public void printFilmsActorsTogether(Actor actor_1, Actor actor_2) {
        final Collection<Film> films = filmService.filmsActorsTogether(actor_1, actor_2);
        filmView.print(films);
    }
 
    public void printFilmsOfCategory(Category category) {
        final Collection<Film> films = filmService.filmsByCategory(category);
        filmView.print(films);
    }
}

CategoryController.java
package biz.tugay.sakilaconsole.controller;
 
import biz.tugay.sakilaconsole.model.entity.Category;
import biz.tugay.sakilaconsole.model.service.CategoryService;
import biz.tugay.sakilaconsole.view.CategoryView;
 
import java.util.List;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/9/2016
 * Time: 7:46 PM
 */
public class CategoryController {
 
    private CategoryService categoryService;
    private CategoryView categoryView;
 
    public CategoryController(CategoryService categoryService, CategoryView categoryView) {
        this.categoryService = categoryService;
        this.categoryView = categoryView;
    }
 
    public void listAll() {
        final List<Category> categories = categoryService.allCategories();
        categoryView.print(categories);
    }
 
    public Category askForId() {
        int categoryId = categoryView.askForId();
        Category category = categoryService.byId(categoryId);
        return category;
    }
}

AppOption.java
package biz.tugay.sakilaconsole.controller;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 21:41 PM
 */
public enum AppOption {
 
    FILMS_BY_ACTOR(1, "Find Films by Actor"),
    ACTORS_OF_FILM(2, "Find Actors of a Film"),
    FILMS_ACTORS_TOGETHER(3, "Find Films where 2 Actors acted together"),
    FILMS_BY_CATEGORY(4, "Find Films by Category"),
    QUIT_PROGRAM(-1, "Quit Program");
 
    private int key;
    private String value;
 
    AppOption(int key, String value) {
        this.key = key;
        this.value = value;
    }
 
    public int getKey() {
        return key;
    }
 
    public String getValue() {
        return value;
    }
 
    static AppOption byKey(int key) {
        for (AppOption appOption : AppOption.values()) {
            if (appOption.key == key) {
                return appOption;
            }
        }
        return null;
    }
}

AppOptionProcessor.java
package biz.tugay.sakilaconsole.controller.helper;
 
import biz.tugay.sakilaconsole.controller.AppOption;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/13/2016
 * Time: 9:29 AM
 */
public interface AppOptionProcessor {
 
    void processAppOption(AppOption appOptionToProcess);
    void setOptionTypeToProcess(AppOption appOptionProcessable);
}

BaseAppOptionProcessor.java
package biz.tugay.sakilaconsole.controller.helper;
 
import biz.tugay.sakilaconsole.controller.AppOption;
import org.springframework.beans.factory.annotation.Required;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/13/2016
 * Time: 9:42 AM
 */
public abstract class BaseAppOptionProcessor implements AppOptionProcessor {
 
    protected AppOption appOptionProcessable;
 
    @Override
    @Required
    public void setOptionTypeToProcess(AppOption appOptionProcessable) {
        this.appOptionProcessable = appOptionProcessable;
    }
}

AppOptionActorsOfFilmProcessor.java
package biz.tugay.sakilaconsole.controller.helper.impl;
 
import biz.tugay.sakilaconsole.controller.ActorController;
import biz.tugay.sakilaconsole.controller.AppOption;
import biz.tugay.sakilaconsole.controller.FilmController;
import biz.tugay.sakilaconsole.controller.helper.AppOptionProcessor;
import biz.tugay.sakilaconsole.controller.helper.BaseAppOptionProcessor;
import biz.tugay.sakilaconsole.model.entity.Film;
import org.springframework.beans.factory.annotation.Required;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/13/2016
 * Time: 9:41 AM
 */
public class AppOptionActorsOfFilmProcessor extends BaseAppOptionProcessor implements AppOptionProcessor {
 
    private ActorController actorController;
    private FilmController filmController;
 
    @Override
    public void processAppOption(AppOption appOptionToProcess) {
        if (!appOptionProcessable.equals(appOptionToProcess)) {
            return;
        }
        filmController.listAllFilms();
        final Film film = filmController.askForFilmById();
        actorController.printActorsOfFilm(film);
    }
 
    @Required
    public void setActorController(ActorController actorController) {
        this.actorController = actorController;
    }
 
    @Required
    public void setFilmController(FilmController filmController) {
        this.filmController = filmController;
    }
}

AppOptionFilmsActorsTogetherProcessor.java
package biz.tugay.sakilaconsole.controller.helper.impl;
 
import biz.tugay.sakilaconsole.controller.ActorController;
import biz.tugay.sakilaconsole.controller.AppOption;
import biz.tugay.sakilaconsole.controller.FilmController;
import biz.tugay.sakilaconsole.controller.helper.AppOptionProcessor;
import biz.tugay.sakilaconsole.controller.helper.BaseAppOptionProcessor;
import biz.tugay.sakilaconsole.model.entity.Actor;
import org.springframework.beans.factory.annotation.Required;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/13/2016
 * Time: 9:54 AM
 */
public class AppOptionFilmsActorsTogetherProcessor extends BaseAppOptionProcessor implements AppOptionProcessor {
 
    private ActorController actorController;
    private FilmController filmController;
 
    @Override
    public void processAppOption(AppOption appOptionToProcess) {
        if (!appOptionProcessable.equals(appOptionToProcess)) {
            return;
        }
        actorController.listAllActors();
        final Actor actor_1 = actorController.askForActorId();
        final Actor actor_2 = actorController.askForActorId();
        filmController.printFilmsActorsTogether(actor_1, actor_2);
    }
 
    @Required
    public void setActorController(ActorController actorController) {
        this.actorController = actorController;
    }
 
    @Required
    public void setFilmController(FilmController filmController) {
        this.filmController = filmController;
    }
}

AppOptionFilmsByActorProcessor
package biz.tugay.sakilaconsole.controller.helper.impl;
 
import biz.tugay.sakilaconsole.controller.ActorController;
import biz.tugay.sakilaconsole.controller.AppOption;
import biz.tugay.sakilaconsole.controller.FilmController;
import biz.tugay.sakilaconsole.controller.helper.AppOptionProcessor;
import biz.tugay.sakilaconsole.controller.helper.BaseAppOptionProcessor;
import biz.tugay.sakilaconsole.model.entity.Actor;
import org.springframework.beans.factory.annotation.Required;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/13/2016
 * Time: 9:31 AM
 */
public class AppOptionFilmsByActorProcessor extends BaseAppOptionProcessor implements AppOptionProcessor {
 
    private ActorController actorController;
    private FilmController filmController;
 
    @Override
    public void processAppOption(AppOption appOptionToProcess) {
        if (!appOptionToProcess.equals(appOptionProcessable)) {
            return;
        }
        actorController.listAllActors();
        final Actor actor = actorController.askForActorId();
        filmController.printFilmsOfActor(actor);
    }
 
    @Required
    public void setActorController(ActorController actorController) {
        this.actorController = actorController;
    }
 
    @Required
    public void setFilmController(FilmController filmController) {
        this.filmController = filmController;
    }
}

AppOptionFilmsByCategoryProcessor.java
package biz.tugay.sakilaconsole.controller.helper.impl;
 
import biz.tugay.sakilaconsole.controller.AppOption;
import biz.tugay.sakilaconsole.controller.CategoryController;
import biz.tugay.sakilaconsole.controller.FilmController;
import biz.tugay.sakilaconsole.controller.helper.AppOptionProcessor;
import biz.tugay.sakilaconsole.controller.helper.BaseAppOptionProcessor;
import biz.tugay.sakilaconsole.model.entity.Category;
import org.springframework.beans.factory.annotation.Required;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/13/2016
 * Time: 9:56 AM
 */
 
public class AppOptionFilmsByCategoryProcessor extends BaseAppOptionProcessor implements AppOptionProcessor {
 
    private CategoryController categoryController;
    private FilmController filmController;
 
    @Override
    public void processAppOption(AppOption appOptionToProcess) {
        if (!appOptionProcessable.equals(appOptionToProcess)) {
            return;
        }
        categoryController.listAll();
        final Category category = categoryController.askForId();
        filmController.printFilmsOfCategory(category);
    }
 
    @Required
    public void setCategoryController(CategoryController categoryController) {
        this.categoryController = categoryController;
    }
 
    @Required
    public void setFilmController(FilmController filmController) {
        this.filmController = filmController;
    }
}

Bootstrap & Configuration

App.java
package biz.tugay.sakilaconsole;
 
import java.io.IOException;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 17:18 PM
 */
public interface App {
 
    void start() throws IOException, InterruptedException;
}

AppConsoleImpl.java
package biz.tugay.sakilaconsole;
 
import biz.tugay.sakilaconsole.controller.MainMenuController;
 
import java.io.IOException;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 10/23/2016
 * Time: 12:12 PM
 */
public class AppConsoleImpl implements App {
 
    private final MainMenuController mainMenuController;
 
    public AppConsoleImpl(MainMenuController mainMenuController) {
        this.mainMenuController = mainMenuController;
    }
 
    @Override
    public void start() throws IOException, InterruptedException {
        mainMenuController.showMainMenu();
        System.exit(-1);
    }
}

AppNetworkImpl.java
package biz.tugay.sakilaconsole;
 
import biz.tugay.sakilaconsole.controller.MainMenuController;
import biz.tugay.sakilaconsole.view.helper.IOResolver;
import biz.tugay.sakilaconsole.view.helper.impl.NetworkIOResolverImpl;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 17:16 PM
 */
public class AppNetworkImpl implements App, ApplicationContextAware {
 
    private final MainMenuController mainMenuController;
    private ApplicationContext applicationContext;
 
    public AppNetworkImpl(MainMenuController mainMenuController) {
        this.mainMenuController = mainMenuController;
    }
 
    @Override
    public void start() throws IOException, InterruptedException {
        final ServerSocket serverSocket = new ServerSocket(9090);
        while (true) {
            final Socket accept = serverSocket.accept();
            final NetworkIOResolverImpl networkIOResolverImpl = (NetworkIOResolverImpl) applicationContext.getBean(IOResolver.class);
            final Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        mainMenuController.showMainMenu();
                        final Socket socket = networkIOResolverImpl.socketFor(Thread.currentThread());
                        socket.close();
                    } catch (IOException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            final Thread thread = new Thread(runnable);
            networkIOResolverImpl.add(thread, accept);
            thread.start();
        }
    }
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

AppBoostrap.java
package biz.tugay.sakilaconsole;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import java.io.IOException;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 11/12/2016
 * Time: 17:11 PM
 */
public class AppBootstrap {
 
    public static void main(String[] args) throws IOException, InterruptedException {
        final ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/app-context.xml");
        final App app = applicationContext.getBean(App.class);
        app.start();
    }
}

app-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">
 
    <beans profile="base">
        <!-- Model -->
        <bean id="persistenceUtil" class="biz.tugay.sakilaconsole.model.persistence.impl.PersistenceUtilImpl">
            <constructor-arg value="sakiladb"/>
        </bean>
        <bean id="actorService" class="biz.tugay.sakilaconsole.model.service.impl.ActorServiceImpl">
            <constructor-arg ref="persistenceUtil"/>
        </bean>
 
        <bean id="filmService" class="biz.tugay.sakilaconsole.model.service.impl.FilmServiceImpl">
            <constructor-arg ref="persistenceUtil"/>
        </bean>
        <bean id="categoryService" class="biz.tugay.sakilaconsole.model.service.impl.CategoryServiceImpl">
            <constructor-arg ref="persistenceUtil"/>
        </bean>
 
        <!-- View -->
        <bean id="abstractView" class="biz.tugay.sakilaconsole.view.impl.AbstractViewImpl" abstract="true">
            <property name="ioResolver" ref="ioResolver"/>
        </bean>
 
        <bean id="mainMenuView" class="biz.tugay.sakilaconsole.view.impl.MainMenuViewImpl">
            <constructor-arg ref="ioResolver"/>
        </bean>
 
        <bean id="actorView" class="biz.tugay.sakilaconsole.view.impl.ActorViewImpl" parent="abstractView"/>
        <bean id="filmView" class="biz.tugay.sakilaconsole.view.impl.FilmViewImpl" parent="abstractView"/>
        <bean id="categoryView" class="biz.tugay.sakilaconsole.view.impl.CategoryViewImpl" parent="abstractView"/>
 
        <!-- Controller -->
        <bean id="mainMenuController" class="biz.tugay.sakilaconsole.controller.MainMenuController">
            <constructor-arg index="0" ref="mainMenuView"/>
            <property name="appOptionProcessorList">
                <list value-type="biz.tugay.sakilaconsole.controller.helper.AppOptionProcessor">
                    <ref bean="appOptionFilmsByActorProcessor"/>
                    <ref bean="appOptionActorsOfFilmProcessor"/>
                    <ref bean="appOptionFilmsActorsTogetherProcessor"/>
                    <ref bean="appOptionFilmsByCategoryProcessor"/>
                </list>
            </property>
        </bean>
 
        <bean id="actorController" class="biz.tugay.sakilaconsole.controller.ActorController">
            <constructor-arg index="0" ref="actorView"/>
            <constructor-arg index="1" ref="actorService"/>
        </bean>
 
        <bean id="filmController" class="biz.tugay.sakilaconsole.controller.FilmController">
            <constructor-arg index="0" ref="filmService"/>
            <constructor-arg index="1" ref="filmView"/>
        </bean>
 
        <bean id="categoryController" class="biz.tugay.sakilaconsole.controller.CategoryController">
            <constructor-arg index="0" ref="categoryService"/>
            <constructor-arg index="1" ref="categoryView"/>
        </bean>
 
        <bean id="baseAppOptionProcessor"
              class="biz.tugay.sakilaconsole.controller.helper.BaseAppOptionProcessor"
              abstract="true">
        </bean>
 
        <bean id="appOptionFilmsByActorProcessor"
              class="biz.tugay.sakilaconsole.controller.helper.impl.AppOptionFilmsByActorProcessor"
              parent="baseAppOptionProcessor">
            <property name="optionTypeToProcess" value="FILMS_BY_ACTOR"/>
            <property name="actorController" ref="actorController"/>
            <property name="filmController" ref="filmController"/>
        </bean>
 
        <bean id="appOptionActorsOfFilmProcessor"
              class="biz.tugay.sakilaconsole.controller.helper.impl.AppOptionActorsOfFilmProcessor"
              parent="baseAppOptionProcessor">
            <property name="optionTypeToProcess" value="ACTORS_OF_FILM"/>
            <property name="actorController" ref="actorController"/>
            <property name="filmController" ref="filmController"/>
        </bean>
 
        <bean id="appOptionFilmsActorsTogetherProcessor"
              class="biz.tugay.sakilaconsole.controller.helper.impl.AppOptionFilmsActorsTogetherProcessor"
              parent="baseAppOptionProcessor">
            <property name="optionTypeToProcess" value="FILMS_ACTORS_TOGETHER"/>
            <property name="actorController" ref="actorController"/>
            <property name="filmController" ref="filmController"/>
        </bean>
 
        <bean id="appOptionFilmsByCategoryProcessor"
              class="biz.tugay.sakilaconsole.controller.helper.impl.AppOptionFilmsByCategoryProcessor"
              parent="baseAppOptionProcessor">
            <property name="optionTypeToProcess" value="FILMS_BY_CATEGORY"/>
            <property name="categoryController" ref="categoryController"/>
            <property name="filmController" ref="filmController"/>
        </bean>
 
    </beans>
 
    <beans profile="console">
        <bean id="ioResolver" class="biz.tugay.sakilaconsole.view.helper.impl.ConsoleIOResolverImpl"/>
        <bean id="app" class="biz.tugay.sakilaconsole.AppConsoleImpl">
            <constructor-arg ref="mainMenuController"/>
        </bean>
    </beans>
 
    <beans profile="net">
        <bean id="ioResolver" class="biz.tugay.sakilaconsole.view.helper.impl.NetworkIOResolverImpl"/>
        <bean id="app" class="biz.tugay.sakilaconsole.AppNetworkImpl">
            <constructor-arg ref="mainMenuController"/>
        </bean>
    </beans>
</beans>


Finally In Action!!!
Start with compiling:

Lets first run our application with base and console profiles:

Lets try base and net now..

So what do you think? Any comments? Any questions? Please email me! Thank you!