Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Antonio Rueda
/
UJACoin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
34ee0a7c
authored
Nov 23, 2020
by
Antonio Rueda
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Modificados atributos de transacción. Bloqueo pesimista en operaciones
en las cuentas.
parent
c0779679
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
113 additions
and
9 deletions
pom.xml
src/main/java/es/ujaen/dae/ujacoin/entidades/Cuenta.java
src/main/java/es/ujaen/dae/ujacoin/repositorios/RepositorioClientes.java
src/main/java/es/ujaen/dae/ujacoin/repositorios/RepositorioCuentas.java
src/main/java/es/ujaen/dae/ujacoin/servicios/ServicioUjaCoin.java
src/test/java/es/ujaen/dae/ujacoin/servicios/ServicioUjaCoinTest.java
pom.xml
View file @
34ee0a7c
...
...
@@ -50,6 +50,13 @@
<artifactId>
junit-jupiter
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.assertj
</groupId>
<artifactId>
assertj-core
</artifactId>
<scope>
test
</scope>
</dependency>
</dependencies>
<build>
...
...
src/main/java/es/ujaen/dae/ujacoin/entidades/Cuenta.java
View file @
34ee0a7c
...
...
@@ -11,7 +11,6 @@ import es.ujaen.dae.ujacoin.util.ExprReg;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.stream.Collectors
;
import
javax.persistence.CascadeType
;
import
javax.persistence.Entity
;
...
...
@@ -19,7 +18,7 @@ import javax.persistence.Id;
import
javax.persistence.JoinColumn
;
import
javax.persistence.ManyToOne
;
import
javax.persistence.OneToMany
;
import
javax.persistence.
Transient
;
import
javax.persistence.
Version
;
import
javax.validation.constraints.NotNull
;
import
javax.validation.constraints.Pattern
;
import
javax.validation.constraints.PositiveOrZero
;
...
...
@@ -50,6 +49,9 @@ public class Cuenta {
@JoinColumn
(
name
=
"cuenta_num"
)
List
<
Movimiento
>
movimientos
;
// @Version
// int version;
public
Cuenta
()
{
}
...
...
src/main/java/es/ujaen/dae/ujacoin/repositorios/RepositorioClientes.java
View file @
34ee0a7c
...
...
@@ -11,6 +11,7 @@ import java.util.Optional;
import
javax.persistence.EntityManager
;
import
javax.persistence.PersistenceContext
;
import
org.springframework.stereotype.Repository
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
/**
...
...
@@ -18,11 +19,12 @@ import org.springframework.transaction.annotation.Transactional;
* @author ajrueda
*/
@Repository
@Transactional
@Transactional
(
propagation
=
Propagation
.
REQUIRED
)
public
class
RepositorioClientes
{
@PersistenceContext
EntityManager
em
;
@Transactional
(
propagation
=
Propagation
.
SUPPORTS
,
readOnly
=
true
)
public
Optional
<
Cliente
>
buscar
(
String
dni
)
{
return
Optional
.
ofNullable
(
em
.
find
(
Cliente
.
class
,
dni
));
}
...
...
src/main/java/es/ujaen/dae/ujacoin/repositorios/RepositorioCuentas.java
View file @
34ee0a7c
...
...
@@ -6,10 +6,13 @@
package
es
.
ujaen
.
dae
.
ujacoin
.
repositorios
;
import
es.ujaen.dae.ujacoin.entidades.Cuenta
;
import
es.ujaen.dae.ujacoin.entidades.movimientos.Reintegro
;
import
java.util.Optional
;
import
javax.persistence.EntityManager
;
import
javax.persistence.LockModeType
;
import
javax.persistence.PersistenceContext
;
import
org.springframework.stereotype.Repository
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
/**
...
...
@@ -17,15 +20,21 @@ import org.springframework.transaction.annotation.Transactional;
* @author ajrueda
*/
@Repository
@Transactional
@Transactional
(
propagation
=
Propagation
.
REQUIRED
)
public
class
RepositorioCuentas
{
@PersistenceContext
EntityManager
em
;
@Transactional
(
propagation
=
Propagation
.
SUPPORTS
,
readOnly
=
true
)
public
Optional
<
Cuenta
>
buscar
(
String
num
)
{
return
Optional
.
ofNullable
(
em
.
find
(
Cuenta
.
class
,
num
));
}
@Transactional
(
propagation
=
Propagation
.
SUPPORTS
,
readOnly
=
true
)
public
Optional
<
Cuenta
>
buscarYBloquear
(
String
num
)
{
return
Optional
.
ofNullable
(
em
.
find
(
Cuenta
.
class
,
num
,
LockModeType
.
PESSIMISTIC_WRITE
));
}
public
void
guardar
(
Cuenta
cuenta
)
{
em
.
persist
(
cuenta
);
}
...
...
src/main/java/es/ujaen/dae/ujacoin/servicios/ServicioUjaCoin.java
View file @
34ee0a7c
...
...
@@ -126,13 +126,14 @@ public class ServicioUjaCoin {
* @param dni el DNI del cliente
* @param tarjeta la tarjeta a registrar
*/
@Transactional
//
@Transactional
public
void
registrarTarjeta
(
@NotBlank
String
dni
,
@NotNull
@Valid
Tarjeta
tarjeta
)
{
// Cliente cliente = Optional.ofNullable(clientes.get(dni)).orElseThrow(ClienteNoRegistrado::new);
Cliente
cliente
=
repositorioClientes
.
buscar
(
dni
).
orElseThrow
(
ClienteNoRegistrado:
:
new
);
cliente
.
verTarjeta
(
tarjeta
.
getNum
()).
ifPresent
(
x
->
{
throw
new
TarjetaYaRegistrada
();
}
);
cliente
.
nuevaTarjeta
(
tarjeta
);
repositorioClientes
.
actualizar
(
cliente
);
}
/**
...
...
@@ -176,7 +177,7 @@ public class ServicioUjaCoin {
// Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta
cuenta
=
repositorioCuentas
.
buscar
(
numCuenta
)
Cuenta
cuenta
=
repositorioCuentas
.
buscar
YBloquear
(
numCuenta
)
.
orElseThrow
(
CuentaNoRegistrada:
:
new
);
Tarjeta
tarjeta
=
cuenta
.
getTitular
().
verTarjeta
(
numTarjeta
)
...
...
@@ -196,7 +197,7 @@ public class ServicioUjaCoin {
//Cuenta cuenta = Optional.ofNullable(cuentas.get(numCuenta))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta
cuenta
=
repositorioCuentas
.
buscar
(
numCuenta
)
Cuenta
cuenta
=
repositorioCuentas
.
buscar
YBloquear
(
numCuenta
)
.
orElseThrow
(
CuentaNoRegistrada:
:
new
);
Tarjeta
tarjeta
=
cuenta
.
getTitular
().
verTarjeta
(
numTarjeta
)
...
...
@@ -216,13 +217,13 @@ public class ServicioUjaCoin {
// Cuenta cuentaOrigen = Optional.ofNullable(cuentas.get(numCuentaOrigen))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta
cuentaOrigen
=
repositorioCuentas
.
buscar
(
numCuentaOrigen
)
Cuenta
cuentaOrigen
=
repositorioCuentas
.
buscar
YBloquear
(
numCuentaOrigen
)
.
orElseThrow
(
CuentaNoRegistrada:
:
new
);
// Cuenta cuentaDestino = Optional.ofNullable(cuentas.get(numCuentaDestino))
// .orElseThrow(CuentaNoRegistrada::new);
Cuenta
cuentaDestino
=
repositorioCuentas
.
buscar
(
numCuentaDestino
)
Cuenta
cuentaDestino
=
repositorioCuentas
.
buscar
YBloquear
(
numCuentaDestino
)
.
orElseThrow
(
CuentaNoRegistrada:
:
new
);
cuentaOrigen
.
nuevoMovimiento
(
new
TransferenciaEmitida
(
cuentaDestino
,
importe
));
...
...
src/test/java/es/ujaen/dae/ujacoin/servicios/ServicioUjaCoinTest.java
View file @
34ee0a7c
...
...
@@ -12,16 +12,22 @@ import es.ujaen.dae.ujacoin.entidades.movimientos.Ingreso;
import
es.ujaen.dae.ujacoin.entidades.movimientos.Movimiento
;
import
es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaEmitida
;
import
es.ujaen.dae.ujacoin.entidades.movimientos.TransferenciaRecibida
;
import
es.ujaen.dae.ujacoin.excepciones.SaldoInsuficienteParaOperacion
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.Future
;
import
javax.validation.ConstraintViolationException
;
import
org.assertj.core.api.Assertions
;
import
org.junit.jupiter.api.BeforeEach
;
import
org.junit.jupiter.api.Test
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.orm.ObjectOptimisticLockingFailureException
;
/**
*
...
...
@@ -211,6 +217,83 @@ public class ServicioUjaCoinTest {
Assertions
.
assertThat
(
cuentaDestino
.
getSaldo
()).
isEqualTo
(
500
);
}
@Test
public
void
testReintegroDoble
()
{
// Registrar cliente
Cliente
cliente
=
new
Cliente
(
"11995667D"
,
"Juan España España"
,
LocalDate
.
of
(
1990
,
11
,
1
),
"Cl La Luz, 13 - Jaén"
,
"988674533"
,
"jee@gmail.com"
,
"claveyyy"
);
Cuenta
cuenta
=
servicioUjaCoin
.
altaCliente
(
cliente
);
// Añadir una tarjeta
Tarjeta
tarjeta
=
new
Tarjeta
(
"4111111111111111"
,
cliente
.
getNombre
(),
LocalDate
.
of
(
2022
,
12
,
1
),
"365"
);
servicioUjaCoin
.
registrarTarjeta
(
cliente
.
getDni
(),
tarjeta
);
cliente
.
nuevaTarjeta
(
tarjeta
);
// Obtener cuenta y realizar ingreso en cuenta
servicioUjaCoin
.
ingreso
(
cuenta
.
getNum
(),
tarjeta
.
getNum
(),
1000
);
Assertions
.
assertThatThrownBy
(()
->
{
servicioUjaCoin
.
reintegro
(
cuenta
.
getNum
(),
tarjeta
.
getNum
(),
1000
);
servicioUjaCoin
.
reintegro
(
cuenta
.
getNum
(),
tarjeta
.
getNum
(),
1000
);
}).
isInstanceOfAny
(
SaldoInsuficienteParaOperacion
.
class
);
}
@Test
public
void
testReintegroDobleParalelo
()
{
// Registrar cliente
Cliente
cliente
=
new
Cliente
(
"11995667D"
,
"Juan España España"
,
LocalDate
.
of
(
1990
,
11
,
1
),
"Cl La Luz, 13 - Jaén"
,
"988674533"
,
"jee@gmail.com"
,
"claveyyy"
);
Cuenta
cuenta
=
servicioUjaCoin
.
altaCliente
(
cliente
);
// Añadir una tarjeta
Tarjeta
tarjeta
=
new
Tarjeta
(
"4111111111111111"
,
cliente
.
getNombre
(),
LocalDate
.
of
(
2022
,
12
,
1
),
"365"
);
servicioUjaCoin
.
registrarTarjeta
(
cliente
.
getDni
(),
tarjeta
);
cliente
.
nuevaTarjeta
(
tarjeta
);
// Obtener cuenta y realizar ingreso en cuenta
servicioUjaCoin
.
ingreso
(
cuenta
.
getNum
(),
tarjeta
.
getNum
(),
1000
);
Assertions
.
assertThatThrownBy
(()
->
{
// Lanzar un reintegro en un thread secundario
ExecutorService
executor
=
Executors
.
newSingleThreadExecutor
();
Future
<?>
result
=
executor
.
submit
(
()
->
{
servicioUjaCoin
.
reintegro
(
cuenta
.
getNum
(),
tarjeta
.
getNum
(),
1000
);
}
);
executor
.
shutdown
();
// Con una pausa siempre funciona :-)
// Thread.sleep(1000);
// Ejecutar otro reintegro en el thread principal
servicioUjaCoin
.
reintegro
(
cuenta
.
getNum
(),
tarjeta
.
getNum
(),
1000
);
// Esperar finalización del reintegro en el thread secundario
// Y obtener excepciones si las hay
try
{
result
.
get
();
}
catch
(
ExecutionException
e
)
{
throw
e
.
getCause
();
}
}).
isInstanceOfAny
(
SaldoInsuficienteParaOperacion
.
class
);
}
@BeforeEach
void
limpiarBaseDatos
()
{
limpiadorBaseDatos
.
limpiar
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment