Simplifying enterprise applications with durable stm

One of the things I’m currently playing with is creating a durable Stm, functionality is going to be integrated in the main Stm implementation of the Multiverse STM. I’m doing a poc to figure out what kind of interfaces and changes the Multiverse STM is going to need.

The idea is that persistence for a lot of enterprisy applications I have seen just didn’t feel very comfortable:

  1. dealing with proxies; so problematic self calls in services and identity problems on entities
  2. dealing with or mapping
  3. dealing with setting up the db and creating ddl
  4. not being able to do dependency injection on entities
  5. objects getting an id once they are going to commit and not before

It takes up too much time and since STM already manages states of your objects, adding a storage-engine
behind is not that strange. To give you an idea how simple it could be, lets create a small Bank example:

@TransactionalObject
class Customer{
   	private final String id;

	public Customer(String id){
		return id;
	}

	public String getId(){
		return name;
	}
}

@TransactionalObject
class Account{
	private final Customer customer;
	private int balance;

	public Account(Customer customer){
		this.customer = customer;
	}

	public Customer getCustomer(){
		return customer;
	}

	public int getBalance(){
		return balance;
	}

	public void setBalance(int newBalance){
		if(newBalance<0){
			throw new NotEnoughMoneyException();
		}	

		this.balance = newBalance;
	}
}

@TransactionalObject
class Bank{
	private final TransactionalMap customers = 
		new TransactionalHashMap();
	private final TransactionalMap accounts = 
		new TransactionalHashMap();

	public Account find(String id){
		Account account = accounts.get(id);
		if(account == null){
			throw new AccountNotFoundException();
		}
		return account;
	}

	public void transfer(String fromId, String toId, int amount){
		if(amount<0){
			throw new IllegalArgumentException();
		}

		Account from = find(fromId);
		Account to = find(fromId);
		to.setBalance(to.getBalance()+amount);
		from.setBalance(from.getBalance()-amount);
	}

	public Customer createCustomer(){
		Customer customer = new Customer();
		customers.put(customer.getId(),customer);
		return customer;
	}

	public Accoount createAccount(Customer customer){
		Account found = accounts.get(customer.getId());
		if(found!=null){
			throw new AccountAlreadyExists();
		}
		Account newAccount = new Account(customer);
		accounts.put(customer.getId(), newAccount);
		return newAccount;
	}
}

And you could wire it up in Spring like this:

<bean id="bank" class="DurableTransactionalObjectFactoryBean">
         <property name="id" value="bank">
         <property name="class" value="Bank">
</bean>

And use this bean in your controllers for example. The DurableTransactionalObjectFactory will create or load a durable transactional object with the given id from disk.

As you can see there is:

  1. no or-mapping needed
  2. no dao’s needed
  3. no fuss with transaction configuration
  4. no need for rolling back state on objects manually, check the tranfer function where the setBalance on the from could thrown a NotEnoughMoneyException and normally could leave the to account in an illegal state

All operations on the bank are executed in full ACID nature.

I hope I’m able to add a experimental storage engine to Multiverse 0.6 (planned in 3 months) so I can learn more about what I’m going to need and what the exact semantics need to be for durable/non-durable objects and about their lifecycles.

About these ads

10 Responses to Simplifying enterprise applications with durable stm

  1. Alex Cruise says:

    Peer, I’ve been following your involvement in Akka with interest, and this post struck a chord with me. Have you read the JVSTM thesis? One of his most interesting contributions is a declarative language for describing invariants and relationships between managed entities.

    I do think that getting intimately involved in the state space of trees of domain entities is a good direction for STMs, but there need to be ways to hide the plumbing. :)

    • pveentjer says:

      Hi Alex,

      thanks for posting. I have read the thesis some time ago, it seems to me that the versioned boxes are the same thing as ‘managed references’. This essentially is the approach the Akka project currently is using. But I can do a lot more cool stuff in Java (on the bytecode level or using object granularity for example) that it is likely to outperform a managed reference approach that isn’t using instrumentation.

      I haven’t looked at the thesis in more depth caused by lack of time (or lack of priority).

  2. rossputin says:

    This looks so promising! Pretty much the saviour of enterprise devs everywhere, good luck with it, can’t wait for the prototype.

    • pveentjer says:

      Hi Ross,

      I hope I can include some experimental support right after the 0.5 release since I already got a basic storage mechanism up and running. So hooking it up to the manual instrumented AlphaRef (used in Akka) would be no problem. It won’t be fast or protected against system failure, but it nice for experimentation purposes.

      • rossputin says:

        Hi Peer.

        More than happy to provide you with feedback / testing on anything you release in prototype form. You can get my details of the Akka list probably.

        Cheers

        — Ross

  3. Lucky says:

    How could I use Multiverse with Spring. I tried instrumentation mode in my Spring application ie;providing javagent in runtime. But it failed.

    • pveentjer says:

      He Lucky,

      what is the exception you get? And you can exclude packages from being instrumented.

      PS: For the 0.7 release (which is in development for a long time), I have decided to drop the instrumentation. It will be added in the near future again, but the focus atm is on transactional references. So you get something like:

      class Person{
      IntRef ageRef = newIntRef(10);
      }

      • Lucky says:

        org.multiverse.javaagent.MultiverseClassFileTransformer handleThrowable
        SEVERE: Failed while instrumenting class ‘com/xyz/myApp/bpo/StudentService$$EnhancerByCGLIB$$387853e1′. It is not possible to abort the Javaagent instrumentation process, so the JVM is going to continue, but since this class is not instrumented, it is not transactional so all bets are off.
        java.lang.RuntimeException: java.lang.ClassNotFoundException: org.springframework.aop.framework.AopConfigException
        at org.multiverse.repackaged.org.objectweb.asm.ClassWriter.getCommonSuperClass(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.ClassWriter.a(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.Frame.a(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.Frame.a(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.MethodWriter.visitMaxs(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.tree.MethodNode.accept(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.tree.MethodNode.accept(Unknown Source)
        at org.multiverse.repackaged.org.objectweb.asm.tree.ClassNode.accept(Unknown Source)
        at org.multiverse.instrumentation.asm.AsmUtils.toBytecode(AsmUtils.java:528)
        at org.multiverse.instrumentation.PreventReinstrumentationInstrumentationPhase.doInstrument(PreventReinstrumentationInstrumentationPhase.java:73)
        at org.multiverse.instrumentation.AbstractInstrumentationPhase.instrument(AbstractInstrumentationPhase.java:32)
        at org.multiverse.instrumentation.StandardInstrumentor.process(StandardInstrumentor.java:136)
        at org.multiverse.javaagent.MultiverseClassFileTransformer.transform(MultiverseClassFileTransformer.java:41)
        at sun.instrument.TransformerManager.transform(TransformerManager.java:169)
        at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:365)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:384)
        at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:219)
        at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
        at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
        at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:200)
        at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:112)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:476)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:404)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1407)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:512)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:557)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:842)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:416)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:443)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:459)
        at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:340)
        at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:307)
        at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:127)
        at javax.servlet.GenericServlet.init(GenericServlet.java:212)
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4149)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4458)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
        at org.apache.catalina.core.StandardHost.start(StandardHost.java:722)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
        at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
        at org.apache.catalina.core.StandardService.start(StandardService.java:516)
        at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:583)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)

        org.multiverse.javaagent.JavaAgentProblemMonitor$LoggingDaemon run
        SEVERE: STM integrity compromised, instrumentation problems encountered. Partial instrumented classes could give unexpected results. Check the logging for the instrumentation exception(s).
        List of problem classes: (10 max)
        org/springframework/web/servlet/FrameworkServlet

        This is the exception I got when using javaagent..I could successfully able to use multiverse transaction template. But I prefer using annotations because I wont like to change my code developed on SpringFramework.

      • pveentjer says:

        Hi Lucky,

        it appears that it failed during the instrumentation of the org/springframework/web/servlet/FrameworkServlet. Since this class doesn’t contain any Multiverse stuff, there is no issue. Even though an exception is thrown, the Java agent just skips the class file transformers that causes the problem. So I don’t think that will be causing problems.

        Which version are you using? The 0.6.1 contains a whole bunch of automatically excluded projects, and one of them is Spring.

        [edit]
        I see that the instrumentation fails on ‘Failed while instrumenting class ‘com/xyz/myApp/bpo/StudentService$$EnhancerByCGLIB$$387853e1′ which already is a generated proxy. This could be more complicated, you can contact me on alarmnummer at gmail.com and lets see if we can solve the problem.

  4. snnn says:

    Has it been released? (durable stm)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: