Changing source code at run-time with Service Locator pattern - The Koch Family
The Koch Family The Koch Family

Latest news

جاري التحميل ...

Changing source code at run-time with Service Locator pattern

I have a service to get some data but the result can be different basing on where the implementation is. Technically, I have two or more concrete implementation of an interface and I am able to switch using these concrete classes at run-time. That means I have a place to configure it without re-deploying the application. In order to overcome this issue, I use Service Locator design pattern and here I only care about two advantages below:
  • Encapsulating the specific implementation, we just declare the name and don't care about the implementation of the service.
  • Changing the implementation at run-time.



    Client: an object that invokes the services via Service Locator
    Business services: services that is used by Client.


    Once again, I used the JFS Helloworld example from previous post for this example.

    1. Create a service interface "CountryService" and two concrete classes "CountryService1" and "CountryService2" (Business services)

    package vn.nvanhuong.servicelocator.service;

    import java.util.List;

    public interface CountryService{
    public List<String> getCountries();
    }

    The first concrete service:
    package vn.nvanhuong.servicelocator.service.impl;

    import java.util.ArrayList;
    import java.util.List;

    import vn.nvanhuong.servicelocator.service.CountryService;

    public class CountryService1 implements CountryService{

    public List<String> getCountries() {
    List<String> result = new ArrayList<String>();
    result.add("Vietname");
    result.add("Switzerland");
    result.add("Japan");
    return result;
    }

    }

    The second concrete service:
    package vn.nvanhuong.servicelocator.service.impl;

    import java.util.ArrayList;
    import java.util.List;

    import vn.nvanhuong.servicelocator.service.CountryService;

    public class CountryService2 implements CountryService{

    public List<String> getCountries() {
    List<String> result = new ArrayList<String>();
    result.add("Vietname");
    result.add("America");
    result.add("China");
    return result;
    }

    }

    2. Create class "InitialContext" that is used for looking up and creating classes basing on the provided names
    package vn.nvanhuong.servicelocator;

    import java.lang.reflect.Constructor;

    public class IntitialContext {

    public Object lookup(String serviceName){

    if(serviceName != null){
    try {
    Class<?> clazz = Class.forName(serviceName);
    Constructor<?> ctor = clazz.getConstructor();
    Object object = ctor.newInstance();
    return object;
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    return null;
    }

    }


    3. Create class "ServiceLocator", I used Singleton to cache the object.
    package vn.nvanhuong.servicelocator;

    public class ServiceLocator {
    private static ServiceLocator instance;

    private ServiceLocator(){}

    public static synchronized ServiceLocator getInstance(){
    if(instance == null){
    return new ServiceLocator();
    }
    return instance;
    }

    public Object getService(String serviceName) {
    IntitialContext initialContext = new IntitialContext();
    return initialContext.lookup(serviceName);
    }

    }

    4. Create a resource file "services.properties" in order to configure the changing implementation at run-time. :)
    country = vn.nvanhuong.servicelocator.service.impl.CountryService1
    language = vn.nvanhuong.servicelocator.service.impl.LanguageService1

    5. Calling SeviceLocator in Managed bean (Client)
    package vn.nvanhuong.servicelocator.bean;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    import java.util.Properties;

    import javax.faces.bean.ManagedBean;

    import vn.nvanhuong.servicelocator.ServiceLocator;
    import vn.nvanhuong.servicelocator.service.CountryService;

    @ManagedBean(name = "helloBean")
    public class HelloBean {
    private List<String> countries;

    public HelloBean() throws IOException {
    Properties prop = new Properties();
    InputStream input = null;

    String filename = "services.properties";
    input = HelloBean.class.getClassLoader().getResourceAsStream(filename);

    prop.load(input);
    CountryService countryService = (CountryService) ServiceLocator.getInstance()
    .getService(prop.getProperty("country"));
    this.countries = countryService.getCountries();

    }

    public List<String> getCountries() {
    return countries;
    }

    public void setCountries(List<String> countries) {
    this.countries = countries;
    }

    }
    6. GUI code: index.xhtml
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
    <title>Service Locator</title>
    </h:head>
    <h:body>
    <h3>Lis of countries:</h3>
    <h:dataTable value="#{helloBean.countries}" var="country">
    <h:column>
    <h:outputText value="#{country}" />
    </h:column>
    </h:dataTable>

    </h:body>
    </html>

    7. Test (on Tomcat v7.0)

    http://localhost:8080/service_locator/

    Use the "CountryService1" by changing in "services.properties", don't need to restart the server.

    country = vn.nvanhuong.servicelocator.service.impl.CountryService1




    Use the "CountryService2" by changing in "services.properties", don't need to restart the server.

    country = vn.nvanhuong.servicelocator.service.impl.CountryService2

    Here we also can add more concrete classes of CountryService and just declare in file "services.properties" for using. For this reason, I use Java Reflection to create the objects basing on the provided names in general way otherwise we have to change the InitialContext whenever we want to add new concrete class of "CountryService".

    Note:
    There might have several ways to implement this pattern but the idea is general so that my example is only a case. We also can improve my implementation by using caching technique, see reference [3].


    Reference:

    Comments



    If you like the content of our blog, we hope to stay in constant communication, just enter your email to subscribe to the blog's express mail to receive new blog updates, and you can send a message by clicking on the button next ...

    إتصل بنا

    About the site

    author The Koch Family <<  Welcome! I'm so glad that you stopped by Your Modern Family blog. Together, we will talk about raising kids, organizing the home and saving money! and Tips & tricks and more…

    < Learn more ←

    Blog stats

    Sparkline 2513183

    All Copyrights Reserved

    The Koch Family

    2020