I am trying to pass a String array from a Web Service to a Spring web application.
The Web Service code is :
/**
*
*/
package lnt.remote.ws;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* #author 298790
*
* This class is a JAX-WS end-point implementation and contains
* method(s) to fire batch jobs pertaining to reports
*/
#WebService
public class BatchJobWS {
private static String remoteAppURL;
private static Logger log = LoggerFactory.getLogger(Constants.WS_LOGGER);
static {
try {
Properties props = new Properties();
props.load(BatchJobWS.class.getResourceAsStream("/url.properties"));
remoteAppURL = props.getProperty(Constants.REMOTE_APP_URL);
log.info("In BatchJobWS , remote app. url is {}", remoteAppURL);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
log.error("FileNotFoundException in static block of BatchJobWS", e);
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
log.error("IOException in static block of BatchJobWS", e);
}
}
#WebMethod
public String[] generateReportBatchJob(String... params) {
HttpURLConnection httpConn;
URL remotePayrollUrl = null;
ObjectOutputStream oos = null;
String[] returnValues = null;
log.info("In BatchJobWS.generateReportBatchJob(...),params = {}",
params);
if (params == null || params.length == 0) {
return null;
}
try {
remotePayrollUrl = new URL(remoteAppURL);
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
// e1.printStackTrace();
log.error(
"MalformedURLException in BatchJobWS.generateReportBatchJob(...)",
e1);
}
/*
* Give some thought to which exception(s) be handled and which must be
* thrown
*/
try {
httpConn = (HttpURLConnection) remotePayrollUrl.openConnection();
httpConn.setDoOutput(true);
httpConn.setUseCaches(false);
oos = new ObjectOutputStream(httpConn.getOutputStream());
log.info("Writing params to the outputstream");
oos.writeObject(params);
oos.flush();
oos.close();
ObjectInputStream ois = new ObjectInputStream(
httpConn.getInputStream());
Object returnParams = ois.readObject();
log.info("Reading params from the inputstream");
if (returnParams.getClass().isArray()) {
returnValues = (String[]) returnParams;
}
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
log.error("IOException in BatchJobWS.generateReportBatchJob(...)",
e);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
log.error(
"ClassNotFoundException in BatchJobWS.generateReportBatchJob(...)",
e);
}
log.info(
"Returning from BatchJobWS.generateReportBatchJob(...),returnValues = {}",
returnValues);
return returnValues;
}
}
Initially, on the web application side, I had written a plain-old servlet as shown below :
package lnt.remote;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lnt.service.ReportService;
import lnt.utilities.BatchJobService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Servlet implementation class RemoteCallInterceptor
*/
public class RemoteCallInterceptor extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger log = LoggerFactory
.getLogger(RemoteCallInterceptor.class);
/**
* #see HttpServlet#HttpServlet()
*/
public RemoteCallInterceptor() {
// super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
log.info("In Target Payroll. RemoteCallInterceptor.doGet()");
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
log.info(
"In Target Payroll. RemoteCallInterceptor.doPost(),reportService = {}",
reportService);
BatchJobService BatchJobService = new BatchJobService();
BatchJobService.runBatchJob(request, response);
}
}
I wrote a new class BatchJobService that calls a few existing Spring beans which , in turn, have multiple Spring beans injected using #Autowire. Hence, the code in BatchJobService(which is not a Spring-managed component) was failing with NullPointerException(asthe beans were not getting injected).
Hence, to ‘inject’ BatchJobService(thereby, injecting the beans needed in BatchJobService ) in RemoteCallInterceptor, I made the latter a Spring Controller(using #Controller) and modified the doPost(…) as shown :
package lnt.remote;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lnt.service.ReportService;
import lnt.utilities.BatchJobService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Servlet implementation class RemoteCallInterceptor
*/
#Controller
public class RemoteCallInterceptor extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger log = LoggerFactory
.getLogger(RemoteCallInterceptor.class);
#Autowired
#Qualifier("ReportService")
ReportService reportService;
/**
* #see HttpServlet#HttpServlet()
*/
public RemoteCallInterceptor() {
// super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
log.info("In Target Payroll. RemoteCallInterceptor.doGet()");
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
#RequestMapping(value = "/RemoteCallInterceptor.do", method = RequestMethod.POST)
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
log.info(
"In Target Payroll. RemoteCallInterceptor.doPost(),reportService = {}",
reportService);
BatchJobService BatchJobService = new BatchJobService();
BatchJobService.runBatchJob(request, response);
}
}
But now the issue is that the code in BatchJobService that reads the object(String array written by the Web Service) from the input stream gets an EOFException.
I suppose the #RequestMapping thing caused the input stream to be consumed - is my assumption correct ? If not, how should I retrieve the String [] params – which is neither a parameter nor an attribute, in web application? If yes, what can be the work-around?
I suspect that it's broken because the Spring MVC application is broken, and that your WS client is being sent an error response. Your BatchJobWS isn't checking the HTTP response code, and is just assuming everything's fine. It's not surprising that it gets an exception.
You need to do two things. Firstly, add an explicit response status check to BatchJobWS, e.g.
HttpURLConnection httpConn;
...
oos.writeObject(params);
oos.flush();
oos.close();
if (httpConn.getResponseCode() != 200) {
// error - throw an exception, or whatever
}
Secondly, there's no point in annotating an HttpServlet with #Controller - use one or the other, not both. Remove the extends HttpServlet and make doPost public. The protected may be what's causing the error.
Related
I have this code
#Component(service = Servlet.class, scope = ServiceScope.PROTOTYPE, property={
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN+"=/content/*",
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED+"=true",
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED+"=true"}
)
#SlingServletResourceTypes(
resourceTypes="cq/Page",
methods=HttpConstants.METHOD_GET,
selectors = "asynctest",
extensions="json")
public class ReactiveServlet extends HttpServlet {
#Override
protected void doGet(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
AsyncContext async = request.startAsync();
// Some logic
}
}
When calling this servlet /content/mypage.asynctest.json then getting this error
java.lang.IllegalStateException: null
at org.apache.felix.http.base.internal.dispatch.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:338) [org.apache.felix.http.jetty:4.1.10]
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:369) [org.apache.felix.http.servlet-api:1.1.2]
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:369) [org.apache.felix.http.servlet-api:1.1.2]
The short answer is that async is NOT supported by Sling-Servlets. Your exception is thrown in this class:
https://github.com/apache/felix-dev/blob/master/http/base/src/main/java/org/apache/felix/http/base/internal/dispatch/ServletRequestWrapper.java
#Override
public AsyncContext startAsync() throws IllegalStateException
{
if ( !this.asyncSupported )
{
throw new IllegalStateException();
}
return super.startAsync();
}
But you are mixing OSGi Http-Whiteboard Pattern with Sling-Servlets. I'm not sure, what you wanted to do.
Sling/AEM is a technology-stack, where layer is built on layer. Unfortunately multiple of these layers allow registering a servlet.
Sling Servlets = Apache Sling (recommended, default)
OSGi HTTP Whiteboard Pattern = Apache Felix (only for special cases)
JEE Servlet = Jetty Servlet Container (NOT recommended)
Sling-Servlet
The Sling-Servlet you registered with #SlingServletResourceTypes doesn't support async. The output of the following servlet is: Async is not supported by an Sling-Servlet! (http://localhost:4502/content/we-retail.asynctest.json)
import static org.apache.sling.api.servlets.ServletResolverConstants.*;
import javax.servlet.AsyncContext;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.service.component.annotations.Component;
#Component(service = Servlet.class, property = {
SLING_SERVLET_RESOURCE_TYPES + "=cq:Page",
SLING_SERVLET_SELECTORS + "=asynctest",
SLING_SERVLET_EXTENSIONS + "=json",
SLING_SERVLET_METHODS + "=GET"
})
public class AsyncSlingServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(
SlingHttpServletRequest request,
SlingHttpServletResponse response
) throws ServletException, IOException {
if (request.isAsyncSupported() /* false */) {
final AsyncContext async = request.startAsync();
async.start(() -> {
async.getResponse().setContentType("text/plain");
async.getResponse().setCharacterEncoding("utf-8");
try {
async.getResponse().getWriter().println(
"Hello from the Sling-Servlet!");
} catch (IOException e) {
// ignore
}
async.complete();
});
} else {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().println(
"Async is not supported by an Sling-Servlet!");
}
}
}
OSGi HTTP Whiteboard Pattern
The almost same servlet registered via the OSGi HTTP Whiteboard pattern supports async. It returns Hello from the OSGi Http-Whiteboard Servlet! (http://localhost:4502/my-project/hello). But such servlets are aside to Sling, so they are "rivals" or "competitors". You have to be careful, not to negatively impact Sling. So the /content path should be avoided.
import javax.servlet.AsyncContext;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ServiceScope;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
#Component(
service = Servlet.class,
scope = ServiceScope.PROTOTYPE,
property = {
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN
+ "=/my-project/*",
HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT
+ "=("
+ HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME
+ "=org.apache.sling)",
HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_ASYNC_SUPPORTED
+ "=true",
HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED
+ "=true" }
)
public class AsyncOSGiServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (request.isAsyncSupported() /* true */) {
final AsyncContext async = request.startAsync();
async.start(() -> {
async.getResponse().setContentType("text/plain");
async.getResponse().setCharacterEncoding("utf-8");
try {
async.getResponse().getWriter().println(
"Hello from the OSGi Http-Whiteboard Servlet!");
} catch (IOException e) {
// ignore
}
async.complete();
});
} else {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().println(
"Async is not supported by an OSGi Http-Whiteboard Servlet!");
}
}
}
Trying to write very simple http message converter to add encryption around request & respose.
Implemented rest controller and messageConverter. writeInternal does get invoked during response. However readInternal does not get invoked when request is sent to the rest end point.
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.techm.bm.util.EncryptDecryptUtil;
#Component
public class MessageEncryptionConverter extends AbstractHttpMessageConverter<Object> {
#Autowired
private ObjectMapper objectMapper;
public MessageEncryptionConverter() {
super(MediaType.ALL);
}
#Override
protected boolean supports(Class<?> clazz) {
return true;
}
#Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return objectMapper.readValue(decrypt(inputMessage.getBody()), clazz);
}
#Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
outputMessage.getBody().write(encrypt(objectMapper.writeValueAsBytes(o)));
}
The below code is for encryption and decryption of request and response body For overall Project to modify response body and request parameters. Please check this code is works for me
For Request Encryption refer readInternal
below is the front-end or postman request sending, you have to add encrypted request in Json formate
Ex.{data : "+++++++++++++YOUR_ENCRYPTED_STRING++++++++++"}
For Response Descryption refer writeInternal
sending back to your front-end or postman request response with encrypted string
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.techm.bm.util.EncryptDecryptUtil;
#Component
public class MessageEncryptionConverter extends AbstractHttpMessageConverter<Object> {
#Autowired
private ObjectMapper objectMapper;
public MessageEncryptionConverter() {
super(MediaType.ALL);
}
#Override
protected boolean supports(Class<?> clazz) {
return true;
}
#Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return objectMapper.readValue(decrypt(inputMessage.getBody()), clazz);
}
#Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
outputMessage.getBody().write(encrypt(objectMapper.writeValueAsBytes(o)));
}
// Convert request to input stream for sending to the controller
private InputStream decrypt(InputStream inputStream) throws IOException {
//this is API request params
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} catch (UnsupportedEncodingException e) {
logger.error("UnsupportedEncodingException" + e.getMessage());
} catch (IOException e) {
logger.error("IOException" + e.getMessage());
} finally {
inputStream.close();
}
try {
JSONObject requestJsonObject = new JSONObject(writer.toString().replace("\n", ""));
// Add your decryption method the object data will get your encrypted string data and return with string of your JSON object
String decryptRequestString = EncryptionUtils.decryptText(requestJsonObject.getString("data"));
if (decryptRequestString != null) {
return new ByteArrayInputStream(decryptRequestString.getBytes(StandardCharsets.UTF_8));
} else {
return inputStream;
}
} catch (JSONException err) {
logger.error("Error" + err.toString());
} catch (NoSuchAlgorithmException | BadPaddingException | DigestException | InvalidKeyException
| InvalidAlgorithmParameterException | NoSuchPaddingException | IllegalBlockSizeException e) {
logger.info("NoSuchAlgorithmException | BadPaddingException | DigestException | InvalidKeyException | " +
"InvalidAlgorithmParameterException | NoSuchPaddingException | IllegalBlockSizeException:: " + e.getMessage());
}
return inputStream;
}
private byte[] encrypt(Object obj) throws JsonProcessingException {
// do your encryption here
try {
String stringFromObject = objectMapper.writeValueAsString(obj);
// Add your encryption method
String encrypt = EncryptionUtils.encryptText(stringFromObject);
return objectMapper.writeValueAsBytes(encrypt);
} catch (Exception e) {
logger.info("Error While Encrypt data :: " + e.getMessage());
return objectMapper.writeValueAsBytes(obj);
}
}
}
Reference code Spring Boot - Encrypt JSON data
Hope this code is working for you
It is invoking if the request has body and "supports" method return ture
I have implemented an API using spring boot and I want to track the response times of the different API calls (GET, POST, DELETE, PUT).
Currently I've been trying to use the following code as the filter
#Component
public class timeFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(timeFilter.class);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// empty
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
long time = System.currentTimeMillis();
try {
chain.doFilter(req, resp);
} finally {
time = System.currentTimeMillis() - time;
LOGGER.trace("{}: {} ms ", ((HttpServletRequest) req).getRequestURI(), time);
}
}
#Override
public void destroy() {
// empty
}
}
However, this will only track the response time of the GET call that retrieves all students from my repository.
Is there a way that I can track the response time of the other calls as well as I need to plot the response time of each calls against each other on a graph. Also is there a reason why my first GET call has a response time of around 200-300 MS but any call after that has a response time of between 0-20?
In case any one finds this useful, here is one way of doing this using reactive WebFilter
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
#Component
public class RequestTimingFilter implements WebFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(RequestTimingFilter.class);
private final boolean logParameters;
#Autowired
RequestTimingFilter(#Value("${flags.log.parameters:false}") boolean logParameters) {
this.logParameters = logParameters;
}
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
long start = System.currentTimeMillis();
String path = exchange.getRequest().getPath().toString();
StringBuilder params = new StringBuilder();
if (this.logParameters) {
String pairs = exchange.getRequest().getQueryParams().toSingleValueMap()
.entrySet()
.stream()
.map(em -> String.format("%s=%s", em.getKey(), em.getValue()))
.collect(Collectors.joining(", "));
params.append(pairs.isEmpty() ? "" : ", ").append(pairs);
}
return chain.filter(exchange)
.doOnSuccess(v -> {
long endTime = System.currentTimeMillis();
if (LOGGER.isInfoEnabled()) {
LOGGER.info("tag={}, uri=\"{}\", time={}, unit=ms{}", "request-timing",
path, (endTime - start), params.toString());
}
});
}
}
You should do with spring's OncePerRequestFilter , which should do the work and
Make sure this component is scanned.
Note here i also have dynamic property testproject.logging.includeQueryParams which you can control if you need to include query params and same goes for headers,etc..
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Implementation of Spring's {#link OncePerRequestFilter} to log each request
* including the URI, query String and execution time.
*/
#Component
public class RequestLoggingInterceptor extends OncePerRequestFilter {
/** {#code Logger} instance. */
private final Logger logger = LoggerFactory.getLogger(RequestLoggingInterceptor.class);
/** {#code true} if query parameters should be logged. */
private boolean includeQueryParams = true;
/** {#code true} if client address should be logged. */
private boolean includeClient = true;
/** {#code true} if request headers should be logged. */
private boolean includeHeaders = true;
#Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
final long start = System.nanoTime();
try {
filterChain.doFilter(request, response);
} finally {
if( logger.isInfoEnabled() ) {
final long end = System.nanoTime();
logger.info(buildMessage(request, end - start));
}
}
}
/**
* Builds the message to log from the specified {#code request} including
* the {#code executionTime}.
*
* #param request
* #param executionTime in nanoseconds
* #return log message
*/
private String buildMessage(final HttpServletRequest request, final long executionTime) {
final StringBuilder buffer = new StringBuilder();
buffer.append("method=").append(request.getMethod());
buffer.append(" uri=").append(request.getRequestURI());
if( includeQueryParams && request.getQueryString() != null ) {
buffer.append('?').append(request.getQueryString());
}
buffer.append(" executionTime=").append(executionTime);
return buffer.toString();
}
/**
* Sets whether to {#code include} the query parameter String when logging
* the request URI.
*
* #param include
*/
#Value("${testproject.logging.includeQueryParams:true}")
public void setIncludeQueryParams(final boolean include) {
includeQueryParams = include;
}
}
I am implementing OAuth2 using spring boot. And followed this example for the same
Spring-oauth2-jpa-example
Video Tutorial
After implementing I have successfully able to generate access token. But the problem is when I try to access protected resource in my case /api. I am getting 404 not found.
Main Method
package com.gatimaanBoot;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.gatimaanBoot.security.UserRepository;
#SpringBootApplication
public class GatimaanBootApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
System.out.println("booting....");
SpringApplication.run(GatimaanBootApplication.class, args);
}
/* #Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
//System.out.println(beanName);
}
};
}*/
/**
* Password grants are switched on by injecting an AuthenticationManager.
* Here, we setup the builder so that the userDetailsService is the one we coded.
* #param builder
* #param repository
* #throws Exception
*/
#Autowired
public void authenticationManager(AuthenticationManagerBuilder builder, UserRepository repository, com.gatimaanBoot.security.service.UserService service) throws Exception {
//Setup a default user if db is empty
if (repository.count()==0)
service.save(new com.gatimaanBoot.security.entities.User("user", "user", Arrays.asList(new com.gatimaanBoot.security.entities.Role("USER"), new com.gatimaanBoot.security.entities.Role("ACTUATOR"))));
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
}
/**
* We return an instance of our CustomUserDetails.
* #param repository
* #return
*/
private UserDetailsService userDetailsService(final UserRepository repository) {
return username -> new CustomUserDetails(repository.findByUsername(username));
}
}
AuthorizationServer
/**
* Copyright 2017 Duronto Technology (P) Limited . All Rights Reserved.
* Duronto Technology PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.gatimaanBoot.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
/**
*
* #version 1.0, 09-Jul-2017
* #author Nikhil
*/
/**
* Configures the authorization server.
* The #EnableAuthorizationServer annotation is used to configure the OAuth 2.0 Authorization Server mechanism,
* together with any #Beans that implement AuthorizationServerConfigurer (there is a handy adapter implementation with empty methods).
*/
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private PasswordEncoder passwordEncoder;
/**
* Setting up the endpointsconfigurer authentication manager.
* The AuthorizationServerEndpointsConfigurer defines the authorization and token endpoints and the token services.
* #param endpoints
* #throws Exception
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
/**
* Setting up the clients with a clientId, a clientSecret, a scope, the grant types and the authorities.
* #param clients
* #throws Exception
*/
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("my-trusted-client")
.authorizedGrantTypes("password","authorization_code","implicit")
.authorities("ROLE_CLIENT","ROLE_TRUSTED_CLIENT").scopes("read","write","trust")
.resourceIds("oauth2-resource").accessTokenValiditySeconds(5000).secret("secret");
}
/**
* We here defines the security constraints on the token endpoint.
* We set it up to isAuthenticated, which returns true if the user is not anonymous
* #param security the AuthorizationServerSecurityConfigurer.
* #throws Exception
*/
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
}
ResourceServer
package com.gatimaanBoot.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/api/**").authenticated();
}
}
Application.properties
#Application Path
server.contextPath = /gatimaanBoot
security.oauth2.resource.filter-order = 3
# Database
spring.datasource.driver = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/train?zeroDateTimeBehavior=convertToNull
spring.datasource.username = root
spring.datasource.password = root
# Hibernate
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.show_sql= true
spring.jpa.properties.hibernate.hbm2ddl.auto= update
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
Controller
/**
* Copyright 2017 Duronto Technology (P) Limited . All Rights Reserved.
* Duronto Technology PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.gatimaanBoot.station.controller;
/**
*
* #version 1.0, 24-Feb-2017
* #author Deepak Bisht
* #author Nikhil Mishra
*
*
*/
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.gatimaanBoot.station.dto.StationResponseDTO;
import com.gatimaanBoot.station.model.Station;
import com.gatimaanBoot.station.services.StationService;
#Controller
#RequestMapping("/api/")
public class StationController {
private static final Logger LOGGER = LoggerFactory.getLogger(StationController.class);
#Autowired
StationService stationService;
// get data for particular station
#RequestMapping(value = "/v1.0/station/{stationCode}/", method = RequestMethod.GET)
public #ResponseBody Station getStation(#PathVariable String stationCode) {
Station station = null;
try {
station = stationService.getStation(stationCode);
} catch (Exception e) {
e.printStackTrace();
}
return station;
}
/* Getting List of stations in Json format in pagination */
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.GET)
public #ResponseBody List<Station> getStationList(
#RequestParam(value = "page", required = false, defaultValue = "0") int page) {
List<Station> stationList = null;
try {
stationList = stationService.getStationList(page);
} catch (Exception e) {
LOGGER.debug("Station Controller : " + e.getMessage());
e.printStackTrace();
}
return stationList;
}
// insert new station
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.POST)
public #ResponseBody StationResponseDTO insertStation(#RequestBody Station station) {
StationResponseDTO stationDTO = null;
try {
stationDTO = stationService.insertStation(station);
} catch (Exception e) {
e.printStackTrace();
}
return stationDTO;
}
// insert new station
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.PUT)
public #ResponseBody StationResponseDTO updateStation(#RequestBody Station station) {
StationResponseDTO stationDTO = null;
try {
stationDTO = stationService.updateStation(station);
} catch (Exception e) {
e.printStackTrace();
}
return stationDTO;
}
// delete a station
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.DELETE)
public #ResponseBody StationResponseDTO deleteStation(#RequestBody Station station) {
StationResponseDTO stationDTO = null;
try {
stationDTO = stationService.deleteStation(station);
} catch (Exception e) {
e.printStackTrace();
}
return stationDTO;
}
#RequestMapping(value = "/v1.0/station/list/", method = RequestMethod.POST)
public #ResponseBody List<Station> getTrainList(#RequestBody ArrayList<String> stationList) {
return stationService.getStationListBulk(stationList);
}
}
Thanks.
I created a simple Java EE app in bluemix and deployed it. Then I created session bean and a servlet. I am unable to access the session bean method from Servlet.
Anybody has done this on bluemix?
here is my servlet code...
package nags.test.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nags.test.ejb.NagseSessionBean;
/**
* Servlet implementation class TestServlet
*/
#WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
NagseSessionBean nagsBean;
/**
* #see HttpServlet#HttpServlet()
*/
public TestServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doService(request, response);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doService(request, response);
}
public void doService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("TestServlet doService Begin");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title>Nags HTML from Servlet</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h1> This is Nags HTML5 PAge </h1>");
if (nagsBean == null){
System.out.println("TestServlet doService Unable to inject EJB");
}else{
System.out.println("TestServlet doService Able to inject EJB");
String helloString = nagsBean.sayHello("Nagarjun");
if (helloString == null){
out.println("<h1> No Response from Session Bean </h1>");
}else {
out.println("<h1> helloString </h1>");
}
}
out.println("</body>");
out.println("</html>");
System.out.println("TestServlet doService End");
//out.flush();
//out.close();
}
}
Your code has no errors, and trying on Bluemix works fine. I tried it using both a Stateless and a Stateful enterprise bean.
So probably there is an error with your Bean code.
To investigate the possible problem, retrieve the Bluemix logs using the "cf logs --recent" command and analyse the exception thrown.