package com.fasterxml.jackson.jaxrs.json.dw;
import java.io.*;
import java.net.*;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.StreamingOutput;
import org.eclipse.jetty.server.Server;
import org.junit.Assert;
import com.fasterxml.jackson.databind.ObjectMapper;
public abstract class SimpleEndpointTestBase extends ResourceTestBase
{
final static int TEST_PORT = 6011;
static class Point {
public int x, y;
protected Point() { }
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
@Path("/point")
public static class SimpleResource
{
@Path("/javascript")
@GET
@Produces({ MediaType.APPLICATION_JSON, "application/javascript" })
public Point getPointJS() {
return new Point(1, 2);
}
@Path("/jsonx")
@GET
@Produces({ MediaType.APPLICATION_JSON, "text/x-json" })
public Point getPointJSONX() {
return new Point(1, 2);
}
}
public static class SimpleResourceApp extends JsonApplicationWithJackson {
public SimpleResourceApp() { super(new SimpleResource()); }
}
private final static String UNTOUCHABLE_RESPONSE = "[1]";
@Path("/raw")
public static class RawResource
{
@GET
@Produces({ MediaType.APPLICATION_JSON, "application/javascript" })
@Path("string")
public String getString() {
return UNTOUCHABLE_RESPONSE;
}
@GET
@Path("bytes")
@Produces({ MediaType.APPLICATION_JSON, "application/javascript" })
public byte[] getBytes() throws IOException {
return UNTOUCHABLE_RESPONSE.getBytes("UTF-8");
}
}
@Path("/fluff")
public static class FluffyResource
{
@GET
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
@Path("bytes")
public StreamingOutput getFluff(@QueryParam("size") final long size) {
if (size <= 0L) {
throw new IllegalArgumentException("Missing 'size'");
}
return new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException {
byte[] buf = new byte[1024];
for (int i = 0, end = buf.length; i < end; ++i) {
buf[i] = (byte) i;
}
long left = size;
while (left > 0) {
int len;
if (left >= buf.length) {
len = buf.length;
} else {
len = (int) left;
}
output.write(buf, 0, len);
left -= len;
}
}
};
}
}
public static class SimpleRawApp extends JsonApplicationWithJackson {
public SimpleRawApp() { super(new RawResource()); }
}
public static class SimpleFluffyApp extends JsonApplicationWithJackson {
public SimpleFluffyApp() { super(new FluffyResource()); }
}
/*
/**********************************************************
/* Test methods
/**********************************************************
*/
public void testStandardJson() throws Exception
{
final ObjectMapper mapper = new ObjectMapper();
Server server = startServer(TEST_PORT, SimpleResourceApp.class);
Point p;
try {
InputStream in = new URL("http://localhost:"+TEST_PORT+"/point/javascript").openStream();
p = mapper.readValue(in, Point.class);
in.close();
} finally {
server.stop();
}
// ensure we got a valid Point
assertNotNull(p);
assertEquals(1, p.x);
assertEquals(2, p.y);
}
public void testAcceptJavascriptType() throws Exception
{
final ObjectMapper mapper = new ObjectMapper();
Server server = startServer(TEST_PORT, SimpleResourceApp.class);
URL urlJS = new URL("http://localhost:"+TEST_PORT+"/point/javascript");
URL urlJsonX = new URL("http://localhost:"+TEST_PORT+"/point/jsonx");
try {
HttpURLConnection conn = (HttpURLConnection) urlJS.openConnection();
// First: verify that weird types are not supported...
conn.setRequestProperty("Accept", "foo/bar");
conn.connect();
assertEquals(HttpURLConnection.HTTP_NOT_ACCEPTABLE, conn.getResponseCode());
conn.disconnect();
// try again with somewhat non-standard, but supported JSON-like type (application/javascript)
conn = (HttpURLConnection) urlJS.openConnection();
conn.setRequestProperty("Accept", "application/javascript");
assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
InputStream in = conn.getInputStream();
Point p;
try {
p = mapper.readValue(in, Point.class);
} finally {
in.close();
}
assertNotNull(p);
assertEquals(1, p.x);
assertEquals(2, p.y);
conn.disconnect();
// [Issue#40]: another oddball type to consider
conn = (HttpURLConnection) urlJsonX.openConnection();
conn.setRequestProperty("Accept", "text/x-json");
assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
in = conn.getInputStream();
p = null;
try {
p = mapper.readValue(in, Point.class);
} finally {
in.close();
}
assertNotNull(p);
assertEquals(1, p.x);
assertEquals(2, p.y);
conn.disconnect();
} finally {
server.stop();
}
}
// [Issue#34] Verify that Untouchables act the way as they should
@SuppressWarnings("resource")
public void testUntouchables() throws Exception
{
Server server = startServer(TEST_PORT, SimpleRawApp.class);
try {
InputStream in = new URL("http://localhost:"+TEST_PORT+"/raw/string").openStream();
assertEquals(UNTOUCHABLE_RESPONSE, readUTF8(in));
in = new URL("http://localhost:"+TEST_PORT+"/raw/bytes").openStream();
Assert.assertArrayEquals(UNTOUCHABLE_RESPONSE.getBytes("UTF-8"), readAll(in));
} finally {
server.stop();
}
}
/**
* Test that exercises underlying JAX-RS container by reading/writing 500 megs of fluff;
* but does not do actual data format content. Goal being to ensure that
* <code>StreamingOutput</code> works as expected even if provider is registered.
*/
public void testHugeFluffyContent() throws Exception
{
Server server = startServer(TEST_PORT, SimpleFluffyApp.class);
try {
// Let's try with 4.5 gigs, just to be sure (should run OOME if buffering; or be
// super slow if disk-backed buffering)
final long size = 4500 * 1024 * 1024;
InputStream in = new URL("http://localhost:"+TEST_PORT+"/fluff/bytes?size="+size).openStream();
byte[] stuff = new byte[64000];
long total = 0L;
int count;
while ((count = in.read(stuff)) > 0) {
// verify contents, too
for (int i = 0; i < count; ++i) {
int exp = ((int) total) & 0xFF;
int act = stuff[i] & 0xFF;
if (exp != act) {
fail("Content differs at #"+Long.toHexString(total)+"; got 0x"+Integer.toHexString(act)
+", expected 0x"+Integer.toHexString(exp));
}
++total;
}
}
in.close();
assertEquals(size, total);
} finally {
server.stop();
}
}
}