Vaadin Fusion index.html will result in offline-stub - jetty

I'm very new to Jetty and Vaadin. I try to get a Jetty running hosting a minimal Vaadin Fusion example.
However, already on the first visit on my empty index.html I got a connection lost banner and a 404 because it tries to redirect to an /offline-stub.html that I don't have.
The Produced view:
In the network tap, you can see that Vaadin somehow initiates the redirect:
My index.html is very simple:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Vaadin Grocery App</title>
<style>
body {
margin: 0;
width: 100vw;
height: 100vh;
}
#outlet {
height: 100%;
}
</style>
<!-- index.ts is included here automatically (either by the dev server or during the build) -->
</head>
<body>
<h1>hello</h1>
</body>
</html>
an index.ts as well:
import { Router } from '#vaadin/router';
import { routes } from './routes';
import { appStore } from './stores/app-store';
export const router = new Router(document.querySelector('#outlet'));
router.setRoutes(routes);
window.addEventListener('vaadin-router-location-changed', (e) => {
appStore.setLocation((e as CustomEvent).detail.location);
const title = appStore.currentViewTitle;
if (title) {
document.title = title + ' | ' + appStore.applicationName;
} else {
document.title = appStore.applicationName;
}
});
I initiate the Jetty like this:
public static void main(String[] args) throws URISyntaxException, IOException {
Log.setLog(new StdErrLog());
System.out.println("Server starting...");
String extForm = webRoot + "/webapp";
System.out.println(extForm);
final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
final ResourceHandler resHandler = new ResourceHandler();
resHandler.setResourceBase(extForm);
final ContextHandler ctx = new ContextHandler("/");
ctx.setHandler(resHandler);
Server embeddedServer = new Server(8080);
embeddedServer.insertHandler(context); // Rest/Servlets
embeddedServer.insertHandler(resHandler); // HTML Resources
try {
embeddedServer.start();
embeddedServer.join();
} catch (Exception e) {
System.err.println("Server error:\n" + e);
}
System.out.println("Server stopped");
}
Webroot, extform -values are correct and the files are at those specified locations on disk:

Please note that Vaadin Fusion only supports Spring Boot backends right now. Because of that, you don't need to configure your own server. Starting the Spring Boot app is enough. I recommend creating a project starter on https://start.vaadin.com and basing your project on that.
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Don't mix ResourceHandler and ServletContextHandler together like that.
Remove the ResourceHandler entirely (and it's associated ContextHandler)
Properly define the ServletContextHandler with a resource base.
Then ensure that ServletContextHandler has a DefaultServlet setup.
That's it, that's all you have to do.
Oh, and don't declare your REST endpoints on url-pattern / or /* as that also prevents static resource serving. Those url-patterns basically mean that your servlet endpoint (your REST lib?) is the only thing, and it's responsible for 100% of requests.
The reason you don't mix things like this is because both ServletContextHandler and ResourceHandler are terminal (once entered, they must respond with an HTTP response).
If you use the ServletContext properly, then the best match (see Servlet url-pattern matching rules, eg: longest match) against the url-pattern is used, serving static content or your REST endpoint depending on what your client is requesting.

Related

Amazon lex-chatbot-not able to embed using predefined libraries

I have developed chatbot and want to integrate in a website.I am following this github link that has predefined libraries for chatbotUI to embbed as an iframe. https://github.com/aws-samples/aws-lex-web-ui Below is the code from github:
<html>
<head>
<title>My Parent Page</title>
</head>
<body>
<h1>Welcome to my parent page</h1>
<!-- loader script -->
<script src="./lex-web-ui-loader.js"></script>
<script>
/*
The loader library creates a global object named ChatBotUiLoader
It includes the IframeLoader constructor
An instance of IframeLoader has the load function which kicks off
the load process
*/
// options for the loader constructor
var loaderOptions = {
// you can put the chatbot UI config in a JSON file
configUrl: './chatbot-ui-loader-config.json',
// the full page chatbot UI that will be iframed
iframeSrcPath: './chatbot-index.html#/?lexWebUiEmbed=true'
};
// The following statement instantiates the IframeLoader
var iframeLoader = new ChatBotUiLoader.IframeLoader(loaderOptions);
// chatbot UI config
// The loader can also obtain these values from other sources such
// as a JSON file or events. The configUrl variable in the
// loaderOptions above can be used to put these config values in a file
// instead of explicitly passing it as an argument.
var chatbotUiConfig = {
ui: {
// origin of the parent site where you are including the chatbot UI
// set to window.location.origin since hosting on same site
parentOrigin: window.location.origin,
},
iframe: {
// origin hosting the HTML file that will be embedded in the iframe
// set to window.location.origin since hosting on same site
iframeOrigin: window.location.origin,
},
cognito: {
// Your Cognito Pool Id - this is required to provide AWS credentials
poolId: '<your cognito pool id>'
},
lex: {
// Lex Bot Name in your account
botName: '<your lex bot name>'
}
};
// Call the load function which returns a promise that is resolved
// once the component is loaded or is rejected if there is an error
iframeLoader.load(chatbotUiConfig)
.then(function () {
console.log('iframe loaded');
})
.catch(function (err) {
console.error(err);
});
</script>
</body>
</html>
I went to parent.html (almost similar to the code above)inside src/website/parent.html of the github folder and made changes to the srcipt src path ,cognito poolid and lex name referring to the above code.
1)In config url inside the code above,I dont know what path to give for chatbot-ui-loader-config.json.There is no such json file inside dist directory.Should I create my own ?
2)I created an website using EC2 linux instance.I have my index file and aws-lex-web-ui (github folder) inside my var/www/html.Inside index file,I am calling the parent.html of aws-lex-web-ui folder.Is this method correct?
In output I am getting the heading content of the parent .html page .But It seems its not invoking the lex-web-ui-loader.js .I am not sure where I go wrong.
I have given a wrong path .I pointed the loader file lex-web-ui-loader.js to a correct location inside my folder and it worked.

Calling a Spring Boot 2 REST service with multipart/form-data with Postman results in a EOFException

While working on a personal project on Spring Boot, I have to develop a web service that accepts a file and some metadata, and I have decided to test with a Postman client.
Versions I am using:
Postman version: Postman for Mac Version 7.8.0 OS X 18.7.0 / x64
Java version: 1.8.0_212
Spring boot version: 2.1.1.RELEASE
As metadata will potentially be quite structured, I have decided to use the multipart/form-data content type, consisting in two parts:
a "file" part containing the file
a "body" part containing the json with the metadata
I've configured the call in Postman like this
Now, Spring boot configuration. First of all, I've added the following lines to application.properties:
## MULTIPART (MultipartProperties)
# Enable multipart uploads
spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=20MB
# Max Request Size
spring.servlet.multipart.max-request-size=25MB
I've then created my controller with the endpoint
#PostMapping(Paths.Registrations.BASE)
#ResponseBody
public PostRegistrationResponseDto postRegistration(#RequestParam("file") MultipartFile file, #RequestParam("body") PostRegistrationRequestDto req) {
PostRegistrationResponseDto resp = new PostRegistrationResponseDto();
resp.setId(new Random().nextLong());
resp.setFileName(req.getFileName());
resp.setRegistrationTime(LocalDateTime.now());
return resp;
}
Unfortunately, the call does not even arrive to Spring: I receive a HTTP 500 error with this body
<!doctype html>
<html lang="en">
<head>
<title>HTTP Status 500 – Internal Server Error</title>
<style type="text/css">
...
</style>
</head>
<body>
<h1>HTTP Status 500 – Internal Server Error</h1>
</body>
</html>
In my server log I get no exception, but when I set the debugger to block on exceptions I saw that tomcat launches an EOF exception with this stack trace
java.io.EOFException
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1208)
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1142)
at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:729)
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:352)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:294)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:791)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
I admit I do not even know where to start from... can someone give me some hints of what I'm doing wrong?
Thanks :)
In the end, what I discovered is that Tomcat throws a lot of exceptions, not always meaningful.
The problem I had was not related to that exception, but to the fact that Spring doesn't automatically map the String part to the Dto.
To make everything work, I had to write this component:
package it.aegidea.proofy.api.converters;
import com.fasterxml.jackson.databind.ObjectMapper;
import it.aegidea.proofy.api.dtos.proofyapi.PostRegistrationRequestDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.io.IOException;
#Component
public class PostRegistrationRequestDtoConverter implements Converter<String, PostRegistrationRequestDto> {
private final ObjectMapper objectMapper;
#Autowired
public PostRegistrationRequestDtoConverter(final ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
#Override
public PostRegistrationRequestDto convert(String source) {
try {
return objectMapper.readValue(source, PostRegistrationRequestDto.class);
} catch (IOException e) {
return null;
}
}
}
This way, Spring understood how to map the string to a PostRegistrationRequestDto and could successfully map the request to the types on the endpoint.

QWebEngine: handling get and post requests when a runJavaScript is performed

I am looking for possibility of handling get and post requests made by running a java-script code after a website is loaded. Here is the description: a url could be loaded via QWebEnginePage::load and the page contains some buttons with javescript events bind to them. buttons do some get and post requests from internet. Is there anyway that I could signal my classes when the get and post requests are performed by that javascript events. If it is impossible with QWebEngine What are the other options in Qt to do job. I am looking for some options that would not be absolute in the future since it is part of long-term project.
Thanks
You can use QWebChannel that should work in your case.
CPP file
QWebChannel* webChannel = new QWebChannel();
webChannel->registerObject("foo", this);
webview->page()->setWebChannel(webChannel);
in HTML file
<script type="text/javascript" src="qrc:/Map/qwebchannel.js"></script>
<script type="text/javascript">
new QWebChannel(qt.webChannelTransport, function(channel) {
// all published objects are available in channel.objects under
// the identifier set in their attached WebChannel.id property
var foo = channel.objects.foo;
// access a property
alert(foo.hello);
// connect to a signal
foo.someSignal.connect(function(message) {
alert("Got signal: " + message);
});
// invoke a method, and receive the return value asynchronously
foo.someMethod("bar", function(ret) {
alert("Got return value: " + ret);
});
});
</script>

configure jetty in spring boot

I am developing a multi-module spring boot project. My project structure look like
myProject(parent)
front-end
src/main/resources
frontend
index.html
rest
src/main/java
com.example
MyWebApp.java
com.example.config
WebAppConfig.java
I am trying to configure jetty by injecting JettyServerCustomizer as bean in WebAppConfig as following
#Bean
public JettyServerCustomizer customizeJettyServer()
{
return new JettyServerCustomizer()
{
#Override
public void customize(final Server server)
{
ContextHandler frontEndContext = new ContextHandler();
frontEndContext.setContextPath(""); //what should be here
frontEndContext.setResourceBase("");//what should be here
ResourceHandler frontEndResourceHandler = new ResourceHandler();
frontEndResourceHandler.setWelcomeFiles(new String[] { "index.html" });
frontEndContext.setHandler(frontEndResourceHandler);
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { frontEndContext});
server.setHandler(contexts);
}
};
}
What value to set to contextPath and ResourceBase so that I could run my index.html which is in front-end module? How the url will looks like?
Thank you :)
Spring Boot can serve static content for you. Instead of trying to configure Jetty, place your static content beneath src/main/resources/static and they'll be loaded straight from the classpath.

Cross Origin Filter with embedded Jetty

I'm trying to get a CrossOriginFilter working with a couple of embedded Jetty servers, both running on our internal network. Both are running servlets, but I need server A's web page to be able to post to server B's servlets. I think I need to add ACCESS_CONTROL_ALLOW_ORIGIN to a CrossOriginFilter but finding out how to do this with an embedded Jetty instance with no web.xml isn't proving to be easy. I get the following error message in the browser when trying to access server b's serlvets
No 'Access-Control-Allow-Origin' header is present on the requested resource
Im using angularjs to post to the other server's servlets in a controller.
And here is the code for one of the servers (both are pretty much the same)
Server server = new Server(httpPort);
ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[] { "index.html" });
resource_handler.setResourceBase("./http/");
ServletHandler handler = new ServletHandler();
handler.addServletWithMapping(ServerPageRoot.class, "/servlet/*");
FilterHolder holder = new FilterHolder(CrossOriginFilter.class);
holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
holder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin");
handler.addFilter(holder );
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resource_handler, handler,new DefaultHandler() });
server.setHandler(handlers);
server.start();
A few points:
Don't use ServletHandler naked like that. The ServletHandler is an internal class that ServletContextHandler uses.
The ServletContextHandler is what provides the needed ServletContext object and state for the various servlets and filters you are using.
The ServletContextHandler also provides a place for the overall Context Path declaration
The ServletContextHandler is also the place for Welcome Files declaration.
Don't use ResourceHandler, when you have DefaultServlet available, its far more capable and feature rich.
Example:
Server server = new Server(httpPort);
// Setup the context for servlets
ServletContextHandler context = new ServletContextHandler();
// Set the context for all filters and servlets
// Required for the internal servlet & filter ServletContext to be sane
context.setContextPath("/");
// The servlet context is what holds the welcome list
// (not the ResourceHandler or DefaultServlet)
context.setWelcomeFiles(new String[] { "index.html" });
// Add a servlet
context.addServlet(ServerPageRoot.class,"/servlet/*");
// Add the filter, and then use the provided FilterHolder to configure it
FilterHolder cors = context.addFilter(CrossOriginFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin");
// Use a DefaultServlet to serve static files.
// Alternate Holder technique, prepare then add.
// DefaultServlet should be named 'default'
ServletHolder def = new ServletHolder("default", DefaultServlet.class);
def.setInitParameter("resourceBase","./http/");
def.setInitParameter("dirAllowed","false");
context.addServlet(def,"/");
// Create the server level handler list.
HandlerList handlers = new HandlerList();
// Make sure DefaultHandler is last (for error handling reasons)
handlers.setHandlers(new Handler[] { context, new DefaultHandler() });
server.setHandler(handlers);
server.start();
managed to get it working by doing
FilterHolder holder = new FilterHolder(CrossOriginFilter.class);
holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
holder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin");
holder.setName("cross-origin");
FilterMapping fm = new FilterMapping();
fm.setFilterName("cross-origin");
fm.setPathSpec("*");
handler.addFilter(holder, fm );
Maybe this will help someone even though it is not a good answer to the original question. I realized that you can easaly enable cross origin request sharing in an embedded jetty instance by manipulating the headers directly in your handler. The response object below is an instance of HttpServletResponse (which is passed to the handler).
Example:
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods", "POST, GET");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
I tried all the way of above answers and other similar ones. But always, I came across same error message.
Finally I reach a correct answer for my situation. I use Jersey with Jetty and I am not using web.xml. If you try all methods and you don't enable the CORS support, maybe you can try this solution below.
First, define a filter (you can define another one which directly implements Filter class)
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null && request.getMethod().equalsIgnoreCase("OPTIONS");
}
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
// if there is no Origin header, we don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With,Content-Type,Content-Length,Authorization,"
+ "Accept,Origin,Cache-Control,Accept-Encoding,Access-Control-Request-Headers,"
+ "Access-Control-Request-Method,Referer,x-csrftoken,ClientKey");
}
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
Register this filter to resource config
import java.io.IOException;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
public class AppServer {
public static void main(String[] args) throws Exception {
Server jettyServer = new Server();
// Add port
ServerConnector jettyServerConnector = new ServerConnector(jettyServer);
jettyServerConnector.setPort(Integer.parseInt("9090"));
jettyServer.addConnector(jettyServerConnector);
// Define main servlet context handler
ServletContextHandler jettyServletContextHandler = new ServletContextHandler();
jettyServletContextHandler.setContextPath("/service");
// Define main resource (webapi package) support
ResourceConfig webapiResourceConfig = new ResourceConfig();
webapiResourceConfig.packages("com.example.service");
ServletContainer webapiServletContainer = new ServletContainer(webapiResourceConfig);
ServletHolder webapiServletHolder = new ServletHolder(webapiServletContainer);
jettyServletContextHandler.addServlet(webapiServletHolder, "/webapi/*");
// Add Cors Filter
webapiResourceConfig.register(CorsFilter.class, 1);
try {
jettyServer.start();
jettyServer.dump(System.err);
jettyServer.join();
} catch (Throwable t) {
t.printStackTrace(System.err);
} finally {
jettyServer.destroy();
}
}
}
That's it. This solution solved my problem. Maybe it can be useful for others.