Monday, January 26, 2015

Anti Pattern - ThreadLocal variables with Thread Pool

In a previous post I wrote the usage and benefits of ThreadLocal based instance variables in concurrent applications. This seemingly innocent and fail proof implementation will provide clear data separation and visibility between threads in multi threaded applications UNTIL, you use Thread Pooling.

ThreadLocal variables as the name suggest is local to the thread, til the thread is alive the ThreadLocal instance variable can not be Garbage Collected. This post explains the theory clearly.

To see it in action I wrote small program which infinitely creates Tasks in one implementation submitting tasks to a Thread Pool and in another instance creating ad-hoc Threads which are no pooled. And I used jVisualVM to monitor the VM.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ThreadLocalTest {

    private static ExecutorService executor = Executors.newFixedThreadPool(100);
    
    public static void main(String[] args) {
        while(true) {
            // Thread Pooled based implementation
            executor.execute(new SimpleThread());
            // Ad-hoc Thread based implementation
            new SimpleThread().start();
        }
    }
    
    public static class SimpleThread extends Thread {
        
        private ThreadLocal<Integer> no = new ThreadLocal<Integer>() {

            @Override
            protected Integer initialValue() {
                return 0;
            }
            
        };
        
        public void run() {
            while(no.get() < 100) {
                no.set(no.get() + 1);
            }
            System.out.println(String.format("Thread : %s Finished", Thread.currentThread().getName()));
            no.remove();
        }
    }
}


In the Thread pooled implementation one thread throwing an Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Thread Name" is just a matter of time.

Where as the adhoc Thread creation seems to keep on running with good VM Garbage Collection but the Thread pool implementation fills up the heap space within minutes and eventually runs out of memory. 

Lesson

Always keep an eye on the Thread classes you use in your application, make sure they don't have ThreadLocal variables when you are using Thread Pooling.

Give special care when you get pre-compiled third party libraries which might have ThreadLocal so always read javadocs thoroughly when you use Thread pooling.


Tuesday, December 23, 2014

IoT with MQTT + Apache Kafka (Arduino + Raspberry Pi)

Motivation

Internet of Things always fascinated me because of the sheer no of people talking about it and the no of projects coming up related to it. So I thought I should give it a go myself and put up a small demonstration to learn the concepts of IoT projects.

This project is about implementing a IoT system to measure illumination inside of a house and act upon when there is low illumination by illuminating a light.

Design

Architecture


Arduino + Photoresistor Schematic


Raspberry Pi + LED Schematic



Implementation Decisions

I could have easily connected the Arduino and Raspberry Pi directly and get the thing done but I wanted to learn the correct and hard way to do as that is the whole purpose of this project. After some research on the internet I found that the best way to connect CPU and Memory constraint devices to IoT system is by using a protocol called MQTT. MQTT is a pub/sub protocol with a very small (2 byte) header which is ideal for small devices such as Arduino and reduces bandwidth usage when sending data across networks. 

But my aim was not fulfilled with this, what I wanted to implement is a system where more and more devices can be connected both as publishers of parameters (Illumination, Temperature, Humidity, etc.) and as consumers of those parameters in a scalable, decoupled manner. So after some more research I found that there are messaging queues used to enable this decoupling and scalability concerns. During my research I found that there is a upcoming tool named Apache Kafka which is capable of delivering what I am expecting in a more secure fault tolerant manner, so I decided to have it a go and see.

Implementation

Hardware
  1. 1 Arduino UNO Development Board
  2. 1 Raspberry Pi Model B
  3. 1 Ethernet Shield
  4. 1 Wifi Adaptor (Dongle)
  5. 1 Photoresistor 
  6. 1 LED
  7. 1 Resistors
  8. 1 Wireless Router with LAN Port
Software

All Software used in this project is available at https://github.com/shazin/iot

Prerequisites

Apache Kafka must be downloaded and configured to be started on a PC/Laptop, MQTT Server mosquitto must also be running.

For Apache Kafka refer this url Kafka Getting Started
For Mosquitto refer this url Mosquitto

Demonstraton


The Terminal Tabs in the video have the following started;

  1. Mosquitto Server 
  2. Zookeeper Server for Apache Kafka
  3. Apache Kafka Server
  4. Apache Kafka Consumer consuming on topic illumination
  5. SSH session to raspberry pi which is running illumination.py python script
And the Spring Source IDE is running Mqtt Kafka Bridge.

When the Photoresistor in Arduino is cover the illumination parameter drops below 300 which will trigger the LED in Raspberry Pi to illuminate.

Lessons Learnt

The approach I tried is very responsive and is easy to scale because of the decoupling I have done by using Mosquitto and Apache Kafka. I didn't see any lags in Raspberry Pi consumer or Arduino Producer. This is may be required for System with lower latency SLAs. 

Future Work

As this is my first attempt at IoT systems, I have left out security and device identification aside. But these are highly required in a fully fledged IoT system. Planning to work on them in the future.

References

  1. Samza in LinkedIn: How LinkedIn Processes Billions of Events Everyday in Real-time - Neha Narkhede
  2. Federated Identity for IoT with OAuth - Paul Fremantle
  3. Python Kafka
  4. Kafka Java API 
  5. MQTT Java API
  6. Arduino Pub/Sub Client

Wednesday, November 12, 2014

Java 8 : Not a Paradigm Shift. Just Revisiting the Old Roots 2

This post is a continuation of previous post.

Recently I was privileged enough to see two great talks by two Industry Experts. Namely Jessica Kerr and Dr. Venkat Subramaniam and I have the links to those talks at references section and I strongly advise to watch those. First I watched Jessica Kerr's talk on Functional Principles for Object-Oriented Developers and secondly I watched Dr. Subramaniam's talk on Java 8 Language Capabilities. What's in It for You?. I am really glad that I watched those videos in that order because it made me understand the problems prior to Java 8 and how Java 8 has solved those problems elegantly.

Main takeouts from Jessica's talk are the followings;
  1. Function/Methods should not modify shared mutable states.
  2. Function/Methods should not modify input parameters.
  3. Function/Methods should not do harm to the world.
  4. Function/Methods should not change the execution flow (Exceptions must be returned as data not thrown).
She clearly goes through the benefits of being functional and how it can be achieved in different languages including Java prior to Java 8 using Google Guava library. She further explains that our code must move away from being Imperative to being more Functional/Declarative. In the sense we must say what we are need to do but not how to do it. One great example she points out is SQL. SQL language is highly declarative where we don't care how Oracle, MySQL, MS SQL RDBMS's store data underneath. We just say I want all the data of customers by just issuing "SELECT * FROM Customers". This is a really strong concept because this gives the actual Oracle, MySQL, MS SQL implementations to change transparently without ever breaking the client code. Those RDBMS's can retrieve data sequentially, parallel or in any other form. More on this through the words of Jessica herself;

"The power of SQL's declarative style isn't about swapping out Oracle for MySQL; any standard can do that. It's more about, for a given query, the database is free to swap out its strategy based on the shape of the data.
Say you want to count customers in the UK with open orders. (approximate syntax, crude table design)

SELECT COUNT(DISTINCT customer_id) FROM customers JOIN orders ON customer_id
WHERE orders.status = 'OPEN'
AND customer.country = 'UK'

If both tables are small, the database might start with the join and then filter.
If the order table is huge but very few of them are OPEN, the database might start by finding open orders, then connect them to customers, then filter again.
If the customers table is partitioned, the database might split up the table and run in parallel on each partition.

This is the power of a declarative style, of telling the database WHAT to do, not HOW to go about it. All within one underlying database implementation!"

Dr. Subramaniam's talk further verifies the claims of Jessica and explains in detail how Java 8 allows Developers to make the transition from being Imperative to being more Functional/Declarative by introducing Lambda Expressions and Streams. Lambda Expressions makes functions act also as first class citizens allowing Functional/Declarative style coding. One code excerpt I took from Dr. Subramaniam's talk is the following;

import java.util.List;
import java.util.Arrays;
import java.util.function.Consumer;

public class Sample {

    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        //Imperative
        //External Iteration

        for(int i = 0;i<numbers.size();i++) {
            System.out.println(numbers.get(i));
        }

        for(int e:numbers) {
            System.out.println(e);
        }

        //Internal Iteration

        numbers.forEach(new Consumer<Integer>() {
            public void accept(Integer no) {
                System.out.println(no);
            }
        });

        numbers.forEach((Integer no) -> System.out.println(no));

        numbers.forEach((no) -> System.out.println(no));

        numbers.forEach(no -> System.out.println(no));

        numbers.forEach(System.out::println);

        //Functional/Declarative
    }
}

The above code can be described as the blue print of Imperative to Functional/Declarative evolution in Java. The code begins being highly Imperative where we need to tell how to loop a Collection of numbers then it gradually evolves to become a highly Functional/Declarative where Iteration and Logic is handed over to the Collection itself. All the codes print out the same results.

Furthermore he shows how mutations takes place with Imperative code and how we can eliminate mutations by making use of Functional/Declarative style of coding in Java 8. Following code describes;

import java.util.List;
import java.util.Arrays;
import java.util.function.*;

public class Sample1 {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Imperative
        int total = 0;
        for(int e:numbers) {
            total += e;
        }    
        System.out.println(total);

        // Functional/Declarative
        System.out.println(numbers.stream()
                                  .reduce(0, (c, e) -> { return c + e; }));

        // Imperative
        total = 0;
        for(int e:numbers) {
            if(e % 2 == 0) {
                total += e;
            }
        }     
        System.out.println(total);

        // Functional/Declarative
                System.out.println(numbers.stream()
                                          .filter(e -> e % 2 == 0)
                                          .reduce(0, (c, e) -> { return c + e; }));
        
        // Imperative
        total = 0;
        for(int e:numbers) {
              total += (e * 2);
        }     
        System.out.println(total);

        // Functional/Declarative
                System.out.println(numbers.stream()
                                          .map(e -> e * 2)
                                          .reduce(0, (c, e) -> { return c + e; }));

        // Imperative
        int no = 0;
        for(int e:numbers) {
             if(e > 3 && e % 2 == 0) {
                 no = e;
                 break;
             }  
        }     
        System.out.println(no);

        // Functional/Declarative
        System.out.println(numbers.stream()
                                  .filter(e -> e > 3)
                                  .filter(e -> e % 2 == 0)
                                  .findFirst()
                                  .orElse(0));

        // Imperative
        System.out.println(total(numbers, e -> true));
        System.out.println(total(numbers, e -> e % 2 == 0));
        System.out.println(total(numbers, e -> e % 2 == 1));

        // Functional/Declarative
        System.out.println(total2(numbers, e -> true));
        System.out.println(total2(numbers, e -> e % 2 == 0));
        System.out.println(total2(numbers, e -> e % 2 == 1));

    }

    public static int total(List<Integer> numbers, Predicate<Integer> condition) {
        int total = 0;
        for(int e:numbers) {
            if(condition.test(e)) {
                total += e;
            }
        }
        return total;
    }

    public static int total2(List<Integer> numbers, Predicate<Integer> condition) {
        return numbers.stream()
                      .filter(condition)
                      .reduce(0, (c, e) -> c + e);
    }
    
}

The fact of the matter is Imperative code with mutations can cause headaches and hair loss if they need parallelism. Where as the Functional/Declarative style of coding in the above code can be parallelized by just changing "numbers.stream()" to "numbers.parallelStream()". That's it.

This is because in Functional/Declarative we are saying what needs to be done not how to do it. So how to do it can be decided by the JVM just as how RDBMS decide how to retrieve data for a particular SQL query. Furthermore Functional/Declarative style is combined with Lazy (Efficient) execution where there are Intermediate (map, filter) and Terminal (reduces, findFirst) functions. The Stream will not be evaluated until we call a Terminal function making our code efficient.

Both of the speaker agree on one thing. Familiar code is not necessarily Readable code. Just because we have written for loops to iterate a zillion times doesn't mean it is not complex. Don't be fooled by thinking that because Java 8 Functional/Declarative style of coding is Complex because it looks Unfamiliar. May be it is the best and efficient way to do what you really want to do.

I would like to end this by a quote by Dr. Subramaniam, he states "The biggest change in Java 8 are in the minds of the programmers".

References
  1. Functional Principles for Object-Oriented Developers - By Jessica Kerr
  2. Java 8 Language Capabilities. What's in It for You? - By Dr. Venkat Subramaniam

Java 8 : Not a Paradigm Shift. Just Revisiting the Old Roots 1

When I started my Bachelor's in Software Engineering back in 2007 during very early stages I was attending a Module for Programming Principles and there the lecturer said that our programs must never use global variables (Module was using C++) and each problem should be broken into a Function/Method essentially the practice Functional Decomposition. But during this time I was working as a Java Developer for a Company and my inner Java Developer opposed to this.


As Java being an Object Oriented Programming language, we are advised to think in terms of Objects rather than Function/Method. Practically functions/methods are second class citizens in Java. There is no way a Function/Method can exist without it being attached to a Class or being part of an Object. So I thought Functional Decomposition is old school and was only applicable for languages that is highly function oriented like C/C++.

But couple of years back I started reading the book Java Concurrency in Practice book and it stated that thread safety is all about protecting shared mutable state. If a Class in Java has no instance or static variables that Class becomes thread safe. One theory I learned from that book is that,

"If there are shared mutable states in a Class and if more than one thread reads those states and also if at least one thread modifies those states then access (read/modification) to those states must be synchronized"

So it all came back to me, What I learnt in 2007 as part of my Bachelor's is actually part of Java also. Global variables can be considered as shared mutable states. It is better if a Class has lesser no of shared mutable states so that in can become more concurrent friendly. Because synchronization is costly, be it Monitor lock, Copy-On-Write, Compare-And-Swap, etc. all must be used to a minimum level with shared mutable variables or the program performance can degrade.

Best approach is Immutability in classes. Immutable classes are inherently thread safe and performance degrading is not a concern. For example Java String class immutable being that after instantiate and initialization its state can not be modified. Invoking almost every Method on a String object will produce a new String object.

Furthermore the theory I learned in 2007 is so much alive today. Functional Decomposition is actually the ideal solution for today's problems. Problems broken down into Functions/Methods are easier to code/test/debug/maintain.

Next we'll see how Java 8 Helps to achieve Immutability and Functional Decomposition.

References

  1. Java Concurrency in Practice - http://jcip.net/

Wednesday, October 22, 2014

Neo4j Graph Database Backend for Spring Security Acl 2

Problem

Discussed in previous post

Design

The first challenge was Modelling a set of Tables with Relationships to a Graph. After studying the Tables and Their Relationships I came up with the following Design.

This design can be improved but I stuck with this because the intention was to increase performance not to win a Design competition. Furthermore this design covers the Domain of Spring Security ACL concisely so I stuck with this. Naming of the relationships could be improved but I like these.

In order to successfully provide a Neo4j back-end for Spring Security ACL we must implement three interfaces with Neo4j specific implementation.
  1. LookupStrategy - Used to Read Acls based on Class Name and Instance Id
  2. AclService - Non Mutable Acl related Services
  3. MutableAclService - Mutable Acl related Services

Implementation Decisions

I used Spring-Data-Neo4j project which is an abstraction layer on top of the Neo4j Graph Database which allows annotated classes to be represented as Nodes and Edges, which is convenient for Rapid Development. Furthermore it allows Repositories to do CRUD operations also but in this project I opted not to use them and instead used Neo4jTemplate because I knew I would need to write alot of Dynamic Cypher queries.

Development

The full source of the development is available at https://github.com/shazin/spring-security-acl-neo4j

Testing

The biggest question is "Will it be faster than RDBMS based implementations?". If not the whole project was a failure. Test coverage was done on both Mutable and Non Mutable Acl Services. Testing Non Mutable Acl Service will cover Lookup Strategy as it is used underneath. 

Neo4j In-memory Test Database was used to Test. This is a JVM based, Production Not Ready, Single Database instance. Assuming Production ready Neo4j Embedded or Neo4j Server Databases will increase performance (It ideally should) I decided to test using this. 

The RDBMS I used to Test against was H2, which is also a JVM based, but Production Ready In-memory Database. 

Both being in-memory implementations and being JVM based somewhat testifies that the underlying Storage hardware has no input in performance (SATA, SSD, doesn't matter) and no latency due to Network congestion.

And I was using the Ubuntu 14.04 LTS 64-bit Operating system with Intel Core i7 Processor, 4 Gb RAM and Sun JDK 8.

Test Data comprised of 200 ACL Entries (2 for each Object Identity), 3 Sids (Including logged in User Sid), 100 Classes and 100 Object Identities.

Testing was mainly focused on Retrieval and for to retrieve 50 non following Object Identities with ACL Entries (2 for each Object Identity) while running four random times with an Empty Cache, following were the results. 


The results are in Nanoseconds and Neo4j based Spring Security Acl implementation is a clear winner!

Conclusion

Neo4j clearly stands up for its claims and with this implementation Spring Security ACL could also reach its fullest potential. Can clearly say that this is one of the fastest backend implementations for Spring Security ACL. Even though the difference is in Nanoseconds, the performance will matter with higher volume of Users, Object Identities, Sids and ACL Entries. 

The code base could be improved, specially in Cypher queries thus increasing performance even more. Anyone who likes to contribute is welcome.

This doesn't mean that RDBMS are now obsolete. I personally think that RDBMS will be here for at least another 20 years if not more!

And constructive criticism is always welcome.

References
  1. http://neo4j.com/docs/stable/introduction.html - Cypher Language
  2. http://www.h2database.com/html/main.html - H2 Database


Neo4j Graph Database Backend for Spring Security Acl 1

As part of work here at Mimos, I have been working a lot with Spring Security. Some of my previous posts are testament for this. I even got the chance to work with Spring Security ACL which is a project which also comes under Spring Security eco-system and covers the "Authorization" part of Security. I feel Spring Security ACL project is seriously under-rated and one factor which stops it from reaching its fullest potential is in my opinion its Data store end. 

Predominantly design to work with a Relational Database, Spring Security ACL Team have done a great job to reduce the round trips to fetch data from Database by using Caching extensively which decreases data read time heavily.  Yet in a production system where ACL data also tend to change rapidly and with higher volume of users, ACLs and Objects to Protect, Bottleneck at Data end is inevitable. 

Furthermore Spring Security ACL Data is distributed in 4 tables named acl_sid, acl_class, acl_object_identity and acl_entry. So to query and retrieve ACL entries for a Principal or Role for a Particular class instance, Joining of these 4 tables is required. 

Also I got the exposure to do a Research and Development on Neo4j Graph Database which is a NoSQL, Schema-less, Graph Database which stores Data in the form of Property Nodes and Edges.

Neo4j is widely used in the Industry from Courier Route Decision Making to Finding a Date Match. Neo4j is said to be really good to represent Highly Connected Data because it stores all the Data in a Graph and said to be able to Model the real world as close as possible.

While reading through Neo4j Use Cases, I found that a Telecommunication company has used Neo4j for its Identity and Access Management system to improve performance. With Neo4j they have managed to reduce load time from Minutes to Milliseconds. 

This got me thinking and lit a light bulb over my head. What if I can write a Data backend for Spring Security ACL using Neo4j? Easier said than done. Neo4j being a Graph Database is a completely different paradigm with its own query language to named Cypher. 

References
  1. http://docs.spring.io/spring-security/site/docs/3.0.x/reference/domain-acls.html - Spring Security Acl
  2. http://neo4j.com/ - Neo4j
  3. http://neo4j.com/users/telenor/ - Telecom Use Case

Tuesday, September 30, 2014

Spring Security Filter Chain Registration Using WebApplicationInitializer for Servlet 3.x

Starting from Servlet 3.x Specification some code saving features have been introduced such as XML less annotation based Servlet and Filter registration. In conjunction with this Spring has introduced WebApplicationInitializer interface which allows the registration of Servlet and Filters using Java instead of using web.xml file.

This is neat feature because this will eliminate the need for the XML files required in the Spring MVC based web applications. Since most of the Spring Application Context configurations are also directing towards Java Config, Moving to would be ideal;

I read the documentation of the Spring WebApplicationInitializer and was able to register both DispatcherServlet and DelegatingFilterProxy in using it. So the following web.xml tags;

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.lkbotics.visualizer.config.AppConfig</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <filter>
      <filter-name>springSecurityFilterChain</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
      <filter-name>springSecurityFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
      <filter-name>eTagFilter</filter-name>
      <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
      <async-supported>true</async-supported>
  </filter>
  <filter-mapping>
      <filter-name>eTagFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
          <param-value>com.lkbotics.visualizer.web.config.MvcConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

Can effectively be replaced by the following implementation of WebApplicationInitializer

import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import org.springframework.web.servlet.DispatcherServlet;

import com.lkbotics.visualizer.config.AppConfig;
import com.lkbotics.visualizer.web.config.MvcConfig;

public class CustomWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);
        
        container.addListener(new ContextLoaderListener(rootContext));
        
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(MvcConfig.class);
        
        FilterRegistration.Dynamic springSecurityFilterChain = container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy());
        springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
        springSecurityFilterChain.setAsyncSupported(true);
        
        FilterRegistration.Dynamic shallowETagFilter = container.addFilter("shallowETagFilter", new ShallowEtagHeaderFilter());
        shallowETagFilter.addMappingForUrlPatterns(null, true, "/*");
        shallowETagFilter.setAsyncSupported(true);
        
        ServletRegistration.Dynamic dispatcher = container.addServlet("servletDispatcher", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.setAsyncSupported(true);
        dispatcher.addMapping("/");        
    }

}

As usual Spring Security requirements apply, There must be FilterChainProxy bean registered with the name springSecurityFilterChain or custom bean name must be passed in while instantiating the DelegatingFilterProxy inside WebApplicationInitializer.

Caveats [1]

web.xml versioning

WEB-INF/web.xml and WebApplicationInitializer use are not mutually exclusive; for example, web.xml can register one servlet, and a WebApplicationInitializer can register another. An initializer can even modify registrations performed in web.xml through methods such as ServletContext#getServletRegistration(String). However, if WEB-INF/web.xml is present in the application, its version attribute must be set to "3.0" or greater, otherwise ServletContainerInitializer bootstrapping will be ignored by the servlet container.


References
  1. WebApplicationInitializer
  2. FilterRegistration.Dynamic