Then, let's make the component on the S2Container.
The specification of the component is as follows.
The function of an automatic numbering is offered.
When the numbering key is received as an argument, the value by which the number of counter is increased is returned.
When the numbering key which does not exist is specified, the exception is generated.
package examples.dicon.service;
public interface AutoNumber {
public int next(int numberKey) throws NumberKeyNotFoundRuntimeException;
}
The component of DAO becomes the following specifications.
The counter is updateed based on the numbering key.1 is returned when succeeding in the update, 0 is returned when a numbering key does not exist.(Statement.executeUpdate() of JDBC API is assumed.)
The value of the latest counter is returned based on the numbering key.
package examples.dicon.dao;
public interface AutoNumberDao {
public int inclement(int numberKey);
public int getCurrentNumber(int numberKey);
}
The AutoNumber component needs the reference to the AutoNumberDao component.
The constructor is handled this time though there is a method of using the constructor and property to acquire the reference.
package examples.dicon.service;
import examples.dicon.dao.AutoNumberDao;
public class AutoNumberImpl implements AutoNumber {
private AutoNumberDao autoNumberDao_;
public AutoNumberImpl(AutoNumberDao autoNumberDao) {
autoNumberDao_ = autoNumberDao;
}
public int next(int numberKey) throws NumberKeyNotFoundRuntimeException {
int updateCount = autoNumberDao_.inclement(numberKey);
if (updateCount == 1) {
return autoNumberDao_.getCurrentNumber(numberKey);
} else {
throw new NumberKeyNotFoundRuntimeException(numberKey);
}
}
}
Who will set AutoNumberDao which is constructor's argument?
When S2Container is used, S2Container is solved to such a dependency.
Then, let's test AutoNumberImpl.
The class which implements AutoNumberDao is necessary to test.
Mock is made so that you may not actually connect with the database.
S2ではモックを簡単に作成できるようにMockInterceptorが用意されています。
S2Container is made.
S2Container container = new S2ContainerImpl();
S2Container#register(Class componentClass) is used to register the component.
MockInterceptor mi = new MockInterceptor();
mi.setReturnValue("increment", new Integer(1));
mi.setReturnValue("getCurrentNumber", new Integer(1));
AutoNumberDao dao = (AutoNumberDao) mi.createMock(AutoNumberDao.class);
container.register(dao);
S2Container#getComponent(Class componentClass) is used to acquire the component.
Being necessary to know with S2Container at least is only this.
When the type is an interface, the dependency of the component is automatically solved by the type.
Even when property is used, the dependence is automatically similarly solved by the type.
The test case is as follows.
package test.examples.dicon.service;
import org.seasar.framework.aop.interceptors.MockInterceptor;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.impl.S2ContainerImpl;
import examples.dicon.dao.AutoNumberDao;
import examples.dicon.service.AutoNumber;
import examples.dicon.service.AutoNumberImpl;
import examples.dicon.service.NumberKeyNotFoundRuntimeException;
import junit.framework.TestCase;
public class AutoNumberImplTest extends TestCase {
public AutoNumberImplTest(String arg0) {
super(arg0);
}
public static void main(String[] args) {
junit.textui.TestRunner.run(AutoNumberImplTest.class);
}
public void testNext() {
S2Container container = new S2ContainerImpl();
container.register(AutoNumberImpl.class);
MockInterceptor mi = new MockInterceptor();
mi.setReturnValue("increment", new Integer(1));
mi.setReturnValue("getCurrentNumber", new Integer(1));
AutoNumberDao dao = (AutoNumberDao) mi.createMock(AutoNumberDao.class);
container.register(dao);
AutoNumber autoNumber = (AutoNumber) container.getComponent(AutoNumber.class);
assertEquals("1", 1, autoNumber.next(1));
}
public void testNextForNumberKeyNotFound() {
S2Container container = new S2ContainerImpl();
container.register(AutoNumberImpl.class);
MockInterceptor mi = new MockInterceptor();
mi.setReturnValue(new Integer(0));
AutoNumberDao dao = (AutoNumberDao) mi.createMock(AutoNumberDao.class);
container.register(dao);
AutoNumber autoNumber = (AutoNumber) container.getComponent(AutoNumber.class);
try {
autoNumber.next(-1);
fail("1");
} catch (NumberKeyNotFoundRuntimeException ex) {
assertEquals("2", -1, ex.getNumberKey());
}
}
}
In Dependency Injection, there are Interface Injection, Setter Injection, Constructor Injection, and Method Injection.
Method Injection is original of S2.S2 supports all types and the hybrids.
The value is written in the body of the arg tag.
Please refer to the manual of OGNL for details.
Two or more arg tags are defined when there are two or more arguments.
The component tag can be used for the child tag of the arg tag.
To make S2Container, passing XML is specified for the first argument of S2ContainerFactory.create().
It is necessary to include XML in CLASSPATH.
The component can be acquired even in the name and the type.
Two or more property tags are defined when there is two or more property.
The component tag can be used for the child tag of the property tag.
Other components can be referred to by specifying the component name for the body of the property tag as well as the arg tag.
The name of the method is specified by the name attribute of the initMethod tag.
The usage of the arg tag is similar to constructor's case.
Two or more initMethod tag can be defined.
In the timing of S2Container.destroy(), the call method can be specified with the destroyMethod tag.
If OGNL is used, the method can be called more easily.
The name of Interceptor is specified by the body of the aspect tag.
The method name is specified for pointcut attribute by the comma delimitation.
When the pointcut attribute is not specified, all the methods of the interface which the component inpliments.
The regular expression (reqex of JDK1.4) can be used for the method name.
examples.dicon.xml.AopClient
private static final String PATH = "examples/dicon/xml/Aop.dicon";
S2Container container = S2ContainerFactory.create(PATH); List list = (List) container.getComponent(List.class); list.size(); Date date = (Date) container.getComponent(Date.class); date.getTime(); date.hashCode(); date.toString();
The execution result is as follows.
BEGIN java.util.ArrayList#size()
END java.util.ArrayList#size() : 0
BEGIN java.util.Date#getTime()
END java.util.Date#getTime() : 0
BEGIN java.util.Date#hashCode()
BEGIN java.util.Date#getTime()
END java.util.Date#getTime() : 0
END java.util.Date#hashCode() : 0
BEGIN java.util.Date#getTime()
END java.util.Date#getTime() : 0
If all components are described in one file, the file expands immediately and management becomes difficult.
Therefore, the function to divide the definition of the component into the plural and the divided definition are provided for one and the function to bring is provided in S2Container.
The definition of each usecase is recommended to be divided.
<components>
<include path=""Definition of component of usecase 1".dicon"/>
<include path=""Definition of component of usecase 2".dicon"/>
</components>
The namespace can be specified by the namespace attribute of the components tag so that the name should not coflict between two or more component definitions.
It is possible to refer in the same component definition without the namespace.
When the component of other component definitions is referred, namespace dot(.) is applied to the head of the component name.
Because the namespace is different, foo.aaa and bar.aaa are recognized as a different component though give the same name.
It is recommended that the name of the definition file be made namespace.dicon as a custom.
The instance of the component managed with the container is managed with Singleton for default.
The component returned by S2Container.getComponent() is always a meaning of the same.
When you want the component newly made to be returned whenever S2Container.getComponent() is called, prototype is specified for instance attribute of the component tag.
As for the instance attribute, singleton becomes default.
When the dependency is injected into the component outside the container, S2Container.injectDependency(Object outerComponent,Class componentClass) and S2Container.injectDependency(Object outerComponent,String componentName) are used.
Outer is specified for instance attribute for the component made on the outside.
The lifecycle of the component can be managed with the container by using the initMethod tag and the destroyMethod tag.
The method of the specification with the initMethod tag when the container is begun is called.
The method of the specification with the destroyMethod tag when the container is ended is called.
Even if destroyMethod is specified, except when the instance attribute is singleton, S2Container is disregarded.
It is possible to control in detail by specifying the autoBinding attribute of the component tag.
autoBinding
description
auto
When constructor's argument is specified specifying, S2Container follows it.
When the default constructor who does not have the argument is defined, the component is made by handling the constructor.
The component is made by the constructor which the number of constructor's arguments is one or more and the type of all the arguments is an interface when there is no constructor of default.
When property is specified specifying, S2Container follows it.
明示的に指定されていないプロパティで型がインターフェースの場合は自動的にバインドします。