Handling multiple parameters in a URI (RESTfully) in Java - java

I've been working on a small scale web service in Java/Jersey which reads lists of user information from clients contained in XML files. I currently have this functioning in all but one aspect: using multiple parameters in the URI to denote pulling multiple sets of user information or multiple sets of client information. I have a version which currently works, but is not the best way nor what the project description calls for.
Currently, my code looks like this:
#Path("Client/{client}/users")
public class UserPage
{
#GET
#Produces(MediaType.TEXT_HTML)
public String userChoice(#PathParam(value = "client") final String client)
{****Method here which handles a list of 'users'****}
#GET
#Path("{name}")
#Produces(MediaType.TEXT_HTML)
public String userPage(#PathParam(value = "client") final String client, #PathParam(value = "name") final String name)
{****Method here which handles 'user' information****}
The first method handles a list of users from a 'client' denoted by "{client}" in the URI. The second method delivers 'user' information denoted by "{name}" in the URI. Both will function with a single argument. Currently, in order to handle multiple 'users' I have "{name}" comma separated like "Client/Chick-Fil-A/users/Phil,Bradley". I can parse this after using #PathParam and create an array of these 'users', but again, I feel this is not the best way to handle this, and the project description calls for something different.
Is there a way to accomplish this same task with a URI formatted as "Client/Chick-Fil-A;cd=Phil,Bradley"? (The ;cd= is what's giving me the most trouble.)
I also need to be able to use this format for multiple clients, i.e. "Client;cd=Chick-Fil-A,Subway/users;cd=Phil,Bradley".
Edit: To clarify the project:
The client information is contained in 6 separate files. Each of these files has the same 3 users (this is a proof of concept, effectively). I need to be able to pull different subsets of information, for instance, user Phil from McDonalds and Chick-Fil-A, or users Phil and Peter from McDonalds, or users named Peter from all clients, etc.

You cannot use '=' in the URL path since it's a reserved character. However there are many other character you can use as delimiters such as '-' and ','. So instead of '=' you can use '-'. If you really really want to use '=' then you will have to URL-encode it; however, I would strongly recommend against this because it may make things more complicated then it should be.
You can see the grammar of the URL string here:
http://www.w3.org/Addressing/URL/url-spec.txt
Copy and search the following string to skip to the path grammar:
path void | segment [ / path ]
segment xpalphas
That said, I believe HTTP request is usually used for request single resource only. So my personal opinion is to not implement the service the way you implemented. For getting multiple clients I would use query parameters as filters like this:
Client/{cName}/users?filters=<value1>,<value2> ...
Edit: From the business case you got there, it seems like you probably need service like
/users?<filters>
/clients?<filters>
So say you want to get Peter from all clients then can have a request of this form:
/users?name=Peter
Similarly, if you want to get Jack and Peter from Starbucks then you can do:
/users?name=Peter,Jack&client=Starbucks
Hopefully this helps.

Query strings have the following syntax and you can have multiple parameters with the same name:
http://server/path/program?<query_string>
where query_string has the following syntax:
field1=value1&field1=value2&field1=value3…
For more details check out this entry in Wikipedia: http://en.wikipedia.org/wiki/Query_string

Related

In Java, how do I extract the domain of a URL?

I'm using Java 8. I want to extract the domain portion of a URL. Just in case I'm using the word "domain" incorrectly, what i want is if my server name is
test.javabits.com
I want to extract "javabits.com". Similarly, if my server name is
firstpart.secondpart.lastpart.org
I want to extract "lastpart.org". I tried the below
final String domain = request.getServerName().replaceAll(".*\\.(?=.*\\.)", "");
but its not extracting the domain properly. Then I tried what this guy has in his site -- https://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/, e.g.
private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$";
but that is also not extracting what I want. How can I extract the domain name portion properly?
Summary: Do not use regex for this. Use whois.
If I try to extrapolate from your question, to find out what you really want to do, I guess you want to find the domain belonging to some non-infrastructural owner from the host part of a URL. Additionally, from the tag of your question, you want to do it with the help of a regex.
The task you are undertaking is at best impractical, but probably impossible.
There are a number of corner cases that you would have to weed out. Apart from the list of infrastructural domains kindly provided by Lennart in https://publicsuffix.org/list/public_suffix_list.dat, you also have the cases of an empty host field in the URL or an IP-address forming the host part.
So, is there a better approach to this? Of course there is. What you do want to do is query a public database for the data you need. The protocol for such queries is called WHOIS.
Apache Commons provide an easy way to access WHOIS information in the WhoisClient. From there you can query the domain field, and find some more information that may be useful to you.
It shouldn't be harder than
import org.apache.commons.net.whois.WhoisClient;
import java.io.IOException;
public class CommonsTest {
public static void main(String args) {
WhoisClient c = new WhoisClient();
try {
c.connect(WhoisClient.DEFAULT_HOST);
System.out.println(c.query(URL));
c.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Using this will get you the whois information aboutt he domain you are asking for. If the domain is uregistered, that is, is a private domain, as in the case of www.stackexchange.com you will get an error saying no domain is registered. Remove the first part of the address and try again. Once you found the registered domain, you will also find the registrar and the registrer.
Now, unfortunately, whois is not as simple as one would think. Read further on https://manpages.debian.org/jessie/whois/whois.1.en.html for an elaboration on how to use it and what information you can expect from different sources.
Also, check related questions here.
try it like this:
String parts[] = longDomain.split(".");
String domain = parts[parts.length-2] + "." + [parts.length -1];

jackson empty query param behavior

I am working in a REST service using javax.ws.rs, running under Glassfish, and I have some strange behavior differences on different servers, regarding the interpretation of empty query params.
Note, actual names of services and implementation details deemed unimportant have had their names changed or been omitted, to protect the innocent.
Some (most) servers treat a request
http://localhost/serviceRoot/orders?status=
(i.e. a query param named status is provided, but with no value after the = sign) as equivalent to
http://localhost/serviceRoot/orders
essentially letting that query param be null, but some treat it as though that query param had the value of "" (empty-string).
This is a problem in my case, because:
/* In a Resource class, I have this method defined: */
#GET
#Path("/orders")
public Response getOrders(#QueryParam("status") OrderStatus orderStatus) throws Exception {
/* code to pull orders, optionally by status, and return them in a Response */
}
/* ... and elsewhere, our enum */
public enum OrderStatus {
RECEIVED, ACKNOWLEDGED, CANCELLED
}
and when someone sends the first request above to a server which treats it as an empty string, I get an error in the form:
"java.lang.IllegalArgumentException: No enum constant com.fqcn.OrderStatus."
(because "" is not a valid value in the enum which it tries to automatically construct) whereas it would successfully retrieve a list of orders, if the request hit a different server.
In order to debug, though I was not able to make it produce a stack trace under normal execution, I was able to write an ExceptionMapper, and output the stack trace of that, explicitly, so I came up with this:
com.sun.jersey.server.impl.model.parameter.QueryParamInjectableProvider$QueryParamInjectable.getValue(QueryParamInjectableProvider.java:74),
com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46),
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153),
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203),
com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75),
com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288),
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147),
com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108),
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147),
com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84),
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469),
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400),
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349),
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339),
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416),
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537),
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708),
javax.servlet.http.HttpServlet.service(HttpServlet.java:770),
org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550),
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281),
org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:175),
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java),
org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655),
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595),
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161),
org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331),
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231),
com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317),
com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195),
com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860),
com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757),
com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056),
com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229),
com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137),
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104),
com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90),
com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79),
com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54),
com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59),
com.sun.grizzly.ContextTask.run(ContextTask.java:71),
com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532),
com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513),
java.lang.Thread.run(Thread.java:724)
My problem is: I do not know where this query-param interpreting behavior resides (what config file, or class/jar file), and I do not have control over the clients requesting this. Furthermore, the "big red button" approach of taking down the offending servers and standing up new clones from a "known good" instance is time-expensive and has to be done very carefully.
The question I would like answered is: Where, if anywhere within Glassfish or Jackson (or another layer of the service stack?), is this empty-query-param interpreting behavior configured, and how do I change it?

Enumerate Custom Slot Values from Speechlet

Is there any way to inspect or enumerate the Custom Slot Values that are set-up in your interaction model? For Instance, Say you have an intent schema with the following intent:
{
"intent": "MySuperCoolIntent",
"slots":
[
{
"name": "ShapesNSuch",
"type": "LIST_OF_SHAPES"
}
]
}
Furthermore, you've defined the LIST_OF_SHAPES Custom Slot to have the following Values:
SQUARE
TRIANGLE
CIRCLE
ICOSADECAHECKASPECKAHEDRON
ROUND
HUSKY
Question: is there a method I can call from my Speechlet or my RequestStreamHandler that will give me an enumeration of those Custom Slot Values??
I have looked through the Alexa Skills Kit's SDK Javadocs Located Here
And I'm not finding anything.
I know I can get the Slot's value that is sent in with the intent:
String slotValue = incomingIntentRequest.getIntent().getSlot("LIST_OF_SHAPES").getValue();
I can even enumerate ALL the incoming Slots (and with it their values):
Map<String, Slot> slotMap = IncomingIntentRequest.getIntent().getSlots();
for(Map.Entry<String, Slot> entry : slotMap.entrySet())
{
String key = entry.getKey();
Slot slot = (Slot)entry.getValue();
String slotName = slot.getName();
String slotValue = slot.getValue();
//do something nifty with the current slot info....
}
What I would really like is something like:
String myAppId = "amzn1.echo-sdk-ams.app.<TheRestOfMyID>";
List<String> posibleSlotValues = SomeMagicAlexaAPI.getAllSlotValues(myAppId, "LIST_OF_SHAPES");
With this information I wouldn't have to maintain two separate "Lists" or "Enumerations"; One within the interaction Model and another one within my Request Handler. Seems like this should be a thing right?
No, the API does not allow you to do this.
However, since your interaction model is intimately tied with your development, I would suggest you check in the model with your source code in your source control system. If you are going to do that, you might as well put it with your source. Depending on your language, that also means you can probably read it during run-time.
Using this technique, you can gain access to your interaction model at run-time. Instead of doing it automatically through an API, you do it by best practice.
You can see several examples of this in action for Java in TsaTsaTzu's examples.
No - there is nothing in the API that allows you to do that.
You can see the full extent of the Request Body structure Alexa gives you to work with. It is very simple and available here:
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#Request%20Format
Please note, the Request Body is not to be confused with the request, which is a structure in the request body, with two siblings: version and session.

box-api search parameters not working?

I'm using the Java SDK to connect to Box. I find the root folder (this is a small dev instance so I don't mind searching from there.) I execute the search query and I get results. My problem is that the search parameters do not seem to work consistently or at all.
For example, this query
Iterator resultSet = rootFolder.search("query=NR_chewy_chic_swt_pot_app&file_extensions=jpg&content_type=name&type=file").iterator();
returns three entries.
NR_chewy_chic_swt_pot_app.jpg
NR Chewy Chicken AD02.xls
PreInvoice_M197301-3644756_NR Chewy Treats SURP.pdf
I remove the substring "&file_extensions=jpg" because it doesn't seem to do anything and save/recompile/run and I get the same three results.
I change "&type=file" to "&type=folder" and I get the same three results.
I change "query=NR_chewy_chic_swt_pot_app" to "query=NR" and I get NO results. Even though SO user Peter (who appears to work for Box) says that partial strings should match1.
I've tried rearranging the order of the search parameters to no avail. What am I missing?
Thanks,
Eric B.
Advanced search has yet to be implemented in the SDK (since it's still in beta), but it will be added in the coming weeks.
The reason why your call doesn't work is because the query method parameter is sent as the "query" URL parameter in the API call. Therefore, the ampersands in your query string are being escaped.
If you need an immediate workaround, you can use the BoxAPIRequest and BoxAPIResponse classes to make a custom search request. For example:
BoxAPIConnection api = new BoxAPIConnection("token");
URL url = new URL("https://api.box.com/2.0/search?query=NR_chewy_chic_swt_pot_app&file_extensions=jpg&content_type=name&type=file")
BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
BoxJSONResponse response = (BoxJSONResponse) request.send();
String json = response.getJSON();
Sorry that this wasn't clear. We'll update the documentation to make it more explicit that query represents the query field and not the URL query string.

How can I get the current URL in Google Web Toolkit via client side Java code?

I'm trying to read the query arguments of the URL in client side Java code, but I can't figure out how to find the current URL in Java.
When I tried using httpServletRequest as recommended in this question, it says that it cannot be resolved and it doesn't offer adding an import statement.
I'm using Google Web Toolkit with Google App Engine.
Look at Window.Location:
public static class Window.Location
This class provides access to the browser's location's object. The location object contains information about the current URL and methods to manipulate it. Location is a very simple wrapper, so not all browser quirks are hidden from the user.
There are a number of methods to retrieve info about the URL, including one to get the whole thing (getHref()) or get the constituent components (e.g. getProtocol(), getHost(), getHostName(), etc).
Since you say you want to read the query arguments, you probably want one of these:
static java.lang.String getQueryString()
Gets the URL's query string.
static java.lang.String getParameter(java.lang.String name)
Gets the URL's parameter of the specified name
static java.util.Map<java.lang.String,java.util.List<java.lang.String>> getParameterMap()
Returns a Map of the URL query parameters for the host page; since changing the map would not change the window's location, the map returned is immutable.

Categories

Resources