Tuesday, February 17, 2015

Java 8 lambda Example 2

Here is a slightly more interesting Java 8 example.  The larger problem being solved involves several smaller needs.
  1. Finding a users active directory group memberships that match an application specific pattern
  2. Extracting an organizational "short name" from the group definitions
  3. Returning a list of official organizational ID's associated with the short names. 
Described in a little more detail; if you had a user that belonged to the AD groups like:
    CN=HapBu-WidgetMaint-App-Employee-Role,OU=Security,OU=Groups.DC=TESTORG,DC=ORG
    CN=ChkSk-WidgetMgr-App-Employee-Role,OU=Security,OU=Groups.DC=TESTORG,DC=ORG

    CN=Other-App-Role,OU=Security,OU=Groups.DC=TESTORG,DC=ORG
You want to select the first 2 roles because they contain: 
     App-Employee-Role,OU=Security,OU=Groups
which would be the first 2 items.  From those, you want to take the "friendly org name" which would be the values "HapBu" and "ChkSk" and map those to an organization # by using an enum of valid organizations which maintains the mapping.
In the past this would probably require some fairly specific dedicated classes/methods.  I found that I am able to do this in a simpl fashion in Java 8.  I won't say that it was especially fast for me to develop this but I think over time it will become easier and more natural.

This enumeration, OrganizationInfo, is simply showing the use of a lambda if defining an a method which uses alternative key type info to search/select an enum value.
 package test2;  
 import java.util.Arrays;  
 import java.util.function.Predicate;  
 public     enum OrganizationInfo  
 {  
      HAPPYBURGER("O123", "HapBu"),  
      TONYTORTILLA("O543", "TonTo"),  
      CHICKENSHACK("O443", "ChkSk");  
      OrganizationInfo(final String orgCode,  
                final String displayableName)  
      {  
           this.orgCode = orgCode;  
           this.displayableName = displayableName;  
      }  
      String getOrgCode()  
      {  
           return orgCode;  
      }  
      /* This is a pretty generic method to select an enum  
       * value based on some attribute. For this example,  
       * it is a bit overkill but in a more realistic context this  
       * allows a good amount of code reuse.  
      */  
      private static OrganizationInfo search(  
                final Predicate<OrganizationInfo> predicate)  
      {  
           // This filters the enum list by the provided predicate and  
           // returns the first match.  
           return Arrays.asList(  
                     OrganizationInfo.values()).  
                     stream().  
                     filter(predicate).  
                     findFirst().  
                     get();  
      }  
      public static OrganizationInfo displayableNameToEnum(  
                final String displayableName)  
      {  
           // This is example client code to the previous private method and  
           // demonstrates using a lambda to specify the filter predicate  
           return search(p -> p.displayableName.equals(displayableName));  
      }  
      private String orgCode;  
      private String displayableName;  
 }  

The getMultValAttrib method is a good example of what code looks like which receives the lambda.
 package test2;  
 import java.util.Arrays;  
 import java.util.Collections;  
 import java.util.List;  
 import java.util.function.Function;  
 import java.util.function.Predicate;  
 import java.util.stream.Collectors;  
 public class User  
 {  
      /**  
           Responsible for querying multi-valued attribute data from  
           Active Directory for attribute "attribName", only process  
           items matching the predicate and then return values  
           as processed by the provided mapper function.  
      */  
      public List<String> getMultValAttrib(final String attribName,  
        final Predicate<String> predicate,  
           final Function<String, String> mapper)  
      {  
        List<String> data = Collections.emptyList();  
        // Get the data from active directory; skipping  
        // the real details here. Using some dummy data.  
        final String [] attributeData =  
             {  
                  "CN=HapBu-WidgetMaint-App-Employee-Role,OU=Security,OU=Groups.DC=TESTORG,DC=ORG",  
                  "CN=ChkSk-WidgetMgr-App-Employee-Role,OU=Security,OU=Groups.DC=TESTORG,DC=ORG"  
             };  
                  //adctx.getStringAttributes(attribName);  
        if (attributeData != null)  
        {  
                // This is where all the processing is actually done but  
                // note that the processing functions are passed in so this  
                // method is pretty generic.  
          data = Arrays.asList(attributeData). // stream uses a list  
            stream().  
            filter(predicate).  // Filter out only what we want to keep  
            map(mapper). // Perform some caller specific mapping  
            collect(Collectors.toList()); // Produce a list of results  
        }  
        return data;  
      }  
 }  


Below is an example of the above in use.
 package test2;  
 import java.util.List;  
 public class Test2  
 {  
      public static void main(String args[])  
      {  
           User aUser = new User();  
           //....  
           //...  
           List<String> orgCodes =  
                aUser.getMultValAttrib(  
                     "memberOf",  
                     p -> p.matches("(.*App-Employee-Role,OU=Security,OU=Groups.*)"),  
                     g -> OrganizationInfo.displayableNameToEnum(  
                               g.substring(3, g.indexOf('-'))).  
                               getOrgCode());  
           for(String org: orgCodes)  
           {  
                System.out.println(org);  
           }  
      }  
 }  


The above code produces the following output:
O123
O443

No comments:

Post a Comment