When trying to use a webservice, a NullPointerException is thrown, and expected log statements are missing in the application's log.
I get a NullPointerException in the following code:
public void useWebservice() {
initEndpoint();
try {
port.usefulFunctionWebserviceProvides(); // NullPointerException is thrown here!
} catch (javax.xml.ws.soap.SOAPFaultException ex) {
log.error("Something went wrong making a request to the webservice");
}
}
The initEndpoint method looks like this:
private volatile Webservice service = null; // instance variable
private WebservicePort port = null; // instance variable
private void initEndpoint() {
String username = "username"; // Loaded from a properties file
String password = "password"; // Loaded from a properties file
LoginResponse loginResponse;
Webservice theService = service;
if (theService == null || port == null) {
synchronized (this) {
theService = service;
if (theService == null) {
try {
log.info("Initializing Endpoint (service & port)"); // This line appears in the log
service = new Webservice();
port = service.getWebservicePort();
final String wsdlUrl = properties.getProperty(WSDL_URL, WSDL_DEFAULT_URL);
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, wsdlUrl);
log.info("EndpointAddress set");
LoginRequestType loginRequest = new LoginRequestType();
loginRequest.setUsername(username);
loginRequest.setPassword(password);
loginResponse = port.login(loginRequest, null, null);
} catch (Exception e) {
try {
log.info("re-Initializing Endpoint (service & port)");
// Try to connect to the webservice using a fallback URL
} catch (Exception e2) {
log.error("Couldn't connect to webservice");
service = null;
throw new CustomException();
}
}
if (loginResponse == null) {
service = null;
throw new CustomException();
}
}
}
}
}
None of the info logging is printed to the log file except for the log message "Initializing Endpoint (service & port)".
I don't understand how the port variable can be null in the useWebservice method. I also expect to see either "EndpointAddress set" or "re-Initializing Endpoint (service & port)" in the log file. But neither are printed to the file.
The code has worked fine before, but has started to give problems after being moved to a new project and used as a dependency.
The problem has been identified, it was a missing dependency. Because of that an error was thrown when the code tried to initialize the port. The catch block only catches exceptions so that code was never executed. If we caught throwable for example we would see the log statements from the catch block.
PS: Initializing the port object as it is done in the initEndpoint method in the question is NOT thread safe! The port needs to be initialized for each request.
Related
I'm trying to connect to the on-line broker https://test.mosquitto.org/ using the code below and the Paho library in Java:
private final String brokerURI = "test.mosquitto.org:1883"; //should be changed to 8883 with SSL
try { //tentativo di creazione del client
client = new MqttClient(brokerURI, idClient); <--NullPointerException here
client.setCallback(new ClientCallback(codaTopic, codaMessaggi, finestra)); //set delle callback
setConnectionOptions(); //set delle opzioni connessione
client.connect(opzioni); //connessione al server
} catch (MqttException e) {
System.err.println(e.getMessage());
System.err.println("Connessione fallita Client, riavviare il sistema.");
}
Connection options are set here:
private void setConnectionOptions() {
opzioni = new MqttConnectOptions();
opzioni.setAutomaticReconnect(true);
opzioni.setCleanSession(false);
opzioni.setConnectionTimeout(30);
opzioni.setKeepAliveInterval(60);
}
but it continues to show a NullPointerException while creating the MqttClient. In particular the console displays:
Exception in thread "Thread-3" java.lang.NullPointerException
at org.eclipse.paho.client.mqttv3.MqttConnectOptions.validateURI(MqttConnectOptions.java:489)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:291)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.<init>(MqttAsyncClient.java:185)
at org.eclipse.paho.client.mqttv3.MqttClient.<init>(MqttClient.java:226)
at org.eclipse.paho.client.mqttv3.MqttClient.<init>(MqttClient.java:138)
at client.Client.run(Client.java:78)
How can i manage to connect and use SSL?
Surfing the net none of the tutorial or guides were useful, I already downloaded the mosquitto.org.crtfile for SSL connection, but i don't know where to use it and I found no tutorials.
EDIT
Changing the BrokerUri to
private final String brokerURI = "tcp://test.mosquitto.org:1883"; //indirizzo broker
the console shows the error
Client non connesso (32104)
at org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:31)
at org.eclipse.paho.client.mqttv3.internal.ClientComms.sendNoWait(ClientComms.java:166)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.subscribe(MqttAsyncClient.java:835)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:322)
at org.eclipse.paho.client.mqttv3.MqttClient.subscribe(MqttClient.java:315)
at client.Client.subscribe(Client.java:214)
at client.Client.run(Client.java:89)
while trying to subscribe to a Topic with the instruction
client.subscribe(topic, 1);
The topic argument is a String that contains the topic name.
Mosquitto's URI needs the protocol. Taking a look at its source code, this is where your exception is being thrown, class MqttConnectOpts.java :
protected static int validateURI(String srvURI) {
try {
URI vURI = new URI(srvURI);
if (!vURI.getPath().equals("")) {
throw new IllegalArgumentException(srvURI);
}
if (vURI.getScheme().equals("tcp")) {
return URI_TYPE_TCP;
}
else if (vURI.getScheme().equals("ssl")) {
return URI_TYPE_SSL;
}
else if (vURI.getScheme().equals("local")) {
return URI_TYPE_LOCAL;
}
else {
throw new IllegalArgumentException(srvURI);
}
} catch (URISyntaxException ex) {
throw new IllegalArgumentException(srvURI);
}
}
So, it accepts 3 types of protocol prefixes: tcp, ssl, local. Regarding your example, you could try it this way:
TCP
private final String brokerURI = "tcp://test.mosquitto.org:1883";
SSL
private final String brokerURI = "ssl://test.mosquitto.org:8883";
I am writing a rest client using java.net which should do a PATCH request. But as PATCH is not a supported method in java.net, I used reflection to make it supported by changing the code like
private void updateConnectionToSupportPatchRequest(final HttpURLConnection conn)
throws ReflectiveOperationException {
try {
final Object targetConn;
if (conn instanceof HttpsURLConnectionImpl) {
final Field delegateField = HttpsURLConnectionImpl.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
targetConn = delegateField.get(conn);
} else {
targetConn = conn;
}
final Field methodField = HttpURLConnection.class.getDeclaredField("method");
methodField.setAccessible(true);
methodField.set(targetConn, "PATCH");
} catch (final NoSuchFieldException ex) {
LOGGER.error("NoSuchFieldException: {} ", ex.getMessage());
}
}
but when I deploy my application which uses my rest client in JBoss, I get this error -
java.lang.NoClassDefFoundError: sun/net/www/protocol/https/HttpsURLConnectionImpl
I looked up on this error and came across this post http://planet.jboss.org/post/dealing_with_sun_jdk_related_noclassdeffounderror_under_jboss
I tried the suggested solution in the post still getting the same error. Any ideas on how to get passed this issue?
P.S. I cannot use the Apache HttpClient or RestEasy(Jboss) as there is another 3PP being used in the project which does not support Apache HttpClient
Have you tried using the workaround X-HTTP-Method-Override before trying to fiddle with internal classes of the JDK? If that's the case, you can use the instance's getClass-method to access fields and use isAssignableFrom as alternative to instanceof.
Another approach to get rid off specifying concrete classes is just trying to get the field in HttpsURLConnection and assuming a non-Https-URLConnection if the field can't be found. This might look like the following code:
private void updateConnectionToSupportPatchRequest(final HttpURLConnection conn)
throws ReflectiveOperationException {
try {
final Object targetConn = conn;
try {
final Field delegateField = findField(conn.getClass(), "delegate");
delegateField.setAccessible(true);
targetConn = delegateField.get(conn);
}
catch(NoSuchFieldException nsfe) {
// no HttpsURLConnection
}
final Field methodField = findField(conn.getClass(), "method");
methodField.setAccessible(true);
methodField.set(targetConn, "PATCH");
} catch (final NoSuchFieldException ex) {
LOGGER.error("NoSuchFieldException: {} ", ex.getMessage());
}
}
private Field findField(Class clazz, String name) throws NoSuchFieldException {
while (clazz != null) {
try {
return clazz.getDeclaredField(name);
}
catch(NoSuchFieldException nsfe) {
// ignore
}
clazz = clazz.getSuperclass();
}
throw new NoSuchFieldException(name);
}
But this might fail at another level because - obviously - the class that is used within JBoss is not the one you implemented the workaround, so fields and methods might be named differently.
I've been given the task to move our application from WebLogic 12.1.3 to Payara 4.1 and have run into an issue that I feel I'm more or less at the end of the line of troubleshooting.
We have an EJB (a Stateless bean) that has two methods, one that makes a call to the Google Maps Directions API and one that makes a call to the Google Maps Geocoding API, both using the same credentials and Googles client libraries for Java. Both methods work perfectly running on WebLogic, but after switching to Payara the one using the Directions API gives me an error. Here's the relevant part of the stacktrace:
java.io.IOException: Server Error: 403 Forbidden
at com.google.maps.internal.OkHttpPendingResult.parseResponse(OkHttpPendingResult.java:258)
at com.google.maps.internal.OkHttpPendingResult.await(OkHttpPendingResult.java:167)
at com.google.maps.PendingResultBase.await(PendingResultBase.java:56)
at com.somecompany.integration.GoogleDirectionsIntegration.getDirections(GoogleDirectionsIntegration.java:XXX)
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:498)
So the geocoding-method still works on both platforms, but when attempting the call to the Directions API I get a 403 back from Google indicating that my credentials are messed up, but the very same credentials work for the geocoding call. The code hasn't been changed in any way switching from one platform to the other.
What's even more confusing is that if I grab the actual URL of the call to Google from the logs and try it in my browser, i.e. paste "https://maps.googleapis.com/maps/api/directions/json?client=gme-company&mode=driving&arrival_time=1435825037&o
rigin=Somewhere&destination=Somewhere+else&alternat
ives=false&signature=nfre3XYZ2kmuDX8Qibce87ZFKQQ=" into Chrome, it works. I get a proper answer from Google. (btw, those aren't the actual credentials or origin and destination I'm using, they've been "anonymized" :-)). I've also checked that this URL (which is built by the client library) is the same running on both platforms as well as used the URL Signing Debugger on Google's developer pages, but to no avail. There should be nothing wrong with my credentials.
I'm really at the end of the line here, having spent days troubleshooting and searching online without finding a solution.
Not that it matters that much but I didn't write this code myself, and the person who did of course doesn't work here anymore :-P
Anyway, here's the code (somewhat anonymized):
#Stateless
public class GoogleDirectionsIntegration {
private static final Logger LOGGER = Logger.getLogger(GoogleDirectionsIntegration.class.getName());
private GeoApiContext context = null;
/**
* Initializer
*/
#PostConstruct
public void init() {
LOGGER.log(Level.INFO, "initiating {0}", this.getClass().getSimpleName());
this.context = new GeoApiContext().setEnterpriseCredentials("gme-company", "companyGoogleCryptographicSecret");
this.context.setReadTimeout(1, TimeUnit.SECONDS)
.setRetryTimeout(1, TimeUnit.SECONDS)
.setConnectTimeout(1, TimeUnit.SECONDS)
.setWriteTimeout(1, TimeUnit.SECONDS);
OkHttpRequestHandler okHttpRequestHandler = null;
OkHttpClient okHttpClient = null;
try {
Field requestField = this.context.getClass().getDeclaredField("requestHandler");
requestField.setAccessible(true);
okHttpRequestHandler = (OkHttpRequestHandler) requestField.get(this.context);
Field f = okHttpRequestHandler.getClass().getDeclaredField("client");
f.setAccessible(true);
okHttpClient = (OkHttpClient) f.get(okHttpRequestHandler);
} catch (NoSuchFieldException | SecurityException | IllegalAccessException | IllegalArgumentException e) {
throw new IllegalStateException("Failed to create SSL context", e);
}
SSLContext sslCtx = this.getSslContext();
if (sslCtx != null && okHttpClient != null) {
SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory();
okHttpClient.setSslSocketFactory(sslSocketFactory);
}
}
private SSLContext getSslContext() {
TrustManager[] tm = new TrustManager[] {
new CustomTrustManager()
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, tm, new SecureRandom());
} catch (NoSuchAlgorithmException | KeyManagementException ex) {
throw new IllegalStateException("Failed to create SSL context", ex);
}
return sslContext;
}
public DirectionsRoute getDirections(final String origin, final String destination, final DistanceUnit distanceUnit,
#Nullable TransportMode mode, #NotNull Instant arrivalTime) throws NotFoundException {
TransportMode actualMode = mode == null ? TransportMode.CAR : mode;
DirectionsRoute[] directionsRoutes;
DirectionsApiRequest directionsApiRequest = DirectionsApi.getDirections(this.context, origin, destination);
directionsApiRequest.arrivalTime(new Instant(arrivalTime));
directionsApiRequest.alternatives(false);
directionsApiRequest.mode(this.toTravelMode(actualMode));
try {
DirectionsResult res = directionsApiRequest.await(); // THIS IS WHERE IT BREAKS!
directionsRoutes = res.routes;
} catch (Exception e) {
LOGGER.log(Level.WARNING, e.getMessage(), e);
throw new NotFoundException(e.getMessage());
}
if (directionsRoutes.length != 1) {
throw new NotFoundException("Failed to fetch valid directions");
}
return directionsRoutes[0];
}
public void getAddress(LatLng startLocation, Location location, boolean cacheOverride) throws Exception {
com.google.maps.model.LatLng gLatLng = new com.google.maps.model.LatLng(startLocation.getLat(), startLocation.getLng());
GeocodingApiRequest geocodingApiRequest = GeocodingApi.reverseGeocode(this.context, gLatLng);
GeocodingResult[] geocodingResults;
geocodingResults = geocodingApiRequest.await();
if (0 < geocodingResults.length) {
//.. Code that does stuff with the result..
} else {
LOGGER.log(Level.WARNING, "Received empty results from Google reverse geocode for [{0}].", startLocation);
}
}
}
So I solved it. The problem wasn't in the code but in the dependencies, or rather in a dependency to one of the dependencies - OkHttp. I simply changed the version and it works now.
I am getting the below exception before hitting a axis 2 webservice.
org.apache.axis2.AxisFault: org.apache.axis2.databinding.ADBException: Unexpected subelement underTimelyRenewal
I can't reproduce the same issue locally on tomcat or in DEV environment which runs in Weblogic. It justs happens only in 1 environment which runs on Weblogic 11g. This makes to think that I am missing some config in that environment, I am not sure what it is. Any help on this is highly appreciated.
Here is code that calls web service.
public com.ibs.accouting.employeeVerificationResponse getEmployeeVerificationRequest(
com.ibs.accounting.EmployeeVerificationRequest employeeVerificationRequest108)
throws java.rmi.RemoteException
{
org.apache.axis2.context.MessageContext _messageContext = null;
try{
org.apache.axis2.client.OperationClient _operationClient = _serviceClient.createClient(_operations[5].getName());
_operationClient.getOptions().setAction("http://ibs.com/accounting/WBLEmployeeVerificationRequest");
_operationClient.getOptions().setExceptionToBeThrownOnSOAPFault(true);
addPropertyToOperationClient(_operationClient,org.apache.axis2.description.WSDL2Constants.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR,"&");
// create a message context
_messageContext = new org.apache.axis2.context.MessageContext();
// create SOAP envelope with that payload
org.apache.axiom.soap.SOAPEnvelope env = null;
env = toEnvelope(getFactory(_operationClient.getOptions().getSoapVersionURI()),
employeeVerificationRequest108,
optimizeContent(new javax.xml.namespace.QName("http://ibs.com/accounting",
"getEmployeeVerificationRequest")));
//adding SOAP soap_headers
_serviceClient.addHeadersToEnvelope(env);
// set the message context with that soap envelope
_messageContext.setEnvelope(env);
// add the message contxt to the operation client
_operationClient.addMessageContext(_messageContext);
//execute the operation client
_operationClient.execute(true);
org.apache.axis2.context.MessageContext _returnMessageContext = _operationClient.getMessageContext(
org.apache.axis2.wsdl.WSDLConstants.MESSAGE_LABEL_IN_VALUE);
org.apache.axiom.soap.SOAPEnvelope _returnEnv = _returnMessageContext.getEnvelope();
java.lang.Object object = fromOM(
_returnEnv.getBody().getFirstElement() ,
com.ibs.accounting.EmployeeVerificationResponse.class,
getEnvelopeNamespaces(_returnEnv));
return (com.ibs.accounting.EmployeeVerificationResponse)object;
}catch(org.apache.axis2.AxisFault f){
org.apache.axiom.om.OMElement faultElt = f.getDetail();
if (faultElt!=null){
if (faultExceptionNameMap.containsKey(faultElt.getQName())){
//make the fault by reflection
try{
java.lang.String exceptionClassName = (java.lang.String)faultExceptionClassNameMap.get(faultElt.getQName());
java.lang.Class exceptionClass = java.lang.Class.forName(exceptionClassName);
java.lang.Exception ex=
(java.lang.Exception) exceptionClass.newInstance();
//message class
java.lang.String messageClassName = (java.lang.String)faultMessageMap.get(faultElt.getQName());
java.lang.Class messageClass = java.lang.Class.forName(messageClassName);
java.lang.Object messageObject = fromOM(faultElt,messageClass,null);
java.lang.reflect.Method m = exceptionClass.getMethod("setFaultMessage",
new java.lang.Class[]{messageClass});
m.invoke(ex,new java.lang.Object[]{messageObject});
throw new java.rmi.RemoteException(ex.getMessage(), ex);
}catch(java.lang.ClassCastException e){
// we cannot intantiate the class - throw the original Axis fault
throw f;
} catch (java.lang.ClassNotFoundException e) {
// we cannot intantiate the class - throw the original Axis fault
throw f;
}catch (java.lang.NoSuchMethodException e) {
// we cannot intantiate the class - throw the original Axis fault
throw f;
} catch (java.lang.reflect.InvocationTargetException e) {
// we cannot intantiate the class - throw the original Axis fault
throw f;
} catch (java.lang.IllegalAccessException e) {
// we cannot intantiate the class - throw the original Axis fault
throw f;
} catch (java.lang.InstantiationException e) {
// we cannot intantiate the class - throw the original Axis fault
throw f;
}
}else{
throw f;
}
}else{
throw f;
}
} finally {
_messageContext.getTransportOut().getSender().cleanup(_messageContext);
}
}
This error can be kind of misleading. AFter I modified the WSDL and added a new mandatory element, I created my client. Than this error appeared. The solution was, that I forgot to fill this element in one method of the my web service. If this error appears, also check if your mandatory elements are filled within the server.
That it works under one environment and not in an other can also mean, that a mandatory item is filled on one server (development server) and not under the other (productive server).
i try to passing numeric parameter to a web service that receive the value and return it back.
this is the snippet of the web method :
#WebMethod(operationName = "getNumber")
public Integer getNumber(#WebParam(name = "i")
Integer i) {
//TODO write your implementation code here:
System.out.println("number : "+i);
return i;
}
an this is the snippet of my client code :
Map results = FastMap.newInstance();
results.put("result", "success");
String endPoint = "http://localhost:8084/ProvideWS/MathWS";
URL endpoint=null;
try{
endpoint = new URL(endPoint);
}
catch (MalformedURLException e) {
org.ofbiz.base.util.Debug.log("Location not a valid URL "+e);
// TODO: handle exception
}
Service service = null;
Call call = null;
try{
service = new Service();
call = (Call)service.createCall();
call.setTargetEndpointAddress(endpoint);
String nameSpace = "http://ws/";
String serviceName = "getNumber";
call.setOperationName(new QName(nameSpace, serviceName));
call.addParameter("i",org.apache.axis.Constants.XSD_INTEGER , ParameterMode.IN);
call.setReturnType(org.apache.axis.Constants.XSD_INTEGER);
Object msg[] = new Object[]{new Integer(5)};
for (Object o : msg) {
org.ofbiz.base.util.Debug.log("object to be sent===== "+o.toString());
}
Object ret = call.invoke(msg);
results.put("result", "result : "+ ret.toString());
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
org.ofbiz.base.util.Debug.log("exc when running soap client test : "+e);
results.put("result", "error : "+e);
}
return results;
the problem is the return value in the client always 0 (the server received the number as zero), the method i used to pass the parameter works fine when the paramater is String. I.ve tried to hard-coding the return value in server and the output in client is fine, so i thought it must be how the server retrieved the parameter is the problem.
do you have any idea why this is happen and how to solve this?
any help will be appreciated, thanks
I don't know what is causing your problem. But the first thing I would do would be to try to capture the actual request that is being sent to the server. That should give you some clues as to whether the root problem is on the client or server side.