This is going to be quite long!
I am running the sample Sakila database that MySQL provides.
Directory Layout
pom.xml
persistence.xml
hibernate.properties
Actor.java
Film.java
Category.java
FilmActorPK.java
FilmActor.java
FilmCategoryPK.java
FilmCategory.java
PersistenceUtil.java
PersistenceUtilImpl.java
ActorService.java
ActorServiceImpl.java
FilmService.java
FilmServiceImpl.java
CategoryService.java
CategoryServiceImpl.java
FilmActorService.java
FilmActorServiceImpl.java
AbstractViewImpl.java
MainMenuView.java
MainMenuViewImpl.java
ActorView.java
ActorViewImpl.java
FilmView.java
FilmViewImpl.java
CategoryView.java
CategoryViewImpl.java
IOResolver.java
ConsoleIOResolverImpl.java
NetworkIOResolverImpl.java
ActorController.java
FilmController.java
CategoryController.java
AppOption.java
AppOptionProcessor.java
BaseAppOptionProcessor.java
AppOptionActorsOfFilmProcessor.java
AppOptionFilmsActorsTogetherProcessor.java
AppOptionFilmsByActorProcessor
AppOptionFilmsByCategoryProcessor.java
AppConsoleImpl.java
AppNetworkImpl.java
AppBoostrap.java
app-context.xml
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!
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.javapackage 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.javapackage 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.javapackage 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.javapackage 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!