Saturday, April 9, 2016

SSH key forwarding is not working on Mac OS

If you need to use ssh key forwarding (in git, for example) from Mac - it might not work. This is because Mac is not loading SSH keys automatically.
It can be easily done manually by calling command:

ssh-add

There is good tutorial about configuration and troubleshooting at https://developer.github.com/guides/using-ssh-agent-forwarding/




Saturday, March 5, 2016

XML parsing in Java

JSON is much popular now, but occasionally it is still possible to come across XML API. I had such experience recently and I have to say that in 2016 it is much easier than some 10 years ago. I mostly use Jackson for JSON, so for me best way to use it is XmlMapper plugin. After that it is plain Jackson.
There is example:


XmlMapper mapper = new XmlMapper();
List rates = mapper.readValue(ratesString, List.class);




compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.6.3'
compile 'org.codehaus.woodstox:woodstox-core-asl:4.4.1'





Friday, February 12, 2016

Using property files with map values in Spring configuration beans

Spring and Spring Boot can map property files as configuration beans automatically. What is less known is that it can easily wire Map objects too:


@Configuration
@Component
@PropertySource("classpath:config.properties")
public class Config {
    @Value("#{${my.map}}")
    private Map map;
...





my.map={\
'key1' : 'val1', \
'key2' : 'val2', \
...




Saturday, January 9, 2016

Selenium style automation script with plain JavaScript in Chrome

It is hard to beat Selenium for heavy browser scripting - it has a lot of features, support and infrastructure. But if you only need it occasionally, everything already exists in Chrome.

For example:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo($x) {
    $x('//a[@title="Click here first"]')[0].click();
    await sleep(2000);
    $x('//button[text()=\"Click here then\"]')[0].click();
}

demo($x);


It even have advantages over Selenium: you can omit initialisation, like logins and captchas and script only functional parts. Perfect for boring repetitive tasks and adhoc testing.

Saturday, December 5, 2015

Returning first successful result from CompletableFuture

Recently I wanted to get first non empty result from bunch of CompletableFutures. For my case, allOf - is bad because it runs all futures till end and returns nothing. AnyOf - is bad because it returns first result, even if it is empty. So there is no such function in Java API, but it is still very easy to implement, and maybe it is even more logical, because actually there are 2 cases: found or not found; and it can be easily solved with two CompletableFutures. There is example:

import java.util.concurrent.CompletableFuture

success = new CompletableFuture()

def futures = (1..10).collect { CompletableFuture.supplyAsync {
                                    if (val == 6) {
                                        success.complete(val)
                                    } else {
                                        Thread.sleep(1000)
                                    }
                                }
                          }

println CompletableFuture.allOf(futures as CompletableFuture[])
        .thenApply({ throw new RuntimeException("not found") })
        .applyToEither(success, {it}).get()


This way it will return result if there is any, or throw exception if all done and there is no result, and it can be easily adjusted to return default value, for example.

Saturday, November 28, 2015

Groovy framework for AWS lambda

I was playing with AWS lambda recently and I find it pretty exciting. It is cheap, does not require any maintenance and it is simple. The biggest problem I found so far, is lack of tooling. AWS has web UI which does what it supposed to do, but is far from pleasant. AWS command line tools and API are much better, but are AWS centric. So, I have created tool to work with AWS lambda. It uses some convention now, but can be adjusted to whatever feels right for specific situation, idea is that it is just one script with few lines of code. Basically, it does 2 things: uploads application and local testing. I have created small example that illustrates how and what it does.

Example is trivial application that increments number by clicking on button. It is SPA, with static client in S3 and two API functions add and get.

All lambda code is just single Groovy script. It consists of router function, dependencies and logic. Router function is what will be mapped to lambda. It is function that accepts map and returns map. Input map can be plain request JSON, or some additional parameters can be injected at API gateway. Even for this trivial case it was a good idea and I injected configuration parameters - AWS access and secret keys and region for DynamoDB access, so they are hidden at admin level and are environment specific. Simplest way to do routing is just by using some designated parameter, in this example, it is called "function". Doing it with real URI will need AWS configuration, and it is not very convenient and flexible.

In this simple example, router script does logic, but for more complex cases it is better to be just router and logic would be in dependencies.

During packaging Groovy script is compiled and packaged together with all dependencies into uberjar which is required by AWS. After that, it is uploaded via AWS API.

Development can be done and tested locally by using mock server. Mock server mimics AWS, parses input into JSON like lambda, injects parameters like API gateway, includes Access-Control-Allow-Origin and separates configuration via config.js, supports debug and reloading.

Saturday, October 17, 2015

Trim is not removing all whitespaces in Java

Java trim is removing only ASCII whitespace characters, but ignores unicode whitespaces. This is backward compatibility thing, and there is big and detailed explanation of this problem. It can be easily fixed by using regular expression that will remove all official unicode whitespaces:
Pattern TRIM_PATTERN = Pattern.compile("^\\s*(.*?)\\s*$", Pattern.UNICODE_CHARACTER_CLASS);
Matcher matcher = TRIM_PATTERN.matcher(input);
if (matcher.matches() && matcher.groupCount() > 0) {
    return matcher.group(1);
}
return input;

But for more extreme cases you may want to use also this pattern
"^[\\s\\u2060\\u200D\\u200C\\u200B\\u180E\\uFEFF\\u00AD]*(.*?)[\\s\\u2060\\u200D\\u200C\\u200B\\u180E\\uFEFF\\u00AD]*$"

besides whitespaces it will also remove other invisible symbols.