How to run WebSockets with Spark Framework via Tomcat? - java

I've taken an Example from https://sparktutorials.github.io/2015/11/08/spark-websocket-chat.html and want to deploy it as war to Tomcat to run it on web server. I've found several examples with basic request (like get, for Ex.) but such way doesn't work with web sockets.
public class Chat implements SparkApplication{
static Map<Session, String> userUsernameMap = new HashMap<>();
static int nextUserNumber = 1; //Used for creating the next username
public static void main(String[] args) {
new Chat().init();
}
//Sends a message from one user to all users, along with a list of current usernames
public static void broadcastMessage(String sender, String message) {
userUsernameMap.keySet().stream().filter(Session::isOpen).forEach(session -> {
try {
session.getRemote().sendString(String.valueOf(new JSONObject()
.put("userMessage", createHtmlMessageFromSender(sender, message))
.put("userlist", userUsernameMap.values())
));
} catch (Exception e) {
e.printStackTrace();
}
});
}
//Builds a HTML element with a sender-name, a message, and a timestamp,
private static String createHtmlMessageFromSender(String sender, String message) {
return article().with(
b(sender + " says:"),
p(message),
span().withClass("timestamp").withText(new SimpleDateFormat("HH:mm:ss").format(new Date()))
).render();
}
#Override
public void init() {
String route = "/chat";
webSocket(route, ChatWebSocketHandler.class);
}
}
When I run it I get
org.apache.catalina.core.StandardContext.filterStart Exception starting filter SparkFilter
java.lang.IllegalStateException: WebSockets are only supported in the embedded server
at line webSocket(route, ChatWebSocketHandler.class); in void init() method.
If smth depends on my web.xml (i've not changed it), the list is here:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
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-app_2_5.xsd">
<display-name>Messenger</display-name>
<filter>
<filter-name>SparkFilter</filter-name>
<filter-class>spark.servlet.SparkFilter</filter-class>
<init-param>
<param-name>applicationClass</param-name>
<param-value>com.barbarian.messenger.Chat</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SparkFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
If I put new SparkFilter(); before that line (just tried) I got
org.apache.catalina.core.StandardContext.filterStart Exception starting filter SparkFilter
java.lang.IllegalStateException: WebSockets are only supported in the embedded server
at the same line.
Does anybody have ideas of valid running it?

Based on the documentation (at least the current one):
WebSockets only works with the embedded Jetty server, and must be defined before regular HTTP routes......
http://sparkjava.com/documentation.html#websockets
Which is why you do not see any servlet config in web.xml in the sample code (https://github.com/tipsy/spark-websocket) since the embedded Jetty container can be run directly in the main method. Also it uses the org.eclipse.jetty.websocket.api.* package for websocket implementation.
If you need websocket to be run on Tomcat, you might want to consider using WebSocketServlet implementation in catalina package. I've found sample codes here (even though I haven't tested it yet): https://gist.github.com/chitan/3063774. Hope this helps.

Related

Reading System Properties in Web.XML

in order to access global values stored in the file src/resources/settings.properties from web.xml on a JBoss EAP 7 Server, I implemented the following class from a similar Stack Overflow topic:
public class ConfigurationWebFilter implements ServletContextListener {
protected static final Properties properties = new Properties();
#Override
public void contextInitialized(final ServletContextEvent event){
try {
try (InputStream stream = new FileInputStream("/settings.properties")) {
properties.load(stream);
}
for (String prop : properties.stringPropertyNames())
{
if (System.getProperty(prop) == null)
{
System.setProperty(prop, properties.getProperty(prop));
}
}
} catch (IOException ex) {
logger.error("Failed loading settings from configuration file for web.xml", ex);
}
}
}
Then I added the according listener to web.xml:
<listener>
<listener-class>
com.product.util.ConfigurationWebFilter
</listener-class>
</listener>
The code gets called properly and I can verify by debugging that the system variables get set correctly. However, the properties of my web.xml do not seem to be replaced/interpreted. The following parameter does still evaluate to ${serverName}, even after restarting the server and/or republishing:
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>(...)</filter-class>
<init-param>
<param-name>serverName</param-name>
<param-value>${serverName}</param-value>
</init-param>
</filter>
All the other topics on this issue were of no use because no solution worked for me. How can I replace web.xml parameters by values stored in a properties file?
Works now, I had to set a parameter related to the replacement of variables to true (was false) in the Wildfly standalone.xml.

Exception on library in Tomcat Apache web application no TLDs found

I just started learning Apache Tomcat and I just even recently Installed it, Am trying to run a particular Java program/class that waits/listens for data from a php post request and below is the code. I call this class Listener.java
package matchfaces;
public class Listener {
public static final String JAVABRIDGE_PORT = "1699";//8080
static final php.java.bridge.JavaBridgeRunner runner =
php.java.bridge.JavaBridgeRunner.getInstance(JAVABRIDGE_PORT);
public static void main() {
// TODO code application logic here
try {
System.loadLibrary("facesdk");
int res = FSDK
.ActivateLibrary("LICENCE KEY");
FSDK.Initialize();
FSDK.SetFaceDetectionParameters(true, true, 384);
FSDK.SetFaceDetectionThreshold(5);
if (res == FSDK.FSDKE_OK) {
System.out.println("FaceSDK activated\n");
} else {
System.out.println("Error activating FaceSDK: " + res + "\n");
}
} catch (java.lang.UnsatisfiedLinkError e) {
System.out.println("exception " + e.getMessage());
}
runner.waitFor();
}
}
After much research I tried a couple of things but now, it seems the libraries I need are not being load and thus throwing an exception. My web.xml is as follows
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 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-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Match Faces</servlet-name>
<servlet-class>matchfaces.Listener</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Match Faces</servlet-name>
<url-pattern>/matchfaces</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<listener>
<listener-class>ViewHandler.handler</listener-class>
</listener>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
So I used a listener so On Tomcat start server it would fire the web application java class Listener.java
public class handler implements javax.servlet.ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
Listener listen = new Listener();
listen.main();
} catch (InterruptedException ex) {
Logger.getLogger(Listener.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
The error I get is this
exception no facesdk in java.library.path
The major problem you are having is fron the System.loadLibrary("facesdk"); It seems you have not provided a path to the facesdk.dll library. But rather than state the path in the loadLibrary method just head to your catalina.bat file and right under :noJuliManager
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER% add this set JAVA_OPTS="-Djava.library.path=%CATALINA_BASE%\lib"
This should work just fine.

Objectify - scavenging sessions

My original HttpSessionListener code:
public class SessionListener implements HttpSessionListener {
#Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user insteaceof User) {
UserUtils.deleteUser((User) user);
}
}
}
and my web.xml
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
When a session timeout event happens it throws:
WARNING: Problem scavenging sessions
java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
at com.learnkeeper.server.OfyService.ofy(OfyService.java:61)
at com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28)
at com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:36)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:926)
at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285)
at org.mortbay.jetty.servlet.HashSessionManager.access$000(HashSessionManager.java:44)
at org.mortbay.jetty.servlet.HashSessionManager$2.run(HashSessionManager.java:219)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
I tried that (from this post How to resolve "You have not started an Objectify context" in JUnit?):
public class SessionListener implements HttpSessionListener {
private Closeable closeable;
#Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user instanceof User) {
closeable = OfyService.begin();
UserUtils.deleteUser((User) user);
closeable.close();
}
}
}
And here is my OfyService class:
class OfyService {
static {
// Register all my Entities classes
ObjectifyService.register(User.class);
...
}
public static Closeable begin() {
return ObjectifyService.begin();
}
public static ObjectifyFactory factory() {
return ObjectifyService.factory();
}
public static Objectify ofy() {
return ObjectifyService.ofy();
}
}
but same stacktrace :(
So what did I miss?
thx
EDIT
to follow-up with #stickfigure
So I cleaned my project and re-run my use case and I get this stacktrace now:
WARNING: Problem scavenging sessions
java.lang.NullPointerException: No API environment is registered for this thread.
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:132)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:148)
at com.google.appengine.api.datastore.Key.(Key.java:96)
at com.google.appengine.api.datastore.Key.(Key.java:78)
at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:54)
at com.google.appengine.api.datastore.KeyFactory.createKey(KeyFactory.java:47)
at com.googlecode.objectify.util.DatastoreUtils.createKey(DatastoreUtils.java:86)
at com.googlecode.objectify.impl.KeyMetadata.getRawKey(KeyMetadata.java:187)
at com.googlecode.objectify.impl.Keys.rawKeyOf(Keys.java:36)
at com.googlecode.objectify.impl.Keys.keyOf(Keys.java:29)
at com.googlecode.objectify.impl.LoaderImpl.entity(LoaderImpl.java:121)
at com.learnkeeper.server.UserUtils.deleteUser(UserUtils.java:28)
at com.learnkeeper.server.SessionListener.sessionDestroyed(SessionListener.java:40)
at org.mortbay.jetty.servlet.AbstractSessionManager.removeSession(AbstractSessionManager.java:669)
at org.mortbay.jetty.servlet.AbstractSessionManager$Session.timeout(AbstractSessionManager.java:926)
at org.mortbay.jetty.servlet.HashSessionManager.scavenge(HashSessionManager.java:285)
at org.mortbay.jetty.servlet.HashSessionManager.access$000(HashSessionManager.java:44)
at org.mortbay.jetty.servlet.HashSessionManager$2.run(HashSessionManager.java:219)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
I don't see any reason why that code should fail, although it can be written more elegantly:
public class SessionListener implements HttpSessionListener {
#Override
public void sessionDestroyed(HttpSessionEvent event) {
final Object user = event.getSession().getAttribute("user");
if (user != null && user instanceof User) {
try (Closable closable = OfyService.begin()) {
UserUtils.deleteUser((User) user);
}
}
}
I have many variations of this code in my applications and there are examples in the test cases - actually, all of Objectify's test cases rely on this pattern.
I would like to see the exact stacktrace generated when you run this code. It should be quite impossible to get that stacktrace if you have called begin() properly. You can look at the code in ObjectifyService.ofy() - it is quite simple. Doublecheck that the code you have deployed is the code you think you have deployed.
UPDATE: The new stacktrace is quite different, and indicates that GAE is not set up to perform API calls from that listener callback. It has nothing to do with Objectify; this is now a question for Google. I suggest writing a new question that focuses on that aspect and tagging it with GAE-related tags.
That said, my general advice is to avoid relying on this callback. Aside from technical issues like this, I would not trust it to be executed consistently in a distributed environment like GAE. If you want to expire an object, put a datestamp on it and cull anything older than a week (or whatever is reasonable).
Google App Engine Doesn't support session listeners. Session listeners may get invoke in local, but No API environment is registered for this thread. In production listeners will not even invoke.
Source #Ramesh V
https://stackoverflow.com/a/11152125/421563
Anyway thx #stickfigure

Prevent suffix from being added to resources when page loads

I have a JSF2 application running and working no problem. The issue I am having with JSF is with the resource bundle. All resources have the .xhtml suffix appended to it. So main.css becomes main.css.xhtml when loaded in the browser. I would like to have it so the .xhtml isn't apended to the resources (don't mind about the pages themselves).
Is there a way where we can NOT have .xhtml appended to resources?
I would ideally not have to change the internal workings of the site. I have listed ideas below, but I have to say I don't really like these. Hoping for a solution somewhere?
I am using Majorra v.2.1.17 on Glassfish 3.1.2.2.
Current Faces Servlet loading as in web.xml (updated)
<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>*.xhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
Why this questions is different from others
JSF 2 resources with CDN?. I am not looking to place my resources on a CDN, but to have my resources stay on my server but are pushed towards a CDN.
Change /javax.faces.resource prefix of resource URLs. I don't want to change the prefix. I want only to change the suffix. I would want <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css.xhtml?ln=styles"> to become : <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css?ln=styles"> WITHOUT the .xhtml extension.
Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images. Since I have no issue with loading the resources. The site works, we are simply having a hard time differrentiating a webpage from a resource (Since we are looking at the extention alone).
Reasoning
Sure you might be asking me why I need this. Well, we are moving our application to be served by the Akamai CDN.
The issue we are having with the integration of the site is that we are trying to cache static content on the edge servers. This is done by matching file extensions (ie: .js, .doc, .png, css, etc). We cannot match xhtml because this would be caching all pages as well as static content. Which by that would cause problems with sessions and such.
Attempted Solution
In line with the answer by BalusC, I have implemented the resource handler as suggested. I will not rewrite code here, since it is in answer below.
However, I am getting an error when loading composite components. I am getting an error as such :
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at com.sun.faces.application.ApplicationImpl.createComponent(ApplicationImpl.java:975)
at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.createComponent(CompositeComponentTagHandler.java:162)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.createComponent(ComponentTagHandlerDelegateImpl.java:494)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:169)
...
Composite component is loaded correctly because if I "unregister" the new ResourceHandler we just created it will load. The stack trace leads me to believe that it is trying to find this component in a java class, instead of finding it in the resources. According to grepcode this would be at this last line (975) where the error happens :
String packageName = componentResource.getLibraryName();
String className = componentResource.getResourceName();
className = packageName + '.' + className.substring(0, className.lastIndexOf('.'));
Meaning that the resourceName, aka className is null since the error I am getting is java.lang.NullPointerException. I can't seem to figure out how/where the ResourceHandler is called vis-a-vis a composite component. Any help figuring out this last issue?
This is doable with a custom ResourceHandler which returns in createResource() a Resource which in turn returns an "unmapped" URL on Resource#getRequestPath(). You only need to add the default JSF resource prefix /javax.faces.resource/* to the <url-pattern> list of the FacesServlet mapping in order to get it to be triggered anyway.
Further, you need to override isResourceRequest() to check if the URL starts with the JSF resource prefix and also the handleResourceRequest() to locate and stream the proper resource.
All with all, this should do:
public class UnmappedResourceHandler extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
public UnmappedResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public Resource createResource(final String resourceName, final String libraryName) {
final Resource resource = super.createResource(resourceName, libraryName);
if (resource == null) {
return null;
}
return new ResourceWrapper() {
#Override
public String getRequestPath() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String mapping = externalContext.getRequestServletPath();
if (externalContext.getRequestPathInfo() == null) {
mapping = mapping.substring(mapping.lastIndexOf('.'));
}
String path = super.getRequestPath();
if (mapping.charAt(0) == '/') {
return path.replaceFirst(mapping, "");
}
else if (path.contains("?")) {
return path.replace(mapping + "?", "?");
}
else {
return path.substring(0, path.length() - mapping.length());
}
}
#Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
public String getResourceName() {
return resource.getResourceName();
}
#Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
public String getLibraryName() {
return resource.getLibraryName();
}
#Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
public String getContentType() {
return resource.getContentType();
}
#Override
public Resource getWrapped() {
return resource;
}
};
}
#Override
public boolean isResourceRequest(FacesContext context) {
return ResourceHandler.RESOURCE_IDENTIFIER.equals(context.getExternalContext().getRequestServletPath());
}
#Override
public void handleResourceRequest(FacesContext context) throws IOException {
ExternalContext externalContext = context.getExternalContext();
String resourceName = externalContext.getRequestPathInfo();
String libraryName = externalContext.getRequestParameterMap().get("ln");
Resource resource = context.getApplication().getResourceHandler().createResource(resourceName, libraryName);
if (resource == null) {
super.handleResourceRequest(context);
return;
}
if (!resource.userAgentNeedsUpdate(context)) {
externalContext.setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
externalContext.setResponseContentType(resource.getContentType());
for (Entry<String, String> header : resource.getResponseHeaders().entrySet()) {
externalContext.setResponseHeader(header.getKey(), header.getValue());
}
ReadableByteChannel input = null;
WritableByteChannel output = null;
try {
input = Channels.newChannel(resource.getInputStream());
output = Channels.newChannel(externalContext.getResponseOutputStream());
for (ByteBuffer buffer = ByteBuffer.allocateDirect(10240); input.read(buffer) != -1; buffer.clear()) {
output.write((ByteBuffer) buffer.flip());
}
}
finally {
if (output != null) try { output.close(); } catch (IOException ignore) {}
if (input != null) try { input.close(); } catch (IOException ignore) {}
}
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
Register it as follows in faces-config.xml:
<application>
<resource-handler>com.example.UnmappedResourceHandler</resource-handler>
</application>
Extend the FacesServlet URL pattern with ResourceHandler.RESOURCE_IDENTIFIER:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
You could have a look at Rewrite. Rewrite allows to modify URLs that are rendered to the page and modify them in any way you want. You could do something like this to add a CDN To your site:
.addRule(CDN.relocate("{p}foo-{version}.css")
.where("p").matches(".*")
.where("version").matches(".*")
.to("http://mycdn.com/foo-{version}.css"));
I think it should be easy to implement your requirement using Rewrite.
Have a look at the example configurations to learn about the features of rewrite.

IncompatibleRemoteServiceException while using RPC in GWT

I have web application Project having RPC call.
one RPC async is working fine. but Another gives a error
Mar 21, 2012 1:34:51 PM com.google.appengine.tools.development.ApiProxyLocalImpl log
SEVERE: javax.servlet.ServletContext log: ObjectStore: An IncompatibleRemoteServiceException was thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: This application is out of date, please click the refresh button on your browser. ( Blocked attempt to access interface 'com.client.RepositoryInterface', which is not implemented by 'com.server.ObjectStore'; this is either misconfiguration or a hack attempt )
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:252)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:206)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
Working RPC
public interface ConnectionInterface extends RemoteService{
String connection(String[] authentication);
}
public interface ConnectionInterfaceAsync {
void connection(String[] authentication, AsyncCallback<String> callback);
}
public class ConnectionService implements ConnectionInterfaceAsync {
ConnectionInterfaceAsync service = (ConnectionInterfaceAsync)GWT.create(ConnectionInterface.class);
ServiceDefTarget endpoint = (ServiceDefTarget) service;
public ConnectionService() {
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "rpc");
}
public void connectionCMIS(String[] authentication,
AsyncCallback<String> callbackConnection) {
service.connectionCMIS(authentication, callbackConnection);
}
// client Call
public class Login extends Composite {
private ConnectionService connectionService = new ConnectionService();
// more code
public void onClick(ClickEvent event) {
AsyncCallback<String> callbackConnection = new AsyncCallback<String>() {
public void onSuccess(String result) {
// print Succuss
}
}
connectionService.connection(authentication, callbackConnection );
}
}
}
Not Workink RPC
public interface RepositoryInterface extends RemoteService {
public FolderCollection getRepositories();
}
public interface RepositoryInterfaceAsync {
void getRepositories(AsyncCallback<FolderCollection> repositoryCallback);
}
public class RepositoryService implements RepositoryInterfaceAsync{
RepositoryInterfaceAsync async = (RepositoryInterfaceAsync)GWT.create(RepositoryInterface.class);
ServiceDefTarget endpoint = (ServiceDefTarget) async;
public CmisRepositoryService() {
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "repository");
}
public void getRepositories(
AsyncCallback<FolderCollection> repositoryCallback) {
async.getRepositories(repositoryCallback);
}
}
client call
public class Workplace {
private RepositoryService service = new RepositoryService();
// some more code
void doRepo(){
AsyncCallback<FolderCollection> repositoryCallback = new AsyncCallback<FolderCollection>() {
public void onSuccess(FolderCollection result) {
}
public void onFailure(Throwable caught) {
}
};
service.getRepositories(repositoryCallback);
}
}
XML Code
<servlet>
<servlet-name>ConnectionServlet</servlet-name>
<servlet-class>com.server.ConnectionServiceImpl</servlet-class>
</servlet>
<servlet>
<servlet-name>ObjectStore</servlet-name>
<servlet-class>com.server.ObjectStore</servlet-class>
<servlet-mapping>
<servlet-name>ConnectionServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ObjectStore</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Both RPC is designed in similar patter still it gives me an error.
If any one can tell me why will be of great Help
thanks.
Your URL-mapping is off, you need to map your RPC RemoteServiceServlets to a better url-pattern. You map both servlets to /*. There is no guarantee which Servlet is executed when two or more a mapped to the exact same url-pattern. So my guess is, everytime you execute your not working service, the call is mapped to the other service.
A way to work this out would be to use a web.xml like
<servlet-mapping>
<servlet-name>ConnectionServlet</servlet-name>
<url-pattern>/ConnectionService.rpc</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ObjectStore</servlet-name>
<url-pattern>/ObjectStoreService.rpc</url-pattern>
</servlet-mapping>
Of course you also have to change your client-side services to use the correct serviceEntryPoint , so
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "rpc");
would have to change to something like
endpoint.setServiceEntryPoint(GWT.getHostPageBaseURL() + "ConnectionService.rpc");
to get to the right servlet.
EDIT: Error of change:
ERROR
#ftr `com.google.appengine.tools.development.ApiProxyLocalImpl log
SEVERE: javax.servlet.ServletContext log: ConnectionServlet: An IncompatibleRemoteServiceException was thrown while processing this call.
com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException: This application is out of date, please click the refresh button on your browser. ( Blocked attempt to access interface 'com.client.RepositoryInterface', which is not implemented by 'com.server.ConnectionServiceImpl'; this is either misconfiguration or a hack attempt )
at com.google.gwt.user.server.rpc.RPC.decodeRequest(RPC.java:252)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:206)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
So if you look closely, the error is different:
Blocked attempt to access interface 'com.client.RepositoryInterface', which is not implemented by 'com.server.ConnectionServiceImplObjectStore'
instead of
Blocked attempt to access interface 'com.client.RepositoryInterface', which is not implemented by 'com.server.ObjectStore'
This means your configuration is still wrong, you have to point your client-side RepositoryInterfaceAsync to a RemoteServiceServlet that implements RepositoryInterface.
It might be misconfiguration of gwt-servlet.jar version on your web-container.Check your development gwt-servlet.jar version and web container gwt-servlet.jar version. n For reference
Misconfiguration or hack attempt

Categories

Resources