Jacn Scripting Manual

Last changed on July 2, 2006 by Bing Ran (bran@icer.com.cn)

Requirement and Dependencies

Jacn has been tested with

The build process will use jarjar to embed ASM into the distribution, to avoid potential version conflict.

To run the test cases you'll also need (already in the lib directory of the source tree):

Build and Deployment

Getting Started

You can start by study the following little applicationm, which is a complete Spring/Jacn application, all in a single compilation unit. The configuration part happens in the inner Jacn_foo class. This class is loaded by the JacnApplicationContext to extract the meta-information about constructing the managed beans ( the fields of the configuration class).

ConvertUtil.jacn2Xml() is used to quickly dump a Jacn file to XML format for viewing and debugging.

package bran.jacn.test;

import bran.spring.jacn.AbstractJacnConfigFile;
import bran.spring.jacn.ConvertUtil;
import bran.spring.jacn.JacnApplicationContext;

public class SimpleFlatJacnApp {
	private static final String HELLO = "hello";

	public static void main(String[] args) throws Exception {
		System.out.println(ConvertUtil.jacn2Xml(Jacn_foo.class));
		JacnApplicationContext ctx = new JacnApplicationContext

(Jacn_foo.class);
		Foo foo = (Foo) ctx.getBean("foo");
		if(HELLO.equals(foo.getBar().getMsg())) {
			System.out.println("good");
		}
		else {
			System.out.println("bad");
		}
	}
	
	static class Foo {
		Bar bar;
		public Bar getBar() {return 

bar;}
		public void setBar(Bar bar) {this.bar = bar;}
	}

	static class Bar {
		String msg;
		private Bar(String msg) {this.msg = msg;}
		public String getMsg() {return msg;}
	}

	/**
	 * the configuration file 
	 */
	static class Jacn_foo extends 

AbstractJacnConfigFile{
		static Foo foo;
		static Bar bar;
		public void wire() throws 

Exception {
			bar = new Bar(HELLO);
			foo.setBar(bar);
		}
	}
}

Play with it and get a good feel of the natural way of configuring DI.

There is another very useful tool in the ConvertUtil.java. By calling the xml2JacnClass() in the utility, as in

File f = new File("/path/myContext.xml");
String ss = ConvertUtil.xml2JacnClass(f);
System.out.println(ss);

you'll realize that you immediately have got an almost valid Jacn configuration file! For heavily nested configurations you won't get everyting done for you automatically, but the skeleton code will get you started very quickly.

If you want to migrate a bunch of Spring XMLs, this is the tool to use.

Jacn Files

Here is a complete jacn configuration file.

package bran.jacn.test;
import bran.spring.jacn.AbstractJacnConfigFile;

public class ApplicationContext_foo extends 

AbstractJacnConfigFile{
	static Foo foo;
	Foo foo1;
	Bar bar;
	public void wire() throws Exception {
		foo.setBar(bar);
		foo.setNum(1);
		foo.setCls(Foo.class);
	}
}

The principles are:

Deploying Jacn with Spring

Using Jacn with Spring is pretty much a drop-in replacement of the XML configurations. There are two runtime environment that Jacn can be used with Spring: in standalone Java applications and in web applications.

Use Jacn in Standalone Java Applications

The above example shows how to use Jacn in a standalone application.

Use Jacn in Web Applications

TODO:

Compare Jacn and Classical Spring XML Side-by-side

The following table shows the capability of Jacn:

Topic XML Jacn
a simple singleton bean
the static modifier is used to indicate
the bean is a singleton
<beans>
   <bean id="foo" class="Foo" />
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
  }
}
prototype bean
declare none static fields
<beans>
  <bean id="foo" class="Foo" singleton="false"/>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  Foo foo; // instance field -> "prototype" bean 
  public void wire() throws Exception {
  }
}
lazy init
call lazyInit() method
<beans>
  <bean id="foo" class="Foo" lazy-init="true"/>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
    lazyInit(foo);
  }
}
property
call the type-safe setters directly
<beans>
  <bean id="foo" class="Foo">
    <property name="bar">
      <ref bean="bar"/>
    </property>
  </bean> 
  <bean id="bar" class="Bar"/>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  static Bar bar; 
  public void wire() throws Exception {
    foo.setBar(bar);
  }
}
init method
make a call to the method directly
<beans>
  <bean id="foo" class="Foo" init-method="init" />
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
    foo.init();
  }
}
property place holder
invoke the loadPlaceholderProperties()
<beans>
   <bean id="propertyConfigurer" 
   class="org.springframework...PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:mail.properties</value>
                <value>classpath:database.properties</value>
            </list>
        </property>
    </bean>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  public void wire() throws Exception {
    loadPlaceholderProperties( 
      new String[]{
        "classpath:database.properties", 
        "classpath:mail.properties"});
  }
}
autowire
invoke autoWireByName() or autoWireByType()
<beans>
   <bean id="foo" class="Foo" autowire="byName"/>
   <bean id="foo2" class="Foo" autowire="byType"/>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo, foo2;
  public void wire() throws Exception {
    autoWireByName(foo);
    autoWireByType(foo2);
  }
}
use array
new MyObject[]{...}
<beans>
  <bean id="foo" class="Foo" >
    <property name="bars">
      <list>
        <value>hello</value>
        <ref bean="b1"/>
      </list>
    </property>
  </bean>  
  <bean id="b1" class="Bar" />
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  static Bar b1;
  public void wire() throws Exception {
    foo.setBars(new Object[]{"hello", b1});
  }
}
use List
  • create a List and set it on the target
  • use a magic casting on an array
<beans>
  <bean id="foo" class="Foo" >
    <property name="list">
      <list>
        <value>hello</value>
        <ref bean="b1"/>
      </list>
    </property>
  </bean>  
  <bean id="b1" class="Bar" />
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  static Bar b1;
  public void wire() throws Exception {
    foo.setList(Arrays.asList(new Object[]

{"hello", b1}));

    // or
    List l = new ArrayList(); {
        l.add("hello");
        l.add(b1);
    } // I use curlies to pretty format the code
    foo.setList(l);

    // or
    Object l = new Object[]{"hello", b1};
    foo.setList((List)l); // magic casting
  }
}
use Map
create a Map and set it on the target
<beans>
  <bean id="foo" class="Foo" >
    <property name="map">
      <map>
        <entry key="config-map">
          <value>MyConfigMap</value>
        </entry>
        <entry key="MailAccount">
          <value>PopMailAccount</value>
        </entry>    
      </map>	
    </property>
  </bean>  
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
    Map map = new Hashmap(); {
      map.put("config-map", "MyConfigMap");
      map.put("MailAccount", "PopMailAccount");
    }
    foo.setMap(map);
  }
}
use Properties
create a Properties and set it on the target
<beans>
  <bean id="foo" class="Foo" >
    <property name="props">
       <property name="transactionAttributes">
         <props>
           <prop key="*">PROPAGATION_REQUIRED</prop>
         </props>
       </property>
    </property>
  </bean>  
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
    Properties p = new Proerpties(); {
      p.put("*", "PROPAGATION_REQUIRED");
    }	
    foo.setProps(p);
  }
}
reference external beans defined in XML
Jacn and XML can co-exisit in an application.
use refBean() to reference external beans
<beans>
  <bean id="foo" class="Foo" >
    <property name="bar">
      <ref bean="bar"/>
    </property>
  </bean>  
</beans> 

<beans>
  <bean id="bar" class="Bar" />
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
    foo.setBar((Bar)refBean("bar"));
  }
}
<beans>
  <bean id="bar" class="Bar" />
</beans>
reference external beans defined in another Jacn file
just reference it as you would in Java
<beans>
  <bean id="foo" class="Foo" />
    <property name="bar">
      <ref bean="bar"/>
    </property>
  </bean>  
</beans> 

<beans>
  <bean id="bar" class="Bar" />
</beans>
class Jacnfig2 extends AbstractJacnConfigFile {
  static Foo foo; 
  public void wire() throws Exception {
    foo.setBar(Jacnfig.bar);
  }
}

class Jacnfig extends AbstractJacnConfigFile {
  static Bar bar; 
  public void wire() throws Exception {
  }
}
enable transactions on service objects
enableTx(...) will do the trick
<beans>
  <bean id="userManager" 
  class="org...TransactionProxyFactoryBean">
    <property name="transactionManager">
      <ref local="transactionManager"/>
    </property>
    <property name="target">
      <ref local="userManagerTarget"/>
    </property>
    <property name="transactionAttributes">
      <props>
        <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
        <prop key="*">PROPAGATION_REQUIRED</prop>
      </props>
    </property>
    <property name="proxyInterfaces">
      <value>IUserManager</value>
    </property>
    <property name="preInterceptors">
      <list>
        <ref local="preInterceptor"/>
      </list>
    </property>
    <property name="postInterceptors">
      <list>
        <ref local="postInterceptor"/>
      </list>
    </property>
  </bean>

  <bean id="userManagerTarget" class="UserManagerImpl">
    <property name="userDao">
      <ref bean="userDao"/>
    </property>
  </bean>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static UserManagerImp userManager; 
  //.. other dependents
  public void wire() throws Exception {
    Properties p = new Properties(); {
      p.put("get*", "PROPAGATION_REQUIRED,readOnly");
      p.put("*", "PROPAGATION_REQUIRED");
    }
    enableTx(userManager, transactionManager, p, 
      new Class[]{IUserManager.class}, 
      new Object[] {preInterceptor},
      new Object[] {postInterceptor});
    userManager.setUserDao(userDao);
  }
}
DI via contructors
just make a call to the constructors as in Java
<beans>
  <bean id="foo" class="Foo">
    <constructor-arg>
      <ref bean="bar" />
    </constructor-arg>
    <constructor-arg>
      <value>hello</value>
    </constructor-arg>
  </bean>
</beans>
class Jacnfig extends AbstractJacnConfigFile {
  static Foo foo;
  static Bar bar;
  public void wire() throws Exception {
    foo = new Foo(bar, "hello");
  }
}
facory methods
just make a call to the factory methods as in Java
<beans>
  <bean id="a" class="bran.jacn.test.AA">
    <property name="b2">
      <bean class="bran.jacn.test.BBFactory" 
      factory-method="newInstanceStatic">
        <constructor-arg>
          <value>hello1</value>
        </constructor-arg>
        <constructor-arg>
          <value>b2</value>
        </constructor-arg>
      </bean>
    </property>
  </bean>
</beans>
static class Jacn_factoryMethod extends AbstractJacnConfigFile {
  static AA a;
  static BBeanFactory bbf;
  public void wire() throws Exception {
    a.setB1(bbf.newInstance("hello", "b1")); 
    a.setB2(BBFactory.newInstanceStatic("hello1", "b2"));
  }
}
"init-method" and "destroy-method"
make a init/destroy function call in the init()/destroy() method in the config file
<beans>
  <bean id="des" 
  	class="bran.jacn.test.TestInitDestroyMethod$InitDestroyer" 
  	singleton="true" 
  	init-method="setup" 
  	destroy-method="clean" 
  />
</beans>
public static class 

Jacn_config extends AbstractJacnConfigFile {
	static InitDestroyer des;
		
	public void wire() throws Exception {
	}

	public void init() throws Exception {
		des.setup();
	}

	public void destroy() throws Exception {
		des.clean();
	}
}

TODO: