Friday, September 18, 2015

Oracle Taleo WebService Sample Client Code to Create New Candidate and apply to a Taleo job offer (requisition)

Let's assume you are a Taleo Partner (EBS/Peoplesoft) and want to export a candidate from your application and import it into Taleo systems by attaching candidate to a existing Taleo job offer (requisition) .

<!-- Candidate Import Request with attaching Taleo job offer (requisition) -->
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:e="http://www.taleo.com/ws/tee800/2009/01/candidate">
   <soapenv:Header>
      <itk:Debug xmlns:itk="http://www.taleo.com/ws/itk21/2005/07">
         <itk:StackTrace>true</itk:StackTrace>
      </itk:Debug>
   </soapenv:Header>
   <soapenv:Body>
      <e:merge>
         <e:candidate>
            <e:Address>123 Main Street</e:Address>
            <e:Address2>Apartment 1</e:Address2>
            <e:City>Seattle</e:City>
            <e:EmailAddress>xxx@invalid.address.com</e:EmailAddress>
            <e:FirstName>XYZ</e:FirstName>
            <e:LastName>XYZ</e:LastName>
            <e:ZipCode>74554-234</e:ZipCode>
            <e:Applications>
               <e:Application>
                  <e:Requisition>
                     <e:Requisition>
                        <e:ContestNumber searchType="search" searchValue="XXXXX"/>
                     </e:Requisition>
                  </e:Requisition>
               </e:Application>
            </e:Applications>
         </e:candidate>
      </e:merge>
   </soapenv:Body>
</soapenv:Envelope>

Oracle Taleo WebService Sample Client Code to Create New Candidate

Let's assume you wants to import the candidates into Taleo systems. Using Taleo BulkAPI, CandidateService allows your application to create and update a candidate in Taleo systems.

We can implement the above usecase with following options:

  • Java Code using SAAJ: SAAJ stands for "SOAP with Attachments API for Java." With it, you can make Java API calls that generate XML messages which comply with the SOAP 1.1 or 1.2 specifications, as well as the WS-I Basic Profile 1.1 specification. It allows developers to read and write SOAP-based XML messages, and in some cases, to send and receive those messages over the Internet. SAAJ offers an alternative to JAX-RPC or JAX-WS
public class SOAPClientSAAJ {
    /**
     * This method process the new candidate creation
     * @return employeeNumber
     * @throws SOAPException
     * @throws Exception
     */
    public static String processCandidateCreationSOAPRequest() throws SOAPException, Exception {
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection = soapConnectionFactory.createConnection();

        // Trust to certificates
        doTrustToCertificates();

        // Send SOAP Message to SOAP Server
        String url = "https://xxx.taleo.net/enterprise/soap?ServiceName=CandidateService";
        SOAPMessage soapResponse = soapConnection.call(callCandidateCreationSOAPRequest(), url);
        String employeeNumber = processCandidateCreationSOAPResponse(soapResponse);
        return employeeNumber;
    }
 
    public SOAPClientSAAJ() {
        super();
    }
    
    /**
     * This method parse the soapResponse and gets the employeeNumber 
     * @param soapResponse
     * @return employeeNumber
     * @throws TransformerConfigurationException
     * @throws SOAPException
     * @throws ParserConfigurationException
     * @throws TransformerException
     * @throws SAXException
     * @throws IOException
     */
    private static String processCandidateCreationSOAPResponse(SOAPMessage soapResponse) throws TransformerConfigurationException,
                                                                               SOAPException,
                                                                               ParserConfigurationException,
                                                                               TransformerException, SAXException,
                                                                               IOException {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        Source sourceContent = soapResponse.getSOAPPart().getContent();
        StringWriter writer = new StringWriter();
        transformer.transform(sourceContent, new StreamResult(writer));
        String output = writer.toString();

        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        InputSource is = new InputSource();
        is.setCharacterStream(new StringReader(output));

        Document doc = db.parse(is);
        NodeList nodes = doc.getElementsByTagName("createResponse");
        Element element = (Element)nodes.item(0);
        NodeList name = element.getElementsByTagName("Number");
        Element line = (Element)name.item(0);
        return getCharacterDataFromElement(line).toString();
    }

    /**
     * This method creates the soapMessage and calls the webservice
     * @return
     * @throws Exception
     */
    private static SOAPMessage callCandidateCreationSOAPRequest() throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        // SOAP Envelope
        SOAPEnvelope envelope = soapPart.getEnvelope();
        envelope.addNamespaceDeclaration("can", "http://www.taleo.com/ws/tee800/2009/01/candidate");
        envelope.addNamespaceDeclaration("ns1",
                                         "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

        SOAPHeader soapHeader = envelope.getHeader();
        SOAPElement SecuritySoapElement = soapHeader.addChildElement("Security", "ns1");
        SOAPElement usernameTokenSoapElement = SecuritySoapElement.addChildElement("UsernameToken", "ns1");

        SOAPElement usernameSoapElement = usernameTokenSoapElement.addChildElement("Username", "ns1");
        usernameSoapElement.addTextNode("username");
        SOAPElement passwordSoapElement = usernameTokenSoapElement.addChildElement("Password", "ns1");
        passwordSoapElement.addTextNode("password");


        // SOAP Body
        SOAPBody soapBody = envelope.getBody();
        SOAPElement createSoapBodyElem = soapBody.addChildElement("create", "can");
        SOAPElement candidateSoapBodyElem = createSoapBodyElem.addChildElement("candidate", "can");

        SOAPElement emailAddressSoapBodyElem = candidateSoapBodyElem.addChildElement("EmailAddress", "can");
        emailAddressSoapBodyElem.addTextNode("xxx@invalid.address.com");

        SOAPElement addressSoapBodyElem = candidateSoapBodyElem.addChildElement("Address", "can");
        addressSoapBodyElem.addTextNode("123 Main Street");

        SOAPElement address2SoapBodyElem = candidateSoapBodyElem.addChildElement("Address2", "can");
        address2SoapBodyElem.addTextNode("Apartment 1");

        SOAPElement firstNameSoapBodyElem = candidateSoapBodyElem.addChildElement("FirstName", "can");
        firstNameSoapBodyElem.addTextNode("XYZ");

        SOAPElement lastNameSoapBodyElem = candidateSoapBodyElem.addChildElement("LastName", "can");
        lastNameSoapBodyElem.addTextNode("XYZ");

        // Save message
        soapMessage.saveChanges();
        return soapMessage;
    }

    /**
     * This method trust the https certificates 
     * @throws Exception
     */
    private static void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                    return;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                    return;
                }
            } };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" +
                                       session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

    private static String getCharacterDataFromElement(Element e) {
        Node child = e.getFirstChild();
        if (child instanceof CharacterData) {
            CharacterData cd = (CharacterData)child;
            return cd.getData();
        }
        return "";
    }

}

  • Java Code using Apache Axis2: - First you should Import the WSDL Files into Your Development Platform using below command.

“wsdl2java.bat -uri pathToWsdl/WsdlFilename -d xmlbeans -ns2p namespaceURL=javaPackageName”

public class CandidateDC {
 
    /**
     * Main method call the importCandidate method
     * @param args
     */
    public static void main(String[] args) {
        try {
            long employeeNumber = importCandidate();
            System.out.println("Candidate Num: " + employeeNumber);
        } catch (AxisFault e) {
            e.printStackTrace();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (WebServiceFault e) {
            e.printStackTrace();
        }
    }
 
    /**
     * This method process the new candidate creation
     * @return employeeNumber
     * @throws AxisFault
     * @throws RemoteException
     * @throws WebServiceFault
     */
    public static long importCandidate() throws AxisFault, RemoteException, WebServiceFault {
        CandidateServiceStub stub =
            new CandidateServiceStub("https://hostname/enterprise/soap?ServiceName=CandidateService");
        HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
        auth.setUsername("Username");
        auth.setPassword("Password");
        auth.setPreemptiveAuthentication(true); // activate preemptive authentication
        stub._getServiceClient().getOptions().setProperty(HTTPConstants.AUTHENTICATE, auth);


        CreateDocument createDoc = CreateDocument.Factory.newInstance();
        CreateDocument.Create create = createDoc.addNewCreate();
        Candidate candidate = create.addNewCandidate();

        SearchableStringField address = candidate.addNewAddress();
        address.setStringValue("123 Main Street");

        SearchableStringField address2 = candidate.addNewAddress2();
        address2.setStringValue("Apartment 1");

        SearchableStringField lastName = candidate.addNewLastName();
        lastName.setStringValue("XYZ");

        SearchableStringField firstName = candidate.addNewFirstName();
        firstName.setStringValue("XYZ");

        SearchableStringField emailAddress = candidate.addNewEmailAddress();
        emailAddress.setStringValue("xxx@invalid.address.com");

        CreateResponseDocument createResponse = stub.create(createDoc);
        long val = createResponse.getCreateResponse().getNumber();
        return val;
    }
 
 public CandidateDC() {
        super();
    }
}

If you get the "java.net.SocketException: Software caused connection abort: recv failed" issue - More Details

Thursday, January 15, 2015

Oracle Taleo WebService Integration - "java.net.SocketException: Software caused connection abort: recv failed"

Recently I was trying to integrate Oracle Taleo WebService with one of the 3rd party system. I tried with WSDL2Java from the Apache Axis2 and SAAJ (SOAP with Attachments API for Java) types for the integration.

But on both the types I was getting "java.net.SocketException: Software caused connection abort: recv failed" issue. Below is the error detail.

org.apache.axis2.AxisFault: Software caused connection abort: recv failed 
at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430) 
at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:197) 
at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:75) 
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:404) 
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:231) 
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:443) 
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:406) 
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229) 
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165) 
at com.taleo.www.ws.tee800._2009._01.candidate.CandidateServiceStub.create(CandidateServiceStub.java:1284) 
at com.taleo.Generic.main(Generic.java:54) 
Caused by: java.net.SocketException: Software caused connection abort: recv failed 
at java.net.SocketInputStream.socketRead0(Native Method) 
at java.net.SocketInputStream.read(SocketInputStream.java:152) 
at java.net.SocketInputStream.read(SocketInputStream.java:122) 
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) 
at java.io.BufferedInputStream.read(BufferedInputStream.java:254) 
at org.apache.commons.httpclient.HttpParser.readRawLine(HttpParser.java:78) 
at org.apache.commons.httpclient.HttpPars 

Solution:-

The error message that we are getting is not because of the java code, it's related to a HTTPS/SSL setup/configuration problem.

Connection to the Taleo zone requires use of the "HTTPS" protocol which uses "SSL". You need to Import the HTTPS Certificate into Java HTTPS certificates, this should solve the above issue.

Note:- If you are deploying your application to any web server, please check if the certificate is trusted by the 3rd party web server.

Steps to Import Certificate :-

  • Export the HTTPS Certificate into a file
    • Open your web browser
    •  Enter your web browser's "Options" utility. Internet Explorer users will need to click "Tools" and then "Internet Options," for example. Mozilla Firefox users will need to click "Tools" and then "Options..." Google Chrome users will need to click "Customize" and then "Options"
    • Click "Content" and then "Certificates" in Internet Explorer. Click on the certificate you'd like to export and then click on the "Export" button to export it for use on other servers
    • Click "Advanced" and then "View Certificates" in Mozilla Firefox. Click on the certificate you'd like to export and then click on the "Export" button to export it for use on other servers
    • Click "Under the Hood" and then "Manage Certificates" in Google Chrome. Click on the certificate you'd like to export and then click on the "Export" button to export it for use on other servers
  • Import the HTTPS Certificate into Java HTTPS certificates
    • Java HTTPS certificates stored in - $JAVA_HOME/jre/lib/security/cacerts
    • To import your new certificate into “cacerts” run below command:
“keytool -import -file amirssw.cer -keystore cacerts”
The Password is “changeit”