package com.xebialabs.restito.resources;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.glassfish.grizzly.http.Method;
import static java.lang.String.format;
/**
* <p><u><b>!EXPERIMENTAL!</b> This stuff is experimental. Which means it may change significantly in future versions.</u></p>
* <p>Responsible for discovering a resource which will be used as a response body. Discovery happens based on URI and and request method.</p>
*/
public class SmartDiscoverer {
private String resourcePrefix;
public SmartDiscoverer(final String resourcePrefix) {
this.resourcePrefix = resourcePrefix;
}
/**
* Discovers resource based on request
* Tries different options:
* <ul>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/get.asd.bsd.asd</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/get/asd/bsd/asd</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/asd.bsd.asd</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/asd/bsd/asd</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/get.asd.bsd.asd.xml</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/get/asd/bsd/asd.xml</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/asd.bsd.asd.xml</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/asd/bsd/asd.xml</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/get.asd.bsd.asd.json</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/get/asd/bsd/asd.json</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/asd.bsd.asd.json</li>
* <li>GET asd/bsd/asd => resource: {resourcePrefix}/asd/bsd/asd.json</li>
* </ul>
*/
public URL discoverResource(Method m, String uri) {
for (String s : possibleLocations(m, uri)) {
try {
URL resource = this.getClass().getClassLoader().getResource(resourcePrefix + "/" + URLDecoder.decode(s, "UTF-8"));
if (resource == null) {
throw new IllegalArgumentException(String.format("Resource %s not found.", uri));
}
if (!new File(URLDecoder.decode(resource.getFile(), "UTF-8")).isFile()) {
continue; // Probably directory
}
return resource;
} catch (IllegalArgumentException ignored) {
} // just go on
catch (UnsupportedEncodingException ignored) {
} // just go on
}
throw new IllegalArgumentException(format("Can not discover resource for method [%s] and URI [%s]", m, uri));
}
private List<String> possibleLocations(final Method m, String uri) {
final Iterable<String> split = split(uri, "/");
return new ArrayList<String>() {{
add(m.toString().toLowerCase() + "." + join(split, "."));
add(m.toString().toLowerCase() + "/" + join(split, "/"));
add(join(split, "."));
add(join(split, "/"));
add(m.toString().toLowerCase() + "." + join(split, ".") + ".xml");
add(m.toString().toLowerCase() + "/" + join(split, "/") + ".xml");
add(join(split, ".") + ".xml");
add(join(split, "/") + ".xml");
add(m.toString().toLowerCase() + "." + join(split, ".") + ".json");
add(m.toString().toLowerCase() + "/" + join(split, "/") + ".json");
add(join(split, ".") + ".json");
add(join(split, "/") + ".json");
}};
}
private Iterable<String> split(String data, String delimiter) {
List<String> result = new ArrayList<>();
StringTokenizer tokenizer = new StringTokenizer(data, delimiter);
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken().trim();
if (token.length() > 0) {
result.add(token);
}
}
return result;
}
private String join(Iterable<String> elements, String delimiter) {
Iterator<String> iter = elements.iterator();
StringBuilder result = new StringBuilder();
while (iter.hasNext()) {
result.append(iter.next());
if (iter.hasNext()) {
result.append(delimiter);
}
}
return result.toString();
}
}