How to add swagger annotation for rest endpoint #GetMapping("/**")? - web-services

I wanted to add swagger implementation for below snippet. But couldn't find exact annotation to read url input from swagger.
Tried using,
#ApiOperation(httpMethod = "GET",value = "Get Value",response = String.class)
#ApiImplicitParams({#ApiImplicitParam(name="basePath",paramType = "path")
#GetMapping(value = "/**")
public String getUrlPath(HttpServletRequest request){
return request.getServletPath();
}
above code didn't help.
#GetMapping(value = "/**")
public String getUrlPath(HttpServletRequest request){
return request.getServletPath();
}
Expectation is to get a url as input via swagger-ui and return the same as response.

Let suppose that your controller look like :
package com.sample.controller;
#RestController
#RequestMapping
#Api(value = "GreetingsController", tags = {"Just for greetings"})
Public class GreetingsController{
#ApiOperation(httpMethod = "GET", value = "Get value",notes = "description")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK !"),
#ApiResponse(code = 500, message = "Internal Error")
})
#GetMapping(value = "/")
public String getUrlPath(HttpServletRequest request){
return request.getServletPath();
}
}
The Dependency:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version> <!-- maybe there a new version -->
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version> <!-- maybe there a new version -->
</dependency>
Configurations:
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#Configurable
public class AppConfig{
public #Bean Docket restApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("GroupeName").apiInfo(apiInfo())
.select().paths(PathSelectors.regex(".*controller.*")).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("App title").description("App description")
.termsOfServiceUrl("").license("©Licence").licenseUrl("").version("1.0").build();
}
}
Application.yml:
server:
port: 8111
servlet:
context-path: /exampleApp
Access url : http://localhost:8111/exampleApp/swagger-ui.html

Related

X-Appengine-Country header shows wrong country

<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>1.0.2</version>
<scope>provided</scope>
</dependency>
POM dependency given above
import java.time.Instant;
import java.time.ZoneId;
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
public abstract class CommonGCF implements HttpFunction {
private static final String name = CommonGCF.class.getName();
protected String m_Client_IP = null;
protected String m_Client_Country = null;
protected String m_Client_Region = null;
protected String m_Client_City = null;
protected Instant m_api_invocationTime_UTC = null;
protected ZoneId m_Client_ZoneId = null;
/**
*
*/
public CommonGCF() {
}
#Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
m_api_invocationTime_UTC = Instant.now();
m_Client_IP = request.getFirstHeader("X-Forwarded-For").get();
m_Client_Country = request.getFirstHeader("X-Appengine-Country").get();
m_Client_Region = request.getFirstHeader("X-Appengine-Region").get();
m_Client_City = request.getFirstHeader("X-Appengine-City").get();
m_Client_ZoneId = this.getZoneId(m_Client_Country);
}
protected ZoneId getZoneId(String m_Client_Country2) {
System.out.println("received m_Client_Country=" + m_Client_Country2);
if (m_Client_Country2.equalsIgnoreCase("IN")) {
System.out.println("returning Asia/Kolkata");
return ZoneId.of("Asia/Kolkata");
}
System.out.println("returning UTC");
return ZoneId.of("UTC");
}
}
m_Client_Country = request.getFirstHeader("X-Appengine-Country").get();
returns TW when i invoke my cloud function from India.
when i check for my ip using other services it is showing correctly as India.
No VPN used. It was working until yesterday.
log from Google log console
2020-09-23 16:17:15.143 IST RegisterGetProfile am11zdsz2weq received
m_Client_Country2=TW
Any guidance?

HTTP Status 405 - Request method 'POST' not supported while running API using POSTMAN Client

I am executing a rest API with help of postman client as part of testing my Spring MVC application.
While testing the GET APIs I am getting correct response but while I am making a POST request through POSTMAN client I am getting 405 error
Following are my files:
WebController:
package com.websystique.springsecurity.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.websystique.springsecurity.model.Operations;
import com.websystique.springsecurity.service.KeywordService;
import com.websystique.springsecurity.service.OperationService;
#RestController
public class WebserviceController {
#Autowired
KeywordService keywordService;
#Autowired
OperationService operationService;
#RequestMapping(value = "/webservice/keywords", method = RequestMethod.GET)
public ResponseEntity<List<String>> listAllKeywords() {
List<String> keywords = keywordService.listAllKeywords();
if(keywords.isEmpty()){
return new ResponseEntity<List<String>>(HttpStatus.NO_CONTENT);//You many decide to return HttpStatus.NOT_FOUND
}
return new ResponseEntity<List<String>>(keywords, HttpStatus.OK);
}
#RequestMapping(value = "/webservice/findalloperations",method = RequestMethod.GET)
public ResponseEntity<List<Operations>> findAllOperations() {
List<Operations> operations = operationService.findAllOperations();
if(operations.isEmpty()) {
return new ResponseEntity<List<Operations>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<Operations>>(operations, HttpStatus.OK);
}
#RequestMapping(value ="/webservice/getOperation" , method = RequestMethod.POST)
public ResponseEntity<Operations> findOperationByKeyword(#RequestBody String keyword) {
System.out.println("Running webservice for keyword" + keyword);
Operations operation = operationService.findOperationByKeyword(keyword);
if(operation == null) {
return new ResponseEntity<Operations>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<Operations>(operation,HttpStatus.OK);
}
#RequestMapping(value ="/webservice/getOperation/{keyword}" , method = RequestMethod.GET)
public ResponseEntity<Operations> findOperationByKeywordGet(#PathVariable String keyword) {
System.out.println("Running webservice for keyword" + keyword);
Operations operation = operationService.findOperationByKeyword(keyword);
if(operation == null) {
return new ResponseEntity<Operations>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<Operations>(operation,HttpStatus.OK);
}
#RequestMapping(value ="/webservice/getAllOperationNames" , method = RequestMethod.GET)
public ResponseEntity<List<String>> findAllOperationName() {
System.out.println("Getting all operation names");
List<String> operationnames = operationService.findAllOperationName();
if(operationnames.isEmpty()) {
return new ResponseEntity<List<String>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<List<String>>(operationnames,HttpStatus.OK);
}
}
SecurityWebApplicationInitializer
package com.websystique.springsecurity.configuration;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfiguration:
package com.websystique.springsecurity.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
auth.inMemoryAuthentication().withUser("Ashvarya").password("ashvarya123").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//----------------------------------------------------------
.antMatchers("/index").permitAll()
.antMatchers("/webservice/**").permitAll()
//-------------------------------------------------------
.antMatchers("/", "/home").access("hasRole('USER') or hasRole('ADMIN')")
.antMatchers("/protected/**").access("hasRole('USER') or hasRole('ADMIN')")
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.and().formLogin()
.and().formLogin().loginPage("/login")
.usernameParameter("ssoId").passwordParameter("password")
.and().csrf()
.and().exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
CORSFilter:
package com.websystique.springsecurity.configuration;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("Filtering on...........................................................");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
POST URL: http://localhost:8080/AutomationToolWebPortal/webservice/getOperation
POST Request:
{
"keyword":"Click"
}
RESPONSE HEADERS RECIEVED:
Access-Control-Allow-Headers → x-requested-with, Content-Type
Access-Control-Allow-Methods → POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Origin → *
Access-Control-Max-Age → 3600
Allow → GET
Cache-Control → no-cache, no-store, max-age=0, must-revalidate
Content-Language → en
Content-Length → 1090
Content-Type → text/html;charset=ISO-8859-1
Date → Fri, 11 Sep 2015 10:36:06 GMT
Expires → 0
Pragma → no-cache
Server → Apache-Coyote/1.1
X-Content-Type-Options → nosniff
X-Frame-Options → DENY
X-XSS-Protection → 1; mode=block
I have gone through different answers for this question but most of them talk about sending csrfilter in request. Not sure how to do that in postman.
Please help

#ModelAttribute controller spring-mvc mocking

I want to test a controller which is using #ModelAttribute for one of its method arguments.
public String processSaveAction(#ModelAttribute("exampleEntity") ExampleEntity exampleEntity)
#ModelAttribute method getExampleEntity is using #RequestParam:
#ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(#RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
My controller is using WebDataBinder to call a factory, which returns an object based on param "id".
#Controller
public class ExampleController(){
#Autowired private IdEditorFactory idEditorFactory;
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(ExampleEntity.class, idEditorFactory.createEditor(ExampleEntity.class));
}
#ModelAttribute("exampleEntity")
public ExampleEntity getExampleEntity(#RequestParam(value = "id", required = true) ExampleEntity exampleEntity) {
//Irrelevant operations
return exampleEntity;
}
#RequestMapping(method = RequestMethod.POST, params = "action=save")
public String processSaveAction(
#RequestParam(value = "confirmed") String exampleString,
#ModelAttribute("exampleEntity") ExampleEntity exampleEntity,
BindingResult result, HttpServletRequest request)
throws IOException {
boolean success = editorProcessor.processSaveAction(exampleString,
exampleEntity, result, request);
return success ? getSuccessView(exampleEntity) : VIEW_NAME;
}
}
And my test:
#WebAppConfiguration
public class ExampleControllerTest{
#Mock private EditorProcessor editorProcessor;
#Mock private IdEditorFactory idEditorFactory;
#InjectMocks private ExampleController exampleController;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(exampleController).build();
WebDataBinder webDataBinder = new WebDataBinder(ExampleEntity.class);
webDataBinder.registerCustomEditor(ExampleEntity.class, idEditorFactory.createEditor(ExampleEntity.class));
}
#Test
public void shouldProcessSaveAction() throws Exception {
// given
BindingResult result = mock(BindingResult.class);
ExampleEntity exampleEntity = mock(ExampleEntity.class);
HttpServletRequest httpServletRequest = mock(HttpServletRequest.class);
given(editorProcessor.processSaveAction("confirmed", exampleEntity, result, httpServletRequest)).willReturn(true);
// when
ResultActions perform = mockMvc.perform(post("/").sessionAttr("exampleEntity", exampleEntity)
.param("id", "123456"
.param("action","save"));
// then
perform.andDo(print())
.andExpect(status().isOk());
}
}
I want to somehow mock getExampleEntity() so that every time I perform a POST with parameter "id", I receive a mocked object ("exampleEntity") for the test.
I could introduce #Binding to the test, but then I would have to mock many levels of methods (like initBinder -> idEditoryFactory-> editor -> hibernateTemplate and so on) only to get an entity from some source (for example, a database).
You can pass in the required #ModelAttribute object with the .flashAttr() method like so:
mockMvc.perform(post("/")
.param("id", "123456")
.param("action","save")
.flashAttr("exampleEntity", new ExampleEntity()));
First, test code shouldn't change our development code. #ModelAttribute will be mount from your param attribute, so .param() is enough. Below is my demo:
#Test
public void registerUser() throws Exception {
System.out.println("hello......." + rob.toString());
RequestBuilder request = post("/register.html")
.param("username", rob.getUsername())
.param("password", rob.getPassword())
.param("firstName", rob.getFirstName())
.param("lastName", rob.getLastName())
.param("email", rob.getEmail())
.with(csrf());
mvc
.perform(request)
.andDo(MockMvcResultHandlers.print())
.andExpect(redirectedUrl("/"));
}
Then is my #Controller:
#Controller
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = "/remove", method = RequestMethod.GET)
public String removeById(#RequestParam("userid") int id, RedirectAttributes attr) {
attr.addFlashAttribute("message", "remove!!!");
attr.addAttribute("mess", "remove ");
return "redirect:/userlist.html";
}
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(#ModelAttribute("user") User user, ModelMap model) {
System.out.println("register " + user.toString());
boolean result = userService.add(user);
model.addAttribute("message", "add " + (result ? "successed" : "failed") + "!!!");
return "/";
}
}
This can submit the right user object to the public String register(#ModelAttribute("user") User user, ModelMap model).
I'm new to Spring MVC, and currently writing a #Controller class but none of the methods have business logic, let alone HTML files for the views under'/static/'. First, I wanted to see how I can Unit Test every method to make sure all end points responded 200/ok before I inserted the business logic, you know Test Driven Development. Then I had difficulty when unit testing #PostMapping annotation method that had a #ModelAttribute assigned to it. After my whole search yesterday, I put together code for someone to unit test such cases involving #PostMapping and #ModelAttribute where you need to update the parameter values of your model attribute on the 'post' method. I'm more than welcome positive feedback to make my tests better, just wanted to post this in cases someone else that's also new wanted to test and make sure that the new info will be saved after the post in the #ModelAttribute without needing a html/jsp file for views for standalone unit testing, look at #Controller2 and String updateQuoteRequest() method for reference, and the last test in class QuoteRequestManagementController_UnitTests for more details.
pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-mvc-hotel-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>serving-web-content</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- Spring Boot Test Starter is Starter for testing Spring Boot applications
with libraries including JUnit, Hamcrest and Mockito. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Model Attribute Class:
package com.corplithotel.eventsapp.domain;
//Create the Model Attribute class, and its class members
public class QuoteRequest {
String customer;
String age;
String budget;
String eventType;
String foodAllergies;
//getters and setters
public String getCustomer() {
return customer;
}
public void setCustomer(String customer) {
this.customer = customer;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getBudget() {
return budget;
}
public void setBudget(String budget) {
this.budget = budget;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public String getFoodAllergies() {
return foodAllergies;
}
public void setFoodAllergies(String foodAllergies) {
this.foodAllergies = foodAllergies;
}
}
Main Class:
package com.corplithotel.eventsapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CorpLitHotel {
public static void main(String[] args) {
SpringApplication.run(CorpLitHotel.class, args);
}
}
#Controller1
package com.corplithotel.eventsapp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.corplithotel.eventsapp.domain.QuoteRequest;
//Step 1: * Create QuoteRequestController *
/*#Conroller annotation makes this class a controller, next we need to
* add 'handler mappings' to provide the controller some functionality.
* For Step 1, we won't add logic for #RequestMapping 'beginQuoteRequest()'
* & #Postrequest 'submitQuoteRequest()' methods, we will Mock the class
* and unit test in Step 2 for TDD examples:
*
*
*/
#Controller
public class QuoteRequestController {
/*#GetMapping annotation is a 'handler mapping' annotation.
* When a user comes to the page to fill out the Quote form, they
* first need to get the page. The return of the method will be a
* 'logical view name', which is just a string, and tends to correlate
* to some HTML, JSP or whatever file you're using for your View.
*
*/
#GetMapping("/newquote")
public String beginQuoteRequest(Model model) {
//Check Unit Test for logic
return "newQuote";
}//beginQuoteRequest()
/*#PosMapping annotation is another 'handler mapping' annotation.
* Once a user fills out the Quote form with their name and
* other event details, they may want to save or post that quote.
* We need to add a handler for the Post, and needs to be a separate
* method. Will be a separate page with a confirmation message to let
* the user know their Quote request has been received.
*/
#PostMapping("/newquote")
public String submitQuoteRequest(#ModelAttribute QuoteRequest formBean) {
//Check Unit Test for ideal logic
return "newQuoteConfirmation";
}//submitQuoteRequest()
}
Controller 1 Unit Tests:
package com.corplithotel.eventsapp.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.corplithotel.eventsapp.domain.QuoteRequest;
/*Step 2 *Create Unit tests for QuoteRequestController*:
* this tests are assuming
*/
#ExtendWith(MockitoExtension.class)
#WebMvcTest( QuoteRequestController.class)
#TestInstance(Lifecycle.PER_CLASS)
public class QuoteRequestController_UnitTests {
#Mock
private WebApplicationContext wac;
#InjectMocks
private QuoteRequestController qrc;
private MockMvc qrcMockMvc;
#BeforeAll
public void setUp() {
qrcMockMvc = MockMvcBuilders.standaloneSetup(qrc).build();
}//BeforeAll
#Test
#DisplayName("testGetQuoteForm.. beginQuoteRequest().. Expected to pass..")
public void testGetQuoteForm() throws Exception {
//simulate getting a new form for the user to fill in (GET)
qrcMockMvc
.perform(get("/newquote"))
.andExpect(status().is(200))
.andReturn();
}//testGetQuoteForm()
#Test
#DisplayName("testPostQuoteForm().. submitQuoteRequest.. Expected to pass..")
public void testPostQuoteForm() throws Exception {
QuoteRequest aFormBean = new QuoteRequest();
qrcMockMvc
.perform(post("/newquote", aFormBean))
.andExpect(status().isOk())
.andReturn();
}//testGetQuoteForm()
}// QuoteRequestController_UnitTests
Result 1:
Junit Controller 1 Results
Controller 2:
package com.corplithotel.eventsapp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.corplithotel.eventsapp.domain.QuoteRequest;
/*Step 3 *Creating QuoteRequestManagementController
* This is the controller that the sales team member
* uses to reply to a customer's request for an estimate.
* Sale's Team member can see all the incoming requests.
*
*Controller method's body for Step 3 will be empty, we will unit test
* every method of the Controller first in Step 4.
*/
#Controller
public class QuoteRequestManagementController {
/*
* We will be specifying, parameters, look for a parameter of
* a particular value; or looking for the absence of a parameter
*/
//Specifying: Sale's Team member can see all the incoming requests.
#GetMapping(path = "/quoteRequests")
public String listQuoteRequests() {
return "quoteRequestsList";
}//listRequests()
/*Parameter Of A Specific Value: Narrow down search for different
* types of sales reps. Look for 'eventType' = 'wedding' for sales reps that
* only deal with weddings and only see events associated
* with weddings.
*/
#GetMapping(path = "/quoteRequests", params="eventType=wedding")
public String listWeddingRequests() {
return "quoteWeddingRequestsList";
}//listWeddingRequests()
/*Parameter Of A Specific Value: Narrow down search for different types of sales
reps.
* Look for 'eventType' = 'birthday' for sales reps that
* only deal with weddings and only see events associated
* with weddings.
*/
#GetMapping(path = "/quoteRequests", params="eventType=birthday")
public String listBirthdayRequests() {
return "quoteBirthdayRequestsList";
}//listBirthdayRequests()
/*
* Look for 'eventType' parameter regardless of its value
*/
#GetMapping(path = "/quoteRequests", params="eventType")
public String listAllEventTypeRequests() {
return "quoteAllEventTypeRequestList";
}//listAllEventTypeRequests()
/*
* Absence of a parameter: Look for requests with no 'eventType' parameter
*/
#GetMapping(path = "/quoteRequests", params="!eventType")
public String listNoneEventTypeRequests() {
return "quoteNoneEventTypeRequestsList";
}//listNoneEventTypeRequests()
/*
* Specifying: Create another mapping for a sales rep to drill down
* from what I see in a list and pick one particular quote
* request. We will accomplish this by providing each
* quote request a unique quoteID using #PathVariable
*/
#GetMapping("/quoteRequests/{quoteID}")
public String viewQuoteRequest(#PathVariable int quoteID) {
//refer to quoteID in my implementation
return "quoteRequestsDetails";
}//viewQuoteRequest()
/*
*For this scenario lets say a sales rep is in a particular
* quote and maybe want to add a note, which will require them
* to save the content of the screen. This means we need a
* #PostMapping. The sales rep might want to update the customer
* name, event type, food allergy side note, etc.
*
*Once they hit 'save', all the data will come in and be accessible
* through #ModelAttribute and we can reference the Model Attribute in
* the method signature. So as we implement the logic in the controller
* we get to use a Model Bean and pull in all the updated data
* and ultimately save the data somewhere.
*/
#PostMapping ("/quoteUpdateDetails")
public String updateQuoteRequest(
#ModelAttribute("quoteRequest") QuoteRequest quoteRequest) {
//implement a save of all the form bean information
return "quoteUpdateDetails";
}//updateQuoteRequest()
}
Controller 2 Unit Test:
package com.corplithotel.eventsapp.controller;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import
org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.corplithotel.eventsapp.domain.QuoteRequest;
#ExtendWith(MockitoExtension.class)
#WebMvcTest( QuoteRequestManagementController.class)
#TestInstance(Lifecycle.PER_CLASS)
class QuoteRequestManagementController_UnitTests {
#Mock
private WebApplicationContext wac;
#InjectMocks
private QuoteRequestManagementController qrmc;
private MockMvc qrmcMockMvc;
#BeforeAll
public void setUp() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/");
viewResolver.setSuffix(".html");
qrmcMockMvc=
MockMvcBuilders.standaloneSetup(qrmc)
.setViewResolvers(viewResolver).build();
}//BeforeAll
#Test
#DisplayName("testListQuoteRequests().. Test should pass")
void testlistQuoteRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests"))
.andExpect(status().is(200))
.andReturn();
}//testlistRequests()
#Test
#DisplayName("testListWeddingRequests() .. Parameter Of A Specific Value Test1.. Test should pass")
void testlistWeddingRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?eventType=wedding"))
.andExpect(status().is(200))
.andReturn();
}//testlistWeddingRequests()
#Test
#DisplayName("testListBirthdayRequests() .. Parameter Of A Specific Value Test2.. Test should pass")
void testlistBirthdayRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?eventType=birthday"))
.andExpect(status().is(200))
.andReturn();
}//testlistBirthdayRequests()
#Test
#DisplayName("testListAllEventsRequests() .. Parameter with no specified value.. Test should pass")
void testlistAllEventsRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?eventType"))
.andExpect(status().is(200))
.andReturn();
}//testlistBirthdayRequests()
#Test
#DisplayName("testNoneEventTypeRequests() .. no parameter .. Test should pass")
void testNoneEventTypeRequests() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests?!eventType"))
.andExpect(status().is(200))
.andReturn();
}//testlistBirthdayRequests()
#Test
#DisplayName("testViewQuoteRequest().. by 'quoteID'.. Test should pass")
void testViewQuoteRequest() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests/{quoteID}", 4))
.andExpect(status().is(200))
.andReturn();
}//testViewQuoteRequest()
#Test
#DisplayName("test2ViewQuoteRequest().. by 'quoteID'.. Test should pass")
void tes2tViewQuoteRequest() throws Exception {
qrmcMockMvc
.perform(get("/quoteRequests/{quoteID}", 415))
.andExpect(status().is(200))
.andReturn();
}//testViewQuoteRequest()
#Test
void testupdateQuoteRequest() throws Exception {
MockHttpServletRequestBuilder updateDetails = post("/quoteUpdateDetails")
.param("customer", "Joe")
.param("age", "12")
.param("budget", "$1209")
.param("eventType", "wedding")
.param("foodAllergies", "fish")
.flashAttr("quoteRequest", new QuoteRequest());
qrmcMockMvc
.perform( updateDetails)
.andExpect(status().is(200));
}
}

Endpoint Publish for REST Web Services

I've published JAX-WS web services with Endpoint.publish during development. Is there any such utility class exists (in JAX-RS) for publishing REST web services in jersey? I referred couple of articles, and majority of them are based on publishing the web services in some containers like Jetty, Grizzly etc.
Jersey-Grizzly has a very simple solution. From https://github.com/jesperfj/jax-rs-heroku:
package embedded.rest.server;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;
#Path("/hello")
public class Main {
public static void main(String[] args) {
final String baseUri = "http://localhost:7080/";
final Map<String, String> initParams = new HashMap<String, String>();
// Register the package that contains your javax.ws.rs-annotated beans here
initParams.put("com.sun.jersey.config.property.packages","embedded.rest.server");
System.out.println("Starting grizzly...");
try {
SelectorThread threadSelector =
GrizzlyWebContainerFactory.create(baseUri, initParams);
System.out.println(String.format("Jersey started with WADL "
+ "available at %sapplication.wadl.", baseUri));
}
catch(Exception e) {
e.printStackTrace();
}
}
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Well, this was easy!";
}
}
If you're using Maven, you'll need the following three dependencies:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-grizzly</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.sun.grizzly</groupId>
<artifactId>grizzly-servlet-webserver</artifactId>
<version>1.9.18-i</version>
</dependency>
To test it, just open http://localhost:7080/hello in a browser.
I think you can use Provider interface to publishing a RESTful Web Service with JAX-WS.
The example class:
#WebServiceProvider
#BindingType(value=HTTPBinding.HTTP_BINDING)
public class AddNumbersImpl implements Provider {
#Resource
protected WebServiceContext wsContext;
public Source invoke(Source source) {
try {
MessageContext mc = wsContext.getMessageContext();
// check for a PATH_INFO request
String path = (String)mc.get(MessageContext.PATH_INFO);
if (path != null && path.contains("/num1") &&
path.contains("/num2")) {
return createResultSource(path);
}
String query = (String)mc.get(MessageContext.QUERY_STRING);
System.out.println("Query String = "+query);
ServletRequest req = (ServletRequest)mc.get(MessageContext.SERVLET_REQUEST);
int num1 = Integer.parseInt(req.getParameter("num1"));
int num2 = Integer.parseInt(req.getParameter("num2"));
return createResultSource(num1+num2);
} catch(Exception e) {
e.printStackTrace();
throw new HTTPException(500);
}
}
private Source createResultSource(String str) {
StringTokenizer st = new StringTokenizer(str, "=&/");
String token = st.nextToken();
int number1 = Integer.parseInt(st.nextToken());
st.nextToken();
int number2 = Integer.parseInt(st.nextToken());
int sum = number1+number2;
return createResultSource(sum);
}
private Source createResultSource(int sum) {
String body =
"<ns:addNumbersResponse xmlns:ns="http://java.duke.org"><ns:return>"
+sum
+"</ns:return></ns:addNumbersResponse>";
Source source = new StreamSource(
new ByteArrayInputStream(body.getBytes()));
return source;
}
}
To deploy our endpoint on a servlet container running with the JAX-WS
RI we need to create a WAR file.
The adjusted web.xml:
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener>
<servlet>
<servlet-name>restful-addnumbers</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restful-addnumbers</servlet-name>
<url-pattern>/addnumbers/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
and need to add sun-jaxws.xml deployment descriptor to the WAR file.
<endpoints
xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">
<endpoint
name="restful-addnumbers"
implementation="restful.server.AddNumbersImpl"
wsdl="WEB-INF/wsdl/AddNumbers.wsdl"
url-pattern="/addnumbers/*" />
</endpoints>
Or could be create simple HttpServer
import java.io.IOException;
import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.net.httpserver.HttpServer;
public class YourREST {
static final String BASE_URI = "http://localhost:9999/yourrest/";
public static void main(String[] args) {
try {
HttpServer server = HttpServerFactory.create(BASE_URI);
server.start();
System.out.println("Press Enter to stop the server. ");
System.in.read();
server.stop(0);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Web service soap header authentication

I have a web service, i want to authenticate the user from the soap header. That is, i want to check a token id (random number) in soap header and validate it against a value in my database and if the number matches i allow the request to go through otherwise i dont want to allow execution of my web method.
Is there any clean way of doing it using SOAP headers?
Thanks,
Mrinal Jaiswal
Have you looked into WS-Security? Assuming you're not already using it for something else, you could carry your token in the Username element, etc.
<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1">
<wsse:Username>yourusername</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">yourpassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<yourbodygoeshere>
</soapenv:Body>
</soapenv:Envelope>
I created a web service using JDK API, and do a simple authentication by soap header.
This simple project provide two services:
login
get message from server
Client posts username and password in the soap body to server, if login successfully, the server will return a token in the soap header.
Clients calls getMessage service by including this token in the soap header, server check the token, if it is a logged in user, then return a success message, otherwise return a failed message.
The following is the code:
package com.aug.ws;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.Holder;
//Service Endpoint Interface
#WebService
#SOAPBinding(style = Style.RPC)
public interface HelloWorld {
#WebMethod
void login(String userName, String password, #WebParam(header = true, mode = Mode.OUT, name = "token") Holder<String> token);
String getMessage(String message);
}
package com.aug.ws;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebParam.Mode;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import com.sun.xml.internal.ws.api.message.Header;
import com.sun.xml.internal.ws.api.message.HeaderList;
import com.sun.xml.internal.ws.developer.JAXWSProperties;
#WebService(endpointInterface = "com.aug.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
private Map<String, String> authorizedUsers = new HashMap<String, String>();
#Resource
WebServiceContext wsctx;
#Override
#WebMethod
public void login(String userName, String password, #WebParam(header = true, mode = Mode.OUT, name = "token") Holder<String> token) {
if (("user1".equals(userName) && "pwd1".equals(password)) || ("user2".equals(userName) && "pwd2".equals(password))) {
String tokenValue = "authorizeduser1234" + userName;
token.value = tokenValue;
authorizedUsers.put(tokenValue, userName);
System.out.println("---------------- token: " + tokenValue);
}
}
#Override
#WebMethod
public String getMessage(String message) {
if (isLoggedInUser()) {
return "JAX-WS message: " + message;
}
return "Invalid access!";
}
/**
* Check token from SOAP Header
* #return
*/
private boolean isLoggedInUser() {
System.out.println("wsctx: " + wsctx);
MessageContext mctx = wsctx.getMessageContext();
HeaderList headerList = (HeaderList) mctx.get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
String nameSpace = "http://ws.aug.com/";
QName token = new QName(nameSpace, "token");
try {
Header tokenHeader = headerList.get(token, true);
if (tokenHeader != null) {
String user = authorizedUsers.get(tokenHeader.getStringContent());
if (user != null) {
System.out.println(user + " has logged in.");
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
package com.aug.endpoint;
import javax.xml.ws.Endpoint;
import com.aug.ws.HelloWorldImpl;
public class HelloWorldPublisher {
/**
* #param args
*/
public static void main(String[] args) {
Endpoint.publish("http://localhost:9000/ws/hello", new HelloWorldImpl());
System.out.println("\nWeb service published # http://localhost:9000/ws/hello");
System.out.println("You may call the web service now");
}
}
package com.aug.client;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.aug.ws.HelloWorld;
import com.sun.xml.internal.ws.api.message.HeaderList;
import com.sun.xml.internal.ws.api.message.Headers;
import com.sun.xml.internal.ws.developer.JAXWSProperties;
import com.sun.xml.internal.ws.developer.WSBindingProvider;
public class HelloWorldClient {
private static final String WS_URL = "http://localhost:9000/ws/hello?wsdl";
private static final String NAME_SPACE = "http://ws.aug.com/";
public static String login() throws Exception {
URL url = new URL(WS_URL);
QName qname = new QName(NAME_SPACE, "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
hello.login("user1", "pwd1", null);
WSBindingProvider bp = (WSBindingProvider) hello;
HeaderList headerList = (HeaderList) bp.getResponseContext().get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
bp.close();
return headerList.get(new QName(NAME_SPACE, "token"), true).getStringContent();
}
public static void getMessage() throws Exception {
String token = login();
System.out.println("token: " + token);
URL url = new URL(WS_URL);
QName qname = new QName(NAME_SPACE, "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
WSBindingProvider bp = (WSBindingProvider) hello;
bp.setOutboundHeaders(
Headers.create(new QName(NAME_SPACE, "token"), token)
);
System.out.println(hello.getMessage("hello world"));
bp.close();
}
public static void main(String[] args) throws Exception {
getMessage();
}
}