Trouble getting unit testing of RPC on GWT - google-app-engine

I am trying to get RPC testing using GWT. I am using the default StockWatcher project that is mentioned here, I download the project, I import it, everything works fine.
I then run junitcreator in the StockWatcher project:
/Users/stephen/Work/gwt/gwt-mac-1.6.4/junitCreator -junit /Users/stephen/Applications/eclipse/plugins/org.junit_3.8.2.v20080602-1318/junit.jar -module stockwatcher -eclipse StockWatcher com.google.gwt.sample.stockwatcher.StockWatcherTest
this creates the StockWatcherTest.java in the appropriate test directory, and gives me some hosted and web mode launch files.
I then also added junit.jar to the classpath for this project.
I then modify StockWatcherTest.java to test whether I am capable of making a asynchronous request to the server. Everything looks fine, but when I try to run StockWatcherTest.java in hosted mode, I get the following error:
Starting HTTP on port 0 HTTP
listening on port 49569
The development shell servlet received a
request for 'greet' in module
'com.google.gwt.sample.stockwatcher.StockWatcher.JUnit.gwt.xml'
[WARN] Resource not found: greet;
(could a file be missing from the
public path or a tag
misconfigured in module
com.google.gwt.sample.stockwatcher.StockWatcher.JUnit.gwt.xml
?)
com.google.gwt.user.client.rpc.StatusCodeException:
Cannot find resource 'greet' in the
public path of module
'com.google.gwt.sample.stockwatcher.StockWatcher.JUnit'
Here is my StockWatcherTest.java class
package com.google.gwt.sample.stockwatcher.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.rpc.AsyncCallback;
/**
* GWT JUnit tests must extend GWTTestCase.
*/
public class StockWatcherTest extends GWTTestCase {
/**
* Must refer to a valid module that sources this class.
*/
public String getModuleName() {
return "com.google.gwt.sample.stockwatcher.StockWatcher";
}
/**
* Add as many tests as you like.
*/
public void testSimple() {
GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
greetingService.greetServer("Bob",
new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
System.out.println(caught);
fail("big time failure");
finishTest();
}
public void onSuccess(String result) {
System.out.println("success, biatch");
assertTrue(true);
}
});
delayTestFinish(1000);
}
}
Here is com/google/gwt/sample/stockwatcher/StockWatcher.gwt.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.6.2//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.6.2/distro-source/core/src/gwt-module.dtd">
<module rename-to='stockwatcher'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<!-- Inherit the default GWT style sheet. You can change -->
<!-- the theme of your GWT application by uncommenting -->
<!-- any one of the following lines. -->
<inherits name='com.google.gwt.user.theme.standard.Standard'/>
<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->
<!-- Other module inherits -->
<!-- Specify the app entry point class. -->
<entry-point class='com.google.gwt.sample.stockwatcher.client.StockWatcher'/>
</module>
and here is web.xml in my generated war
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>StockWatcher.html</welcome-file>
</welcome-file-list>
<!-- Servlets -->
<servlet>
<servlet-name>greetServlet</servlet-name>
<servlet-class>com.google.gwt.sample.stockwatcher.server.GreetingServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>greetServlet</servlet-name>
<url-pattern>/stockwatcher/greet</url-pattern>
</servlet-mapping>
</web-app>
So what am I doing wrong? Any help is appreciated. Thank you.

1-you need to add "finishTest();" at the end of the "onSuccess" method.
2-And to resolve the exeption you got : add in your StockWatcher.gwt.xml the path to your servlet greet.
servlet path='/greet' class='com.google.gwt.sample.stockwatcher.server.GreetingServiceImpl'/

Another solution is using GWT SyncProxy (support both sync & async) to test GWT RPC services in JRE
See the post at http://www.gdevelop.com/w/blog/2010/01/10/testing-gwt-rpc-services/ for details

i made some simple tests for the stock watcher. you can see them at: http://tayek.com/StockWatcher.zip

Related

Ktor App's Main Method Not Called When Deployed to AppEngine

Issue
The Ktor application's main method is not called when deployed to AppEngine. In the applications's main method is logic to retrieve content from an API request based on a Timer and save that information to a Firestore database which a client consumes.
This logic currently works when deployed in a Jar to AppEngine. However, implementing this with Ktor would save deploy time and help future proof the backend service if endpoints are required.
Expected
The Ktor application's main method is called once the app is deployed to AppEngine similar to how an application's main method is called when ran in IntelliJ.
Actual
The main method is only called once the app's hosted route is called.
ie: https://[yourProjectName].appspot.com
Setup
Main Method
import io.ktor.application.Application
fun Application.main() {
// App logic here.
}
build.gradle
buildscript {
ext.kotlin_version = '1.3.10'
ext.ktor_version = '1.0.0'
ext.appengine_version = '1.9.60'
ext.appengine_plugin_version = '1.3.4'
ext.junitJupiterVersion = '5.0.3'
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.cloud.tools:appengine-gradle-plugin:$appengine_plugin_version"
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3'
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.2.51'
}
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'war'
apply plugin: 'com.google.cloud.tools.appengine'
sourceSets {
main.kotlin.srcDirs = [ 'src/main/kotlin' ]
}
sourceCompatibility = 1.8
repositories {
jcenter()
mavenCentral()
maven { url "https://kotlin.bintray.com/ktor" }
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "io.ktor:ktor-server-servlet:$ktor_version"
implementation "io.ktor:ktor-html-builder:$ktor_version"
providedCompile "com.google.appengine:appengine:$appengine_version"
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
implementation 'com.google.firebase:firebase-admin:6.3.0'
implementation 'com.google.apis:google-api-services-youtube:v3-rev204-1.23.0'
testCompile group: 'junit', name: 'junit', version: '4.12'
// JUnit Jupiter API and TestEngine implementation
testCompile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
testCompile("org.assertj:assertj-core:3.10.0")
// To avoid compiler warnings about #API annotations in JUnit code
testCompileOnly('org.apiguardian:apiguardian-api:1.0.0')
}
kotlin.experimental.coroutines = 'enable'
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
task run(dependsOn: appengineRun)
appengine {
deploy {
version = 'media-staging-1201181257pm'
}
}
src/main/resources/application.conf
ktor {
application {
modules = [ InitializationKt.main ]
}
}
src/main/webapp/WEB-INF/
appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<threadsafe>true</threadsafe>
<runtime>java8</runtime>
</appengine-web-app>
web.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<web-app 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" version="3.0">
<servlet>
<display-name>KtorServlet</display-name>
<servlet-name>KtorServlet</servlet-name>
<servlet-class>io.ktor.server.servlet.ServletApplicationEngine</servlet-class>
<!-- path to application.conf file, required -->
<init-param>
<param-name>io.ktor.config</param-name>
<param-value>application.conf</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>KtorServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Thank you to Gabriel Machado on Kotlin Slack for answering this.
Gabriel recommends using a Cron Job as opposed to a Timer Task because there may be issues with a Timer thread based on scaling type.
GAE probably expects your app to look like a Java app (e.g., a Java style "main", not a Kotlin style "main").
Look at this for more info on how to do this: How to run Kotlin class from the command line?

Migrating to Cloud Endpoints 2.0 - Working on localhost but not on App Engine

I'm migration my GAE Java app to Google Cloud Endpoints 2.0. I followed the migration guide (https://cloud.google.com/endpoints/docs/frameworks/legacy/v1/java/migrating) to migrate to Endpoints v2.0.
The endpoints service calls are working on localhost but returning 404 (Not Found) when uploaded to the App Engine. I'm using Guice.
The relevant section from my web.xml looks similar to this:
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.xyz.myapp.server.guice.MyAppGuiceServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>EndpointsServlet</servlet-name>
<servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value>com.xyz.myapp.server.endpoints.MyEP1,com.xyz.myapp.server.endpoints.MyEP2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>EndpointsServlet</servlet-name>
<url-pattern>/_ah/api/*</url-pattern>
</servlet-mapping>
MyAppGuiceServletContextListener.java
public class MyAppGuiceServletContextListener extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new GuiceServletModule(), new EPServletModule());
}
}
EPServletModule.java
public class EPServletModule extends EndpointsModule {
#Override
protected void configureServlets() {
super.configureServlets();
Set<Class<?>> serviceClasses = new HashSet<Class<?>>();
serviceClasses.add(MyEP1.class);
serviceClasses.add(MyEP2.class);
configureEndpoints("/_ah/api/*", serviceClasses);
}
}
GuiceServletModule:
public class GuiceServletModule extends ServletModule {
#Override
protected void configureServlets() {
super.configureServlets();
serve("/myapp/servlet1").with(Servlet1.class);
serve("/myapp/servlet2").with(Servlet2.class);
}
}
I'm able to invoke the regular servlets at the paths:
https://[version]-dot-myapp-id.appspot.com/myapp/servlet1
https://[version]-dot-myapp-id.appspot.com/myapp/servlet2
But I'm not able to access the endpoints. It always returns 404 error code. I tried via my Javascript client and also via the APIs Explorer, and get the same error.
I also checked the logs and strangely the logs show the POST request like this:
"POST /_ah/spi/com.xyz.myapp.server.endpoints.MyEP1.myEPMethod HTTP/1.1" 404
Why does it start with /_ah/spi/ when my client is invoking it via /_ah/api/ ?
NOTE: I'm able to invoke the Endpoints 1.0, which are deployed on a different version of the same app, without any issue. But the Endpoints 2.0 version is not working.
Am I missing something?
I also have a very basic question. My client is Javascript based. Does it really make use of the Discovery Document?
I fixed this by Updating Android Studio to the latest version and updating the SDK.

How to handle routing when both front end and back end are on the same server

I have a Spring boot and it has some services running on it. It also has a react view that has its own routing. Is this even possible, can I have a backend routing and front end routing within the same server?
Thanks
After some research, front-end routing is a misleading term, although it is being widely used. The routing needs to always go to the back-end, and the back-end decides what happens with the request. If React.js, Angular or any other front-end frameworks are handling routing, back-end needs to forward all the requests that are coming from the front-end to the front-end again, which is the HTML page that has the JS and CSS. To achieve this with spring framework, I used a tuckey filter to forward requests to the html page. The magic word is FORWARDING the request to the html page.
The urlrewrite.xml for the tuckey filter forwards the requests to the ui again, it looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN" "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<!-- Configuration file for UrlRewriteFilter http://www.tuckey.org/urlrewrite/ -->
<urlrewrite>
<rule match-type="regex">
<name>Front-end forwarding</name>
<note>Forwarding all routes from the front-end to the ui controller</note>
<condition type="request-uri" operator="notequal">^\/([\-\w\.]+)([\-/\w\.]*)(\.([\-\w]+))$</condition>
<from>^\/ui\/([/\-\w]+)$</from>
<to type="forward" last="true">/ui</to> <!--This is where the ui controller is located-->
</rule>
</urlrewrite>
This is the tuckey filter java configurations:
#Component
public class TuckeyFilterConfigurations extends UrlRewriteFilter{
private static final String CONFIG_LOCATION = "classpath:/urlrewrite.xml";
#Value(CONFIG_LOCATION)
private Resource resource;
#Override
protected void loadUrlRewriter(FilterConfig filterConfig) throws ServletException {
try {
Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "");
checkConf(conf);
} catch (IOException ex) {
throw new ServletException("Unable to load URL-rewrite configuration file from " + CONFIG_LOCATION, ex);
}
}
}
And finally, the controller that serves the html page simply looks like:
#Controller
public class UiController {
#RequestMapping("/ui")
public String entrance(){
return "index.html";
}
}
Yes you can have but it's always a good practice to have the routing logic at one place, as it helps a lot in troubleshooting the application once it's size grows.
How this would work, can you give an example? When I have a front end routing to a certain link, it is always directed to the backend. I know that there is the # routing, but I'm looking for a solution for the regular "/" routing?
You can use BrowserRouter or StaticRouter to achieve it. Here is the nice guide by React training team to implement Server Rendering using StaticRouter - Server Rendering with React.
Step 1 add below in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
Step 2, Please add below two lines in your application.properties :
#reload static content lively without reboot spring boot app
spring.devtools.livereload.enabled: true
#specify the static file location
spring.resources.static-locations: file:${your-frontend-file-root-location}

Apache Camel - Deploy war application with RouteBuilder

Im new to Apache Camel, Please let me know How do we deploy a war with camel which activate routeBulder automatically?
I have configure in the applicationContext.xml
<camelContext xmlns="http://camel.apache.org/schema/spring" id="camel-3">
<routeBuilder ref="SearchProcessRoute" />
<bean id="SearchProcessRoute" class="camel.core.SearchProcessRouteBuilder" />
and the Route builder
public class SearchProcessRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// TODO Auto-generated method stub
from("activemq://search.queue")
.log("Process from the queue")
.bean("SearchProcessBean","ProcessData")
.to("activemq://search.process.queue");
}}
When I send a message to the search.queue it doesnt process anything?
Please let me know the proper way to deploy a web app with camel (Is there any sample application) and how do we solve the above issue?
PS. I was able to execute this as a standalone application. However, What I want to achieve is that connect from the standalone application to the activmq ("activemq://search.queue") which is deployed in the war and then the route (SearchProcessRouteBuilder) which is in the war activate automatically and that would process the queue. Then it will send the message to the other queue "activemq://search.process.queue".
Is this possible with Apache Camel, if So how we can achieve this?
you just need to add the following to the web.xml to bootstrap the Spring/Camel contexts
<!-- location of spring xml files -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- the listener that kick-starts Spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
see http://camel.apache.org/servlet-tomcat-example.html

Appengine with Google Cloud Endpoints and Guice

So i want to use Guice in Appengine with Cloud Endpoints to inject my services, or daos - pretty common I guess, but I found no tutorial for this.
Official Guice for Appengine documentation seems to be here: https://github.com/google/guice/wiki/GoogleAppEngine
When configuring Guice you set up the com.google.inject.servlet.GuiceFilter to intercept every request "/*". And at some point you must initialize the modules. Like the documentation says a good place to do that is a ServletContextListener.
One special kind of Module are ServletModules, that map request-Paths to Servlet-Classes, instead of doing this in the web.xml you can now do this programmatically.
Pretty straight forward up until here. But how do I configure Guice to also include the Endpoint-Classes?
Turns out there is a GuiceSystemServiceServletModule that handles exactly this.
public class GuiceSSSModule extends GuiceSystemServiceServletModule {
#Override
protected void configureServlets() {
super.configureServlets();
Set<Class<?>> serviceClasses = new HashSet<Class<?>>();
serviceClasses.add(MyEndpoint.class);
serviceClasses.add(AnotherAndpoint.class);
this.serveGuiceSystemServiceServlet("/_ah/spi/*", serviceClasses);
}
}
Include this module in the Injector construction in your ServletContextListener:
public class MyGSCL extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new GuiceSSSModule(), new BaseModule());
}
}
and use this listener in your web.xml:
<listener>
<listener-class>de.mypkg.MyGSCL</listener-class>
</listener>
Also make sure to include the Guice filter in your web.xml:
<!-- GUICE -->
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Your endpoints will be available under /_ah/api/... again and you can use #Inject in your endpoint classes.

Resources