So im trying to create a remote Rest (JSON) service inside an OSGi bundle based in Felix with Maven.
my basic service interface :
#Controller
#RequestMapping("/s/fileService")
public interface RestFileService {
#RequestMapping(value = "/file", method = RequestMethod.POST)
#ResponseBody
public String getFile(Long id);
}
My implementation of the interface
public class RestFileServiceImpl implements RestFileService{
public String getFile(Long id) {
return "test service";
}
}
Normally i would add this to my web.xml
<servlet>
<servlet-name>spring-mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
And this would work fine inside a normal webapp.
But now i want to put this inside an OSGi bundle.
Servlet 3.0 allows you to use #WebServlet to declare a servlet without the web.xml
So i created a RestServlet
#WebServlet(value="/rest", name="rest-servlet")
public class RestServlet implements ServletContextListener {
private static Log sLog = LogFactory.getLog(RestServlet.class);
public void contextInitialized(ServletContextEvent arg0) {
sLog.info("initializing the Rest Servlet");
}
public void contextDestroyed(ServletContextEvent arg0) {
sLog.info("un-initializing the Rest Servlet");
}
}
This is my OSGi activator:
public class Activator implements BundleActivator {
private static Log sLog = LogFactory.getLog(Activator.class);
public void start(BundleContext context) throws Exception {
/*
* Exposing the Servlet
*/
Dictionary properties = new Hashtable();
context.registerService(RestFileService.class.getName(), new RestFileServiceImpl(), properties );
sLog.info("Registered Remote Rest Service");
}
public void stop(BundleContext context) throws Exception {
sLog.info("Unregistered Remote Rest Service");
}
}
I know Felix has its own http implementation with JAX but im trying to do this with spring annotations and as little XML as possible.
Can i force it to register the annotation driven 3.0 servlet ?
What am i doing wrong ? is this even possible ?
If you're looking for an easy way to do REST in OSGi, take a look at some of the web components provided by the Amdatu project. This page pretty much explains how to create a REST service: https://amdatu.org/application/web/ and there is also a video which will talk you through the whole process: https://amdatu.org/generaltop/videolessons/
Related
I have
#MultipartConfig(location="/tmp", fileSizeThreshold=1048576,
maxFileSize=20848820, maxRequestSize=418018841)
#Path("/helloworld")
public class HelloWorld extends HttpServlet {
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
//#Consumes()
#Produces("text/plain")
public void doPost(#Context HttpServletRequest httpRequest) {
System.out.println("pinged");
//...
}
}
and I want to access the parts and get the files. But when I do httpRequest.getPart("token") I get java.lang.IllegalStateException: Request.getPart is called without multipart configuration. How do i get this to work? I am using Jersey and I know there is a better way to do this with FormDataMultiPart but my goal is to write a function that takes a HttpServletRequest and extracts some data and turns it into a custom object. (The use of a jersey server here is purely random. I want my function to work with other java servers that my not have FormDataMultiPart but do have HttpServletRequest).
First of all this is not how JAX-RS is supposed to be used. You don't mix the JAX-RS annotations with a Servlet. What you need to do is add the multipart config into the web.xml.
<servlet>
<servlet-name>com.example.AppConfig</servlet-name>
<load-on-startup>1</load-on-startup>
<multipart-config>
<max-file-size>10485760</max-file-size>
<max-request-size>20971520</max-request-size>
<file-size-threshold>5242880</file-size-threshold>
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>com.example.AppConfig</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
Notice the servlet-name is the fully qualified class of the Application subclass.
And the rest I used to test
import javax.ws.rs.core.Application;
// if you're using `#ApplicationPath`, remove it
public class AppConfig extends Application {
}
#Path("upload")
public class FileUpload {
#POST
#Path("servlet")
public Response upload(#Context HttpServletRequest request)
throws IOException, ServletException {
Collection<Part> parts = request.getParts();
StringBuilder sb = new StringBuilder();
for (Part part: parts) {
sb.append(part.getName()).append("\n");
}
return Response.ok(sb.toString()).build();
}
}
I am new to JavaEE and am trying to create a WAR containing an application that performs a task every 30 minutes (and is started when the app is deployed), and a servlet that will allow a client to connect and get status information, using WildFly.
Is this possible? If so, how do I get WildFly to start the long running process, and how do I get it to inject that object into the servlet?
The long running application is in a class ProcessData() which uses ScheduledExecutorService to spawn a thread on a schedule to perform data management tasks, and has a getStatus() method returning a string about the processing.
This is the servlet:
#WebServlet("/procStat")
public class processorServlet extends HTTPServlet {
#Inject
ProcessData processData;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.println("<p>" + processData.getStatus() + "</p>");
writer.close();
}
}
Why you need to inject it? Can you initialize it and use it with static method or something? Here is my example for that:
public class HelloWorld extends HttpServlet
{
private static final long serialVersionUID = -1L;
ProcessData processData;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// Set response content type
response.setContentType("text/html");
// Actual logic goes here.
PrintWriter out = response.getWriter();
out.println("<h1>" + ProcessData.getStatus() + "</h1>");
}
}
After this the ProcessData class which implements javax.servlet.ServletContextListener
This listener has method which will be executed when web application initialization process is starting.
public class ProcessData implements ServletContextListener
{
private static String message;
private int counter = 0;
Runnable run = new Runnable()
{
#Override
public void run()
{
message = "counter: " + (counter++);
System.out.println(message);
}
};
#Override
public void contextInitialized(ServletContextEvent arg0)
{
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(run, 0, 1, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent arg0)
{
// Empty method
}
public static String getStatus()
{
return message;
}
}
And the web.xml add the servlet and also ServletContextListener like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>TestTask</display-name>
<servlet>
<servlet-name>HelloWorld</servlet-name>
<servlet-class>servlet.HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorld</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
<listener>
<listener-class>schedule.ProcessData</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
I ask before why you need to inject it because if you have a task which is not connected with specific user (like yours is executed regardless if the user is logon or not) then you end up in situation that many users need access to a single data. You need some kind of singleton and yes you can do it with CDI beans or other Injection technology but you also can make it working without this overhead. In my example I do it with static method and static field.
I am working with the Spark web framework and creating a RESTful API.
(http://sparkjava.com since there are multiple things out there named "Spark")
My employer's standards mandate that we write a series of unit tests that will be automatically run once a day to confirm that applications are still up.
Spark is easy to test myself using a tool like Postman but I have not found any good examples of JUnit tests being written with Spark or even with HTTP Requests being made programmatically with it.
Has anyone done this before? Is it possible?
we have develop a small library that facilitates the unit testing of Spark controllers/endpoints.
Github
Also, the version 1.1.3 is published in Maven Central Repository
<dependency>
<groupId>com.despegar</groupId>
<artifactId>spark-test</artifactId>
<version>1.1.3</version>
<scope>test</scope>
</dependency>
I had the same requirement that you and I found a way to make it work.
I searched over Spark source code and I found two classes that are useful:
SparkTestUtil: this class wraps Apache HttpClient and expose methods to make different http requests against a local web server (running in localhost) with customizable port (in constructor) and relative path (in requests methods)
ServletTest: it starts a Jetty instance in a local port with an application context and a relative directory path where a WEB-INF/web.xml file descriptor can be found. This web.xml will be use to simulate a web application. Then it uses SparkTestUtil to make http requests against this simulated application and assert results.
This is what I did: I created a junit test class that implements SparkApplication interface. In that interface I create and initialize the "controller" (a class of my application) in charge of answer http requests. In a method annotated with #BeforeClass I initialize the Jetty instance using a web.xml that refers to the junit test class as the SparkApplication and a SparkTestUtil
JUnit test class
package com.test
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.webapp.WebAppContext;
public class ControllerTest implements SparkApplication {
private static SparkTestUtil sparkTestUtil;
private static Server webServer;
#Override
public void init() {
new Controller(...)
}
#BeforeClass
public static void beforeClass() throws Exception {
sparkTestUtil = new SparkTestUtil(PORT);
webServer = new Server();
ServerConnector connector = new ServerConnector(webServer);
connector.setPort(PORT);
webServer.setConnectors(new Connector[] {connector});
WebAppContext bb = new WebAppContext();
bb.setServer(webServer);
bb.setContextPath("/");
bb.setWar("src/test/webapp/");
webServer.setHandler(bb);
webServer.start();
(...)
}
#AfterClass
public static void afterClass() throws Exception {
webServer.stop();
(...)
}
}
src/test/webapp/WEB-INF/web.xml file
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>SparkFilter</filter-name>
<filter-class>spark.servlet.SparkFilter</filter-class>
<init-param>
<param-name>applicationClass</param-name>
<param-value>com.test.ControllerTest</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SparkFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
This can be improved, but it is a good starting point I think.
Maybe some "spark-test" component could be created?
Hope this would be useful for you!
Here is my Solution.You just need additional add apache-http and junit dependency.
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
public class SparkServer {
public static void main(String[] args) {
Spark.port(8888);
Spark.threadPool(1000, 1000,60000);
Spark.get("/ping", (req, res) -> "pong");
}
}
public class SparkTest {
#Before
public void setup() {
SparkServer.main(null);
}
#After
public void tearDown() throws Exception {
Thread.sleep(1000);
Spark.stop();
}
#Test
public void test() throws IOException {
CloseableHttpClient httpClient = HttpClients.custom()
.build();
HttpGet httpGet = new HttpGet("http://localhost:8888/ping");
CloseableHttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
assertEquals(200, statusCode);
assertEquals("pong", result.toString());
}
}
Another approach wis to create a class which implements Route in each path or route. For example, if you have a route like next:
get("maintenance/task", (req, response) -> {....});
Then replace (req, response) -> {....} lambda by a class implementing Route.
For example:
public class YourRoute implements Route {
public Object handle(Request request, Response response) throws Exception {
....
}
}
Would be:
get("maintenance/task", new YourRoute());
Then you can unit testing YourRoute class using JUnit.
I use Tomcat 7 and Lo4j for all my server logs and GWT for client (only AJAX calls).
All my unhandled exceptions get logged in my catalina.log.
Now I want to catch all exceptions and add some of the user's specific Tomcat SessionData.
There are several ways:
Try catch over all servlets (there must be a better solution).
http://tomcat.apache.org/tomcat-7.0-doc/aio.html: I would have to change my connecter, and I don't know if I could use the Tomcat Session within the Event Handler (EventType.ERROR).
Better way?
What would be the best way to achieve this?
Out of what I understood from your question, you can try to use at least one of two ways:
Basic Logging Servlet
If you have access to the source code of all of your servlets, you can make a little refactoring using a basic super-servlet that is responsible for the logging/whatever of every request working transparently with AJAX, no error forwards directives, and no global exception handlers. Suppose you use service(ServletRequest,ServletResponse) as the servlet entry point (but you can do the following for every do*() method either), then you can create an abstract super-servlet and simply inherit your servlets from it.
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>stackoverflow.Servlet1</servlet-class>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>stackoverflow.Servlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>servlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet2</servlet-name>
<url-pattern>servlet2</url-pattern>
</servlet-mapping>
public abstract class BasicServlet extends HttpServlet {
/**
* Won't let it be {#code abstract} - we don't want to force any sub-servlet to implement this method.
*/
protected void doService(ServletRequest request, ServletResponse response) {
}
#Override
public final void service(ServletRequest request, ServletResponse response) {
try {
doService(request, response);
} catch ( Throwable ex ) {
err.println(ex.getMessage());
}
}
}
public final class Servlet1 extends BasicServlet {
#Override
protected void doService(ServletRequest request, ServletResponse response) {
out.println("I'm servlet #1");
}
}
public final class Servlet2 extends BasicServlet {
#Override
protected void doService(ServletRequest request, ServletResponse response) {
out.println("I'm servlet #2");
}
}
An advantage of this method is that you do not need to configure anything else than changing your servlet classes and not depend on the external configuration or context. The disadvantage is that you always must extend BasicServlet.
Filter
I didn't actually test it right now, for more information please see http://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html . Filters allow to intercept each request (we use such a filter implementation for our JSPs while debugging and writing the exceptions into the common log file). The disadvantage is that it's not guaranteed that the filter can cover every exception/case, for example if any filter preceded your own filter.
<filter>
<filter-name>exceptionLoggingFilter</filter-name>
<filter-class>stackoverflow.ExceptionLoggingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>exceptionLoggingFilter</filter-name>
<url-pattern>*</url-pattern> <!-- we will process every request -->
</filter-mapping>
public final class ExceptionLoggingFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) {
try {
filterChain.doFilter(request, response);
} catch ( Throwable ex ) {
err.println(ex);
}
}
#Override
public void destroy() {
}
}
Hope this helps.
Just Overriding the GWT function doUnexpectedFailure worked.
#Override
protected void doUnexpectedFailure(Throwable t) {
ServerLog.error(t.getMessage(), t);
super.doUnexpectedFailure(t);
}
1) You can define error page for your webapp, like this:
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error</location>
</error-page>
Then you can bind another servlet at /error and handle the exception there.
2) You can setUncaughtExceptionHandler for every HTTP connector thread. You could use this technique with servlet filter which would contain reference to the current HttpRequest (say, via a thread local). This won't work with async I/O by the way.
I am developing inherited jsp/java ee application and I would like to introduce Guice IoC container to my application. However, I found some obstacles. I can't translate web.xml entries into guice registrations if there are more then one routing to single servlet using different urls. Problem is with init-parameters.
Here are some extracts from my web.xml:
This one is unrelated to problem, but it is good example how we are using init parameters. Basically it maps users with different roles in systems to appropriate pages.
<!-- LIST INTERNSHIPS SERVLET -->
<servlet>
<servlet-name>ListInternships</servlet-name>
<servlet-class>pl.poznan.put.ims.controllers.ListInternships</servlet-class>
<init-param>
<param-name>CoordinatorPage</param-name>
<param-value>WEB-INF/pages/coordinator/listinternships.jsp</param-value>
</init-param>
<init-param>
<param-name>MentorPage</param-name>
<param-value>WEB-INF/pages/mentor/listinternships.jsp</param-value>
</init-param>
<init-param>
<param-name>AdministratorPage</param-name>
<param-value>WEB-INF/pages/administrator/listinternships.jsp</param-value>
</init-param>
<init-param>
<param-name>AllowedRoles</param-name>
<param-value>Coordinator, Mentor, Administrator</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ListInternships</servlet-name>
<url-pattern>/internships</url-pattern>
</servlet-mapping>
Those two are the troublesome ones:
<!-- CHANGE PASSWORD SERVLET -->
<servlet>
<servlet-name>ChangePassword</servlet-name>
<servlet-class>myapp.controllers.ContextForwarder</servlet-class>
<init-param>
<param-name>SharedPage</param-name>
<param-value>WEB-INF/pages/shared/password.jsp</param-value>
</init-param>
<init-param>
<param-name>AllowedRoles</param-name>
<param-value>*</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ChangePassword</servlet-name>
<url-pattern>/changepassword</url-pattern>
</servlet-mapping>
<!-- HELP SERVLET -->
<servlet>
<servlet-name>Help</servlet-name>
<servlet-class>myapp.controllers.ContextForwarder</servlet-class>
<init-param>
<param-name>SharedPage</param-name>
<param-value>WEB-INF/pages/help/help.jsp</param-value>
</init-param>
<init-param>
<param-name>AllowedRoles</param-name>
<param-value>*</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Help</servlet-name>
<url-pattern>/help</url-pattern>
</servlet-mapping>
Here is my servlet:
#Singleton
public class ContextForwarder extends HttpServlet {
private static final long serialVersionUID = 1L;
private final IUserDao dao;
#Inject
public ContextForwarder(IUserDao dao) {
this.dao = dao;
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//trying to get rid of statics, using Ioc
Validator.checkUserLoggedIn (request);
Validator.checkUserAuthorized(this, request);
User currentUser = UserManager.getCurrentUser(request);
//pick matching page for user
String userViewPage = ServletUtils.getUserURL(this, currentUser, "Page");
try {
dao.openSession();
dao.beginTransaction();
currentUser = UserManager.reloadCurrentUser(request, dao);
ServletUtils.forward(request, response, userViewPage);
dao.commit();
}
catch(ServletException e) {
dao.rollback();
throw e;
}
catch(Exception e) {
dao.rollback();
throw new ServletException(e);
}
finally {
dao.closeSession();
}
}
}
public class ServletUtils {
public static void forward(HttpServletRequest request, HttpServletResponse response, String location)
throws ServletException, IOException {
RequestDispatcher view = request
.getRequestDispatcher( response.encodeRedirectURL(location) );
view.forward(request, response);
}
public static String getUserParameter(GenericServlet servlet, User user, String suffix) {
return servlet.getInitParameter( user.getRoles() + suffix );
}
public static String getUserURL(GenericServlet servlet, User user, String suffix)
throws ResourceNotFoundException {
String URL = getUserParameter(servlet, user, suffix);
if(URL == null) {
URL = servlet.getInitParameter("Shared" + suffix);
if(URL == null)
throw new ResourceNotFoundException(suffix);
}
return URL;
}
public static void redirect(HttpServletRequest request, HttpServletResponse response, String location)
throws ServletException, IOException {
response.sendRedirect( response.encodeRedirectURL(location) );
}
}
When i try to translate it into guice (and then register this module):
public class MyServletModule extends ServletModule
{
#Override
protected void configureServlets() {
configureHelp();
configurePassword();
}
private void configureHelp()
{
Map<String, String> params = new HashMap<String, String>();
params.put("SharedPage", "WEB-INF/pages/shared/help.jsp");
params.put("AllowedRoles", "*");
serve("/help").with(ContextForwarder.class, params);
}
private void configurePassword()
{
Map<String, String> params = new HashMap<String, String>();
params.put("SharedPage", "WEB-INF/pages/shared/password.jsp");
params.put("AllowedRoles", "*");
// it's routing correctly to servlet, but it uses params from first registration,
// so that routing to jsp page is incorrect
serve("/changepassword").with(ContextForwarder.class, params);
}
}
The problem is that guice creates ContextForwarder servlet as a singleton with init parameters from the first registered method and then regardless of the request url it has parameters from the first registration. Is there any other solution to route user to different sites considering current user role? Is it possible to configure the same servlet class with two different configurations?
I have found a solution, however I am not fully satisfied with it. I found out that, in solution without guice, web container (tomcat) creates two separate servlets using the same servlet class and injecting different init parameters. Guice by default restricts servlets to be singletons, so to copy default behaviour from web.xml solution I needed to find a way to create two instance of the same class and register it twice with different parameters. I solved this by creating two sub-classes to my servlet class, both with empty body, then I registered them with different parameters.
This solution works, but it involve creating empty-body sub-classes which I am not satisfied with. It's not a problem when I got two sub-classes, but with more of them code is becoming cumbersome.