How to restrict to a list of query params for a REST api - rest

I want to restrict to a set of query params for rest Method.
#Path("/users")
public class UserService {
#GET
#Path("/query")
public Response getUsers(
#QueryParam("from") int from,
#QueryParam("to") int to,
#QueryParam("orderBy") List<String> orderBy) {
return Response
.status(200)
.entity("getUsers is called, from : " + from + ", to : " + to
+ ", orderBy" + orderBy.toString()).build();
}
}
“users/query?from=100&to=200&orderBy=age&orderBy=name” [WORKS]
“users/query?x=y” [also works and when my query params are set with default values]
i want throw some exceptions based on that.

Related

returning a value using REST

I am getting errors when I am trying to return values using REST. The error is:
A HTTP GET method, public - should not consume any entity.
This is my class:
public class StockManagement {
ArrayList<String> items = new ArrayList<>();
ArrayList<Integer> stockLevel = new ArrayList<>();
#GET
#Produces("application/xml")
public String addItem(String item) {
if(items.contains(item)) { // returns true is item is exists else false
String r = "Item is already in list";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>"+ "<div>" + result + "</div>" +"</StockManagementService>";
}
else {
String r = "Item has been added successfully";
String result = "#Produces(\"application/xml\")" + r;
items.add(item); // add item to inventory
stockLevel.add(0); // set the number of stock for the item in inventory
return "<StockManagementService>" +"<div>" + result + "</div>" +"</StockManagementService>";
}
}
#GET
#Produces("application/xml")
public String setStock(String item, int stockLevels) {
if(!items.contains(item)) {
String r = "Item is not in the inventory";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
else {
int index = items.indexOf(item);
stockLevel.set(index, stockLevels);
String r = "Set stock has been complete successfully";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
}
#GET
#Produces("application/xml")
public String addStock(String item, int numItem) {
if(!items.contains(item)) {
String r = "Error, Cannot add item";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
else {
int index = items.indexOf(item);
String r = "Successfully added stock";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
}
#GET
#Produces("application/xml")
public String removeStock(String item, int numItem) {
if(items.contains(item)) {
int index = items.indexOf(item);
int val = stockLevel.get(index);
val = val - numItem;
stockLevel.set(index, val);
String r = "Successfully removed item.";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
else {
String r = "Item is not in the inventory";
String result = "#Produces(\"application/xml\")" + r;
return "<StockManagementService>" + result + "</StockManagementService>";
}
}
This is the error shown on eclipse terminal:
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int), should not consume any entity.
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.addStock(java.lang.String,int), should not consume any entity.
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.removeStock(java.lang.String,int), should not consume any entity.
WARNING: A HTTP GET method, public java.lang.String com.crunchify.restjersey.StockManagement.addItem(java.lang.String), should not consume any entity.
SEVERE: Consuming media type conflict. The resource methods public java.lang.String com.crunchify.restjersey.StockManagement.addStock(java.lang.String,int) and public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int) can consume the same media type
SEVERE: Consuming media type conflict. The resource methods public java.lang.String com.crunchify.restjersey.StockManagement.removeStock(java.lang.String,int) and public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int) can consume the same media type
SEVERE: Consuming media type conflict. The resource methods public java.lang.String com.crunchify.restjersey.StockManagement.addItem(java.lang.String) and public java.lang.String com.crunchify.restjersey.StockManagement.setStock(java.lang.String,int) can consume the same media type
I cannot figure out what this error means, obviously it has to be the way I am returning, any help would be appreciated.
Thanks.
No promises, but I think the WARNING is trying to remind you that, in HTTP, GET doesn't take a message body. So String item should probably be encoded into the URI itself, which might mean a #QueryParam or #PathParam annotation.
SEVERE is trying to tell you that there are multiple methods that are all trying to be mapped to the same route. That is to say, they are all mapped to the same URI with the same method and the same application type, so how is the routing logic supposed to choose between them.
That might mean that you need to specify different paths for each, or that you should have only one annotated method that has the logic to choose which implementation to use.

How to print some logs "before" a spring-data repository method, without custom repo

I have a Spring data repository.
When http://localhost:8080/persons webservice is called, I want to log something. I DO NOT want to make MyCustomRepository<>. Cleaner options?
Repo class:
#RepositoryRestResource(collectionResourceRel = "persons", path = "persons")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
Sample log:
log.error("AccessToken: " + securityContext.getTokenString());
log.error("User: {} / {}", accessToken.getPreferredUsername(), accessToken.getName());
log.error("Principal: {}", principal.getName());
You can create an aspect to intercept calls to your PersonRepository. From there you can access OAuth2 access token and the security context to retrieve the principal. Here is an example,
#Component
#Aspect
#Log
public class SecurityAspect {
#Autowired
private OAuth2ClientContext oauth2ClientContext;
#Pointcut("execution(public * my.example.repository.PersonRepository.*(..))")
public void pointcut() {
}
#Around("pointcut()")
public Object advice(ProceedingJoinPoint pjp) throws Throwable {
log.info(
"Entering SecurityAspect.advice() in class "
+ pjp.getSignature().getDeclaringTypeName()
+ " - method: " + pjp.getSignature().getName());
OAuth2AccessToken accessToken = oauth2ClientContext.getAccessToken();
log.info("AccessToken: " + accessToken);
if (SecurityContextHolder.getContext().getAuthentication()
instanceof OAuth2Authentication) {
OAuth2Authentication authentication =
(OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
if (authentication.getUserAuthentication() instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken userToken =
(UsernamePasswordAuthenticationToken) authentication.getUserAuthentication();
log.info("Principal id: " + userToken.getPrincipal());
if (userToken.getDetails() instanceof Map) {
Map details = (Map) userToken.getDetails();
log.info("Principal Name: " + details.get("name"));
}
}
}
return pjp.proceed();
}
}

RestEasy - Unable to find MessageBodyReader ... application/xml?

i try since 2 days to find something about this problem, still don't get it. I got my Maven-Project running on Wildfly.
Rest-Code:
#Override
#GET
#Path("{id}")
// #Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Customer getOverId(#PathParam("id") String id) {
logger.info("put in " + this.getClass().getName() + " over id " + id);
// if (id != null) {
// Customer object = service.loadOneCustomer(new Integer(id));
// logger.info("found in " + this.getClass().getName());
// return Response.ok(object).build();
// }
Customer customer = service.loadOneCustomer(new Integer(id));
// logger.info("nix found");
if(customer == null) {
throw new NotFoundException("No customer found with the matching ID: " + id);
}
logger.info("Customer found: " + customer.getCustomerNumber());
// return Response.status(Status.BAD_REQUEST).build();
return customer;
}
Client-Implementation:
public Response readCustomer(String id){
log.info("Starting: Rest get a Customer with ID: " + id);
log.info(this.URL);
this.customerWebTarget = this.client.target(this.URL).path(id);
Response response = this.customerWebTarget.request().buildGet().invoke();
// TODO Customer cast application_xml auf Customer? Customer customer = response.readEntity(Customer.class);
Customer customer = response.readEntity(Customer.class);
log.info("Ending: Rest invoque a Customer with ID:" + customer.getCustomerNumber());
// System.out.println("Ending: Rest get a Customer with ID: " + response.readEntity(String.class));
return response;
}
J-Unit Test:
#Test
public void testGetCustomerById() throws Exception {
Response response = this.customerRestClient.readCustomer("112");
System.out.println("--->" + response.getStatus());
Assert.assertTrue(response.getStatus() == 200);
}
Everything works perfekt till i try to get the Java-Object from the XML i get (Customer customer = response.readEntity(Customer.class);)
Am i missing something. I mean, i get read the xml-File and see every data in it... Why can't i cast it into Java-Object?
I always get this Error:
Javax.ws.rs.ProcessingException: Unable to find a MEssageBody of content-type-application/xml and type class de.....model.Customer
Without seeing the Customer class, it's hard to tell, but most likely some or all JAXB annotations are missing. In particular, you'll need an #XmlRootElement annotation.
Can you post the Customer class please. Was it properly annotated?
Also add the #Produces back in.

Use Google volley api to send HTTP POST request of RDF data

So, I have recently integrated the Volley API in my app in order to provide a Cloud storage solution (REST). Since, i have never used the API before i have some trouble trying to send RDF (text/turtle) data via HTTP POST. The REST server is working perfectly since I send GET and POST requests (via the Postman Chrome app) and every time i receive 200 and 201 responses. Although i managed to send a simple GET request via the API, i get a 400 error when i send an HTTP POST.
The code is the following:
//the RDF turtle payload to send over HTTP POST
final String bodyPost = "#prefix : <http://xxx.xxx.xxx.gr/xxx/schema/xxx#> ." + "\n" +
"#prefix xsd: <http://www.w3.org/2001/XMLSchema#> ." + "\n" +
"[a :Patient ;" + "\n" +
":lastName "+'"'+"Aylakiotis"+'"'+"^^xsd:string ; " + "\n" +
":firstName "+'"'+"Yiannis"+'"'+"^^xsd:string ;" + "\n" +
":dateOfBirth "+'"'+"1970-04-14"+'"'+"^^xsd:date ;" + "\n" +
":amka "+'"'+"12345678903"+'"'+"^^xsd:string ;" + "\n" +
":gender :Male ;" + "\n" +
"] .";
RequestQueue queue = Volley.newRequestQueue(this);
final String URL ="http://xxx.xxx.xxx:8080/xxx/";
EditText folderTitle = (EditText) findViewById(R.id.folderTitle);
StringRequest strReq = new StringRequest(Request.Method.POST, URL,
new Response.Listener() {
#Override
public void onResponse(Object response) {
folderTitle.setText("Response is: " + response.toString().substring(0,500));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
folderTitle.setText("Error: " + error.getMessage());
}
}) {
#Override
public byte[] getBody() throws AuthFailureError {
System.out.println("string post data: " + bodyPost);
if (params != null && params.size() > 0) {
System.out.println("string post data: " + bodyPost);
return encodeParameters(params, getParamsEncoding());
}
return bodyPost.getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
String creds = String.format("%s:%s", "xxx", "xxx");
String auth = "Basic " + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);
headers.put("Authorization", auth);
headers.put("Content-Type", "text/turtle");
return headers;
}
};
// Add the request to the RequestQueue.
queue.add(strReq);
String bodyPost is the data payload i want to send in a turtle RDF format. I am putting this in my getBody() method, however i still get a 400 bad request. I have already sent this String via POST http through the Postman Chrome app and it works (201 Created). I saw that most implementations had getParams() but this requires key/value pairs whereas i am using triples that i want to send as a whole string of raw data
Set your Content-type to text/turtle. Override your request header like this:
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
final HashMap<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "text/turtle");
return params;
}

How to retrieve all the Groups/Roles a user is member of using SOAP services?

I am trying to collect some user informations using SOAP services.
I was able to get the Job Title for a given user, but I don't understand how to retrieve the list of groups and roles that a user has.
Can I simply use the GroupServiceSoap.getUserPlaces(long userId, String[] classNames, int max) method? Or is there another way I can get these fields?
Currently my code:
private static URL _getURL(String remoteUser, String password, String serviceName) {
final String LIFERAY_PROTOCOL = "http://";
final String LIFERAY_TCP_PORT = "8080";
final String LIFERAY_FQDN = "localhost";
final String LIFERAY_AXIS_PATH = "/api/secure/axis/";
try {
return new URL(LIFERAY_PROTOCOL + URLEncoder.encode(remoteUser, "UTF-8") + ":"
+ URLEncoder.encode(password, "UTF-8") + "#" + LIFERAY_FQDN
+ ":" + LIFERAY_TCP_PORT + LIFERAY_AXIS_PATH + serviceName);
} catch (MalformedURLException e) {
return null;
} catch (UnsupportedEncodingException e) {
return null;
}
}
[...]
public static void main(String[] argv){
public final String LIFERAY_USER_SERVICE="Portal_UserService";
public final String LIFERAY_COMPANY_SERVICE="Portal_CompanyService";
public final String LIFERAY_GROUP_SERVICE = "Portal_GroupService";
//company.default.web.id property
public final String LIFERAY_DEFAULT_COMPANY_ID = "liferay.com";
UserServiceSoap userService = new UserServiceSoapServiceLocator().getPortal_UserService(_getURL(USER_IDENTIFIER,USER_PASSWORD, LIFERAY_USER_SERVICE));
//This code is usefull if you want to use SOAP setter.
//((Portal_UserServiceSoapBindingStub) userService).setUsername(USER_IDENTIFIER);
//((Portal_UserServiceSoapBindingStub) userService).setPassword(USER_PASSWORD);
CompanyServiceSoap companyService = new CompanyServiceSoapServiceLocator().getPortal_CompanyService(_getURL(USER_IDENTIFIER, USER_PASSWORD, LIFERAY_COMPANY_SERVICE));
long companyId = companyService.getCompanyByMx(LIFERAY_DEFAULT_COMPANY_ID).getCompanyId();
// Here I retrieve my user, and can access some properties, but not them all !
UserSoap user = userService.getUserByEmailAddress(companyId, target_user_mail);
//TODO : I got hte JobTittle that I want, later I will do something more util thant just print it, I swear it my precious !
System.out.println(user.getJobTitle());
GroupServiceSoap groupService = new GroupServiceSoapServiceLocator().getPortal_GroupService(_getURL(USER_IDENTIFIER, USER_PASSWORD, LIFERAY_GROUP_SERVICE));
//this one return an empty array
GroupSoap[] userPlaces = groupService.getUserPlaces(new String[]{"Group", "Role"}, 150);
//this return an array of size 1, but the only GroupSoap seems to be a structural groups without any usefull properties to me.
GroupSoap[] userPlaces = groupService.getUserPlaces(null, 150);
}
Use this method to get user role and group user id
UserServiceSoap.getRoleUserIds
UserServiceSoap.getGroupUserIds
HTH
It is only a partial answer.
In order to get all the User Roles one can do this :
RoleServiceSoap roleService = new RoleServiceSoapServiceLocator().getPortal_RoleService(_getURL(USER_IDENTIFIER, USER_PASSWORD, LIFERAY_ROLE_SERVICE));
RoleSoap[] userRoles = roleService.getUserRoles(user.getUserId());
with user variable an instance of UserSoap.
The SOAP access must be done by an Admin user in order to get access to the Role List. The user can't access this himself.