Regular Expression to Validate a Comma-Separated List of Email Addresses

Recently I needed to create a regular expression to validate the format of a comma-separated list of email addresses. Just thought I’d share the result in case it is of use to anyone:

\w+@\w+\.\w+(,\s*\w+@\w+\.\w+)*

Here’s an example of applying the pattern in Java:

// Compile pattern
Pattern emailAddressPattern = Pattern.compile(String.format("%1$s(,\\s*%1$s)*", "\\w+@\\w+\\.\\w+"));

// Validate addresses
System.out.println(emailAddressPattern.matcher("xyz").matches()); // false
System.out.println(emailAddressPattern.matcher("foo@bar.com").matches()); // true
System.out.println(emailAddressPattern.matcher("foo@bar.com, xyz").matches()); // false
System.out.println(emailAddressPattern.matcher("foo@bar.com, foo@bar.com").matches()); // true

Using MarkupKit with Charts

For a while now, I’ve been meaning to see if the popular open-source Charts library would work with MarkupKit. I finally got around to trying it this morning.

It actually turned out to be much easier than I expected. All of the Charts demos are built using XIB files. All I had to do was create a markup document that mimicked the contents of a XIB file, including outlets and actions, and add the code to load the view from markup instead of the XIB. I chose to try to replicate the pie chart example:

To load the view declaration, I added the following method to the demo’s PieChartViewController class. No other changes to the controller were necessary:

- (void)loadView
{
    [self setView:[LMViewBuilder viewWithName:@"PieChartViewController" owner:self root:nil]];
}

The contents of PieChartViewController.xml are shown below. Note the use of the Charts prefix in the PieChartView declaration. This is necessary because the PieChartView class is defined in the Charts module:

<?xml version="1.0" encoding="UTF-8"?>
    
<!-- Pie chart demo -->
<LMColumnView layoutMarginsRelativeArrangement="false" backgroundColor="#f0f0f0">
    <!-- Options button -->
    <LMRowView layoutMarginTop="6" layoutMarginLeft="18" layoutMarginRight="18">
        <LMSpacer/>
        
        <UIButton style="systemButton" title="Options"
            titleLabel.font="HelveticaNeue-Light 17.0" tintColor="#4c8fbd"
            onTouchUpInside="optionsButtonTapped:"/>
    </LMRowView>
    
    <!-- Pie chart view -->
    <Charts.PieChartView id="chartView" weight="1"/>
    
    <!-- Sliders -->
    <LMColumnView layoutMarginLeft="8" layoutMarginRight="8" layoutMarginBottom="24">
        <LMRowView>
            <UISlider id="sliderX" minimumValue="1" maximumValue="25" value="1" weight="4"
                onValueChanged="slidersValueChanged:"/>
            
            <UITextField id="sliderTextX" weight="1"
                font="HelveticaNeue-Light 15.0"
                textAlignment="center"/>
        </LMRowView>
        
        <LMRowView>
            <UISlider id="sliderY" minimumValue="1" maximumValue="200" value="1" weight="4"
                onValueChanged="slidersValueChanged:"/>
    
            <UITextField id="sliderTextY" weight="1"
                font="HelveticaNeue-Light 15.0"
                textAlignment="center"/>
        </LMRowView>
    </LMColumnView>
</LMColumnView>

The results are shown below. They are virtually indistinguishable from the original (though the chart data differs slightly, since it appears to be randomly generated each time the app is run):

So, I was very happy to discover that, not only did MarkupKit work with the Charts library, I was able to use it as a drop-in replacement for the original XIB file in the demo application!

The latest version of MarkupKit can be downloaded here. See the project README for more information.

Named Parameters in JDBC Queries

Prepared statements are a common way to execute parameterized queries in JDBC. For example, the following SQL might be used to retrieve a list of all users whose first or last name matches a particular character sequence:

SELECT * FROM user WHERE first_name LIKE ? or last_name LIKE ?

Parameter values are supplied at runtime via indexed setter methods defined by the PreparedStatement class:

statement.setString(1, pattern);
statement.setString(2, pattern);

This works fine for simple queries, but it becomes increasingly difficult to manage as the number of parameters grows. It is also redundant – although this query only requires a single argument, two parameter values must be supplied.

The Java Persistence API (JPA) provides a more convenient alternative using named parameters. For example, the above query might be written as follows in JPQL:

SELECT u FROM User u WHERE u.firstName LIKE :pattern or u.lastName LIKE :pattern

This is more readable and less verbose, as the caller only needs to provide the value of the “pattern” parameter once. It is also more resilient to changes, as the arguments are not dependent on ordinal position. Unfortunately, it requires a JPA-compliant object-relational mapping (ORM) framework such as Hibernate, a dependency that may not be satisfiable in all situations.

The org.httprpc.sql.Parameters class provided by the HTTP-RPC framework brings named parameter support to JDBC. The parse() method of this class is used to create a Parameters instance from a JPA-like SQL query; for example:

SELECT * FROM user WHERE first_name LIKE :pattern or last_name LIKE :pattern

It takes a string or reader containing the query text as an argument:

Parameters parameters = Parameters.parse(sqlReader);

The getSQL() method of the Parameters class returns the processed query in standard JDBC syntax. This value can be used in a call to Connection#prepareStatement():

PreparedStatement statement = connection.prepareStatement(parameters.getSQL());

Parameter values are specified via a Map passed to the Parameters#apply() method (mapOf() is a convenience method provided by HTTP-RPC for simplifying map creation):

parameters.apply(statement, mapOf(entry("pattern", pattern)));

Once applied, the query can be executed:

ResultSet resultSet = statement.executeQuery();

Note that Parameters is not limited to queries; it can also be used for updates.

A complete example using the Parameters class can be found here. It is a simple REST service that allows a caller to search a database of pets by owner name.

See the project README for more information.

HTTP-RPC 3.2 Released

HTTP-RPC 3.2 is now available for download. This release includes a number of notable enhancements:

  • Support for custom content deserialization in Java and Objective-C clients
  • More flexible Number implementation in Java client (allows callers to compare numeric values regardless of data type)
  • Support for accessing values by key path in Java client (e.g. “foo.bar”)
  • Optional result handlers in Java client (supports blocking/synchronous results)
  • Support for custom content serialization on server
  • Exception logging on server

For more information, see the project README.

A Practical Example Using MarkupKit and HTTP-RPC

In my spare time, I work on two open-source projects: MarkupKit and HTTP-RPC. MarkupKit allows developers to construct iOS applications declaratively using a human-readable markup language, and HTTP-RPC simplfies development of REST applications using a convenient, RPC-like metaphor.

I’ve written a few articles highlighting some of each project’s key features independently, so I thought I’d put together an example that demonstrates how they can be used together to implement a complete application. The example simulates a connected air conditioner that can be controlled remotely via an iOS client app. The server-side Java version of HTTP-RPC is used to implement the simulated air conditioner, and MarkupKit is used to create the user interface for the iOS client:

Air Conditioner Remote

The iOS app uses the Objective-C HTTP-RPC client library to communicate with the server.

Service Implementation

The simulated air conditioner is implemented as an HTTP-RPC web service, which provides methods for remotely managing the unit. The service class is defined as follows (it simply logs messages to the console to simulate the unit’s behavior):

public class AirConditionerService extends WebService {
    private static Status status = new Status();

    @RPC(method="GET", path="status")
    public Map getStatus() {
        return new BeanAdapter(status);
    }

    @RPC(method="PUT", path="status")
    public void setOnStatus(boolean on) {
        System.out.println("Setting unit power to " + (on ? "on" : "off"));

        status.setOn(on);
    }

    @RPC(method="PUT", path="status")
    public void setTemperatureStatus(int temperature) {
        if (temperature < 32 || temperature > 96) {
            throw new IllegalArgumentException("Invalid temperature.");
        }

        System.out.println("Setting unit temperature to " + temperature);

        status.setTemperature(temperature);
    }

    @RPC(method="PUT", path="status")
    public void setFanSpeedStatus(int fanSpeed) {
        if (fanSpeed < 1 || fanSpeed > 3) {
            throw new IllegalArgumentException("Invalid fan speed.");
        }

        System.out.println("Setting unit fan speed to " + fanSpeed);

        status.setFanSpeed(fanSpeed);
    }
}

Status is a simple POJO (“plain old Java object”) type defined as follows:

public class Status {
    private boolean on = false;
    private int temperature = 70;
    private int fanSpeed = 1;

    public boolean isOn() {
        return on;
    }

    public void setOn(boolean on) {
        this.on = on;
    }

    public int getTemperature() {
        return temperature;
    }

    public void setTemperature(int temperature) {
        this.temperature = temperature;
    }

    public int getFanSpeed() {
        return fanSpeed;
    }

    public void setFanSpeed(int fanSpeed) {
        this.fanSpeed = fanSpeed;
    }
}

Client Implementation

The client application (written in Swift) allows the user to turn the simulated air conditioner on and off and set the unit’s temperature and fan speed. It is implemented using a static table view whose contents are defined in markup.

The table view contains three sections: power, temperature, and fan speed. The power section contains a single on/off switch. The temperature section contains a label that displays the current temperature along with a stepper control that is used to increase or decrease the temperature. The fan speed section contains a list of three speeds, only one of which may be selected at a time:

<?properties {
    "cell.header": {
        "textLabel.font": "subheadline",
        "textLabel.textColor": "#808080"
    }
}?>

<LMTableView style="groupedTableView">
    <!-- Power -->
    <UITableViewCell textLabel.text="@power" selectionStyle="none">
        <UISwitch id="onSwitch" onValueChanged="togglePower:"/>
    </UITableViewCell>

    <!-- Temperature -->
    <?sectionBreak?>
    <?sectionHeaderView?>
    <UITableViewCell class="cell.header" textLabel.text="@temperature"/>

    <UITableViewCell id="temperatureCell" selectionStyle="none">
        <UIStepper id="temperatureStepper" minimumValue="32" maximumValue="96" onValueChanged="updateTemperature:"/>
    </UITableViewCell>

    <!-- Fan Speed -->
    <?sectionBreak?>
    <?sectionName fanSpeed?>
    <?sectionSelectionMode singleCheckmark?>
    
    <?sectionHeaderView?>
    <UITableViewCell class="cell.header" textLabel.text="@fanSpeed"/>

    <UITableViewCell textLabel.text="@low"/>
    <UITableViewCell textLabel.text="@medium"/>
    <UITableViewCell textLabel.text="@high"/>
</LMTableView>

The markup uses inline template properties to style the section headers. Localizable content is defined in Localizable.strings:

"title" = "Air Conditioner Remote";

"power" = "Power";

"temperature" = "Temperature";

"fanSpeed" = "Fan Speed";
"high" = "High";
"medium" = "Medium";
"low" = "Low";

"serviceErrorTitle" = "Error";
"serviceErrorMessage" = "An error occurred while communicating with the unit.";

The main view controller coordinates the interaction between the user interface and the air conditioner service. At startup, the controller creates an instance of WSWebServiceProxy that it uses to communicate with the service:

override func viewDidLoad() {
    super.viewDidLoad()

    title = NSBundle.mainBundle().localizedStringForKey("title", value: nil, table: nil)

    serviceProxy = WSWebServiceProxy(session: NSURLSession.sharedSession(), serverURL: NSURL(string: "http://localhost:8080")!)
}

When the view appears, the controller calls the service’s getStatus() method to retreive the air conditioner’s current state, and updates the UI to reflect this state:

override func viewWillAppear(animated: Bool) {
    serviceProxy.invoke("GET", path: "/ac-service/ac/status") {(result, error) in
        if (error == nil) {
            let status = result as! NSDictionary

            // Update power
            self.onSwitch.on = status["on"] as! Bool

            // Update temperature
            self.temperatureStepper.value = status["temperature"] as! Double

            self.updateTemperatureLabel()

            // Update fan speed
            let fanSpeed = status["fanSpeed"] as! Int
            let fanSpeedSection = self.tableView.sectionWithName(ViewController.FanSpeedSectionName)

            self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: fanSpeed - 1, inSection: fanSpeedSection))!.checked = true
        } else {
            self.handleServiceError(error!);
        }
    }
}

The handleServiceError: method is called if the remote method call fails. This method simply displays an alert to the user:

func handleServiceError(error: NSError) {
    let mainBundle = NSBundle.mainBundle()

    let alertController = UIAlertController(title: mainBundle.localizedStringForKey("serviceErrorTitle", value: nil, table: nil),
        message: mainBundle.localizedStringForKey("serviceErrorMessage", value: nil, table: nil),
        preferredStyle: .Alert)

    alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))

    self.presentViewController(alertController, animated: true, completion: nil)
}

The controller responds to user input on the various UI elements by invoking service methods to update the air conditioner’s state. For example, the togglePower: method is called in response to a value change event on the power switch:

@IBAction func togglePower(sender: UISwitch) {
    serviceProxy.invoke("PUT", path: "/ac-service/ac/status", arguments: ["on": sender.on]) {(result, error) in
        if (error != nil) {
            self.handleServiceError(error!);
        }
    }
}

The updateTemperature: method is called in response to a value change event on the temperature stepper:

@IBAction func updateTemperature(sender: UIStepper) {
    let temperature = Int(sender.value)

    serviceProxy.invoke("PUT", path: "/ac-service/ac/status", arguments: ["temperature": temperature]) {(result, error) in
        if (error != nil) {
            self.handleServiceError(error!);
        }
    }

    updateTemperatureLabel()
}

func updateTemperatureLabel() {
    temperatureCell.textLabel!.text = "\(Int(temperatureStepper.value))° F"
}

Finally, the tableView:didSelectRowAtIndexPath: method is called in response to a table view selection. If a selection occurs in the fan speed section, the controller invokes the service method to update the unit’s fan speed:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if let sectionName = tableView.nameForSection(indexPath.section) {
        if (sectionName == ViewController.FanSpeedSectionName) {
            let fanSpeed = indexPath.row + 1

            serviceProxy.invoke("PUT", path: "/ac-service/ac/status", arguments: ["fanSpeed": fanSpeed]) {(result, error) in
                if (error != nil) {
                    self.handleServiceError(error!);
                }
            }
        }
    }
}

Summary

This example provided a practical example of how MarkupKit and HTTP-RPC can be used together to implement a complete application. For more information, please see the project documentation.

A Quick Introduction to HTTP-RPC

HTTP-RPC is an open-source framework for simplifying development of REST-based applications. It allows developers to create and access HTTP-based web services using a convenient, RPC-like metaphor while preserving fundamental REST principles such as statelessness and uniform resource access.

The project currently includes support for implementing REST services in Java and consuming services in Java, Objective-C/Swift, or JavaScript. The server component provides a lightweight alternative to other, larger Java-based REST frameworks, and the consistent cross-platform client API makes it easy to interact with services regardless of target device or operating system.

This article provides an introduction to the HTTP-RPC framework along with sample code demonstrating the implementation of a simple HTTP-RPC service in Java. Client examples in Swift, Java, and JavaScript are also provided.

Overview

HTTP-RPC services are accessed by applying an HTTP verb such as GET or POST to a target resource. The target is specified by a path representing the name of the resource, and is generally expressed as a noun such as /calendar or /contacts.

Arguments are provided either via the query string or in the request body, like an HTML form. Results are generally returned as JSON, although operations that do not return a value are also supported.

For example, the following request might retrieve the sum of two numbers, whose values are specified by the a and b query arguments:

GET /math/sum?a=2&amp;b=4

The service would return the value 6 in response.

Example Service

WebService is an abstract base class for HTTP-RPC web services. Service operations are defined by adding public methods to a concrete service implementation.

The @RPC annotation is used to flag a method as remotely accessible. This annotation associates an HTTP verb and a resource path with the method. All public annotated methods automatically become available for remote execution when the service is published.

For example, the following class might be used to implement the simple addition operation discussed in the previous section:

public class MathService extends WebService {
    @RPC(method="GET", path="sum")
    public double getSum(double a, double b) {
        return a + b;
    }
}

Java Client

Services operations are invoked in Java using an instance of the WebServiceProxy class:

// Create service proxy
URL serverURL = new URL("https://localhost:8443");
ExecutorService executorService = Executors.newFixedThreadPool(10);

WebServiceProxy serviceProxy = new WebServiceProxy(serverURL, executorService);

// Get sum of "a" and "b"
serviceProxy.invoke("GET", "/math/sum", mapOf(entry("a", 2), entry("b", 4)), new ResultHandler() {
    @Override public void execute(Number result, Exception exception) {
        // result is 6 
    } 
});

The result handler is a callback that will be executed upon completion of the request. In Java 7, anonymous inner classes are typically used to implement result handers. In Java 8 or later, lambda expressions can be used instead, reducing the invocation code to the following:

// Get sum of "a" and "b"
serviceProxy.invoke("GET", "/math/sum", mapOf(entry("a", 2), entry("b", 4)), (result, exception) -&gt; {
    // result is 6 
});

Swift Client

The WSWebServiceProxy class is used to invoke service operations in Swift. Result handlers are implemented using closures:

// Configure session 
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() 

configuration.requestCachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData

let delegateQueue = NSOperationQueue() delegateQueue.maxConcurrentOperationCount = 10

let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: delegateQueue)

// Initialize service proxy and invoke methods 
let serverURL = NSURL(string: "https://localhost:8443")
let serviceProxy = WSWebServiceProxy(session: session, serverURL: serverURL!)

// Get sum of "a" and "b" 
serviceProxy.invoke("GET", path: "/math/sum", arguments: ["a": 2, "b": 4]) {(result, error) in
    // result is 6
}

JavaScript Client

In JavaScript, services are accessed using the WebServiceProxy class. As in Swift, result handlers are implemented using closures:

// Create service proxy 
var serviceProxy = new WebServiceProxy();

// Get sum of "a" and "b"
serviceProxy.invoke("GET", "/math/sum", {a:4, b:2}, function(result, error) {
    // result is 6 
});

Summary

This article introduced the HTTP-RPC framework and provided a brief example of how it can be used to create and consume cross-platform RESTful web services. For more information, please see the project README.

HTTP-RPC 3.1 Released

HTTP-RPC 3.1 is now available for download. This release restores support for transforming method results using Mustache-like template documents. It also adds support for returning binary content from service methods. There were no client-side changes in this release.

For more information, please see the project README.