Authentication issue using QuickBooks Web Connector: Object reference not set to an instance of an object

百般思念 提交于 2019-12-11 05:29:56

问题


(Yes, I realize that this question is similar to another question posted; however, that question was never answered.)

Objective

I'm trying to use Clojure with Axis 2 to access QuickBooks data using the QuickBooks WebConnector (QBWC from now on). QBWC uses SOAP to communicate with external applications, so that's why my Clojure application uses Axis 2 as a SOAP interface. I use micha's clj-soap from GitHub to provide higher-level (abstracted) Clojure interop with the Java calls of Axis 2.

Issue

The issue is in authenticating my SOAP web service with QBWC. With the authenticate method of my SOAP web service, QBWC throws an error. In the QBWC log file it says the following:

QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message: Object reference not set to an instance of an object.
StackTrace = at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector

Code

Below is the Clojure code that defines a web service called SOCAccess for the Axis 2 server I'm using.

(For those unfamiliar with Clojure but familiar with Java, the following code creates a class called developer.intuit.com.SOCAccess and defines a number of methods which are needed to communicate with QBWC (including authenticate, serverVersion, etc.). The carets indicate the return or parameter type. Clojure compiles into Java bytecode and by default it doesn't use strong typing, which translates into most type hints being Object, but because of the way Java2WSDL works, strong typing is required. For instance:

Type ^String ends up as <xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>

Type ^Object ends up as <xs:element minOccurs="0" name="return" nillable="true" type="xs:anyType"/>

Type ^"[Ljava.lang.String;" is the same thing as String[], and ends up as <xs:element maxOccurs="unbounded" minOccurs="0" name="return" nillable="true" type="xs:string"/>)

(soap/defservice developer.intuit.com.SOCAccess
  (authenticate2 ^"[Ljava.lang.String;" [^String username ^String password]
    (authenticate2* username password))
  (authenticate ^"[Ljava.lang.String;" [^String username ^String password]
    (authenticate* username password))
  (prefix35authenticate ^"[Ljava.lang.String;" [^String username ^String password]
    (authenticate* username password))
  (sendRequestXML ^Object
    [^String ticket ^String hcp-response ^String company-file-name ^String qb-xml-country
     ^Integer qb-xml-major-vers, ^Integer qb-xml-minor-vers]
    (send-request-xml ticket hcp-response company-file-name qb-xml-country qb-xml-major-vers qb-xml-minor-vers))
  (receiveResponseXML  ^Integer [^String ticket ^String response ^String hresult ^String message]
    (receive-response-xml ticket response hresult message))
  (connectionError     ^Object [^String ticket ^String hresult ^String message]
    (connection-error ticket hresult message))
  (getLastError        ^String [^String ticket]
    (get-last-error ticket))
  (closeConnection     ^String [^String ticket]
    (close-connection ticket))
  (getServerVersion    ^String [^String ticket] (server-version ticket))
  (serverVersion       ^String [^String ticket] (server-version ticket))
  (clientVersion       ^String [^String version] (client-version version))
  (interactiveDone     ^String [^String ticket] (interactive-done ticket))
  (interactiveRejected ^String [^String ticket ^String reason] (interactive-rejected ticket reason)))

Server Initialization

The output window prints the following once I start an AxisServer and call .addService using the class name "developer.intuit.com.SOCAccess", which is a class compiled from the code above:

Jul 07, 2014 11:22:20 AM org.apache.axis2.transport.http.server.DefaultConnectionListener run
INFO: Listening on port 6060

And everything appears to be running normally.

SOAP Calls

However, when I make the SOAP call (authenticate "my-username" "my-password") to my web service within the JVM I'm running, the return value is supposed to be a String[] and the println() output shows that it is indeed a String[] but the return value is shown as only being the first element of the array, which is strange. My guess is that this is the cause of the Object reference not set to an instance of an object error from QBWC, because it's trying to get the nth element of a String as if it were an array.

========

Any thoughts? I realize this is a long question. Let me know what else you would like me to provide in the way of code, WSDLs, etc.

Thanks!

ADDENDUM: LOG FILE

20140707.20:06:40 UTC   : QBWebConnector.WebServiceManager.DoUpdateSelected() : updateWS() for application = 'SOCAccess' has STARTED
20140707.20:06:40 UTC   : QBWebConnector.RegistryManager.getUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock = FALSE
20140707.20:06:40 UTC   : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to True
20140707.20:06:40 UTC   : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session locked *********************
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.instantiateWebService() : Initiated connection to the following application.
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.instantiateWebService() : AppName: SOCAccess
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.instantiateWebService() : AppUniqueName (if available): SOCAccess
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.instantiateWebService() : AppURL: http://localhost:6060/axis2/services/SOCAccess
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_serverVersion() : *** Calling serverVersion().
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_serverVersion() : Received from serverVersion() following parameter:<serverVersionRet="">
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_serverVersion() : This application sent a null for server version. Allowing update operation.
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_clientVersion() : *** Calling clientVersion() with following parameter:<productVersion="2.1.0.27">
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_clientVersion() : Received from clientVersion() following parameter:<clientVersionRet="">
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_clientVersion() : This application agrees with the current version of QBWebConnector. Allowing update operation.
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_authenticate() : Authenticating to application 'SOCAccess', username = 'alexandergunnarson'
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="alexandergunnarson"><password=<MaskedForSecurity>
20140707.20:06:40 UTC   : QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Object reference not set to an instance of an object.
More info:
StackTrace =    at QBWebConnector.WebService.do_authenticate(String& ticket, String& companyFileName)
Source = QBWebConnector
20140707.20:06:40 UTC   : QBWebConnector.RegistryManager.setUpdateLock() : HKEY_CURRENT_USER\Software\Intuit\QBWebConnector\UpdateLock has been set to False
20140707.20:06:40 UTC   : QBWebConnector.RegistryManager.setUpdateLock() : ********************* Update session unlocked *********************
20140707.20:06:40 UTC   : QBWebConnector.WebServiceManager.DoUpdateSelected() : Update completed with errors. See log (QWClog.txt) for details.

ADDENDUM: SOAP IN

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
  <soapenv:Body>
    <axis2ns34:authenticate xmlns:axis2ns34=\"http://developer.intuit.com/\">
      <axis2ns35:args0 xmlns:axis2ns35=\"http://developer.intuit.com/\">
        alexandergunnarson
      </axis2ns35:args0>
      <axis2ns36:args1 xmlns:axis2ns36=\"http://developer.intuit.com/\">
        password
      </axis2ns36:args1>
    </axis2ns34:authenticate>
  </soapenv:Body>
</soapenv:Envelope>

ADDENDUM: SOAP OUT

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">
  <soapenv:Body>
    <ns:authenticateResponse xmlns:ns=\"http://developer.intuit.com/\">
      <return>my-session-token</return>
      <return>none</return>
      <return>60</return>
      <return>60</return>
    </ns:authenticateResponse>
  </soapenv:Body>
</soapenv:Envelope>

UPDATE

Lots of things have happened since last I posted. 1) I tried to implement ArrayOfString, but that didn't integrate into the WSDL well. 2) I downloaded the QuickBooks WSDL from the Intuit website and used WSDL2Java (in Axis2) to generate a megalithic (10K LOC) .java file called QBWebConnectorSvcStub.java. 3) I tried extending the class and overriding the methods, but I kept getting lots of exceptions/errors. 4) I then tried editing the source code of the QBWebConnectorSvcStub class, specifically focusing on certain methods (editing authenticate, serverVersion, and clientVersion first because that's what QBWC first calls). For these methods, I tied the return values to functions in a Clojure class, passing the input of the QBWebConnectorSvcStub methods to the corresponding Clojure functions and returning the output of said functions. Basically I had the Clojure functions do the work and QBWebConnectorSvcStub act as a SOAP go-between. 5) At this point, I'm back to the same error as before (although blessedly, clientVersion works as expected, as evidenced by the log: Received from clientVersion() following parameter:<clientVersionRet="">:

QBWebConnector.SOAPWebService.do_authenticate() : Authenticating to application 'QBWebConnectorSvcStub', username = 'alexandergunnarson'
QBWebConnector.SOAPWebService.do_authenticate() : *** Calling authenticate() with following parameters:<userName="alexandergunnarson"><password=<MaskedForSecurity>
QBWebConnector.SOAPWebService.do_authenticate() : QBWC1012: Authentication failed due to following error message.
Object reference not set to an instance of an object.

The SOAP output to QuickBooks for this is:

 <ns:authenticateResponse xmlns:ns="http://developer.intuit.com/">
    <return xmlns:ax22="http://io.java/xsd" xmlns:ax21="http://rmi.java/xsd" xmlns:ax25="http://developer.intuit.com/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ax25:QBWebConnectorSvcStub_AuthenticateResponse">
      <authenticateResult>
        <string xmlns="http://developer.intuit.com/">
          my-session-token
        </string>
        <string xmlns="http://developer.intuit.com/">
          nvu
        </string>
        <string xmlns="http://developer.intuit.com/">
          60
        </string>
        <string xmlns="http://developer.intuit.com/">
          60
        </string>
      </authenticateResult>
    <authenticateResultSpecified>
      true
    </authenticateResultSpecified>
  </return>
</ns:authenticateResponse>

Luckily (!) there is now only one return value, unlike before.

Having taken a look at the example working authenticate SOAP request, perhaps there's still an issue because I took out the SOAP envelope/headers? They were giving me problems with nullPointerExceptions and such. I'll try to put them back in.

FINAL WORD

The next installment of this painful adventure is now here.


回答1:


I am not sure what your QBC file looks like (the xml file where your app is defined for Quickbooks Web Connector), but I fixed a similar problem by changing the Style setting from

<Style>RPC</Style>

to

<Style>DocWrapped</Style>

You may want to try the 'DocWrapped' or 'RPC' values if it is not defined. Details for Style from the QBWC_proguide:

The SOAP encoding style used by your web service. If not supplied, the default used is Document. Document is the standard encoding style used by .NET when the [WebMethod] attribute is applied to a function declaration. Optionally, you can specify the value DocWrapped. DocWrapped interoperates very well with Axis web services that are built as we recommend, using WSDL2Java to generate Java web classes from the standard WSDL used by the web connector (http:// developer.intuit.com/uploadedFiles/Support/ QBWebConnectorSvc.wsdl) Or, optionally, you can specify the value RPC. The RPC style is the standard encoding style used by Axis when a Java class is automatically converted to a SOAP service either through JWS or the Java2WSDL tool.



来源:https://stackoverflow.com/questions/24618311/authentication-issue-using-quickbooks-web-connector-object-reference-not-set-to

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!