Thursday, February 18, 2016

Find Tomcat Version

The Tomcat browser user interface displays the version at the top.  If it's running locally, you can usually reach it at localhost:8080.


From Command Line


To find the version of Tomcat from the command line:
java -cp {tomcat home directory}/lib/catalina.jar org.apache.catalina.util.ServerInfo
The result will look like:
Server version: Apache Tomcat/7.0.52
Server built:   Feb 13 2014 10:24:25
Server number:  7.0.52.0
OS Name:        Mac OS X
OS Version:     10.11.3
Architecture:   x86_64
JVM Version:    1.7.0_75-b13
JVM Vendor:     Oracle Corporation
If Tomcat is running, you can use this script to show its version.  It looks for Tomcat among the running processes and uses the command line options specified (catalina.base or catalina.home) when it was started to find the home directory.
#!/bin/bash
# If Tomcat is running, display its version.
#
# This script looks for Tomcat among running process and locates its
# home directory from the command line options specified when it was
# started, either in catalina.base or catalina.home.
#
# Trick: use grep "[c]atalina.base" and awk "[c]atalina.base" so the
# regular expression won't match itself and return 2 results.
# "grep [c]atalina.base" does not match the string "grep [c]atalina.base".
# Try doing "ps -ef | grep catalina.base" and see that it returns 2 results.
# Try doing "ps -ef | grep [c]atalina.base" and see that it returns 1 result.

TOMCAT_DIR=`ps -ef | grep "[c]atalina.base" | awk -F "[c]atalina.base=" '{print $2}' | cut -d ' ' -f 1`
if [ -z "$TOMCAT_DIR" ]; then
    TOMCAT_DIR=`ps -ef | grep "[c]atalina.home" | awk -F "[c]atalina.home=" '{print $2}' | cut -d ' ' -f 1`
    if [ -z "$TOMCAT_DIR" ]; then
        echo "Tomcat does not appear to be running."
        echo -e "If you know where the Tomcat home directory is, you can find the version by running:\n"
        echo -e "java -cp {tomcat home directory}/lib/catalina.jar org.apache.catalina.util.ServerInfo\n"
        exit 1
    fi
fi
echo -e "Tomcat is running.\n"
echo -e "Home directory: $TOMCAT_DIR\n"
java -cp $TOMCAT_DIR/lib/catalina.jar org.apache.catalina.util.ServerInfo

Remember to make the file executable with "chmod a+x filename".

Thursday, February 4, 2016

Apple Mac Keyboard

MacBook Pro Layout (U.S.)


You can see these layouts on your Mac using Show Keyboard Viewer in the keyboard menu.  See "Add Keyboard Layouts" below for how to set this up.

Default MacBook Pro U.S. Keyboard Layout

shift pressed

fn key pressed

option (alt) key pressed

shift + option (alt) pressed



104-Key Layout (U.S.)

Default Apple 104-Key U.S. Layout 

shift pressed

option (alt) pressed

shift + option (alt) pressed


Add Keyboard Layouts


To add other keyboard layouts in your default language:

1. Go to System Preferences > Keyboard.
2. On Input Sources tab, select + to add another keyboard layout.


3. To simplify switching keyboard layouts when editing, mark the "Show Input menu in menu bar" check box. This will show a language and keyboard icon in the Status Menu (right side of menu bar at the top). Click on it to switch keyboard layouts and see other options.


4. To show the layout of keys in case you forget, go to the Keyboard tab and mark the "Show Keyboard & Character Viewers in menu bar" checkbox. When you click on the keyboard layout icon in the Status Menu you will see the "Show Character Viewer" and "Show Keyboard Viewer" options.



Keyboard Layout for Another Language


1. Go to System Preferences > Language & Region.


2. Select + to add another language.
3. Once you select a language and choose which language will be the default, you will be asked to add an input source; the keyboard layout you will use for that language.


4. If you select the "Keyboard Preferences" button (see step 1 image above) you can add or remove different keyboard options for that language.
5. You can choose from different Input modes and modify Caps lock action and Typing method among other options.


6. To make it easier to switch between language keyboards, select the "Show input menu in menu bar" checkbox.
7. The added language keyboard will show up in the Status Menu with any options you checked in Keyboard Preferences.


Now you can switch to a different language and keyboard by simply selecting it from the status menu.

Monday, February 1, 2016

Jackson UnrecognizedPropertyException

For complicated APIs, I use the XJC binding compiler included with JAXB to generate Java classes using the XSD schema of the XML results of a web service.  This is a huge time saver.

For JSON results, there isn't a standard binding compiler to generate Java classes but since JSON and XML are almost interchangeable, I generate the Java classes the same way and fix the differences after the classes have been compiled.

One common error I get is an "unrecognized field" because of the slight differences between XML and JSON representations of data.

For example, I got this error:
com.sun.jersey.api.client.ClientHandlerException: org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "geonames" (Class org.learn.ws.model.jaxb.api.geonames.org.postal.countryinfo.types.GeonamesType), not marked as ignorable
when unmarshalling this JSON:
{
  "geonames": [
    {
      "numPostalCodes": 7,
      "maxPostalCode": "AD700",
      "countryCode": "AD",
      "minPostalCode": "AD100",
      "countryName": "Andorra"
    },
    {
      "numPostalCodes": 20260,
      "maxPostalCode": "9431",
      "countryCode": "AR",
      "minPostalCode": "1601",
      "countryName": "Argentina"
    }
    ...lots more rows...
  ]
}
to this GeonamesType class:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "geonamesType", propOrder = {
    "country"
})
public class GeonamesType {

    protected List<countrytype> country;

    public List<countrytype> getCountry() {
        if (country == null) {
            country = new ArrayList<countrytype>();
        }
        return this.country;
    }
}
and this CounryType class:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "countryType", propOrder = {
    "countryCode",
    "countryName",
    "numPostalCodes",
    "minPostalCode",
    "maxPostalCode"
})
public class CountryType {

    @XmlElement(required = true)
    protected String countryCode;
    @XmlElement(required = true)
    protected String countryName;
    @XmlElement(required = true)
    protected String numPostalCodes;
    @XmlElement(required = true)
    protected String minPostalCode;
    @XmlElement(required = true)
    protected String maxPostalCode;

    public String getCountryCode() {
        return countryCode;
    }

    public void setCountryCode(String value) {
        this.countryCode = value;
    }

    public String getCountryName() {
        return countryName;
    }

    public void setCountryName(String value) {
        this.countryName = value;
    }

    public String getNumPostalCodes() {
        return numPostalCodes;
    }

    public void setNumPostalCodes(String value) {
        this.numPostalCodes = value;
    }

    public String getMinPostalCode() {
        return minPostalCode;
    }

    public void setMinPostalCode(String value) {
        this.minPostalCode = value;
    }

    public String getMaxPostalCode() {
        return maxPostalCode;
    }

    public void setMaxPostalCode(String value) {
        this.maxPostalCode = value;
    }

}
The GeonamesType class is the root-level class generated and annotated automatically with the JAXB XJC shell script. For more on XJC, see http://www.thoughts-on-java.org/generate-your-jaxb-classes-in-second/.

The XJC shell script is used to generate Java classes from an XSD schema file. The XSD schema file can be generated automatically from sample XML with any number of online XML schema generators, for example this one: http://www.freeformatter.com/xsd-generator.html.

The error is telling me that the root-level node in the returned JSON, "geonames", doesn't have a correspondingly-named property in the root-level class, GeonamesType.  In the class, its name is "country".  The class was generated with xjc from the XML version of the result returned from the web service, which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<geonames>
    <country>
        <countryCode>AD</countryCode>
        <countryName>Andorra</countryName>
        <numPostalCodes>7</numPostalCodes>
        <minPostalCode>AD100</minPostalCode>
        <maxPostalCode>AD700</maxPostalCode>
    </country>
    <country>
        <countryCode>AR</countryCode>
        <countryName>Argentina</countryName>
        <numPostalCodes>20260</numPostalCodes>
        <minPostalCode>1601</minPostalCode>
        <maxPostalCode>9431</maxPostalCode>
    </country>
    ...lots more rows...
</geonames>
In the XML version, geonames is a list of country objects, which is how it is represented in the Java classes. In the JSON version, geonames is an array (list) of objects, but the objects aren't named. I could fix this by renaming "country" in the GeonamesType class to "geonames" like this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "geonamesType", propOrder = {
    "geonames"
})
public class GeonamesType {

    protected List<countrytype> geonames;

    public List<countrytype> getCountry() {
        if (geonames == null) {
            geonames = new ArrayList<countrytype>();
        }
        return this.geonames;
    }
}
This solves the problem for JSON results, but it doesn't work anymore for the XML results.

Use Same Classes With XML And JSON


By modifying the original GeonamesType class (at the top) with a Jackson annotation that is specific to JSON, it is possible to use the same Java classes for both XML and JSON versions of the results.

Just add the @JsonElement annotation to the country property to tell Jackson that the name of the element in the JSON result will be "geonames", not "country", like this:
import org.codehaus.jackson.annotate.JsonProperty;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "geonamesType", propOrder = {
    "country"
})
public class GeonamesType {

    @JsonProperty(value = "geonames")
    protected List<countrytype> country;

    public List<countrytype> getCountry() {
        if (country == null) {
            country = new ArrayList<countrytype>();
        }
        return this.country;
    }
}
Now the classes work for both the XML and JSON results as shown above.

Set Cmder (ConEmu) console emulator to open new tab in current directory with Bash shell

Windows is a truly bad operating system for almost everything except games. Unfortunately sometimes we have to use it for web development. I...