Spring Boot Abstract Singleton Service problem - java

Hi everyone this is my simple project code block
This service is renewing by sending a request once a day.
public class SingletonService {
private static final SingletonService INSTANCE = new SingletonService();
public static final int TIMEOUT_SEC = 86400 ;//SECONDS every day ONE REQUEST remote service
private static final Object lock = new Object();
private LocalDateTime queryDate;//Time
private EmployeeRepository employeeRepository;//My Remote Employee Repository
private List<Employee> list = new CopyOnWriteArrayList<>();
SingletonService() {//Singleton Design Pattern
}
public static SingletonService getInstance() {
return INSTANCE;
}
private boolean isTimeout() {//this methods check date
LocalDateTime execDate = LocalDateTime.now();
if (queryDate == null) {
return true;
}
LocalDateTime expireDate = queryDate.plusSeconds(TIMEOUT_SEC);
return expireDate.isBefore(execDate);
}
public synchronized void reload() {//this methods call repository employee list
queryDate = LocalDateTime.now();
list = employeeRepository.findAll();
}
public void initQuery() {//this methods check expire date and list size
synchronized(lock) {
if (isTimeout() || list.size() <= 0) {
reload();
}
}
}
public Integer countLatestRanking() {
return list.size();
}
public void setEmployeeRepository(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
public List<Employee> getList() {
return this.list;
}
public void setList(List<Employee> list) {
this.list = list;
}
}
My SingletonInitService
#Component
public class SingletonInitService {
#Autowired
private EmployeeRepository employeeRepository;
#PostConstruct
public void init() {
SingletonService.INSTANCE.setEmployeeRepository(employeeRepository);
}
public void onContextRefreshedEvent() {
SingletonService.INSTANCE.initQuery();
}
public List<Employee> getEmployees(){
return SingletonService.INSTANCE.getList();
}
}
My EmployeeService
#Service
public class EmployeeService {
#Autowired
private SingletonInitService singletonInitService;
public List<Employee> getEmployees(){
singletonInitService.onContextRefreshedEvent();
return singletonInitService.getEmployees();
}
}
My question is how can I write SingletonService abtract because I have too many repositories and I don't want to write this code over and over again (Please don't say why you didn't use the scheduler because it's not good to use job all the time)

Related

Java - Generic for Payment processing with Strategy pattern

I am trying to implement Strategy pattern approach for payment processing in my Spring webflux based application.
My application supports multiple payment method like, Card Payment, Cash Payment, ...
Also, we have to support Square & Stripe for Card payment.
Model class,
// Model interface
public interface PaymentModel {
}
// Base model with attributes needed for all payment types
public class BaseModel implements PaymentModel {
private Float amount;
private Integer userId;
}
public class SquareCardModel extends BaseModel {
private String merchantId;
private String device;
private String orderId;
}
public class StripeCardModel extends BaseModel {
private String merchantId;
private String orderId;
}
public class CashModel extends BaseModel {
private String name;
private String orderId;
}
Service Class,
#Service
public interface PaymentService<T extends PaymentModel> {
Mono<ServerResponse> pay(T model);
String method();
}
#Service
public class CashPaymentService implements PaymentService<CashModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(CashModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
#Service
public class SquarePaymentService implements PaymentService<SquareCardModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(SquareCardModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
#Service
public class StripePaymentService implements PaymentService<StripeCardModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(SquareCardModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
Factory Class,
#Service
public class PaymentFactory<T> {
private final List<PaymentService<? extends PaymentModel>> paymentServices;
#Autowired
public PaymentFactory(List<PaymentService<? extends PaymentModel>> paymentServices) {
this.paymentServices = paymentServices;
}
public PaymentService<? extends PaymentModel> retrievePaymentService(final String paymentMethod) {
Optional<PaymentService<? extends PaymentModel>> paymentService = paymentServices.stream()
.filter(service -> service.method().equals(paymentMethod)).findFirst();
if (paymentService.isEmpty()) {
throw new IllegalArgumentException("Unsupported Payment method ");
}
return paymentService.get();
}
}
User choose the payment method and the call comes to the backend,
#Transactional
public Mono<ServerResponse> payBilling(ServerRequest request) {
return request.bodyToMono(PaymentDto.class).flatMap(paymentReq -> {
if (paymentReq.getPaymentType().equals("CC")) { // For Card
return processCardPayment(usr, paymentReq);
} else {
return badRequest().bodyValue("Not supported yet !");
}
});
}
private Mono<? extends ServerResponse> processCardPayment(
PaymentDto paymentReq) {
PaymentService<PaymentModel> paymentService = (PaymentService<PaymentModel>) paymentFactory
.retrievePaymentService(paymentReq.getPaymentType());
PaymentModel paymentModel = buildPaymentModel((String) paymentReq.getPaymentType(), paymentReq,
jsonMap);
return paymentService.pay(paymentModel);
}
private PaymentModel buildPaymentModel(final String paymentMethod, final PaymentDto paymentReq,
if (paymentMethod.equals("squarePayment")) {
SquareCardModel model = new SquareCardModel();
model.setAmount(paymentReq.getTotal());
model.setMerchantId(paymentReq.getMerchantid());
model.setOrderId(orderId);
return model;
}
return null;
}
Questions:
Not sure if I have implemented generics properly with the strategy pattern.
Also, I dont like type casting here. (PaymentService). is there any better approach?
Why do I still need to use if for creating different model.
if (paymentMethod.equals("squarePayment")) {
PaymentService<PaymentModel> paymentService = (PaymentService<PaymentModel>) paymentFactory
.retrievePaymentService(paymentReq.getPaymentType());
PaymentModel paymentModel = buildPaymentModel((String) paymentReq.getPaymentType(), paymentReq,
jsonMap);
return paymentService.pay(paymentModel);
Here's a simplified version of your code which I think maintains what you need to do, from a type perspective:
import java.util.Optional;
public class App {
public interface PaymentModel { }
public static class CashModel implements PaymentModel { }
public interface PaymentService<T extends PaymentModel> {
void pay(T model);
void pay2(PaymentModel model);
}
public static class PaymentFactory {
public PaymentService<PaymentModel> retrievePaymentService(final String paymentMethod) {
Optional<PaymentService<PaymentModel>> paymentService = null;
return paymentService.get();
}
public PaymentService<? extends PaymentModel> retrievePaymentService2(final String paymentMethod) {
Optional<PaymentService<PaymentModel>> paymentService = null;
return paymentService.get();
}
}
public static void main(String... args) throws NoSuchFieldException, IllegalAccessException {
PaymentFactory paymentFactory = null;
PaymentService<PaymentModel> paymentService = paymentFactory
.retrievePaymentService("foo");
paymentService.pay(new CashModel());
PaymentService<? extends PaymentModel> paymentService2 = paymentFactory
.retrievePaymentService2("foo");
paymentService2.pay(new CashModel()); // error
paymentService2.pay2(new CashModel()); // ok
}
}
Look at the difference between retrievePaymentService and retrievePaymentService2.
retrievePaymentService returns PaymentService<PaymentModel> which says that it is a payment service which works on any PaymentModel implementation.
retrievePaymentService2 returns PaymentService<? extends PaymentModel> which says that it is a payment service which works on some specific, unknown PaymentModel implementation.
As you have already made sure that your PaymentModel type matches the PaymentService you are getting from the factory, the first form is what you want.
A better design might try to not have two parallel class hierarchies which need to be matched up carefully at runtime.
Also, processCardPayment seems as though it should handle all PaymentModels?

DAO pattern with realm

How can DAO be used with realm? Because when in my activity I try to set members of my model class I get an exception :
java.lang.IllegalStateException: Changing Realm data can only be done from inside a transaction.
I know that using realm.executeTransaction fixes the issue, but the code in my activity is no more database-agnostic because it will countain code that is specific to low level database communication. So later if I want to change database, the refactoring will cost a lot of time and work... Besides, I will have to handle in all my activities a reference to Realm.getDefaultInstance();
Here is sample of code of my activity
protected void onCreate(Bundle savedInstanceState)
{
mBook = mBookDaoImpl.getBookById(bookId);
}
// Later in the code
private void saveBook(String name)
{
mBook.setName(name);
}
Here is my model class
public class Book extends RealmObject
{
#Required
#PrimaryKey
private String id;
private String name;
public Book() {
}
public Book(String id, String name) {
this.id = id;
this.name = name;
}
// getter setter methods
}
Here is my DAO interface :
public interface BookDao
{
List<Book> getAllBooks();
Book getBookByIsbn(int isbn);
void saveBook(Book book);
void deleteBook(Book book);
}
And finally is my implementation :
public class BookDaoImpl implements BookDao
{
private static BookDaoImpl INSTANCE = null;
private Realm mRealm;
private BookDaoImpl()
{
mRealm = Realm.getDefaultInstance();
}
public static BookDaoImpl getInstance()
{
if (INSTANCE == null)
INSTANCE = new BookDaoImpl();
return INSTANCE;
}
#Override
public List<Book> getAllBooks()
{
return mRealm.where(Book.class).findAll();
}
#Override
public Book getBookById(String id)
{
return mRealm.where(Book.class).equalTo("id", id).findFirst();
}
#Override
public void saveBook(final Book book)
{
mRealm.executeTransaction(new Realm.Transaction()
{
#Override
public void execute(Realm realm)
{
if (book.getId() == null)
book.setId(UUID.randomUUID().toString());
realm.copyToRealmOrUpdate(book);
}
});
}
#Override
public void deleteBook(final Book book)
{
mRealm.executeTransaction(new Realm.Transaction()
{
#Override
public void execute(Realm realm)
{
mRealm.where(Counter.class).equalTo("id", book.getId())
.findFirst()
.deleteFromRealm();
}
});
}
}
Realm's getInstance() method returns a thread-local, reference counted instance which must be paired with a close() call, so your DAO implementation probably won't suit what you expect.
If you use my library Realm-Monarchy which I created specifically for making it easier to "abstract Realm away", then you can implement your DAO like this:
public class BookDaoImpl implements BookDao
{
private static BookDaoImpl INSTANCE = null;
private Monarchy monarchy;
private BookDaoImpl(Monarchy monarchy)
{
this.monarchy = monarchy;
}
public static BookDaoImpl getInstance(Monarchy monarchy)
{
if (INSTANCE == null) {
synchronized(BookDaoImpl.class) {
if(INSTANCE == null) {
INSTANCE = new BookDaoImpl(monarchy);
}
}
}
return INSTANCE;
}
#Override
public List<Book> getAllBooks()
{
return monarchy.fetchAllCopiedSync((realm) -> realm.where(Book.class));
}
#Override
public Book getBookById(final String id)
{
List<Book> books = monarchy.fetchAllCopiedSync((realm) -> realm.where(Book.class).equalTo("id", id));
if(books.isEmpty()) {
return null;
} else {
return books.get(0);
}
}
#Override
public void saveBook(final Book book)
{
monarchy.runTransactionSync((realm) -> {
if (book.getId() == null)
book.setId(UUID.randomUUID().toString());
realm.insertOrUpdate(book);
});
}
#Override
public void deleteBook(final Book book)
{
monarchy.runTransactionSync((realm) -> {
realm.where(Counter.class).equalTo("id", book.getId())
.findFirst()
.deleteFromRealm();
});
}
}
P.S.: you're throwing away a lot of power/functionality if you return List<T> synchronously, instead of an observable like LiveData<List<T>> (or originally, RealmResults<T>).

Spring boot - Service class is null

I'm dwelling with an autoWired service class which is null in a Spring Boot application.. Every object is instantiated by Spring, so I don't know why it happens.
The situation is:
I have a Rele.java class which is the following:
#Component
public class Rele {
private Pin pin;
private GpioController gpio;
private GpioPinDigitalOutput relePin;
private static final Logger logger = Logger.getLogger(Rele.class);
private Interruttore interruttore;
#Autowired AccensioneService accensioneService;
public Rele(){
}
// Costruttore
public Rele(Pin pin, Interruttore interruttore) {
this.pin = pin;
this.gpio = GpioFactory.getInstance();
this.relePin = gpio.provisionDigitalOutputPin(pin, "MyRele", PinState.LOW);
this.interruttore = interruttore;
}
public void lightOn() {
try {
if (relePin.isLow()) {
relePin.high();
updateAccensione(interruttore, true);
logger.debug("Rele acceso");
}
} catch (NullPointerException e) {
logger.debug("relepin è:" +relePin);
logger.debug("gpio è:"+gpio);
}
}
public void lightOff() {
if (relePin.isHigh()) {
relePin.low();
updateAccensione(interruttore, false);
logger.debug("Rele spento");
}
}
public void updateAccensione(Interruttore interruttore, boolean acceso) {
Date lastDateAccensione = new Date();
try {
logger.debug("accensioneService is"+accensioneService);
lastDateAccensione = accensioneService.findLastDate(interruttore);
} catch(NullPointerException npe){
logger.debug("accensioneService is: "+accensioneService);
logger.error("Error is:", npe);
lastDateAccensione = new Timestamp(lastDateAccensione.getTime());
}
Accensione accensione = new Accensione();
Date date = new Date();
logger.debug("lastDate:" + lastDateAccensione);
accensione.setDateTime(new Timestamp(date.getTime()));
accensione.setInterruttore(interruttore);
accensione.setIsLit(acceso);
accensione.setLastDateTime(lastDateAccensione);
logger.debug("Accensione è:"+accensione.toString());
accensioneService.saveAccensione(accensione);
}
public Pin getPin() {
return pin;
}
public void setPin(Pin pin) {
this.pin = pin;
}
public Interruttore getInterruttore() {
return interruttore;
}
public void setInterruttore(Interruttore interruttore) {
this.interruttore = interruttore;
}
public GpioPinDigitalOutput getRelePin() {
return relePin;
}
public void setRelePin(GpioPinDigitalOutput relePin) {
this.relePin = relePin;
}
public GpioController getGpio() {
return gpio;
}
public void setGpio(GpioController gpio) {
this.gpio = gpio;
}
}
When trying to call for updateAccensione, this is null.
Rele is created from a Controller, by this method
#RequestMapping(value="/illuminazione")
public ResponseEntity<Illuminazione> findIlluminazione(#RequestParam(value="idLuce") int idLuce,
#RequestParam(value="lit") boolean lit,
#RequestParam(value="suServer") boolean suServer) {
Illuminazione illuminazione = new Illuminazione();
Date lastDate = illuminazioneService.findLastDate(idLuce);
illuminazione.setLastDateTime(lastDate);
illuminazione.setIdLuce(idLuce);
illuminazione.setIsLit(lit);
Date date = new Date();
illuminazione.setDateTime(new Timestamp(date.getTime()));
illuminazioneService.saveIlluminazione(illuminazione);
logger.debug("Aggiornata luce " + idLuce + " accesa: "+lit);
//managing rele
if(suServer){
//check if status has changed
Luce luce = luceService.findById(idLuce);
int idInterruttore = luce.getInterruttore().getIdInterruttore();
Interruttore interruttore = interruttoreService.findById(idInterruttore);
Rele rele = releService.findByInterruttore(interruttore);
logger.debug("rele="+rele.toString());
if(lit){
rele.lightOn();
} else {
rele.lightOff();
}
}
return new ResponseEntity<Illuminazione>(illuminazione,HttpStatus.OK);
}
Rele is created, i find it in my logs.
AccensioneService is an interface, it's concrete implementation is AccensioneServiceImpl:
#Service("accensioneService")
#Transactional
public class AccensioneServiceImpl implements AccensioneService{
#Autowired AccensioneDao dao;
#Override
public void saveAccensione(Accensione accensione) {
dao.saveAccensione(accensione);
}
#Override
public Accensione findById(int id) {
return dao.findById(id);
}
#Override
public Date findLastDate(Interruttore interruttore) {
return dao.findLastDate(interruttore);
}
#Override
public boolean findLastStatus(int id) {
return dao.findLastStatus(id);
}
#Override
public void updateAccensione(Interruttore interruttore) {
}
}
I don't know if anything else is needed. AccensioneService is also called in other methods and controller, and it works... only when called inside Rele gives me this error...
Edited to add
You must be calling new Rele() or the other Rele(Pin, Interruttore ) constructor? If you are calling these in your code, the accensioneService will be null because Spring needs to create the bean, you cannot create it with its constructor if you want beans Autowired into it or for it to be Autowired. If you want it to behave like this, Spring has to know about it, so it has to be in (and come from) the Spring context.
Put a log statement in each constructor and find out who is calling them, and fix that so that instead of calling the constructor, you get the bean from Spring.
Old answer below
You need to post this method to be sure:
Rele rele = releService.findByInterruttore(interruttore);
I'll bet you are creating rele somewhere by calling new Rele(), which is not correct. You need to let Spring create it for you.
You did not post enough code to give further suggestions.
Also, you say this is null. What this are you talking about?

How abstract common classes?

Am developing webapplication with JSF and Hibernate, have Entity, Entity data access & JSF managed bean classes in following pattern and same repeats in all the classes. Since all the classes have the same pattern, I would like to make it as abstract class.
Entity Class
public class MyEntity {
-----
-----
}
Data Access class
public class MyEntityDAO extends AbstractDAO<MyEntity> {
MyEnitityDAO(){
-------
}
}
JSF Managed bean
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private MyEntity current;
private MyEntityDAO dao;
private DataModel<MyEntity> items = null;
public MyBean() {
// TODO Auto-generated constructor stub
}
public MyEntity getCurrent() {
return current;
}
public void setCurrent(MyEntity current) {
this.current = current;
}
public MyEntityDAO getDao() {
if (dao == null) {
dao = new MyEntityDAO();
}
return dao;
}
public DataModel<MyEntity> getItems() {
return items;
}
public List<MyEntity> getMyEntityList() {
return getDao().findAll();
}
public MyEntity getMyEntity(int id) {
return getDao().findById(id);
}
private void reSetDataModel() {
items = null;
}
private void reSetCurrent() {
setCurrent(null);
}
public void prepareCreate() {
current = new MyEntity();
}
public void create() {
// Save the entity
}
public void edit() {
// Update the entity
}
public void delete() {
// Remove the entity
}
}
How to make the abstract class out of above pattern?
Type the word abstract between public and class

Java - Singleton is causing null errors

I made a DAO class with factory method and the specific DAO returns singleton, a single instance of the DAO. But I been tracing it and its being created but I try to call on it and it always null.
Just to explain the storage factory
I call on DAOFactory to get RAMDAOFactory to get to RAMUserDAO
If there is better way to handle RAM, Serialization and SQL type DAOs or CRUD please let me know.
class that I'm calling the storage from.
public class Registration
{
private UserDAO userStorage;
private static Logger log = LogClass.getLog();
Registration(DAOFactoryType typeDataStorage)
{
userStorage = DAOFactory.getDAOFactory(typeDataStorage).getUserDAO();
log.trace("insdie Reg");
}
void addUser(String userName, String password, UserType... args)
throws Exception
{
List<UserType> userTypes = new ArrayList<UserType>(args.length);
for (UserType userType : args)
{
log.trace("userType " + userType);
userTypes.add(userType);
}
User newUser = new DefaultUser(userName, password, userTypes);
log.trace("newUser " + newUser);
if (userStorage != null)
{
userStorage.insert(newUser);
}
else
{
log.trace("userStorage null");
}
}
}
This is my DAOFactory
public abstract class DAOFactory
{
private static Logger log = LogClass.getLog();
public abstract TradeDAO getTradeDAO();
public abstract UserDAO getUserDAO();
public abstract LogDAO getLogDAO();
public static DAOFactory getDAOFactory(DAOFactoryType factoryType)
{
switch (factoryType)
{
case SQL:
return new SQLDAOFactory();
case RAM:
log.trace("insdie RAM");
return new RAMDAOFactory();
case SERIAL:
return new SerialDAOFactory();
default:
return null;
}
}
}
RAMDAOFactory
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
private TradeDAO ramTradeDAO;
private UserDAO ramUserDAO;
private LogDAO ramLogDAO;
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
#Override
public TradeDAO getTradeDAO()
{
return ramTradeDAO;
}
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
#Override
public LogDAO getLogDAO()
{
return ramLogDAO;
}
}
This is my UserDAO
public class RAMUserDAO implements UserDAO
{
/*
* Map<Integer, List<byte[]>> userHash; List<byte[]> arrayHashSalt;
*/
private static RAMUserDAO userDAO = null;
private Map<String, User> userList;
private static Logger log = LogClass.getLog();
private RAMUserDAO()
{
userList = new HashMap<String, User>();
log.trace("insdie RAMUserDAO constructor");
}
public static RAMUserDAO getRAMUserDAO()
{
log.trace("insdie getRAMUserDAO");
if(userDAO == null) {
log.trace("insdie new RAMUserDAO()");
userDAO = new RAMUserDAO();
}
/*if (userDAO == null)
{
synchronized (RAMUserDAO.class)
{
if (userDAO == null)
{
userDAO = new RAMUserDAO();
}
}
}*/
return userDAO;
}
#Override
public void insert(User user) throws Exception
{
log.trace("insdie insert");
userList.put(user.getUserName(), user);
}
}
The oversight was in RAMDAOFactory and fix was:
public class RAMDAOFactory extends DAOFactory
{
private static Logger log = LogClass.getLog();
#Override
public TradeDAO getTradeDAO()
{
return RAMTradeDAO.getRAMTradeDAO();
}
#Override
public UserDAO getUserDAO()
{
return RAMUserDAO.getRAMUserDAO();
}
#Override
public LogDAO getLogDAO()
{
return RAMLogDAO.getRAMLogDAO();
}
}
You've called the methods
public RAMDAOFactory()
{
log.trace("insdie RAMDAOFactory");
RAMUserDAO.getRAMUserDAO();
RAMTradeDAO.getRAMTradeDAO();
RAMLogDAO.getRAMLogDAO();
}
but you haven't assigned their value to anything
#Override
public UserDAO getUserDAO()
{
return ramUserDAO;
}
Either always call
RAMUserDao.getRAMUserDAO();
when you want to return the UserDAO or assign it to ramUserDAO and return that.

Categories

Resources