2011년 5월 24일 화요일

XINS(XML Interface for Network Services) - Part 2

XINS goals
1. 분산 어플리케이션의 손쉬운 개발
2. 모니터와 조작이 쉽게
3. 테스트가 쉽게
4. Consistent
5. High quality
6. Stable

DOD(Definition-Oriented Development)
1. 코드보다는 명확한 정의에 초점
2. 정의는 의무적이다.
3. 정의가 주도한다.
4. 정의가 먼저, 그후에 코딩

XINS Sample Program : 사용자관리 Web Service
사용자관리 Web Service는 다음 API를 포함한다.
addUser새로운 사용자를 추가한다.
getUserList현재 등록된 사용자 리스트
modifyUser사용자 정보를 변경
deleteUser지정된 사용자를 리스트에서 삭제한다.



xins-project.xml
새로운 프로젝트 디렉토리(여기서는 UserAPI)을 만들고 xins-project.xml 파일을 작성한다.
<?xml version="1.0"?>
<!DOCTYPE project PUBLIC
"-//XINS//DTD XINS Project 1.4//EN"
"http://www.xins.org/dtd/xins-project_1_4.dtd">
<project name="UserManager" domain="com.naver.blog.inter999">
</project>



userManagerAPI 개발하기
1. xinx create-api 실행
QuestionAnswer
API name?UserManagerAPI
API description?User Management Web Service API
Want an implementation?y (for yes)
Want to define environments?y (for yes)
Function name?addUser
Function description?Add User


2. xins create-function
기존에 만든 API에 새로운 Function을 추가하기 위해서는 create-function 옵션을 사용한다.
QuestionAnswer
API name?UserManagerAPI
Function name?getUserList
Function description?get UserList


나머지 modifyUser, deleteUser Method도 create-function 옵션을 사용하여 등록해준다.
3. xins create-type
xins에서 지원하는 Predefined 된 Parameter Type은 아래에 나렬된 17가지 이다. 개발자는 아래에 나열된 17가지 타입을 이용하여 새로운 타입을 정의할 수 있다.
XINS intergrated types
type
Java representation
Example
_textjava.lang.Stringhello world
_booleanbooleantrue
_int8byte25
_int16short2004
_int32int15
_int64long654654132135544566
_float32float25.6
_float64double3.14159
_dateorg.xins.common.types.standard.Date.Value20040514
_timestamporg.xins.common.types.standard.Timestamp.Value20040514115930
_propertyorg.xins.common.collections.PropertyReaderupgrade%3Dtrue%26surname%3Dde%2BHaan
_listorg.xins.common.types.standard.List.Valueitem1%26item2%26item1
_setorg.xins.common.types.standard.Set.Valueitem3%26item1%26item2
_base64byte[]aGVsbG8=
_hexbyte[]546573746f
_urlStringhttp://www.google.com
_descriptororg.xins.common.service.Descriptordescriptor=group, random, target1, target2
descriptor.target1=service, http://127.0.0.1:8080/my-project/, 8000
descriptor.target2=service, http://192.168.0.1:8080/my-project/, 8000


사용자 정의에 사용되는 Parameter와 Type
userID_text
age_int8
name_text
phone_text
address_text


4. Function Parameter 지정
apis/UserManagerAPI/spec/addUser.fuc, deleteUser.fuc, getUserList.fnc, modifyUser.fuc에 Paramter 지정을 위하여 아래와 같이 수정한다.
addUser.fnc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE function PUBLIC "-//XINS//DTD Function 2.2//EN" "http://www.xins.org/dtd/function_2_2.dtd">
<function name="addUser" rcsversion="$Revision$" rcsdate="$Date$">
<description>Add User</description>
<input>
<data>
<contains>
<contained element="user" />
</contains>
<element name="user">
<description>A User</description>
<attribute name="userID" required="true" type="_text">
<description>User's UserID</description>
</attribute>
<attribute name="name" required="true" type="_text">
<description>User's Name.</description>
</attribute>
<attribute name="phone" required="false" type="_text">
<description>User's Phone.</description>
</attribute>
<attribute name="address" required="false" type="_text">
<description>User's Address</description>
</attribute>
<attribute name="age" required="false" type="_int8">
<description>An example of input for a int8 type with a minimum and maximum.</description>
</attribute>
</element>
</data>
</input>
<output>
</output>
</function>


<data> Tag에 user element을 선언하고 속성(attribution) 지정하면 User 객체가 생성되어 setter/getter 메서드로 각 속성에 접근할 수 마치 ValueObject 처럼 사용할 수 있게 된다. user element가 <input> Tag 안에서 생성 되었기 때문에 Request로 하나 이상의 user을 전달할 수 있다.
deleteUser.fnc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE function PUBLIC "-//XINS//DTD Function 2.2//EN" "http://www.xins.org/dtd/function_2_2.dtd">
<function name="deleteUser" rcsversion="$Revision$" rcsdate="$Date$">
<description>Delete User</description>
<input>
<param name="userID" required="true" type="_text">
<description>User's UserID</description>
</param>
</input>
<output>
</output>
</function>


파라미터로 userID을 선언한다. Request에 getUserID 메서드가 추가되게 된다.

getUserList.fnc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE function PUBLIC "-//XINS//DTD Function 2.2//EN" "http://www.xins.org/dtd/function_2_2.dtd">
<function name="getUserList" rcsversion="$Revision$" rcsdate="$Date$">
<description>get UserList</description>
<input>
</input>
<output>
<data>
<contains>
<contained element="user" />
</contains>
<element name="user">
<description>A User</description>
<attribute name="userID" required="true" type="_text">
<description>User's UserID</description>
</attribute>
<attribute name="name" required="true" type="_text">
<description>User's Name.</description>
</attribute>
<attribute name="phone" required="false" type="_text">
<description>User's Phone.</description>
</attribute>
<attribute name="address" required="false" type="_text">
<description>User's Address</description>
</attribute>
<attribute name="age" required="false" type="_int8">
<description>An example of input for a int8 type with a minimum and maximum.</description>
</attribute>
</element>
</data>
</output>
</function>


<output> tag안에 user element을 선언하면 Response 객체에 addUser 메서드가 생성되고 User 클래스가 생성된다 . 여기에 생성되는 User는 addUser.fnc에 의해서 생성된 User하고는 다른 객체이다.

modifyUser.fnc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE function PUBLIC "-//XINS//DTD Function 2.2//EN" "http://www.xins.org/dtd/function_2_2.dtd">
<function name="modifyUser" rcsversion="$Revision$" rcsdate="$Date$">
<description>Modify User</description>
<input>
<data>
<contains>
<contained element="user" />
</contains>
<element name="user">
<description>A User</description>
<attribute name="userID" required="true" type="_text">
<description>User's UserID</description>
</attribute>
<attribute name="name" required="true" type="_text">
<description>User's Name.</description>
</attribute>
<attribute name="phone" required="false" type="_text">
<description>User's Phone.</description>
</attribute>
<attribute name="address" required="false" type="_text">
<description>User's Address</description>
</attribute>
<attribute name="age" required="false" type="_int8">
<description>An example of input for a int8 type with a minimum and maximum.</description>
</attribute>
</element>
</data>
</input>
<output>
</output>
</function>



5. UserManagerAPI Generate
xins all-UserManagerAPI 실행
6. 사용자 정보 메모리 저장소 만들기
User 정보를 메모리리에 저장하는 클래스 Storage.java와 저장객체 UserVO.java을 생성한다.
UserVO.java
package com.naver.blog.inter999.UserManagerAPI.api.vo;
import java.io.Serializable;
public class UserVO implements Serializable {
private static final long serialVersionUID = 20090106L;
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
private String userID;
private int age;
private String name;
private String phone;
private String address;
}


Storage.java
package com.naver.blog.inter999.UserManagerAPI.api;
import java.util.Collection;
import java.util.HashMap;
import com.naver.blog.inter999.UserManagerAPI.api.vo.UserVO;
public class Storage {
private static HashMap<String, UserVO> repository = new HashMap<String, UserVO>();

public static void insert(UserVO user) {
repository.put(user.getUserID(), user);
}

public static UserVO select(String userID) {
return repository.get(userID);
}

public static void delete(String userID) {
repository.remove(userID);
}

public static Collection<UserVO> list() {
return repository.values();
}
}


7. 구현 클래스 작성
api/UserManagerAPI/impl에 생성된 addUserImpl.java, deleteUserImpl.java, getUserListImpl.java, modifyUserImpl.java 을 아래와 같이 수정한다.
addUserImpl.java
package com.naver.blog.inter999.UserManagerAPI.api;
import java.util.List;
import com.naver.blog.inter999.UserManagerAPI.api.addUser.Request.User;
import com.naver.blog.inter999.UserManagerAPI.api.vo.UserVO;
public final class addUserImpl extends addUser {
public addUserImpl(APIImpl api) {
super(api);
}
public Result call(Request request) throws Throwable {
SuccessfulResult result = new SuccessfulResult();
List<User> list = request.listUser();
for(User user : list) {
UserVO vo = new UserVO();
vo.setUserID(user.getUserID());
vo.setAge(user.getAge());
vo.setName(user.getName());
vo.setPhone(user.getPhone());
vo.setAddress(user.getAddress());
Storage.insert(vo);
}
return result;
}
}


addUser.fnc에서 <input> Tag에 user element을 작성하여서 request에 listUser 메서드가 추가 되어 있다.
Request에서 전달 받은 User 객체를 UserVO로 변환하고 Storage에 insert한다.
deleteUserImpl.java
package com.naver.blog.inter999.UserManagerAPI.api;
public final class deleteUserImpl extends deleteUser {
public deleteUserImpl(APIImpl api) {
super(api);
}
public Result call(Request request) throws Throwable {
SuccessfulResult result = new SuccessfulResult();
String userID = request.getUserID();
Storage.delete(userID);
return result;
}
}


Request객체에서 getUserID 메서드를 이용하여 클라이언트에서 전달 받은 userID을 이용하여 Storage로 부터 해당 UserID객체를 삭제한다.

getUserListImpl.java
public final class getUserListImpl extends getUserList {
public getUserListImpl(APIImpl api) {
super(api);
}
public Result call(Request request) throws Throwable {
SuccessfulResult result = new SuccessfulResult();
Collection<UserVO> list = Storage.list();
for(UserVO vo : list) {
User user = new User();
user.setUserID(vo.getUserID());
user.setName(vo.getName());
user.setAge((byte)vo.getAge());
user.setAddress(vo.getAddress());
user.setPhone(vo.getPhone());
result.addUser(user);
}
return result;
}
}


Storate에서 모든 UserVO을 가져와서 User객체로 변환한 후 Result 객체에 추가한다.
modifyUserImpl.java
package com.naver.blog.inter999.UserManagerAPI.api;
public final class modifyUserImpl extends modifyUser {
public modifyUserImpl(APIImpl api) {
super(api);
}
public Result call(Request request) throws Throwable {
SuccessfulResult result = new SuccessfulResult();
// TODO 해보세요~~
return result;
}
}


사용자 정보 수정이지만 Request로 부터 user을 꺼내온 후 이를 UserVO변경하고 Storage에 insert 하면 된다.

8. Server Side Deployment
- 구현 클래스가 포함된 모듈을 배포하기 위해서 xins all-UserManagerAPI 명령어를 다시 한번 실행한다.
- WAS(여기서는 Tomcat)의 webapp에 build/webapps/UserManagerAPI/UserManagerAPI.war 파일을 복사해 넣고 WAS을 구동한다.

9. 클라이언트 만들기
UserManagerAPITestCase.java
package com.naver.blog.inter999;
import java.util.List;
import org.junit.Test;
import org.xins.common.service.TargetDescriptor;
import com.naver.blog.inter999.UserManagerAPI.capi.CAPI;
import com.naver.blog.inter999.UserManagerAPI.capi.addUserRequest;
import com.naver.blog.inter999.UserManagerAPI.capi.getUserListRequest;
import com.naver.blog.inter999.UserManagerAPI.capi.getUserListResult;
import com.naver.blog.inter999.UserManagerAPI.capi.addUserRequest.User;
public class UserManagerAPITestCase {
@Test
public void addUser() throws Exception {
TargetDescriptor descriptor = new TargetDescriptor(
"http://192.168.13.76:8080/UserManagerAPI", 20000);
CAPI project = new CAPI(descriptor);
addUserRequest request = new addUserRequest();
User user = new User();
user.setUserID(System.currentTimeMillis() + "");
user.setName("YunChang.Lee");
user.setAge((byte) 20);
user.setPhone("02-347x-55xx");
user.setAddress("서울특별시 강남구 역삼동...");
request.addUser(user);
project.calladdUser(request);
}
@Test
public void getList() throws Exception {
TargetDescriptor descriptor = new TargetDescriptor(
"http://192.168.13.76:8080/UserManagerAPI", 20000);
CAPI project = new CAPI(descriptor);
getUserListResult result = project
.callgetUserList(new getUserListRequest());
List<com.naver.blog.inter999.UserManagerAPI.capi.getUserListResult.User> list = result
.listUser();
for (com.naver.blog.inter999.UserManagerAPI.capi.getUserListResult.User usr : list) {
System.out.println(usr.getUserID());
System.out.println(usr.getName());
System.out.println(usr.getPhone());
System.out.println(usr.getAge());
System.out.println(usr.getAddress());
}
}
}


TargetDescriptor에 UserManagerAPI가 서비스 되고 있는 URL과 호출 타임 아웃시간(20000)을 지정한다.
CAPI(클라이언트 API) 객체를 생성하고 addUser API을 호출에 사용할 Reqest(addUserRequest)을 생성한후 calladdUser 메서드의 파라미터로 전달 한다. getList 테스트 메서드로 구현 방식은 유사하다.

10. 실행완료 로그
1231205784335
YunChang.Lee
02-347x-55xx
20
서울특별시 강남구 역삼동...
1231205477941
YunChang.Lee
02-347x-55xx
20
서울특별시 강남구 역삼동...

댓글 없음:

댓글 쓰기

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...