On my web host, I can enter the room, but no message is ever sent (I type and press enter, but the message doesn't appear on the screen) If someone else enters the room, I cannot see they coming online either.
I have tried many, many different things, so I reverted back to the most simple setup that works on my localhost, but not online.
Main Setup
- Tomcat 8.0.26
JSF 2.2.8
PrimeFaces 5.2
atmosphere-runtime-2.3.1
sl4j-api-1.7.5
commons-logging-1.1.3
javax.inject-1
JDK 1.7
- spark-theme-1.3
commons-fileuplod-1.3
gson-2-2.4
json-simple-1.1.1
javabase64-1.3.1
jdom-2.0.6
httpclient-4.5
httpcore-4.4.1
Services-3.0
pdfbox-app-1.8.10
itextpdf-5.1.0
java-json
java-mail-1.4.4
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<context-param>
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>spark-blue</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/primefaces-spark.taglib.xml</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>production</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>
<servlet-name>Push Servlet</servlet-name>
<servlet-class>org.primefaces.push.PushServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Push Servlet</servlet-name>
<url-pattern>/primepush/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<mime-mapping>
<extension>ttf</extension>
<mime-type>application/font-sfnt</mime-type>
</mime-mapping>
<mime-mapping>
<extension>woff</extension>
<mime-type>application/font-woff</mime-type>
</mime-mapping>
<mime-mapping>
<extension>woff2</extension>
<mime-type>application/font-woff2</mime-type>
</mime-mapping>
<mime-mapping>
<extension>eot</extension>
<mime-type>application/vnd.ms-fontobject</mime-type>
</mime-mapping>
<mime-mapping>
<extension>eot?#iefix</extension>
<mime-type>application/vnd.ms-fontobject</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exosemibold</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exobolditalic</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exomedium</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exoregular</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#fontawesomeregular</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>ttf</extension>
<mime-type>application/font-sfnt</mime-type>
</mime-mapping>
<mime-mapping>
<extension>woff</extension>
<mime-type>application/font-woff</mime-type>
</mime-mapping>
<mime-mapping>
<extension>woff2</extension>
<mime-type>application/font-woff2</mime-type>
</mime-mapping>
<mime-mapping>
<extension>eot</extension>
<mime-type>application/vnd.ms-fontobject</mime-type>
</mime-mapping>
<mime-mapping>
<extension>eot?#iefix</extension>
<mime-type>application/vnd.ms-fontobject</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exosemibold</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exobolditalic</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exomedium</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#exoregular</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>svg#fontawesomeregular</extension>
<mime-type>image/svg+xml</mime-type>
</mime-mapping>
<error-page>
<error-code>404</error-code>
<location>/pages/account/404.xhtml</location>
</error-page>
</web-app>
Code: Select all
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/template.xhtml"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<ui:define name="head"> </ui:define>
<ui:define name="content">
<p:growl id="growl" showDetail="true" />
<h:form id="form">
<p:remoteCommand name="updateList" update="users" process="@this" />
<p:fieldset id="container" legend="PrimeChat" toggleable="true">
<h:panelGroup rendered="#{chatView.loggedIn}">
<h:panelGrid columns="2" columnClasses="publicColumn,usersColumn" style="width:100%">
<p:outputPanel id="public" layout="block" styleClass="ui-corner-all ui-widget-content chatlogs" />
<p:dataList id="users" var="user" value="#{chatUsers.users}" styleClass="usersList">
<f:facet name="header">
Users
</f:facet>
<p:commandButton title="Chat" icon="ui-icon-comment" oncomplete="PF('pChat').show()" update=":form:privateChatContainer">
<f:setPropertyActionListener value="#{user}" target="#{chatView.privateUser}" />
</p:commandButton>
#{user}
</p:dataList>
</h:panelGrid>
<p:separator />
<p:inputText value="#{chatView.globalMessage}" styleClass="messageInput" />
<p:spacer width="5" />
<p:commandButton value="Send" actionListener="#{chatView.sendGlobal}" oncomplete="$('.messageInput').val('').focus()" />
<p:spacer width="5" />
<p:commandButton value="Disconnect" actionListener="#{chatView.disconnect}" global="false" update="container" />
</h:panelGroup>
<h:panelGroup rendered="#{not chatView.loggedIn}" >
Username: <p:inputText value="#{chatView.username}" />
<p:spacer width="5" />
<p:commandButton value="Login" actionListener="#{chatView.login}" update="container"
icon="ui-icon-person" />
</h:panelGroup>
</p:fieldset>
<p:dialog widgetVar="pChat" header="Private Chat" modal="true" showEffect="fade" hideEffect="fade">
<h:panelGrid id="privateChatContainer" columns="2" columnClasses="vtop,vtop">
<p:outputLabel for="pChatInput" value="To: #{chatView.privateUser}" />
<p:inputTextarea id="pChatInput" value="#{chatView.privateMessage}" rows="5" cols="30" />
<p:spacer />
<p:commandButton value="Send" actionListener="#{chatView.sendPrivate}" oncomplete="PF('pChat').hide()" />
</h:panelGrid>
</p:dialog>
</h:form>
<p:socket onMessage="handleMessage" channel="/{room}" autoConnect="false" widgetVar='subscriber' />
<script type="text/javascript">
function handleMessage(message) {
var chatContent = $(PrimeFaces.escapeClientId('form:public')),
text = (message.user) ? message.user + ':' + message.text : message.text;
chatContent.append(text + '<br />');
//keep scroll
chatContent.scrollTop(chatContent.height());
if (message.updateList) {
updateList();
}
}
</script>
</ui:define>
</ui:composition>
Code: Select all
package chat;
import com.leah.util.Log;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import org.primefaces.push.EventBus;
import org.primefaces.push.RemoteEndpoint;
import org.primefaces.push.annotation.OnClose;
import org.primefaces.push.annotation.OnMessage;
import org.primefaces.push.annotation.OnOpen;
import org.primefaces.push.annotation.PathParam;
import org.primefaces.push.annotation.PushEndpoint;
import org.primefaces.push.annotation.Singleton;
@PushEndpoint("/{room}/{user}")
@Singleton
public class ChatResource {
private static Log log = new Log(ChatResource.class, "chat");
@PathParam("room")
private String room;
@PathParam("user")
private String username;
@Inject
private ServletContext ctx;
@OnOpen
public void onOpen(RemoteEndpoint r, EventBus eventBus) {
log.info("OnOpen {}", r);
eventBus.publish(room + "/*", new Message(String.format("%s entrou na sala '%s'", username, room), true));
}
@OnClose
public void onClose(RemoteEndpoint r, EventBus eventBus) {
log.info("Close {}", r);
ChatUsers users= (ChatUsers) ctx.getAttribute("chatUsers");
users.remove(username);
eventBus.publish(room + "/*", new Message(String.format("%s saiu da sala", username), true));
}
@OnMessage(decoders = {MessageDecoder.class}, encoders = {MessageEncoder.class})
public Message onMessage(Message message) {
return message;
}
}
Code: Select all
package chat;
import com.leah.util.Log;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@ApplicationScoped
public class ChatUsers implements Serializable {
private List<String> users;
private static Log log = new Log(ChatUsers.class, "chat");
@PostConstruct
public void init() {
users = new ArrayList<String>();
log.info("init()");
}
public List<String> getUsers() {
return users;
}
public void remove(String user) {
this.users.remove(user);
}
public void add(String user) {
this.users.add(user);
}
public boolean contains(String user) {
return this.users.contains(user);
}
}
Code: Select all
package chat;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import org.primefaces.context.RequestContext;
import org.primefaces.push.EventBus;
import org.primefaces.push.EventBusFactory;
@ManagedBean
@ViewScoped
public class ChatView implements Serializable {
//private final PushContext pushContext = PushContextFactory.getDefault().getPushContext();
private final EventBus eventBus = EventBusFactory.getDefault().eventBus();
@ManagedProperty("#{chatUsers}")
private ChatUsers users;
private String privateMessage;
private String globalMessage;
private String username;
private boolean loggedIn;
private String privateUser;
private final static String CHANNEL = "/{room}/";
public ChatUsers getUsers() {
return users;
}
public void setUsers(ChatUsers users) {
this.users = users;
}
public String getPrivateUser() {
return privateUser;
}
public void setPrivateUser(String privateUser) {
this.privateUser = privateUser;
}
public String getGlobalMessage() {
return globalMessage;
}
public void setGlobalMessage(String globalMessage) {
this.globalMessage = globalMessage;
}
public String getPrivateMessage() {
return privateMessage;
}
public void setPrivateMessage(String privateMessage) {
this.privateMessage = privateMessage;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public boolean isLoggedIn() {
return loggedIn;
}
public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}
public void sendGlobal() {
eventBus.publish(CHANNEL + "*", username + ": " + globalMessage);
globalMessage = null;
}
public void sendPrivate() {
eventBus.publish(CHANNEL + privateUser, "[PM] " + username + ": " + privateMessage);
privateMessage = null;
}
public void login() {
RequestContext requestContext = RequestContext.getCurrentInstance();
if(users.contains(username)) {
loggedIn = false;
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Username taken", "Try with another username."));
requestContext.update("growl");
}
else {
users.add(username);
requestContext.execute("PF('subscriber').connect('/" + username + "')");
loggedIn = true;
}
}
public void disconnect() {
//remove user and update ui
users.remove(username);
RequestContext.getCurrentInstance().update("form:users");
//push leave information
eventBus.publish(CHANNEL + "*", username + " left the channel.");
//reset state
loggedIn = false;
username = null;
}
}
Code: Select all
package chat;
import com.leah.util.Log;
public class Message {
private String text;
private String user;
private boolean updateList;
private static Log log = new Log(Message.class, "chat");
public Message() {
}
public Message(String text) {
log.info("new message");
this.text = text;
}
public Message(String text, boolean updateList) {
this.text = text;
this.updateList = updateList;
}
public Message(String user, String text, boolean updateList) {
this.text = text;
this.user = user;
this.updateList = updateList;
}
public String getText() {
return text;
}
public Message setText(String text) {
this.text = text;
return this;
}
public String getUser() {
return user;
}
public Message setUser(String user) {
this.user = user;
return this;
}
public boolean isUpdateList() {
return updateList;
}
public void setUpdateList(boolean updateList) {
this.updateList = updateList;
}
}
Code: Select all
package chat;
import org.primefaces.push.Decoder;
/**
* A Simple {@link org.primefaces.push.Decoder} that decode a String into a {@link Message} object.
*/
public class MessageDecoder implements Decoder<String,Message> {
//@Override
public Message decode(String s) {
String[] userAndMessage = s.split(":");
if (userAndMessage.length >= 2) {
return new Message().setUser(userAndMessage[0]).setText(userAndMessage[1]);
}
else {
return new Message(s);
}
}
}
Code: Select all
package chat;
import org.primefaces.json.JSONObject;
import org.primefaces.push.Encoder;
/**
* A Simple {@link org.primefaces.push.Encoder} that decode a {@link Message} into a simple JSON object.
*/
public final class MessageEncoder implements Encoder<Message, String> {
//@Override
public String encode(Message message) {
return new JSONObject(message).toString();
}
}
I can connect to it via http://localhost:8084/pages/efpc/chat.xhtml.
If I try to connect to it by adding primepush to the address (http://localhost:8084/primepush/pages/efpc/chat.xhtml) I get the following error:
Code: Select all
XML Parsing Error: no element found Location: http://localhost:8084/primepush/pages/efpc/chat.xhtml Line Number 1, Column 1:
^
I can connect to it via http://myaddress.com/pages/efpc/chat.xhtml (but no message is sent, like said earlier).
If I log in with a certain username, open a new tab and try to log in with the same username, the growl message appears telling me that username is taken.
After I log in, I have 3 requests (Firefox 43.0.a2):
Code: Select all
200 - http://myaddress.com/primepush/{room}/diogo?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.9-javascript&X-Atmosphere-Transport=long-polling&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&_=1444075051877
500 - http://myaddress.com/primepush/{room}/diogoo?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.9-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true
No Code - http://myaddress.com/primepush/{room}/diogoo?X-Atmosphere-tracking-id=5ac64ccd-b8a0-49a9-9551-eaf209a0a611&X-Atmosphere-Framework=2.2.9-javascript&X-Atmosphere-Transport=long-polling&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true&_=1444075052054
Code: Select all
NetworkError: A network error occurred. <unknown>
Websocket closed, reason: Connection was closed abnormally (that is, with no close frame being sent). push.js.xhtml:1:39484
Websocket closed, wasClean: false push.js.xhtml:1:39484
Websocket failed. Downgrading to Comet and resending push.js.xhtml:1:39484
Firefox can't establish a connection to the server at ws://myaddress.com/primepush/%7Broom%7D/diogo?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.9-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-atmo-protocol=true. push.js.xhtml:1:12442
Not sure if I should be adding primepush to it anyway.
Any help will be hugely appreciated.
Thank you.