I need to make push notifications on our webapp. Currently we built the app using Spring Framework MVC in Maven using Spring Tool Suite. All features are done but we need to add this real time notification feature like in facebook using Atmosphere-jersey.
I did a thorough search everywhere in the web before posting this btw. Soooooooo...
MAIN PROBLEM: Spring Framework MVC 4 is separate instance in Atmosphere.(Instance or whatever the term is) So I cant Autowire the service from spring to Atmosphere service. Please give me concepts or ideas on what to do here using this libraries.
There's no problem in the frontend. Just got stucked on this spring and atmosphere thingy.
Tried the answers in this question but didn't work: atmosphere + spring + autowired problems
Approach 1: @Configurable, @Autowired but service is still null.
Searches did: Using @Configurable which needs enabled LTW(Load Time Weaving), but got stucked when whwre -javaagent has a bug or whatever in vFabric TC Server. - http://forum.spring.io/forum/spring-projects/springsource-tool-suite/116703-vmware-vfabric-tc-server-does-not-save-launch-configuration
@ManagedService(path = "/notification/{channel: [a-zA-Z][a-zA-Z_0-9]*}")
@Singleton
@Configurable(dependencyCheck=true,autowire=Autowire.BY_TYPE)
public final class NotificationChannelController {
private final Logger logger = LoggerFactory.getLogger(NotificationChannelController.class);
private final ConcurrentHashMap<String, String> users = new ConcurrentHashMap<String, String>();
private final static String notifChannel = "/notification/";
@Autowired
private NotificationService notificationService;
@PathParam("channel")
private String channel;
@Inject
private BroadcasterFactory factory;
@Inject
private AtmosphereResourceFactory resourceFactory;
@Inject
private MetaBroadcaster metaBroadcaster;
@Ready(encoders = {NotificationProtocolCodec.class})
@DeliverTo(DeliverTo.DELIVER_TO.ALL)
public void onReady(final AtmosphereResource r) {
logger.info("Browser {} connected.", r.uuid());
return;
}
@Disconnect
public void onDisconnect(AtmosphereResourceEvent event) {
users.values().remove(event.getResource().uuid());
if (event.isCancelled()) {
// We didn't get notified, so we remove the user.
logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
} else if (event.isClosedByClient()) {
logger.info("Browser {} closed the connection", event.getResource().uuid());
}
}
@Message(encoders = {NotificationProtocolCodec.class}, decoders = {NotificationProtocolCodec.class})
public NotificationProtocol onMessage(NotificationProtocol message) throws IOException {
if (!users.containsKey(message.getConciergeId())) {
users.put(message.getConciergeId(), message.getUuid());
}
if (message.getMessage().contains("disconnecting")) {
users.remove(message.getConciergeId());
return new NotificationProtocol(message.getConciergeId(), "", "");//" disconnected from room " + channel);
}
logger.info("{} just send {}", message.getConciergeId(), message.getMessage());
return new NotificationProtocol(message);
}
@Message(encoders = {NotificationProtocolCodec.class}, decoders = {NotificationCodec.class})
public void onPrivateNotification(NotificationComment notificationComment) throws IOException {
List<NotificationProtocol> npList = notificationService.saveAndNotifyUsers(notificationComment);
for(NotificationProtocol np : npList){
if (userUUID != null) {
// Retrieve the original AtmosphereResource
AtmosphereResource r = resourceFactory.find(userUUID);
if (r != null) {
factory.lookup(notifChannel + channel).broadcast(np, r);
}
}
}
}
Service to Autowire
@Service
@Transactional
public class NotificationServiceImpl implements NotificationService{
}
web.xml
<!-- Atmosphere -->
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet>
<description>AtmosphereServlet</description>
<servlet-name>AtmosphereServlet</servlet-name>
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
<init-param>
<param-name>org.atmosphere.cpr.broadcasterLifeCyclePolicy</param-name>
<param-value>EMPTY_DESTROY</param-value>
</init-param>
<init-param>
<param-name>org.atmosphere.cpr.broadcaster.shareableThreadPool</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>org.atmosphere.cpr.recoverFromDestroyedBroadcaster</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>org.atmosphere.websocket.messageContentType</param-name>
<param-value>application/json</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/notification/*</url-pattern>
</servlet-mapping>
application-context.xml
<context:component-scan base-package="packagefolder" />
<context:annotation-config />
<context:load-time-weaver aspectj-weaving="on"/>
pom.xml
<!-- Atmosphere -->
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-jersey</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.atmosphere.client</groupId>
<artifactId>javascript</artifactId>
<version>2.2.4</version>
<type>war</type>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<!-- Spring ORM Hibernate -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-acl</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
Just say so if you want more of the pom.xml
Tried this but no good
-javaagent:"pathto/spring-instrument-4.0.6.RELEASE.jar"
Approach 2: For now, trying to get the users connected to NotificationChannelController from a spring controller. But still null even if clients conneted to the managedservice path when accessing from spring controller. I know its not the right way but have to do some tricks to make this work.
Controller:
@Controller
@RequestMapping("secured/*")
public class BaseController {
private static final Logger LOGGER = LoggerFactory
.getLogger(BaseController.class);
@RequestMapping(value = "test", method = RequestMethod.GET)
@ResponseBody
public void testMethod() throws Exception {
System.out.println("AAAAAAAAAAAAAAAAAA");
NotificationChannelController ncc = new NotificationChannelController();
ncc.show();
}
}
NotificationChannelController
@ManagedService(path = "/notification/{channel: [a-zA-Z][a-zA-Z_0-9]*}")
@Singleton
@Configurable(preConstruction=true,dependencyCheck=true,autowire=Autowire.BY_TYPE)
public final class NotificationChannelController {
private final Logger logger = LoggerFactory.getLogger(NotificationChannelController.class);
private final ConcurrentHashMap<String, String> users = new ConcurrentHashMap<String, String>();
public void show(){
System.out.println("A");
for(String key : users.keySet()){
System.out.println(key + " " + users.get(key));
}
System.out.println("B");
for(String s : getRooms(factory.lookupAll())){
System.out.println(s);
}
System.out.println("C");
}
}
Thanks for taking time on reading this and I hope someone can shed light on this. Thanks!