Has anyone successfully deployed a GWT app on Heroku? - gwt

Heroku recently began supporting Java apps. Looking through the docs, it seems to resemble the Java Servlet Standard. Does anyone know of an instance where a GWT app has been successfully deployed on Heroku? If so, are there any limitations?

Yes, I've got a successful deployment using the getting started with Java instructions here:
http://devcenter.heroku.com/articles/java
I use the Maven project with appassembler plugin approach but added gwt-maven-plugin to compile a GWT app during the build.
When you push to heroku you see the GWT compile process running, on one thread only so quite slow but it works fine.
The embedded Jetty instance is configured to serve up static resources at /static from src/main/resources/static and I copy the compiled GWT app to this location during the build and then reference the .nocache.js as normal.
What else do you want to know?
You've got a choice, either build the Javascript representation of your GWT app locally into your Maven project, commit it and the read it from your app, or to generate it inside Heroku via the gwt-maven-plugin as I mentioned.
The code to serve up files from a static location inside your jar via embedded Jetty is something like this inside a Guice ServletModule:
(See my other answer below for a simpler and less Guice-driven way to do this.)
protected void configureServlets() {
bind(DefaultServlet.class).in(Singleton.class);
Map<String, String> initParams = new HashMap<String, String>();
initParams.put("pathInfoOnly", "true");
initParams.put("resourceBase", staticResourceBase());
serve("/static/*").with(DefaultServlet.class, initParams);
}
private String staticResourceBase() {
try {
return WebServletModule.class.getResource("/static").toURI().toString();
}
catch (URISyntaxException e) {
e.printStackTrace();
return "couldn't resolve real path to static/";
}
}
There's a few other tricks to getting embedded Jetty working with guice-servlet, let me know if this isn't enough.

My first answer to this turned out to have problems when GWT tried to read its serialization policy. In the end I went for a simpler approach that was less Guice-based. I had to step through the Jetty code to understand why setBaseResource() was the way to go - it's not immediately obvious from the Javadoc.
Here's my server class - the one with the main() method that you point Heroku at via your app-assembler plugin as per the Heroku docs.
public class MyServer {
public static void main(String[] args) throws Exception {
if (args.length > 0) {
new MyServer().start(Integer.valueOf(args[0]));
}
else {
new MyServer().start(Integer.valueOf(System.getenv("PORT")));
}
}
public void start(int port) throws Exception {
Server server = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setBaseResource(createResourceForStatics());
context.setContextPath("/");
context.addEventListener(new AppConfig());
context.addFilter(GuiceFilter.class, "/*", null);
context.addServlet(DefaultServlet.class, "/");
server.setHandler(context);
server.start();
server.join();
}
private Resource createResourceForStatics() throws MalformedURLException, IOException {
String staticDir = getClass().getClassLoader().getResource("static/").toExternalForm();
Resource staticResource = Resource.newResource(staticDir);
return staticResource;
}
}
AppConfig.java is a GuiceServletContextListener.
You then put your static resources under src/main/resources/static/.

In theory, one should be able to run GWT using the embedded versions of Jetty or Tomcat, and bootstrap the server in main as described in the Heroku Java docs.

Related

Embedded Jetty Server giving Same response for different urls , without restarting its not working,

I have developed the embedded jetty server to implement the rest service.
I have setup the eclipse project in the eclipse.
I have written the sample program which returns some details through rest url,
I was successfully compiled the program and created a Runnable jar.
I was successfully able to run the Jar files and the server started and running on the port which i gave ,
I have the testing url
http://localhost:1234/getuser/1
it gave me the user details in the response
<username>test1</username>
I ran the same url with different id no
http://localhost:1234/getuser/2
Again it gave me the same result,
`<username>test1</username>`
So i have restarted the server and then it got me the proper details,
<username>test2</username>
public static void main(String[] args) {
// TODO Auto-generated method stub
ServletContextHandler context = new
ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
Server jettyServer = new Server(1234);
jettyServer.setHandler(context);
ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", org.test.test.getuser.class.getCanonicalName());
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
e.printStackTrace();
} finally{
jettyServer.destroy();
}
}
Without restarting the jetty web server how to get the proper results.
Is there any thing i need to add in the code to get it worked.
or any settings i need to do for this auto refresh?
I have found the answer, jetty server was able to refresh automatically, there was a object refresh didnt happened in the back end, resolved it from myside and it worked

Container managed MongoDB Connection in Liberty + Spring Data

We have developed an application in Spring Boot + spring data (backend) + MongoDB and used IBM Websphere Liberty as application Server. We were used "Application Managed DB Connection" in an yml file and enjoyed the benefit of Spring Boot autoconfiguration.
Due to policy changes, we would need to manage our DB Connection in Liberty Server(using mongo feature), in Server.xml. I spent whole day in finding out an good example to do this, but dont find any example in Spring with "Container Managed MongoDB Connection" in IBM Websphere Liberty Server.
Can someone please support here?
Check out this other stackoverflow solution. The following is an extension of how you would use that in your Spring Boot app.
You should be able to inject your datasource the same way. You could even inject it into your configuration and wrap it in a Spring DelegatingDataSource.
#Configuration
public class DataSourceConfiguration {
// This is the last code section from that link above
#Resource(lookup = "jdbc/oracle")
DataSource ds;
#Bean
public DataSource mySpringManagedDS() {
return new DelegatingDataSource(ds);
}
}
Then you should be able to inject the mySpringManagedDS DataSource into your Component, Service, etc.
In the past Liberty had a dedicated mongodb-2.0 feature for the server.xml, however this feature provided pretty minimal benefit, since you still needed to bring your own MongoDB libraries. Also, over time MongoDB made significant breaking changes to their API, including how MongoDB gets configured.
Since the MongoDB API is changing so drastically between releases, we found it better to not provide any new MongoDB features in Liberty and instead suggest that users simply use a CDI producer like this:
CDI producer (holds any configuration too):
#ApplicationScoped
public class MongoProducer {
#Produces
public MongoClient createMongo() {
return new MongoClient(new ServerAddress(), new MongoClientOptions.Builder().build());
}
#Produces
public MongoDatabase createDB(MongoClient client) {
return client.getDatabase("testdb");
}
public void close(#Disposes MongoClient toClose) {
toClose.close();
}
}
Example usage:
#Inject
MongoDatabase db;
#POST
#Path("/add")
#Consumes(MediaType.APPLICATION_JSON)
public void add(CrewMember crewMember) {
MongoCollection<Document> crew = db.getCollection("Crew");
Document newCrewMember = new Document();
newCrewMember.put("Name",crewMember.getName());
newCrewMember.put("Rank",crewMember.getRank());
newCrewMember.put("CrewID",crewMember.getCrewID());
crew.insertOne(newCrewMember);
}
This is just the basics, but the following blog post goes into much greater detail along with code examples:
https://openliberty.io/blog/2019/02/19/mongodb-with-open-liberty.html

Unable to download embedded MongoDB, behind proxy, using automatic configuration script

I have a Spring Boot project, built using Maven, where I intend to use embedded mongo db. I am using Eclipse on Windows 7.
I am behind a proxy that uses automatic configuration script, as I have observed in the Connection tab of Internet Options.
I am getting the following exception when I try to run the application.
java.io.IOException: Could not open inputStream for https://downloads.mongodb.org/win32/mongodb-win32-i386-3.2.2.zip
at de.flapdoodle.embed.process.store.Downloader.downloadInputStream(Downloader.java:131) ~[de.flapdoodle.embed.process-2.0.1.jar:na]
at de.flapdoodle.embed.process.store.Downloader.download(Downloader.java:69) ~[de.flapdoodle.embed.process-2.0.1.jar:na]
....
MongoDB gets downloaded just fine, when I hit the following URL in my web browser:
https://downloads.mongodb.org/win32/mongodb-win32-i386-3.2.2.zip
This leads me to believe that probably I'm missing some configuration in my Eclipse or may be the maven project itself.
Please help me to find the right configuration.
What worked for me on a windows machine:
Download the zip file (https://downloads.mongodb.org/win32/mongodb-win32-i386-3.2.2.zip)
manually and put it (not unpack) into this folder:
C:\Users\<Username>\.embedmongo\win32\
Indeed the problem is about your proxy (a corporate one I guess).
If the proxy do not require authentication, you can solve your problem easily just by adding the appropriate -Dhttp.proxyHost=... and -Dhttp.proxyPort=... (or/and the same with "https.[...]") as JVM arguments in your eclipse junit Runner, as suggested here : https://github.com/learning-spring-boot/learning-spring-boot-2nd-edition-code/issues/2
One solution to your problem is to do the following.
Download MongoDB and place it on a ftp server which is inside your corporate network (for which you would not need proxy).
Then write a configuration in your project like this
#Bean
#ConditionalOnProperty("mongo.proxy")
public IRuntimeConfig embeddedMongoRuntimeConfig() {
final Command command = Command.MongoD;
final IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder()
.defaults(command)
.artifactStore(new ExtractedArtifactStoreBuilder()
.defaults(command)
.download(new DownloadConfigBuilder()
.defaultsForCommand(command)
.downloadPath("your-ftp-path")
.build())
.build())
.build();
return runtimeConfig;
}
With the property mongo.proxy you can control whether Spring Boot downloads MongoDB from your ftp server or from outside. If it is set to true then it downloads from the ftp server. If not then it tries to download from the internet.
The easiest way seems to me to customize the default configuration:
#Bean
DownloadConfigBuilderCustomizer mongoProxyCustomizer() {
return configBuilder -> {
configBuilder.proxyFactory(new HttpProxyFactory(host, port));
};
}
Got the same issue (with Spring Boot 2.6.1 the spring.mongodb.embedded.version property is mandatory).
To configure the proxy, I've added the configuration bean by myself:
#Value("${spring.mongodb.embedded.proxy.domain}")
private String proxyDomain;
#Value("${spring.mongodb.embedded.proxy.port}")
private Integer proxyPort;
#Bean
RuntimeConfig embeddedMongoRuntimeConfig(ObjectProvider<DownloadConfigBuilderCustomizer> downloadConfigBuilderCustomizers) {
Logger logger = LoggerFactory.getLogger(this.getClass().getPackage().getName() + ".EmbeddedMongo");
ProcessOutput processOutput = new ProcessOutput(Processors.logTo(logger, Slf4jLevel.INFO), Processors.logTo(logger, Slf4jLevel.ERROR), Processors.named("[console>]", Processors.logTo(logger, Slf4jLevel.DEBUG)));
return Defaults.runtimeConfigFor(Command.MongoD, logger).processOutput(processOutput).artifactStore(this.getArtifactStore(logger, downloadConfigBuilderCustomizers.orderedStream())).isDaemonProcess(false).build();
}
private ExtractedArtifactStore getArtifactStore(Logger logger, Stream<DownloadConfigBuilderCustomizer> downloadConfigBuilderCustomizers) {
de.flapdoodle.embed.process.config.store.ImmutableDownloadConfig.Builder downloadConfigBuilder = Defaults.downloadConfigFor(Command.MongoD);
downloadConfigBuilder.progressListener(new Slf4jProgressListener(logger));
downloadConfigBuilderCustomizers.forEach((customizer) -> {
customizer.customize(downloadConfigBuilder);
});
DownloadConfig downloadConfig = downloadConfigBuilder
.proxyFactory(new HttpProxyFactory(proxyDomain, proxyPort)) // <--- HERE
.build();
return Defaults.extractedArtifactStoreFor(Command.MongoD).withDownloadConfig(downloadConfig);
}
In my case, I had to add the HTTPS corporate proxy to Intellij Run Configuration.
Https because it was trying to download:
https://downloads.mongodb.org/win32/mongodb-win32-x86_64-4.0.2.zip
application.properties:
spring.data.mongodb.database=test
spring.data.mongodb.port=27017
spring.mongodb.embedded.version=4.0.2
Please keep in mind this is a (DEV) setup.

SpringBoot Rest Application + Arquillian

I want to test my Rest Application that uses SpringBoot to test with Arquillian but none of the online examples work i am not able to test a GET call and facing difficulties deploying to Jboss EAP-6.4. Can anyone guide me on how to achieve this. Any simple Examples ???
I think that here there are a lot of things to check, so I would say 1) have you tried to deploy the spring boot app to EAP 6.4 to check that it works (not using Arquillian)? and 2) is it possible to share a simple github project so we can check?
This link helped me to solve the issue : Adding all Maven dependencies to Arquillian.
The code that works :
#Deployment
public static Archive<?> createTestArchive() {
File[] files = Maven.resolver()
.loadPomFromFile("pom.xml")
.importRuntimeDependencies()
.resolve().withTransitivity()
.asFile();
return ShrinkWrap.create(WebArchive.class, "FileUploadIssue.war")
.addPackages(true,"com.example")
.addAsLibraries(files);
}
#Test
#RunAsClient
public void shouldGetFileContents() {
String result = restTemplate.getForObject(contextPath + "upload/sayhello", String.class);
System.out.println( "Test : " + result);
}
Is there any way to refactor this code even more ??

ClassCastException On JBOSS OSGI 7.1

I use JBOSS OSGI 7.1 for my project.
I have 2 bundle:
usermanagement (service provider)
jerseyBundle (service consumer)
When I deploy and start usermanagement bundle,
Then deploy and start jersey bundle.
jerseyBundle getServiceReference() successful.
Then.
I try to redeploy and restart usermanagement. Then refresh all bundles.
JerseyBundle getServiceReference() with Exception: "ClassCastException"
This is code I use to get service:
public <T> T getService(Class<T> type,List<ServiceReference> _sref) {
try {
ServiceReference sref = bundleContext.getServiceReference(type.getName());
if(sref != null)
{
_sref.add(sref);
}
return type.cast(bundleContext.getService(sref));
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
I use blueprint to register services.
I tried to ungetservice but it don't solved this problem.
public void unGetService(List<ServiceReference> _sref) {
try{
while(_sref != null && _sref.size() >0 )
{
System.err.println("==============" + bundleContext.ungetService(_sref.remove(0)));
}
}catch(Exception ex){
ex.printStackTrace();
}
}
Are there any ways to redeploy service provider bundle, don't need redeploy service consumer bundle?
The reason for the observed behaviour may be that OSGi caches the service object by bundle. So if you do bundleContext.getService(sref) then OSGI will store this object internally and always return the same until you do ungetService.
So when you update the service bundle which also contains the interface and refresh the client you will have a new class for the interface. If you now do a cast of an old service object to the new interface the ClassCastException will occur.
One way to cope with this is to only use the service object for a short period of time and then unget it. Like this:
ServiceReference sref = bundleContext.getServiceReference(type.getName());
myO = type.cast(bundleContext.getService(sref));
doStuff(myO);
bundleContext.ungetService(sref)
Of course this is only practicable for infrequent calls as you have some overhead.
The other way is to use a ServiceTracker and react on service additions and removals. So for example you could inject a service into your class which does "doStuff" and remove / replace the service when there are changes. This is quite hard to do on your own though.
In fact this is the reason why there are frameworks like declarative services (DS) or blueprint. These make sure to reinject service and restart your components when services come and go.
As you are already using blueprint on the provider side you might try to use it on the client side too. The blueprint client should not have the problems you observed.
Btw. blueprint and DS handle service dynamics very differently. Blueprint injects a proxy once and then just replaces the service object inside the proxy while DS will really restart your user component.