Java - Singleton is causing null errors - java

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.

Related

Why triggered only one cache? (RedisCacheManager and CacheOperationInvocationContext issue)

I configure first_cache and it works fine.
But when I want add second_cache in FirstCasheResolver CacheOperationInvocationContext has only one cache while RedisCacheManager has two caches.
Also SecondCacheResolver even not triggered.
Please help me.
Here is my CacheConfiguration class
#EnableCaching
#Configuration
public class CacheConfiguration {
public static final String FIRST_CACHE_NAME = "first_cache";
public static final String SECOND_CACHE_NAME = "second_cache";
private int defaultTokenExpirationTime = 1000;
#Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(getDefaultRedisCacheConfiguration())
.withCacheConfiguration(FIRST_CACHE_NAME, getCustomRedisCacheConfiguration())
.withCacheConfiguration(SECOND_CACHE_NAME, getCustomRedisCacheConfiguration())
.build();
}
private RedisCacheConfiguration getDefaultRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues();
}
private RedisCacheConfiguration getCustomRedisCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(defaultTokenExpirationTime));
}
#Bean("firstCacheResolver")
public CacheResolver firstCacheResolver(RedisCacheManager redisCacheManager) {
return new FirstCacheResolver(redisCacheManager);
}
#Bean("secondCacheResolver")
public CacheResolver secondCacheResolver(RedisCacheManager redisCacheManager) {
return new SecondCacheResolver(redisCacheManager);
}
}
Here is my FirstCacheResolver class
public class FirstCacheResolver extends SimpleCacheResolver {
public FirstCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
return super.resolveCaches(context).stream().toList();
}
}
here super.resolveCaches(context) returns list only one first_cache but CacheManager has first_cache and second_cache
Here is my SecondCacheResolver class
public class SecondCacheResolver extends SimpleCacheResolver {
public SecondCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
#Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
return super.resolveCaches(context).stream().toList();
}
}
this resolveCaches() method even not triggered
here is usage of both caches. They
public class FirstClass {
#Cacheable(
cacheNames = {CacheConfiguration.FIRST_CACHE_NAME},
key = "#params.get('first').get(0)",
cacheResolver = "firstCacheResolver"
)
public int getFirst(MultiValueMap<String, Object> params) {
// some logic
}
}
public class SecondClass {
#Cacheable(
cacheNames = {CacheConfiguration.SECOND_CACHE_NAME},
key = "#params.get('second').get(0)",
cacheResolver = "secondCacheResolver"
)
public int getSecond(MultiValueMap<String, Object> params) {
// some logic
}
}
cacheManager in debug
I try implement two caches with custom CacheResolvers.

add data to the database from a class

hello can I add data in the databse DAO from a class, or can I do it only from the mainthread?For example, if i have Database DAO:
public interface UserDAO {
#Query("select*from User")
List<User> getAll();
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(User...users);
}
and i have Appdatabase.class:
#Database(entities = {User.class},version=1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDAO userDAO();
}
i also have a class that initializes the DAO database:
Model_user {
public static synchronized Model_user getInstance() {
if (theinstance == null) {
theinstance = new Model_user();
}
return theinstance;
}
public static synchronized Model_user getInstance(Context c) {
if (theinstance == null) {
userDAOs = Room.databaseBuilder(c, AppDatabase.class, "userdb").build();
theinstance = new Model_user();
}
return theinstance;
}
private Model_user() {
user_list = new ArrayList<User>();
}
public void addUsers(User[] s) {
Log.d("main_activity_uid", "ok it start");
userDAOs.userDAO().insertAll(s);
user_list.addAll(Arrays.asList(s));
Log.d("main_activity_uid", "ok");
return;
}
Now in Utils.class , i can't add data;in Utils.class i have:
Model_user.getInstance(activity.getApplicationContext()).addUsers(u.toArray(new User[0]));
for store data in DAO database,but but it does not start.Why?How can i do? can i add data to the DAO database only from the main activity?

Not able to access InheritableThreadLocal object from parent thread in fall back method

I have InheritableThreadLocal<ConcurrentHashMap<String, Object>> thread that initializes when a request comes via the filter and set some transaction_id in it.
Now at the service layer, I'm calling 10 different API calls via CompletableFuture. All API service class have one execute method that is using RestTempate to make an API call. I put #HystrixCommand on execute method.
execute method is void type but it put the API response in InheritableThreadLocal object.
Problem is when an API call fails Hystrix call FallBackMethod and when I put error response in InheritableThreadLocal, I'm not able to send that error response to the client.
ThreadLocalUtil.class
public class ThreadLocalUtil {
private static InheritableThreadLocal<ConcurrentHashMap<String, Object>> transmittableThreadLocal = new InheritableThreadLocal<>();
public static void addDataToThreadLocalMap(String key, Object value) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
if (value != null) {
existingDataMap.put(key, value);
}
}
public static Object getDataFromThreadLocalMap(String key) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
return existingDataMap.get(key);
}
public static void clearThreadLocalDataMap() {
if (transmittableThreadLocal != null)
transmittableThreadLocal.remove();
}
public static Object getRequestData(String key) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
if (existingDataMap != null) {
return existingDataMap.get(key);
}
return "-1";
}
public static void initThreadLocals() {
ConcurrentHashMap<String, Object> dataForDataMap = new ConcurrentHashMap<String, Object>();
String requestId = "REQUEST_ID_" + System.currentTimeMillis();
dataForDataMap.put("REQUEST_ID", requestId);
transmittableThreadLocal.set(dataForDataMap);
}
}
CommonFilter.class
#Component
#Order(1)
public class CommonFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
ThreadLocalUtil.initThreadLocals();
filterChain.doFilter(request, response);
} catch (Exception e) {
if (e instanceof ServletException) {
throw (ServletException) e;
}
} finally {
ThreadLocalUtil.clearThreadLocalDataMap();
}
}
EmployeeService.class
#Component
public abstract class EmployeeService {
#Autowired
private ThreadLocalUtil threadLocalUtil;
public abstract void getEmployee(int employeeId);
public void fallbackMethod(int employeeid) {
threadLocalUtil.addDataToThreadLocalMap("ErrorResponse", "Fallback response:: No employee details available temporarily");
}
}
EmployeeServiceImpl.class
#Service
public class EmployeeServiceImpl extends EmployeeService {
#HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
#HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "900"),
#HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10") })
public void getEmployee(int employeeId) {
System.out.println("Getting Employee details for " + employeeId + ", threadLocalUtil : " + threadLocalUtil.getDataFromThreadLocalMap("EMPLOYE_ID"));
String response = restTemplate.exchange("http://localhost:8011/findEmployeeDetails/{employeeid}",
HttpMethod.GET, null, new ParameterizedTypeReference<String>() {
}, employeeId).getBody();
threadLocalUtil.addDataToThreadLocalMap("Response", response);
}
#Autowired
RestTemplate restTemplate;
#Autowired
private ThreadLocalUtil threadLocalUtil;
}
So, first of all since internally Hystrix uses ThreadPoolExecutor (Threads created once and reused), so it is wrong to use InheritableThreadLocal.
From the above question and what you asked in my blog, I understand that you problem is
InheritableThreadLocal becomes null in hystrix fallback method
Further adding to this (you may verify this)
InheritableThreadLocal becomes null in hystrix fallback method only in case of timeouts and not in case of any other exception
I would recommend others to refer to my blog. Hystrix fallback in case of timeout, takes place in hystrix-timer thread.
Hystrix fallback execution thread
You can verify this by logging Thread.currentThread().getName()
Since the parent of hystrix-timer thread is not your calling thread, and so your transmittableThreadLocal.get() becomes null.
To solve this I would recommend using HystrixCommandExecutionHook and HystrixRequestVariableDefault. Using this you can implement hooks like onStart, onExecutionStart, onFallbackStart etc., in which you need to get/set the threadLocal variables. For more details you can refer to the last section in the blog.
Update:
For your use-case you can modify your code as follows:
ThreadLocalUtil.java
public class ThreadLocalUtil {
private static ThreadLocal<ConcurrentHashMap<String, Object>> transmittableThreadLocal = new ThreadLocal<>();
public static ConcurrentHashMap<String, Object> getThreadLocalData() {
return transmittableThreadLocal.get();
}
public static void setThreadLocalData(ConcurrentHashMap<String, Object> data) {
transmittableThreadLocal.set(data);
}
public static void addDataToThreadLocalMap(String key, Object value) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
if (value != null) {
existingDataMap.put(key, value);
}
}
public static Object getDataFromThreadLocalMap(String key) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
return existingDataMap.get(key);
}
public static void clearThreadLocalDataMap() {
if (transmittableThreadLocal != null)
transmittableThreadLocal.remove();
}
public static Object getRequestData(String key) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
if (existingDataMap != null) {
return existingDataMap.get(key);
}
return "-1";
}
public static void initThreadLocals() {
transmittableThreadLocal.set(new ConcurrentHashMap<>());
String requestId = "REQUEST_ID_" + System.currentTimeMillis();
addDataToThreadLocalMap("REQUEST_ID", requestId);
}
}
EmployeeService.java
#Component
public abstract class EmployeeService {
public abstract void getEmployee(int employeeId);
public void fallbackMethod(int employeeid) {
threadLocalUtil.addDataToThreadLocalMap("ErrorResponse", "Fallback response:: No employee details available temporarily");
}
}
EmployeeServiceImpl.java
#Service
public class EmployeeServiceImpl extends EmployeeService {
#HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
#HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "900"),
#HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10") })
public void getEmployee(int employeeId) {
System.out.println("Getting Employee details for " + employeeId + ", threadLocalUtil : " + threadLocalUtil.getDataFromThreadLocalMap("EMPLOYEE_ID"));
String response = restTemplate.exchange("http://localhost:8011/findEmployeeDetails/{employeeid}",
HttpMethod.GET, null, new ParameterizedTypeReference<String>() {
}, employeeId).getBody();
threadLocalUtil.addDataToThreadLocalMap("Response", response);
}
#Autowired
RestTemplate restTemplate;
}
HystrixHook.java
public class HystrixHook extends HystrixCommandExecutionHook {
private HystrixRequestVariableDefault<ConcurrentHashMap<String, Object>> hrv = new HystrixRequestVariableDefault<>();
#Override
public <T> void onStart(HystrixInvokable<T> commandInstance) {
HystrixRequestContext.initializeContext();
getThreadLocals();
}
#Override
public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {
setThreadLocals();
}
#Override
public <T> void onFallbackStart(HystrixInvokable<T> commandInstance) {
setThreadLocals();
}
#Override
public <T> void onSuccess(HystrixInvokable<T> commandInstance) {
HystrixRequestContext.getContextForCurrentThread().shutdown();
super.onSuccess(commandInstance);
}
#Override
public <T> Exception onError(HystrixInvokable<T> commandInstance, HystrixRuntimeException.FailureType failureType, Exception e) {
HystrixRequestContext.getContextForCurrentThread().shutdown();
return super.onError(commandInstance, failureType, e);
}
private void getThreadLocals() {
hrv.set(ThreadLocalUtil.getThreadLocalData());
}
private void setThreadLocals() {
ThreadLocalUtil.setThreadLocalData(hrv.get());
}
}
AbcApplication.java
public class AbcApplication {
public static void main(String[] args) {
HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixHook());
SpringApplication.run(Abc.class, args);
}
}
Hope this helps

How to inject into an interceptor?

I have configured a security-interceptor which should have the user-session object (which is a singleton) injected here is what I tried:
public DependencyInjection extends AbstractModule{
//Class that has AccessLevel Annoation
bind(InterfaceA.class).to(ImplA.class);
bind(UserPersistor.class).to(UserPersistorImpl.class);
//My session that I wish to inject
bind(UserSession.class).to(UserSessionHandler.class);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
}
Here my UserSessionHandler:
#Singleton
public class UserSessionHandler implements UserSession {
private UserLevel userLevel = UserLevel.DEFAULT;
private final UserPersistor userPersistor;
#Inject
public UserSessionHandler(UserPersistor userPersistor) {
this.userPersistor = userPersistor;
}
#Override
public boolean loginUser(String userName, String password) {
Benutzer user = userPersistor.getUserByName(userName);
if (user == null) {
return false;
} else {
if (user.getKennwort().equals(password)) {
userLevel = UserLevel.valueOf(user.getRolleId().getBezeichnung().toUpperCase());
return true;
} else {
return false;
}
}
}
#Override
public boolean logoutUser() {
userLevel = UserLevel.DEFAULT;
return true;
}
#Override
public UserLevel getUserLevel() {
return userLevel;
}
}
Here how the SecurityInterceptor currently looks like:
#Singleton
public class SecurityInterceptor implements MethodInterceptor {
private final Provider<UserSession> session;
#Inject
public SecurityInterceptor(Provider<UserSession> session){
this.session = session;
}
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
AccessLevel[] acessRoles = invocation.getMethod().getAnnotationsByType(AccessLevel.class);
List<UserLevel> allowedRoles = new ArrayList<>();
for(AccessLevel accessRole: acessRoles){
allowedRoles.add(accessRole.value());
}
//Make sure that User has one of the allowed Access-Levels
if (!allowedRoles.contains(session.get().getUserLevel())) {
throw new InvalidAccessException("No Access allowed with userlevel" + session.get().getUserLevel());
}
return invocation.proceed();
}
}
Now I managed to get it working in my Mockito-Test with a binding to an instance like this:
bind(MockInterface.class).to(MockClass.class);
bind(UserSession.class).toInstance(user);
bind(UserPersistor.class).toInstance(mockUserPersistor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AccessLevel.class),
new SecurityInterceptor(getProvider(UserSession.class)));
However I don't want to create an instance myself but want the once guice is creating. How can I do that, or what am I currently doing wrong?
EDIT: My main issue is that the usersession seems to be different to the one that is generated. Here a simple example:
Injector injector = Guice.createInjector(new DependencyInjection());
UserSession session = injector.createInstance(UserSession.class);
InterfaceA methodCaller = injector.createInstance(InterfaceA.class);
if(session.loginUser("a","b")){
System.out.println(session.getUserLevel().toString()); //Returns Admin
}
methodCaller.callMethodWithAnnotation();
Now when I check the session.getUserLevel in the interceptor I get "Default"
EDIT2: My endgoal is to have the same session instance in my interceptor and anywhere I used UserSession

How to implement GenericDAO class on Hibernate

I want UserDao class to extend GenericDAO where i'll have all CRUD methods. I have read article from IBM: http://www.ibm.com/developerworks/java/library/j-genericdao/index.html , but i could not implement it. Could someone show me example based on my custom UserDao class.
#Transactional(value="myTransactionManager")
public class UserDao {
#Qualifier("mySessionFactory")
public SessionFactoryImpl sessionFactory;
public void setSessionFactory(SessionFactoryImpl sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List<UserEntity> getAll() {
Query query = sessionFactory.getCurrentSession().createQuery(
"from UserEntity ");
List<UserEntity> userList = query.list();
return userList;
}
public void updaet(UserEntity userEntity) {
sessionFactory.getCurrentSession().update(userEntity);
}
public void delete(UserEntity userEntity) {
sessionFactory.getCurrentSession().delete(userEntity);
}
public void save(UserEntity userEntity) {
sessionFactory.getCurrentSession().save(userEntity);
}
}
i tried to write class like this
public class GenericDao{
#Qualifier("mySessionFactory")
public SessionFactoryImpl sessionFactory;
public void setSessionFactory(SessionFactoryImpl sessionFactory) {
this.sessionFactory = sessionFactory;
}
public <T> List<T> getAll(Class<T> t) {
Query query = sessionFactory.getCurrentSession().createQuery(
"from " + t.getName());
List<T> list = query.list();
return list;
}
public <T> void save(T t) {
sessionFactory.getCurrentSession().save(t);
}
public <T> void update(T t) {
sessionFactory.getCurrentSession().update(t);
}
public <T> void delete(T t) {
sessionFactory.getCurrentSession().delete(t);
}
}
but when i try to pull data with UserDao like this:
public List<UserEntity> getAll() {
List<UserEntity> list = UserDao.findAll();
}
Eclipse IDE for line List<UserEntity> list = UserDao.findAll(); give error : The method findAll() is underfined for type UserDao.
this is my implementation :
GenericDao :
#Repository
public class GenericDao<T extends DbObject> {
#Autowired
private SessionFactory sessionFactory;
private Class<T> getParameterizedClass() {
return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public T findById(final Serializable id) {
return (T) getCurrentSession().get(getParameterizedClass(), id.toString());
}
public void persist(final T object) {
getCurrentSession().persist(object);
}
public void saveOrUpdate(final T object) {
getCurrentSession().saveOrUpdate(object);
}
public void delete(final T object) {
getCurrentSession().delete(object);
}
public T merge(final T object) {
return (T) getCurrentSession().merge(object);
}
}
UserDao :
public class UserDao extends GenericDao<User> {
}
Entity :
#Entity
#Table(name = "...")
public class User extends DbObject {
}

Categories

Resources