Author: nbelaevski
Date: 2010-11-01 22:44:05 -0400 (Mon, 01 Nov 2010)
New Revision: 19881
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/
trunk/core/api/src/main/java/org/richfaces/application/push/EventAbortedException.java
trunk/core/api/src/main/java/org/richfaces/application/push/MessageDataSerializer.java
trunk/core/api/src/main/java/org/richfaces/application/push/MessageException.java
trunk/core/api/src/main/java/org/richfaces/application/push/PushContext.java
trunk/core/api/src/main/java/org/richfaces/application/push/PushContextFactory.java
trunk/core/api/src/main/java/org/richfaces/application/push/Request.java
trunk/core/api/src/main/java/org/richfaces/application/push/Session.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionFactory.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionManager.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionPreSubscriptionEvent.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionSubscriptionEvent.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicEvent.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicListener.java
trunk/core/api/src/main/java/org/richfaces/application/push/SessionUnsubscriptionEvent.java
trunk/core/api/src/main/java/org/richfaces/application/push/SubscriptionFailureException.java
trunk/core/api/src/main/java/org/richfaces/application/push/Topic.java
trunk/core/api/src/main/java/org/richfaces/application/push/TopicEvent.java
trunk/core/api/src/main/java/org/richfaces/application/push/TopicKey.java
trunk/core/api/src/main/java/org/richfaces/application/push/TopicListener.java
trunk/core/api/src/main/java/org/richfaces/application/push/TopicMode.java
trunk/core/api/src/main/java/org/richfaces/application/push/TopicsContext.java
trunk/core/impl/src/main/java/org/richfaces/application/push/
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractRequest.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractSession.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractTopic.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmosphereHandlerProvider.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmospherePushHandler.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/ConsumingCollection.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/DefaultMessageDataSerializer.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionManagerImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionQueue.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/MessagingContext.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextFactoryImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushHandlerImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/RequestImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/SessionImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicImpl.java
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicsContextImpl.java
trunk/core/impl/src/main/java/org/richfaces/webapp/PushFilter.java
trunk/examples/push-demo/
trunk/examples/push-demo/pom.xml
trunk/examples/push-demo/src/
trunk/examples/push-demo/src/main/
trunk/examples/push-demo/src/main/java/
trunk/examples/push-demo/src/main/java/demo/
trunk/examples/push-demo/src/main/java/demo/Channel.java
trunk/examples/push-demo/src/main/java/demo/ChannelsBean.java
trunk/examples/push-demo/src/main/java/demo/ChatBean.java
trunk/examples/push-demo/src/main/java/demo/HornetQInitializer.java
trunk/examples/push-demo/src/main/java/demo/TopicsInitializer.java
trunk/examples/push-demo/src/main/resources/
trunk/examples/push-demo/src/main/webapp/
trunk/examples/push-demo/src/main/webapp/META-INF/
trunk/examples/push-demo/src/main/webapp/META-INF/MANIFEST.MF
trunk/examples/push-demo/src/main/webapp/WEB-INF/
trunk/examples/push-demo/src/main/webapp/WEB-INF/faces-config.xml
trunk/examples/push-demo/src/main/webapp/WEB-INF/jboss-scanning.xml
trunk/examples/push-demo/src/main/webapp/WEB-INF/lib/
trunk/examples/push-demo/src/main/webapp/WEB-INF/web.xml
trunk/examples/push-demo/src/main/webapp/chat.xhtml
trunk/examples/push-demo/src/main/webapp/index.jsp
trunk/examples/push-demo/src/main/webapp/index.xhtml
trunk/examples/push-demo/src/main/webapp/resources/
trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/PushRendererBase.java
trunk/ui/core/ui/src/main/resources/META-INF/resources/net.java.dev.atmosphere/
trunk/ui/core/ui/src/main/resources/META-INF/resources/net.java.dev.atmosphere/jquery-atmosphere.js
trunk/ui/core/ui/src/main/resources/META-INF/resources/org.richfaces/push.js
trunk/ui/core/ui/src/main/templates/org/ajax4jsf/renderkit/html/push.template.xml
Removed:
trunk/core/api/src/main/java/org/ajax4jsf/event/PushEventListener.java
trunk/core/impl/src/main/java/org/ajax4jsf/webapp/PushEventsCounter.java
trunk/ui/core/ui/src/main/java/org/richfaces/component/PushEventTracker.java
trunk/ui/core/ui/src/main/java/org/richfaces/component/PushListenersManager.java
trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java
trunk/ui/core/ui/src/main/java/org/richfaces/view/facelets/html/AjaxPushHandler.java
trunk/ui/core/ui/src/main/resources/META-INF/push-managed-beans.faces-config.xml
Modified:
trunk/bom/pom.xml
trunk/core/impl/pom.xml
trunk/core/impl/richfaces-suppressions.xml
trunk/core/impl/src/main/java/org/richfaces/application/CoreConfiguration.java
trunk/core/impl/src/main/java/org/richfaces/application/DefaultModule.java
trunk/core/impl/src/main/resources/META-INF/resources/richfaces-base-component.js
trunk/core/impl/src/main/resources/META-INF/resources/richfaces-event.js
trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js
trunk/examples/pom.xml
trunk/ui/common/ui/checkstyle-suppressions.xml
trunk/ui/core/ui/src/main/java/org/richfaces/component/AbstractPush.java
trunk/ui/core/ui/src/main/java/org/richfaces/resource/PushResource.java
Log:
https://jira.jboss.org/browse/RF-9158
Modified: trunk/bom/pom.xml
===================================================================
--- trunk/bom/pom.xml 2010-11-02 01:14:12 UTC (rev 19880)
+++ trunk/bom/pom.xml 2010-11-02 02:44:05 UTC (rev 19881)
@@ -206,6 +206,18 @@
<artifactId>ehcache</artifactId>
<version>1.6.0</version>
</dependency>
+
+ <!-- Push dependencies -->
+ <dependency>
+ <groupId>org.atmosphere</groupId>
+ <artifactId>atmosphere-runtime</artifactId>
+ <version>0.6.3</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.jms</groupId>
+ <artifactId>jms</artifactId>
+ <version>1.1</version>
+ </dependency>
</dependencies>
</dependencyManagement>
Deleted: trunk/core/api/src/main/java/org/ajax4jsf/event/PushEventListener.java
===================================================================
--- trunk/core/api/src/main/java/org/ajax4jsf/event/PushEventListener.java 2010-11-02
01:14:12 UTC (rev 19880)
+++ trunk/core/api/src/main/java/org/ajax4jsf/event/PushEventListener.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,31 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-
-package org.ajax4jsf.event;
-
-import java.util.EventListener;
-import java.util.EventObject;
-
-public interface PushEventListener extends EventListener {
- public void onEvent(EventObject event);
-}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/EventAbortedException.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/application/push/EventAbortedException.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/EventAbortedException.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class EventAbortedException extends Exception {
+
+ private static final long serialVersionUID = -1546282468438542993L;
+
+ public EventAbortedException() {
+ super();
+ }
+
+ public EventAbortedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public EventAbortedException(String message) {
+ super(message);
+ }
+
+ public EventAbortedException(Throwable cause) {
+ super(cause);
+ }
+
+}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/MessageDataSerializer.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/application/push/MessageDataSerializer.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/MessageDataSerializer.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+//TODO - byte message serializer?
+public interface MessageDataSerializer {
+
+ public static final String MESSAGE_ATTRIBUTE_NAME =
MessageDataSerializer.class.getName();
+
+ public String serialize(Object data);
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/MessageException.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/MessageException.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/MessageException.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class MessageException extends Exception {
+
+ private static final long serialVersionUID = -8684363449647232385L;
+
+ public MessageException() {
+ super();
+ }
+
+ public MessageException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public MessageException(String message) {
+ super(message);
+ }
+
+ public MessageException(Throwable cause) {
+ super(cause);
+ }
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/PushContext.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/PushContext.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/PushContext.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,44 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface PushContext {
+
+ public static final String INSTANCE_KEY_NAME = PushContext.class.getName();
+
+ public TopicsContext getTopicsContext();
+
+ public SessionFactory getSessionFactory();
+
+ public SessionManager getSessionManager();
+
+ public void init(FacesContext facesContext);
+
+ public void destroy();
+
+}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/PushContextFactory.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/PushContextFactory.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/PushContextFactory.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,32 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface PushContextFactory {
+
+ public PushContext getPushContext();
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/Request.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/Request.java
(rev 0)
+++ trunk/core/api/src/main/java/org/richfaces/application/push/Request.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import java.io.IOException;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface Request {
+
+ //TODO expose request/session/application maps
+
+ public void flushMessages() throws IOException;
+
+ //TODO suspend with timeout?
+ public void suspend() throws IOException;
+
+ public void resume() throws IOException;
+
+ public Session getSession();
+
+ public boolean isSuspended();
+
+ public boolean isPolling();
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/Session.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/Session.java
(rev 0)
+++ trunk/core/api/src/main/java/org/richfaces/application/push/Session.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,62 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import java.util.Map;
+
+import com.google.common.collect.Multimap;
+
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface Session {
+
+ public int getMaxInactiveInterval();
+
+ public long getLastAccessedTime();
+
+ public String getId();
+
+ public Multimap<TopicKey, TopicKey> getSuccessfulSubscriptions();
+
+ public Map<TopicKey, String> getFailedSubscriptions();
+
+ public void subscribe(String[] topics);
+
+ public void connect(Request request) throws Exception;
+
+ public void disconnect() throws Exception;
+
+ public void onRequestSuspended();
+
+ public void onRequestDisconnected();
+
+ public void onRequestResumed();
+
+ public void destroy();
+
+ public Request getRequest();
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/SessionFactory.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/SessionFactory.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionFactory.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,32 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface SessionFactory {
+
+ public Session createSession(String pushSessionId);
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/SessionManager.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/SessionManager.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionManager.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface SessionManager {
+
+ public void putPushSession(Session pushSession) throws IllegalStateException;
+
+ public Session getPushSession(String id);
+
+ public void removePushSession(Session session);
+
+ public void requeue(Session session);
+
+ public void destroy();
+
+}
\ No newline at end of file
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/SessionPreSubscriptionEvent.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/application/push/SessionPreSubscriptionEvent.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionPreSubscriptionEvent.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class SessionPreSubscriptionEvent extends SessionTopicEvent {
+
+ private static final long serialVersionUID = 2741390800212036457L;
+
+ public SessionPreSubscriptionEvent(Topic topic, TopicKey topicKey, Session session)
{
+ super(topic, topicKey, session);
+ }
+
+ @Override
+ public void invokeListener(TopicListener listener) throws EventAbortedException {
+ ((SessionTopicListener) listener).processPreSubscriptionEvent(this);
+ }
+}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/SessionSubscriptionEvent.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/application/push/SessionSubscriptionEvent.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionSubscriptionEvent.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class SessionSubscriptionEvent extends SessionTopicEvent {
+
+ private static final long serialVersionUID = -463481692840464586L;
+
+ public SessionSubscriptionEvent(Topic topic, TopicKey topicKey, Session session) {
+ super(topic, topicKey, session);
+ }
+
+ @Override
+ public void invokeListener(TopicListener listener) throws EventAbortedException {
+ ((SessionTopicListener) listener).processSubscriptionEvent(this);
+ }
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicEvent.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicEvent.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicEvent.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,54 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class SessionTopicEvent extends TopicEvent {
+
+ private static final long serialVersionUID = 6339351737472180503L;
+
+ private Session session;
+
+ private TopicKey topicKey;
+
+ public SessionTopicEvent(Topic topic, TopicKey topicKey, Session session) {
+ super(topic);
+ this.topicKey = topicKey;
+ this.session = session;
+ }
+
+ public Session getSession() {
+ return session;
+ }
+
+ public TopicKey getTopicKey() {
+ return topicKey;
+ }
+
+ @Override
+ public boolean isAppropriateListener(TopicListener listener) {
+ return (listener instanceof SessionTopicListener);
+ }
+}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicListener.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicListener.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionTopicListener.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,37 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface SessionTopicListener extends TopicListener {
+
+ public void processPreSubscriptionEvent(SessionPreSubscriptionEvent event) throws
EventAbortedException;
+
+ public void processSubscriptionEvent(SessionSubscriptionEvent event) throws
EventAbortedException;
+
+ public void processUnsubscriptionEvent(SessionUnsubscriptionEvent event) throws
EventAbortedException;
+
+}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/SessionUnsubscriptionEvent.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/application/push/SessionUnsubscriptionEvent.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SessionUnsubscriptionEvent.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class SessionUnsubscriptionEvent extends SessionTopicEvent {
+
+ private static final long serialVersionUID = -2286664647234464678L;
+
+ public SessionUnsubscriptionEvent(Topic topic, TopicKey topicKey, Session session) {
+ super(topic, topicKey, session);
+ }
+
+ @Override
+ public void invokeListener(TopicListener listener) throws EventAbortedException {
+ ((SessionTopicListener) listener).processUnsubscriptionEvent(this);
+ }
+}
Added:
trunk/core/api/src/main/java/org/richfaces/application/push/SubscriptionFailureException.java
===================================================================
---
trunk/core/api/src/main/java/org/richfaces/application/push/SubscriptionFailureException.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/SubscriptionFailureException.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class SubscriptionFailureException extends Exception {
+
+ private static final long serialVersionUID = -2070837902276133333L;
+
+ public SubscriptionFailureException() {
+ super();
+ }
+
+ public SubscriptionFailureException(String message) {
+ super(message);
+ }
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/Topic.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/Topic.java
(rev 0)
+++ trunk/core/api/src/main/java/org/richfaces/application/push/Topic.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,46 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface Topic {
+
+ public TopicKey getKey();
+
+ public MessageDataSerializer getMessageDataSerializer();
+
+ public void setMessageDataSerializer(MessageDataSerializer serializer);
+
+ public void addTopicListener(TopicListener topicListener);
+
+ public void removeTopicListener(TopicListener topicListener);
+
+ public void publishEvent(TopicEvent event) throws EventAbortedException;
+
+ public void publish(String subtopic, Object messageData) throws MessageException;
+
+}
\ No newline at end of file
Added: trunk/core/api/src/main/java/org/richfaces/application/push/TopicEvent.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/TopicEvent.java
(rev 0)
+++ trunk/core/api/src/main/java/org/richfaces/application/push/TopicEvent.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import java.util.EventObject;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TopicEvent extends EventObject {
+
+ private static final long serialVersionUID = 1986841627148973279L;
+
+ public TopicEvent(Topic topic) {
+ super(topic);
+ }
+
+ public Topic getTopic() {
+ return (Topic) source;
+ }
+
+ public boolean isAppropriateListener(TopicListener listener) {
+ return false;
+ }
+
+ public void invokeListener(TopicListener listener) throws EventAbortedException {
+ throw new IllegalArgumentException(listener.getClass().getName());
+ }
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/TopicKey.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/TopicKey.java
(rev 0)
+++ trunk/core/api/src/main/java/org/richfaces/application/push/TopicKey.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,169 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import java.io.Serializable;
+import java.util.regex.Pattern;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TopicKey implements Serializable {
+
+ public static final char SUBCHANNEL_SEPARATOR = '@';
+
+ private static final Function<String, TopicKey> FACTORY = new
Function<String, TopicKey>() {
+ public TopicKey apply(String from) {
+ return new TopicKey(from);
+ };
+ };
+
+ private static final Function<TopicKey, String> TO_ADDRESS = new
Function<TopicKey, String>() {
+ public String apply(TopicKey from) {
+ return from.getTopicAddress();
+ };
+ };
+
+ private static final long serialVersionUID = -6967010810728932698L;
+
+ private static final Pattern NAME_PATTERN =
Pattern.compile("[a-zA-Z0-9_]+");
+
+ private static final Joiner AT_JOINER = Joiner.on(SUBCHANNEL_SEPARATOR).skipNulls();
+
+ private final String topicName;
+
+ private final String subtopicName;
+
+ public TopicKey(String topicAddress) {
+ this(getTopicName(topicAddress), getSubtopicName(topicAddress));
+ }
+
+ public TopicKey(String topicName, String subtopicName) {
+ super();
+
+ if (topicName == null) {
+ throw new NullPointerException();
+ }
+
+ this.topicName = topicName;
+ this.subtopicName = subtopicName;
+
+ if (!NAME_PATTERN.matcher(topicName).matches()) {
+ throw new IllegalArgumentException(topicName);
+ }
+
+ if (subtopicName != null &&
!NAME_PATTERN.matcher(subtopicName).matches()) {
+ throw new IllegalArgumentException(subtopicName);
+ }
+ }
+
+ public static Function<String, TopicKey> factory() {
+ return FACTORY;
+ }
+
+ public static Function<TopicKey, String> toAddress() {
+ return TO_ADDRESS;
+ }
+
+ private static String getTopicName(String topicAddress) {
+ int idx = topicAddress.indexOf(SUBCHANNEL_SEPARATOR);
+
+ if (idx < 0) {
+ return topicAddress;
+ }
+
+ return topicAddress.substring(idx + 1);
+ }
+
+ private static String getSubtopicName(String topicAddress) {
+ int idx = topicAddress.indexOf(SUBCHANNEL_SEPARATOR);
+
+ if (idx < 0) {
+ return null;
+ }
+
+ return topicAddress.substring(0, idx);
+ }
+
+ public String getTopicName() {
+ return topicName;
+ }
+
+ public String getSubtopicName() {
+ return subtopicName;
+ }
+
+ public String getTopicAddress() {
+ return AT_JOINER.join(subtopicName, topicName);
+ }
+
+ public TopicKey getRootTopicKey() {
+ if (getSubtopicName() == null) {
+ return this;
+ } else {
+ return new TopicKey(getTopicName(), null);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((subtopicName == null) ? 0 :
subtopicName.hashCode());
+ result = prime * result + ((topicName == null) ? 0 : topicName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ TopicKey other = (TopicKey) obj;
+ if (subtopicName == null) {
+ if (other.subtopicName != null) {
+ return false;
+ }
+ } else if (!subtopicName.equals(other.subtopicName)) {
+ return false;
+ }
+ if (topicName == null) {
+ if (other.topicName != null) {
+ return false;
+ }
+ } else if (!topicName.equals(other.topicName)) {
+ return false;
+ }
+ return true;
+ }
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/TopicListener.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/TopicListener.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/TopicListener.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,32 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import java.util.EventListener;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface TopicListener extends EventListener {
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/TopicMode.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/TopicMode.java
(rev 0)
+++ trunk/core/api/src/main/java/org/richfaces/application/push/TopicMode.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,32 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public enum TopicMode {
+
+ flash, persistent, persistentLast
+
+}
Added: trunk/core/api/src/main/java/org/richfaces/application/push/TopicsContext.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/application/push/TopicsContext.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/application/push/TopicsContext.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,83 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push;
+
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.richfaces.application.ServiceTracker;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+//TODO annotations for declarative topics registration
+public abstract class TopicsContext {
+
+ private ConcurrentMap<String, Topic> topics = new ConcurrentHashMap<String,
Topic>();
+
+ protected abstract Topic createTopic(TopicKey key);
+
+ public Topic getOrCreateTopic(TopicKey key) {
+ Topic result = topics.get(key.getTopicName());
+
+ if (result == null) {
+ Topic newTopic = createTopic(key);
+ result = topics.putIfAbsent(key.getTopicName(), newTopic);
+ if (result == null) {
+ result = newTopic;
+ }
+ }
+
+ return result;
+ }
+
+ public Topic getTopic(TopicKey key) {
+ Topic topic = topics.get(key.getTopicName());
+
+ if (topic == null) {
+ //TODO
+ }
+
+ return topic;
+ }
+
+ public void removeTopic(TopicKey key) {
+ topics.remove(key.getTopicName());
+ }
+
+ public void publish(TopicKey key, Object data) throws MessageException {
+ Topic topic = getTopic(key);
+
+ if (topic == null) {
+ throw new MessageException(MessageFormat.format("Topic {0} not
found", key.getTopicAddress()));
+ }
+
+ topic.publish(key.getSubtopicName(), data);
+ }
+
+ public static TopicsContext lookup() {
+ return
ServiceTracker.getService(PushContextFactory.class).getPushContext().getTopicsContext();
+ }
+
+}
Modified: trunk/core/impl/pom.xml
===================================================================
--- trunk/core/impl/pom.xml 2010-11-02 01:14:12 UTC (rev 19880)
+++ trunk/core/impl/pom.xml 2010-11-02 02:44:05 UTC (rev 19881)
@@ -87,6 +87,18 @@
<optional>true</optional>
</dependency>
+ <!-- Push dependencies -->
+ <dependency>
+ <groupId>org.atmosphere</groupId>
+ <artifactId>atmosphere-runtime</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.jms</groupId>
+ <artifactId>jms</artifactId>
+ <optional>true</optional>
+ </dependency>
+
<!-- Test Dependencies -->
<dependency>
<groupId>org.jboss.test-jsf</groupId>
Modified: trunk/core/impl/richfaces-suppressions.xml
===================================================================
--- trunk/core/impl/richfaces-suppressions.xml 2010-11-02 01:14:12 UTC (rev 19880)
+++ trunk/core/impl/richfaces-suppressions.xml 2010-11-02 02:44:05 UTC (rev 19881)
@@ -16,4 +16,5 @@
<suppress checks="IllegalCatch"
files="ResourceHandlerImpl.java" />
<suppress checks="IllegalThrows"
files="AbstractThreadedTest.java" />
<suppress checks="ModifiedControlVariable"
files="URLCodec.java" />
+ <suppress checks="IllegalCatch" files="AbstractRequest.java"
/>
</suppressions>
Deleted: trunk/core/impl/src/main/java/org/ajax4jsf/webapp/PushEventsCounter.java
===================================================================
--- trunk/core/impl/src/main/java/org/ajax4jsf/webapp/PushEventsCounter.java 2010-11-02
01:14:12 UTC (rev 19880)
+++ trunk/core/impl/src/main/java/org/ajax4jsf/webapp/PushEventsCounter.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,53 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.ajax4jsf.webapp;
-
-import java.io.Serializable;
-import java.util.EventObject;
-
-import org.ajax4jsf.event.PushEventListener;
-
-public class PushEventsCounter implements PushEventListener, Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = 4060284352186710009L;
- private volatile boolean performed = false;
-
- public void onEvent(EventObject event) {
- performed = true;
- }
-
- /**
- * @return the performed
- */
- public boolean isPerformed() {
- return performed;
- }
-
- /**
- */
- public void processed() {
- this.performed = false;
- }
-}
Modified: trunk/core/impl/src/main/java/org/richfaces/application/CoreConfiguration.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/CoreConfiguration.java 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/core/impl/src/main/java/org/richfaces/application/CoreConfiguration.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -70,6 +70,18 @@
staticResourceLocation,
@ConfigurationItem(defaultValue = "true", names =
"org.richfaces.executeAWTInitializer", literal = true)
- executeAWTInitializer
+ executeAWTInitializer,
+
+ @ConfigurationItem(defaultValue = "/ConnectionFactory", names =
"org.richfaces.push.jms.connectionFactory")
+ pushJMSConnectionFactory,
+
+ @ConfigurationItem(defaultValue = "/topic", names =
"org.richfaces.push.jms.topicsNamespace")
+ pushJMSTopicsNamespace,
+
+ @ConfigurationItem(defaultValue = "", names =
"org.richfaces.push.jms.connectionUsername")
+ pushJMSConnectionUsername,
+
+ @ConfigurationItem(defaultValue = "", names =
"org.richfaces.push.jms.connectionPassword")
+ pushJMSConnectionPassword
}
}
Modified: trunk/core/impl/src/main/java/org/richfaces/application/DefaultModule.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/application/DefaultModule.java 2010-11-02
01:14:12 UTC (rev 19880)
+++ trunk/core/impl/src/main/java/org/richfaces/application/DefaultModule.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -2,6 +2,8 @@
import org.richfaces.application.configuration.ConfigurationService;
import org.richfaces.application.configuration.ConfigurationServiceImpl;
+import org.richfaces.application.push.PushContextFactory;
+import org.richfaces.application.push.impl.jms.PushContextFactoryImpl;
import org.richfaces.cache.Cache;
import org.richfaces.l10n.BundleLoader;
import org.richfaces.renderkit.AjaxDataSerializer;
@@ -25,6 +27,7 @@
factory.setInstance(DependencyInjector.class, new
DependencyInjectionServiceImpl());
factory.setInstance(MessageFactory.class, new MessageFactoryImpl(new
BundleLoader()));
factory.setInstance(ResourceLibraryFactory.class, new
ResourceLibraryFactoryImpl());
+ factory.setInstance(PushContextFactory.class,
ServiceLoader.loadService(PushContextFactory.class, PushContextFactoryImpl.class));
}
}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractRequest.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractRequest.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractRequest.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,231 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.ajax4jsf.javascript.JSLiteral;
+import org.ajax4jsf.javascript.ScriptString;
+import org.ajax4jsf.javascript.ScriptUtils;
+import org.atmosphere.cpr.AtmosphereEventLifecycle;
+import org.atmosphere.cpr.AtmosphereResource;
+import org.atmosphere.cpr.AtmosphereResourceEvent;
+import org.atmosphere.cpr.AtmosphereResourceEventListener;
+import org.atmosphere.websocket.WebSocketSupport;
+import org.richfaces.application.push.Request;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.TopicKey;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class AbstractRequest implements Request {
+
+ private static final String TOPIC_KEY = "topic";
+
+ private static final String DATA_KEY = "data";
+
+ private static final int SUSPEND_TIMEOUT = 30 * 1000;
+
+ private static final class Message implements ScriptString {
+
+ private TopicKey topicKey;
+
+ private String serializedData;
+
+ public Message(TopicKey topicKey, String serializedData) {
+ super();
+ this.topicKey = topicKey;
+ this.serializedData = serializedData;
+ }
+
+ public String toScript() {
+ Map<String,Object> map = new HashMap<String, Object>(2);
+
+ map.put(TOPIC_KEY, topicKey.getTopicAddress());
+ map.put(DATA_KEY, new JSLiteral(serializedData));
+
+ return ScriptUtils.toScript(map);
+ }
+
+ public void appendScript(StringBuffer functionString) {
+ functionString.append(toScript());
+ }
+ }
+
+ private static final class FlushMessagesTask implements Runnable {
+
+ private Request request;
+
+ public FlushMessagesTask(Request request) {
+ super();
+ this.request = request;
+ }
+
+ public void run() {
+ try {
+ request.flushMessages();
+ } catch (Throwable e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ private final AtmosphereResourceEventListener resourceEventListener = new
AtmosphereResourceEventListener() {
+
+ public void onSuspend(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event) {
+ AbstractRequest.this.onSuspend();
+ }
+
+ public void onResume(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event) {
+ AbstractRequest.this.onResume();
+ }
+
+ public void onDisconnect(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event) {
+ AbstractRequest.this.onDisconnect();
+ }
+
+ public void onBroadcast(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event) {
+ AbstractRequest.this.onBroadcast();
+ }
+ };
+
+ private final AtmosphereResource<HttpServletRequest, HttpServletResponse>
atmosphereResource;
+
+ private final Session session;
+
+ private final ExecutorService executorService;
+
+ private final Queue<Message> messagesQueue = new
ConcurrentLinkedQueue<Message>();
+
+ private AtomicBoolean submitted = new AtomicBoolean(false);
+
+ public AbstractRequest(AtmosphereResource<HttpServletRequest,
HttpServletResponse> atmosphereResource, Session session,
+ ExecutorService executorService) {
+
+ super();
+
+ this.atmosphereResource = atmosphereResource;
+
+ ((AtmosphereEventLifecycle)
atmosphereResource).addEventListener(resourceEventListener);
+
+ this.session = session;
+ this.executorService = executorService;
+ }
+
+ private void submitToWorker() {
+ if (submitted.compareAndSet(false, true)) {
+ executorService.submit(new FlushMessagesTask(this));
+ }
+ }
+
+ private String serializeMessages() {
+ return ScriptUtils.toScript(new
ConsumingCollection<Message>(messagesQueue));
+ }
+
+ public void flushMessages() throws IOException {
+ String serializedMessages = serializeMessages();
+ PrintWriter writer = atmosphereResource.getResponse().getWriter();
+ writer.write(serializedMessages);
+ writer.flush();
+
+ submitted.compareAndSet(true, false);
+
+ if (isPolling()) {
+ atmosphereResource.resume();
+ } else if (!messagesQueue.isEmpty()) {
+ submitToWorker();
+ }
+ }
+
+ public void postMessage(TopicKey topicKey, String serializedMessage) {
+ messagesQueue.add(new Message(topicKey, serializedMessage));
+ submitToWorker();
+ }
+
+ public void suspend() throws IOException {
+ atmosphereResource.suspend(SUSPEND_TIMEOUT, isPolling());
+ }
+
+ public void resume() throws IOException {
+ atmosphereResource.resume();
+ }
+
+ public boolean isSuspended() {
+ return atmosphereResource.getAtmosphereResourceEvent().isSuspended();
+ }
+
+ public boolean isPolling() {
+ HttpServletRequest req = atmosphereResource.getRequest();
+ boolean isWebsocket = req.getAttribute(WebSocketSupport.WEBSOCKET_SUSPEND) !=
null ||
+ req.getAttribute(WebSocketSupport.WEBSOCKET_RESUME) != null;
+
+ //TODO how to detect non-polling transports?
+ return !isWebsocket;
+ }
+
+ public Session getSession() {
+ return session;
+ }
+
+ protected AtmosphereResource<HttpServletRequest, HttpServletResponse>
getResource() {
+ return atmosphereResource;
+ }
+
+ protected void onSuspend() {
+ }
+
+ protected void onResume() {
+ try {
+ session.disconnect();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ protected void onDisconnect() {
+ try {
+ session.disconnect();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ protected void onBroadcast() {
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractSession.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractSession.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractSession.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,115 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.io.IOException;
+
+import org.richfaces.application.push.Request;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.SessionManager;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class AbstractSession implements Session {
+
+ private static final int MAX_INACTIVE_INTERVAL = 5 * 60 * 1000;
+
+ private final String id;
+
+ private final SessionManager sessionManager;
+
+ private volatile long lastAccessedTime;
+
+ private volatile Request request;
+
+ public AbstractSession(String id, SessionManager sessionManager) {
+ super();
+ this.id = id;
+ this.sessionManager = sessionManager;
+
+ resetLastAccessedTimeToCurrent();
+ }
+
+ private void resetLastAccessedTimeToCurrent() {
+ lastAccessedTime = System.currentTimeMillis();
+ }
+
+ private void requeue() {
+ resetLastAccessedTimeToCurrent();
+ sessionManager.requeue(this);
+ }
+
+ public void connect(Request request) throws Exception {
+ if (this.request != null) {
+ this.request.resume();
+ }
+
+ this.request = request;
+
+ requeue();
+
+ request.suspend();
+ }
+
+ public void disconnect() throws Exception {
+ this.request = null;
+ }
+
+ public long getLastAccessedTime() {
+ if (request != null) {
+ return System.currentTimeMillis();
+ }
+
+ return lastAccessedTime;
+ }
+
+ public int getMaxInactiveInterval() {
+ return MAX_INACTIVE_INTERVAL;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Request getRequest() {
+ return request;
+ }
+
+ public void destroy() {
+ if (request != null) {
+ try {
+ request.resume();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ request = null;
+ //TODO - clean up request
+ }
+
+ sessionManager.removePushSession(this);
+ // TODO Auto-generated method stub
+
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractTopic.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractTopic.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AbstractTopic.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,107 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.richfaces.application.push.EventAbortedException;
+import org.richfaces.application.push.MessageDataSerializer;
+import org.richfaces.application.push.MessageException;
+import org.richfaces.application.push.Topic;
+import org.richfaces.application.push.TopicEvent;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.TopicListener;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class AbstractTopic implements Topic {
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private TopicKey key;
+
+ private volatile MessageDataSerializer serializer;
+
+ private volatile boolean allowSubtopics;
+
+ private List<TopicListener> listeners = new
CopyOnWriteArrayList<TopicListener>();
+
+ public AbstractTopic(TopicKey key) {
+ super();
+ this.key = key;
+ }
+
+ public MessageDataSerializer getMessageDataSerializer() {
+ if (serializer == null) {
+ return DefaultMessageDataSerializer.instance();
+ }
+
+ return serializer;
+ }
+
+ public void setMessageDataSerializer(MessageDataSerializer serializer) {
+ this.serializer = serializer;
+ }
+
+ public boolean isAllowSubtopics() {
+ return allowSubtopics;
+ }
+
+ public void setAllowSubtopics(boolean allowSubtopics) {
+ this.allowSubtopics = allowSubtopics;
+ }
+
+ public TopicKey getKey() {
+ return key;
+ }
+
+ public void addTopicListener(TopicListener topicListener) {
+ listeners.add(topicListener);
+ }
+
+ public void removeTopicListener(TopicListener topicListener) {
+ listeners.remove(topicListener);
+ }
+
+ public void publishEvent(TopicEvent event) throws EventAbortedException {
+ for (TopicListener listener: listeners) {
+ if (event.isAppropriateListener(listener)) {
+ try {
+ event.invokeListener(listener);
+ } catch (EventAbortedException e) {
+ throw e;
+ } catch (Exception e) {
+ LOGGER.error(MessageFormat.format("Exception invoking listener:
{0}", e.getMessage()), e);
+ }
+ }
+ }
+ }
+
+ public abstract void publish(String subtopic, Object messageData) throws
MessageException;
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmosphereHandlerProvider.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmosphereHandlerProvider.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmosphereHandlerProvider.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,37 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.atmosphere.cpr.AtmosphereHandler;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface AtmosphereHandlerProvider {
+
+ public AtmosphereHandler<HttpServletRequest, HttpServletResponse>
getHandler();
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmospherePushHandler.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmospherePushHandler.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/AtmospherePushHandler.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,124 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.atmosphere.cpr.AtmosphereHandler;
+import org.atmosphere.cpr.AtmosphereResource;
+import org.atmosphere.cpr.AtmosphereResourceEvent;
+import org.richfaces.application.push.Request;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.SessionManager;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class AtmospherePushHandler implements
AtmosphereHandler<HttpServletRequest, HttpServletResponse> {
+
+ private static final ThreadFactory DAEMON_THREADS_FACTORY = new ThreadFactory() {
+
+ private final AtomicInteger threadsCounter = new AtomicInteger();
+
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "rf-push-worker-thread-" +
threadsCounter.getAndIncrement());
+ t.setDaemon(true);
+
+ return t;
+ }
+ };
+
+ private static final String PUSH_SESSION_ID_PARAM = "pushSessionId";
+
+ private SessionManager sessionManager;
+
+ private ExecutorService worker;
+
+ public AtmospherePushHandler() {
+ super();
+
+ sessionManager = new SessionManagerImpl(DAEMON_THREADS_FACTORY);
+ worker = Executors.newCachedThreadPool(DAEMON_THREADS_FACTORY);
+ }
+
+ public SessionManager getSessionManager() {
+ return sessionManager;
+ }
+
+ public void onRequest(AtmosphereResource<HttpServletRequest,
HttpServletResponse> resource) throws IOException {
+ // TODO Auto-generated method stub
+
+ HttpServletRequest req = resource.getRequest();
+ HttpServletResponse resp = resource.getResponse();
+
+ String pushSessionId = req.getParameter(PUSH_SESSION_ID_PARAM);
+
+ Session session = null;
+
+ if (pushSessionId != null) {
+ session = getSessionManager().getPushSession(pushSessionId);
+ }
+
+ if (session == null) {
+ //TODO - debug log
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+
+ resp.setContentType("text/plain");
+
+ try {
+ session.connect(createRequest(resource, session));
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public void onStateChange(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event)
+ throws IOException {
+ //do nothing
+ }
+
+ protected abstract Request createRequest(AtmosphereResource<HttpServletRequest,
HttpServletResponse> resource, Session session);
+
+ protected ExecutorService getWorker() {
+ return worker;
+ }
+
+ public void init(ServletConfig servletConfig) throws Exception {
+ }
+
+ public void destroy() throws Exception {
+ sessionManager.destroy();
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/ConsumingCollection.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/ConsumingCollection.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/ConsumingCollection.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.util.AbstractCollection;
+import java.util.Iterator;
+import java.util.Queue;
+
+import com.google.common.collect.AbstractIterator;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class ConsumingCollection<T> extends AbstractCollection<T> {
+
+ private final class ConsumingIterator extends AbstractIterator<T> {
+ @Override
+ protected T computeNext() {
+ T next = queue.poll();
+ if (next == null) {
+ endOfData();
+ }
+ return next;
+ }
+ }
+
+ private Queue<T> queue;
+
+ public ConsumingCollection(Queue<T> queue) {
+ super();
+ this.queue = queue;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new ConsumingIterator();
+ }
+
+ @Override
+ public int size() {
+ return queue.size();
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/DefaultMessageDataSerializer.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/DefaultMessageDataSerializer.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/DefaultMessageDataSerializer.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,44 @@
+package org.richfaces.application.push.impl;
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+import org.ajax4jsf.javascript.ScriptUtils;
+import org.richfaces.application.push.MessageDataSerializer;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public final class DefaultMessageDataSerializer implements MessageDataSerializer {
+
+ private static final MessageDataSerializer INSTANCE = new
DefaultMessageDataSerializer();
+
+ private DefaultMessageDataSerializer() {}
+
+ public static MessageDataSerializer instance() {
+ return INSTANCE;
+ }
+
+ public String serialize(Object data) {
+ return ScriptUtils.toScript(data);
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionManagerImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionManagerImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionManagerImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,105 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ThreadFactory;
+
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.SessionManager;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+import com.google.common.collect.MapMaker;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class SessionManagerImpl implements SessionManager {
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private final class SessionsExpirationRunnable implements Runnable {
+ public void run() {
+ while (true) {
+ try {
+ Session session = sessionQueue.take();
+ sessionMap.remove(session.getId());
+ session.destroy();
+ } catch (InterruptedException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ }
+ }
+
+ private ConcurrentMap<String, Session> sessionMap = new MapMaker().makeMap();
+
+ private SessionQueue sessionQueue = new SessionQueue();
+
+ public SessionManagerImpl(ThreadFactory threadFactory) {
+ threadFactory.newThread(new SessionsExpirationRunnable()).start();
+ }
+
+ public Session getPushSession(String id) {
+ return sessionMap.get(id);
+ }
+
+ public void removePushSession(Session session) {
+ sessionMap.remove(session.getId());
+ if (session != null) {
+ sessionQueue.remove(session);
+ }
+ }
+
+ public void destroy() {
+ //TODO notify all session
+ sessionQueue.clear();
+
+ while (!sessionMap.isEmpty()) {
+ for (Iterator<Session> sessionsItr = sessionMap.values().iterator();
sessionsItr.hasNext(); ) {
+ Session session = sessionsItr.next();
+ sessionsItr.remove();
+
+ session.destroy();
+ }
+ }
+
+ sessionMap.clear();
+ }
+
+ public void putPushSession(Session session) throws IllegalStateException {
+ Session existingSession = sessionMap.putIfAbsent(session.getId(), session);
+ if (existingSession != null) {
+ throw new IllegalStateException();
+ }
+
+ requeue(session);
+ }
+
+ public void requeue(Session session) {
+ sessionQueue.requeue(session);
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionQueue.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionQueue.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/SessionQueue.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,126 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.richfaces.application.push.Session;
+
+/**
+ * Based on DelayQueue by Doug Lea:
http://gee.cs.oswego.edu/
+ * @author Nick Belaevski
+ *
+ */
+//TODO - optimize algorithm
+final class SessionQueue {
+
+ private static final Comparator<? super Session> SESSIONS_COMPARATOR = new
Comparator<Session>() {
+
+ public int compare(Session o1, Session o2) {
+ Long delay1 = Long.valueOf(o1.getLastAccessedTime() +
o1.getMaxInactiveInterval());
+ Long delay2 = Long.valueOf(o2.getLastAccessedTime() +
o2.getMaxInactiveInterval());
+
+ return delay1.compareTo(delay2);
+ }
+
+ };
+
+ private final Queue<Session> queue = new PriorityQueue<Session>(1,
SESSIONS_COMPARATOR);
+
+ private final ReentrantLock lock = new ReentrantLock();
+
+ private final Condition available = lock.newCondition();
+
+ private long getDelay(Session session, TimeUnit unit) {
+ return unit.convert(session.getLastAccessedTime() +
session.getMaxInactiveInterval() - System.currentTimeMillis(),
+ TimeUnit.MILLISECONDS);
+ }
+
+ public Session take() throws InterruptedException {
+ final ReentrantLock lock = this.lock;
+ lock.lockInterruptibly();
+ try {
+ while (true) {
+ Session first = queue.peek();
+ if (first == null) {
+ available.await();
+ } else {
+ long delay = getDelay(first, TimeUnit.NANOSECONDS);
+ if (delay > 0) {
+ available.awaitNanos(delay);
+ } else {
+ Session x = queue.poll();
+ assert x != null;
+ if (queue.size() != 0) {
+ available.signalAll(); // wake up other takers
+ }
+ return x;
+ }
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ }
+
+ public void remove(Session session) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ queue.remove(session);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void requeue(Session session) {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ queue.remove(session);
+
+ Session first = queue.peek();
+ queue.offer(session);
+ if (first == null || SESSIONS_COMPARATOR.compare(session, first) < 0) {
+ available.signalAll();
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void clear() {
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ try {
+ queue.clear();
+ } finally {
+ lock.unlock();
+ }
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/MessagingContext.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/MessagingContext.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/MessagingContext.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,172 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import javax.faces.context.FacesContext;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.servlet.ServletContext;
+
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.TopicKey;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class MessagingContext {
+
+ static final String SUBTOPIC_ATTRIBUTE_NAME = "rf_push_subtopic";
+
+ private static final Joiner OR_JOINER = Joiner.on(" OR ").skipNulls();
+
+ private static final Function<TopicKey, String> TOPIC_KEY_TO_MESSAGE_SELECTOR =
new Function<TopicKey, String>() {
+ public String apply(TopicKey from) {
+ if (Strings.isNullOrEmpty(from.getSubtopicName())) {
+ return null;
+ }
+
+ return SUBTOPIC_ATTRIBUTE_NAME + " = '" +
from.getSubtopicName() + "'";
+ }
+ };
+
+ private static final String SHARED_INSTANCE_KEY = MessagingContext.class.getName();
+
+ private final InitialContext initialContext;
+
+ private final Name connectionFactoryName;
+
+ private final Name topicsNamespace;
+
+ private final String applicationName;
+
+ private final String username;
+
+ private final String password;
+
+ private Connection connection;
+
+ public MessagingContext(InitialContext initialContext, Name connectionFactoryName,
Name topicsNamespace,
+ String applicationName, String username, String password) {
+
+ super();
+ this.initialContext = initialContext;
+ this.connectionFactoryName = connectionFactoryName;
+ this.topicsNamespace = topicsNamespace;
+ this.applicationName = applicationName;
+ this.username = username;
+ this.password = password;
+ }
+
+ private Name appendToName(Name name, String comp) throws NamingException {
+ Name clonedName = (Name) name.clone();
+ return clonedName.add(comp);
+ }
+
+ public void start() throws Exception {
+ ConnectionFactory connectionFactory = (ConnectionFactory)
initialContext.lookup(connectionFactoryName);
+
+ connection = connectionFactory.createConnection(username, password);
+
+ //TODO - review
+ try {
+ //durable subscription requires ClientID to be set
+ connection.setClientID(UUID.randomUUID().toString());
+ } catch (IllegalStateException e) {
+ //ignore - clientId has already been set
+ }
+
+ connection.start();
+ }
+
+ public void stop() throws Exception {
+ connection.stop();
+ connection = null;
+ }
+
+ public Connection getConnection() {
+ if (connection == null) {
+ throw new IllegalStateException("connection is absent");
+ }
+
+ return connection;
+ }
+
+ public Topic lookup(TopicKey topicKey) throws NamingException {
+ Name topicName = appendToName(topicsNamespace, topicKey.getTopicName());
+
+ return (Topic) initialContext.lookup(topicName);
+ }
+
+ public javax.jms.Session createSession() throws JMSException {
+ return connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
+ }
+
+ public String getSubscriptionClientId(Session session, TopicKey topicKey) {
+ //here TopicKey#topicName should be used, not TopicKey#topicAddress
+ return "rf-push:" + applicationName + ":" +
topicKey.getTopicName() + ":" + session.getId();
+ }
+
+ public void shareInstance(FacesContext facesContext) {
+ Map<String, Object> applicationMap =
facesContext.getExternalContext().getApplicationMap();
+ applicationMap.put(SHARED_INSTANCE_KEY, this);
+ }
+
+ public static MessagingContext getSharedInstance(ServletContext servletContext) {
+ return (MessagingContext) servletContext.getAttribute(SHARED_INSTANCE_KEY);
+ }
+
+ private String createMessageSelector(Iterable<TopicKey> topicKeys) {
+ Iterable<String> sqlStrings = Iterables.transform(topicKeys,
TOPIC_KEY_TO_MESSAGE_SELECTOR);
+ return OR_JOINER.join(sqlStrings) + " OR false" /* workaround for
HornetQ */;
+ }
+
+ public TopicSubscriber createTopicSubscriber(Session pushSession, javax.jms.Session
jmsSession,
+ Entry<TopicKey, Collection<TopicKey>> entry)
+ throws JMSException, NamingException {
+
+ TopicKey rootTopicKey = entry.getKey();
+
+ String subscriptionClientId = getSubscriptionClientId(pushSession,
rootTopicKey);
+
+ javax.jms.Topic jmsTopic = lookup(rootTopicKey);
+
+ return jmsSession.createDurableSubscriber(jmsTopic, subscriptionClientId,
createMessageSelector(entry.getValue()), true);
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextFactoryImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextFactoryImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextFactoryImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,57 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import javax.faces.context.FacesContext;
+
+import org.richfaces.application.push.PushContext;
+import org.richfaces.application.push.PushContextFactory;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class PushContextFactoryImpl implements PushContextFactory {
+
+ private static final class PushContextHolder {
+
+ static final PushContext INSTANCE = createInstance();
+
+ private PushContextHolder() {
+ }
+
+ }
+
+ private static PushContext createInstance() {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+
+ PushContextImpl pushContext = new PushContextImpl();
+ pushContext.init(facesContext);
+
+ return pushContext;
+ }
+
+ public PushContext getPushContext() {
+ return PushContextHolder.INSTANCE;
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushContextImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,145 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import static
org.richfaces.application.CoreConfiguration.Items.pushJMSConnectionFactory;
+import static
org.richfaces.application.CoreConfiguration.Items.pushJMSConnectionPassword;
+import static
org.richfaces.application.CoreConfiguration.Items.pushJMSConnectionUsername;
+import static org.richfaces.application.CoreConfiguration.Items.pushJMSTopicsNamespace;
+
+import javax.faces.FacesException;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.PreDestroyApplicationEvent;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+import javax.naming.CompositeName;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.atmosphere.cpr.AtmosphereHandler;
+import org.richfaces.application.ServiceTracker;
+import org.richfaces.application.configuration.ConfigurationService;
+import org.richfaces.application.push.PushContext;
+import org.richfaces.application.push.SessionFactory;
+import org.richfaces.application.push.SessionManager;
+import org.richfaces.application.push.TopicsContext;
+import org.richfaces.application.push.impl.AtmosphereHandlerProvider;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class PushContextImpl implements PushContext, SystemEventListener,
AtmosphereHandlerProvider {
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private MessagingContext messagingContext;
+
+ private TopicsContext topicsContext;
+
+ private PushHandlerImpl pushHandlerImpl;
+
+ public TopicsContext getTopicsContext() {
+ return topicsContext;
+ }
+
+ private String getApplicationName(FacesContext facesContext) {
+ ServletContext servletContext = (ServletContext)
facesContext.getExternalContext().getContext();
+ return servletContext.getContextPath();
+ }
+
+ public void init(FacesContext facesContext) {
+ try {
+
facesContext.getApplication().subscribeToEvent(PreDestroyApplicationEvent.class, this);
+
facesContext.getExternalContext().getApplicationMap().put(PushContext.INSTANCE_KEY_NAME,
this);
+
+ ConfigurationService configurationService =
ServiceTracker.getService(ConfigurationService.class);
+
+ InitialContext initialContext = new InitialContext();
+ Name cnfName = new
CompositeName(configurationService.getStringValue(facesContext,
pushJMSConnectionFactory));
+ Name topicsNamespace = new
CompositeName(configurationService.getStringValue(facesContext, pushJMSTopicsNamespace));
+
+ messagingContext = new MessagingContext(initialContext, cnfName,
topicsNamespace,
+ getApplicationName(facesContext),
+ configurationService.getStringValue(facesContext,
pushJMSConnectionUsername),
+ configurationService.getStringValue(facesContext,
pushJMSConnectionPassword));
+
+ messagingContext.shareInstance(facesContext);
+
+ messagingContext.start();
+
+ topicsContext = new TopicsContextImpl(messagingContext);
+
+ pushHandlerImpl = new PushHandlerImpl(messagingContext, topicsContext);
+ } catch (Exception e) {
+ throw new FacesException(e.getMessage(), e);
+ }
+ }
+
+ public void destroy() {
+ if (messagingContext != null) {
+ try {
+ messagingContext.stop();
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ if (pushHandlerImpl != null) {
+ try {
+ pushHandlerImpl.destroy();
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ public void processEvent(SystemEvent event) throws AbortProcessingException {
+ if (event instanceof PreDestroyApplicationEvent) {
+ destroy();
+ } else {
+ throw new IllegalArgumentException(event.getClass().getName());
+ }
+ }
+
+ public boolean isListenerForSource(Object source) {
+ return true;
+ }
+
+ public SessionFactory getSessionFactory() {
+ return pushHandlerImpl;
+ }
+
+ public AtmosphereHandler<HttpServletRequest, HttpServletResponse> getHandler()
{
+ return pushHandlerImpl;
+ }
+
+ public SessionManager getSessionManager() {
+ return pushHandlerImpl.getSessionManager();
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushHandlerImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushHandlerImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/PushHandlerImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.atmosphere.cpr.AtmosphereResource;
+import org.richfaces.application.push.Request;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.SessionFactory;
+import org.richfaces.application.push.SessionManager;
+import org.richfaces.application.push.TopicsContext;
+import org.richfaces.application.push.impl.AtmospherePushHandler;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class PushHandlerImpl extends AtmospherePushHandler implements SessionFactory {
+
+ private MessagingContext messagingContext;
+
+ private TopicsContext topicsContext;
+
+ public PushHandlerImpl(MessagingContext messagingContext, TopicsContext
topicsContext) {
+ super();
+ this.messagingContext = messagingContext;
+ this.topicsContext = topicsContext;
+ }
+
+ public Session createSession(String key) {
+ SessionManager sessionManager = getSessionManager();
+ Session session = new SessionImpl(key, sessionManager, messagingContext,
topicsContext);
+ sessionManager.putPushSession(session);
+
+ return session;
+ }
+
+ @Override
+ protected Request createRequest(AtmosphereResource<HttpServletRequest,
HttpServletResponse> resource,
+ Session session) {
+ return new RequestImpl(resource, session, getWorker(), messagingContext,
topicsContext);
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/RequestImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/RequestImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/RequestImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,186 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutorService;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.ObjectMessage;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.atmosphere.cpr.AtmosphereResource;
+import org.richfaces.application.push.MessageDataSerializer;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.TopicsContext;
+import org.richfaces.application.push.impl.AbstractRequest;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class RequestImpl extends AbstractRequest implements MessageListener {
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private javax.jms.Session jmsSession;
+
+ private MessagingContext messagingContext;
+
+ private TopicsContext topicsContext;
+
+ public RequestImpl(AtmosphereResource<HttpServletRequest, HttpServletResponse>
atmosphereResource, Session session,
+ ExecutorService executorService, MessagingContext messagingContext, TopicsContext
topicsContext) {
+
+ super(atmosphereResource, session, executorService);
+
+ this.messagingContext = messagingContext;
+ this.topicsContext = topicsContext;
+ }
+
+ private void closeSession() {
+ if (jmsSession != null) {
+ try {
+ jmsSession.close();
+ } catch (JMSException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+
+ jmsSession = null;
+ }
+ }
+
+ @Override
+ public void onSuspend() {
+ super.onSuspend();
+
+ try {
+ jmsSession = messagingContext.createSession();
+
+ //TODO - remove this case
+ SessionImpl sessionImpl = (SessionImpl) getSession();
+
+ for (Entry<TopicKey, Collection<TopicKey>> entry:
sessionImpl.getSuccessfulSubscriptions().asMap().entrySet()) {
+ messagingContext.createTopicSubscriber(sessionImpl, jmsSession,
entry).setMessageListener(this);
+ }
+
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void flushMessages() throws IOException {
+ if (isPolling()) {
+ closeSession();
+ }
+
+ super.flushMessages();
+ }
+
+ @Override
+ public void onDisconnect() {
+ closeSession();
+ super.onDisconnect();
+ }
+
+ @Override
+ public void onResume() {
+ closeSession();
+ super.onResume();
+ }
+
+ private String serializeMessage(org.richfaces.application.push.Topic topic, Message
message) {
+ String serializedMessageData = null;
+ Object messageData = null;
+
+ try {
+ if (message instanceof ObjectMessage) {
+ messageData = ((ObjectMessage) message).getObject();
+ } else if (message instanceof TextMessage) {
+ TextMessage textMessage = (TextMessage) message;
+
+ if (message.getBooleanProperty(TopicImpl.SERIALIZED_DATA_INDICATOR)) {
+ serializedMessageData = textMessage.getText();
+ } else {
+ messageData = textMessage.getText();
+ }
+ }
+ } catch (JMSException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+
+ if (serializedMessageData != null) {
+ return serializedMessageData;
+ }
+
+ if (messageData != null) {
+ MessageDataSerializer messageDataSerializer =
topic.getMessageDataSerializer();
+ try {
+ return messageDataSerializer.serialize(messageData);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jms.MessageListener#onMessage(javax.jms.Message)
+ */
+ public void onMessage(Message message) {
+ try {
+ String topicName = ((Topic) message.getJMSDestination()).getTopicName();
+
+ org.richfaces.application.push.Topic topic = topicsContext.getTopic(new
TopicKey(topicName));
+ if (topic == null) {
+ //TODO log
+ return;
+ }
+
+ String serializedMessageData = serializeMessage(topic, message);
+ if (serializedMessageData == null) {
+ //TODO log
+ return;
+ }
+
+ postMessage(new TopicKey(topicName,
message.getStringProperty(MessagingContext.SUBTOPIC_ATTRIBUTE_NAME)),
serializedMessageData);
+
+ message.acknowledge();
+ } catch (JMSException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/SessionImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/SessionImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/SessionImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,166 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+
+import org.richfaces.application.push.EventAbortedException;
+import org.richfaces.application.push.SessionManager;
+import org.richfaces.application.push.SessionPreSubscriptionEvent;
+import org.richfaces.application.push.Topic;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.TopicsContext;
+import org.richfaces.application.push.impl.AbstractSession;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class SessionImpl extends AbstractSession {
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private final MessagingContext messagingContext;
+
+ private final TopicsContext topicsContext;
+
+ private final Multimap<TopicKey, TopicKey> successfulSubscriptions =
ArrayListMultimap.<TopicKey, TopicKey>create();
+
+ private final Map<TopicKey, String> failedSubscriptions = Maps.newHashMap();
+
+ public SessionImpl(String id, SessionManager sessionManager, MessagingContext
messagingContext, TopicsContext topicsContext) {
+ super(id, sessionManager);
+
+ this.messagingContext = messagingContext;
+ this.topicsContext = topicsContext;
+ }
+
+ public void onRequestSuspended() {
+ // TODO Auto-generated method stub
+ }
+
+ public void onRequestDisconnected() {
+ // TODO Auto-generated method stub
+ // TODO Auto-generated method stub
+ try {
+ disconnect();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public void onRequestResumed() {
+ // TODO Auto-generated method stub
+ try {
+ disconnect();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public Map<TopicKey, String> getFailedSubscriptions() {
+ return failedSubscriptions;
+ }
+
+ public Multimap<TopicKey, TopicKey> getSuccessfulSubscriptions() {
+ return successfulSubscriptions;
+ }
+
+ private void createSubscriptions(Iterable<TopicKey> topicKeys) {
+ javax.jms.Session jmsSession = null;
+ try {
+ Multimap<TopicKey, TopicKey> rootTopicsMap =
createRootTopicsKeysMap(topicKeys);
+
+ jmsSession = messagingContext.createSession();
+
+ for (Entry<TopicKey, Collection<TopicKey>> entry:
rootTopicsMap.asMap().entrySet()) {
+ messagingContext.createTopicSubscriber(this, jmsSession, entry);
+
+ successfulSubscriptions.putAll(entry.getKey(), entry.getValue());
+ }
+ } catch (JMSException e) {
+ LOGGER.error(e.getMessage(), e);
+ } catch (NamingException e) {
+ LOGGER.error(e.getMessage(), e);
+ } finally {
+ if (jmsSession != null) {
+ try {
+ jmsSession.close();
+ } catch (JMSException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ private Multimap<TopicKey, TopicKey>
createRootTopicsKeysMap(Iterable<TopicKey> topicKeys) {
+ Multimap<TopicKey, TopicKey> rootTopicKeys =
ArrayListMultimap.<TopicKey, TopicKey>create();
+
+ for (TopicKey topicKey : topicKeys) {
+ rootTopicKeys.put(topicKey.getRootTopicKey(), topicKey);
+ }
+
+ return rootTopicKeys;
+ }
+
+ private void processFailedSubscriptions(Iterable<TopicKey> topicKeys) {
+ for (Iterator<TopicKey> itr = topicKeys.iterator(); itr.hasNext(); ) {
+ TopicKey topicKey = itr.next();
+
+ TopicKey rootTopicKey = topicKey.getRootTopicKey();
+ Topic pushTopic = topicsContext.getTopic(rootTopicKey);
+
+ try {
+ //TODO - publish another events
+ pushTopic.publishEvent(new SessionPreSubscriptionEvent(pushTopic,
topicKey, this));
+ } catch (EventAbortedException e) {
+ itr.remove();
+ failedSubscriptions.put(topicKey, e.getMessage());
+ }
+ }
+ }
+
+ public void subscribe(String[] topics) {
+ Iterable<TopicKey> topicKeys =
Iterables.transform(Lists.newLinkedList(Arrays.asList(topics)), TopicKey.factory());
+
+ processFailedSubscriptions(topicKeys);
+ createSubscriptions(topicKeys);
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicImpl.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,89 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.NamingException;
+
+import org.richfaces.application.push.MessageException;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.impl.AbstractTopic;
+import org.richfaces.log.Logger;
+import org.richfaces.log.RichfacesLogger;
+
+import com.google.common.base.Strings;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TopicImpl extends AbstractTopic {
+
+ static final String SERIALIZED_DATA_INDICATOR =
"org_richfaces_push_SerializedData";
+
+ private static final Logger LOGGER = RichfacesLogger.APPLICATION.getLogger();
+
+ private MessagingContext messagingContext;
+
+ public TopicImpl(TopicKey key, MessagingContext messagingContext) {
+ super(key);
+
+ this.messagingContext = messagingContext;
+ }
+
+ @Override
+ public void publish(String subtopic, Object messageData) throws MessageException {
+ String serializedData = getMessageDataSerializer().serialize(messageData);
+
+ Session session = null;
+ try {
+ session = messagingContext.createSession();
+ MessageProducer producer =
session.createProducer(messagingContext.lookup(getKey()));
+
+ TextMessage textMessage = session.createTextMessage();
+ textMessage.setText(serializedData);
+ textMessage.setBooleanProperty(SERIALIZED_DATA_INDICATOR, true);
+
+ if (!Strings.isNullOrEmpty(subtopic)) {
+ textMessage.setStringProperty(MessagingContext.SUBTOPIC_ATTRIBUTE_NAME,
subtopic);
+ }
+
+ producer.send(textMessage);
+ } catch (JMSException e) {
+ throw new MessageException(e.getMessage(), e);
+ } catch (NamingException e) {
+ throw new MessageException(e.getMessage(), e);
+ } finally {
+ if (session != null) {
+ try {
+ session.close();
+ } catch (JMSException e) {
+ LOGGER.debug(e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+}
Added:
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicsContextImpl.java
===================================================================
---
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicsContextImpl.java
(rev 0)
+++
trunk/core/impl/src/main/java/org/richfaces/application/push/impl/jms/TopicsContextImpl.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.application.push.impl.jms;
+
+import org.richfaces.application.push.Topic;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.TopicsContext;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TopicsContextImpl extends TopicsContext {
+
+ private MessagingContext messagingContext;
+
+ public TopicsContextImpl(MessagingContext messagingContext) {
+ super();
+ this.messagingContext = messagingContext;
+ }
+
+ protected Topic createTopic(TopicKey key) {
+ return new TopicImpl(key, messagingContext);
+ }
+
+}
Added: trunk/core/impl/src/main/java/org/richfaces/webapp/PushFilter.java
===================================================================
--- trunk/core/impl/src/main/java/org/richfaces/webapp/PushFilter.java
(rev 0)
+++ trunk/core/impl/src/main/java/org/richfaces/webapp/PushFilter.java 2010-11-02 02:44:05
UTC (rev 19881)
@@ -0,0 +1,159 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.webapp;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Set;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.atmosphere.cpr.AtmosphereServlet;
+import org.richfaces.application.push.PushContext;
+import org.richfaces.application.push.impl.AtmosphereHandlerProvider;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Sets;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+//TODO override broadcaster
+public class PushFilter implements Filter {
+
+ private static final String PUSH_HUB_MAPPING = "/*";
+
+ private static final long serialVersionUID = 7616370505508715222L;
+
+ /**
+ * @author Nick Belaevski
+ *
+ */
+ private final class ServletConfigFacade implements ServletConfig {
+ /**
+ *
+ */
+ private final FilterConfig filterConfig;
+
+ /**
+ * @param filterConfig
+ */
+ private ServletConfigFacade(FilterConfig filterConfig) {
+ this.filterConfig = filterConfig;
+ }
+
+ public String getServletName() {
+ return filterConfig.getFilterName();
+ }
+
+ public ServletContext getServletContext() {
+ return filterConfig.getServletContext();
+ }
+
+ public String getInitParameter(String name) {
+ String result = filterConfig.getInitParameter(name);
+
+ if (result == null) {
+ result = filterConfig.getServletContext().getInitParameter(name);
+ }
+
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Enumeration<String> getInitParameterNames() {
+ Set<String> result = Sets.newLinkedHashSet();
+
+ result.addAll(Collections.list(filterConfig.getInitParameterNames()));
+
result.addAll(Collections.list(filterConfig.getServletContext().getInitParameterNames()));
+
+ return Iterators.asEnumeration(result.iterator());
+ }
+ }
+
+ private AtmosphereServlet atmosphereServlet;
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ AtmosphereHandlerProvider handlerProvider = (AtmosphereHandlerProvider)
filterConfig.getServletContext().getAttribute(PushContext.INSTANCE_KEY_NAME);
+
+ if (handlerProvider == null) {
+ return;
+ }
+
+ atmosphereServlet = new AtmosphereServlet() {
+
+ private static final long serialVersionUID = -8719394110408476331L;
+
+ protected boolean detectSupportedFramework(ServletConfig sc) throws
ClassNotFoundException, IllegalAccessException, InstantiationException
,NoSuchMethodException ,java.lang.reflect.InvocationTargetException {
+ return false;
+ };
+ };
+ ServletConfigFacade servletConfig = new ServletConfigFacade(filterConfig);
+ atmosphereServlet.init(servletConfig);
+
+ atmosphereServlet.addAtmosphereHandler(PUSH_HUB_MAPPING,
handlerProvider.getHandler());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
javax.servlet.ServletResponse, javax.servlet.FilterChain)
+ */
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain
chain) throws IOException,
+ ServletException {
+
+ if (atmosphereServlet != null && request instanceof HttpServletRequest
&& response instanceof HttpServletResponse) {
+ HttpServletRequest httpReq = (HttpServletRequest) request;
+ HttpServletResponse httpResp = (HttpServletResponse) response;
+
+ if ("GET".equals(httpReq.getMethod()) &&
httpReq.getQueryString() != null &&
httpReq.getQueryString().contains("__richfacesPushAsync")) {
+ atmosphereServlet.doGet(httpReq, httpResp);
+ return;
+ }
+ }
+
+ // TODO Auto-generated method stub
+ chain.doFilter(request, response);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.Filter#destroy()
+ */
+ public void destroy() {
+ if (atmosphereServlet != null) {
+ atmosphereServlet.removeAtmosphereHandler(PUSH_HUB_MAPPING);
+ atmosphereServlet.destroy();
+ atmosphereServlet = null;
+ }
+ // TODO Auto-generated method stub
+ }
+
+}
Modified:
trunk/core/impl/src/main/resources/META-INF/resources/richfaces-base-component.js
===================================================================
---
trunk/core/impl/src/main/resources/META-INF/resources/richfaces-base-component.js 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/core/impl/src/main/resources/META-INF/resources/richfaces-base-component.js 2010-11-02
02:44:05 UTC (rev 19881)
@@ -228,8 +228,11 @@
source = source || this.id;
var element = richfaces.getDomElement(source);
if (element) {
- element[richfaces.RICH_CONTAINER] = element[richfaces.RICH_CONTAINER] || {};
- element.richfaces.component = this;
+ element[richfaces.RICH_CONTAINER] = $.extend(element[richfaces.RICH_CONTAINER] ||
{},
+ {
+ component:this
+ }
+ );
}
return element;
},
Modified: trunk/core/impl/src/main/resources/META-INF/resources/richfaces-event.js
===================================================================
--- trunk/core/impl/src/main/resources/META-INF/resources/richfaces-event.js 2010-11-02
01:14:12 UTC (rev 19880)
+++ trunk/core/impl/src/main/resources/META-INF/resources/richfaces-event.js 2010-11-02
02:44:05 UTC (rev 19881)
@@ -32,6 +32,9 @@
var getHandlerWrapper = function (component, fn) {
return function (e,d){
+ if (!e[richfaces.RICH_CONTAINER]) {
+ e[richfaces.RICH_CONTAINER] = {data: d};
+ }
return fn.call(component||this, e, this, d);
};
}
@@ -52,6 +55,13 @@
* */
RICH_NAMESPACE : "RICH",
+ /**
+ * @constant
+ * @name RichFaces.Event.EVENT_NAMESPACE_SEPARATOR
+ * @type string
+ * */
+ EVENT_NAMESPACE_SEPARATOR : ".",
+
/**
* Attach an event handler to execute when the DOM is fully loaded.
*
@@ -215,7 +225,7 @@
* */
fire : function(selector, eventType, data) {
var event = $.Event(eventType);
- getEventElement(selector).trigger(eventType, data);
+ getEventElement(selector).trigger(event, data);
return !event.isDefaultPrevented();
},
@@ -287,7 +297,7 @@
if (id) {
a.push(id);
}
- return a.join('.');
+ return a.join(richfaces.Event.EVENT_NAMESPACE_SEPARATOR);
}
});
Modified: trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js
===================================================================
--- trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js 2010-11-02 01:14:12
UTC (rev 19880)
+++ trunk/core/impl/src/main/resources/META-INF/resources/richfaces.js 2010-11-02 02:44:05
UTC (rev 19881)
@@ -13,7 +13,7 @@
(function(jQuery, richfaces) {
- richfaces.RICH_CONTAINER = "richfaces";
+ richfaces.RICH_CONTAINER = "rf";
// get DOM element by id or DOM element or jQuery object
richfaces.getDomElement = function (source) {
Modified: trunk/examples/pom.xml
===================================================================
--- trunk/examples/pom.xml 2010-11-02 01:14:12 UTC (rev 19880)
+++ trunk/examples/pom.xml 2010-11-02 02:44:05 UTC (rev 19881)
@@ -1,4 +1,3 @@
-<<<<<<< .working
<?xml version="1.0" encoding="UTF-8"?>
<!--
JBoss, Home of Professional Open Source Copyright 2010, Red Hat,
@@ -47,8 +46,9 @@
<module>input-demo</module>
<module>repeater-demo</module>
<module>iteration-demo</module>
+ <module>push-demo</module>
<module>richfaces-showcase</module>
- <!--<module>dist</module>-->
+ <module>validator-demo</module>
</modules>
<scm>
@@ -57,66 +57,4 @@
<
url>http://fisheye.jboss.org/browse/richfaces/trunk/examples</url>
</scm>
-</project>
-=======
-<?xml version="1.0" encoding="UTF-8"?>
- <!--
- JBoss, Home of Professional Open Source Copyright 2010, Red Hat,
- Inc. and individual contributors by the @authors tag. See the
- copyright.txt in the distribution for a full listing of
- individual contributors. This is free software; you can
- redistribute it and/or modify it under the terms of the GNU
- Lesser General Public License as published by the Free Software
- Foundation; either version 2.1 of the License, or (at your
- option) any later version. This software is distributed in the
- hope that it will be useful, but WITHOUT ANY WARRANTY; without
- even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- PARTICULAR PURPOSE. See the GNU Lesser General Public License
- for more details. You should have received a copy of the GNU
- Lesser General Public License along with this software; if not,
- write to the Free Software Foundation, Inc., 51 Franklin St,
- Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site:
-
http://www.fsf.org.
- -->
-<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <!--
- This aggregator pom, is not released, and is only used to make
- it easy to build all of the examples at once from trunk.
- -->
-
- <parent>
- <groupId>org.richfaces</groupId>
- <artifactId>richfaces-parent</artifactId>
- <version>10</version>
- <relativePath>../build/parent/pom.xml</relativePath>
- </parent>
-
- <groupId>org.richfaces.examples</groupId>
- <artifactId>examples-aggregator</artifactId>
- <version>4.0.0-SNAPSHOT</version>
- <packaging>pom</packaging>
- <name>RichFaces Examples: Aggregator</name>
-
- <modules>
- <module>parent</module>
- <module>template</module>
- <module>core-demo</module>
- <module>misc-demo</module>
- <module>output-demo</module>
- <module>input-demo</module>
- <module>repeater-demo</module>
- <module>iteration-demo</module>
- <module>richfaces-showcase</module>
- <module>validator-demo</module>
- </modules>
-
- <scm>
-
<
connection>scm:svn:http://anonsvn.jboss.org/repos/richfaces/trunk/exam...
-
<
developerConnection>scm:svn:https://svn.jboss.org/repos/richfaces/trun...
- <
url>http://fisheye.jboss.org/browse/richfaces/trunk/examples</url>
- </scm>
-
-</project>
->>>>>>> .merge-right.r19180
+</project>
\ No newline at end of file
Added: trunk/examples/push-demo/pom.xml
===================================================================
--- trunk/examples/push-demo/pom.xml (rev 0)
+++ trunk/examples/push-demo/pom.xml 2010-11-02 02:44:05 UTC (rev 19881)
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <!--
+ JBoss, Home of Professional Open Source Copyright 2010, Red Hat,
+ Inc. and individual contributors by the @authors tag. See the
+ copyright.txt in the distribution for a full listing of
+ individual contributors. This is free software; you can
+ redistribute it and/or modify it under the terms of the GNU
+ Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1 of the License, or (at your
+ option) any later version. This software is distributed in the
+ hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ for more details. You should have received a copy of the GNU
+ Lesser General Public License along with this software; if not,
+ write to the Free Software Foundation, Inc., 51 Franklin St,
+ Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site:
+
http://www.fsf.org.
+ -->
+<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.richfaces.examples</groupId>
+ <artifactId>richfaces-example-parent</artifactId>
+ <version>4.0.0-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.richfaces.examples</groupId>
+ <artifactId>push-demo</artifactId>
+ <packaging>war</packaging>
+ <version>4.0.0-SNAPSHOT</version>
+ <name>RichFaces Examples: Push</name>
+
+ <properties>
+ <hornetq.version>2.1.2.Final</hornetq.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.hornetq</groupId>
+ <artifactId>hornetq-core</artifactId>
+ <version>${hornetq.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hornetq</groupId>
+ <artifactId>hornetq-jms</artifactId>
+ <version>${hornetq.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hornetq</groupId>
+ <artifactId>hornetq-logging</artifactId>
+ <version>${hornetq.version}</version>
+ </dependency>
+ <!-- dependency>
+ <groupId>org.hornetq</groupId>
+ <artifactId>hornetq-transports</artifactId>
+ <version>2.1.0.r9031</version>
+ </dependency -->
+ <dependency>
+ <groupId>org.jboss.netty</groupId>
+ <artifactId>netty</artifactId>
+ <version>3.2.2.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.jms</groupId>
+ <artifactId>jms</artifactId>
+ <version>1.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.atmosphere</groupId>
+ <artifactId>atmosphere-runtime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.richfaces.core</groupId>
+ <artifactId>richfaces-core-impl</artifactId>
+ </dependency>
+
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet.jsp</groupId>
+ <artifactId>jsp-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>el-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jstl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.richfaces.ui.core</groupId>
+ <artifactId>richfaces-ui-core-ui</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>net.sf.ehcache</groupId>
+ <artifactId>ehcache</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>jee6</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+
<webappDirectory>${project.build.directory}/${project.build.finalName}-jee6</webappDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <!-- TODO these should be switchable in example specific parent
-->
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>jta</artifactId>
+ <version>1.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ <profile>
+ <id>jetty</id>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-websocket</artifactId>
+ <version>8.0.0.M1</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>8.0.0.M1</version>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <scm>
+
<
connection>scm:svn:http://anonsvn.jboss.org/repos/richfaces/trunk/exam...
+
<
developerConnection>scm:svn:https://svn.jboss.org/repos/richfaces/trun...
+ <
url>http://fisheye.jboss.org/browse/richfaces</url>
+ </scm>
+</project>
Added: trunk/examples/push-demo/src/main/java/demo/Channel.java
===================================================================
--- trunk/examples/push-demo/src/main/java/demo/Channel.java (rev
0)
+++ trunk/examples/push-demo/src/main/java/demo/Channel.java 2010-11-02 02:44:05 UTC (rev
19881)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package demo;
+
+import java.io.Serializable;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ValueChangeEvent;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class Channel implements Serializable {
+
+ private static final long serialVersionUID = 6798558262812940593L;
+
+ private String name;
+
+ private boolean rendered = true;
+
+ public Channel(String name) {
+ super();
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isRendered() {
+ return rendered;
+ }
+
+ public void setRendered(boolean rendered) {
+ this.rendered = rendered;
+ }
+
+ public void processChannelStateChange(ValueChangeEvent event) {
+ setRendered(Boolean.TRUE.equals(event.getNewValue()));
+
+ ExternalContext externalContext =
FacesContext.getCurrentInstance().getExternalContext();
+ ChatBean chatBean = (ChatBean)
externalContext.getSessionMap().get("chatBean");
+
+ chatBean.handleStateChange(this);
+ }
+}
Added: trunk/examples/push-demo/src/main/java/demo/ChannelsBean.java
===================================================================
--- trunk/examples/push-demo/src/main/java/demo/ChannelsBean.java
(rev 0)
+++ trunk/examples/push-demo/src/main/java/demo/ChannelsBean.java 2010-11-02 02:44:05 UTC
(rev 19881)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package demo;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.SessionScoped;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+@SessionScoped
+@ManagedBean
+public class ChannelsBean implements Serializable {
+
+ private static final long serialVersionUID = 2916670958555985564L;
+
+ private List<Channel> channels = new ArrayList<Channel>();
+
+ public ChannelsBean() {
+ channels.add(new Channel("upgrade"));
+ channels.add(new Channel("programming"));
+ channels.add(new Channel("hardware"));
+ channels.add(new Channel("os"));
+ }
+
+ public List<Channel> getChannels() {
+ return channels;
+ }
+}
Added: trunk/examples/push-demo/src/main/java/demo/ChatBean.java
===================================================================
--- trunk/examples/push-demo/src/main/java/demo/ChatBean.java (rev
0)
+++ trunk/examples/push-demo/src/main/java/demo/ChatBean.java 2010-11-02 02:44:05 UTC (rev
19881)
@@ -0,0 +1,153 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package demo;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.Date;
+
+import javax.annotation.PostConstruct;
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.ManagedProperty;
+import javax.faces.bean.SessionScoped;
+
+import org.richfaces.application.push.MessageException;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.TopicsContext;
+import org.richfaces.log.LogFactory;
+import org.richfaces.log.Logger;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+@ManagedBean
+@SessionScoped
+public class ChatBean implements Serializable {
+
+ private static final long serialVersionUID = -6377543444437645751L;
+
+ private static final Logger LOGGER = LogFactory.getLogger(ChatBean.class);
+
+ private String userName;
+
+ private String message;
+
+ private boolean chatJoined;
+
+ private transient TopicsContext topicsContext;
+
+ private String subchannel;
+
+ @ManagedProperty("#{channelsBean}")
+ private ChannelsBean channelsBean;
+
+ @PostConstruct
+ public void init() {
+ topicsContext = TopicsContext.lookup();
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ private void publishStateChangeMessage(String name, String action) {
+ try {
+ topicsContext.publish(new TopicKey("chat", name),
MessageFormat.format("*** {0} {1} chat in {2,time,medium}",
+ userName, action, new Date()));
+ } catch (MessageException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ public void joinChat() {
+ if (!chatJoined) {
+ if (userName == null) {
+ throw new NullPointerException("username");
+ }
+
+ chatJoined = true;
+
+ for (Channel subchannel : channelsBean.getChannels()) {
+ publishStateChangeMessage(subchannel.getName(), "joined");
+ }
+ }
+ }
+
+ public void handleStateChange(Channel channel) {
+ String action;
+ if (channel.isRendered()) {
+ action = "joined";
+ } else {
+ action = "left";
+ }
+
+ publishStateChangeMessage(channel.getName(), action);
+ }
+
+ public void say() {
+ try {
+ topicsContext.publish(new TopicKey("chat", subchannel),
MessageFormat.format("{0,time,medium} {1}: {2}", new Date(),
+ userName, message));
+ } catch (MessageException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+ public void setTopicsContext(TopicsContext topicsContext) {
+ this.topicsContext = topicsContext;
+ }
+
+ /**
+ * @return the subchannel
+ */
+ public String getSubchannel() {
+ return subchannel;
+ }
+
+ /**
+ * @param subchannel the subchannel to set
+ */
+ public void setSubchannel(String subchannel) {
+ this.subchannel = subchannel;
+ }
+
+ /**
+ * @param channelsBean the channelsBean to set
+ */
+ public void setChannelsBean(ChannelsBean channelsBean) {
+ this.channelsBean = channelsBean;
+ }
+
+}
Added: trunk/examples/push-demo/src/main/java/demo/HornetQInitializer.java
===================================================================
--- trunk/examples/push-demo/src/main/java/demo/HornetQInitializer.java
(rev 0)
+++ trunk/examples/push-demo/src/main/java/demo/HornetQInitializer.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,118 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package demo;
+
+import java.util.HashSet;
+
+import javax.faces.application.Application;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.PostConstructApplicationEvent;
+import javax.faces.event.PreDestroyApplicationEvent;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+import javax.naming.InitialContext;
+
+import org.hornetq.api.core.TransportConfiguration;
+import org.hornetq.core.config.Configuration;
+import org.hornetq.core.config.impl.ConfigurationImpl;
+import org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory;
+import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
+import org.hornetq.core.server.HornetQServer;
+import org.hornetq.core.server.HornetQServers;
+import org.hornetq.jms.server.JMSServerManager;
+import org.hornetq.jms.server.impl.JMSServerManagerImpl;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class HornetQInitializer implements SystemEventListener {
+
+ private JMSServerManager serverManager;
+
+ public void processEvent(SystemEvent event) throws AbortProcessingException {
+ if (event instanceof PostConstructApplicationEvent) {
+ try {
+ startHornetQ();
+ } catch (Exception e) {
+ throw new AbortProcessingException(e);
+ }
+
+ Application application =
FacesContext.getCurrentInstance().getApplication();
+ application.subscribeToEvent(PreDestroyApplicationEvent.class, this);
+ } else {
+ try {
+ stopHornetQ();
+ } catch (Exception e) {
+ throw new AbortProcessingException(e);
+ }
+ }
+ }
+
+ /**
+ * @throws Exception
+ *
+ */
+ private void stopHornetQ() throws Exception {
+ serverManager.stop();
+ serverManager = null;
+ }
+
+ /**
+ * @throws Exception
+ *
+ */
+ private void startHornetQ() throws Exception {
+ // Step 2. Create the Configuration, and set the properties accordingly
+ Configuration configuration = new ConfigurationImpl();
+ configuration.setPersistenceEnabled(false);
+ configuration.setSecurityEnabled(false);
+
+ TransportConfiguration transpConf = new
TransportConfiguration(NettyAcceptorFactory.class.getName());
+
+ HashSet<TransportConfiguration> setTransp = new
HashSet<TransportConfiguration>();
+ setTransp.add(transpConf);
+
+ configuration.setAcceptorConfigurations(setTransp);
+
+ // Step 3. Create and start the server
+ HornetQServer server = HornetQServers.newHornetQServer(configuration);
+
+ serverManager = new JMSServerManagerImpl(server);
+
+ //if you want to use JNDI, simple inject a context here or don't call this
method and make sure the JNDI parameters are set.
+ serverManager.setContext(new InitialContext());
+ serverManager.start();
+
+ serverManager.createConnectionFactory("ConnectionFactory", new
TransportConfiguration(NettyConnectorFactory.class.getName()),
+ "ConnectionFactory");
+
+ serverManager.createTopic(false, "chat", "/topic/chat");
+ serverManager.createTopic(false, "info", "/topic/info");
+ }
+
+ public boolean isListenerForSource(Object source) {
+ return true;
+ }
+
+}
Added: trunk/examples/push-demo/src/main/java/demo/TopicsInitializer.java
===================================================================
--- trunk/examples/push-demo/src/main/java/demo/TopicsInitializer.java
(rev 0)
+++ trunk/examples/push-demo/src/main/java/demo/TopicsInitializer.java 2010-11-02 02:44:05
UTC (rev 19881)
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package demo;
+
+import java.text.MessageFormat;
+
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.SystemEvent;
+import javax.faces.event.SystemEventListener;
+import javax.servlet.http.HttpServletRequest;
+
+import org.richfaces.application.push.EventAbortedException;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.SessionPreSubscriptionEvent;
+import org.richfaces.application.push.SessionSubscriptionEvent;
+import org.richfaces.application.push.SessionTopicListener;
+import org.richfaces.application.push.SessionUnsubscriptionEvent;
+import org.richfaces.application.push.Topic;
+import org.richfaces.application.push.TopicKey;
+import org.richfaces.application.push.TopicsContext;
+import org.richfaces.application.push.impl.DefaultMessageDataSerializer;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TopicsInitializer implements SystemEventListener {
+
+ public void processEvent(SystemEvent event) throws AbortProcessingException {
+ TopicsContext topicsContext = TopicsContext.lookup();
+
+ Topic topic = topicsContext.getOrCreateTopic(new TopicKey("chat"));
+
+ topic.setMessageDataSerializer(DefaultMessageDataSerializer.instance());
+
+ topic.addTopicListener(new SessionTopicListener() {
+
+ public void processUnsubscriptionEvent(SessionUnsubscriptionEvent event)
throws EventAbortedException {
+ TopicKey topicKey = event.getTopicKey();
+ Session session = event.getSession();
+ System.out.println(MessageFormat.format("Session {0} disconnected
from {1}", session.getId(), topicKey.getTopicAddress()));
+ }
+
+ public void processSubscriptionEvent(SessionSubscriptionEvent event) throws
EventAbortedException {
+ TopicKey topicKey = event.getTopicKey();
+ Session session = event.getSession();
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ HttpServletRequest hsr = (HttpServletRequest)
facesContext.getExternalContext().getRequest();
+
+ System.out.println(MessageFormat.format("Session {0} connected to
{1} from {2}", session.getId(),
+ topicKey.getTopicAddress(), hsr.getRemoteAddr()));
+ }
+
+ public void processPreSubscriptionEvent(SessionPreSubscriptionEvent event)
throws EventAbortedException {
+ ExternalContext externalContext =
FacesContext.getCurrentInstance().getExternalContext();
+ ChatBean chatBean = (ChatBean)
externalContext.getSessionMap().get("chatBean");
+ if (chatBean == null ||
"badname".equals(chatBean.getUserName())) {
+ throw new EventAbortedException("User name has not passed
validation");
+ }
+ }
+ });
+ }
+
+ public boolean isListenerForSource(Object source) {
+ return true;
+ }
+
+}
Added: trunk/examples/push-demo/src/main/webapp/META-INF/MANIFEST.MF
===================================================================
--- trunk/examples/push-demo/src/main/webapp/META-INF/MANIFEST.MF
(rev 0)
+++ trunk/examples/push-demo/src/main/webapp/META-INF/MANIFEST.MF 2010-11-02 02:44:05 UTC
(rev 19881)
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+
Added: trunk/examples/push-demo/src/main/webapp/WEB-INF/faces-config.xml
===================================================================
--- trunk/examples/push-demo/src/main/webapp/WEB-INF/faces-config.xml
(rev 0)
+++ trunk/examples/push-demo/src/main/webapp/WEB-INF/faces-config.xml 2010-11-02 02:44:05
UTC (rev 19881)
@@ -0,0 +1,32 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<faces-config version="2.0"
xmlns="http://java.sun.com/xml/ns/javaee"
+
xmlns:xi="http://www.w3.org/2001/XInclude"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
+
+ <application>
+ <system-event-listener>
+
<system-event-listener-class>demo.HornetQInitializer</system-event-listener-class>
+
<system-event-class>javax.faces.event.PostConstructApplicationEvent</system-event-class>
+ </system-event-listener>
+ <system-event-listener>
+
<system-event-listener-class>demo.TopicsInitializer</system-event-listener-class>
+
<system-event-class>javax.faces.event.PostConstructApplicationEvent</system-event-class>
+ </system-event-listener>
+ </application>
+
+ <navigation-rule>
+ <from-view-id>*</from-view-id>
+ <navigation-case>
+ <from-outcome>chat</from-outcome>
+ <to-view-id>/chat.xhtml</to-view-id>
+ <redirect>
+ <view-param>
+ <name>username</name>
+ <value>#{username}</value>
+ </view-param>
+ </redirect>
+ </navigation-case>
+ </navigation-rule>
+
+</faces-config>
\ No newline at end of file
Added: trunk/examples/push-demo/src/main/webapp/WEB-INF/jboss-scanning.xml
===================================================================
--- trunk/examples/push-demo/src/main/webapp/WEB-INF/jboss-scanning.xml
(rev 0)
+++ trunk/examples/push-demo/src/main/webapp/WEB-INF/jboss-scanning.xml 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,11 @@
+<scanning xmlns="urn:jboss:scanning:1.0">
+<!--
+ For JBoss AS 6 integration there is a conflict with guava, and
+ google-collections. JBAS-8361
+-->
+ <path name="WEB-INF/classes"></path>
+
+ <path name="WEB-INF/lib/guava-r05.jar">
+ <exclude name="com.google.common.collect" />
+ </path>
+</scanning>
\ No newline at end of file
Added: trunk/examples/push-demo/src/main/webapp/WEB-INF/web.xml
===================================================================
--- trunk/examples/push-demo/src/main/webapp/WEB-INF/web.xml (rev
0)
+++ trunk/examples/push-demo/src/main/webapp/WEB-INF/web.xml 2010-11-02 02:44:05 UTC (rev
19881)
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xmlns="http://java.sun.com/xml/ns/javaee"
+
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ id="WebApp_ID" version="3.0">
+
+ <context-param>
+ <param-name>javax.faces.PROJECT_STAGE</param-name>
+ <param-value>Development</param-value>
+ </context-param>
+
+ <listener>
+
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
+ </listener>
+
+ <filter-mapping>
+ <filter-name>PushFilter</filter-name>
+ <url-pattern>/faces/*</url-pattern>
+ </filter-mapping>
+
+ <filter>
+ <filter-name>PushFilter</filter-name>
+ <filter-class>org.richfaces.webapp.PushFilter</filter-class>
+ <async-supported>true</async-supported>
+ </filter>
+
+ <!-- context-param>
+ <param-name>org.atmosphere.useWebSocket</param-name>
+ <param-value>true</param-value>
+ </context-param-->
+
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>/faces/*</url-pattern>
+ </servlet-mapping>
+</web-app>
\ No newline at end of file
Added: trunk/examples/push-demo/src/main/webapp/chat.xhtml
===================================================================
--- trunk/examples/push-demo/src/main/webapp/chat.xhtml (rev 0)
+++ trunk/examples/push-demo/src/main/webapp/chat.xhtml 2010-11-02 02:44:05 UTC (rev
19881)
@@ -0,0 +1,72 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html
xmlns="http://www.w3.org/1999/xhtml"
+
xmlns:ui="http://java.sun.com/jsf/facelets"
+
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:f="http://java.sun.com/jsf/core"
+
xmlns:c="http://java.sun.com/jsp/jstl/core"
+
xmlns:a4j="http://richfaces.org/a4j">
+
+ <f:view>
+ <f:metadata>
+ <f:viewParam name="username" value="#{chatBean.userName}"
/>
+ <f:event type="preRenderView"
listener="#{chatBean.joinChat}"/>
+ </f:metadata>
+ <h:head>
+ <h:outputStylesheet>
+ .pushBlock {
+ width: 300px;
+ float: left;
+ border: 2px dotted navy;
+ margin: 10px;
+ }
+
+ .chatOutput {
+ width: 280px;
+ height: 200px;
+ overflow: auto;
+ }
+ </h:outputStylesheet>
+ </h:head>
+ <h:body>
+ <h:form id="form">
+ You are: #{chatBean.userName} <br />
+
+ <script type="text/javascript">
+ function clearInput(event) {
+ if (event.status == 'success') {
+ jQuery('.messageInput').val('');
+ }
+ }
+ </script>
+
+ <c:forEach var="channel" items="#{channelsBean.channels}">
+ <c:set var="channelName" value="#{channel.name}" />
+
+ <h:panelGroup styleClass="pushBlock" layout="block"
id="pushBlock_#{channelName}">
+
+ Subchannel: #{channelName}
+
+ <h:selectBooleanCheckbox value="true"
valueChangeListener="#{channel.processChannelStateChange}">
+ <f:ajax event="click" render="pushBlock_#{channelName}"
/>
+ </h:selectBooleanCheckbox>
+
+ <h:panelGroup layout="block"
rendered="#{channel.rendered}">
+ <a4j:push address="#{channelName}@chat"
onerror="alert(event.rf.data)" ondataavailable="jQuery('<div
/>').prependTo('.#{channelName}Output').text(event.rf.data)"
/>
+
+ <h:inputText styleClass="messageInput"
value="#{chatBean.message}" size="40" />
+
+ <h:commandLink value="ajax" action="#{chatBean.say}">
+ <f:setPropertyActionListener value="#{channelName}"
target="#{chatBean.subchannel}" />
+ <f:ajax execute="pushBlock_#{channelName}"
onevent="clearInput" />
+ </h:commandLink>
+
+ <h:panelGroup styleClass="#{channelName}Output chatOutput"
layout="block" />
+ </h:panelGroup>
+ </h:panelGroup>
+ </c:forEach>
+ </h:form>
+ </h:body>
+ </f:view>
+</html>
\ No newline at end of file
Added: trunk/examples/push-demo/src/main/webapp/index.jsp
===================================================================
--- trunk/examples/push-demo/src/main/webapp/index.jsp (rev 0)
+++ trunk/examples/push-demo/src/main/webapp/index.jsp 2010-11-02 02:44:05 UTC (rev
19881)
@@ -0,0 +1,6 @@
+<%@ page language="java" contentType="text/html;
charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+
+<%
+ response.sendRedirect(request.getContextPath() + "/faces/index.xhtml");
+%>
\ No newline at end of file
Added: trunk/examples/push-demo/src/main/webapp/index.xhtml
===================================================================
--- trunk/examples/push-demo/src/main/webapp/index.xhtml (rev 0)
+++ trunk/examples/push-demo/src/main/webapp/index.xhtml 2010-11-02 02:44:05 UTC (rev
19881)
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html
xmlns="http://www.w3.org/1999/xhtml"
+
xmlns:ui="http://java.sun.com/jsf/facelets"
+
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:f="http://java.sun.com/jsf/core">
+
+ <f:view>
+ <h:head>
+ </h:head>
+ <h:body>
+ <h:form id="form">
+ Enter username: <h:inputText value="#{username}"
required="true" />
+ <h:commandLink action="chat" value="Enter chat" />
+ </h:form>
+ <h:link value="Test with bad user name" outcome="chat">
+ <f:param name="username" value="badname" />
+ </h:link>
+ </h:body>
+ </f:view>
+</html>
\ No newline at end of file
Modified: trunk/ui/common/ui/checkstyle-suppressions.xml
===================================================================
--- trunk/ui/common/ui/checkstyle-suppressions.xml 2010-11-02 01:14:12 UTC (rev 19880)
+++ trunk/ui/common/ui/checkstyle-suppressions.xml 2010-11-02 02:44:05 UTC (rev 19881)
@@ -33,4 +33,8 @@
<!-- TODO it is hot fix for building process, this files belong to the
ui/output/trunk/panela/ui module,
and must be removed from here -->
<suppress checks="IllegalCatch"
files="AbstractTogglePanel.java" />
-</suppressions>
+
+ <!-- TODO it is hot fix for building process, this files belong to the
push-redesign module,
+ and must be removed from here -->
+ <suppress checks="IllegalCatch" files="AbstractRequest.java"
/>
+</suppressions>
\ No newline at end of file
Modified: trunk/ui/core/ui/src/main/java/org/richfaces/component/AbstractPush.java
===================================================================
--- trunk/ui/core/ui/src/main/java/org/richfaces/component/AbstractPush.java 2010-11-02
01:14:12 UTC (rev 19880)
+++ trunk/ui/core/ui/src/main/java/org/richfaces/component/AbstractPush.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,123 +1,58 @@
-/**
- * License Agreement.
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
*
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
*
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
+ * This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
*/
-
-
-
package org.richfaces.component;
-import java.io.IOException;
-import java.util.EventListener;
+import javax.faces.component.UIComponentBase;
-import javax.el.MethodExpression;
-import javax.faces.component.NamingContainer;
-import javax.faces.context.FacesContext;
-import javax.servlet.http.HttpSession;
-
import org.richfaces.cdk.annotations.Attribute;
import org.richfaces.cdk.annotations.EventName;
import org.richfaces.cdk.annotations.JsfComponent;
import org.richfaces.cdk.annotations.JsfRenderer;
-import org.richfaces.cdk.annotations.Signature;
import org.richfaces.cdk.annotations.Tag;
import org.richfaces.cdk.annotations.TagType;
/**
- * Component for periodically call AJAX events on server ( poll actions )
- * @author shura
- *
+ * @author Nick Belaevski
+ *
*/
-@JsfComponent(
- tag = @Tag(generate = false, handler =
"org.richfaces.view.facelets.html.AjaxPushHandler", type = TagType.Facelets),
- renderer = @JsfRenderer(type = "org.richfaces.PushRenderer")
-)
-public abstract class AbstractPush extends AbstractActionComponent {
+@JsfComponent(type = AbstractPush.COMPONENT_TYPE, family = AbstractPush.COMPONENT_FAMILY,
tag = @Tag(name = "push", type = TagType.Facelets),
+ renderer = @JsfRenderer(type = "org.richfaces.PushRenderer"))
+public abstract class AbstractPush extends UIComponentBase {
public static final String COMPONENT_TYPE = "org.richfaces.Push";
-
- public static final String COMPONENT_FAMILY = "org.richfaces.Push";
- public static final String DATA_AVAILABLE = "dataAvailable";
-
- public static final String ON_DATA_AVAILABLE = "ondataavailable";
-
+ public static final String COMPONENT_FAMILY = "org.richfaces.Push";
+
@Override
- public void encodeBegin(FacesContext context) throws IOException {
- MethodExpression producer = getEventProducer();
-
- // Subscribe events producer to push status listener.
- if (null != producer) {
- producer.invoke(context.getELContext(), new Object[]
{getListener(context)});
- }
-
- super.encodeBegin(context);
+ public String getFamily() {
+ return COMPONENT_FAMILY;
}
- private PushEventTracker getListener(FacesContext context) {
- PushListenersManager pushListenersManager =
PushListenersManager.getInstance(context);
+ @Attribute(required = true)
+ public abstract String getAddress();
- return pushListenersManager.getListener(getListenerId(context));
- }
-
- public String getListenerId(FacesContext context) {
- Object session = context.getExternalContext().getSession(false);
- StringBuffer id = new StringBuffer();
-
- if (null != session && session instanceof HttpSession) {
- HttpSession httpSession = (HttpSession) session;
-
- id.append(httpSession.getId());
- }
-
- id.append(context.getViewRoot().getViewId());
- id.append(NamingContainer.SEPARATOR_CHAR);
- id.append(getClientId(context));
-
- return id.toString();
- }
-
- // ---------------------------------------
- @Attribute(signature = @Signature(parameters = EventListener.class))
- public abstract MethodExpression getEventProducer();
-
- public abstract void setEventProducer(MethodExpression producer);
-
- /**
- * @return time in mc for polling interval.
- */
- @Attribute(defaultValue = "1000")
- public abstract int getInterval();
-
- @Attribute(defaultValue = "true")
- public abstract boolean isEnabled();
-
- // TODO what wrong with that name?
- @Attribute(events = @EventName(value = DATA_AVAILABLE, defaultEvent = true))
+ @Attribute(events = {@EventName("dataavailable")})
public abstract String getOndataavailable();
- @Attribute(events = @EventName("begin"))
- public abstract String getOnbegin();
-
- @Attribute(events = @EventName("beforedomupdate"))
- public abstract String getOnbeforedomupdate();
-
- @Attribute(events = @EventName("complete"))
- public abstract String getOncomplete();
+ @Attribute(events = {@EventName("error")})
+ public abstract String getOnerror();
}
Deleted: trunk/ui/core/ui/src/main/java/org/richfaces/component/PushEventTracker.java
===================================================================
---
trunk/ui/core/ui/src/main/java/org/richfaces/component/PushEventTracker.java 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/ui/core/ui/src/main/java/org/richfaces/component/PushEventTracker.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,52 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-
-package org.richfaces.component;
-
-import java.io.Serializable;
-
-import java.util.EventObject;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.ajax4jsf.event.PushEventListener;
-
-/**
- * @author Nick Belaevski
- * @since 4.0
- */
-public class PushEventTracker implements PushEventListener, Serializable {
-
- /**
- *
- */
- private static final long serialVersionUID = -4362297582678089326L;
- private final AtomicBoolean eventPerformed = new AtomicBoolean(false);
-
- public void onEvent(EventObject event) {
- eventPerformed.set(true);
- }
-
- public boolean pollStatus() {
- return eventPerformed.compareAndSet(true, false);
- }
-}
Deleted: trunk/ui/core/ui/src/main/java/org/richfaces/component/PushListenersManager.java
===================================================================
---
trunk/ui/core/ui/src/main/java/org/richfaces/component/PushListenersManager.java 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/ui/core/ui/src/main/java/org/richfaces/component/PushListenersManager.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,66 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-
-package org.richfaces.component;
-
-import java.util.Map;
-
-import javax.faces.context.FacesContext;
-
-import org.richfaces.util.LRUMap;
-
-/**
- * @author Nick Belaevski
- * @since 4.0
- */
-public class PushListenersManager {
-
- private static final String CONTEXT_ATTRIBUTE_NAME =
"richFacesPushListenersManager";
-
- private Map<String, PushEventTracker> listeners;
-
- public PushListenersManager() {
-
- // TODO configure map size
- this.listeners = new LRUMap<String, PushEventTracker>();
- }
-
- public static PushListenersManager getInstance(FacesContext context) {
- return (PushListenersManager)
context.getExternalContext().getApplicationMap().get(CONTEXT_ATTRIBUTE_NAME);
- }
-
- public PushEventTracker getListener(String name) {
- synchronized (listeners) {
-
- // LRUMap involves write for each operation, so RWLock is not acceptable
here
- PushEventTracker listener = listeners.get(name);
-
- if (listener == null) {
- listener = new PushEventTracker();
- listeners.put(name, listener);
- }
-
- return listener;
- }
- }
-}
Added: trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/PushRendererBase.java
===================================================================
--- trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/PushRendererBase.java
(rev 0)
+++
trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/PushRendererBase.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,74 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.renderkit;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.application.Resource;
+import javax.faces.application.ResourceHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.render.Renderer;
+
+import org.ajax4jsf.javascript.ScriptUtils;
+import org.richfaces.component.AbstractPush;
+import org.richfaces.resource.PushResource;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class PushRendererBase extends Renderer {
+
+ private static final String PUSH_URL_ENCODED_ATTRIBUTE =
PushRendererBase.class.getName();
+
+ protected String getPushUrl(FacesContext context) {
+ ResourceHandler resourceHandler = context.getApplication().getResourceHandler();
+ Resource pushResource =
resourceHandler.createResource(PushResource.class.getName());
+
+ return pushResource.getRequestPath();
+ }
+
+ protected boolean shouldEncodePushUrl(FacesContext context) {
+ Map<Object, Object> attributes = context.getAttributes();
+
+ if (attributes.get(PUSH_URL_ENCODED_ATTRIBUTE) == null) {
+ attributes.put(PUSH_URL_ENCODED_ATTRIBUTE, Boolean.TRUE);
+ return true;
+ }
+
+ return false;
+ }
+
+ protected String getOptionsString(FacesContext context, UIComponent component) {
+ AbstractPush push = (AbstractPush) component;
+
+ Map<String, Object> options = new HashMap<String, Object>(2);
+
+ options.put("address", push.getAddress());
+ options.put("dataHandler", push.getOndataavailable());
+ options.put("errorHandler", push.getOnerror());
+
+ return ScriptUtils.toScript(options);
+ }
+}
Deleted:
trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java
===================================================================
---
trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/ui/core/ui/src/main/java/org/richfaces/renderkit/html/AjaxPushRenderer.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,153 +0,0 @@
-/**
- * License Agreement.
- *
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
- *
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-package org.richfaces.renderkit.html;
-
-import static org.richfaces.renderkit.RenderKitUtils.shouldRenderAttribute;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.faces.application.ResourceDependency;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.faces.context.ResponseWriter;
-import javax.faces.event.ActionEvent;
-
-import org.ajax4jsf.javascript.JSFunction;
-import org.ajax4jsf.javascript.JSFunctionDefinition;
-import org.ajax4jsf.javascript.JSReference;
-import org.richfaces.cdk.annotations.JsfRenderer;
-import org.richfaces.component.AbstractPush;
-import org.richfaces.renderkit.HtmlConstants;
-import org.richfaces.renderkit.RendererBase;
-import org.richfaces.renderkit.util.HandlersChain;
-import org.richfaces.resource.PushResource;
-
-/**
- * @author shura
- */
-@ResourceDependency(library = "org.richfaces", name = "ajax.reslib")
-@JsfRenderer
-public class AjaxPushRenderer extends RendererBase {
-
- public static final String COMPONENT_FAMILY = "org.richfaces.Push";
-
- public static final String RENDERER_TYPE = "org.richfaces.PushRenderer";
-
- public static final String PUSH_INTERVAL_PARAMETER =
"A4J.AJAX.Push.INTERVAL";
-
- public static final int DEFAULT_PUSH_INTERVAL = 1000;
-
- public static final int DEFAULT_PUSH_WAIT = Integer.MIN_VALUE;
-
- @Override
- protected void queueComponentEventForBehaviorEvent(FacesContext context, UIComponent
component, String eventName) {
- super.queueComponentEventForBehaviorEvent(context, component, eventName);
-
- if (AbstractPush.DATA_AVAILABLE.equals(eventName)) {
- new ActionEvent(component).queue();
- }
- }
-
- /* (non-Javadoc)
- * @see
org.ajax4jsf.renderkit.RendererBase#doEncodeEnd(javax.faces.context.ResponseWriter,
- * javax.faces.context.FacesContext, javax.faces.component.UIComponent)
- */
- protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent
component) throws IOException {
- AbstractPush push = (AbstractPush) component;
- writer.startElement(HtmlConstants.SPAN_ELEM, component);
- writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, "display:none;",
null);
- getUtils().encodeId(context, component);
-
- //TODO - ?
- getUtils().encodeBeginFormIfNessesary(context, component);
- // pushing script.
- writer.startElement(HtmlConstants.SCRIPT_ELEM, component);
- writer.writeAttribute(HtmlConstants.TYPE_ATTR, "text/javascript",
null);
- StringBuffer script = new StringBuffer("\n");
- if (push.isEnabled()) {
- JSFunction function = new JSFunction("RichFaces.startPush");
- // Set dummy form id, if nessesary.
- Map<String, Object> options = new HashMap<String, Object>();
-
- int interval = push.getInterval();
- if (shouldRenderAttribute(interval)) {
- String intervalInitParameter =
context.getExternalContext().getInitParameter(PUSH_INTERVAL_PARAMETER);
- if (null != intervalInitParameter) {
- interval = Integer.parseInt(intervalInitParameter);
- } else {
- interval = DEFAULT_PUSH_INTERVAL;
- }
- }
-
- options.put("interval", interval);
- options.put("pushResourceUrl", new
PushResource().getRequestPath());
- options.put("pushId", push.getListenerId(context));
- options.put("clientId", component.getClientId(context));
-
- HandlersChain handlersChain = new HandlersChain(context, push);
- handlersChain.addInlineHandlerFromAttribute(AbstractPush.ON_DATA_AVAILABLE);
- handlersChain.addBehaviors(AbstractPush.DATA_AVAILABLE);
- handlersChain.addAjaxSubmitFunction();
-
- String handler = handlersChain.toScript();
-
- if (handler != null) {
- JSFunctionDefinition dataAvailableHandler = new
JSFunctionDefinition(JSReference.EVENT);
- dataAvailableHandler.addToBody(handler);
- options.put(AbstractPush.ON_DATA_AVAILABLE, dataAvailableHandler);
- }
- function.addParameter(options);
- script.append(function.toScript());
- } else {
-
script.append("RichFaces.stopPush('").append(push.getListenerId(context)).append("')");
- }
- script.append(";\n");
- writer.writeText(script.toString(), null);
- writer.endElement(HtmlConstants.SCRIPT_ELEM);
- getUtils().encodeEndFormIfNessesary(context, component);
- writer.endElement(HtmlConstants.SPAN_ELEM);
- }
-
- /* (non-Javadoc)
- * @see org.ajax4jsf.renderkit.RendererBase#getComponentClass()
- */
- protected Class<? extends UIComponent> getComponentClass() {
- // only push component is allowed.
- return AbstractPush.class;
- }
-
- @Override
- protected void doDecode(FacesContext context, UIComponent component) {
- super.doDecode(context, component);
-
- AbstractPush push = (AbstractPush) component;
- if (push.isEnabled()) {
- Map<String, String> requestParameterMap =
context.getExternalContext().getRequestParameterMap();
- if (requestParameterMap.get(push.getClientId(context)) != null) {
- new ActionEvent(push).queue();
- }
- }
- }
-
-}
Modified: trunk/ui/core/ui/src/main/java/org/richfaces/resource/PushResource.java
===================================================================
--- trunk/ui/core/ui/src/main/java/org/richfaces/resource/PushResource.java 2010-11-02
01:14:12 UTC (rev 19880)
+++ trunk/ui/core/ui/src/main/java/org/richfaces/resource/PushResource.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,97 +1,125 @@
-/**
- * License Agreement.
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
*
- * Rich Faces - Natural Ajax for Java Server Faces (JSF)
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
*
- * Copyright (C) 2007 Exadel, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful,
+ * This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
*/
-
package org.richfaces.resource;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
-import javax.faces.application.Resource;
+import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
+import org.ajax4jsf.javascript.ScriptUtils;
import org.richfaces.application.ServiceTracker;
-import org.richfaces.component.PushEventTracker;
-import org.richfaces.component.PushListenersManager;
+import org.richfaces.application.push.PushContext;
+import org.richfaces.application.push.PushContextFactory;
+import org.richfaces.application.push.Session;
+import org.richfaces.application.push.TopicKey;
/**
* @author Nick Belaevski
- * @since 4.0
+ *
*/
-
-//TODO make this a singleton
@DynamicResource
-public class PushResource extends Resource {
+public class PushResource implements UserResource {
- public PushResource() {
- setResourceName(getClass().getName());
+ private static final String PUSH_TOPIC_PARAM = "pushTopic";
+
+ private static final String FORGET_PUSH_SESSION_ID_PARAM =
"forgetPushSessionId";
+
+ public Map<String, String> getResponseHeaders() {
+ return null;
}
-
- public InputStream getInputStream() throws IOException {
+
+ public Date getLastModified() {
return null;
}
- public Map<String, String> getResponseHeaders() {
- Map<String, String> headers = new HashMap<String, String>();
+ private InputStream mapToScript(Map<String, Object> map) {
+ try {
+ byte[] bs = ScriptUtils.toScript(map).getBytes("UTF-8");
+ return new ByteArrayInputStream(bs);
+ } catch (UnsupportedEncodingException e) {
+ throw new FacesException(e.getMessage(), e);
+ }
+ }
+
+ private Map<String, String> getFailuresMap(Map<TopicKey, String>
failedSubscriptions) {
+ Map<String,String> result = new HashMap<String, String>();
+
+ for (Entry<TopicKey, String> entry: failedSubscriptions.entrySet()) {
+ result.put(entry.getKey().getTopicAddress(), entry.getValue());
+ }
+
+ return result;
+ }
+
+ public InputStream getInputStream() throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
- String pushId = externalContext.getRequestParameterMap().get("id");
- if (pushId != null && pushId.length() != 0) {
- PushListenersManager manager =
PushListenersManager.getInstance(facesContext);
- PushEventTracker eventTracker = manager.getListener(pushId);
-
- if (eventTracker != null) {
- if (eventTracker.pollStatus()) {
- headers.put("Ajax-Push-Status", "READY");
- }
+ PushContextFactory pushContextFactory =
ServiceTracker.getService(PushContextFactory.class);
+ PushContext pushContext = pushContextFactory.getPushContext();
+
+ String forgetPushSessionId =
externalContext.getRequestParameterMap().get(FORGET_PUSH_SESSION_ID_PARAM);
+ if (forgetPushSessionId != null) {
+ Session oldSession =
pushContext.getSessionManager().getPushSession(forgetPushSessionId);
+ if (oldSession != null) {
+ oldSession.destroy();
}
}
+
+ Session session =
pushContext.getSessionFactory().createSession(UUID.randomUUID().toString());
+
+ String[] topicNames =
externalContext.getRequestParameterValuesMap().get(PUSH_TOPIC_PARAM);
+
+ if (topicNames == null) {
+ throw new IllegalArgumentException();
+ }
+
+ session.subscribe(topicNames);
+
+ Map<String, Object> subscriptionData = new HashMap<String,
Object>(4);
+ subscriptionData.put("sessionId", session.getId());
- return headers;
+ Map<TopicKey, String> failedSubscriptions =
session.getFailedSubscriptions();
+ subscriptionData.put("failures", getFailuresMap(failedSubscriptions));
+
+ return mapToScript(subscriptionData);
}
public String getContentType() {
- return null;
+ return "application/javascript; charset=utf-8";
}
- @Override
- public String getRequestPath() {
- FacesContext facesContext = FacesContext.getCurrentInstance();
- ResourceCodec resourceCodec = ServiceTracker.getService(ResourceCodec.class);
-
- String requestPath = resourceCodec.encodeResourceRequestPath(facesContext, null,
getResourceName(), null, null);
- return resourceCodec.encodeJSFMapping(facesContext, requestPath);
+ public int getContentLength() {
+ return -1;
}
- @Override
- public URL getURL() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean userAgentNeedsUpdate(FacesContext context) {
- return true;
- }
}
Deleted:
trunk/ui/core/ui/src/main/java/org/richfaces/view/facelets/html/AjaxPushHandler.java
===================================================================
---
trunk/ui/core/ui/src/main/java/org/richfaces/view/facelets/html/AjaxPushHandler.java 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/ui/core/ui/src/main/java/org/richfaces/view/facelets/html/AjaxPushHandler.java 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,83 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright , Red Hat, Inc. and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.richfaces.view.facelets.html;
-
-import javax.faces.event.ActionEvent;
-import javax.faces.view.facelets.*;
-import org.richfaces.component.AbstractPush;
-import org.richfaces.view.facelets.MethodMetadata;
-
-import java.util.EventListener;
-
-public class AjaxPushHandler extends ComponentHandler {
-
- private static final AjaxPushHandlerMetaRule META_RULE = new
AjaxPushHandlerMetaRule();
-
-
- public AjaxPushHandler(ComponentConfig config) {
- super(config);
-
- }
-
- protected MetaRuleset createMetaRuleset(Class type) {
- MetaRuleset m = super.createMetaRuleset(type);
- m.addRule(META_RULE);
- return m;
- }
-
- static class AjaxPushHandlerMetaRule extends MetaRule{
-
- public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget
meta) {
- if (meta.isTargetInstanceOf(AbstractPush.class)) {
- if ("action".equals(name)) {
- return new MethodMetadata(attribute) {
- public void applyMetadata(FaceletContext ctx, Object instance) {
- ((AbstractPush) instance).setAction(getMethodBinding(ctx));
- }
- };
- }
- if ("actionExpression".equals(name)) {
- return new MethodMetadata(attribute) {
- public void applyMetadata(FaceletContext ctx, Object instance) {
- ((AbstractPush)
instance).setActionExpression(getMethodExpression(ctx));
- }
- };
- }
- if ("actionListener".equals(name)) {
- return new MethodMetadata(attribute, ActionEvent.class) {
- public void applyMetadata(FaceletContext ctx, Object instance) {
- ((AbstractPush)
instance).setActionListener(getMethodBinding(ctx));
- }
- };
- }
- if ("eventProducer".equals(name)) {
- return new MethodMetadata(attribute, EventListener.class) {
- public void applyMetadata(FaceletContext ctx, Object instance) {
- ((AbstractPush)
instance).setEventProducer(getMethodExpression(ctx));
- }
- };
- }
- }
- return null;
- }
- }
-}
Deleted: trunk/ui/core/ui/src/main/resources/META-INF/push-managed-beans.faces-config.xml
===================================================================
---
trunk/ui/core/ui/src/main/resources/META-INF/push-managed-beans.faces-config.xml 2010-11-02
01:14:12 UTC (rev 19880)
+++
trunk/ui/core/ui/src/main/resources/META-INF/push-managed-beans.faces-config.xml 2010-11-02
02:44:05 UTC (rev 19881)
@@ -1,12 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-
-<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
- version="2.0">
-
- <managed-bean eager="true">
- <managed-bean-name>richFacesPushListenersManager</managed-bean-name>
- <managed-bean-class>org.richfaces.component.PushListenersManager</managed-bean-class>
- <managed-bean-scope>application</managed-bean-scope>
- </managed-bean>
-
-</faces-config>
\ No newline at end of file
Added:
trunk/ui/core/ui/src/main/resources/META-INF/resources/net.java.dev.atmosphere/jquery-atmosphere.js
===================================================================
---
trunk/ui/core/ui/src/main/resources/META-INF/resources/net.java.dev.atmosphere/jquery-atmosphere.js
(rev 0)
+++
trunk/ui/core/ui/src/main/resources/META-INF/resources/net.java.dev.atmosphere/jquery-atmosphere.js 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,508 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *
http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+jQuery.atmosphere = function() {
+ var activeRequest;
+ $(window).unload(function() {
+ if (activeRequest)
+ activeRequest.abort();
+ });
+
+ return {
+ version : 0.7,
+ response : {
+ status : 200,
+ responseBody : '',
+ headers : [],
+ state : "messageReceived",
+ transport : "polling",
+ push : [],
+ error : null,
+ id : 0
+ },
+
+ request : {},
+ logLevel : 'info',
+ callbacks : [],
+ activeTransport : null,
+ websocket : null,
+ killHiddenIFrame : null,
+
+ subscribe : function(url, callback, request) {
+ jQuery.atmosphere.request = jQuery.extend({
+ timeout : 300000,
+ method : 'GET',
+ headers : {},
+ contentType : "text/html;charset=ISO-8859-1",
+ cache : true,
+ async : true,
+ ifModified : false,
+ callback : null,
+ dataType : '',
+ url : url,
+ data : '',
+ suspend : true,
+ maxRequest : 60,
+ lastIndex : 0,
+ logLevel : 'info',
+ requestCount : 0,
+ fallbackTransport : 'streaming',
+ transport : 'long-polling'
+
+ }, request);
+
+ logLevel = jQuery.atmosphere.request.logLevel || 'info';
+ if (callback != null) {
+ jQuery.atmosphere.addCallback(callback);
+ jQuery.atmosphere.request.callback = callback;
+ }
+
+ if (jQuery.atmosphere.request.transport != jQuery.atmosphere.activeTransport) {
+ jQuery.atmosphere.closeSuspendedConnection();
+ }
+ jQuery.atmosphere.activeTransport = jQuery.atmosphere.request.transport;
+
+ if (jQuery.atmosphere.request.transport != 'websocket') {
+ jQuery.atmosphere.executeRequest();
+ } else if (jQuery.atmosphere.request.transport == 'websocket') {
+ if (!window.WebSocket) {
+ jQuery.atmosphere
+ .log(
+ logLevel,
+ [ "Websocket is not supported, using request.fallbackTransport" ]);
+ jQuery.atmosphere.request.transport = jQuery.atmosphere.request.fallbackTransport;
+ jQuery.atmosphere.executeRequest();
+ } else {
+ jQuery.atmosphere.executeWebSocket();
+ }
+ }
+ },
+
+ /**
+ * Always make sure one transport is used, not two at the same time except for
Websocket.
+ */
+ closeSuspendedConnection : function() {
+ if (activeRequest != null) {
+ activeRequest.abort();
+ }
+
+ if (jQuery.atmosphere.websocket != null) {
+ jQuery.atmosphere.websocket.close();
+ jQuery.atmosphere.websocket = null;
+ }
+ },
+
+ executeRequest : function() {
+
+ if (jQuery.atmosphere.request.transport == 'streaming') {
+ if ($.browser.msie) {
+ jQuery.atmosphere.ieStreaming();
+ return;
+ } else if ((typeof window.addEventStream) == 'function') {
+ jQuery.atmosphere.operaStreaming();
+ return;
+ }
+ }
+
+ if (jQuery.atmosphere.request.requestCount++ <
jQuery.atmosphere.request.maxRequest) {
+ jQuery.atmosphere.response.push = function(url) {
+ jQuery.atmosphere.request.callback = null;
+ jQuery.atmosphere.publish(url, null,
+ jQuery.atmosphere.request);
+ };
+
+ var request = jQuery.atmosphere.request;
+ var response = jQuery.atmosphere.response;
+ if (request.transport != 'polling') {
+ response.transport = request.transport;
+ }
+
+ var ajaxRequest;
+ var error = false;
+ if ($.browser.msie) {
+ var activexmodes = [ "Msxml2.XMLHTTP", "Microsoft.XMLHTTP" ]
+ for ( var i = 0; i < activexmodes.length; i++) {
+ try {
+ ajaxRequest = new ActiveXObject(activexmodes[i])
+ } catch (e) {
+ }
+ }
+ } else if (window.XMLHttpRequest) {
+ ajaxRequest = new XMLHttpRequest();
+ }
+
+ if (request.suspend) {
+ activeRequest = ajaxRequest;
+ }
+
+ ajaxRequest.open(request.method, request.url, true);
+ ajaxRequest.setRequestHeader("X-Atmosphere-Framework",
+ jQuery.atmosphere.version);
+ ajaxRequest.setRequestHeader("X-Atmosphere-Transport",
+ request.transport);
+ ajaxRequest.setRequestHeader("X-Cache-Date", new Date());
+
+ if (!$.browser.msie) {
+ ajaxRequest.onerror = function() {
+ error = true;
+ try {
+ response.status = XMLHttpRequest.status;
+ } catch (e) {
+ response.status = 404;
+ }
+
+ response.state = "error";
+ jQuery.atmosphere.invokeCallback(response);
+ ajaxRequest.abort();
+ activeRequest = null;
+ }
+ }
+
+ ajaxRequest.onreadystatechange = function() {
+ var junkForWebkit = false;
+ var update = false;
+ if (ajaxRequest.readyState == 4) {
+ jQuery.atmosphere.request = request;
+ if (request.suspend && ajaxRequest.status == 200) {
+ jQuery.atmosphere.executeRequest();
+ }
+
+ if ($.browser.msie) {
+ update = true;
+ }
+ } else if (!$.browser.msie && ajaxRequest.readyState == 3
+ && ajaxRequest.status == 200) {
+ update = true;
+ } else {
+ clearTimeout(request.id);
+ }
+
+ if (update) {
+ if (request.transport == 'streaming') {
+ response.responseBody = ajaxRequest.responseText
+ .substring(request.lastIndex,
+ ajaxRequest.responseText.length);
+ request.lastIndex = ajaxRequest.responseText.length;
+
+ if (response.responseBody.indexOf("<!--") != -1) {
+ junkForWebkit = true;
+ }
+
+ } else {
+ response.responseBody = ajaxRequest.responseText;
+ }
+
+ if (response.responseBody.indexOf("parent.callback") != -1) {
+ var start = response.responseBody.indexOf("('") + 2;
+ var end = response.responseBody.indexOf("')");
+ response.responseBody = response.responseBody
+ .substring(start, end);
+ }
+
+ if (junkForWebkit)
+ return;
+
+ try {
+ response.status = ajaxRequest.status;
+ response.headers = ajaxRequest
+ .getAllResponseHeaders();
+ } catch (e) {
+ response.status = 404;
+ }
+
+ if (request.suspend) {
+ response.state = "messageReceived";
+ } else {
+ response.state = "messagePublished";
+ }
+ jQuery.atmosphere.invokeCallback(response);
+ }
+ }
+ ajaxRequest.send(request.data);
+
+ if (request.suspend) {
+ request.id = setTimeout(
+ function() {
+ ajaxRequest.abort();
+ jQuery.atmosphere.subscribe(request.url, null,
+ request);
+
+ }, request.timeout);
+ }
+ } else {
+ jQuery.atmosphere.log(logLevel,
+ [ "Max re-connection reached." ]);
+ }
+ },
+
+ operaStreaming : function() {
+
+ var url = jQuery.atmosphere.request.url;
+ var es = document.createElement('event-source');
+ var response = jQuery.atmosphere.response;
+
+ jQuery.atmosphere.response.push = function(url) {
+ jQuery.atmosphere.request.transport = 'polling';
+ jQuery.atmosphere.request.callback = null;
+ jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request);
+ };
+
+ es.setAttribute('src', url);
+ // without this check opera 9.5 would make two connections.
+ if (opera.version() < 9.5) {
+ document.body.appendChild(es);
+ }
+
+ var operaCallback = function(event) {
+ if (event.data) {
+ var junkForWebkit = false;
+
+ response.responseBody = event.data;
+ if (event.data.indexOf("<!--") != -1) {
+ junkForWebkit = true;
+ }
+
+ if (response.responseBody.indexOf("parent.callback") != -1) {
+ var start = response.responseBody.indexOf("('") + 2;
+ var end = response.responseBody.indexOf("')");
+ response.responseBody = response.responseBody
+ .substring(start, end);
+ }
+
+ if (junkForWebkit)
+ return;
+
+ response.state = "messageReceived";
+ jQuery.atmosphere.invokeCallback(response);
+ }
+ };
+
+ es.addEventListener('payload', operaCallback, false);
+
+ },
+
+ ieStreaming : function() {
+ var url = jQuery.atmosphere.request.url;
+ jQuery.atmosphere.response.push = function(url) {
+ jQuery.atmosphere.request.transport = 'polling';
+ jQuery.atmosphere.request.callback = null;
+ jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request);
+ };
+
+ transferDoc = new ActiveXObject("htmlfile");
+ transferDoc.open();
+ transferDoc.close();
+ var ifrDiv = transferDoc.createElement("div");
+ transferDoc.body.appendChild(ifrDiv);
+ ifrDiv.innerHTML = "<iframe src='" + url +
"'></iframe>";
+ transferDoc.parentWindow.callback = jQuery.atmosphere.streamingCallback;
+ },
+
+ streamingCallback : function(args) {
+ var response = jQuery.atmosphere.response;
+ response.transport = "streaming";
+ response.status = 200;
+ response.responseBody = args;
+ response.state = "messageReceived";
+
+ jQuery.atmosphere.invokeCallback(response);
+ },
+
+ executeWebSocket : function() {
+ var request = jQuery.atmosphere.request;
+ jQuery.atmosphere.log(logLevel, [ "Invoking executeWebSocket" ]);
+ jQuery.atmosphere.response.transport = "websocket";
+ var url = jQuery.atmosphere.request.url;
+ var callback = jQuery.atmosphere.request.callback;
+ var location = url.replace('http:', 'ws:')
+ .replace('https:', 'wss:');
+
+ var websocket = new WebSocket(location);
+ jQuery.atmosphere.websocket = websocket;
+
+ jQuery.atmosphere.response.push = function(url) {
+ var data;
+ var ws = jQuery.atmosphere.websocket;
+ try {
+ data = jQuery.atmosphere.request.data;
+ ws.send(jQuery.atmosphere.request.data);
+ } catch (e) {
+ jQuery.atmosphere
+ .log(
+ logLevel,
+ [ "Websocket failed. Downgrading to Comet and resending "
+ + data ]);
+ // Websocket is not supported, reconnect using the fallback transport.
+ request.transport = request.fallbackTransport;
+ jQuery.atmosphere.request = request;
+ jQuery.atmosphere.executeRequest();
+
+ // Repost the data.
+ jQuery.atmosphere.request.suspend = false;
+ jQuery.atmosphere.request.method = 'POST';
+ jQuery.atmosphere.request.data = data;
+ jQuery.atmosphere.response.state = 'messageReceived';
+ jQuery.atmosphere.response.transport = request.fallbackTransport;
+ jQuery.atmosphere.publish(url, null,
+ jQuery.atmosphere.request);
+
+ ws.onclose = function(message) {
+ }
+ ws.close();
+ }
+ };
+
+ websocket.onopen = function(message) {
+ jQuery.atmosphere.response.state = 'openning';
+ jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
+ };
+
+ websocket.onmessage = function(message) {
+ var data = message.data;
+ if (data.indexOf("parent.callback") != -1) {
+ var start = data.indexOf("('") + 2;
+ var end = data.indexOf("')");
+ jQuery.atmosphere.response.responseBody = data.substring(
+ start, end);
+ } else {
+ jQuery.atmosphere.response.responseBody = data;
+ }
+ jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
+ };
+
+ websocket.onerror = function(message) {
+ jQuery.atmosphere.response.state = 'error';
+ jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
+ };
+
+ websocket.onclose = function(message) {
+ jQuery.atmosphere.response.state = 'closed';
+ jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
+ };
+ },
+
+ addCallback : function(func) {
+ if (jQuery.inArray(func, jQuery.atmosphere.callbacks) == -1) {
+ jQuery.atmosphere.callbacks.push(func);
+ }
+ },
+
+ removeCallback : function(func) {
+ if (jQuery.inArray(func, jQuery.atmosphere.callbacks) != -1) {
+ jQuery.atmosphere.callbacks.splice(index);
+ }
+ },
+
+ invokeCallback : function(response) {
+ var call = function(index, func) {
+ func(response);
+ };
+
+ jQuery.atmosphere.log(logLevel, [ "Invoking "
+ + jQuery.atmosphere.callbacks.length + " callbacks" ]);
+ if (jQuery.atmosphere.callbacks.length > 0) {
+ jQuery.each(jQuery.atmosphere.callbacks, call);
+ }
+ },
+
+ publish : function(url, callback, request) {
+ jQuery.atmosphere.request = jQuery.extend({
+ connected : false,
+ timeout : 60000,
+ method : 'POST',
+ headers : {},
+ cache : true,
+ async : true,
+ ifModified : false,
+ callback : null,
+ dataType : '',
+ url : url,
+ data : '',
+ suspend : false,
+ maxRequest : 60,
+ logLevel : 'info',
+ requestCount : 0,
+ transport : 'polling'
+ }, request);
+
+ if (callback != null) {
+ jQuery.atmosphere.addCallback(callback);
+ }
+ jQuery.atmosphere.request.transport = 'polling';
+ if (jQuery.atmosphere.request.transport != 'websocket') {
+ jQuery.atmosphere.executeRequest();
+ } else if (jQuery.atmosphere.request.transport == 'websocket') {
+ if (!window.WebSocket) {
+ alert("WebSocket not supported by this browser");
+ } else {
+ jQuery.atmosphere.executeWebSocket();
+ }
+ }
+ },
+
+ unload : function(arg) {
+ if (window.addEventListener) {
+ document.addEventListener('unload', arg, false);
+ window.addEventListener('unload', arg, false);
+ } else { // IE
+ document.attachEvent('onunload', arg);
+ window.attachEvent('onunload', arg);
+ }
+ },
+
+ kill_load_bar : function() {
+ if (jQuery.atmosphere.killHiddenIFrame == null) {
+ jQuery.atmosphere.killHiddenIFrame = document
+ .createElement('iframe');
+ var ifr = jQuery.atmosphere.killHiddenIFrame;
+ ifr.style.display = 'block';
+ ifr.style.width = '0';
+ ifr.style.height = '0';
+ ifr.style.border = '0';
+ ifr.style.margin = '0';
+ ifr.style.padding = '0';
+ ifr.style.overflow = 'hidden';
+ ifr.style.visibility = 'hidden';
+ }
+ document.body.appendChild(ifr);
+ ifr.src = 'about:blank';
+ document.body.removeChild(ifr);
+ },
+
+ log : function(level, args) {
+ if (window.console) {
+ var logger = window.console[level];
+ if (typeof logger == 'function') {
+ logger.apply(window.console, args);
+ }
+ }
+ },
+
+ warn : function() {
+ log('warn', arguments);
+ },
+
+ info : function() {
+ if (logLevel != 'warn') {
+ log('info', arguments);
+ }
+ },
+
+ debug : function() {
+ if (logLevel == 'debug') {
+ log('debug', arguments);
+ }
+ }
+ }
+
+}();
Added: trunk/ui/core/ui/src/main/resources/META-INF/resources/org.richfaces/push.js
===================================================================
--- trunk/ui/core/ui/src/main/resources/META-INF/resources/org.richfaces/push.js
(rev 0)
+++
trunk/ui/core/ui/src/main/resources/META-INF/resources/org.richfaces/push.js 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,237 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright ${year}, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+(function(jsf, richfaces, _$) {
+
+ var COMPONENT_NAME = "Push";
+
+ var RICH_NAMESPACE = richfaces.Event.RICH_NAMESPACE;
+
+ var EVENT_NAMESPACE_SEPARATOR = richfaces.Event.EVENT_NAMESPACE_SEPARATOR;
+
+ var DATA_EVENT_NAME = 'dataAvailable' + EVENT_NAMESPACE_SEPARATOR +
RICH_NAMESPACE + EVENT_NAMESPACE_SEPARATOR + COMPONENT_NAME;
+
+ var ERROR_EVENT_NAME = 'error' + EVENT_NAMESPACE_SEPARATOR + RICH_NAMESPACE +
EVENT_NAMESPACE_SEPARATOR + COMPONENT_NAME;
+
+ var getDataEventNamespace = function(address) {
+ return DATA_EVENT_NAME + EVENT_NAMESPACE_SEPARATOR + address;
+ };
+
+ var getErrorEventNamespace = function(address) {
+ return ERROR_EVENT_NAME + EVENT_NAMESPACE_SEPARATOR + address;
+ };
+
+ richfaces.Push = (function() {
+
+ var addedTopics = {};
+
+ var removedTopics = {};
+
+ var handlersCounter = {};
+
+ var pushUrl = null;
+
+ var pushSessionId = null;
+
+ var suspendMessageEndMarker = /(<!--[^>]+-->\s*)+/;
+
+ var messageCallback = function(response) {
+ var dataString = response.responseBody.replace(suspendMessageEndMarker,
"");
+ if (dataString) {
+ var messages = _$.parseJSON(dataString);
+ if (messages) {
+ for (var i = 0; i < messages.length; i++) {
+ var message = messages[i];
+
+ richfaces.Event.fire(document, getDataEventNamespace(message.topic),
message.data);
+ }
+ }
+ }
+ };
+
+ var connect = function() {
+ var pushSessionIdRequestHandler = function(data) {
+ var subscriptionData = _$.parseJSON(data);
+
+
+ for (var failedTopicKey in subscriptionData.failures) {
+ richfaces.Event.fire(
+ document,
+ getErrorEventNamespace(failedTopicKey),
+ subscriptionData.failures[failedTopicKey]
+ );
+ }
+
+ if (subscriptionData.sessionId) {
+ pushSessionId = subscriptionData.sessionId;
+
+ _$.atmosphere.subscribe(pushUrl +
"?__richfacesPushAsync=1&pushSessionId=" + pushSessionId, messageCallback,
{
+ /*transport: 'websocket'*/
+ });
+ }
+ };
+
+ var topics = new Array();
+ for (var topicName in handlersCounter) {
+ topics.push(topicName);
+ }
+
+ var data = {
+ "pushTopic": topics
+ };
+
+ if (pushSessionId) {
+ data['forgetPushSessionId'] = pushSessionId;
+ }
+
+ //TODO handle request errors
+ _$.ajax({
+ data: data,
+ dataType: 'text',
+ success: pushSessionIdRequestHandler,
+ traditional: true,
+ type: 'POST',
+ url: pushUrl
+ });
+ };
+
+ var disconnect = function() {
+ _$.atmosphere.closeSuspendedConnection();
+ };
+
+ return {
+ increaseSubscriptionCounters: function(address) {
+ if (isNaN(handlersCounter[address]++)) {
+ handlersCounter[address] = 1;
+ addedTopics[address] = true;
+ }
+ },
+
+ decreaseSubscriptionCounters: function(address) {
+ if (--handlersCounter[address] == 0) {
+ delete handlersCounter[address];
+ removedTopics[address] = true;
+ }
+ },
+
+ setPushUrl: function(argPushUrl) {
+ if (argPushUrl.charAt(0) == '/') {
+ pushUrl = location.protocol + '//' + location.host + argPushUrl;
+ } else {
+ pushUrl = argPushUrl;
+ }
+ },
+
+ updateConnection: function() {
+ if (_$.isEmptyObject(handlersCounter)) {
+ disconnect();
+ } else if (!_$.isEmptyObject(addedTopics) || !_$.isEmptyObject(removedTopics)) {
+ disconnect();
+ connect();
+ }
+
+ addedTopics = {};
+ removedTopics = {};
+ }
+ };
+
+ }());
+
+ _$(document).ready(richfaces.Push.updateConnection);
+
+ var ajaxEventHandler = function(event) {
+ if (event.type == 'event') {
+ if (event.status != 'success') {
+ return;
+ }
+ } else if (event.type != 'error') {
+ return;
+ }
+
+ richfaces.Push.updateConnection();
+ };
+
+ jsf.ajax.addOnEvent(ajaxEventHandler);
+ jsf.ajax.addOnError(ajaxEventHandler);
+
+ richfaces.ui = richfaces.ui || {};
+
+ richfaces.ui.Push = richfaces.BaseComponent.extendClass({
+
+ name: COMPONENT_NAME,
+
+ init: function (id, options) {
+ this.id = id;
+ this.attachToDom();
+
+ this.__address = options.address;
+ this.__handlers = {};
+
+ if (options.ondataavailable) {
+ //TODO check compatibility with f:ajax
+ this.__bindDataHandler(options.ondataavailable);
+ }
+
+ if (options.onerror) {
+ //TODO check compatibility with f:ajax
+ this.__bindErrorHandler(options.onerror);
+ }
+
+ richfaces.Push.increaseSubscriptionCounters(this.__address);
+ },
+
+ __bindDataHandler: function(handlerCode) {
+ var ns = getDataEventNamespace(this.__address)
+ this.__handlers.data = richfaces.Event.bind(document, ns, new
Function("event", handlerCode));
+ },
+
+ __unbindDataHandler: function() {
+ if (this.__handlers.data) {
+ var ns = getDataEventNamespace(this.__address);
+ richfaces.Event.unbind(document, ns, this.__handlers.data);
+
+ this.__handlers.data = null;
+ }
+ },
+
+ __bindErrorHandler: function(handlerCode) {
+ var ns = getErrorEventNamespace(this.__address);
+ this.__handlers.error = richfaces.Event.bind(document, ns, new
Function("event", handlerCode));
+ },
+
+ __unbindErrorHandler: function() {
+ if (this.__handlers.error) {
+ var ns = getErrorEventNamespace(this.__address);
+ richfaces.Event.unbind(document, ns, this.__handlers.error);
+
+ this.__handlers.error = null;
+ }
+ },
+
+ destroy: function() {
+ this.__unbindDataHandler();
+ this.__unbindErrorHandler();
+
+ richfaces.Push.decreaseSubscriptionCounters(this.__address);
+ }
+ });
+
+}(jsf, window.RichFaces, jQuery));
\ No newline at end of file
Added: trunk/ui/core/ui/src/main/templates/org/ajax4jsf/renderkit/html/push.template.xml
===================================================================
--- trunk/ui/core/ui/src/main/templates/org/ajax4jsf/renderkit/html/push.template.xml
(rev 0)
+++
trunk/ui/core/ui/src/main/templates/org/ajax4jsf/renderkit/html/push.template.xml 2010-11-02
02:44:05 UTC (rev 19881)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<cdk:root
xmlns="http://jboss.org/schema/richfaces/cdk/xhtml-el"
xmlns:cdk="http://jboss.org/schema/richfaces/cdk/core"
+
xmlns:c="http://jboss.org/schema/richfaces/cdk/jstl/core"
xmlns:cc="http://jboss.org/schema/richfaces/cdk/jsf/composite"
+
xmlns:javaee="http://java.sun.com/xml/ns/javaee">
+
+ <cc:interface>
+ <cdk:class>org.richfaces.renderkit.html.PushRenderer</cdk:class>
+
<cdk:superclass>org.richfaces.renderkit.PushRendererBase</cdk:superclass>
+ <cdk:component-family>org.richfaces.Push</cdk:component-family>
+ <cdk:renderer-type>org.richfaces.PushRenderer</cdk:renderer-type>
+ <cdk:renders-children>true</cdk:renders-children>
+
+ <cdk:resource-dependency library="javax.faces"
name="jsf.js" />
+ <cdk:resource-dependency name="jquery.js" />
+ <cdk:resource-dependency name="richfaces.js" />
+ <cdk:resource-dependency name="richfaces-event.js" />
+ <cdk:resource-dependency name="richfaces-base-component.js" />
+ <cdk:resource-dependency library="net.java.dev.atmosphere"
name="jquery-atmosphere.js" />
+ <cdk:resource-dependency library="org.richfaces"
name="push.js" />
+ </cc:interface>
+
+ <cc:implementation>
+ <span id="#{clientId}">
+ <script type="text/javascript">
+ <c:if test="#{shouldEncodePushUrl(facesContext)}">
+ RichFaces.Push.setPushUrl("#{getPushUrl(facesContext)}");
+ </c:if>
+
+ <cdk:scriptObject name="options">
+ <cdk:scriptOption attributes="address ondataavailable
onerror" />
+ </cdk:scriptObject>
+
+ new RichFaces.ui.Push(#{toScriptArgs(clientId, options)});
+ </script>
+ </span>
+ </cc:implementation>
+
+</cdk:root>