Doorgaan naar hoofdcontent

Data sharding and handling it in code

So I was at a project where data was somewhat sharded. We had a customer, which was part of a customer database (accessible by webservice calls), however, we had some additional customer data. This led to the (I think somewhat unfortunate) situation where the application reasoned from their own business object, and, when necessary, retrieved data from the relation system.

I feel this is flawed, ideally the entirety of the customer data should be invisible to the business logic of the application. Where I normally would like to have an anemic domain model, this data sharding makes it hard. Let's say you have relation R, and our extended data S. In our application, we want to reason about RS (or at least, not have to make that distinction). So maybe S has some additional attribute which may (or may not) be filled, depending on whether R is available or not. That sounds like a nice idea, but everywhere when R is necessary (and S is available), R needs to be retrieved.
And that is where the flaw is, since this doesn't help reusability. Our components are built using S, and it is quite possible that we retrieve R multiple times!

That is not desired. We can go two ways.
* we have a factory which always enriches our content upon the start, so we never have S, we always ensure we have RS
* We have a thicker model, in which S can retrieve R when necessary. This entails giving S the means to retrieve R.

To me, the last option feels the cleanest, however, both leave the issue of synchronisation. What happens when R is (implicitly) updated? This sounds like our entitymanager, however an entitymanager does so much more. Yet, we might do something with it.

I really should test this, but so far, it's just a Poc:
Usually, we have some sort of Factory for S objects, which contains the entitymanager and persists S.
However, what we can do is have that Factory also insert the soap client, so S can retrieve R if necessary. Moreover, we *can* use the entitymanager! (whoopee!).
If we register an entitylistener, and use some transient fields, we can have the cake and eat it:
@EntityListeners({CustomerDataPersister.class})
public class ApplicationCustomerData {

    private String customerKey;

    @Transient
    private Customer customer;

    @Transient
    private CustomerWebserviceClient webserviceClient;

    public Customer getCustomer() {
        if(customer == null) {
            customer = webserviceClient.retrieve(key);
        }
        return customer;
    }

    public boolean isEnhanced() {
        return customer!= null;
    }
}


public class CustomerDataPersister {
    // use CDI to inject the webserviceclient, see below
    @PrePersist // and others
    public void update(ApplicationCustomerData d)
        if ( d.isEnhanced() ) {
            webserviceClient.update(d.getCustomer());
        }
    }
}


Now we're talking! We can even do this all behind the scenes using more entitylisteners, say, one which inserts the webserviceclient through @postload annotations.

However, the big secret is injecting the webserviceclient in the first place. We need this in the listeners, but they need not be managed beans! Luckily for us, JPA 2.1 supports this (JPA 2.0 does not). Stackoverflow has this covered!
http://stackoverflow.com/questions/10765508/cdi-injection-in-entitylisteners

Now we all of a sudden have an S object which implicitly loads R when necessary. Our entire application is none the wiser, and all of a sudden a complex issue which would eat through our entire application is neatly tucked away!




Reacties

Populaire posts van deze blog

Spring's conditional annotation with properties

Spring has a nice @Conditional annotation, to have the option to have beans be available in the context depending a specific condition (Of course, this can also be realized by using @Configuration objects, but that's a different post). Ideally, we'd have the option to have a condition evaluate to true or false depending on a property. Sadly, Spring does not support that out of the box. Googling and looking around gives a partial solution, but the complete one here, so we won't forget: /** * Components annotated with ConditionalOnProperty will be registered in the spring context depending on the value of a * property defined in the propertiesBeanName properties Bean. */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { /** * The name of the property. If not found, it will evaluate to false. */ String value(); /** * if the p...

OSGI insights without sonar

So I was on a project without sonar. Oh my. Well, it was an OSGI project, so the problems couldn't be that bad, right? But how good were they (and what things were bad?) I found Stan4j , a code analysis tool for eclipse, which draws nice graphs and can handle osgi pretty well it seems. Now I can see that dependencies/bundle names aren't properly aligned (even though OSGI doesn't complain), etc.

JPA and transactions

So I was working with JPA and transactions. Consider the following: In bean 1, with implicit TX 1, managed entities are loaded/created,and returned in bean 2, with implicit TX 2, entities are modified in bean 3, with NO TX, bean 1 is called, and the results are passed to bean 2. and bean 4 is similar to bean 3, but with it's own transaction, TX3 What happens when bean 3 finishes: are the entities updated? What happens when bean 4 finishes, are the entities updated? The answer to this is simple; entities are managed through a persistance context. That context is tied to the transaction. So in bean 2, there is a difference. When called from bean 3, it runs in a different transaction then bean 1, and thus a different persistance context, and thus the entities are not managed 'by this transaction'.When called from bean 4, it all runs in the same transaction, TX3, and the results are persisted.