Getting notification when bounded/unbounded to a HTTP session - session

How can i get notified when my Object gets bounded/unbounded to a session object of HTTP.

Let the object's class implement HttpSessionBindingListener.
public class YourObject implements HttpSessionBindingListener {
#Override
public void valueBound(HttpSessionBindingEvent event) {
// The current instance has been bound to the HttpSession.
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
// The current instance has been unbound from the HttpSession.
}
}
If you have no control over the object's class code and thus you can't change its code, then an alternative is to implement HttpSessionAttributeListener.
#WebListener
public class YourObjectSessionAttributeListener implements HttpSessionAttributeListener {
#Override
public void attributeAdded(HttpSessionBindingEvent event) {
if (event.getValue() instanceof YourObject) {
// An instance of YourObject has been bound to the session.
}
}
#Override
public void attributeRemoved(HttpSessionBindingEvent event) {
if (event.getValue() instanceof YourObject) {
// An instance of YourObject has been unbound from the session.
}
}
#Override
public void attributeReplaced(HttpSessionBindingEvent event) {
if (event.getValue() instanceof YourObject) {
// An instance of YourObject has been replaced in the session.
}
}
}
Note: when you're still on Servlet 2.5 or older, replace #WebListener by a <listener> configuration entry in web.xml.

Related

Spring: Publishing event from InitializingBean's afterPropertiesSet method does NOT work

Recently I have found that when I publish an event from org.springframework.beans.factory.InitializingBean.afterPropertiesSet(), then it is unable to publish that event!
However this very same event trigger gets invoked if I invoke it from #Controller or any other class class (the event invocation mechanism remains same for both places).
I have put a print statement after publishing event in InitBean ('Trigger done') and that is successfully printed too.
If you have any idea about this behaviour then please let me know.
Thanks very much
//Sample code for InitializingBean:
#Component
public class InitBean implements InitializingBean {
private final ApplicationEventPublisher publisher;
public InitBean(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
#Override
public void afterPropertiesSet() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
// Sample code for trigger event:
public class TriggerEvent extends ApplicationEvent {
public TriggerEvent() {
super("source");
}
}
// Sample code for listener:
#Component
public class TriggerListener {
#EventListener(TriggerEvent.class)
public void trigger(TriggerEvent triggerEvent) {
System.out.println("Trigger event has come");
}
}
Without testing, I think the problem is that afterPropertiesSet is just too early in the Spring Bean live cycle.
Try firing the event a little later.
Rather in a #PostConstruct, an init-method, or when the application context refresh event was catched.
#PostConstruct:
#Component
public class InitBean {
...
#PostConstruct
public void fire() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
init-method:
#Configuration
public class AppConfig {
#Bean(initMethod="fire")
public InitBean initBean (ApplicationEventPublisher publisher) {
return new InitBean (publisher);
}
}
public class InitBean {
...
#PostConstruct
public void fire() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
context refresh way
#Component
public class InitBean {
...
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
fire();
}
public void fire() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
I don't know if the first two approaches solve the suspected problem, but the last one should work.

JavaFX custom controls created with a Builder and binding expressions

I’m using Spring together with JavaFx. To use spring bean as a custom control I need to use BuilderFactory and a Builder to get a bean from the context. Otherwice I don't have an application context
Parent.java
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ParentControl extends VBox {
#Autowired
ControlFXMLLoader controlFXMLLoader;
#Value("classpath:/parent.fxml")
private Resource fxml;
#PostConstruct
void load() throws IOException {
controlFXMLLoader.load(fxml.getURL(), this);
}
public ParentControl() {
//no application context
}
public LocalDate getDate() {
return LocalDate.now();
}
}
BeanBuilderFactory.java
#Component
public class BeanBuilderFactory implements BuilderFactory {
private Logger logger = LogManager.getLogger(BeanBuilderFactory.class);
#Autowired
private ConfigurableApplicationContext context;
public BeanBuilderFactory() {
}
private JavaFXBuilderFactory defaultBuilderFactory = new JavaFXBuilderFactory();
#Override
public Builder<?> getBuilder(Class<?> type) {
try {
String[] beanNames = context.getBeanNamesForType(type);
if (beanNames.length == 1) {
return new Builder<Object>() {
#Override
public Object build() {
return context.getBean(beanNames[0]);
}
};
} else {
return defaultBuilderFactory.getBuilder(type);
}
} catch (BeansException e) {
return defaultBuilderFactory.getBuilder(type);
}
}
}
And then I user this BuilderFactory to load fxml for a custom control
ControlFXMLLoader.java
#Component
public class ControlFXMLLoader {
private Logger logger = LogManager.getLogger(ControlFXMLLoader.class);
#Autowired
protected ConfigurableApplicationContext context;
#Autowired
protected BeanBuilderFactory beanBuilderFactory;
public Object load(URL fxmlUrl, Parent root, Object controller) throws IOException {
logger.debug("load");
javafx.fxml.FXMLLoader loader = new javafx.fxml.FXMLLoader(fxmlUrl);
loader.setControllerFactory(context::getBean);
loader.setBuilderFactory(beanBuilderFactory);
loader.setRoot(root);
loader.setController(controller);
return loader.load();
}
public Object load(URL fxmlUrl, Parent root) throws IOException {
return load(fxmlUrl, root, root);
}
}
Now I have a child custom control
ChildControl.java
#Component
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ChildControl extends VBox {
public ChildControl() {
}
#Autowired
ControlFXMLLoader controlFXMLLoader;
#Value("classpath:/child.fxml")
private Resource fxml;
#PostConstruct
void load() throws IOException {
controlFXMLLoader.load(fxml.getURL(), this);
}
ObjectProperty<LocalDate> date = new SimpleObjectProperty<LocalDate>();
public LocalDate getDate() {
return date.get();
}
public void setDate(LocalDate date) {
this.date.set(date);
}
public ObjectProperty<LocalDate> dateProperty() {
return date;
}
#FXML
protected void doSomething() {
System.out.println("The button was clicked! " + date.get().toString());
}
}
And want to assign the date to the child from parent fxml
parent.fxml
<fx:root type="com.example.javafx.ParentControl" xmlns:fx="http://javafx.com/fxml">
<ChildControl date="${controller.date}"/>
</fx:root>
child.fxml
<fx:root type="com.example.javafx.ChildControl" xmlns:fx="http://javafx.com/fxml">
<TextField fx:id="textField"/>
<Button text="Click Me" onAction="#doSomething"/>
</fx:root>
The problem is that FXMLLoader doesn’t not allow to use Binding Expression together with a Builder. I got "Cannot bind to builder property." exception.
Below is the part of the code from FXMLLoader.java and the very last if that causes the problem.
Is there some other solution?
FXMLLoader.java
public void processPropertyAttribute(Attribute attribute) throws IOException {
String value = attribute.value;
if (isBindingExpression(value)) {
// Resolve the expression
Expression expression;
if (attribute.sourceType != null) {
throw constructLoadException("Cannot bind to static property.");
}
if (!isTyped()) {
throw constructLoadException("Cannot bind to untyped object.");
}
// TODO We may want to identify binding properties in processAttribute()
// and apply them after build() has been called
if (this.value instanceof Builder) {
throw constructLoadException("Cannot bind to builder property.");
}

JMeter Plugin - How to Listen to TestState

I am working on developing a JMeter plugin. I'm trying to create an AbstractVisualizer that is capable of monitoring the current test state. However, implementing the TestStateListener doesn't seem to be working.
I'm testing this by creating a basic listener that has a login to output arbitrary info to JMeter's logging console. When a sample is sent through the Add function, a line is sent to the console. But nothing is ever triggered on the various TestState functions. Is there something more structural I'm missing?
public class TestListener extends AbstractVisualizer
implements TestStateListener
{
private static final Logger log = LoggingManager.getLoggerForClass();
#Override
public void add(SampleResult arg0) {
log.info("add");
}
#Override
public void clearData() {
// TODO Auto-generated method stub
}
#Override
public String getStaticLabel()
{
return "Test Listener";
}
#Override
public String getLabelResource() {
return null;
}
#Override
public void testEnded() {
log.info("Test Ended");
}
#Override
public void testEnded(String arg0) {
log.info("Test Ended");
}
#Override
public void testStarted() {
log.info("Test started");
}
#Override
public void testStarted(String arg0) {
log.info("Test started");
}
}
I'm not sure how to do it in 1 class. I have 2 classes:
The UI:
public class MonitorGui extends AbstractListenerGui
{
// ...
#Override
public TestElement createTestElement()
{
TestElement element = new Monitor();// <-- this is the backend
modifyTestElement(element);
return element;
}
// ...
}
And then the backend goes like this:
public class Monitor extends AbstractListenerElement
implements SampleListener,
Clearable, Serializable,
TestStateListener, Remoteable,
NoThreadClone
{
private static final String TEST_IS_LOCAL = "*local*";
// ...
#Override
public void testStarted()
{
testStarted(TEST_IS_LOCAL);
}
#Override
public void testEnded()
{
testEnded(TEST_IS_LOCAL);
}
#Override
public void testStarted(String host)
{
// ...
}
// ...
}
You may not need to implement SampleListener like I do, but probably other things are quite similar.
I based that implementation on a built-in pair of ResultSaverGui and ResultCollector which are the components that are saving results into the file(s) for Simple Data Writer, Summary Report and so on.

Accessing HttpSession inside an annotated #WebSocket class on Embedded Jetty 9

How can I access a HttpSession object inside an annotated #WebSocket class in Jetty 9?
I found how to do it using #ServerEndpoint annotation, like here: HttpSession from #ServerEndpoint
Using the #WebSocket annotation, like in the class bellow, how can I do it?
#WebSocket
public class AuctionWebSocket {
// NEED TO ACCESS HttpSession OBJECT INSIDE THESE METHODS:
#OnWebSocketConnect
public void onConnect(Session session) {
System.out.println("onConnect...");
}
#OnWebSocketMessage
public void onMessage(String message) {
System.out.println("Message: " + message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("onClose...");
}
#OnWebSocketError
public void onError(Throwable t) {
System.out.println("onError...");
}
}
Inside the method onConnect(Session session), I tried to call session.getUpgradeRequest().getSession() which always returns null.
For sake of information, here is how I start embedded Jetty 9:
public class Main {
public static void main(String[] args) throws Exception {
String webPort = System.getenv("PORT");
if (webPort == null || webPort.isEmpty()) {
webPort = "8080";
}
Server server = new Server(Integer.parseInt(webPort));
ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
WebAppContext wac = new WebAppContext();
String webappDirLocation = "./src/main/webapp/";
wac.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/classes/.*");
wac.setDescriptor(webappDirLocation + "/WEB-INF/web.xml");
wac.setBaseResource(new ResourceCollection(new String[]{webappDirLocation, "./target"}));
wac.setResourceAlias("/WEB-INF/classes/", "/classes/");
wac.setContextPath("/");
wac.setParentLoaderPriority(true);
/*
* WebSocket handler.
*/
WebSocketHandler wsh = new WebSocketHandler() {
#Override
public void configure(WebSocketServletFactory wssf) {
wssf.register(AuctionWebSocket.class);
}
};
ContextHandler wsc = new ContextHandler();
wsc.setContextPath("/auction-notifications");
wsc.setHandler(wsh);
ContextHandlerCollection chc = new ContextHandlerCollection();
chc.setHandlers(new Handler[]{wac, wsc});
server.setHandler(chc);
server.start();
server.join();
}
}
Let me know if you need more information.
Any help will be appreciated.
Thanks in advance.
You'll want to use the WebSocketCreator concepts.
First you set the WebSocketCreator of your choice in the WebSocketServletFactory that you configure in your WebSocketServlet
public class MySessionSocketServlet extends WebSocketServlet
{
#Override
public void configure(WebSocketServletFactory factory)
{
factory.getPolicy().setIdleTimeout(30000);
factory.setCreator(new MySessionSocketCreator());
}
}
Next, you'll want to grab the HttpSession during the upgrade and pass it into the WebSocket object that you are creating.
public class MySessionSocketCreator implements WebSocketCreator
{
#Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
HttpSession httpSession = req.getSession();
return new MySessionSocket(httpSession);
}
}
Finally, just keep track of that HttpSession in your own WebSocket.
#WebSocket
public class MySessionSocket
{
private HttpSession httpSession;
private Session wsSession;
public MySessionSocket(HttpSession httpSession)
{
this.httpSession = httpSession;
}
#OnWebSocketConnect
public void onOpen(Session wsSession)
{
this.wsSession = wsSession;
}
}
Of note: the HttpSession can expire and be scavenged and cleaned up while a WebSocket is active. Also, the HttpSession contents at this point are not guaranteed to be kept in sync with changes from other web actions (this mostly depends on what Session storage / caching technology you use on the server side)
And one more note: resist the urge to store / track the ServletUpgradeRequest object in your Socket instance, as this object is recycled and cleaned up aggressively by Jetty proper.

how to bundle handlers in the handlerManager?

is there a option to bundle different eventhandler in one javafile?
Like:
public interface MyHandlerr extends EventHandler {
void myEvent1(Event1 event);
void myEvent2(Event2 event);
}
in the moment i have for each event one handler....but i'm not happy with it.
greetz
You can create your own EventHandler interface for handling multiple events
public interface MultipleEventsHandler extends EventHandler {
void onMyEvent(MyEvent event);
void onMyOtherEvent(MyOtherEvent event);
}
Then in your event classes you can define which of the methods should be called
public class MyEvent extends GwtEvent<MultipleEventsHandler> {
public static final Type<MultipleEventsHandler> TYPE = new Type<MultipleEventsHandler>();
#Override
public Type<MultipleEventsHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(MultipleEventsHandler handler) {
handler.onMyEvent(this);
}
}
public class MyOtherEvent extends GwtEvent<MultipleEventsHandler> {
public static final Type<MultipleEventsHandler> TYPE = new Type<MultipleEventsHandler>();
#Override
public Type<MultipleEventsHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(MultipleEventsHandler handler) {
handler.onMyOtherEvent(this);
}
}
If you just want to reduce number of classes/interfaces then you can put EventHandler's inside your event classes, e.g.
public class MyEvent extends GwtEvent<MyEvent.Handler> {
public interface Handler extends EventHandler {
void onMyEvent(SomeEvent event);
}
public static final Type<MyEvent.Handler> TYPE = new Type<MyEvent.Handler>();
#Override
public Type<MyEvent.Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(MyEvent.Handler handler) {
handler.onMyOtherEvent(this);
}
}

Resources