i have an unmanaged extension for my neo4j server.
and the code like the following.
#Path("/helloworld")
public class HelloWorldResource {
private final GraphDatabaseService database;
public HelloWorldResource(#Context GraphDatabaseService database) {
this.database = database;
}
#GET
#Produces(MediaType.TEXT_PLAIN)
#Path("/{nodeId}")
public Response hello(#PathParam("nodeId") long nodeId) {
String res = "";
try ( Transaction ignored = database.beginTx();)
{
//##problem
Result result = database.execute( "MATCH (n:KISI) where id(n)=1 return n" );
} catch (Exception e) {
res = "Error = " + e.getMessage();
}
return Response
.status(Status.OK)
.entity(("nodeId =" + nodeId + " " + res).getBytes(Charset
.forName("UTF-8"))).build();
}
}
When i deploy the code i got 500 internal error.
if i remove the code
Result result = database.execute( "MATCH (n:KISI) where id(n)=1 return
n" );
then everything is fine.
i checked the log file and the error is the following
Aug 13, 2015 3:34:36 AM com.sun.jersey.spi.container.ContainerResponse
mapMappableContainerException SEVERE: The exception contained within
MappableContainerException could not be mapped to a response,
re-throwing to the HTTP container
java.lang.NoSuchMethodError:
org.neo4j.graphdb.GraphDatabaseService.execute(Ljava/lang/String;)Lorg/neo4j/graphdb/Result;
at
org.neo4j.examples.server.unmanaged.HelloWorldResource.hello(HelloWorldResource.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606) at
com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
at
com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at
org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:139)
at
com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at
com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at
com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at
com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
at
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848) at
org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:698)
at
org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:505)
at
org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:211)
at
org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1096)
at
org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:432)
at
org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:175)
at
org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1030)
at
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:136)
at
org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)
at
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:445) at
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:268) at
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:229)
at
org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358)
at
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601)
at
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:532)
at java.lang.Thread.run(Thread.java:745)
so whats wrong with my code?
I guess that your Neo4j distribution version and maven dependency version in pom.xml are not same.
But there are several things to check:
1) You should always close Result object.
Example:
try(Result result = database.execute( "MATCH (n:KISI) where id(n)=1 return n" )) {
// do stuff here
}
```
2) Exception occurs not in try-catch but later. You should change your code to this:
try ( Transaction tx = database.beginTx()) {
String query = "MATCH (n:KISI) where id(n)=1 return n";
// use result with try-with-resource to ensure that it will be closed
try(Result result = database.execute(query)) {
// do stuff you need with result here
return Response.ok("nodeId =" + nodeId).build();
}
tx.success(); // mark transaction as successful
} catch (Exception e) {
// If exception occurs - send exception message with 500 status code
// It's good idea to write Exception stacktrace to log there
return Response.serverError().entity(e.getMessage()).build()
}
3) You should check how unmanaged extension .jar file is build.
All Neo4j dependencies should be provided in pom.xml (there are already there in Neo4j distribution).
Check that your database version and your dependency version in pom.xml are same. GraphDatabaseService::execute method is invented recently (2.2.3 if I remember correctly). Probably your database distribution is older than your maven dependencies.
Related
I'm creating a rest api that will consume an xml document and create two objects from that document. The objects will then be persisted on a database using hibernate. This is what I have right now:
#PUT
#Path("saveVehicle")
#Consumes("application/xml;charset=utf-8")
#Produces("text/plain")
public String saveVehicleData(String xml) {
DBClient client = new DBClient();
Session session = client.getVehicleSession();
JAXBContext jaxbContext;
try {
Reader reader = new StringReader(xml);
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader xmlReader = factory.createXMLStreamReader(reader);
jaxbContext = JAXBContext.newInstance(VehicleData.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
VehicleData vehicle = (VehicleData) jaxbUnmarshaller.unmarshal(xmlReader);
session.saveOrUpdate(vehicle);
session.flush();
jaxbContext = JAXBContext.newInstance(VehicleOwner.class);
jaxbUnmarshaller = jaxbContext.createUnmarshaller();
VehicleOwner owner = (VehicleOwner) jaxbUnmarshaller.unmarshal(xmlReader);
session.saveOrUpdate(owner);
session.flush();
return vehicle.getRegistrationNo() + " " + owner.getName();
} catch (JAXBException e) {
e.printStackTrace();
return "JAXBException " + e.getMessage() + "\nCaused by " + e.getCause();
} catch (XMLStreamException e) {
e.printStackTrace();
return "XMLStreamException " + e.getMessage();
}
}
As you can see, this method is supposed to take in xml as a string. It will then generate a vehicle and a vehicle owner from that document. The document contains information about vehicles and their owners but I want them in separate database tables.
The classes use jaxb annotations for all the fields that I want to store on the database.
However, When I try to run this, I get the following stacktrace:
java.lang.ClassCastException: org.package.VehicleOwner cannot be cast to org.package.VehicleData
org.package.rest.LoginController.saveVehicleData(LoginController.java:369)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
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:1542)
com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
Before I added the mapping for vehicle owners, I was able to instantiate a VehicleData and store it on the database. But now it seems like it is expecting this xml document to be mapped to a VehicleOwner. I thought it would be possible to map the document to different classes. Is that not the case? if it is, How would I do it?
It is possible to map document to different classes, but apparently you don't do this. Just doing:
jaxbContext = JAXBContext.newInstance(VehicleData.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
VehicleData vehicle = (VehicleData) jaxbUnmarshaller.unmarshal(xmlReader);
Does not magically map you XML structure to VehicleData structure. You have to define or generate mappings so that the same XML would map to different structures (VehicleData/VehicleOwner) in different JAXB contexts. You also have to make sure these contexts do not intersect (I guess they do in your case).
Looking at the output of redis client list, I see there are 600 active clients at the moment, and it continues to grow. Here's a snippet of output:
id=285316 addr=x.x.x.x:55699 fd=14131 name= age=53055 idle=53029 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=sismember
id=285317 addr=x.x.x.x:55700 fd=14132 name= age=53055 idle=53050 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=sismember
Here's my code:
Listener.java:
import com.sun.jersey.api.model.AbstractResourceModelContext;
import com.sun.jersey.api.model.AbstractResourceModelListener;
import javax.ws.rs.ext.Provider;
#Provider
public class Listener implements AbstractResourceModelListener {
#Override
public void onLoaded(AbstractResourceModelContext modelContext) {
RedisManager.getInstance().connect();
}
}
RedisManager.java:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisManager {
private static final RedisManager instance = new RedisManager();
private static JedisPool pool;
private RedisManager() {
}
public final static RedisManager getInstance() {
return instance;
}
public void connect() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(5000);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setMaxIdle(50);
poolConfig.setMinIdle(1);
poolConfig.setTestWhileIdle(true);
poolConfig.setNumTestsPerEvictionRun(10);
poolConfig.setTimeBetweenEvictionRunsMillis(60000);
pool = new JedisPool(poolConfig, "redis_hostname");
}
public void release() {
pool.destroy();
}
public Jedis getJedis() {
return pool.getResource();
}
public void returnJedis(Jedis jedis) {
pool.returnResourceObject(jedis);
}
}
APIServlet.java:
#Path("/")
public class APIService {
#GET
#Path("/lookup")
#Produces(MediaType.APPLICATION_JSON)
public Response getMsg(#QueryParam("email") String email,
#QueryParam("pretty") String pretty
) throws JSONException {
Jedis jedis = RedisManager.getInstance().getJedis();
if (jedis.sismember("inprocess", email)) {
RedisManager.getInstance().returnJedis(jedis);
return Response.status(202).entity("{\"status\":202, " +
"\"processing\":{\"type\":\"Lookup performed\", " +
"\"message\":\"We're performing analysis on this " +
"record. Result should be ready in a few minutes" +
".\"}}").build();
}
Person person = new Person();
person.lookup(person);
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(person);
JSONObject jsonObj = new JSONObject(jsonString);
jsonObj.remove("objectID");
jsonObj.remove("data_quality");
jsonObj.put("status", 200);
RedisManager.getInstance().returnJedis(jedis);
if (!jsonObj.isNull("name") && !jsonObj.get("name").equals("")) {
if (hasPretty) {
return Response.status(200).entity(jsonObj.toString(4))
.build();
}
return Response.status(200).entity(jsonObj.toString()).build();
}
return Response.status(404).entity("{\"status\":404, " +
"\"error\":{\"type\":\"Data Not Found.\", " +
"\"message\":\"We were not able to find data " +
"on this email.\"}}").build();
}
}
Maven Dependencies:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.2.0</version>
</dependency>
The Listener creates an instance of RedisManager to be used throughout the application--this should happen only once, on startup (note: I have no idea how to call destroy on shutdown, which would be nice to know). Throughout the program, this instance of JedisPool is used in Jersey routes, as shown in APIServlet.java. In the route, I get a JedisPool resource, then before I return on any part of the route, I return the resource.
What is happening is that the resource does not seem to be returned (or my understanding of the pool is wrong). After a period of time, the connections to my Redis instance grow to the maxTotal of 5,000, and then I start getting errors "could not get a resource from the pool," and Tomcat dies.
A few things I've noticed:
There seems to be a large amount of ESTABLISHED https connections that stick around (not 100% sure on this, but it seems to be the case).
All Redis clients that are idle (well, nearly all anyway) have a cmd of sismember.
NOTE: I've not included the full APIService.java code because I'm really not allowed to do so. The snippet I included does give the overall gist of the code. I am returning throughout the APIService.java code (return 404, return 429, etc), and before each return I make sure I am returning the resource to the pool.
Finally, here's the stacktrace:
10-Feb-2016 08:04:23.161 SEVERE [http-nio-443-exec-14] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:50)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:86)
at co.talentiq.api.APIService.getMsg(APIService.java:63)
at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
First: If you already have pool initialized do not create a new one:
public class RedisManager {
...
public void connect() {
if(pool != null) {
System.out.println("Already exists");
return;
}
JedisPoolConfig poolConfig = new JedisPoolConfig();
...
Second ... Do you have exceptions in your logs from getMsg method?
public Response getMsg(#QueryParam("email") String email,
#QueryParam("pretty") String pretty
You should have all work with pooled resources being wrapped into try-catch-finally and always return resource in finally block. NB: make sure not to return resource (jedis in this case) to pool twice.
Jedis jedis;
try {
jedis = RedisManager.getInstance().getJedis();
...
} finally {
if (jedis != null) {
RedisManager.getInstance().returnJedis(jedis);
jedis = null;
}
}
Btw: you can create a small AutoCloseable wrapper around your jedis get/return code and use java try with resources - https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Code snippet with try-with-resource
public void release() {
pool.destroy();
}
public static class JedisWrapper implements AutoCloseable {
private final JedisPoolConfig pool;
private final Jedis jedis;
public JedisWrapper(JedisPoolConfig pool, Jedis jedis) {
this.pool = pool;
this.jedis = jedis;
}
public Jedis get() {
return jedis;
}
#Override
public void close() {
pool.returnResourceObject(jedis);
}
}
public JedisWrapper getJedis() {
return new JedisWrapper(pool, pool.getResource());
}
// you can delete this method
public void returnJedis(Jedis jedis) {
pool.returnResourceObject(jedis);
}
And later in usage place
public Response getMsg(#QueryParam("email") String email,
#QueryParam("pretty") String pretty
) throws JSONException {
try(JedisWrapper jw = ...) {
Jedis jedis = jw.get();
...
}
I'm running my tests using gradle testFlavorType
JSONObject jsonObject1 = new JSONObject();
JSONObject jsonObject2 = new JSONObject();
jsonObject1.put("test", "test");
jsonObject2.put("test", "test");
assertEquals(jsonObject1.get("test"), jsonObject2.get("test"));
The above test succeeds.
jsonObject = new SlackMessageRequest(channel, message).buildBody();
String channelAssertion = jsonObject.getString(SlackMessageRequest.JSON_KEY_CHANNEL);
String messageAssertion = jsonObject.getString(SlackMessageRequest.JSON_KEY_TEXT);
assertEquals(channel, channelAssertion);
assertEquals(message, messageAssertion);
But the above two requests fail. The stack trace says that channelAssertion and messageAssertion are null, but not sure why. My question is: Why are the above two asserts failing?
Below is the SlackMessageRequest.
public class SlackMessageRequest
extends BaseRequest {
// region Variables
public static final String JSON_KEY_TEXT = "text";
public static final String JSON_KEY_CHANNEL = "channel";
private String mChannel;
private String mMessage;
// endregion
// region Constructors
public SlackMessageRequest(String channel, String message) {
mChannel = channel;
mMessage = message;
}
// endregion
// region Methods
#Override
public MethodType getMethodType() {
return MethodType.POST;
}
#Override
public JSONObject buildBody() throws JSONException {
JSONObject body = new JSONObject();
body.put(JSON_KEY_TEXT, getMessage());
body.put(JSON_KEY_CHANNEL, getChannel());
return body;
}
#Override
public String getUrl() {
return "http://localhost:1337";
}
public String getMessage() {
return mMessage;
}
public String getChannel() {
return mChannel;
}
// endregion
}
Below is the stacktrace:
junit.framework.ComparisonFailure: expected:<#tk> but was:<null>
at junit.framework.Assert.assertEquals(Assert.java:100)
at junit.framework.Assert.assertEquals(Assert.java:107)
at junit.framework.TestCase.assertEquals(TestCase.java:269)
at com.example.app.http.request.SlackMessageRequestTest.testBuildBody(SlackMessageRequestTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at junit.framework.TestCase.runTest(TestCase.java:176)
at junit.framework.TestCase.runBare(TestCase.java:141)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:129)
at junit.framework.TestSuite.runTest(TestSuite.java:252)
at junit.framework.TestSuite.run(TestSuite.java:247)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
EDIT 5:55PM EST
I've figured out that I can log with System.out.println("") and then see the results by running gradle testFlavorType --debug and by trial and error I've discovered the following weird situation:
#Override
public JSONObject buildBody() throws JSONException {
System.out.println("buildBody mChannel = " + mChannel);
System.out.println("buildBody mMessage = " + mMessage);
JSONObject body = new JSONObject();
body.put(JSON_KEY_TEXT, getMessage());
body.put(JSON_KEY_CHANNEL, getChannel());
if (body.length() != 0) {
Iterator<String> keys = body.keys();
if (keys.hasNext()) {
do {
String key = keys.next();
System.out.println("keys: " + key);
} while (keys.hasNext());
}
} else {
System.out.println("There are no keys????");
}
return body;
}
For some reason, "There are no keys????" is printing out?!?!?!?! Why?!
EDIT 6:20PM EST
I've figured out how to debug unit tests. According to the debugger, the assigned JSONObject is returning "null". I have no clue what this means (see below). Since I think this is relevant, my gradle file includes the following:
testOptions {
unitTests.returnDefaultValues = true
}
It's especially strange because if I construct a JSONObject inside the test, then everything works fine. But if it is part of the original application's code, then it doesn't work and does the above.
As Lucas says, JSON is bundled up with the Android SDK, so you are working with a stub.
The current solution is to pull JSON from Maven Central like this:
dependencies {
...
testImplementation 'org.json:json:20210307'
}
You can replace the version 20210307 with the the latest one depending on the Android API. It is not known which version of the maven artefact corresponds exactly/most closely to what ships with Android.
Alternatively, you can download and include the jar:
dependencies {
...
testImplementation files('libs/json.jar')
}
Note that you also need to use Android Studio 1.1 or higher and at least build tools version 22.0.0 or above for this to work.
Related issue: #179461
The class JSONObject is part of the android SDK. That means that is not available for unit testing by default.
From http://tools.android.com/tech-docs/unit-testing-support
The android.jar file that is used to run unit tests does not contain
any actual code - that is provided by the Android system image on real
devices. Instead, all methods throw exceptions (by default). This is
to make sure your unit tests only test your code and do not depend on
any particular behaviour of the Android platform (that you have not
explicitly mocked e.g. using Mockito).
When you set the test options to
testOptions {
unitTests.returnDefaultValues = true
}
you are fixing the "Method ... not mocked." problem, but the outcome is that when your code uses new JSONObject() you are not using the real method, you are using a mock method that doesn't do anything, it just returns a default value. That's the reason the object is null.
You can find different ways of solving the problem in this question: Android methods are not mocked when using Mockito
Well, my first hunch would be that your getMessage() method returns null. You could show the body of that method in your question and have us find the answer for you, but you should probably research how to debug android applications using breakpoints.
That way you can run your code step by step and see the values of each variable at every step. That would show you your problem in no time, and it's a skill you should definitely master as soon as possible if you intend to get seriously involved in programming.
I have a ServerEndpoint class that throws this error as soon as I attempt to connect to it from the client. I presume that some sort of dependency is missing, i.e a bundled library that is missing another jar, although it may be some other problem.
I see the following stack trace in the server log, with no additional information.
An exception or error occurred in the container during the request processing
java.lang.NoClassDefFoundError: Could not initialize class org.example.ServerSocketEndpoint
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at java.lang.Class.newInstance(Class.java:374)
at org.glassfish.tyrus.core.ReflectionHelper.getInstance(ReflectionHelper.java:807)
at org.glassfish.tyrus.core.DefaultComponentProvider.create(DefaultComponentProvider.java:60)
at org.glassfish.tyrus.core.ComponentProviderService.getInstance(ComponentProviderService.java:232)
at org.glassfish.tyrus.core.ComponentProviderService.getEndpointInstance(ComponentProviderService.java:293)
at org.glassfish.tyrus.server.TyrusServerEndpointConfigurator.getEndpointInstance(TyrusServerEndpointConfigurator.java:160)
at org.glassfish.tyrus.core.AnnotatedEndpoint$1.getEndpointInstance(AnnotatedEndpoint.java:144)
at org.glassfish.tyrus.core.ComponentProviderService.getInstance(ComponentProviderService.java:149)
at org.glassfish.tyrus.core.AnnotatedEndpoint.callMethod(AnnotatedEndpoint.java:452)
at org.glassfish.tyrus.core.AnnotatedEndpoint.onError(AnnotatedEndpoint.java:507)
at org.glassfish.tyrus.core.TyrusEndpointWrapper.onConnect(TyrusEndpointWrapper.java:657)
at org.glassfish.tyrus.core.TyrusWebSocket.onConnect(TyrusWebSocket.java:141)
at org.glassfish.tyrus.core.TyrusWebSocketEngine$TyrusConnection.<init>(TyrusWebSocketEngine.java:611)
at org.glassfish.tyrus.core.TyrusWebSocketEngine$SuccessfulUpgradeInfo.createConnection(TyrusWebSocketEngine.java:556)
at org.glassfish.tyrus.servlet.TyrusHttpUpgradeHandler.init(TyrusHttpUpgradeHandler.java:111)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:777)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:745)
]]
How can I get more relevant information? I am running the server with --debug.
I also added the following to my domain configuration in order to monitor class loading:
<jvm-options>-verbose:class</jvm-options>
<jvm-options>-XX:LogFile=${com.sun.aas.instanceRoot}/logs/jvm.log</jvm-options>
<jvm-options>-XX:+LogVMOutput</jvm-options>
Is it possible to increase the verbosity further?
I am running GlassFish Server Open Source Edition 4.0 (build 89) on Linux x64 with the latest Oracle Java 7 JDK & Tyrus 1.7
Any ideas would be welcome.
The endpoint stripped to its core; I tried to leave anything that could cause issues:
#ServerEndpoint(
value = "/main",
encoders = { BinaryEncoder.class }, // TextEncoder.class
decoders = { BinaryDecoder.class } // TextDecoder.class
)
#Stateful
public class ServerSocketEndpoint implements IServerSocketEndpoint
{
static {
logger = Debug.getLogger(ServerSocketEndpoint.class);
ds = DB.initDs();
gson = GsonPlus.create();
sessions = Collections.synchronizedSet(new HashSet<Session>());
peers = Collections.synchronizedSet(new HashSet<ISocketPeer>());
}
protected static final DataSource ds;
protected static final Logger logger;
protected static final Gson gson;
protected static final Set<Session> sessions;
protected static final Set<ISocketPeer> peers;
protected TyrusSession _session; // TyrusSession implements JSR-356 Session
protected long _socketSessionId;
protected BasicPeer _peer;
public static void send(final Session session, Msg msg)
{
RemoteEndpoint.Async remote = session.getAsyncRemote();
if (session.isOpen())
{
try {
remote.sendObject(msg);
logger.log(Level.INFO, String.format("send() msg: %s", msg.toJson(gson)));
}
catch (IllegalArgumentException ex) {
Logger.getLogger(ServerSocketEndpoint.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public ServerSocketEndpoint()
{
}
#Override
public void close(CloseReason closeReason)
{
if (_session == null)
return;
try {
_peer.free();
_session.close(closeReason);
_session = null;
}
catch (IOException ex) {
methodException(ex);
}
}
#OnOpen
public void onOpen(Session session, EndpointConfig config)
{
_session = (TyrusSession)session;
if (ds == null) {
// No connection available somehow - nothing to do except log the error
}
InetAddress clientExtIp;
try {
clientExtIp = InetAddress.getByName(_session.getRemoteAddr());
}
catch (UnknownHostException ex) {
}
try (Connection dbc = ds.getConnection())
{
CallableStatement proc = dbc.prepareCall("{call newSocketSession(?, ?, ?, ?, ?, ?)}");
proc.setBytes("extIp", clientExtIp.getAddress());
proc.setString("extHostName", clientExtIp.getHostName());
proc.registerOutParameter("id", Types.BIGINT);
if (proc.execute()) {
// Process results
}
// Stash a reference to this DB socket session
_socketSessionId = proc.getLong("id");
}
catch (SQLException ex) {
methodException(ex);
}
}
#OnError
public void onError(Session session, Throwable ex)
{
methodException(ex);
}
#OnMessage
public void onMessage(final Session session, Msg msg) throws IOException, EncodeException
{
// deal with messages
}
#OnClose
public void onClose(Session session)
{
sessions.remove(session);
_session = null;
_peer = null;
}
}
Okay so I got it to work with Pavel's help.
Tyrus should not be included in the WAR as this results in duplicate files on the class path.
The apache.commons.codec.binary.Base64 class was not being linked in (required for GsonPlus).
So my question becomes the following more specifically: is there a non-brute-force method of diagnosing such CNFE errors, i.e without de-constructing & re-constructing the endpoint piece by piece?
I'm beginner for using JPOS with ISO8583. At this time, I try my application using Spring to build the request using JPOS where I want to send it to BASE24.
Here my code for build :
public class BuildISO {
public void sentISOMsg(String hostname, int portNumber) {
// Create Packager based on XML that contain DE type
GenericPackager packager;
ASCIIChannel channel;
try {
packager = new GenericPackager("packager/iso93ascii.xml");
channel = new ASCIIChannel(hostname, portNumber, packager);
ISOMUX isoMux = new ISOMUX(channel) {
#Override
protected String getKey(ISOMsg m) throws ISOException {
return super.getKey(m);
}
};
new Thread(isoMux).start();
// Create ISO Message
ISOMsg isoRequest = new ISOMsg();
isoRequest.setMTI("1800");
isoRequest.set(3, "123456");
isoRequest.set(7, new SimpleDateFormat("yyyyMMdd").format(new Date()));
isoRequest.set(11, "000001");
isoRequest.set(12, new SimpleDateFormat("HHmmss").format(new Date()));
isoRequest.set(13, new SimpleDateFormat("MMdd").format(new Date()));
isoRequest.set(48, "Tutorial ISO 8583 Dengan Java");
isoRequest.set(70, "001");
ISORequest req = new ISORequest(isoRequest);
isoMux.queue(req);
ISOMsg isoReply = req.getResponse(50*1000);
if (isoReply != null) {
System.out.println("Req ["+new String(isoRequest.pack()) + "]");
System.out.println("Res ["+new String(isoReply.pack()) + "]");
}
// print the DE list
logISOMsg(isoRequest);
// Get and print the output result
byte[] data = isoRequest.pack();
System.out.println("RESULT : " + new String(data));
} catch (ISOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void logISOMsg(ISOMsg msg) {
System.out.println("----ISO MESSAGE-----");
try {
System.out.println(" MTI : " + msg.getMTI());
for (int i=1;i<=msg.getMaxField();i++) {
if (msg.hasField(i)) {
System.out.println(" Field-"+i+" : "+msg.getString(i));
}
}
} catch (ISOException e) {
e.printStackTrace();
} finally {
System.out.println("--------------------");
}
}
}
and next, while I want to call that class in here :
public #ResponseBody ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
String hostname = request.getParameter("hostname");
int portNumber = Integer.parseInt(request.getParameter("portNumber"));
System.out.println("handleRequest... : " + hostname + " : " + portNumber);
BuildISO buildISO = new BuildISO();
buildISO.sentISOMsg(hostname, portNumber);
return null;
}
I got error like this :
SEVERE: Servlet.service() for servlet spring threw exception
java.lang.ClassNotFoundException: org.jpos.iso.ISOException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)
at org.sprint.controller.HandleController.handleRequest(HandleController.java:28)
at org.sprint.controller.HandleController$$FastClassByCGLIB$$fc3d18c.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.interceptor.CustomizableTraceInterceptor.invokeUnderTrace(CustomizableTraceInterceptor.java:256)
at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke(AbstractTraceInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at org.sprint.controller.HandleController$$EnhancerByCGLIB$$fbdc3830.handleRequest(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:212)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:900)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:722)
I have searched through StackOverflow's already asked questions, but have not found any of the situations in which the changes to the project were NONE. So I am feeling quite frustrated now because I have actually changed NOTHING and my project has stopped working. Help me please, any ideas would be grateful.
You should be sure that you have all jars in the CLASSPATH. In your case it is jpos.jar. And they all (with Spring) should be loaded withing the same classloader.
And one more advice: add -verbose option to the java (I guess Tomcat) to see from where your classes are loaded.
Please add the maven jpos dependency to you project.
<dependency>
<groupId>org.jpos</groupId>
<artifactId>jpos</artifactId>
<version>1.9.4</version>
</dependency>
Choose any one of the repository available from maven Maven Repository Link