Monday, 30 May 2016

Distributed SolrCloud setup with external ZooKeeper ensemble

We all know that Solr search performs better than database queries because of "inverse index" rather than database queries with a full table scan. Databases and Solr have complementary strengths and weaknesses though. In this blogpost we will set up a SolrCloud just like a production system.

SolrCloud or Solr Master Slave
SolrCloud and master-slave both address four particular issues:
  • Sharding
  • Near Real Time (NRT) search and incremental indexing
  • Query distribution and load balancing
  • High Availability (HA) 
If our application just reads data from Solr and need high availability on reading data from Solr then a simple one master to many slave hierarchy is more than sufficient. But if you are looking out for high availability on writing to Solr too, then SolrCloud is a right option

Is SolrCloud is better? Maintaining SolrCloud needs a good infrastructure and have to look out the availability of ZooKeepers, and nodes health, high performance disk for better replication speed etc. But, other than this we don't need to worry about Data consistency among nodes as this will be taken care by SolrCloud.

In which cases is better to coose SolrCloud? 
When we need high availability on Solr Writes as well as reads, we have to go for SolrCloud. Also, if we cannot afford bigger machines to have one single node, then we can split index to shards and keep it under smaller config machines.

In which cases is better to choose Solr Replication? 
When our application does not write in real time to SOLR, Replication is enough and no need to get complicated with SolrCloud. Also, its comparatively easy to setup Master Slave than SolrCloud

Sharding and Data consistency, automatic rebalancing of shards are better in SolrCloud. Query distribution and load balancing is automatic for SolrCloud, in sharded environment for master slave we need to use distributed query.

To setup a distributed SolrCloud we must have the following - 
  1. At least 6 serves (3 for ZooKeeper cluster setup and 3 for SolrCloud setup)
  2. Zookeper
  3. Solr 6
For this blogpost we will be using a single system with three different ZooKeeper and three different Solr6 instances running on different port.

ZooKeeper Cloud Setup 

1. Download Apache ZooKeeper 3.4.6 is the version I am using
2. Create a directory, lets assume zk_cluster under $<home> .
3. Create three instances for ZooKeeper under zk_cluster, lets assume they are zookeeper-3.4.6_1,           zookeeper-3.4.6_2, zookeeper-3.4.6_3.
4. Create data and logs directory under zk_cluster directory.
5. Create ZooKeeper Server ID, basically this file reside in the ZooKeeper data directory.

At this point of time your ZooKeeper cluster will look like -

zk_cluster
|
    |-data
|---zookeeper-3.4.6_1
|--myid (content numeric 1)
|---zookeeper-3.4.6_2
|--myid (content numeric 2)
|---zookeeper-3.4.6_3
|--myid (content numeric 3)
|-log
|---zookeeper-3.4.6_1
|---zookeeper-3.4.6_2
|---zookeeper-3.4.6_3
|-zookeeper-3.4.6_1
|-zookeeper-3.4.6_2
|-zookeeper-3.4.6_3

6. Preparing ZooKeeper configuration called zoo.cfg at $<home>/zk_cluster/{zookeeper-3.4.6_1}/conf/zoo.cfg.  Here I will show you for Server 1. We have to perform same steps with appropriate values (clientPort, dataDir, dataLogDir) for respective ZooKeeper server.


# The number of milliseconds of each tick
tickTime=2000

# The number of ticks that the initial synchronization phase can take
initLimit=10

# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5

# the directory where the snapshot is stored.
# Choose appropriately for your environment
dataDir=$<home>/zk-cluster/data/zookeeper-3.4.6_1

# the port at which the clients will connect
clientPort=2181 <change for other instances>

# the directory where transaction log is stored.
# this parameter provides dedicated log device for ZooKeeper
dataLogDir=$<home>/zk-cluster/logs/zookeeper-3.4.6_1

# ZooKeeper server and its port no.
# ZooKeeper ensemble should know about every other machine in the ensemble
# specify server id by creating 'myid' file in the dataDir
# use hostname instead of IP address for convenient maintenance
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

7. Once zoo.cfg created for all the server then we can start the ZooKeeper Servers. ZooKeeper supports the following commands

  • start
  • start-foreground
  • stop
  • restart
  • status
  • upgrade
  • print-cmd

SolrCloud Setp

Before we create the Solr instances, we'll need to create a configset in order to create a collection to shard and replicate across multiple instances.  Creating a configset is very specific to our  collection. We can use the pre-built configsets that come with Solr 6, they are located in solr-6.0.0/server/solr/configsets and we don't have to do anything.

A custom configset requires taking care of path and third party libraries defined in solrconfig.xml file.We also have to create/update the schema.xml as necessary to map data from the source to a Solr document

Lets assume we are creating a configset named solr_cloud_example simply copying the content of  basic_configs. Additional libraries and schema can be updated before we actually start creating indexes.

Uploading a configset to Zookeeper

This is relevant if we want to upload  configuration ahead of time instead of specifying the configuration to use in the "create" command or if we are using the Collections API to issue a "create" command via the REST interface.


To upload the configset, we have to use zkcli.sh which is in <BASE_INSTALL_DIR>/solr-6.0.0/server/scripts/cloud-scripts.  Lets go to that directory and issue the following command:

./zkcli.sh -zkhost localhost:2181,localhost:2182,localhost:2183 -cmd upconfig -confname < solr_cloud_example > -confdir <base_installation_dir>/solr-6.0.0/sever/solr/configsets/< solr_cloud_example >/conf

This will upload the config directory in ZooKeeper cluster we have setup earlier.

Creating Solr Instances

Under the <base_directory> create a directory <solr_cluster> , download and copy three solr 6 installations. So the directory structure looks like  -

<base_dir>/<solr_cluster>
                            |
                            |-- solr-6.0.0_1
                                    | -- server
                                           |--solr
                                                 |--configsets
                                                       |-- <solr_cloud_example>
                                   
                            |-- solr-6.0.0_2
                            |-- solr-6.0.0_3


Now we are ready with the setup.

Start SolrCloud

At this point of time we have all the setup ready, before we start solr instances make sure the zookeeper cluster is up and running.

Goto
<base_dir>/solr-cluster/solr-6.0.1 and execute
bin/solr start -cloud  -p 8983 -z localhost:2181,localhost:2182,localhost:2183 -noprompt

Goto
<base_dir>/solr-cluster/solr-6.0.2 and execute
bin/solr start -cloud  -p 8984 -z localhost:2181,localhost:2182,localhost:2183 -noprompt

Goto
<base_dir>/solr-cluster/solr-6.0.3 and execute
bin/solr start -cloud  -p 8985 -z localhost:2181,localhost:2182,localhost:2183 -noprompt


once all the instances are running just type
http://localhost:8983/solr/admin/collections?action=CREATE&name=test_solr_cloud&numShards=2&replicationFactor=2&maxShardsPerNode=2
&collection.configName= solr_cloud_example to create a collection named solr_cloud_example

Now go to http://localhost:8983/solr/#/~cloud  you will see the collection along with shards and replications in different nodes


















Wednesday, 16 December 2015

Solr Master - Slave Configuration with DataImportHandler & Scheduling

In this post we will se how we can setup Solr Master - Slave replication setup as shown below -


For simplicity lets assume that we have two nodes node1 and node2. Node1 is the master node and Node2 is the slave node.

1. Install solr-5.3.1 on both Node1(master) and Node2(slave)
2. Create Solr core using the command
    $> bin/solr create [-c name] [-d confdir] [-n configName] [-shards #] [-replicationFactor #] [-p           port]
on both Node1 and Node2

Lets assume the name of the core is test_core.

So in both the instance if we go to ${SOLR_HOME}/server/solr we will see test_core which have conf directory , core.properties file and data directory.

Now lets start with master slave configuration -

Master Setup 

If we navigate to conf directory within the test-core directory under /server/solr we will see solrconfig.xml file

Edit the file and add

<requestHandler name="/replication" class="solr.ReplicationHandler">
    <lst name="master">
         <str name="enable">${master.replication.enabled:false}</str>
         <str name="replicateAfter">commit</str>
         <str name="replicateAfter">optimize</str>
        <str name="replicateAfter">startup</str>
    </lst>

</requestHandler>

add master.replication.enabled=true in core.properties file located in /solr directory.


Slave Setup

If we navigate to conf directory within the test-core directory under /server/solr we will see solrconfig.xml file

Edit the file and add

<requestHandler 
name="/replication" class="solr.ReplicationHandler">
     <lst name="slave">
           <str name="enable">${slave.replication.enabled:false}</str>
           <str name="masterUrl">http://${masterserver}/solr/${solr.core.name}/replication</str>
          <str name="pollInterval">00:05:00</str></lst>

</requestHandler>

add 


slave.replication.enabled=true
masterserver=52.33.134.44:8983


solr.core.name=<core_name> (test_core)

in core.properties file located in /solr directory.


Thats it we are done with master slave configuration.

DataImportHandler

Using solr DataImportHandler we can create indexes in solr directly from data store like MySQL Oracle, Postgre SQL etc.

Lets continue with previous example to configure a data import handler
1.  Edit solrconfig.xml file under conf directory of your core and add -

<requestHandler name="/dataimport"                           class="org.apache.solr.handler.dataimport.DataImportHandler">
  <lst name="defaults">
      <str name="config">data-config.xml</str>
  </lst>
</requestHandler>

2. Create data-config.xml file within the conf directory with following content-

<dataConfig>
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="" user="" password=""/>
    <document name="">
        <entity name="" query=""
deltaQuery="<some_date_condition> &gt; '${recommendation.last_index_time}';">
 <field column="" name="" />
            .
.
.
.
      <field column="allcash_total_annualized_return_growth" name="Allcash_total_annualized_return_growth" />
        </entity>
    </document>
</dataConfig>

3. Create corresponding filed mapping in managed-schema file for index creation.

4. Make sure you have the jar file for Driver class is available in lib directory or any other directory and you have mentioned that in solrconfig.xml file like

<lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />

We are done with DataImportHandler configuration.

Scheduling: 

Solr by default don,t support scheduling for delta import.
Clone either of

1. https://github.com/badalb/solr-data-import-scheduler.git
2. https://github.com/mbonaci/solr-data-import-scheduler.git

Create a jar file and put that jar file in {SOLR_HOME}/ server/solr-webapp/ webapp/ WEB-INF / lib directory

3. Make sure, regardless of whether you have single or multi-core Solr, that you create dataimport.properties located in your solr.home/conf (NOT solr.home/core/conf) with the content like

 #  to sync or not to sync
#  1 - active; anything else - inactive
syncEnabled=1

#  which cores to schedule
#  in a multi-core environment you can decide which cores you want syncronized
#  leave empty or comment it out if using single-core deployment
syncCores=coreHr,coreEn

#  solr server name or IP address
#  [defaults to localhost if empty]
server=localhost

#  solr server port
#  [defaults to 80 if empty]
port=8080

#  application name/context
#  [defaults to current ServletContextListener's context (app) name]
webapp=solrTest_WEB

#  URL params [mandatory]
#  remainder of URL
params=/select?qt=/dataimport&command=delta-import&clean=false&commit=true

#  schedule interval
#  number of minutes between two runs
#  [defaults to 30 if empty]
interval=10

4. Add application listener to web.xml of solr web app ({SOLR_HOME}/ server/solr-webapp/WEB-INF/web.xml)

<listener>
  <listener-class>org.apache.solr.handler.dataimport.scheduler.ApplicationListener</listener-class>
</listener>

Restart Solr so that changes are reflected.

Happy searching .....

Tuesday, 15 December 2015

Integrating Tableau Desktop with Spark SQL

In this post we will see how we can integrate Tableau Desktop with Spark SQL. Tableau’s integration with Spark brings tremendous value to the Spark community – we can visually analyse data without writing a single line of Spark SQL code. That’s a big deal because creating a visual interface to our data expands the Spark technology beyond data scientists and data engineers to all business users. The Spark connector takes advantage of Tableau’s flexible connection architecture that gives customers the option to connect live and issue interactive queries, or use Tableau’s fast in-memory database engine.

Software requirements :-

We will be using the following softwares to do the integration -
1. Tableau Desktop-9-2-0
2. Hive 1.2.1
3. Spark 1.4.0 for Hadoop 2.6.0

We can skip the Hive and can directly work with Spark SQL. For this example we will use Hive, import Hive tables to Spark SQL and will Integrate them with Tableau SQL.

Hive Setup :-

1. Download and install Hive 1.2.1.
2. Download and copy mysql connector jar file to ${HIVE_HOME}/lib directory so hive will use           MySql metastore.
3. Start Hive ${HIVE_HOME}/bin $./hive
4. Create some table and insert data to that table

create table product(productid INT, productname STRING, proce FLOAT, category STRING) ROW FORMAT DELIMITED
        FIELDS TERMINATED BY ',';

INSERT INTO TABLE product VALUES(1,Book,25,Statonery);
INSERT INTO TABLE product VALUES(2,Pens,10,Stationery);
INSERT INTO TABLE product VALUES(3,Sugar,40.05,House Hold Item);
INSERT INTO TABLE product VALUES(4,Furniture,1200,Interiors);

Hive setup is complete now.

Spark Setup :-

1. Download and extract Spark 1.5.2 for Hadoop 2.6.0
2. Copy hive-site.xml from ${HIVE_HOME}/conf directory to ${SPARK_HOME}/conf directory
3. Replace all "s" from time values like 0s to 0 or <xyz>ms to <xyz> else it might give us Number         Format Exception
4. Define  SPARK MASTER IP export SPARK_MASTER_IP=<host_ip_addr>  in spark-env.sh file  (without this thrift server will not work) located at ${SPARK_HOME}/conf directory

5. Start spark master and slave
  1. ${SPARK_HOME}/sbin $./start-master.sh 
  2. ${SPARK_HOME}/sbin $./start-slaves.sh 
6. Goto http://localhost:8080/   and check that worker has started

Now time to start Thrift server -

7.  ${SPARK_HOME}/sbin $ ././start-thriftserver.sh --master spark://<spark_host_ip>:<port> --driver-class-path ../lib/mysql-connector-java-5.1.34.jar  --hiveconf hive.server2.thrift.bind.host localhost --hiveconf hive.server2.thrift.port 10001

It will start thrift server on 10001 port


8. Go to http://localhost:8080/  and check spark sql application has started








































Now go to Tableau Desktop
  1. Select Spark Sql.
  2. Enter host as localhost, enter thrift server port from step here its 10001
  3. Select type as SparkThriftServer, Authentication as User Name 
  4. Keep rest of the fields empty and click on OK
You are done!!! Happy report building using Tableau-Spark.




Monday, 19 October 2015

Vagrant - Puppet Java development environment setup


Vagrant:-

Vagrant is an open-source (MIT) tool for building and managing virtualised development environments

Simply put, Vagrant makes it really easy to work with virtual machines. According to the Vagrant docs:

"If you’re a designer, Vagrant will automatically set everything up that is required for that web app in order for you to focus on doing what you do best: design. Once a developer configures Vagrant, you don’t need to worry about how to get that app running ever again. No more bothering other developers to help you fix your environment so you can test designs. Just check out the code, vagrant up, and start designing."

Puppet:-

Puppet is a configuration management tool that is extremely powerful in deploying, configuring, managing, maintaining, a server machine.


Librarian Puppet:-

Librarian-puppet is a project by the amazing Tim Sharpe to take Librarian, a general reimplementation of Bundler, and provide an implementation for the Puppet ecosystem. It has support for installing Puppet modules from the Puppet Forge as well as Github, and provides any number of other features like version locking of installed modules.

Simply, we can have a virtual box and vagrant setup and we can write shell scripts/batch files to install softwares based on the development environment.

If we use puppet and librarian puppet along with with virtual box we only need to concentrate on setting up vagrant, puppet, librarian puppet rest will be taken care of by puppet module itself.

Virtual Box Setup

Download virtual box from here [https://www.virtualbox.org/wiki/Downloads] for the environment you are working on. Once downloaded follow the instructions to install

If we want to work with vagrant we must have a virtual box.

Vagrant Setup

With virtual box installed we are ready to go ahead with vagrant installation. 
Download vagrant from here [https://www.vagrantup.com/downloads.html]. Once downloaded follow the instructions to install.

Puppet Setup

You can write a environment specific shell script/batch file to install puppet manually or shell script could be executed from Vargrant file itself while executing the command  $ vagrant up For simplicity lets assume we will manually execute the shell script/batch file to install puppet.


Librarian Puppet Setup

You can write a environment specific shell script/batch file to install librarian puppet manually or shell script could be executed from Vargrant file itself while executing the command  $ vagrant up For simplicity lets assume we will manually execute the shell script/batch file to install librarian puppet.

Now we have a virual box, vagrant, puppet, librarian puppet installed.


Lets create our First Instance 

$ mkdir my_first_instance
$ cd my_first_instance
$ vagrant init precise32  http://files.vagrantup.com/precise32.box

once successfully executed it will create Vagrantfile in the empty directory created above with some default settings. Now execute 

$vagrant up

Wait for few minutes, this will start the virtual box [ubuntu machine]. Now using ssh we can interact with the virtual box

$vagrant ssh 

[
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)

 * Documentation:  https://help.ubuntu.com/
New release '14.04.3 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Fri Sep 14 06:22:31 2012 from 10.0.2.2
vagrant@precise32:~$  ]

$vagrant ssh exit  - command to exit virtual box

$vagrant suspend -  command to stop virtual machine

$vagrant destroy - command to remove the setup

Development Environment Setup

At this point we have a virtual box up and running, vagrant setup, puppet and librarian puppet installed.

$ cd my_first_instance
$ mkdir puppet
$ cd puppet
$ mkdir  manifests
$ mkdir modules
$ touch Puppetfile
$ cd manifests
$ touch default.pp

the Puppetfile will have the modules required for your development and default.pp file will have the dependencies.

Sample Puppetfile
[forge "http://forge.puppetlabs.com"

mod "puppetlabs/stdlib", "3.2.1"
mod "puppetlabs/apt", "1.5.0"
mod "puppetlabs/mysql", "2.2.3"
#mod "puppetlabs/rabbitmq", "5.0.0"
mod "thomasvandoren/redis", "0.10.0"
mod "jbussdieker/memcached"
mod "puppetlabs/git"
mod "tylerwalts/jdk_oracle"
mod "gini/gradle"]

Puppet modules could be found executing the command $ sudo puppet module search {mysql}
In default.pp file under manifests define the dependencies like -

# --- MySQL --- #

class { '::mysql::server':
 root_password => 'foo'
}

Once defined go to puppet directory under parent directory [$ cd my_first_instance/puppet] and execute 
$ sudo librarian-puppet install - this will install modules under puppet directory
$ cd ..
$ vagrant reload --provision

Once provisioning has been successfully completed it will install the software module to virtual box. We can now login to vm and start using it.

Sample virtual box setup scripts are available here [https://github.com/badalb/vagrant-java]


Tuesday, 9 June 2015

Real Time Data Streaming with Epoch

Streams of data are becoming ubiquitous today – clickstreams, log streams, event streams, and more. Building a clickstream monitoring system, for example, where data is in the form of a continuous clickstream rather than discrete data sets, requires the use of continuous processing rather than ad-hoc, one-time queries.

In this blogpost we will explore how we can build a real-time monitoring system with Spring framework, Kafka, Storm, Redis, Node.Js and EpochJS ( https://fastly.github.io/epoch/ ).

We will have a producer producing the stream data to a Kafka topic and a consumer, Storm spout consuming the stream and storm bolts publishing those streams to redis. A simple node application subscribed to redis continuously push consumed stream to epoch using the open socket. Epoch creates a realtime view of the stream to the end user. So the architecture looks like -



Implementation code code be found here -

Spring-Kafka :- https://github.com/badalb/spring-kafka.git
Real Time Streaming :- https://github.com/badalb/epoch-realtime-data-stream.git 

Monday, 8 June 2015

External Project Dependency in Gradle

Lets assume that you are working in a multi-module and distributed project and projects are organised like the structure below -

root1
       |__ project _1
       |__ project _2

root2
        |__ project _X
        |__ project _Y


Now we want to add dependency of project_1 of root1 in project_Y of root2, If you achieve that easily with -

1. Add the snippet below in settings.gradle file of project_Y

include ":project_1"
project(":project_1").projectDir = file("<path_to_project_1>")

2. Add dependency of project_1 in build.gradle file of project_Y

compile project(":project_1")

Wednesday, 22 April 2015

Multiple Authentication Schemes in Spring Security

While developing server side applications using spring framework sometimes we encounter situations where need to support web based clients (typically developed in Backbone.js or Angular.js or JSP based multi form applications), Mobile clients (Android, IOS etc). The RESTfull services exposed may have third party clients as well.


If we have a consumer facing web interface typically accessed by web browsers where we need to maintain a user session we have to end up having a form based authentication mechanism. Third party clients for B2B service consumption we can have token based security in place and mobile users security could be supported by OAuth2. Lets see how we could implement all three types of security mechanisms in a web application using Spring Security.


Security Configuration files for REST and Form based security :-

@Configuration
@EnableWebSecurity

public class MultiHttpSecurityConfig {
   
   @Configuration
    @Order(1)                                                        
    public static class RestSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public RestAuthenticationEntryPoint restAuthenticationEntryPoint() {
    RestAuthenticationEntryPoint entryPoint = new RestAuthenticationEntryPoint();
    entryPoint.setRealmName("<your_realm_name>");
    return entryPoint;
    }

    @Bean
    public RestAuthenticationProvider restAuthenticationProvider() {
    RestAuthenticationProvider authProvider = new RestAuthenticationProvider();
    return authProvider;
    }

    @Bean
    public RestSecurityFilter restSecurityFilter() {

    RestSecurityFilter filter = null;
    try {
    filter = new RestSecurityFilter(authenticationManagerBean());
    } catch (Exception e) {
    e.printStackTrace();
    }

    return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http
    .antMatcher("/api/**")    
    .sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
    //.addFilterBefore(restSecurityFilter(), BasicAuthenticationFilter.class)
    .exceptionHandling()
    .authenticationEntryPoint(restAuthenticationEntryPoint()).and()
    .authorizeRequests()
    .antMatchers("/api/**")
    .authenticated().and().addFilterBefore(restSecurityFilter(), BasicAuthenticationFilter.class);
    

    }
    
    @Override
        protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
    authManagerBuilder.authenticationProvider(restAuthenticationProvider());
        }
    }

    @Configuration
    public static class FormSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    @Autowired
    private <custom_user_detail_service> customUserDetailsService;

    @Autowired
    CustomSecuritySuccessHandler customSecuritySuccessHandler;

    @Autowired
    CustomSecurityFailureHandler customSecurityFailureHandler;

    @Autowired
    private <password_encoder> passwordEncoder;
    
    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;

    
    @Override
    public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/resources/**");
    }

    protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.authorizeRequests()
    .antMatchers("/", "/login.html", "/app/**", "/assets/**", "/login","/failure","/register","/public/**", "/oauth/v1/**").permitAll().anyRequest().authenticated();
    http.formLogin().loginPage("/login").failureUrl("/")
    .successHandler(customSecuritySuccessHandler)
    .failureHandler(customSecurityFailureHandler).permitAll().and()

    .logout().logoutSuccessUrl("/login").permitAll().and()
                .rememberMe().and().exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
    
    
    return;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder)
    throws Exception {
    authManagerBuilder.userDetailsService(customUserDetailsService)
    .passwordEncoder(passwordEncoder);
    }
    
    }

}


OAuth2 Security Configuartion:-

@Configuration
public class GlobalAuthenticationConfig extends GlobalAuthenticationConfigurerAdapter {
    
@Autowired
private <custom_user_detail_service> oAuthUserDetailService;
@Autowired
private <password_encoder> commonPasswordEncoder;
      
    @Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(oAuthUserDetailService).passwordEncoder(commonPasswordEncoder);

}
}


@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter  {

@Autowired
DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}

@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);

}

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}

}

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter  {

private static final String HU_REST_RESOURCE_ID = "rest_api";

@Autowired
DataSource dataSource;

@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}


@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(HU_REST_RESOURCE_ID).stateless(false);
}

@Override
public void configure(HttpSecurity http) throws Exception {
http.
requestMatchers().antMatchers("/oauth/v1/**").and().
authorizeRequests().antMatchers("/oauth/v1/**").access("#oauth2.hasScope('read') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))");
}

}

With these configurations the incoming requests with URL pattern -
i. <context>/api/<version>/<some_request>  will be intercepted by RestSecurityConfig
ii. <context>/oauth/v1/<some_request> will be intercepted by OAuth2ResourceServerConfig
iii. All other requests will be intercepted by FormSecurityConfig

[Feel free to clone https://github.com/badalb/multi-security-config-web.git for detail code.]