Registering a resteasy service in a Quarkus extension - quarkus

I am currently attempting to write my first Quarkus extension, which needs to deploy a rest service. For that purpose I have been looking at the Quarkus tutorial for creating extensions here, and it is pretty close to what I need to do. The problem is that it shows a Servlet, and I would very much like to deploy a RestEasy(Jackson) service instead.
I have created an extension project and added the following service in the runtime module
package my.test.quarkus.extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/mytest")
public class TestEndpoint {
private static Logger LOGGER = LoggerFactory.getLogger(TestEndpoint.class);
#POST
#Path("/service")
public void testService(){
LOGGER.info("Logit!");
}
}
But the service is not being picked up it seems, as my test returns 404.
package my.test.quarkus.extension.test;
import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
public class ExtensionTest {
#RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withEmptyApplication();
#Test
public void testGreeting() {
RestAssured.when().post("/mytest/service").then().statusCode(200);
}
}
I assume i need a BuildItem registering the service inside the deployment project of my extension, but my question is, which BuildItem do i use? Looking at the list of BuildItems there are loads of them, and even filtering those out that has nothing to do with RestEasy, still leaves over 50, most of them without JavaDoc.
If someone can help me with the problem at hand, simply registering a RestEasy service, as well as an interceptor, from an extension, that would be appreciated. And you will get bonus gratitude if you can explain exactly how to navigate through the Quarkus BuildItems when building extensions, because to me it just seems like a jungle of code, but I am guessing I am missing something.

Related

Spring redirect happening to "http://...../login" instead of "https://...../login"

I have deployed a war file generated by spring boot application using oauth2 for single sign on using Azure App service (https only).
When I browse to the home page, the home page loads with a login button.
On clicking the login button a redirect is happening to "http://..../login" (/login is the default sso login path) Since my app service is https only, the http url does not work.
I have tried the redirect_uri settings in the application.property file, but it is not helping.
Has anybody faced this problem?
How can it solved?
I found a similar issue mentioned here
This problem happens when your Tomcat server is behind a proxy. The HTTPS requests terminate at the proxy and the proxy then uses HTTP protocol to communicate to your Tomcat server. You will face this if you deploy your code on cloud providers like Azure (App Service), etc.
For anyone facing this problem, here is the solution:
in application.properties file, add the following. Note: some of the properties have different names in Spring Boot 2.* versions.
security.oauth2.client.pre-established-redirect-uri=https://yourappurl.net/login
security.oauth2.client.registered-redirect-uri=https://yourappurl.net/login
security.oauth2.client.use-current-uri=false
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.use-relative-redirects=true
server.use-forward-headers=true
server.tomcat.internal-proxies=.*
In your SpringBootApplication class, add the following bean. With Spring Boot <= 2.1.x you had to provide a ForwardedHeaderFilter-Bean. Since Spring Boot 2.2.0 you don't have to do this anymore.
import org.springframework.core.Ordered;
import org.springframework.web.filter.ForwardedHeaderFilter;
#Bean
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
final FilterRegistrationBean<ForwardedHeaderFilter> filterRegistrationBean = new FilterRegistrationBean<ForwardedHeaderFilter>();
filterRegistrationBean.setFilter(new ForwardedHeaderFilter());
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
Add the following line in configure method of your AppConfiguration class:
http.requiresChannel().anyRequest().requiresSecure();
For official info visit this page.
Ranbir has well explained the usecase where someone will face this problem.
I didnt have to add any additional properties to my springboot project. I just had to add ForwardedHeaderFilter as part of spring configuration and mentions the urls where I want this filter to act on x-forwarded header:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import javax.servlet.DispatcherType;
import org.springframework.core.Ordered;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.web.filter.ForwardedHeaderFilter;
import java.security.Security;
import java.util.Arrays;
#SpringBootApplication(scanBasePackages = {"com.abc.xyz"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
log.info("--- Security Overrides ---");
log.info("networkaddress.cache.ttl =" + Security.getProperty("networkaddress.cache.ttl"));
}
#Bean
public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(javax.servlet.DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
registration.setUrlPatterns(Arrays.asList("/app/*", "/ping", "/oauth2/authorization/callback", "/oauth/callback"));
return registration;
}
}
Here are some useful references to follow:
https://tomgregory.com/spring-boot-behind-load-balancer-using-x-forwarded-headers/
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#filters-forwarded-headers
https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#howto-enable-https

Sending email using Java and Spring Boot

I am new to sending email using java. I have a Spring Boot project from where I want to send email. I have tried several examples available on internet. Giving the URL of two examples which I tried:
https://www.mkyong.com/spring-boot/spring-boot-how-to-send-email-via-smtp/
https://www.mkyong.com/java/javamail-api-sending-email-via-gmail-smtp-example/
But none is working. Can anyone say me what customizations I will have to do in these examples and which values I will have to change to make them working? Like I will change the to Address to the adress where I will have to send email, what is the username and password? Whose username, password are they?
You can use Sendgrid API. You can send 100 email per day without paying it's absolutely free. Need to create Sendgrid account and generate an API key to send emails.
Reference:
https://sendgrid.com/docs/for-developers/sending-email/v3-java-code-example/
There is Ogham library. The code to send email is easy to write and you can even use a template to write the content of your email. It is easier to use than other libraries because you don't need to handle technical concerns (like inlining images and styles in the HTML, it is done automatically).
You can even test your code locally with a SMTP server to check the result of your email before sending it through a SMTP provider.
The email can be sent either using SMTP protocol or through providers API (like SendGrid).
It is compatible with Spring Boot and even easier to use because you don't need to instantiate the service.
package fr.sii.ogham.sample.springboot.email;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import fr.sii.ogham.core.exception.MessagingException;
import fr.sii.ogham.core.service.MessagingService;
import fr.sii.ogham.email.message.Email;
#SpringBootApplication
#PropertySource("application-email-basic.properties") // just needed to be able to run the sample
public class BasicSample {
public static void main(String[] args) throws MessagingException {
SpringApplication.run(BasicSample.class, args);
}
#RestController
public static class EmailController {
// Messaging service is automatically created using Spring Boot features
// The configuration can be set into application-email-basic.properties
// The configuration files are stored into src/main/resources
#Autowired
MessagingService messagingService;
#PostMapping(value="api/email/basic")
#ResponseStatus(HttpStatus.CREATED)
public void sendMail(#RequestParam("subject") String subject, #RequestParam("content") String content, #RequestParam("to") String to) throws MessagingException {
// send the email using fluent API
messagingService.send(new Email()
.subject(subject)
.body().string(content)
.to(to));
}
}
}
There are many other features and samples / spring samples.

Google Remote API 404 on Springboot

I'm trying to connect a Spring Boot app running locally/not in Google app engine when deployed to my Google DataStore. I am using Objectify and Google Remote API as my understanding is that Objectify will only work if deployed in App engine(?). The problem is that the Google Remote API is throwing 404 when I try and communicate with the DataStore. I think I might have my config wrong in spring boot as the instructions on the google docs talk about setting up config in web.xml which I don't use on my JAR based spring boot app. I have created a SpringBootServletInitializer class to try and register the servlet (code at the bottom). I'm coming at this from an AWS perspective and so far I've found Google cloud to be a nightmare! Connecting to DynamoDB is so much simpler and I feel I must be missing something!
import com.google.apphosting.utils.remoteapi.RemoteApiServlet;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Thomas on 01/07/2017.
*/
#Configuration
public class GoogleRemoteApiConfig extends SpringBootServletInitializer {
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(GoogleRemoteApiConfig.class, "/remote_api");
}
#Bean
public ServletRegistrationBean remoteApiRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(new RemoteApiServlet(), "/remote_api");
Map<String,String> params = new HashMap<String,String>();
registration.setInitParameters(params);
registration.setLoadOnStartup(1);
registration.setUrlMappings(Arrays.asList("/remote_api"));
registration.setName("RemoteApiServlet");
return registration;
}
}
I'd fundamentally misunderstood how the remote-api worked, and didn't realise I needed an app running in app engine to proxy the requests on to Google DataStore. I'm still confused that there is no simple way to access DataStore from Java but this approach is at least working!

Spring-MVC 3.1: How to map URLs with a trailing slash?

I'm converting a legacy servlet application over to Spring 3.1. In the process some URLs are now obsolete. We've had some problems with our network that will not be resolved anytime soon. My boss doesn't want to trust that their redirects will always be operational. So, she asked me to put my own redirects into the webapp.
All works great, except that if a URL has a trailing slash Spring 3.1 will not find the Controller class function that handles it.
http://blah.blah.blah/acme/makedonation gets found, mapped and handled
http://blah.blah.blah/acme/makedonation/ does not
Here is the controller class I am using to handle my legacy URLs
import org.springframework.stereotype.Controller;
import org.springframework.validation.*;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.apache.log4j.Logger;
#Controller
public class LegacyServletController {
private static final Logger logger = Logger.getLogger(LegacyServletController.class);
// Redirect these legacy screns "home", the login screen via the logout process
#RequestMapping({"makeadonation","contact","complain"})
public String home() {
logger.debug("started...");
return "redirect:logout";
}// end home()
}// end class LegacyServletController
I Googled around and found this Stack Overflow post that offers several suggestions, but I am new to Spring and do not understand enough of it to implement some of those suggestions. This one in particular sounds like it would be good fit with my needs:
spring 3.1 RequestMappingHandlerMapping allows you to set a
"useTrailingSlashMatch" property. By default it is true. I think
switching it to false would solve your issue,
Would anyone give me a basic example of how to that, quote me a URL that has such an example ( I had no luck with Google ) or point me to a better idea?
Thanks much in advance
Steve
you should configure your bean in context.xml,and set property.
or you can refer to link or spring doc section 16.4
example configuration
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useTrailingSlashMatch" value="true">
</property>
</bean>
If you are using spring's Java #Configuration you can also just declare a #Bean like this:
#Bean
public RequestMappingHandlerMapping useTrailingSlash() {
return new RequestMappingHandlerMapping() {{ setUseTrailingSlashMatch(true); }};
}

How to get Spring 3.1.1 works with App Engine datastore

Could everyone show me a tutorial on how to make Spring 3.1.1 running on Google App Engine, please?
I've followed severals tutorial and managed to get the dead simple HelloWorld example to work on App Engine. However, when I go futher, I stuck at the persistent process between Spring and Datastore. I looked at this thread Configuring JDO in Spring 3.1?, too, but it works on localhost but it doesn't work when I deploy to app engine due to the javax.naming.NamingException.
Therefore, I'm looking for a not-too-simple tutorial that covers basic aspects of a real life application such as the view, the model and the database.
Jappstart is a good place to see a working example of GAE that uses Spring and the Datastore (via JPA) and is also a good starting point for building a basic GAE/J app.
Having spent about a day trying to make this work, I thought I'd add some additional useful information here. First take a look at this project https://github.com/hleinone/spring-gae-jdo and this issue: http://code.google.com/p/googleappengine/issues/detail?id=1240 -- comment 24 is the useful one.
In case anyone wants to get this working with annotation-driven configuration, here's how I did it:
package com.domain.yourcode.configuration;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jdo.GAETransactionAwarePersistenceManagerFactoryProxy;
import org.springframework.orm.jdo.JdoTransactionManager;
//import org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy;
#Configuration
public class JDOConfiguration {
private static final PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("transactions-optional");
#Bean
public GAETransactionAwarePersistenceManagerFactoryProxy proxyPmf() {
GAETransactionAwarePersistenceManagerFactoryProxy proxy =
new GAETransactionAwarePersistenceManagerFactoryProxy();
proxy.setTargetPersistenceManagerFactory(pmf);
proxy.setAllowCreate(false);
return proxy;
}
#Bean
public JdoTransactionManager transactionManager() {
JdoTransactionManager mgr = new JdoTransactionManager();
mgr.setPersistenceManagerFactory(pmf);
return mgr;
}
}
You'll still want <tx:annotation-driven/> in your applicationContext.xml

Resources