This is a very small full-stack web application that is used as a sample and is for pure demonstration purposes.
- Checkout code
git clone https://github.com/GunjanKadu/Sales-Order-System.git
- Do a local build
mvn clean package
... will compile the sources, package up the war file
- Run application
go into the online-application directory and execute following command:
mvn tomcat7:run-war
uses maven tomcat7 plugin to run the application within an embedded Apache Tomcat web container
once the application loaded, navigate to:
http://localhost:8080/online-application/login
some sample credentials can be found configured in Spring's application-security.xml configuration file.
mvn test
... this will run all unit test within the suite of tests
or
from your IDE, just navigate to the unit test class and click on the IDE's 'run' button
mvn verify
... this will run all integration test within the suite of tests.
or
from your IDE, just navigate to the integration test class and click on the IDE's 'run' button
[TBD]
Use Sonar (SonarQube) to run code quality analysis on the project. A sonar-project.properties file provided. Will need SonarQube server and Sonar Runner so need to download them both from the SonarQube website and follow the installation instructions.
Assuming Sonar is installed (with Sonar Runner on the environment path), on CLI run:
- Start the SonarQube Server
- Navigate to project root directory and execute:
sonar-runner
It is also possible to run with MySQL. You need MySQL to be installed. Download from the MySQL website and follow installation instructions.
- Start up MySQL server on your system
- Configure Spring's application-datasource.xml configuration file to connect to MySQL:
Uncomment below as specified:
<!-- uncomment out for use with MySQL database -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/sales_order_system" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<jdbc:initialize-database ignore-failures="DROPS">
<jdbc:script location="file:src/main/resources/scripts/db-drop-tables.sql"/>
<jdbc:script location="file:src/main/resources/scripts/db-create.sql"/>
</jdbc:initialize-database>
Assumming MongoDB is installed on system. If not, can download it from MongoDB website and follow installation instructions.
Start up MongoDB Database Server:
./mongod
Open up MongoDB Database client:
./mongo
Load the mongodb javascript file which populates some sample data
load("mongodb.js")
The application is just a simplistic monolithic application built with several layers. In summary, back-end is written in Java which connects to a back-end in-memory relational database (HSQL). Can also connect to other relational databases (MySQL). Application is scafolded by Spring Framework. Model-View-Controller (MVC) architectural pattern is used to separate the front-end from the back-end. This is achieved by Spring Web MVC. This application would then be deployed on an embedded web container (Apache Tomcat).
The front-end is plainly JSP with a bit of JSTL here and there. Dandelion Databases also used to implement tables in the UI. Basic CSS for styling. Bootstrap provides the front-end framework for this.
- The back-end is completely built using Java (Java 8 compiled)
- It is bootstrapped by Spring Framework
- Database is a RDBMS (Relational Database Management System):
- default in memory-db (HSQL)
- MySQL supported too
- Spring Data JPA provides the Data Access Abstraction
- Persistence done using JPA (Hibernate the implementation)
- JSP serves front-end html content...
[TBD]
This application is very simple. It is a web application that currently provides basic CRUD operations. Everything operational is viewed as a business transaction which is executed down through the various layers. Therefore, an anemic domain model is used as opposed to a pure object-oriented domain model. This is sufficient and ideal because at this moment there is not much (if any) complex business logic processing that is required.
Defining the application's boundary and setting the available operations from the perspective of interfacing client layers (front-end). It encapsulates the application's business logic, controlling transactions and coor-dinating responses in the implementation of its operations.
e.g.
@Service("itemServiceImpl")
@Transactional
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemRepository itemRepository;
...
}
An object-oriented view of the data store underneath providing an extra layer of abstraction (Spring Data JPA) in front of the data access capabilities of the Data Mapper pattern. Object Relational Mapping framework (Hibernate) is used to achieve this effect of mapping the differences between relational database tables and the domain model. JPA's entity manager encapsulates the data access element (Data Access Object pattern).
e.g. of a Spring Data JPA Repository
@Repository
public interface ItemRepository extends JpaRepository<Item, Integer> {
}
Spring Framework's annotation support (component scanning) is done to do this taking advantage of Spring Framework's core abilities - Dependency Injection provided by the Inversion of Control (IOC) container.
@Controller
public class OrderController {
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
@Autowired
@Qualifier("orderServiceImpl")
private OrderService orderService;
@Autowired
@Qualifier("customerServiceImpl")
private CustomerService customerService;
@Autowired
@Qualifier("itemServiceImpl")
private ItemService itemService;
@Autowired
@Qualifier("orderFormValidator")
private OrderFormValidator orderFormValidator;
Another example from the Customer model object:
@Entity
@Table(name = "customer")
@Getter
@Setter
@NoArgsConstructor
@EqualsAndHashCode(exclude = "orders")
@ToString
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "customer_id")
private int customerId;
@NotNull(message = "{error.null.firstname}")
@NotBlank(message = "{error.blank.firstname}")
@NotEmpty(message = "{error.empty.firstname}")
@Pattern(regexp = "[a-zA-Z]*", message = "{error.invalid.firstname}")
@Column(name = "customer_firstname", nullable = false, length = 50)
private String firstName;
@NotNull(message = "{error.null.lastname}")
@NotBlank(message = "{error.blank.lastname}")
@NotEmpty(message = "{error.empty.lastname}")
@Pattern(regexp = "[a-zA-Z]*", message = "{error.invalid.lastname}")
@Column(name = "customer_lastname", nullable = false, length = 50)
private String lastName;
Lombok Project used to generate getters/setters/toString/equals and hashcode to remove the boilerplate code
The application enables login/logout feature which was implemented using the basic features of the Spring Security module of the Spring Framework.
The following application-security.xml Spring configuration file shows key security configurations:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http auto-config="true">
<!-- items -->
<intercept-url pattern="/items" access="ROLE_TEST_USER,ROLE_ADMIN" />
<intercept-url pattern="/items/create" access="ROLE_TEST_USER,ROLE_ADMIN" />
<intercept-url pattern="/items/createItem" access="ROLE_TEST_USER,ROLE_ADMIN" />
....
<form-login
login-page="/login"
default-target-url="/customers"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"
/>
<logout logout-success-url="/login?logout" />
<csrf/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<!-- hard coding application user credentials - switch to DB or LDAP -->
<user name="testUser" password="password" authorities="ROLE_TEST_USER" />
<user name="admin" password="password" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Integration Testing is implemented using Spring's Test Context Framework. An in-memory Database (HSQL) is used.
End 2 End Testing (Acceptance Testing) is done using Cucumber-JVM. This is available under the test-automation sub module. The intent of this is to provide end to end automation of the full stack web application. Maybe, can integrate Selenium in the future which would allow automation of the web application on web browsers. But for now, cucumber tests are written in the back-end code. Acceptance criterias are written in the .feature files using the Gherkin language. This area needs improvement. Note that End 2 End testing for this project is still WIP.
Front End | Back End | Database | Testing | Other |
---|---|---|---|---|
HTML | Java 8 | HSQL (HyperSQL) | JUnit | SLF4j - Log4j |
CSS | Spring Core | MySQL | AssertJ | Maven |
JS | Spring Web MVC | MongoDB | Mockito | Tomcat |
Bootstrap | Spring Data JPA | Cucumber-JVM | SonarQube | |
JSP | Spring Security | Spring Test Context | Lombok | |
JSTL | JPA - Hibernate | |||
Dandelion DataTables | JTA | |||
Bean Validation |