Static attribute in Session Scoped Component Bean - java

I am newbie in Spring MVC and I have session scope component bean
#Component
#Scope(value="session",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class NotificationService {
static int unreadMessageCoutner;
static ArrayList<WebSocketNotificationDTO> unreadMessagesDTO;
#PostConstruct
public void initBean(){
this.unreadMessagesDTO = new ArrayList<WebSocketNotificationDTO>();
}
#PreDestroy
public void destroyBean(){
this.unreadMessagesDTO.clear();
this.unreadMessagesDTO=null;
}
#Override
public void addNotification(WebSocketNotificationDTO notification){
this.unreadMessagesDTO.add(notification);
}
#Override
public void incrementCounter(){
this.unreadMessageCoutner++;
}
#Override
public int getUnreadMessageCoutner(){
return this.unreadMessageCoutner;
}
#Override
public ArrayList<WebSocketNotificationDTO> getUnreadMessages(){
return this.unreadMessagesDTO;
}
#Override
public void setCounter(int counter){
//To do
}
}
I have update the attributes of this bean single time and call these method of this bean by #autowired and now I want to get the updated value of these attribute when I call get method.
Actually now getting NULL value whenever I have autowired this bean in different #controller.
Is this any way to get the single updated value in SPRING ?
Thanks in Advance
Note: Every user session have different value.

Related

Spring custom Scope with timed refresh of beans

I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it.
After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:
public class CyberArkScope implements Scope {
private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
private Integer scopeRefresh;
public CyberArkScope(Integer scopeRefresh) {
this.scopeRefresh = scopeRefresh;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
.isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
}
return scopedObjects.get(name).getValue();
}
#Override
public Object remove(String name) {
destructionCallbacks.remove(name);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
destructionCallbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String name) {
return null;
}
#Override
public String getConversationId() {
return "CyberArk";
}
}
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk")
public String dateString(){
return LocalDateTime.now().toString();
}
}
#RestController
public class HelloWorld {
#Autowired
private String dateString;
#RequestMapping("/")
public String index() {
return dateString;
}
}
When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?
It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
public NonFinalString dateString(){
return new NonFinalString(LocalDateTime.now());
}
}

Assign Spring bean to field not managed by Spring

I have a configuration object that is managed by Spring. Let's call that object 'ConfigurationObject'. The configuration contained by that object I also want to make accessible, through delegation, in objects which I instantiate with the 'new' operator. Let's call these objects 'UserObject'.
Would it then be acceptable to pass the configurationObject as an argument to the constructor of the UserObject and then assign it to a regular private field that is not managed by Spring? So that I can then use the ConfigurationObject to return configuration form the UserObject. See below for the story in code.
#Configuration
public class ConfigurationObject {
private final String configItem;
public ConfigurationObject(#Value("${config.item}") final String configItem){
this.configItem = configItem;
}
public String getConfigItem() {
return configItem;
}
}
public final class UserObject {
private ConfigurationObject configurationObject;
/* other properties */
public UserObject(final ConfigurationObject configurationObject) {
this.configurationObject = configurationObject;
}
public String getConfigItem(){
return configurationObject.getConfigItem();
}
}
Best regards,
Henk
You can get Spring class using context from ApplicationInitializer:
ApplicationInitializer.getAppContext().getBean(ConfigurationObject.class);
Or create class to get Spring context using ApplicationContextAware:
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public static UserService getUserService() {
return (UserService)context.getBean("userService");
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// store ApplicationContext reference to access required beans later on
SpringContext.context = context;
}
}
Yes. It is a very valid use-case. I often do it when I need to create an object which some of its properties are determined during the runtime which do not know upfront.
I would suggest creating a factory method on ConfigurationObject for creating an UserObject:
#Configuration
public class ConfigurationObject {
private final String configItem;
public ConfigurationObject(#Value("${config.item}") final String configItem){
this.configItem = configItem;
}
public String getConfigItem() {
return configItem;
}
public UserObject createUserObject(){
return new UserObject(this);
}
}

Nullpointerexception while setting a bean

I have an action URL after clicking a hyper link like so
/SocialStupendous/GetProfile.action?slno=3&slno=3
In my execute method of ActionClass I have the following code
public String execute() {
int urislno=Integer.parseInt(getServletRequest().getParameter("slno"));
System.out.println(urislno);
bean.setUslno(urislno);
}
I am getting NullPointerException when I am performing bean.setuslno(urislno). Even though urislno is printed properly as 3.
ProfileBean class:
public class ProfileBean {
private int uslno;
public int getUslno() {
return uslno;
}
public void setUslno(int uslno) {
this.uslno = uslno;
}
}
Why is this happening?
The bean is not initialized. You should initialize it somehow in the action
private ProfileBean bean = new ProfileBean();
//and add getter ans setter
the better approach, however is let the container to do it for you. You just need to create a bean configuration in the struts.xml
<bean class="com.yourpackagename.ProfileBean" scope="default"/>
then you would have
private ProfileBean bean;
#Inject
public void setProfileBean(ProfileBean bean) {
this.bean = bean;
}
and you don't need to parse request for parameters, this is already done by the params interceptor which is a part of defaultStack that your action should run. You should create properties in your action to hold parameter values.
private Integer slno;
public Integer getSlno() {
return slno;
}
public void setSlno(Integer uslno) {
this.slno = slno;
}
and the action will look like
public String execute() {
if (slno != null) {
System.out.println(slno)
bean.setUslno(slno);
}
......
return SUCCESS;
}

How to call custom data loader on Spring application start

I'm trying to load some data to my DB on application start. I have a bean defined for this purpose
applicationContext.xml
<bean class="com.project.loader.DataLoader"
id="DataLoader"
depends-on="entityManagerFactory"
scope="singleton"/>
class:
#RooJavaBean
#RooConfigurable
public class DataLoader implements InitializingBean
It is being executed however on first persist() method being call, Spring throws me following error:
Caused by: java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
at com.project.lib.model.extensions.i18n.Locale_Roo_Jpa_ActiveRecord.entityManager_aroundBody0(Locale_Roo_Jpa_ActiveRecord.aj:19)
at com.project.lib.model.extensions.i18n.Locale_Roo_Jpa_ActiveRecord.ajc$interMethod$com_project_lib_model_extensions_i18n_Locale_Roo_Jpa_ActiveRecord$com_project_lib_model_extensions_i18n_Locale$entityManager(Locale_Roo_Jpa_ActiveRecord.aj:1)
at com.project.lib.model.extensions.i18n.Locale.entityManager(Locale.java:1)
Previousely it was working when I defined DataLoader in following way:
#Component
#Configurable
public class DataLoader implements ApplicationListener
but using raw types is not good practice so I would like to switch
How can I make it work?
Spring version: 3.1
I've solved this issue in the past by moving the component-scan definition to the end of the application context, as suggested here
I use the spring SmartLifecycle:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/SmartLifecycle.html
I've created a class that does this nicely, just extend and override the run method:
public abstract class StartupService implements SmartLifecycle {
/** Logger for this class and subclasses */
protected static final Logger logger = LoggerFactory.getLogger(StartupService.class);
protected boolean running=false;
////////////////////// Lifecycle Methods \\\\\\\\\\\\\\\\\\
#Override
public void start() {
try {
logger.info("starting {}", this.getClass().getSimpleName());
run();
} catch (Exception e) {
logger.error("failed to run importer", e);
}
}
#Override
public void stop() {
running=false;
}
#Override
public boolean isRunning() {
return running;
}
////////////////////// SmartLifecycle Methods \\\\\\\\\\\\\\\\\\
#Override
public boolean isAutoStartup() {
return true;
}
#Override
public void stop(Runnable callback) {
stop();
callback.run();
}
#Override
public int getPhase() {
return 0;
}
public abstract void run() throws Exception;
}

Setting and getting session-bound attribute in spring

I have followed a tutorial on dynamic datasource routing tutorial in Spring. For that I have to extend AbstractRoutingDataSource to tell spring which datasource to get, so I do:
public class CustomRouter extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}
Everything goes fine till I find the class responsible for keeping the value of the customerType (it should be the same during the whole session):
public class CustomerContextHolder {
private static final ThreadLocal<Integer> contextHolder = new ThreadLocal<Integer>();
public static void setCustomerType(Integer customerType) {
contextHolder.set(customerType);
}
public static Integer getCustomerType() {
return (Integer) contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
This creates a thread-bound variable customerType, but I have a web application with spring and JSF I don't think with threads but with sessions. So I set it in the login page with thread A (View), but then thread B (Hibernate) request the value to know what datasource to use, it is null indeed, because it has a new value for this thread.
Is there any way to do it Session-bounded instead of Thread-bounded?
Things I have tried so far:
Inject the CustomRouter in the view to set it in the session: Not working, it causes a cycle in dependecies
Replace the ThreadLocal with an Integer: Not working, the value is always set by the last user logged in
Is FacesContext.getCurrentInstance() working? If so then you may try with this:
public class CustomerContextHolder {
private static HttpSession getCurrentSession(){
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance()
.getExternalContext().getRequest();
return request.getSession();
}
public static void setCustomerType(Integer customerType) {
CustomerContextHolder.getCurrentSession().setAttribute("userType", customerType);
}
public static Integer getCustomerType() {
return (Integer) CustomerContextHolder.getCurrentSession().getAttribute("userType");
}
public static void clearCustomerType() {
contextHolder.remove(); // You may want to remove the attribute in session, dunno
}
}

Categories