Automation for Java Developers - tips and snippets

Automation is something that can save your future self a lot of time. It is not an urgent thing, but it is very important. It will give you the time to work on business logic, execute certain boring stuff, protect you from yourself and others when the code is changed, get notified early when something is broken, bring better experience to the User (with less bugs) and at last will give you freedom not to worry about low level technical shit and enjoy life more.

Leveraging flavors. These are predefined constants, parameters, even code (although it better be minimal) for the different environments your application will run. On Java Desktop and Server the Standard way of doing this is mostly with .properties files. Everything that is different - database connections, paths on the file systems, JVM parameters, commands etc could be placed outside of the code. This later minimizes the need for extra changes when moving the app to a new place (although this is less of a problem with containers).

On Android - flavors are first class citizens. The run-time system chooses resources, images, menus, layout files, values, colors from the settings of the current operating system environment. At compile time flavor can also be defined. Making the same file structure from the main source folder - with some specific files overwritten, it could replace URL endpoints, data access credentials, signing certificates, resources, and code. And when you compile, you choose with which flavor to be bundled to the installation package.

Lets get to some specific technical snippets that I'm using:

I have used SSHJ https://github.com/hierynomus/sshj to download or upload files to remote servers:

try (SSHClient ssh = new SSHClient()) {
 ssh.loadKnownHosts();        
 ssh.addHostKeyVerifier("some-key");
 ssh.connect(host);
 ssh.authPassword(user, pass);
 ssh.newSCPFileTransfer().upload(localFilePath, remoteFilePath);
 ssh.disconnect();
}

I have used sshxcute https://code.google.com/archive/p/sshxcute/ to do bunch of tasks on the server - copy specific files to their needed location, zip directories, trigger a database backup, delete old files, etc.

CustomTask task = new ExecCommand("some command");
ConnBean cb = new ConnBean(host, user, pass);
SSHExec ssh1 = SSHExec.getInstance(cb);
ssh1.connect();
ssh1.exec(task);
ssh1.disconnect();

I have used the Java Process API to execute some script or command in a sub process and from the returned result, depending on the need, I have executed different code afterwards.

processBuilder = new ProcessBuilder(command and arguments);
processBuilder.directory(working directory);
processBuilder.inheritIO();
process = processBuilder.start();
int waitFor = process.waitFor();
if (waitFor == 0) {
//something
} else {
//something else 
}

While doing builds or in several other places, I am replacing configuration files with different flavors for the different environments with this snippet:

Files.copy(sourceFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

Builds themselves are done with Gradle, Maven and/or Ant. The location of these tools and sometimes their parameters are flavored in properties files, so, migrating the build to a new machine is just a matter of replacing some lines in a .properties file.

From these 3 tools I mostly like Ant, because it gives you full control over the build process without hiding too much of it. The others are very good at managing dependencies but their building process is with plugins and sometimes some of the steps remain hidden which may be good, but sometimes it may be bad (especially if something is not working) or you want to customize something.

I've used in several places the Eclipse JGit API to access local and remote repositories. https://www.eclipse.org/jgit/

    SshSessionFactory.setInstance(new JschConfigSessionFactory()
    {
        @Override
        protected void configure(Host arg0, Session session)
        {
            session.setPassword("the password of a user");
        }
    });
    File file = new File("local directory");
    delete(file);
    Git.cloneRepository().setURI("user@someaddr:/directory-on-the-remote-machine")
    .setDirectory(file).call();

I have used the Java Zip API to package some files into zip.

    Path sourceDir = Paths.get(dirPath);
    String zipFileName = "some file name;
    try {
        ZipOutputStream outputStream = new 
ZipOutputStream(new FileOutputStream(zipFileName));
        Files.walkFileTree(sourceDir, new SimpleFileVisitor() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {
                try {
                    Path targetFile = sourceDir.relativize(file);
                    outputStream.putNextEntry(new ZipEntry(targetFile.toString()));
                    byte[] bytes = Files.readAllBytes(file);
                    outputStream.write(bytes, 0, bytes.length);
                    outputStream.closeEntry();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return FileVisitResult.CONTINUE;
            }
        });
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

Some of the above stuff may be done with little configuration using the Jenkins application or some command from the tools( for example I've used Ant in some cases for some of the stuff), but I find it useful to mix jenkins features with standard commands and java executable applications - coded by me, doing what i needed to do when I couldn't find the feature or the plugin in this tool for that. In the task configuration of this CI/CD app I have especially used:

Probably a lot more could be automated with some configuration, some small code snippets or with some additional tools. But that is for me for now. If you know and use some cool stuff for automation, please let me know.

Share
Add comment