Play deployment to CloudBees

I followed the instructions to deploy the Play application to CloudBees.

CloudBees SDK

I installed this SDK to interact with the cloud infrastructure. So this created a profile based
on my CloudBees account.

Mohans-MacBook-Pro:cloudbees-sdk-1.5.2 radhakrishnan$ bees help
# CloudBees SDK version: 1.5.2
# CloudBees Driver version: 1.3.8
Installing plugin: org.cloudbees.sdk.plugins:ant-plugin:1.3.0

You have not created a CloudBees configuration profile, let’s create one now…
Enter your default CloudBees API end point [us | eu]: us
Enter your CloudBees account email address: radhakrishnan.mohan@gmail.com
Enter your CloudBees account password:
Plugin installed: org.cloudbees.sdk.plugins:ant-plugin:1.3.0
Installing plugin: org.cloudbees.sdk.plugins:app-plugin:1.5.6
Plugin installed: org.cloudbees.sdk.plugins:app-plugin:1.5.6
Installing plugin: org.cloudbees.sdk.plugins:config-plugin:1.3.2
Plugin installed: org.cloudbees.sdk.plugins:config-plugin:1.3.2
Installing plugin: org.cloudbees.sdk.plugins:db-plugin:1.3.3
Plugin installed: org.cloudbees.sdk.plugins:db-plugin:1.3.3
Installing plugin: com.cloudbees.sdk.plugins:service-plugin:1.2.3
Plugin installed: com.cloudbees.sdk.plugins:service-plugin:1.2.3
Type ‘bees help ‘ for help on a specific subcommand.

SDK subcommands:
help List all commands
init Re-initialize the SDK config file
plugin:delete Delete a SDK plugin
plugin:info Get SDK plugin information

Application deployed to CloudBees

app

Provisioned MySQL on CloudBees

db

The parameters I was supposed to set

Mohans-MacBook-Pro:cloudbees-sdk-1.5.2 radhakrishnan$ bees config:set -a mohanr/playconf AppDynamics=false
Application config parameters for mohanr/playconf: saved

Application Parameters:
applyEvolutions.default=true
DB_USER=mohanr
DB_PASS=test
DB_URL=jdbc:mysql://ec2-50-19-213-178.compute-1.amazonaws.com:3306/playconftest
applyDownEvolutions.default=true
AppDynamics=false
Runtime Parameters:
java_version=1.7

The settings to enable evolutions did not work and I could not access the application.

So I switched off the evolution facility and removed 1.sql and then deployed the application. I think this evolution facility can be switched off in application.conf also.

Application Parameters:
DB_USER=mohanr
DB_PASS=test
applyDownEvolutions.default=false
applyEvolutions.default=false
DB_URL=jdbc:mysql://ec2-23-21-211-172.compute-1.amazonaws.com:3306/helloplaytest
AppDynamics=false
Runtime Parameters:
java_version=1.7

Deployment

Mohans-MacBook-Pro:hello-play radhakrishnan$ ./activator dist
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
[info] Loading project definition from /Users/radhakrishnan/Documents/hello-play/project
[warn] Multiple resolvers having different access mechanism configured with same name ‘typesafe-ivy-releases’. To avoid conflict, Remove duplicate project resolvers (`resolvers`) or rename publishing resolver (`publishTo`).
[info] Set current project to hello-play (in build file:/Users/radhakrishnan/Documents/hello-play/)
[info] Packaging /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT-sources.jar …
[info] Done packaging.
[info] Main Scala API documentation to /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/api…
[info] Wrote /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT.pom
[info] Packaging /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT.jar …
[info] Done packaging.
model contains 30 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /Users/radhakrishnan/Documents/hello-play/target/scala-2.10/hello-play_2.10-1.0-SNAPSHOT-javadoc.jar …
[info] Done packaging.
[info]
[info] Your package is ready in /Users/radhakrishnan/Documents/hello-play/target/universal/hello-play-1.0-SNAPSHOT.zip
[info]
[success] Total time: 16 s, completed Feb 23, 2014 9:23:11 PM
Mohans-MacBook-Pro:hello-play radhakrishnan$ bees app:deploy -a playconf -t play2 target/universal/hello-play-1.0-SNAPSHOT.zip
-bash: bees: command not found
Mohans-MacBook-Pro:hello-play radhakrishnan$ source ~/.profile
Mohans-MacBook-Pro:hello-play radhakrishnan$ bees app:deploy -a playconf -t play2 target/universal/hello-play-1.0-SNAPSHOT.zip
Deploying application mohanr/playconf (environment: ): target/universal/hello-play-1.0-SNAPSHOT.zip
Application parameters: {containerType=play2}
……………………uploaded 25%
……………………uploaded 50%
……………………uploaded 75%
……………………upload completed
deploying application to server(s)…
Application mohanr/playconf deployed: http://playconf.mohanr.cloudbees.net

Create tables using MySQL Workbench

MySQL Workbench

The application was accessible now as the following screenshots show.

New Proposal

Submitted Proposal

NIO.2

This post is not exactly about NIO.2 even though I use SeekableByteChannel. It is about a pestering question asked by two interviewers in the past. I believe a coding task is a good and reliable first step in any interview process. But some people ask questions in a patronising way.

This is one such question. How do you identify duplicate rows in a file ?

So I decided to do what any programmer worth her salt will do. This is not the most efficient way but I wanted to try NIO.2’s SeekableByteChannel because none of the firms I have worked for in the past has any need for any new Java API. They still wallow in legacy Java applications. I don’t get a chance to use it for any project.

Sample file to parse

I wanted to filter duplicates in column 3 – the name of the page requested – from a sample log.


timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,Latency
1346999466187,32,Home page - anon,200,OK,Anonymous Browsing 1-2,text,true,31
1346999466182,37,Login form,200,OK,Node save 3-1,text,true,36
1346999466184,35,Home page - anon,200,OK,Anonymous Browsing 1-11,text,true,32
1346999466182,37,Home page - anon,200,OK,Anonymous Browsing 1-1,text,true,34
1346999466189,30,Home page - anon,200,OK,Anonymous Browsing 1-4,text,true,27
1346999466185,46,Home page - anon,200,OK,Anonymous Browsing 1-5,text,true,34
1346999466185,44,Search,200,OK,Search 4-1,text,true,35
1346999466188,28,Home page - anon,200,OK,Anonymous Browsing 1-3,text,true,26
1346999466182,33,Home page - anon,200,OK,Anonymous Browsing 1-7,text,true,32
1346999466182,36,Login Form,200,OK,Perform Login/View Account 5-1,text,true,35
1346999466182,35,Home page - anon,200,OK,Anonymous Browsing 1-10,text,true,33

Sample Java code that is not efficient


package com.test;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import java.util.Set;
import java.util.TreeSet;

public class DuplicateTest {

    Set<String> values = new TreeSet<>();

    public static void main( String... argv ){

        DuplicateTest dt = new DuplicateTest();

        dt.analyze();
    }

    private  void analyze() {
        
        Path p = Paths.get(File.separator + "Users"
                                    + File.separator + "radhakrishnan" +
                                            File.separator + "Lambdas", "duplicate.txt");
        ByteBuffer b = ByteBuffer.allocate(1);
        
        String encoding = System.getProperty( "file.encoding");
        
        b.clear();
        
        char c;
        
        StringBuilder sb = new StringBuilder();
        
        try(
            SeekableByteChannel skbc = Files.newByteChannel(p,
                                                            EnumSet.of(StandardOpenOption.READ))) {
            //Move the position after the first line(heading)
            skbc.position(89);

            while( skbc.read( b ) > 0){
                
                   b.flip();
                
                   c = Charset.forName(encoding).decode(b).get();
                
                   //System.out.println(c);
                   sb.append(c);
                
                   if( c == '\n' || c == '\r'){
                       //Move the position to read the line after the new line
                       skbc.position(skbc.position());
                       extractAndStore(sb.toString());
                       sb = new StringBuilder();
                   }
                   b.clear();
            }

        } catch (IOException e) {
            
            e.printStackTrace();
            
        }
        
        System.out.println(values);
    }

    private  void extractAndStore(String s) {

        values.add(s.split("[,]")[2]);
    }

}

Result

[Home page - anon, Home page - auth, Login, Login Form, Login form, Logout, Node edit form, Random node - anon, Search, User profile page, node edit post]

How to get the value of an Annotation type Element ?


package com.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;



public class ValueAnnotation {


    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    protected @interface  TypeUse {
        int value();
    }

    @TypeUse(value = 0) class Test<T>{

    }
}

Processor


    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private void processClassTypeParameters(Element e) {

            for( AnnotationMirror am  : e.getAnnotationMirrors() ){

                for(Map.Entry< ? extends ExecutableElement, ? extends AnnotationValue> m : am.getElementValues().entrySet()){

                    System.out.println( "[" + m.getKey() +"][" + m.getValue() + "]");

                }

            }
    }


Annotation [@com.test.ValueAnnotation.TypeUse(0)] [com.test.ValueAnnotation.Test]
[value()][0]

IntersectionType

I came across this code that uses a cast to assign a Lambda expression to a marker interface in Angelika Langer’s explanation.

Serializable f2
= (BiPredicate<String,String> & Serializable)
(s,t) -> s.equalsIgnoreCase(t);

As I was curious about this I tried to detect an intersection type (T extends String & @IntersectionType.TypeUse(value = 2) Serializable) and print the annotation applied on one of its bounds.

The result is

Annotation [] [com.test.IntersectionType.Test]
Annotation [[]] [java.lang.String]
Annotation [[]] [java.io.Serializable]

This could be a JDK 8 bug at this time. I am getting nothing.

I am using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b123)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b65, mixed mode)

I presumed there is a javax.lang.model.type.IntersectionType that will match T extends String & Serializable. So I though there is a TypeMirror that I can check for that type. But it does not seem so.

I will update later when I get a proper result.

Update : The method is updated and it works partly. I am getting the intersection type. But I think one cannot get the annotation type of the intersection type directly because the annotation is applied on each of the bounds separately. So the old code(see the comments below) is sufficient but now the returned array is empty which could mean that this is a bug in itself.


Annotation [] [com.test.IntersectionType.Test]
Annotation [[]] [java.lang.String&java.io.Serializable]
Annotation [[]] [java.lang.String]
Annotation [[]] [java.io.Serializable]


public class IntersectionType {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    public @interface TypeUses {
        TypeUse[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @Repeatable(TypeUses.class)
    protected @interface  TypeUse {
        int value();
    }

    //Intersection type
    class Test<T extends String & @IntersectionType.TypeUse(value = 2) Serializable>{

    }
}

Processor method


    private void processClassTypeParameters(Element e) {


        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            for( AnnotationMirror am  : typeParameterElement.getAnnotationMirrors() ){

                System.out.println( "Annotation [" + am + "] [" + typeParameterElement  + "]");


            }
            //Get the intersection type
            TypeVariable tv = (TypeVariable)typeParameterElement.asType();

            TypeMirror tm = tv.getUpperBound();
            //This may not return anything.(See explanation above)
            System.out.println( "Annotation [" + Arrays.asList( tm.getAnnotationsByType(com.test.IntersectionType.TypeUse.class)) + "] [" + tm  + "]");

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {
                //Commented section is not the right way
                //if( typeMirror instanceof javax.lang.model.type.IntersectionType) {

                //The following line returns an empty array most probably due to a different bug.
                    System.out.println( "Annotation [" + Arrays.asList(typeMirror.getAnnotationsByType(com.test.IntersectionType.TypeUse.class)) + "] [" + typeMirror  + "]");

                //}
            }
        }
    }

Repeatable Annotations

It looks like the annotations can repeat according to Repeating Annotations.

I am still using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

This code has a problem.

  1. Arrays.asList(typeMirror.getAnnotationsByType(RepeatableAnnotation.TypeUse.class))

    This does not print anything. There are two annotations.

This could be a problem with the particular JDK 8 build. The latest is b120. I have to try the latest build.

Update: This is most likely a code problem because even b120 does not help.

Update 1: This is not a code problem but b120 has some bugs according to the type-annotations-dev list.

The result is this.


Annotation [@com.test.RepeatableAnnotation.TypeUses({@com.test.RepeatableAnnotation.TypeUse(0), @com.test.RepeatableAnnotation.TypeUse(1)})] [com.test.RepeatableAnnotation.Test1]
[value()][{@com.test.RepeatableAnnotation.TypeUse(0), @com.test.RepeatableAnnotation.TypeUse(1)}]
Annotation [[]] [java.lang.Integer]

I am not able to get the annotations applied on the bound Integer

package com.test;

import java.lang.annotation.*;

public class RepeatableAnnotation {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    public @interface TypeUses {
        TypeUse[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @Repeatable(value = TypeUses.class)
    protected @interface  TypeUse {
        int value();
    }

    @TypeUse(value = 0) @TypeUse(value = 1)class Test1< T extends @TypeUse(value = 2) @TypeUse(value = 3) Integer> {

        /**
         * A type annotation is permitted in front of a constructor declaration, where declaration annotations are already
         permitted.
         */
        @TypeUse(value = 0) <S> Test1(String s){

        }
    }

}

Annotation Processor


package com.test;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.SimpleTypeVisitor8;
import java.util.*;

import static javax.lang.model.util.ElementFilter.typesIn;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class RepeatableAnnotationFinder extends AbstractProcessor{


    public RepeatableAnnotationFinder(){
        super();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        TypeElement tye = null;

        if( !roundEnv.processingOver()){

            Iterator<? extends Element> te = annotations.iterator();

            for (TypeElement element : typesIn(roundEnv.getRootElements()) ) {

                processEnclosedElements(element.getEnclosedElements(),
                                        roundEnv);

            }
        }
        return false;
    }

    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private void processClassTypeParameters(Element e) {

        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            for( AnnotationMirror am  : typeParameterElement.getAnnotationMirrors() ){

                System.out.println( "Annotation [" + am + "] [" + typeParameterElement  + "]");

                for(Map.Entry< ? extends ExecutableElement, ? extends AnnotationValue> m : am.getElementValues().entrySet()){

                    System.out.println( "[" + m.getKey() +"][" + m.getValue() + "]");

                }

            }

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {

                System.out.println( "Annotation [" + Arrays.asList(typeMirror.getAnnotationsByType(RepeatableAnnotation.TypeUse.class)) + "] [" + typeMirror  + "]");

            }
        }
    }
}

So I will wait for a newer build before trying this again.

Annotation Processors

Lambdas are very popular now. But I realized I haven’t used the annotation processor API since JSE 5. None of the projects I came across has even used good generics. So even JSE 5 is not properly used.

I just compiled and executed this. It is not complete because I am trying to print all the annotations actually used in the code shown(Test.java) in my previous blog entry.

I am using

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

Now it is printing this.

Annotation [com.test.Test.TypeUse] [[com.test.Test.Test1]]
Annotation [com.test.Test.TypeParameter] [[T, S]]
Annotation [com.test.Test.TestTypeParameter] [[T, S]]
Annotation [@com.test.Test.TypeUse] [com.test.Test.Test1]
Annotation [] [java.lang.Integer]
Annotation [@com.test.Test.NonNull] [argv]

I will update the code later once I manage to fix it.

Update : Now it is printing this. Code is updated. I will explain the changes.

Annotation [com.test.Test.TypeParameter] [[T, S]]
Annotation [com.test.Test.TestTypeParameter] [[T, S]]
Annotation [@com.test.TypeUse] [com.test.Test.Test1]
Annotation [[Lcom.test.TypeUse;@2a5ca609] [java.lang.Integer]
Annotation [@com.test.Test.NonNull] [argv]
-> (java.lang.String[])void

Change 1

This method which I used earlier turns the TypeMirror back to a DeclaredType. That is not required.

    private void processClassTypeParameters(Element e) {
        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {
            //System.out.println( &quot;Annotation [&quot; + typeParameterElement.getAnnotationMirrors() + &quot;] [&quot; + typeParameterElement  + &quot;]&quot;);
            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {
                System.out.println( &quot;Annotation [&quot; + ((DeclaredType)typeMirror).getAnnotationMirrors() + &quot;] [&quot; + typeMirror  + &quot;]&quot;);
            }
        }
    }

This method is replaced with the new method in Test.java shown below. typeMirror.getAnnotationsByType(TypeUse.class) is sufficient to get the annotation on Integer

Change 2

I introduced a new method to get the annotations inside a method and source on which they are applied. But that is not possible. Alex Buckley, the JSR 308 spec. lead replied that

There is no access to annotations in a method body from the Language Model API (or the Core Reflection API).

Actually I introduced this method and called it like this e.asType().accept(visitor(),null); to try to get the annotations from inside the method. This is the method that is printing

    -> (java.lang.String[])void

    private TypeVisitor<Boolean, Void> visitor() {
        return new SimpleTypeVisitor<Boolean, Void>() {
            public Boolean visitExecutable(ExecutableType t, Void v) {
                System.out.println("-> " + t);
                return true;
            }
        };
    }


AnnotationFinder.java

package com.test;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVisitor;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.lang.model.util.SimpleTypeVisitor8;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static javax.lang.model.util.ElementFilter.typesIn;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class AnnotationFinder extends AbstractProcessor{


    public AnnotationFinder(){
        super();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        TypeElement tye = null;

        if( !roundEnv.processingOver()){

            Iterator<? extends Element> te = annotations.iterator();

            for (TypeElement element : typesIn(roundEnv.getRootElements()) ) {

                processEnclosedElements(element.getEnclosedElements(),
                                        roundEnv);

            }
        }
        return false;
    }

    private void processEnclosedElements(List<? extends Element> enclosedElements,
                                         RoundEnvironment roundEnv) {

        for( Element e : enclosedElements ){

            if( e.getKind() == ElementKind.ANNOTATION_TYPE &&

                    !roundEnv.getElementsAnnotatedWith((TypeElement) e).isEmpty()){

                System.out.println( "Annotation [" + e + "] [" +
                        roundEnv.getElementsAnnotatedWith((TypeElement) e) + "]");

            }else if( e.getKind() == ElementKind.METHOD ){

                for (VariableElement variableElement : ((ExecutableElement) e).getParameters()) {

                    System.out.println("Annotation [" + variableElement.getAnnotationMirrors() + "] [" +

                                                                                         variableElement + "]");
                    e.asType().accept(visitor(),null);

                }

            }else if (e.getKind() == ElementKind.CLASS){

                System.out.println( "Annotation [" + e.getAnnotationMirrors() + "] [" + e  + "]");

                processClassTypeParameters(e);
            }
        }
    }

    private TypeVisitor<Boolean, Void> visitor() {

        return new SimpleTypeVisitor8<Boolean, Void>() {

            public Boolean visitExecutable(ExecutableType t, Void v) {

                System.out.println("-> " + t);

                return true;
            }
        };
    }

    private void processClassTypeParameters(Element e) {

        for (TypeParameterElement typeParameterElement : ((TypeElement) e).getTypeParameters()) {

            //System.out.println( "Annotation [" + typeParameterElement.getAnnotationMirrors() + "] [" + typeParameterElement  + "]");

            for (TypeMirror typeMirror : typeParameterElement.getBounds()) {

                System.out.println( "Annotation [" + typeMirror.getAnnotationsByType(Test.TypeUse.class) + "] [" + typeMirror  + "]");

            }
        }
    }
}

JSR 308

The annotation system has been extended. I realized that there are more annotation types and more source locations where they are permitted.

I compiled a simple example. The specification is here

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)


package com.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


public class Test {

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_USE)
    @interface  TypeUse {}

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_PARAMETER)
    @interface  TypeParameter {}

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE_PARAMETER)
    @interface  TestTypeParameter {}

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    @interface NonNull {}


    /**
             * ElementType.TYPE PARAMETER stands for a type parameter — that is, the declaration of a type variable. Examples
             are in generic class declarations class MyClass<T> {...}, generic method declarations <T> foo(...) {...}, and
             wildcards List<?>, which declare an anonymous type variable.
             * @param <T>
             */
    @TypeUse class Test1<@TypeParameter @TestTypeParameter T extends @TypeUse Integer> {

        /**
         * A type annotation is permitted in front of a constructor declaration, where declaration annotations are already
         permitted.
         */
        @TypeUse <@TypeParameter @TestTypeParameter S> Test1(String s){

        }
    }


    public static void main(  @NonNull String... argv ){

        Object o = ( @TypeUse String ) new String( "Test" );

        if( o instanceof @TypeUse String ){

        }
        try{

        }catch( @NonNull Exception e){

        }

    }
}
        List list1 = list.
                       stream().
                        map(p::matcher).
                          filter(Matcher::find).map(matcher -> matcher.group()).
                              collect(Collectors.toCollection(@ NonNull ArrayList::new));

Simplified code using Java 8 flatMap

This code solved one of the problems. It accumulates all the matches by looping over m.find(). The main problem is still not solved. It does not work on the result of the previous match.

So the result is wrong.

[Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|]
[Current Usage : init:2359296, used:13915200, committed:13959168, max:50331648|]
[2359296, 13914944, 13959168, 50331648, 2359296, 13913536, 13959168, 50331648, 13, 31, 48, 13, 27]
[2359296, 13916608, 13959168, 50331648, 2359296, 13915200, 13959168, 50331648, 13, 31, 48, 13, 27]

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class SimplerFlatMapTest {

    public static void main( String... argv ){

        List<String> source = new ArrayList<String>();
        source.add( "Peak Usage    : init:2359296, used:13914944, committed:13959168, max:50331648Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");
        source.add( "Peak Usage    : init:2359296, used:13916608, committed:13959168, max:50331648Current Usage : init:2359296, used:13915200, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");

        List<Pattern> patterns = Arrays.asList(Pattern.compile("Current.*?[/|]"), Pattern.compile("[0-9]+(/,|/|)"));


        Function<Matcher, List<String>> matches1 = m -> {
            List<String> list = new ArrayList<String>();
            while(m.find()) {
                list.add(m.group());
            }
            return list;
        };

        patterns.stream()
                .flatMap(p -> source.stream().map(p::matcher))
                .map(matches1)
        .forEach(System.out::println);
    }
}

Java 8 flatMap

I compiled this code with

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b113)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b55, mixed mode)

The documentation of flatMap was not easy to understand but there are two streams that are mixed – the source stream and the regular expression pattern stream. I am applying the regular expressions one by one on the source lines to get what I want. So here I am able to get the first value(2359296) from the line

The problem with this approach is this. The result of the first regex match is this line.

Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|

The second regex should be applied on this line. Not on the original line. But that is how this code works. Moreover it does not give me all the values returned by looping over Matcher::find

Not the other values. I have to find a way of coding it to get all.


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FlatMapTest {

    public static void main( String... argv ){

        List<String> source = new ArrayList<String>();
        source.add( "Peak Usage    : init:2359296, used:13914944, committed:13959168, max:50331648Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");
        source.add( "Peak Usage    : init:2359296, used:13916608, committed:13959168, max:50331648Current Usage : init:2359296, used:13915200, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////|                                                  | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb");

        List<Pattern> patterns = Arrays.asList(Pattern.compile("Current.*?[/|]"), Pattern.compile("[0-9]+(/,|/|)"));

        //Style 1
        patterns.stream()
                .flatMap(new Function<Pattern, Stream<String>>() {
                    @Override
                    public Stream<String> apply(Pattern p) {
                        return source.stream()
                                .map(p::matcher)
                                .filter(Matcher::find)
                                .map(Matcher::group);
                    }
                })
                .forEach(System.out::println);

        //Style 2
        patterns.stream().flatMap(( Pattern p1 ) -> source.
                stream().
                map(p1::matcher).
                filter(Matcher::find).map(matcher -> matcher.group())).forEach(x -> System.out.println(x));

    }
}

Learning Lambda

I think Java lambdas have some powerful functional programming support and this is an attempt to convert part of the ‘R’ code to Java.

I start with this line from the GC log file.

Total Memory Pools: 5

Pool: Code Cache (Non-heap memory)

Peak Usage : init:2359296, used:13914944, committed:13959168, max:50331648
Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648

|------------------| committed:13.31Mb
+---------------------------------------------------------------------+
|//////////////////| | max:48Mb
+---------------------------------------------------------------------+
|------------------| used:13.27Mb

Pool: PS Eden Space (Heap memory)

Peak Usage : init:89522176, used:186449920, committed:234356736, max:234618880
Current Usage : init:89522176, used:36258088, committed:233570304, max:233635840

|--------------------------------------------------------------------| committed:222.75Mb
+---------------------------------------------------------------------+
|////////// || max:222.81Mb
+---------------------------------------------------------------------+
|---------| used:34.58Mb

Pool: PS Survivor Space (Heap memory)

Peak Usage : init:14876672, used:25217592, committed:35651584, max:35651584
Current Usage : init:14876672, used:0, committed:1114112, max:1114112

|---------------------------------------------------------------------| committed:1.06Mb
+---------------------------------------------------------------------+
| | max:1.06Mb
+---------------------------------------------------------------------+
| used:0b

Pool: PS Old Gen (Heap memory)

Peak Usage : init:954466304, used:272270080, committed:954466304, max:1886519296
Current Usage : init:954466304, used:269639088, committed:954466304, max:1886519296

|----------------------------------| committed:910.25Mb
+---------------------------------------------------------------------+
|////////// | | max:1.76Gb
+---------------------------------------------------------------------+
|---------| used:257.15Mb

Pool: PS Perm Gen (Non-heap memory)

Peak Usage : init:16777216, used:112329944, committed:210763776, max:1073741824
Current Usage : init:16777216, used:112329944, committed:112852992, max:1073741824

|------| committed:107.62Mb
+---------------------------------------------------------------------+
|//////| | max:1Gb
+---------------------------------------------------------------------+
|------| used:107.13Mb

tables <- htmlParse("memorypools.txt")

y <- xpathSApply(tables,"//b//text()[contains(.,'Pool: Code Cache')]//following::blockquote[1]",xmlValue)
y <- data.frame(y)

I use ‘R’ to parse the line first because I found it hard to use Java to parse the unstructured line with HTML tags

After the first phase the line looks like this.

[1] "Peak Usage : init:2359296, used:13914944, committed:13959168, max:50331648Current Usage : init:2359296, used:13913536, committed:13959168, max:50331648|------------------| committed:13.31Mb+---------------------------------------------------------------------+|//////////////////| | max:48Mb+---------------------------------------------------------------------+|------------------| used:13.27Mb"

Java 8 code

import java.io.IOException;
import java.nio.file.Files;
import java.util.Scanner;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.Paths.get;

public class GCLogParser {

    private void readFile() throws IOException {

        Stream<String> s = Files.lines(get("gclog.txt"), UTF_8);
        s.forEach( this::parse  );
    }

    public static void parseDocument(Parseable parser,
                                     String data){
        parser.apply(data);
    }
    private void parse( String data ){

        Scanner s = new Scanner( data );
        s.findInLine("Current.*?[/|]");
        System.out.println(s.match().group());
    }

    public static void main( String... argv ) throws IOException {
        new GCLogParser().readFile();
    }

    @FunctionalInterface
    public interface Parseable{
         void apply( String s);
    }
}

This Java code gives me this line. This is just new syntax and constrcts and I don’t think I have used the functional style of programming properly here.

Current Usage : init:2359296, used:15775680, committed:15859712, max:50331648|