Banuprakash C
Full Stack Architect,
Co-founder Lucida Technologies Pvt Ltd.,
Corporate Trainer,
Email: banuprakashc@yahoo.co.in
https://www.linkedin.com/in/banu-prakash-50416019/
https://github.com/BanuPrakash/JAVA
Softwares Required:
-
Eclipse IDE for Enterprise Java Developers: https://www.eclipse.org/downloads/packages/release/2020-03/m1/eclipse-ide-enterprise-java-developers
-
MySQL [ Prefer on Docker]
Install Docker Desktop
Docker steps:
a) docker pull mysql
b) docker run --name local-mysql –p 3306:3306 -e MYSQL_ROOT_PASSWORD=Welcome123 -d mysql
container name given here is "local-mysql"
For Mac: docker run -p 3306:3306 -d --name local-mysql -e MYSQL_ROOT_PASSWORD=Welcome123 mysql
c) CONNECT TO A MYSQL RUNNING CONTAINER:
$ docker exec -it local-mysql /bin/bash
d) Run MySQL client:
bash terminal> mysql -u "root" -p
mysql> exit
==========
Java 8 features
- Generic collection
- Lambda expression
- Java 8 stream
Spring Framework Java Persistence API Buidling Traditional Web application
Spring Boot Building Secure RESTful Web services
Collection API ==> Data Containers provided by Java ==> Java Collection Framework
Generics:
class Rectangle { ==> class Rectangle { T width; Object width; T breadth; Object breadth;
} }
Rectangle r1 = new Rectangle<>(4, 5); T is treated as Integer
Integer is a type wrapper class for "int" primitive type
int x = 10;
Integer iX = x; // autoboxing
int y = iX; // unboxing
Rectangle r2 = new Rectangle<>(4.2, 1.5); T is treated as Double
Rectangle r3 = new Rectangle<>("A", "B");
Rectangle r3 = new Rectangle("A", "B");
class Rectangle { ==> class Rectangle { T width; Number width; T breadth; Number breadth;
} }
Rectangle r3 = new Rectangle("A", "B");// error
===============================
Object[] elems = new String[3]; // valid
List list = new ArrayList(); // error
class Product {
}
class Tv extends Product {
}
Object o = new Product(); Object o = new Tv(); Product p = new Tv();
List<?> is refered as unkonow type; can access any type of collection; mutation is not allowed
If T is Tv
List<? super T> dest
dest can be Tv, Product or Object
If is Product
List<? extends T> meaining it can be Product or Tv
====================
private static <T> void copy(List<T> dest, List<T> src) {
for(T obj : src) {
dest.add(obj);
}
}
// PECS ==> Producer extends Consumer Super
private static <T> void copy(List<? super T> dest, List<? extends T> src) {
for(T obj : src) {
dest.add(obj);
}
}
=====================
Functional Interface and Lambda expression
Anonymous class
interface Flyable { void fly(); }
Flyable f = new Flyable(); // error
"f" is an object of anonymous class Flyable f = new Flyable() { public void fly() { ... } };
class Bird implements Flyable { // state // behaviour public void fly() { ... }
}
Flyable f = new Bird();
Dummy1.java Dummy2.java
Metaspace
===
Test.java
public class Test { public static void main(String[] args) { // r is an object of anonymous class Runnable r = new Runnable() { public void run() {
}
};
} }
javap -p Test.class Compiled from "Test.java" public class Test { public Test(); public static void main(java.lang.String[]); }
javap -p Test$1.class Compiled from "Test.java" class Test$1 implements java.lang.Runnable { Test$1(); public void run(); }
==========================
FunctionalInterface is an interface where only one method of it has to be defined.
public class Test { public static void main(String[] args) { // r is an object of anonymous class Runnable r = () -> { }; } }
javap -p Test.class Compiled from "Test.java" public class Test { public Test(); public static void main(java.lang.String[]); private static void lambda$main$0(); }
===============================
Lambda
(parameter) -> body
Many FunctionalInterfaces in Java 8, few are listed below:
- Function [ R apply(T t); ]
Function<Integer, String> f = (x) -> "Hello " + x;
f.apply(5); returns "Hello 5"
-
BiFunction [ R apply(T t, U u); ]
-
Predicate [ boolean test(T t); ]
-
Consumer [ void accept(T t); ]
-
Runnable [ void run() ]
-
Comparator [ int compare (T o1, T o2)]
============================
OOP --> has methods which are tightly coupled to state of object
public class Account { private double balance; //state
public void credit(double amt) {
balance += amt;
}
public double getBalance() {
return balance;
}
}
Functional style of programming ==> functionalities which can be used on any object Functional style uses high order function [ which accept or return a function]
- treat functions as first class members like objects / primitive
Commonly used HOF are:
- filter [ returns a subset based on predicate function]
- map [ transforms the data based on Function]
- reduce [ aggregate function]
- forEach [ consume every element and write to console / Network / database]
- limit
- skip
- flatMap ...
Java 8 streams;
The above mentioned HOF work on stream; Stream is a channel along which data flows [ Collection / Network/ R2DBC / MongoDB]
double sum = products.stream() .map(p -> p.getPrice()) .reduce(0.0, (v1, v2) -> v1 + v2);
reduce(indentity, accumulator) T result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
===================================
Spring Framework + JPA
SOLID Design Principle S ==> Single Responsibility O ==> Open Close Principle [ Closed for chanage; open for extension] L ==> Liskov Substition principle I ==> Interface segregation D ==> Dependency Injection
What is Spring Framework?
- provides Lightweight container which manages life-cycle of objects and depency injection in its core module.
- has many more module for EAI ==> Enterprise application integration [ database , NoSQL, Redis, JMS, EmailService, ..] ==> lots of templates are avaibles which make application development easy.
Guice (pronounced 'juice') is a lightweight dependency injection framework
============================================
Spring framework uses XML or annotation as metadata for life-cycle of objects and depency injection
- XML as metadata
interface EmployeeDao { void addEmployee(Employee e); }
public class EmployeeDaoJdbcImpl implements EmployeeDao { void addEmployee(Employee e) {..} }
public class SampleService { EmployeeDao empDao; public SampleService(EmployeeDao empDao) { this.empDao = empDao; }
public void doAdd(Employee e) {
empDao.addEmployee(e);
}
}
beans.xml
====================
interface EmployeeDao { void addEmployee(Employee e); }
public class EmployeeDaoJdbcImpl implements EmployeeDao { void addEmployee(Employee e) {..} }
public class EmployeeDaoMongoDbImpl implements EmployeeDao { void addEmployee(Employee e) {..} }
public class SampleService { EmployeeDao empDao;
public void setDao(EmployeeDao empDao) {
this.empDao = empDao;
}
public void doAdd(Employee e) {
empDao.addEmployee(e);
}
}
beans.xml
==> setDao(jdbc);
===============================================================
Annotation as Metadata: Spring creates instances of classes which has one of these annotations:
- @Component ==> Untilty class / Helper
- @Repository ==> DAO layer ==> interact with persistent Store
- @Service ==> Service tier which is Transactional
- @Controller ==> Traditional web application development
- @RestController ==> RESTful Web Services
- @Configuration ==> reading properties file and any custom configuration for applicaiton
Wiring is done using @Autowired annotation
interface EmployeeDao { void addEmployee(Employee e); }
@Repository public class EmployeeDaoJdbcImpl implements EmployeeDao { void addEmployee(Employee e) {..} }
@Service public class SampleService { @Autowired EmployeeDao empDao;
public void doAdd(Employee e) {
empDao.addEmployee(e);
}
}
==============
interface EmployeeDao { void addEmployee(Employee e); }
@Repository public class EmployeeDaoJdbcImpl implements EmployeeDao { void addEmployee(Employee e) {..} }
@Repository public class EmployeeDaoMongoImpl implements EmployeeDao { void addEmployee(Employee e) {..} }
@Service public class SampleService { @Autowired EmployeeDao empDao;
public void doAdd(Employee e) {
empDao.addEmployee(e);
}
}
=========================================
Java Build Tool ==> Maven
ANT ==> build.xml [ target as clean, compile, package, jar files...]
Maven is a build tool ==> Main features manage dependencies; configure lifecycle management of applicaiton; uses pom.xml as configuration file; uses XML language
Gradle is a build tool similar to Maven uses "groovy" language
=============
ApplicationContext is an interface for Spring Container.
-
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
-
new AnnotationConfigApplicationContext();
==== Problem: more than 1 bean of a giver interface to be wired Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.cisco.prj.dao.EmployeeDao' available: expected single matching bean but found 2: employeeDaoFileImpl,employeeDaoJdbcImpl
Solutions:
- Mark one of the bean as @Primary
@Primary @Repository public class EmployeeDaoJdbcImpl implements EmployeeDao {
@Repository public class EmployeeDaoFileImpl implements EmployeeDao {
- use @Qualifier
@Repository public class EmployeeDaoJdbcImpl implements EmployeeDao {
@Repository public class EmployeeDaoFileImpl implements EmployeeDao {
@Service public class AppService { @Autowired @Qualifier("employeeDaoJdbcImpl") private EmployeeDao empDao;
- using VM / Program arguments and @Profile
@Service public class AppService { @Autowired private EmployeeDao empDao;
@Profile("dev") @Repository public class EmployeeDaoFileImpl implements EmployeeDao {
@Profile("prod") @Repository public class EmployeeDaoJdbcImpl implements EmployeeDao {
Run As ==> Run Configurations Arguments: VM arguments
-Dspring.profiles.active=prod
=======================================================
- JDBC is an integration aPI to interact with Relational Database [ RDBMS ]
ORM framework
-
Object Relational Mapping to simplify CRUD operations on top of JDBC
-
Hibernate ==> JBoss ==> RedHat
-
TopLink ==> Oracle
-
KODO ==> BEA ==> Oracle
-
JDO ==> Sun MS ==> Oracle
-
OpenJPA ==> Apache
-
EclipseLink ==> eclipse
JPA ==> Java Persistence API is a specification for ORM
Building Blocks of ORM
- DataSource
- EntityManagerFactory
- PersistenceContext
- EntityManager
Within a persistence context, entities are managed within this environmet. The EntityManager controls their lifecycle, and they can access datastore resources.
- Primary KEY is AUTO INCREMENT; no need to pass it from application @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id;
===
- Primary key is assigned from Application @Id private int id;
===================================
Recap:
-
Generic Collections using of <?> and Generic class , Generic methods
-
Functional Style of Programming; @FunctionalInterface, HOF
-
java 8 streams [ map, filter, reduce, forEach, collect]
-
Spring Framework 5.2 version ==> Core Container provides DI and life cycle management XML based metadata and annotaion based metadata; @Component, @Repository, @Service, @Configuration, @Controller, @RestController @Autowired ==> to wire dependencies @Primary, @Qualifier, @Profile with VM arguments -Dspring.profiles.active=prod
-
ORM, EntityManagerFactory, PersistenceContext and EntityManager
-
@Entity, @Table, @Id, @Column
BiFunction<Integer,Integer,Integer> bifn = (x,y) -> x + y;
int x = bifn.apply(4,5); // 9
BiFunction<Integer,Double,String> bifn2 = (x, y) -> "Result " + (x +y);
String str - bifn2.apply(4, 1.2); // "Result 5.2"
==================================
Day 2
Spring creates instances of class using default constructor and it needs one of "6" annotations mentioned
case 1:
class without default constructor
public class EmailService { private String ip; private int port;
public EmailService(String ip, int port) {
...
}
public void sendEmail(String msg) {
}
}
placing any of the "6" annotations on top of this class will lead to Spring initialization error
case 2:
class are provided by 3rd party libraries which doesn't have any of the above annotations; but we need objects of those classes to be managed by Spring container
2.1) jackson library ObjectMapper java <--> json
JAXB
java <--> XML
Solution: use factory pattern
===
EmailService.java MyConfig.java AppService.java
=======================
Once MySQL container on docker is up and running
access MySQL terminal
$ docker exec -it local-mysql bash
Enter Password: Welcome123
mysql> create database CISCO_SPRING; mysql> use CISCO_SPRING;
==============
ddl-auto
Hibernate property values are: create, update, create-drop, validate and none: props.setProperty("hibernate.ddl-auto", "create"); create – Hibernate first drops existing tables, then creates new tables
props.setProperty("hibernate.ddl-auto", "update"); update – uses existing table or creates a new one if not available; alter table if required.
validate – Hibernate only validates whether the tables and columns exist, otherwise it throws an exception none – this value effectively turns off the DDL generation
====
TransactionManager
- Programatic Transaction using JDBC
public void transferFunds(Account fromAcc, Account toAcc, double amt) { Connection con = ... try { con.setAutoCommit(false); PreparedStatement ps1 = "update fromAcc ..."; PreparedStatement ps2= "update toAcc ..."; ps1.executeUpdate(); ps2.executeUpdate(); con.commit(); } catch(SQLException ex) { con.rollback(); } }
- Programatic Transaction using Hibernate
public void transferFunds(Account fromAcc, Account toAcc, double amt) { Session ses = sessionFactory.getSession(); try { Transaction tx = ses.beginTransaction(); ses.update(fromAcc); ses.update(toAcc); ses.save(txinfo); send sms; send email tx.commit(); } catch(SQLException ex) { tx.rollback(); } }
- Declarative Tranasaction using PlatformTransactionManager
@Transactional public void transferFunds(Account fromAcc, Account toAcc, double amt) { // jdbc or hiberante or jpa or jta }
if exception is propagated out of the method "rollback" else "commit"
=======================================================
Service facade a layer on DAO operations; Normally combine many fine grained operations of DAO as one atomic unit of operation which is coarse grained. Service code should be transactional instead of DAO code.
==========================================
Customer.java CustomerDao.java CustomerDaoJpaImpl.java OrderService.java CustomerClient.java
=========================================================
http://www.databaseanswers.org/data_models/index.htm
Mapping Associations
Many-To-one JoinColumn will introduce FK in owning side
One-To-Many JoinColumn will introduce FK in child side
==========
Without Cascade:
@Entity @Table(name="orders") public class Order { @OneToMany @JoinColumn(name="order_fk") private List items = new ArrayList<>(); // order has many items
Assume Order has 4 items;
-
to save orderDao.save(order); itemDao.save(i1); itemDao.save(i2); itemDao.save(i3); itemDao.save(i4);
-
to delete orderDao.delete(oid); itemDao.delete(id1); itemDao.delete(id2); itemDao.delete(id3); itemDao.delete(id4);
With Cascade:
@Entity @Table(name="orders") public class Order { @OneToMany(cascade = CascadeType.ALL) @JoinColumn(name="order_fk") private List items = new ArrayList<>(); // order has many items
Assume Order has 4 items;
- to save orderDao.save(order);
saving an order saves items also
- to delete orderDao.delete(oid); delte order deletes items also
==> No need for ItemDao
============
Fetch Strategy
- ManyToOne is EAGER fetching
- OneToMany is LAZY fetching
orderDao.getOrder(1); this fetches order entry and customer also
override strategy using: @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name="order_fk") private List items = new ArrayList<>(); // order has many items
===
Dirty checking is the capability of ORM ==> within a transactional code if object becomes dirty ==> update SQL is sent
Fetch EAGER: select order0_.oid as oid1_2_0_, order0_.customer_fk as customer4_2_0_, order0_.order_date as order_da2_2_0_, order0_.total as total3_2_0_, customer1_.email as email1_0_1_, customer1_.first_name as first_na2_0_1_, customer1_.last_name as last_nam3_0_1_, items2_.order_fk as order_fk5_1_2_, items2_.itemid as itemid1_1_2_, items2_.itemid as itemid1_1_3_, items2_.amount as amount2_1_3_, items2_.product_fk as product_4_1_3_, items2_.qty as qty3_1_3_, product3_.id as id1_3_4_, product3_.name as name2_3_4_, product3_.price as price3_3_4_, product3_.qty as qty4_3_4_ from orders order0_ left outer join customers customer1_ on order0_.customer_fk=customer1_.email left outer join items items2_ on order0_.oid=items2_.order_fk left outer join products product3_ on items2_.product_fk=product3_.id where order0_.oid=?
Fetch LAZY:
select order0_.oid as oid1_2_0_, order0_.customer_fk as customer4_2_0_, order0_.order_date as order_da2_2_0_, order0_.total as total3_2_0_, customer1_.email as email1_0_1_, customer1_.first_name as first_na2_0_1_, customer1_.last_name as last_nam3_0_1_ from orders order0_ left outer join customers customer1_ on order0_.customer_fk=customer1_.email where order0_.oid=?
Bi-Directional relationship:
@Entity @Table(name="orders") public class Order {
@ManyToOne()
@JoinColumn(name="customer_fk")
private Customer customer; // order is by customer
@Entity @Table(name="customers") public class Customer { @OneToMany(mappedBy = "customer") private List orders = new ArrayList<>();
==================
Many-to-Many ==> OneToMany and ManyToOne with association table
- Project and Employee looks like ManyToMany [ Project has many employees; Employee works in many Project]
======================
Mapping Inheritance:
- Single Table
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "product_type") public abstract class Product { @Id private int id; private String name; private double price;
}
@Entity @DiscriminatorValue("tv") public class Tv extends Product { @Column(name="screen_type") String screenType; }
@Entity @DiscriminatorValue("mobile") public class Mobile extends Product { String connectivity; }
--
- Table per class
@Entity @Inheritance(strategy = InheritanceType.JOINED) public abstract class Product { @Id private int id; private String name; private double price;
}
@Entity public class Tv extends Product { @Column(name="screen_type") String screenType; }
@Entity public class Mobile extends Product { String connectivity; }
========================================================
Task:
-
Start new Spring applicaton ==> pom.xml
-
create 2 entites "Employee" and "Ticket"
-
Use case 1: Employee raises a ticket
-
Use case 2: Employee resolves a ticket
refer: 2. task.svg
===============================
Day 2 Recap:
Mapping associations: one-to-many many-to-one
@JoinColumn() ==> Foreign Key
OneToOne ManyToMany
Inheritance: single table with discriminator column [ type ==> tv, mobile , "microwave"] JOINED Products table ==> common fields tv table mobile table
DataSource, EntityManager, PeristenceContext, EntityManagerFactory,
DirtyChecking
Day 3
Default package is jar mvn package
OR
Run As => Maven Build Goals: package
pom.xml war
Maven => update project ==> Check force update
WAR ==> Web Archive ==> Web based applications are bundeled as "war" files and deployed on server
==
pom Parent Maven Project
ear Enterprise applicaiton ==> Distributed computing , EJB
===================
Tomcat / Eclipse Jetty are Java Servlet container.
============
Resources running on Servlet Container / Servlet Engine / Web Container needs configuration
class LoginServlet extends HttpServlet { public doGet(HttpServletRequest req, HttpServletResponse res) {
}
public doPost(HttpServletRequest req, HttpServletResponse res) {
}
}
class RegisterServlet extends HttpServlet { public doGet(HttpServletRequest req, HttpServletResponse res) {
}
public doPost(HttpServletRequest req, HttpServletResponse res) {
}
}
http://localhost:8080/login http://localhost:8080/register
Deployment Descriptor for servlet engine: ==> web.xml
A pkg.LoginServlet A /login B pkg.RegisterServlet B /register===
Deployment Descriptor using Annoations:
@WebServlet("/login") class LoginServlet extends HttpServlet { public doGet(HttpServletRequest req, HttpServletResponse res) {
}
public doPost(HttpServletRequest req, HttpServletResponse res) {
}
}
@WebServlet("/register") class RegisterServlet extends HttpServlet { public doGet(HttpServletRequest req, HttpServletResponse res) {
}
public doPost(HttpServletRequest req, HttpServletResponse res) {
}
}
==========
Spring Web MVC Module
MVC ==> Model View Controller
View ==> Presentation [ HTML, JSP, Theymeleaf] Model ==> Business data and business logic [ DAO , entity , service] Controller ==> Servlet acts as controller [ application logic]
Run As ==> Maven Build ==> Goals jetty:run
===================
JSTL (JSP Standard Tag Library) The JSP Standard Tag Library (JSTL) represents a set of tags to simplify the JSP development.
Core Tags: <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Adding Validation to Web Application
===========
i18N ==> Internationalization
messages.properties name.required=Provide Name, can't be Blank price.invalid=:-( Negative value is not valid for price
messages_fr.properties name.required= .. price.invalid= ..
messages_hi.properties
name.required= .. price.invalid= ..
messages_ar.properties
name.required= .. price.invalid= ..
Browser ==> locale setting is "arabic" searches for "messages_ar.properties" if not present uses "messages.properties"
==============================
CustomerController ==> add and list customers
==========================
Help ==> Eclipse Market Place
search for STS "GO"
install Spring Tools 4 any latest avaiable
=================================================
Spring Framework and ORM framework [ Hibernate]
Spring + ORM with JPA integration + Spring MVC
Spring Core Spring ORM Spring Transaction Spring WebMVC
===================================================
Spring Boot
Spring Boot is a project that is built on the top of the Spring Framework. Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".
Spring Boot is higly opinated framework on top of Spring which configures requirements out-of-the box
- Spring integrate with JPA
-
Spring boot configures HikariCP as datasource ==> Connection pool to database Below Code is Not required: @Bean public DataSource dataSource() throws PropertyVetoException { ComboPooledDataSource cpds = new ComboPooledDataSource(); cpds.setDriverClass( "com.mysql.cj.jdbc.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/CISCO_SPRING" ); cpds.setUser("root");
cpds.setPassword("Welcome123");
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5); cpds.setMaxPoolSize(20); return cpds; } -
Configures Hibernate as ORM Below Code is not required
@Bean public LocalContainerEntityManagerFactoryBean emf(DataSource ds) { LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); emf.setDataSource(ds); emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); emf.setPackagesToScan("com.cisco.prj.entity");
Properties props = new Properties(); props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); // ORM to generate SQL to compatable to MySql8 props.setProperty("hibernate.hbm2ddl.auto", "update"); props.setProperty("hibernate.show_sql", "true"); props.setProperty("hibernate.format_sql", "true"); emf.setJpaProperties(props); return emf;
}
Simply put AppConfig.java is not required
- Spring with WebMVC
- configures DispatcherServlet to url-pattern "*"
AppInitializer.java is not required
- Configures Embedded Tomcat Container Below code is not required:
==========
@SpringBootApplication public class OrderappApplication {
public static void main(String[] args) {
SpringApplication.run(OrderappApplication.class, args);
}
}
SpringApplication.run ==> Create a Spring Container
same as AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicaitonContext();
ApplicationContext ctx = SpringApplication.run(OrderappApplication.class, args);
@SpringBootApplication is 3 in one
-
@ComponentScan ==> scan for @Component,@Repository, @Service, ... from "com.cisco.prj" and sub-package and creates instances
-
@EnableAutoConfiguration creates lots of builtin configurations like DataSource, EntityManagerFactory, Tomcat,...
-
@Configuration
==============
https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html
===
Spring Data JPA Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that's actually needed.Spring Data JPA provides repository support for the Java Persistence API (JPA).
- we create interface; Spring DATA JPA generates @Repository classes based on interface
public interface ProductDao extends JpaRepository<Product, Integer> { }
Some of the Built-in methods:
T save(T entity); Optional findById(ID id);
List<T> findAll();
void deleteById(ID id);
void delete(T entity);
JDBC ==> executeQuery("SELECT") and executeUpdate("INSERT / DELETE / UPDATE")
========================
ASM ==> Byte Code instrumentation
CGLib, JavaAssist or Byte Buddy
====================================
Building RESTful Web services
REST ==> Representational State Transfer Resources are on server; state of resource can be served to clients in variaous formats like JSON / XML / CSV / YML / ProtoBuf
1 | iPhone 13 | 120000 | 499
JSON ==> JavaScript Object Notation
{
"id": 1,
"name" : "iPhone 13",
"price" : 120000.00
}
XML
1 iPhone 13 120000.00REST depends on HTTP protocol
Http REQUEST headers:
Accept: application/json
this header by client is sent to server to request representation in the form of "json"
content-type: text/xml
this header sent by client to inform server that payload sent by client contains xml
===============
REST uses URL to identify resources and HTTP methods for Verbs/ actions
- use plural nouns to identify the resource
- HTTP methods for CRUD operations
Examples:
to get all products
get product whose id is "3"
use pathparameter [ / ] to get a single resource based on ID / PK
- GET http://localhost:8080/api/products?page=3&size=20 http://localhost:8080/api/products?category=mobile
use Query parameters [ ? ] for filtering ==> sub-set
payload contains new product data to be added to "products" resources
- PUT/ PATCH http://localhost:8080/api/products/2
payload contains new product data to be update to "products" resources whose id is "2"
delete a product resource whose id is "2"
GET, DELETE ==> no payload
PUT/PATCH and POST ==> contains payload
GET and DELETE are IDEMPOTENT ==> Safe methods
PUT and POST are not IDEMPOTENT ==> Not Safe
============== CRUD operations
CREATE ===> POST READ ==> GET UPDATE ==> PUT / PATCH DELETE ==> DELETE
=====================
Traditional web applocation we use "verb based url" ==> addProduct.do, getProduct.do
RESTful Web services always plural nouns http://localhost:8080/api/products http://localhost:8080/api/customers http://localhost:8080/api/orders
===================================================
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
management.endpoints.web.exposure.include=*
Day 3 Recap:
Spring Boot project: simplifies Spring Framework
@SpringBootApplication ==> @ComponentScan ==> @EnableAutoConfiguration [ DataSource, EMF, TomcatEmbeddedContainer, ...]
Spring Data JPA:
JpaRepository @Query ==> JPQL or SQL @Modifying ==> INSERT, UPDATE and DELETE SQL
Day 4:
RESTful Web Service
Charactersitics of RESTful Web services:
- Client-server
- Cachable ==> client side or on MiddleTier [ avoid hits to DB]
- Uniform URL
- Layered
This depedncy includes :
- Tomcat Embedded Web Container
- Spring MVC ==> DispatcherServlet is configured to handle "*" No need explict for WebApplicationInitializer
- HttpMessageHandler for JSON data
Librarires for Java <--> JSON: a) Jackson b) Jettison c) GSON ==> by Google d) Moxy ==> Apcahe
Jackson is configured as default HttpMessageConvertor for Java < -- > JSON
client: GET http://localhost:8080/api/products
Accept:application/json
@GetMapping() public @ResponseBody List getProducts() { return service.getProducts(); }
@ResponseBody ==> handles over List to Jackson to convert it into json
Accept:text/xml
@ResponseBody ==> handles over List to JAXB to convert it into xml
=========================================
GET http://localhost:8080/api/products/3
POST http://localhost:8080/api/products
content-type:application/json
@RequestBody ==> JSON data is converted to Product
(@RequestBody Product p)
http://localhost:8080/api/products http://localhost:8080/api/products/2
==========
POST http://localhost:8080/api/orders
body:
{ "customer" : {"email": "harry@cisco.com"}, "items": [ { "product": {"id": 5}, "qty" : 1}, { "product": {"id": 4}, "qty" : 3}, { "product": {"id": 1}, "qty" : 1} ] }
==========
Try CustomerController
============================
public interface OrderDao extends JpaRepository<Order, Integer>{
@Query("select new com.cisco.prj.dto.ReportDTO(o.oid, o.orderDate, o.total, c.email, c.firstName) from Order o inner join o.customer c")
List<ReportDTO> getReport();
}
@GetMapping("/report") public @ResponseBody List getReport() { return service.getReport(); }
[{"oid":1,"orderDate":"2021-10-26T09:19:12.032+00:00","total":121950.0,"email":"gavin@cisco.com","firstName":"Gavin"},{"oid":2,"orderDate":"2021-10-28T05:03:28.318+00:00","total":173010.0,"email":"harry@cisco.com","firstName":"Harry"}]
============
AOP ==> Aspect Oriented Programming
Why? ==> reduces cross-cutting concerns.
Cross-cutting concerns leads to code tangling and code scattering
public class BankingService {
public void transferFunds(...) {
long startTime = new Date().getTime();
logger.debug("method called!!!"); // log
if(isUserValid(user)) { // security
session.beginTransaction(); // transaction
fromAcc.withdraw(amt); // businesslogic
logger.debug("withdraw done");
toAcc.deposit(amt);
logger.debug("deposit done ...");
...
}
long endTime = new Date().getTime(); // profile
logger.debug( (endTime - startTime) + " ms") ;
}
}
Logging, Security, Profile, transactions ==> Aspects ==> A concern which can be used along with main logic Aspects results in ==>Cross-cutting concerns leads to code tangling and code scattering
===========
Aspect JoinPoint PointCut Advice ==> Before, After, Around, AfterThrowing, AfterReturning
.w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<com.cisco.prj.entity.Product> com.cisco.prj.api.ProductController.addProduct(com.cisco.prj.entity.Product) with 3 errors:
[Field error in object 'product' on field 'price': rejected value [-34.0]; codes [Min.product.price,Min.price,Min.double,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [product.price,price]; arguments []; default message [price],10]; default message [Price -34.0 should be more than 10]]
[Field error in object 'product' on field 'quantity': rejected value [-100]; codes [Min.product.quantity,Min.quantity,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [product.quantity,quantity]; arguments []; default message [quantity],0]; default message [Quantity -100 should be more than 0]]
[Field error in object 'product' on field 'name': rejected value []; codes [NotBlank.product.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [product.name,name]; arguments []; default message [name]]; default message [Name is required]] ]
====================
REST Documentation
1) RAML ==> Rest API modeling Language ==> "yml" files
2) OpenAPI / Swagger ==> Api
books.yml /books: /{bookTitle} get: queryParameters: author: displayName: Author type: string description: An author's full name example: Mary Roach required: false publicationYear: displayName: Pub Year type: number description: The year released for the first time in the US example: 1984 required: false rating: displayName: Rating type: number description: Average rating (1-5) submitted by users example: 3.14 required: false isbn: displayName: ISBN type: string minLength: 10 example: 0321736079 put: queryParameters: access_token: displayName: Access Token type: string description: Token giving you permission to make call required: true
======================================
http://localhost:8080/swagger-ui.html#/
==========================================================
Unit testing RestControllers.
org.springframework.boot spring-boot-starter-test testThis enables below components/ libraries for testing:
- JUnit ==> Testing Framework [ TestNG ]
- Mockito ==> Mocking api
- Hamcrest ==> matchers / assertion
- jsonpath ==> to validate json response [https://jsonpath.com/]
Unit Testing should not load entire spring managed beans
@WebMvcTest(ProductController.class) loads only relevant code for testing and not entire configuration and loads only ProductController [ OrderController and CustomerController are not loaded in test bed created by Spring]
@MockBean private OrderService service; ==> creates a mock OrderService and not actual OrderService bean
MockMvc mockMvc; ==> for making api calls [get / post / put / delete ]
======================================================
Caching
HTTP headers: cache-control, expires, Etag
Middle tier caching to avoid hits to Repository
@EnableCaching by default uses ConcurrentMapCacheManager
@Cacheable(value="productCache", key = "#id")
Input condition @Cacheable(value="productCache", key = "#p.id", condition="#p.price > 1000")
Output Condition @Cacheable(value="productCache", key = "#id", unless="#result == null")
update cache: @CachePut(value="productCache", key ="#id")
REmove from cache @CacheEvict(value="productCache", key ="#id")
@CacheEvict(value="productCache", allEntries="true")
===
@EnableScheduling
@Scheduled(fixedRate = 1000) public void doTask() { System.out.println("do task!!!"); }
@Scheduled(cron = "@daily") public void doTask() { System.out.println("do task!!!"); }
The following macros are also supported:
"@yearly" (or "@annually") to run un once a year, i.e. "0 0 0 1 1 *", "@monthly" to run once a month, i.e. "0 0 0 1 * *", "@weekly" to run once a week, i.e. "0 0 0 * * 0", "@daily" (or "@midnight") to run once a day, i.e. "0 0 0 * * *", "@hourly" to run once an hour, i.e. "0 0 * * * *".
Example expressions:
"0 0 * * * " = the top of every hour of every day. "/10 * * * * *" = every ten seconds. "0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day. "0 0 6,19 * * *" = 6:00 AM and 7:00 PM every day. "0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day. "0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays "0 0 0 25 12 ?" = every Christmas Day at midnight "0 0 0 L * *" = last day of the month at midnight "0 0 0 L-3 * *" = third-to-last day of the month at midnight "0 0 0 1W * *" = first weekday of the month at midnight "0 0 0 LW * *" = last weekday of the month at midnight "0 0 0 * * 5L" = last Friday of the month at midnight "0 0 0 * * THUL" = last Thursday of the month at midnight "0 0 0 ? * 5#2" = the second Friday in the month at midnight "0 0 0 ? * MON#1" = the first Monday in the month at midnight
Clear all entries:
-
@Scheduled(fixedDelay = 5000) @CacheEvict(value = "productCache", allEntries = true) public void doTask() {
}
-
@Autowired CacheManager manager;
@Scheduled(fixedDelay = 5000) public void doTask() { Collection names = manager.getCacheNames(); for(String name : names) { manager.getCache(name).clear(); } }
docker run --name my-redis -p 6379:6379 -d redis
===
Node.JS
npx redis-commander
=============
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Actuator is mainly used to expose operational information about the running application — health, metrics, info, dump, env, etc.
Prometheus / Graffana
Time-series database scrape information timely from actuator and report
172.31.112.1
docker run -d --name=prometheus -p 9090:9090 -v C:\prometheus\prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus --config.file=/etc/prometheus/prometheus.yml
prometheus.yml rules.yml start.txt
try below expression / Graph: jvm_threads_live_threads jvm_threads_peak_threads jvm_threads_states_threads http_server_requests_seconds_count ==> is the total number of request recevied http_server_requests_seconds_sum ==> duration of every request recevied
Check "Alert" tab after making many requests to "api/products"
=================
EntityGraph, Specification API
HATEAOS, Security, Simple MicroService
========================================
Day 4 Recap:
-
RESTful Web services @RestController, @ResponseBody [ Java --> JSON], @RequestBody [ json --> java], @RequestMapping [ Biding URL (generally plural nouns to a resource/controller)] @GetMapping(), @PostMapping(), @PutMapping(), @DeleteMapping() @PathVariable [ Path parameter ], @RequestParam [ Query parameter] ResponseEntity
-
AOP ==> Aspect a concrent which leads to code tangling and code scattering Advice and Pointcut to select JoinPoint
@ControllerAdvice ==> Any exception in Controller/RestController if not handled will be delegated to @ControllerAdvice @ExceptionHandler for methods to handle specific exception
Validation ==> javax.validation.constraints [@Min, @Max, @NotBlank, @Future, @Past, @Pattern]
for method parameter (@RequestBody @Valid Product p)
This throws MethodArgumentNotValidException ==> handled in ControllerAdvice
-
Swagger OpenAPI to document RESTful Web services endpoint
-
Caching ==> ConcurrentHashMap for Caching; Redis as CacheManager / EHCache/ JBoss Swarm Cache
@EnableCaching @Cacheable @CachePut @CacheEvit
@EnableScheduling and @Scheduled( fixedDelay / cron )
- Actuator ==> exposes different metrics like health, info, env, dump of heap/threads/cpu Prometheus ==> Time series database which scrape the information exposed by Actutaor and gives Data Visualization / Alert jvm_threads_live_threads jvm_threads_peak_threads jvm_threads_states_threads http_server_requests_seconds_count ==> is the total number of request recevied http_server_requests_seconds_sum ==> duration of every request recevied
execution("* .(..)") <== Avoid this when used with framework; This applies to built-in frameworks classes; Many a times PRoxying is not allowed
execution("public * pkg.class.method(arguments)")
===============================================
Day 5:
HATEAOS ==> Hypermedia As The Engine of Application State
http://amazon.com/banu@gmail.com/cart
I get Cart Items We need to provide links along with state [ JSON /XML ] for a) checkout b) clear c) remove item from cart ... RepresentationModel EntityModel: A simple wrapping a domain object and adding links to it. CollectionModel: A simple wrapping a colelction entities and adding links to it.
WebMvcLinkBuilder: Builder to ease building {@link Link} instances pointing to Spring MVC controllers.
Comment Swagger Dependicies and SwaggerConfig.java
========
Spring Data REST: makes it easy to build hypermedia-driven REST web services
org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-data-rest org.springframework.boot spring-boot-starter-web <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- create entites and JPARepository interfaces; No need for @Controller / @RestController
=================================
HATEOAS ==> Domain Object + Links ==> WebMvcLinkBuilder for creating links with relationaship [ linkTo and affordance ( exposes HTTP method also)]
EntityModel ==> Wrap Entity + Links CollectionModel ==> Wrap entity collectiosn + links
Spring Data REST
- Spring DATA JPA repositories + HATEOAS
- No need for writing RestControllers
- can override endpoints using @BasePathAwareController and use @RequestMapping
=================================================
- Entity Graph
Flyway is an open-source database-migration tool.
Without Flyway: resources: schema.sql contains CREATE, ALTER, DROP table commands data.sql DML like INSERT , SELECT
companyWithDepartmentsGraph:
select company0_.id as id1_2_0_, company0_.name as name2_2_0_, department1_.company_id as company_3_3_1_, department1_.id as id1_3_1_, department1_.id as id1_3_2_, department1_.company_id as company_3_3_2_, department1_.name as name2_3_2_ from company company0_ left outer join department department1_ on company0_.id=department1_.company_id where company0_.id=?
companyWithDepartmentsAndEmployeesGraph:
select company0_.id as id1_2_0_, company0_.name as name2_2_0_, department1_.company_id as company_3_3_1_, department1_.id as id1_3_1_, department1_.id as id1_3_2_, department1_.company_id as company_3_3_2_, department1_.name as name2_3_2_, employees2_.department_id as departme5_4_3_, employees2_.id as id1_4_3_, employees2_.id as id1_4_4_, employees2_.address_id as address_4_4_4_, employees2_.department_id as departme5_4_4_, employees2_.name as name2_4_4_, employees2_.surname as surname3_4_4_ from company company0_ left outer join department department1_ on company0_.id=department1_.company_id left outer join employee employees2_ on department1_.id=employees2_.department_id where company0_.id=?
=============
JPA Specification API.
is built on Criteria API [ OO way of Querying data instead of SQL / jPQL ]
Spring Data JPA Specifications is yet another tool at our disposal to perform database queries with Spring or Spring Boot. Using Specifications we can build atomic predicates, and combine those predicates to build complex dynamic queries.
=============================
Spring Security
=====
org.springframework.boot spring-boot-starter-security-
By including securty dependencies out of the box all resources are secured;
-
By default it created user with name as "user" and password is generated; Using generated security password: e3c6bca7-579f-4030-964b-c43f02de9abb
-
Login and Logout pages are created
=====================
================= application.properties instead of default user with generated password spring.security.user.name=banu spring.security.user.password=test123
===================
Servlet API Filter ==> Interceptor Pattern
DelegatingFilterProxy is Filter ==> intercept all requests from client
POSTMAN
POST : http://localhost:8080/login
body
{ username : "..", password : ".." }
UsernamePasswordAuthenticationFiler ==> attemptAuthentication() ==> creates Authentication Object with the following detais:
- priciple ==> username from request
- credentials ==> password from request
- authencicated ==> false
- roles ==> Empty
-- Authenication object is passed to AuthenticationManager.
Different AuthenticationProvider ==> Access UserDetailsService implemented by InMemory, JDBC, LDAP, Custom
UserDetailsService==> returns UserDetails ==> update Authentication object
Authentication Object contains now :
- priciple ==> username from request
- credentials ==> null
- authencicated ==> true
- roles ==> ADMIN, USER
Authentication will be stored in SecurityContext; each instance is mapped with JSESSIONID which is sent to client via cookie
From now on client is going to pass cookie with JSESSIONID; using JSESSIONID presting in SecurityContext server identifies client/ roles
JDBCAuthenticationManager
Security ==>
- Authentication
- Authorization
- Exception Handling
JSESSIONID 2ACAD7C1D711D113951A20F60143C3F3
=====================================================
MicroServices
Monolithic applications contains all modules deployed on single server ==> Compromised on data storage ==> Some places we need RDBMS / NoSQL ==> MongoDB / GeoSpatial DB ==> lat long
==> Scalaing indivvidual module is difficult ProductModule CartModule CustomeModule
Netflix OSS:
Eureka Server is an application that holds the information about all client-service applications. Every Micro service will register into the Eureka server and Eureka server knows all the client applications running on each port and IP address. Eureka Server is also known as Discovery Server.
OpenFeign ==> declarative way of invoking APIs from Spring Boot Cloud applicaiton; Alternate: Programatic
RestTemplate
Review revivew = template.getForEntity("uri", Review.class);
==================================================================
Step:
- start Discover-Server ==> Eureka @EnableEurekaServer application.properties server.port=8761
Monitor http://localhost:8761/
- start other services 2.1) Review Services
check Eureka Dashboard
2.2) Movie Service check Eureka Dashboard
http://localhost:8082/api/movies/1
MovieService is making API call to ReviewServices uing Feign client [ declarative interface]
============================================================