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;
        }
    }

Calling a native program from within Java

It had been a long time since I had a need to call a system process from inside Java. The last time I needed to do this, I used Runtime.exec(). Now there is a new sheriff in town… ProcessBuilder. ProcessBuilder was introduced in JDK 5 and makes it super simple to call native processes.

I had two separate cases that I needed to solve. One was a call to a C program with a parameter that returned one line of objects that I needed to parse. The other was a call to a C and it returned multiple lines to me. I only cared about some of the lines of output from the program.

Here is the first example. It calls a C program with one parameter and parses the single line of output. I can call the C program from the command line via:

/usr/local/bin/randint32  5

The output is similar to:

2048211571,-446295626,-1826753911,773673606,-163405466,

Here is the Java method that I used to call the C program and parse the data:

  • Line 11 – 12 – The ProcessBuilder is instantiated with the command as the first parameter and the parameter to the command as the second parameter.
  • Line 13 – This is where the process is returned from calling start() on the ProcessBuilder object.
  • Line 15 – The input stream is retrieved from the process object.

Beyond the Process/ProcessBuilder processing is normal Java code. The process returns me one line, which contains comma-separated integers. I split the string into a bunch of strings containing integer data. I convert them to integers and add them to the Queue. I also set a couple of flags that are related to the application, but are beyond the scope of this article.

    /**
     * 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 integersToGenerate = DESIRED_QUEUE_LENGTH - integerQueue.size();
        try {
            logger.info("Retrieving {} integers from Comscire by calling randint32...", integersToGenerate);
            ProcessBuilder processBuilder = new ProcessBuilder("/usr/local/bin/randint32",
                                                               Integer.toString(integersToGenerate));
            Process process = processBuilder.start();

            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 (IOException e) {
            setErrors(true);
            logger.error("Unable to get integers from Comscire process", e);
            throw e;
        }
    }

The next C program that I had to call returned diagnostic information from a Comscire hardware random number generator. The command that I used to retrieve the data is:

/usr/local/bin/diagnostics

The data is returned as a series of lines containing the following data. I was only concerned with two of the lines from the output:

  • Status: QNG device reports success.
  • DeviceID QWR40026

 
Start Device...

Status: QNG device reports success.

DeviceID QWR40026


Get 128 Raw Bytes - Level 2, Stream 3 (hex)

76 6D 02 B6 BC 05 1D B1 7C 92 BC D7 69 2D 86 27 CC 5D EE 16 4F 17 97 EA B9 BA 32 AE E4 FC FA 57 4B 9C 74 48 0C 51 79 5B 47 82 3C 4B 66 EE 5A EA 83 C2 12 10 AF F2 8F 7B E2 D0 CD 84 40 96 94 A3 30 2D C3 AD 7F FD 06 9C 1F 2A 20 26 41 73 B9 EA 4B 82 DE AB 31 D8 FA 5D 20 1E EA 0F F2 D6 5A BB 4A 82 67 70 C4 C8 40 6E CA 7B 84 DA B4 3D 99 0A A6 BC 36 C3 94 D9 84 D9 F9 5B 00 95 01 4C 64 E2

EXIT...
  • Line 9 – The ProcessBuilder is instantiated with the command.
  • Line 10 – The process is assigned from calling processBuilder.start().
  • Line 12 – The input stream is retrieved from the process object.

I loop over the individual lines of data looking for the 2 lines of data that I need to retrieve. I add those to a StringBuilder. Just for efficiency’s sake, I look for a line that tells me that I am done. There is no data that I am concerned with after this line.

    /**
     * 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 {
            ProcessBuilder processBuilder = new ProcessBuilder("/usr/local/bin/diagnostics");
            Process process = processBuilder.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();
    }

There you have it. Two examples showing how easy it is to use ProcessBuilder to execute native processes from a Java application.

Things I learned in the pursuit of code

LinkedIn Auto Publish Powered By : XYZScripts.com