so i have this jax-rs REST project and ive never used jax in my life.
what id like to do (probably not the right way) is when someone requests something from my api they should
type url.com/token/path/sub-path/
id like to collect the : /token/path/sub-path/ part, even better put it in an array like this :
[token,path,sub-path]
the project says i should use filters. i also have another issue where when im in the filter class i dont know how to output data, to either the web page or even my eclipse console.
package com.di3;
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import com.di3.admin.AdminHandler;
public class LoginFilter implements ContainerRequestFilter{
#Context
#Override
public void filter(ContainerRequestContext request) throws IOException {
// TODO Auto-generated method stub
//do some token checking!
System.out.println(token);
}
}
thank you very much and sorry if the questions are silly or something.
Related
I am replacing PortletAdapter with GenericPortlet class in code. I followed this link - https://help.hcltechsw.com/digital-experience/9.5/dev-portlet/jsrmig.html. I am trying to initialize HATS-Host Access Transformation Services methods (see initializeHats() method) and it needs ServletConfig as a parameter. But I am not able to access the getServletConfig() method in the GenericPortlet class. I passed getPortletConfig() but got a null pointer exception. Below are my old code and new code. What is the replacement for the getServletConfig()?
Old code:
package abcpostavailablefreight;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlet.event.*;
import com.ibm.hats.runtime.connmgr.Runtime;
import com.ibm.hats.util.LicenseManager;
public class AbcPostAvailableFreightPortlet extends PortletAdapter implements ActionListener {
public void init(PortletConfig portletConfig) throws UnavailableException {
super.init(portletConfig);
}
public void initializeHats() {
initHATS = true;
//Initialize and activate the HATS runtime RAS functions,
// including tracing, logging, PII retrieval, locale.
com.ibm.hats.util.Ras.initializeRas(getServletConfig());
//Create the license manager
LicenseManager.getInstance();
//Initialize Host Publisher/connection management runtime
Runtime.initRuntime(getServletConfig());
}
}
New Code:
package abcpostavailablefreight;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.portlet.*;
import javax.portlet.UnavailableException;
import javax.servlet.*;
import javax.servlet.http.HttpSession;
public class AbcPostAvailableFreightPortlet extends GenericPortlet{
public void init(PortletConfig portletConfig) throws UnavailableException, PortletException {
super.init(portletConfig);
}
public void initializeHats(ActionRequest request) {
initHATS = true;
//Initialize and activate the HATS runtime RAS functions,
// including tracing, logging, PII retrieval, locale.
com.ibm.hats.util.Ras.initializeRas(getPortletConfig());
//Create the license manager
LicenseManager.getInstance();
//Initialize Host Publisher/connection management runtime
Runtime.initRuntime(getPortletConfig());
}
}
Lets say I wanted in implement readonly behaviour on my application (not allowing posts/puts). Could I do this by disabling these types/setting a #POST/#PUT that catches requests on any endpoint? (As opposed to putting a boolean flag on every single post/put in my application
You could add a filter, disallowing all the methods you don't want to support:
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.Provider;
#Provider
public class AuthorizationRequestFilter implements ContainerRequestFilter {
private final List<String> disallowed=Arrays.asList("POST","PUT","DELETE","PATCH");
#Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
if (disallowed.contains(requestContext.getMethod())){
requestContext.abortWith(Response
.status(Response.Status.FORBIDDEN)
.entity("User cannot modify the resource.")
.build());
}
}
}
Our project is built with spring boot. Within this project, we've built lot of REST API implementations using the java language, with REST APIs being invocable at URI end-points. Many of these REST API implementations, interact with RDBMS database at back-end (we're using postgresql). The response of all our REST APIs is JSON.
I'm writing API tests that test these REST APIs, using java within the test case, and using JUnit library to write these tests.
I'm writing two kinds of these API tests, as follows,
1) For the REST APIs, that only do read from the database, the test case implementation is simple. I use an HTTP client library from java within my test case, and issue a GET or POST request. I then do 'assert' on the returned JSON response within the test case.
2) For the REST APIs, that do one of create, update or delete on the database, I'm facing challenges to roll back from the database create, update or delete changes that my test case does. In fact, at this moment, I don't know how to roll back create, update or delete changes that my test case does, just before my test case exits. Can anyone please give pointers how to solve this?
Below is also mentioned present source code of one of my test case,
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class ApplnCommonRestControllerTest {
private static String API_URI_2 = "http://localhost:8081/appln-restapis/rest/public/common/getalluniversities";
private static CloseableHttpClient fHttpClient;
#Before
public void setUp() throws Exception {
fHttpClient = HttpClients.createDefault();
}
#After
public void tearDown() throws Exception {
fHttpClient.close();
}
#Test
public void getAllUniversitiesResponseBodyTest() throws ClientProtocolException, IOException {
HttpGet httpGet = new HttpGet(API_URI_2);
HttpResponse httpResponse = fHttpClient.execute(httpGet);
InputStream inpStream = (httpResponse.getEntity()).getContent();
String respBodyJsonString = Utilities.inputStreamToString(inpStream);
JSONObject jsonResponeObj = new JSONObject(respBodyJsonString);
JSONArray dataJsonArray = jsonResponeObj.getJSONArray("data");
assertTrue(dataJsonArray.length() >= 2); // test that array contains at least two elements
JSONObject arrElem = (JSONObject)dataJsonArray.get(0); // test first element of array
int univId = arrElem.getInt("id");
String univName = arrElem.getString("universityname");
assertTrue(univId == 1 && univName.length() > 0);
arrElem = (JSONObject)dataJsonArray.get(dataJsonArray.length() - 1);
// test last element of array
univId = arrElem.getInt("id");
univName = arrElem.getString("universityname");
assertTrue(univId > 1 && univName.length() > 0);
}
}
The above sample test case code from our project, does an HTTP GET database read only call. I'm looking for a database roll back solution for the test case, in case the REST API invoked by the test case did a database create/update/delete (i.e, just before or after the test case method exited, the database create/update/delete changes should roll back).
Generally I tend to mark all my #Test methods as #Transnational. But as your test case is completely detached from application context of course this will not help. spring has great integration test library for web layer MockMvc. Using this library your test will look like:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.transaction.annotation.Transactional;
import static org.hamcrest.Matchers.*;
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class ApplnCommonRestControllerTest {
#Autowired
MockMvc mockMvc;
#Test
#Transactional
public void getAllUniversitiesResponseBodyTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/appln-restapis/rest/public/common/getalluniversities"))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.jsonPath("$.data")
.value(iterableWithSize(2)))
.andExpect(MockMvcResultMatchers.jsonPath("$.data[0].id", is(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.data[0].universityname", not(emptyArray())))
.andExpect(MockMvcResultMatchers.jsonPath("$.data[1].id", greaterThan(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.data[1].universityname", not(emptyArray())));
}
}
And also your test will rollback as this is not really external http call and #Transactional do work in this scenario.
Lately I started working on a tomcat web service again.
I hadn't touched it in a couple of weeks, and when I went to try something I'd written, I received a 404 error.
Stumped by what was going on, I eventually decided to just write a new hello world service to see what was going on, but then that 404's too.
I don't recall any updates to Tomcat, or having tweaked any settings, yet I can no longer access any methods I write for anything and it's confusing the hell out of me.
For example, the below classes should mean that http://localhost:8080/HelloWorld/API/Test/ should return a "Hello World" message, however it 404s and I have no idea what's going on.
context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/HelloWorld"/>
Application Config:
package main;
import java.util.Set;
import javax.ws.rs.core.Application;
#javax.ws.rs.ApplicationPath("API")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(main.HWTest.class);
}
}
HWTest:
package main;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
import javax.ws.rs.core.MediaType;
#Path("/Test")
public class HWTest {
#Context
private UriInfo context;
/**
* Creates a new instance of HWTest
*/
public HWTest() {
}
/**
* Retrieves representation of an instance of main.HWTest
* #return an instance of java.lang.String
*/
#GET
#Path("/")
#Produces(MediaType.TEXT_PLAIN)
public String getText() {
//TODO return proper representation object
return "Hello world";
}
}
This definitely worked a few weeks ago, so I believe it might be something to do with a setting I accidentally tweaked, but I'm not sure as that wouldn't explain why new projects don't work either.
The problem seems to be some poor error message.
I've created a dynamic web app project in eclipse and the runtime is TomEE+ 1.7.2
So this is the publisher
package study;
import java.io.IOException;
import java.net.InetSocketAddress;
import javax.ws.rs.ext.RuntimeDelegate;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class StandaloneJaxRsServer {
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create(new InetSocketAddress(
"localhost", 8765), 8);
HttpHandler requestHandler = RuntimeDelegate.getInstance()
.createEndpoint(new JaxRSApplication(), HttpHandler.class); //<<<<< line 15
server.createContext("/jaxrs/", requestHandler);
server.start();
}
}
this is the app
package study;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath(value="/jaxrs")
public class JaxRSApplication extends Application{
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> set = new HashSet<>();
set.add(NotSingletonResource.class);
return set ;
}
//
// #Override
// public Set<Object> getSingletons() {
// Set<Object> set = new HashSet<>();
// set.add(new SingletonResource());
// return set ;
// }
}
and this is the resource
package study;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/notSingletonResource")
public class NotSingletonResource {
private volatile int counter = 0;
#GET
#Produces({MediaType.TEXT_HTML})
public String getHello() {
return "Not singleton resource " + counter++;
}
}
when I try to run StandaloneJaxRsServer.main() I get
Exception in thread "main" java.lang.IllegalArgumentException
at org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl.createEndpoint(RuntimeDelegateImpl.java:104)
at study.StandaloneJaxRsServer.main(StandaloneJaxRsServer.java:15)
However, IllegalArgumentException does not tell much. What am I doing wrong?
The javadoc for the RuntimeDelegate interface states "Throws: IllegalArgumentException - if application is null or the requested endpoint type is not supported.' For a JAX-RS Application, I think you're supposed to use org.apache.cxf.jaxrs.JAXRSServerFactoryBean, and use the result of creating the endpoint to set up a server.
I won't accept my own answer, I just want to keep here some useful information just in case someone needs it.
TomEE+ does not have the libraries to make this work. Instead, what I've did was to remove all the TomEE+ dependencies from my eclipse project, then I've converted it to a maven project just to include this dependency according to #lmiguelmh answer to this question:
Latest Jersey example does not work
Then I've just added these jersey libraries
I'll wait a little bit more before accepting an answer here, because I really would like a better answer. I am following the steps described in the book "Java Web Services, Up and Running", so I think people will really need to know this information.