CXF generated SOAP client


Creating a SOAP client for a SOAP web service is very straight forward when using CXF. Given a WSDL url or a WSDL file, create a project with a pom.xml containing the following:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rightnow.ws</groupId>
    <artifactId>rightnow</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>3.0.4</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>https://twinspires--tst.custhelp.com/cgi-bin/twinspires.cfg/services/soap?wsdl</wsdl>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

When you run mvn compile, it will generate classes in the generated-sources/cxf directory.

The next step is to use the service client. The normal usage pattern is below. The service is instantiated, then the port is retrieved.

package com.rightnow.ws.wsdl.v1_2;

import com.rightnow.ws.metadata.v1_2.MetaDataClass;
import org.junit.Test;

import javax.xml.datatype.XMLGregorianCalendar;
import java.util.List;

import static org.junit.Assert.assertNotNull;

/**
 * @author norris.shelton
 */
public class TestRightNowSyncService {

    @Test
    public void testName() throws Exception {
        RightNowSyncService rightNowSyncService = new RightNowSyncService();
        RightNowSyncPort rightNowSyncPort = rightNowSyncService.getRightNowSyncPort();

        XMLGregorianCalendar metaDataLastChangeTime = rightNowSyncPort.getMetaDataLastChangeTime();
        assertNotNull(metaDataLastChangeTime);

        List<MetaDataClass> metaDataClasses = rightNowSyncPort.getMetaData();
        assertNotNull(metaDataClasses);

    }
}

How to get the first entry from a LinkedHashMap

I had an array of Strings. I needed to be able to quickly locate each item, so I fed it into a LinkedHashSet.

                Map<String, Boolean> newTableNames = new LinkedHashMap<>(pokerTableNames.length);
                for (String pokerTableName : pokerTableNames) {
                    newTableNames.put(pokerTableName, false);
                }

Later in the code, I needed to grab an item out of the list. My first cut was involved a for-loop. I got the first KeyValueSet, then called remove witht the value.

An easier way seems to be…

String candidateTableName  = newTableNames.entrySet().iterator().next().getKey();

UnsupportedOperationException when trying to iterate over Hazelcast replicatedMap

I needed to iterate over the values contained in a replicatedMap. I thought it would be as simple as:

hz.<Long, GameInfo>replicatedMap(DO.DESK_MAP, DO.DESK_MAP).values();

It would show that there were 2006 entries, but I couldn’t touch them.

I later stumbled upon the following:

hz.mapValues(DO.DESK_MAP);

This gave me a Collection of the values that I could iterate over.

Getting dotCMS JSON API to return more than 10 rows

The dotCMS JSON API is pretty easy to use. It even tells you the query for the content that you are looking for. That makes it super easy to use. What I didn’t know was that the results default to a limit of 10 records.

Here was my original query.

http://youbet.com/api/content/render/false/query/+structureName:PokerTableNameAdjectives%20+(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc/limit/30

That was easy enough, but how to you specify more? You specify the optional limit. It’s pretty easy, once you know what you are looking for.

/api/content/limit/<integer-limit>

That was easy enough. Here is what the final query looks like.

http://youbet.com/api/content/render/false/query/+structureName:PokerTableNameAdjectives%20+(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc/api/content/limit/1000

Getting a list of objects via RestTemplate

Usually we get back an object. Sometimes the object will contain a list. What needs to happen when you need to get back a list of Strings? RestTemplate accepts a parameter that tells it what the data it receives will be put in. I used a String array. It converts the JSON object into a String[] and away I go.

                    String[] pokerTableNames =
                        restTemplate.getForObject(pokerSettingsService.getValueByName(PokerSettings.IGP_ADAPTER_URL) + "/poker/tableNames",
                            String[].class);

Jackson2 and the dreaded com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException

I had a RESTful call to a dotCMS 2.x server worked out. I called it later in the day and a new property was being sent. This resulted in the following exception.

Method threw 'com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException' exception.
class com.cdi.igp.models.dotcms.PokerClient
stInode
 size = 3
 (3 known properties: "version", "whatsNew", "clientType"])
 size = 3
[Source: {"contentlets":[{...removed for brevity...}]}; line: 1, column: 29]
Unrecognized field "stInode" (class com.cdi.igp.models.dotcms.PokerClient), not marked as ignorable
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "stInode" (class com.cdi.igp.models.dotcms.PokerClient), not marked as ignorable (3 known properties: "version", "whatsNew", "clientType"])
 at [Source: ...removed for brevity...]}; line: 1, column: 29] (through reference chain: com.cdi.igp.core.dotcms.DotCmsPokerClientResponse["contentlets"]->java.util.ArrayList[0]->com.cdi.igp.models.dotcms.PokerClient["stInode"])

 size = 0

I fixed it by adding the following to the top of the class that I was mapping the data into.

@JsonIgnoreProperties(ignoreUnknown = true)

Problem solved.

Problems using dotCMS 2.x Restful services

I had a URL that would work when I pasted it into the web browser and would also work in the Chrome Advanced Rest Client. Each time I tried to call it with a Spring Rest Template, I got a HTTP 406.

    /**
     * Gets the poker client content objects from dotCMS.
     * @return poker clients model object
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public PokerClientsModel getPokerClients() throws InvocationTargetException, IllegalAccessException {

        String url = settingRepository.findSettingByIdSetting(SettingEnum.HOST_URL.key()).getValue() +
            "/api/content/render/false/query/+structureName:PokerClient%20+" +
            "(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)" +
            "%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc";

        DotCmsPokerClientResponse dotCmsPokerClientResponse = restTemplate.getForObject(url,
                                                                                        DotCmsPokerClientResponse.class);
        PokerClientsModel pokerClientsModel = new PokerClientsModel();
        PokerClient pokerClient;
        for (DotCmsPokerClient dotCmsPokerClient : dotCmsPokerClientResponse.getDotCmsPokerClients()) {
            pokerClient = new PokerClient();
            BeanUtils.copyProperties(pokerClient, dotCmsPokerClient);
            pokerClientsModel.getPokerClients().add(pokerClient);
        }

        return pokerClientsModel;

    }

That just plain didn’t work.

Method threw 'org.springframework.web.client.HttpClientErrorException' exception.
406
Not Acceptable

 size = 8
UTF-8
406 Not Acceptable
org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable

 size = 0

I thought about what the browser could be sending that I wasn’t. It hit me that the browser may be sending the content type as text/plain. It is a bit of a pain in the rear-end to send a content type on a get request. I eventually got to set the content type by using the Http Entity.

    /**
     * Gets the poker client content objects from dotCMS.
     * @return poker clients model object
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public PokerClientsModel getPokerClients() throws InvocationTargetException, IllegalAccessException {

        String url = settingRepository.findSettingByIdSetting(SettingEnum.HOST_URL.key()).getValue() +
            "/api/content/render/false/query/+structureName:PokerClient%20+" +
            "(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)" +
            "%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_PLAIN);

        HttpEntity entity = new HttpEntity(headers);
        HttpEntity<String> dotCmsPokerClientResponse = restTemplate.exchange(url,
                                                                             HttpMethod.GET,
                                                                             entity,
                                                                             String.class);
        return pokerClientsModel;
    }

This did work better. No more HTTP 406, but the return object contained a blank contentlets array.

<200 OK,{"contentlets":[]},{Date=[Mon, 02 Feb 2015 15:26:09 GMT], Server=[Apache-Coyote/1.1], Content-Type=1, Set-Cookie=[JSESSIONID=8CDC0C67730932FAEBBB729FBA5E2BBA; Path=/, ROUTEID=.1; path=/], Vary=[Accept-Encoding], Keep-Alive=[timeout=5, max=100], Connection=[Keep-Alive], Transfer-Encoding=[chunked]}>

Frustration set in and I was starting to get desperate. I got the idea of using HttpClient directly to make the call.

    /**
     * Gets the poker client content objects from dotCMS.
     * @return poker clients model object
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public PokerClientsModel getPokerClients() throws InvocationTargetException, IllegalAccessException {

        String url = settingRepository.findSettingByIdSetting(SettingEnum.HOST_URL.key()).getValue() +
            "/api/content/render/false/query/+structureName:PokerClient%20+" +
            "(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)" +
            "%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc";

        return get(url);
    }

    /**
     * Performs a HTTP get of the specified URL.
     * @param url the desired URL.
     * @return Http response body as a string
     */
    protected String get(String url) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String responseBody = null;
        try {
            responseBody = httpClient.execute(httpGet, responseHandler);
        } catch (IOException e) {
            logger.error("IOException", e);
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpClient.getConnectionManager().shutdown();
        }
        return responseBody;
    }

Success!!!!!

{"contentlets":[{"stInode":"d5af8654-aa65-4f2f-b2cd-bc6bf54753d5","owner":"norris.shelton","lastReview":"2015-01-30 16:21:56.226","modUser":"norris.shelton","identifier":"42ee0e8c-bd3c-4bae-ac51-b7837dc8e832","version":"000.000.000","clientType":"android","sortOrder":0,"modDate":"2015-01-30 16:21:56.238","host":"915f2552-793a-4f17-96d0-f0955fcc698f","whatsNew":"Initial Android Version","languageId":1,"inode":"ef33dbd6-2e47-44f7-a47f-daaa5c52e74b","folder":"SYSTEM_FOLDER"},{"stInode":"d5af8654-aa65-4f2f-b2cd-bc6bf54753d5","owner":"norris.shelton","lastReview":"2015-01-30 16:21:41.265","modUser":"norris.shelton","identifier":"b670a674-fb54-425a-93b8-432c8443e02d","version":"000.000.000","clientType":"ios","sortOrder":0,"modDate":"2015-01-30 16:21:41.278","host":"915f2552-793a-4f17-96d0-f0955fcc698f","whatsNew":"Initial IOS version","languageId":1,"inode":"929fb049-1c85-4376-bc9f-143981466a0a","folder":"SYSTEM_FOLDER"},{"stInode":"d5af8654-aa65-4f2f-b2cd-bc6bf54753d5","owner":"norris.shelton","lastReview":"2015-01-30 16:21:29.787","modUser":"norris.shelton","identifier":"df0ce56f-8e43-4169-9632-eb05fddd442f","version":"000.000.000","clientType":"flash","sortOrder":0,"modDate":"2015-01-30 16:21:29.8","host":"915f2552-793a-4f17-96d0-f0955fcc698f","whatsNew":"Initial Flash version","languageId":1,"inode":"8ff7fe3f-8064-42cf-8d9a-eaf6f65b52f9","folder":"SYSTEM_FOLDER"}]}

Using NIO Files to write a file

I was working on a piece of code and noticed that it was using an older method to write a file. A fileWriter was used to to write the file. That was wrapped with a bufferedWriter. Here is what the original code looked like.

        BufferedWriter outputWriter = null;
        outputWriter = new BufferedWriter(new FileWriter(filename));
        for (int i = 0; i < x.length; i++) {
            if (i == x.length -1) {
                outputWriter.write(Integer.toString(x[i]));
            } else {
                outputWriter.write(Integer.toString(x[i]) + ",");
            }

            outputWriter.newLine();
        }
        outputWriter.flush();
        outputWriter.close();

I changed it to a NIO Files implementation.

Files.write(Paths.get("/igs/rng/test/" + provider + ".csv"), stringBuilder.toString().getBytes());

It doesn’t get any easier than that.

Try-with-resources

I had some code that was being code reviewed and it was discovered that a buffered reader did not close the reader. That was the perfect time to use the try-with-resources.

The original code looked like:

/**
     * Retrieves the diagnostic information from the Comscire device.
     * @return String containing the "Status" and "DeviceID" information
     * @throws IOException
     */
    public String getDiagnostics() throws IOException {
        StringBuilder output = new StringBuilder();
        try {
            Process process =
                new ProcessBuilder("/usr/local/bin/diagnostics").start();

            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String data = null;
            boolean done = false;
            while ((data = br.readLine()) != null && !done) {
                if (StringUtils.startsWith(data, "Status") ||
                    StringUtils.startsWith(data, "DeviceID")) {
                    output.append("\t").append(data).append("\n");
                } else if (StringUtils.startsWith(data, "Get 128 Raw Bytes")) {
                    done = true;
                }
            }
        } catch (IOException e) {
            setErrors(true);
            logger.error("Unable to get diagnostics from Comscire process", e);
            throw e;
        }

        return output.toString();
    }

The new code takes advantage of the try-with-resources.

    /**
     * Retrieves the diagnostic information from the Comscire device.
     * @return String containing the "Status" and "DeviceID" information
     * @throws IOException
     */
    public String getDiagnostics() throws IOException {
        StringBuilder output = new StringBuilder();
        try {
            Process process =
                new ProcessBuilder("/usr/local/bin/diagnostics").start();

            try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String data = null;
                boolean done = false;
                while ((data = br.readLine()) != null && !done) {
                    if (StringUtils.startsWith(data, "Status") ||
                        StringUtils.startsWith(data, "DeviceID")) {
                        output.append("\t").append(data).append("\n");
                    } else if (StringUtils.startsWith(data, "Get 128 Raw Bytes")) {
                        done = true;
                    }
                }
            }
        } catch (IOException e) {
            setErrors(true);
            logger.error("Unable to get diagnostics from Comscire process", e);
            throw e;
        }

        return output.toString();
    }

Another case that I had was where an exception was being thrown from within the try-with-resources. Here is what a try-with-resources looks like with an exception.

    /**
     * Fills the integer queue with integers.  Opens the process that calls the USB device, reads the data, splits the
     * CSV into integers and adds them to the queue.  Sets the RNG device to available as it writes integers to the
     * queue.
     * @throws InterruptedException throws if the put operation is interrupted by a timeout
     */
    public void getRandomIntegerData() throws IOException, InterruptedException {
        int queueSize = integerQueue.size();
        try {
            logger.info("Retrieving {} integers from Comscire by calling randint32...",
                        DESIRED_QUEUE_LENGTH - queueSize);
            Process process =
                    new ProcessBuilder("/usr/local/bin/randint32",
                                       Integer.toString(DESIRED_QUEUE_LENGTH - queueSize)).start();

            try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String data = br.readLine();
                for (String stringInt : data.split(",")) {
                    integerQueue.put(Integer.valueOf(stringInt));
                    // check it to ensure that it hasn't been emptied as fast as it could be filled
                    if (integerQueue.size() > 0) {
                        setAvailable(true);
                        setErrors(false);
                    }
                }
            } catch (InterruptedException e) {
                logger.error("Unable to add integers to the Comscire queue", e);
                throw e;
            }
        } catch (IOException e) {
            setErrors(true);
            logger.error("Unable to get integers from Comscire process", e);
            throw e;
        }
    }

Things I learned in the pursuit of code

LinkedIn Auto Publish Powered By : XYZScripts.com