0

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!

Community
  • 1
  • 1
Pupukea
  • 3
  • 3

2 Answers2

0

has been a while since implementing Java but don't you need some kind of bean declaration as configuration to get a been autowired?

In Example for a cxf tutorial i autowired a Dao to a service the bean itself is defined in the beans.xml.

maybe you can have a look and good luck!

jethroo
  • 2,086
  • 2
  • 18
  • 30
  • Already did that. There's no problem when using the service and dao in spring. But the problem is when autowiring the spring service to atmosphere. (Example above, NotificationChannelController belongs to atmosphere and NotificationService is from Spring) – Pupukea Oct 14 '14 at 05:38
0

did you read https://github.com/Atmosphere/atmosphere/wiki/Configuring-Atmosphere's-Classes-Creation-and-Injection You needs atmosphere-spring extension if you want to make it work. Take a look a the code here

https://github.com/Atmosphere/atmosphere-extensions/tree/master/spring/modules/src/main/java/org/atmosphere/spring

-- Jeanfrancois

jfarcand
  • 1,705
  • 9
  • 6
  • Bingo! Spring service got Autowired but another issue occured. BroadcasterFactory cannot be autowired/inject this time. Error: No qualifying bean of type [org.atmosphere.cpr.BroadcasterFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()} – Pupukea Oct 15 '14 at 08:54