Pass list of topics from application yml to KafkaListener - spring-boot

I have the following application.yml:
service:
kafka:
groupId: 345
consumer:
topics:
-
name: response
producer:
topics:
-
name: request1
num-partitions: 5
replication-factor: 1
-
name: request2
num-partitions: 3
replication-factor: 1
How can I access the list of topic names using spel for passing to KafkaListener annotation?
#KafkaListener(topics = "#{'${service.kafka.consumer.topics.name}'}", containerFactory = "kafkaListenerContainerFactory")
public void receive(String payload, #Header(KafkaHeaders.RECEIVED_TOPIC)String topic) {

Use configuration properties and collection projection...
#ConfigurationProperties("service.kafka.producer")
#Component
public class ConfigProps {
List<Topic> topics = new ArrayList<>();
public List<Topic> getTopics() {
return this.topics;
}
public void setTopics(List<Topic> topics) {
this.topics = topics;
}
#Override
public String toString() {
return "ConfigProps [topics=" + this.topics + "]";
}
public static class Topic {
private String name;
private int numPartitions;
private short replicationFactor;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getNumPartitions() {
return this.numPartitions;
}
public void setNumPartitions(int numPartitions) {
this.numPartitions = numPartitions;
}
public short getReplicationFactor() {
return this.replicationFactor;
}
public void setReplicationFactor(short replicationFactor) {
this.replicationFactor = replicationFactor;
}
#Override
public String toString() {
return "Topic [name=" + this.name + ", numPartitions=" + this.numPartitions + ", replicationFactor="
+ this.replicationFactor + "]";
}
}
}
and
#SpringBootApplication
public class So52741016Application {
public static void main(String[] args) {
SpringApplication.run(So52741016Application.class, args);
}
#KafkaListener(groupId = "${service.kafka.groupId}", topics = "#{configProps.topics.![name]}")
public void listener(String in) {
}
#Bean
public SmartLifecycle createTopics(KafkaAdmin admin, ConfigProps props) {
return new SmartLifecycle() {
#Override
public int getPhase() {
return Integer.MIN_VALUE;
}
#Override
public void stop() {
}
#Override
public void start() {
try (AdminClient client = AdminClient.create(admin.getConfig())) {
CreateTopicsResult createTopics = client.createTopics(props.topics.stream()
.map(t -> new NewTopic(t.getName(), t.getNumPartitions(), t.getReplicationFactor()))
.collect(Collectors.toList()));
createTopics.all().get();
}
catch (Exception e) {
// e.printStackTrace();
}
}
#Override
public boolean isRunning() {
return false;
}
#Override
public void stop(Runnable callback) {
}
#Override
public boolean isAutoStartup() {
return true;
}
};
}
}
and
2018-10-10 11:20:25.813 INFO 14979 --- [ntainer#0-0-C-1] o.s.k.l.KafkaMessageListenerContainer : partitions assigned: [request1-4, request2-0, request1-0, request2-1, request1-1, request2-2, request1-2, request1-3]
Of course, this is only the producer topics, but you can handle them all this way.

Related

Unable to trigger java class from lambda AWS

I just want to trigger a sample java program through lambda.
So I made two classes in com.amazonaws.lambda package of /src/main /java that is LambdaFunctionHandler.java and MessageService.java.
package com.amazonaws.lambda;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
#Component
public class LambdaFunctionHandler implements RequestHandler<Object, String>
{
#Autowired
private MessageService messsageService;
public String handleRequest(Object input, Context context) {
return messsageService.getMessage();
}
}
And 2nd class is
package com.amazonaws.lambda;
public class MessageService {
public String getMessage() {
return "hello world";
}
}
I am uploading jar file on S3 bucket and triggering it from lambda then getting below error :
{
"errorMessage": "java.lang.NullPointerException",
"errorType": "java.lang.NullPointerException",
"stackTrace":
[
"com.amazonaws.lambda.autorfexecution.LambdaFunctionHandler.handleRequest(LambdaFunctionHandler.java:16)",
"sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
"sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
"java.lang.reflect.Method.invoke(Method.java:498)"
]
}
TextContext.java
package com.amazonaws.lambda;
import com.amazonaws.services.lambda.runtime.ClientContext;
import com.amazonaws.services.lambda.runtime.CognitoIdentity;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
public class TestContext implements Context {
private String awsRequestId = "EXAMPLE";
private ClientContext clientContext;
private String functionName = "EXAMPLE";
private CognitoIdentity identity;
private String logGroupName = "EXAMPLE";
private String logStreamName = "EXAMPLE";
private LambdaLogger logger = new TestLogger();
private int memoryLimitInMB = 128;
private int remainingTimeInMillis = 15000;
private String functionVersion = "EXAMPLE";
private String invokedFunctionArn = "EXAMPLE";
#Override
public String getAwsRequestId() {
return awsRequestId;
}
public void setAwsRequestId(String value) {
awsRequestId = value;
}
#Override
public ClientContext getClientContext() {
return clientContext;
}
public void setClientContext(ClientContext value) {
clientContext = value;
}
#Override
public String getFunctionName() {
return functionName;
}
public void setFunctionName(String value) {
functionName = value;
}
#Override
public CognitoIdentity getIdentity() {
return identity;
}
public void setIdentity(CognitoIdentity value) {
identity = value;
}
#Override
public String getLogGroupName() {
return logGroupName;
}
public void setLogGroupName(String value) {
logGroupName = value;
}
#Override
public String getLogStreamName() {
return logStreamName;
}
public void setLogStreamName(String value) {
logStreamName = value;
}
#Override
public LambdaLogger getLogger() {
return logger;
}
public void setLogger(LambdaLogger value) {
logger = value;
}
#Override
public int getMemoryLimitInMB() {
return memoryLimitInMB;
}
public void setMemoryLimitInMB(int value) {
memoryLimitInMB = value;
}
#Override
public int getRemainingTimeInMillis() {
return remainingTimeInMillis;
}
public void setRemainingTimeInMillis(int value) {
remainingTimeInMillis = value;
}
#Override
public String getFunctionVersion() {
return functionVersion;
}
public void setFunctionVersion(String value) {
functionVersion = value;
}
#Override
public String getInvokedFunctionArn() {
return invokedFunctionArn;
}
public void setInvokedFunctionArn(String value) {
invokedFunctionArn = value;
}
/**
* A simple {#code LambdaLogger} that prints everything to stderr.
*/
private static class TestLogger implements LambdaLogger {
#Override
public void log(String message) {
System.err.println(message);
}
}
}
So anyone please guide me what is missing here.

RabbitMQ separate listeners by type

I have POJO which represents a message to Rabbit MQ. There is an integer which is responsible for the type of the message(whether it's update, remove, add and so on):
public class Message {
private String field1;
private String field2;
private Integer type;
...
<some other fields>
}
I have a consumer which accepts such messages in my spring boot app. So in order to handle each type separately, I have to add some switch/case construction in my code.
Are there any more clear solutions for such case?
You can use Spring Integration with a router...
Rabbit Inbound channel adapter -> router ->
Where the router routes to a different service activator (method) based on the type.
EDIT
Here's an example:
#SpringBootApplication
public class So47272336Application {
public static void main(String[] args) {
SpringApplication.run(So47272336Application.class, args);
}
#Bean
public ApplicationRunner runner(RabbitTemplate rabbitTemplate) {
return args -> {
rabbitTemplate.convertAndSend("my.queue", new Domain(1, "foo"));
rabbitTemplate.convertAndSend("my.queue", new Domain(2, "bar"));
rabbitTemplate.convertAndSend("my.queue", new Domain(3, "baz"));
};
}
#Bean
public Queue queue() {
return new Queue("my.queue");
}
#Bean
public IntegrationFlow flow(ConnectionFactory connectionFactory) {
return IntegrationFlows.from(Amqp.inboundAdapter(connectionFactory, "my.queue"))
.route("payload.type", r -> r
.subFlowMapping("1", f -> f.handle("bean", "add"))
.subFlowMapping("2", f -> f.handle("bean", "remove"))
.subFlowMapping("3", f -> f.handle("bean", "update")))
.get();
}
#Bean
public MyBean bean() {
return new MyBean();
}
public static class MyBean {
public void add(Domain object) {
System.out.println("Adding " + object);
}
public void remove(Domain object) {
System.out.println("Removing " + object);
}
public void update(Domain object) {
System.out.println("Updating " + object);
}
}
public static class Domain implements Serializable {
private final Integer type;
private final String info;
public Domain(Integer type, String info) {
this.type = type;
this.info = info;
}
public Integer getType() {
return this.type;
}
public String getInfo() {
return this.info;
}
#Override
public String toString() {
return "Domain [type=" + this.type + ", info=" + this.info + "]";
}
}
}

What is the best way to use #ConfigurationProperties with Builders?

I have searched and can't find any examples that would show me a better way to do this, but in the Spring/Spring Boot code, there are generic builders but the builder itself seems to apply the properties programmatically. Here is some code trying to configure 2 Oracle Connection Pool Data Sources:
import oracle.ucp.jdbc.PoolDataSourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.sql.SQLException;
#Configuration
#EnableConfigurationProperties
#ConditionalOnClass(PoolDataSourceFactory.class)
public class PersistenceAutoConfiguration {
#Bean (name = "readWriteDataSource")
public DataSource getReadWriteDataSource() throws SQLException {
OracleUcpDataSourceProperties rwProperties = getReadWriteProperties();
return OracleUcpDataSourceBuilder.create()
.connectionFactoryClassName(rwProperties.getConnectionFactoryClassName())
.url(rwProperties.getUrl())
.user(rwProperties.getUser())
.password(rwProperties.getPassword())
.initialPoolSize(rwProperties.getInitialPoolSize())
.minPoolSize(rwProperties.getMinPoolSize())
.maxPoolSize(rwProperties.getMaxPoolSize())
.connectionWaitTimeout(rwProperties.getConnectionWaitTimeout())
.inactiveConnectionTimeout(rwProperties.getInactiveConnectionTimeout())
.maxIdleTime(rwProperties.getMaxIdleTime())
.build();
}
#Bean (name = "readOnlyDataSource")
public DataSource getReadOnlyDataSource() throws SQLException {
OracleUcpDataSourceProperties roProperties = getReadOnlyProperties();
return OracleUcpDataSourceBuilder.create()
.connectionFactoryClassName(roProperties.getConnectionFactoryClassName())
.url(roProperties.getUrl())
.user(roProperties.getUser())
.password(roProperties.getPassword())
.initialPoolSize(roProperties.getInitialPoolSize())
.minPoolSize(roProperties.getMinPoolSize())
.maxPoolSize(roProperties.getMaxPoolSize())
.connectionWaitTimeout(roProperties.getConnectionWaitTimeout())
.inactiveConnectionTimeout(roProperties.getInactiveConnectionTimeout())
.maxIdleTime(roProperties.getMaxIdleTime())
.build();
}
#ConfigurationProperties(prefix = "datasource.readwrite")
#Bean(name = "readWriteProperties")
protected OracleUcpDataSourceProperties getReadWriteProperties() {
return new OracleUcpDataSourceProperties();
}
#ConfigurationProperties(prefix = "datasource.readonly")
#Bean(name = "readOnlyProperties")
protected OracleUcpDataSourceProperties getReadOnlyProperties() {
return new OracleUcpDataSourceProperties();
}
}
and
public class OracleUcpDataSourceProperties {
private String connectionFactoryClassName;
private String url;
private String user;
private String password;
private int initialPoolSize;
private int minPoolSize;
private int maxPoolSize;
private int connectionWaitTimeout;
private int inactiveConnectionTimeout;
private int maxIdleTime;
private Boolean validateConnectionOnBorrow;
public String getConnectionFactoryClassName() {
return connectionFactoryClassName;
}
public void setConnectionFactoryClassName(String connectionFactoryClassName) {
this.connectionFactoryClassName = connectionFactoryClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getInitialPoolSize() {
return initialPoolSize;
}
public void setInitialPoolSize(int initialPoolSize) {
this.initialPoolSize = initialPoolSize;
}
public int getMinPoolSize() {
return minPoolSize;
}
public void setMinPoolSize(int minPoolSize) {
this.minPoolSize = minPoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getConnectionWaitTimeout() {
return connectionWaitTimeout;
}
public void setConnectionWaitTimeout(int connectionWaitTimeout) {
this.connectionWaitTimeout = connectionWaitTimeout;
}
public int getInactiveConnectionTimeout() {
return inactiveConnectionTimeout;
}
public void setInactiveConnectionTimeout(int inactiveConnectionTimeout) {
this.inactiveConnectionTimeout = inactiveConnectionTimeout;
}
public int getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(int maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
public Boolean getValidateConnectionOnBorrow() {
return validateConnectionOnBorrow;
}
public void setValidateConnectionOnBorrow(Boolean validateConnectionOnBorrow) {
this.validateConnectionOnBorrow = validateConnectionOnBorrow;
}
}
and
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import java.sql.SQLException;
public class OracleUcpDataSourceBuilder {
private PoolDataSource pds;
/**
* This will grab the pool factory and initialize it.
*/
public OracleUcpDataSourceBuilder() throws SQLException {
pds = PoolDataSourceFactory.getPoolDataSource();
}
public static OracleUcpDataSourceBuilder create() throws SQLException {
return new OracleUcpDataSourceBuilder();
}
public OracleUcpDataSourceBuilder connectionFactoryClassName(String connectionFactoryClassName) throws SQLException {
pds.setConnectionFactoryClassName(connectionFactoryClassName);
return this;
}
public OracleUcpDataSourceBuilder url(String url) throws SQLException {
pds.setURL(url);
return this;
}
public OracleUcpDataSourceBuilder user(String user) throws SQLException {
pds.setUser(user);
return this;
}
public OracleUcpDataSourceBuilder password(String password) throws SQLException {
pds.setPassword(password);
return this;
}
public OracleUcpDataSourceBuilder initialPoolSize(int initialPoolSize) throws SQLException {
pds.setInitialPoolSize(initialPoolSize);
return this;
}
public OracleUcpDataSourceBuilder minPoolSize(int minPoolSize) throws SQLException {
pds.setMinPoolSize(minPoolSize);
return this;
}
public OracleUcpDataSourceBuilder maxPoolSize(int maxPoolSize) throws SQLException {
pds.setMaxPoolSize(maxPoolSize);
return this;
}
public OracleUcpDataSourceBuilder connectionWaitTimeout(int connectionWaitTimeout) throws SQLException {
pds.setConnectionWaitTimeout(connectionWaitTimeout);
return this;
}
public OracleUcpDataSourceBuilder inactiveConnectionTimeout(int inactiveConnectionTime) throws SQLException {
pds.setInactiveConnectionTimeout(inactiveConnectionTime);
return this;
}
public OracleUcpDataSourceBuilder maxIdleTime(int maxIdleTime) throws SQLException {
pds.setMaxIdleTime(maxIdleTime);
return this;
}
public PoolDataSource build() {
return pds;
}
}
Preferably, I would like to be able to apply the properties directly to the builder in one place. is this possible? what changes would I have to make?
Thanks...
Here is your builder, sir
public class OracleUcpDataSourceBuilder {
private Map<String, String> properties = new HashMap<String, String>();
private static final String[] REQ_PROPERTIES = new String[] {"username", "password", "URL"};
public static OracleUcpDataSourceBuilder create() {
return new OracleUcpDataSourceBuilder();
}
public DataSource build() {
for (String prop : REQ_PROPERTIES) {
Assert.notNull(properties.get(prop), "Property is required:" + prop);
}
PoolDataSource result = PoolDataSourceFactory.getPoolDataSource();
bind(result);
return result;
}
private void bind(DataSource result) {
MutablePropertyValues properties = new MutablePropertyValues(this.properties);
new RelaxedDataBinder(result).bind(properties);
}
public OracleUcpDataSourceBuilder URL(String url) {
this.properties.put("URL", url);
return this;
}
public OracleUcpDataSourceBuilder username(String username) {
this.properties.put("username", username);
return this;
}
public OracleUcpDataSourceBuilder password(String password) {
this.properties.put("password", password);
return this;
}
}
Just define a bean like this:
#Bean (name = "readOnlyDataSource")
#ConfigurationProperties(prefix = "datasource.readonly")
public DataSource getReadOnlyDataSource() {
return OracleUcpDataSourceBuilder.create().build();
}
Just make sure that the property names are correct. Spring will take care of the rest.
Note: I use DataSourceBuilder or Spring as a reference.. You can check it's source code also.
Edit: Added some methods to make sure some properties are configured. But this way, you need to set those properties manually to make sure that they're available.

Problems with #Autowired, with a ManagedBean and an abstract class

Well, I have an abstract class like this:
public abstract class BasicCrudMBImpl<Bean, BO> extends BasicMBImpl {
protected Bean bean;
protected List<Bean> beans;
protected BO boPadrao;
public void deletar() {
try {
((BasicBO) boPadrao).delete((AbstractBean) bean);
addInfoMessage("Registro deletado com sucesso");
beans = retornaBeansDoBanco();
bean = null;
} catch (BOException e) {
addErrorMessage(e.getMessage());
}
}
public void salvar(ActionEvent event) {
try {
if (((AbstractBean) bean).getId() == null) {
bean = (Bean) ((BasicBO) boPadrao).save((AbstractBean) bean);
addInfoMessage("Registro salvo com sucesso");
} else {
((BasicBO) boPadrao).update((AbstractBean) bean);
addInfoMessage("Registro atualizado com sucesso");
}
beans = retornaBeansDoBanco();
} catch (BOException e) {
FacesContext.getCurrentInstance().validationFailed();
addErrorMessage(e.getMessage());
}
}
public Bean getBean() {
return bean;
}
public void setBean(Bean bean) {
this.bean = bean;
}
public List<Bean> getBeans() {
try {
if (beans == null)
beans = (List<Bean>) retornaBeansDoBanco();
return beans;
} catch (BOException e) {
addErrorMessage(e.getMessage());
}
return null;
}
public void setBeans(List<Bean> beans) {
this.beans = beans;
}
// Deve ser implementado para carregar a query adequada ao bean necessário
public abstract List<Bean> retornaBeansDoBanco();
public abstract void novo(ActionEvent event);
public abstract void alterar(ActionEvent event);
public BO getBoPadrao() {
return boPadrao;
}
public abstract void setBoPadrao(BO boPadrao);
public void addErrorMessage(String componentId, String errorMessage) {
addMessage(componentId, errorMessage, FacesMessage.SEVERITY_ERROR);
}
public void addErrorMessage(String errorMessage) {
addErrorMessage(null, errorMessage);
}
public void addInfoMessage(String componentId, String infoMessage) {
addMessage(componentId, infoMessage, FacesMessage.SEVERITY_INFO);
}
public void addInfoMessage(String infoMessage) {
addInfoMessage(null, infoMessage);
}
private void addMessage(String componentId, String errorMessage,
FacesMessage.Severity severity) {
FacesMessage message = new FacesMessage(errorMessage);
message.setSeverity(severity);
FacesContext.getCurrentInstance().addMessage(componentId, message);
}
}
In ManagedBean I tried to inject the "boPadrao" with #Autowired, like this:
#ManagedBean(name = "enderecoMB")
#ViewScoped
public class EnderecoMBImpl extends BasicCrudMBImpl<Endereco, BasicBO> {
private static Logger logger = Logger.getLogger(EnderecoMBImpl.class);
private List<TipoEndereco> tiposEndereco;
private List<Logradouro> logradouros;
#PostConstruct
public void init() {
logger.debug("Inicializando componentes no PostConstruct");
beans = retornaBeansDoBanco();
tiposEndereco = (List<TipoEndereco>) boPadrao
.findByNamedQuery(TipoEndereco.FIND_ALL);
logradouros = (List<Logradouro>) boPadrao
.findByNamedQuery(Logradouro.FIND_ALL_COMPLETO);
}
#Override
public List<Endereco> retornaBeansDoBanco() {
return (List<Endereco>) getBoPadrao().findByNamedQuery(Endereco.FIND_ALL_COMPLETO);
}
#Override
public void novo(ActionEvent event) {
bean = new Endereco();
}
#Override
public void alterar(ActionEvent event) {
// TODO Auto-generated method stub
}
public List<TipoEndereco> getTiposEndereco() {
return tiposEndereco;
}
public void setTiposEndereco(List<TipoEndereco> tiposEndereco) {
this.tiposEndereco = tiposEndereco;
}
public List<Logradouro> getLogradouros() {
return logradouros;
}
public void setLogradouros(List<Logradouro> logradouros) {
this.logradouros = logradouros;
}
#Autowired
public void setBoPadrao(BasicBO boPadrao) {
this.boPadrao = boPadrao;
}
}
But this doesn't works, the boPadrao is always null, getting a "NullPointerException". The error occurs in method retornaBeansDoBanco();

window scope in spring?

i was wondering about the spring scope equivalent to window scope ?
according to the documentation here
http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch04s04.html
i couldn't find any, so if there's a custom scope equivalent, can anyone please tell me, thanks.
EDIT: example of window scope in JSF
http://icefaces-showcase.icesoft.org/showcase.jsf?grp=compatMenu&exp=popup
One possible approach is having a session scoped bean that holds all the window sessions, and a window custom scope that access to the corresponding bean through that session scoped bean.
The required classes are:
Window Session
public class WindowSession {
private Map<String, Map<String,Object>> scopeMap = new HashMap<String, Map<String,Object>>();
private Map<String, Boolean> validSessions = new HashMap<String, Boolean>();
public WindowSession() {
super();
}
public Map<String, Map<String, Object>> getScopeMap() {
return scopeMap;
}
public void setScopeMap(Map<String, Map<String, Object>> scopeMap) {
this.scopeMap = scopeMap;
}
public Map<String, Boolean> getValidSessions() {
return validSessions;
}
public void setValidSessions(Map<String, Boolean> validSessions) {
this.validSessions = validSessions;
}
}
WindowIdContext
#Service
#Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class WindowIdContext {
public static final String DEFAULT_SESSION_ID = "";
private String id = DEFAULT_SESSION_ID;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getQueryParamWithSessionId() {
if (DEFAULT_SESSION_ID.equals(id)) {
return "";
}
return "?" + WindowScope.WINDOW_ID_PARAM + "=" + id;
}
}
WindowSessionContext
#Service
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class WindowSessionContext {
private static SecureRandom random = new SecureRandom();
private WindowSession windowSession = new WindowSession();
#Autowired
private WindowIdContext windowIdContext;
public WindowSessionContext() {
windowSession.getValidSessions().put(WindowIdContext.DEFAULT_SESSION_ID, false);
}
public Object getObject(String name, ObjectFactory<?> objectFactory) {
String sessionId = windowIdContext.getId();
synchronized(this) {
if (!windowSession.getValidSessions().containsKey(sessionId)) {
windowSession.getValidSessions().put(sessionId, false);
}
Map<String,Object> sessionMap = windowSession.getScopeMap().get(sessionId);
if (sessionMap == null) {
sessionMap = new HashMap<String,Object>();
windowSession.getScopeMap().put(sessionId, sessionMap);
}
Object object = sessionMap.get(name);
if (object == null) {
object = objectFactory.getObject();
sessionMap.put(name, object);
}
return object;
}
}
public Object removeObject(String name) {
String sessionId = windowIdContext.getId();
synchronized(this) {
Map<String,Object> sessionMap = windowSession.getScopeMap().get(sessionId);
if (sessionMap == null) {
return null;
}
Object object = sessionMap.remove(name);
return object;
}
}
public String addSession() {
synchronized(this) {
String sessionId;
do {
sessionId = new BigInteger(130, random).toString(32);
} while (windowSession.getValidSessions().containsKey(sessionId));
windowSession.getValidSessions().put(sessionId, false);
return sessionId;
}
}
public void removeSession() {
String sessionId = windowIdContext.getId();
synchronized(this) {
windowSession.getScopeMap().remove(sessionId);
windowSession.getValidSessions().remove(sessionId);
}
}
public boolean isSessionValid(String sessionId) {
Boolean inUse = windowSession.getValidSessions().get(sessionId);
return inUse != null;
}
public boolean isSessionInUse(String sessionId) {
Boolean inUse = windowSession.getValidSessions().get(sessionId);
return inUse == true;
}
public synchronized boolean invalidateSession(String sessionId) {
Boolean valid = windowSession.getValidSessions().get(sessionId);
if (valid == null) {
return false;
}
if (sessionId.equals(WindowIdContext.DEFAULT_SESSION_ID)) {
windowSession.getValidSessions().put(sessionId, false);
} else {
windowSession.getValidSessions().remove(sessionId);
}
windowSession.getScopeMap().remove(sessionId);
for (Entry<String,Boolean> validSession : windowSession.getValidSessions().entrySet()) {
if (validSession.getValue() == true) {
return false;
}
}
return true;
}
public synchronized void setSessionInUse(String sessionId) {
windowSession.getValidSessions().put(sessionId, true);
}
public int getCount() {
return windowSession.getValidSessions().size();
}
}
WindowScope
public class WindowScope implements Scope {
private final int scope;
private static final int WINDOW_SCOPE = 40;
public static final String NAME = "window";
public static final String WINDOW_ID_PARAM = "windowid";
private ServletContext servletContext = null;
public WindowScope(ServletContext sc) {
servletContext = sc;
this.scope = WINDOW_SCOPE;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
WindowSessionContext windowSessionContext = applicationContext.getBean(WindowSessionContext.class);
return windowSessionContext.getObject(name, objectFactory);
}
#Override
public Object remove(String name) {
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
WindowSessionContext windowSessionContext = applicationContext.getBean(WindowSessionContext.class);
return windowSessionContext.removeObject(name);
}
#Override
public String getConversationId() {
return RequestContextHolder.currentRequestAttributes().getSessionId();
}
#Override
public void registerDestructionCallback(String arg0, Runnable arg1) {
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
protected int getScope() {
return this.scope;
}
}
WindowScopeFilter
#Component("windowScopeFilter")
public class WindowScopeFilter implements Filter {
#Autowired
private WindowSessionContext windowSessionContext;
#Autowired
private WindowIdContext windowIdContext;
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
String sessionId = httpRequest.getParameter(WindowScope.WINDOW_ID_PARAM);
if (sessionId != null) {
if (windowSessionContext.isSessionValid(sessionId)) {
windowIdContext.setId(sessionId);
} else {
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
} else {
windowSessionContext.setSessionInUse(WindowIdContext.DEFAULT_SESSION_ID);
}
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
WindowScopeListener
#Component
public class WindowScopeListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
WebApplicationContext applicationContext = (WebApplicationContext)event.getApplicationContext();
Scope windowScope = new WindowScope(applicationContext.getServletContext());
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
beanFactory.registerScope("window", windowScope);
}
}
Source with complete source code: http://notwithoutmycode.com/post/window/scope/in/spring

Resources