Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Thursday, November 1, 2012

Fun at Java One in San Francisco and after

Beside having fun in San Francisco, I've presented at Java One with my more experienced colleague Mitesh Meswani! Recording of our BOF2737 "Developing Multitenant Applications with HK2 2.0 and EclipseLink" session is available here, see Media on right pane.

It was my first talk, and it went quite smoothly, due to small audience :) But the number (20) matched our expectations! HK2 is definitely not so known and sexy, as HTML5, NoSQL and Scala. But we've got something to go on.

Looks like there is no much demand for sharing run-time between tenants. However data isolation draws big interest, so including EclipseLink, was useful for the audience.

From other hand many people think of multi-tenancy in the same way - running single instance of the application for multiple clients. That's great! And everybody tries it differently.

It's worth to mention IBM's CON6465 - JVM Support for Multitenant Applications
talk about multi-tenant JVM. But beside IBM there is Waratek that does very good job in context of multi-tenancy in JVM too, but I have not seen their session, if there was any. And there might be more of course.

Other, not related to multi-tenancy but to CDI, CON7780 - Designing Java EE Applications in the Age of CDI, draw my interest. And caused to check that it's also possible to @Inject Logger with HK2! See my git commit#4dcad7b6e3 for example!. However, it brought rather difficult problem, multi-tenant logging. Well, there are much more problems like this, of course.

Also, I liked Venkat Subramaniam the most! And again, his CON3454 - Concurrency Without Pain in Pure Java makes me to highlight that HK2 also provides STM without pain in even more pure Java. In order to change any configuration element, one must start a configuration transaction that ensures restricted access to the configuration. The following demonstrates transaction invocation for mutating injected configuration object:

@Inject
HttpListener httpListener;

ConfigSupport.apply(new SingleCodeCode<HttpListener>() {
        public Object run(HttpListener wListener) {
                wListener.setPort("8080");
        }, httpListener);


Hopefully there will be something more, stay tuned!

Friday, August 10, 2012

Multi-Tenant Programming Model

This time, as promised, I'd like to describe one of a few possible models of developing Multi-Tenant applications, with HK2 and EclipseLink.

Disclaimer: HK2 and EclipseLink don't have to be used together. This model is not intended for any PaaS. And this post does not cover all aspects of developing multi-tenant applications. This model attempts to simplify programmer experience when developing multi-tenant application with single application instance per tenant approach.

Let me start with less familiar HK2 first. It is an implementation of the JSR 330: Dependency Injection standard for Java.  I won't repeat it's documentation, but highlight its configuration subsystem. HK2 offers support for software configuration in xml file. E.g. you can have pure class with few annotations:

@Configured
public interface HttpServer extends ConfigBeanProxy {
    @Attribute
    String getName();
    void setName(String name);
}

Then it is mapped to xml:
<http-server name="..." />

It is similar to JAXB, without explicit binding, or rather with binding by convention, and with restricted write access. Finally, with HK2, consumer may have configuration injected:

@Service
public class Foo {
    @Inject
    HttpServer httpServer;
}

See my previous post for how to start with HK2 support for xml configuration.

Recent version 2.2 of HK2 among other things, introduces @Proxiable annotation. Combined with custom @Scope-d annotation, and applied to configuration object, it allows to have once injected configuration be different at execution time depending on the state of the system. So configuration may be different for Alice and Bob, tenants of your application.

See Tenant Managed Scope Example for details on how to implement that @TenantScoped trick. And try it yourself, check out examples/ctm@hk2.java.net.

From other hand, hopefully better known, EclipseLink is implementation of Java persistence standard. Version 2.4 (Juno) brings better support for Multi-Tenancy. Beside Documentation and Examples I would like to recommend full-stack MySports example, provided by EclipseLink team also. Shortly, EclipseLink allows to impelement persistence with table per tenant or single table, using column discriminator and gives few architectural options:
  • Dedicated Persistence Unit - separate persistence-unit in persistence.xml, so application must request the correct PersistenceContext or PersistenceUnit for tenant.
  • Persistence Context per Tenant - single persistence unit definition in the persistence.xml and a shared persistence unit (EntityManagerFactory and cache).
  • Persistence Unit per Tenant - single persistence unit defined in the persistence.xml and different persistence contexts with their own caches are created per tenant.

And now, applying @TenantScoped @Proxiable @Scope from HK2 example above to one of the EclipseLink multi-tenant architecture, HK2 will substitute persistence context for tenenat at runtime, like this:

public class TenantEntityManagerFactory implements Factory<entitymanager> {
    @Inject
    private TenantManager manager;

    ...

    @TenantScoped
    public EntityManager provide() {

        String currentTenant = manager.getCurrentTenant();
        Map properties = new HashMap();
        properties.put(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT,
                 currentTenant);
        properties.put(PersistenceUnitProperties.SESSION_NAME, currentTenant);
        EntityManager em = Persistence.createEntityManagerFactory("multi-tenant-pu",
                 properties).createEntityManager();
        return em;
    }
}

So consuming code can have EntityManager provided once by HK2 dependency injection, and have it different depending on current tenant, thread safe! E.g.

public class Foo {
    @Inject
    EntityManager entityManager;

    public void testPersistence() {
        // assume tenantManager.setCurrentTenant() is called somewhere in stack

        entityManager.getTransaction().begin();
        Customer customer = new Customer();
        customer.setName("ACME");
        entityManager.persist(customer);
        entityManager.getTransaction().commit(); 
    }
}

See my eclipselink-hk2@github for working example. It also demonstrates  usage of Extensible Entities.

That's it. Let me know if you try this model.

Monday, February 27, 2012

Update for hello-world-hk2-sample

Take a look at Sahoo's hello-world-hk2-sample part I, updated for hk2 version 1.6.30.

I also extended it with support for Configuration, which is another very interesting part of HK2.

You can find sources at GitHub.

Important points to notice:

1) DomainXml as starting point for configuration. Mainly it is Populator, so with help of ConfigParser.parse it populates habitat with hk2 configuration beans habitants.

2) Named configuration beans:

Domain extends ... Named, so that it can be looked up by name, e.g.

@Inject(name="test")
Domain domain;
or
habitat.getComponent(Domain.class, "test2");
3) And Transactions support (modifiable configuration), for which it's necessary to override DomDocument.make() method to produce ConfigBean objects instead of Dom.

public class MyDocument extends DomDocument<configbean> {
    public MyDocument(final Habitat habitat) {
        super(habitat);
    }
    
    @Override
    public ConfigBean make(final Habitat habitat, XMLStreamReader xmlStreamReader,
            ConfigBean dom, ConfigModel configModel) {
        // by default, people get the translated view.
        return new ConfigBean(habitat,this, dom, configModel, xmlStreamReader);
    }

}

Then use it in DomainXml.run() method for ConfigParser:

parser.parse(res, new MyDocument(habitat));

That's all so far, but it may be updated for persisting configuration modifications.