Spring MVC 3.1.0 integraion with CometD 2.2.0

587 views
Skip to first unread message

Iram

unread,
Feb 2, 2012, 2:48:31 AM2/2/12
to cometd-users
Hi,

I'm new with CometD so please be gentle ... :-)
I read all the documentation at http://cometd.org/documentation regard
configure the Spring integration.
My task is to have:
1. A jsp file which includes some dojox.grid.DataGrid with a
dojox.data.JsonRestStore retrieving data from the server and listens
for notifications from the server and update them into the DataGrid.
2. At the server side I need:
2.1 @Controller which has a method with @RequestMapping suited with
the JsonRestStore target.
2.2 New Service, like the EchoService in documentation, which will be
able to publish notifications to the JsonRestStore.
I need access from the controller for example to the new
Service so I can publish the notification whenever I need( for the POC
I'll just generate a ServerMessage when clicking on some button)

I followed by http://cometdproject.dojotoolkit.org/documentation/cometd-java/server/services/integration-spring
and by http://cometdproject.dojotoolkit.org/documentation/2.x/cometd-java/server/services/integration-spring
but without success.
Actually, just for start testing it I wanted to add the BayeuxServer
as a wired property of the @Controller so I can generate
ServerMessages directly from the Controller:
@Inject
// private BayeuxServer bayeux;

But I'm getting:
09:44:40,294 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].
[localhost].[/prime-network-web].[webmvc]] Servlet.service() for
servlet webmvc threw exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
matching bean of type [org.cometd.bayeux.server.BayeuxServer] found
for dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{@javax.inject.Inject()}
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:
920) [:3.1.0.M2]
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:
789) [:3.1.0.M2]
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:
703) [:3.1.0.M2]
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:
476) [:3.1.0.M2]
at
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:
84) [:3.1.0.M2]
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:
284) [:3.1.0.M2]
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:
1074) [:3.1.0.M2]
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:
517) [:3.1.0.M2]
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:
456) [:3.1.0.M2]
at org.springframework.beans.factory.support.AbstractBeanFactory
$2.getObject(AbstractBeanFactory.java:333) [:3.1.0.M2]
at
org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:
43) [:3.1.0.M2]
at
org.springframework.web.context.request.SessionScope.get(SessionScope.java:
92) [:3.1.0.M2]
...

My web.xml CometD configuration looks like that:
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.server.CometdServlet</servlet-class>
<init-param>
<param-name>timeout</param-name>
<param-value>60000</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>continuation</filter-name>
<filter-
class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>continuation</filter-name>
<url-pattern>/cometd/*</url-pattern>
</filter-mapping>


Why should I declare the BayeuxServer in the application.xml if it
already defined in the CometdServlet?

Thanks a lot,
Iram

Ho.Tri.Bao

unread,
Feb 5, 2012, 8:59:15 PM2/5/12
to cometd...@googlegroups.com
Hi,

From my understanding on cometd

> Why should I declare the BayeuxServer in the application.xml if it
> already defined in the CometdServlet?

Because the BayeusServer in CometdServlet is just a fallback one which
will be created for "generic" purpose if the servlet finds no
"specific" server instance in servlet context. You inject the a
bayeusServer into your spring's controller bean. If you don't declare
BayeusServer as a bean in spring context, there is no way for spring
to inject it. And since by defining a BayeusServer instance in spring
context, you need to tell CometdServlet to use that specfic
BayeusServer instance, that why you need a
ServletContextAttributeExporter as shown in the document.

Have you create a BayeusServer yet in your POC? If not, lets create
one as shown in the document.

For the annotation part, have you create a "Configurer" bean, which
receives a bayeux server and instantiates a ServerAnnotationProcessor.
I think, without ServerAnnotationProcessor, there is no way for cometd
annotation to be understood. I haven't try cometd annotation yet. And
I wonder if the example about the Configurer bean in the document
works as in the 'public BayeuxServer bayeuxServer()" method, it
creates a new BayeusServer server instance instead of reusing the
injected BayeusServer. So lets try as-is with the example in the
document, if doesn't work, try to reuse the injected BayeusServer :)

Hope it helps,
Bao.

> --
> You received this message because you are subscribed to the Google Groups "cometd-users" group.
> To post to this group, send email to cometd...@googlegroups.com
> To unsubscribe from this group, send email to cometd-users...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/cometd-users
>
> Visit the CometD website at http://www.cometd.org

iram lewinger

unread,
Feb 6, 2012, 2:48:46 AM2/6/12
to cometd...@googlegroups.com
Hi Bao,

Thanks a lot for your response!
Actually I managed to start my POC using XML configuration instead of Annotation configuration.
I had some issues in my local environment so I took step back and tried the XML way and it works.
I assume that also the Annotation configuration will work since I found the root cause at my setup(duplicate cometd jars).

No I'm struggling with generating a correct ServerMessage.Mutable in the controller and sending it back to the JsonRestStore in the client.
My current store looks like:
[{"index":"1","value":"first"},{"index":"2","value":"second"}]
The definition of the data store in the client side is:
var dataStore = new dojox.data.JsonRestStore({target: "apps/testNotificationTable/json/", idAttribute: "index"});
The subscription of the data store to notification is:
dojox.cometd.subscribe("/apps/testNotificationTable/json/", function(msg){
dojox.data.restListener({
     channel: msg.data.channel,
     event: msg.data.data.event,
     result: msg.data.data.result
  });
 });
Now I'm trying to modify the store (new,edit,delete) by generating new ServerMessage.Mutable object for example dit notification:
Mutable newMessage = bayeux.newMessage();
newMessage.setChannel("/apps/testNotificationTable/json");
Map innerData = new HashMap();
Map resultData = new HashMap();
resultData.put("index", "1");
resultData.put("value", "one");
innerData.put("event", "PUT");
innerData.put("result", resultData);
newMessage.setData(innerData);
String channel = "/apps/testNotificationTable/json";
ServerChannel serverChannel = bayeux.getChannel(channel);
serverChannel.publish(null, newMessage, null); 

While debugging the client side I see that the new message has been added to the data store but not as expected(you can see in the attached print screen):
instead of the structure of the existing rows (apps/testNotificationTable/json/1 and apps/testNotificationTable/json/2)
there is new row like: /apps/testNotificationTable/json/false

What is the difference between the channel in ServerMessage.Mutable to the channel argument of bayeux.getChannel(channel) ?
Is there any working example of generating server message to data store in the client that was registered to it?

Thanks a lot,
Iram
dataStore structure.jpg

Simone Bordet

unread,
Feb 6, 2012, 3:21:20 AM2/6/12
to cometd...@googlegroups.com
Hi,

On Mon, Feb 6, 2012 at 08:48, iram lewinger <iramle...@gmail.com> wrote:
> No I'm struggling with generating a correct ServerMessage.Mutable in the
> controller and sending it back to the JsonRestStore in the client.
> My current store looks like:
> [{"index":"1","value":"first"},{"index":"2","value":"second"}]
> The definition of the data store in the client side is:
> var dataStore = new dojox.data.JsonRestStore({target:
> "apps/testNotificationTable/json/", idAttribute: "index"});
> The subscription of the data store to notification is:
> dojox.cometd.subscribe("/apps/testNotificationTable/json/", function(msg){
> dojox.data.restListener({
>      channel: msg.data.channel,
>      event: msg.data.data.event,
>      result: msg.data.data.result
>   });
>  });

Bayeux channels should not end with "/". If you need wildcard
subscription, use "/apps/testNotificationTable/json/*".
That's probably the problem. Let us know if that worked.

Simon
--
http://cometd.org
http://intalio.com
http://bordet.blogspot.com
----
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz

iram lewinger

unread,
Feb 6, 2012, 11:13:11 AM2/6/12
to cometd...@googlegroups.com
Hi Simon,

I've managed to receive the notification at client side after removing "/" from the beginning of the channel attribute of the ServerMessage:
Mutable newMessage = bayeux.newMessage();
newMessage.setChannel("apps/testNotificationTable/json/");
Instead of:
newMessage.setChannel("/apps/testNotificationTable/json");

Now I'm facing with a weird issue where after the first time that I'm performing the Server notification, meaning getting the channel from the BayeuxServer, every next bayeux.getChannel(channel) execution ends with NULL value:
String channel = "/apps/testNotificationTable/json";
ServerChannel serverChannel = bayeux.getChannel(channel);

Why is that?

Thanks,
Iram

Simone Bordet

unread,
Feb 6, 2012, 5:34:44 PM2/6/12
to cometd...@googlegroups.com
Hi,

On Mon, Feb 6, 2012 at 17:13, iram lewinger <iramle...@gmail.com> wrote:
> Hi Simon,
>
> I've managed to receive the notification at client side after removing "/"
> from the beginning of the channel attribute of the ServerMessage:
> Mutable newMessage = bayeux.newMessage();
> newMessage.setChannel("apps/testNotificationTable/json/");
> Instead of:
> newMessage.setChannel("/apps/testNotificationTable/json");
>
> Now I'm facing with a weird issue where after the first time that I'm
> performing the Server notification, meaning getting the channel from the
> BayeuxServer, every next bayeux.getChannel(channel) execution ends with NULL
> value:
> String channel = "/apps/testNotificationTable/json";
> ServerChannel serverChannel = bayeux.getChannel(channel);
>
> Why is that?

The server aggressively sweep channels to free memory.
To avoid that, you need to either make the channel persistent or to
add a listener to it.

To make a channel persistent you do:

bayeuxServer.createIfAbsent("/apps/testNotificationTable/json", new
ConfigurableServerChannel.Initializer()
{
public void configureChannel(ConfigurableServerChannel channel)
{
channel.setPersistent(true);
}
}
ServerChannel channel =
bayeuxServer.getChannel("/apps/testNotificationTable/json");

Now you're guaranteed that the channel won't be swept.

See http://docs.cometd.org/apidocs/org/cometd/bayeux/server/BayeuxServer.html#createIfAbsent(java.lang.String,%20org.cometd.bayeux.server.ConfigurableServerChannel.Initializer...)

Tracking this documentation void at http://bugs.cometd.org/browse/COMETD-337

iram lewinger

unread,
Feb 7, 2012, 6:48:27 AM2/7/12
to cometd...@googlegroups.com
Thanks you very much Simon.
I found your information very helpful.
Everything is working now!
Thanks,
Iram

Reply all
Reply to author
Forward
0 new messages