레이블이 serialization인 게시물을 표시합니다. 모든 게시물 표시
레이블이 serialization인 게시물을 표시합니다. 모든 게시물 표시

2013년 4월 3일 수요일

Protocol Buffers - Data serialization

이전 블로그에서 이전 함 (원본 글 2013/04/03 작성)

Android 상에서 Native library와 Application/Service를 개발 시
상호 Layer간 data를 전달하기 위한 방법을 찾다가 발견한 data serialization 방법 중 하나.
Protobuf은은은 기존 JSON, XML에 비해 별도 parser가 필요 없고 사용하고 상대적으로 쉽다는 것과
language별 API를 제공해 준다는 것,
language별로 serialized된 data의 inteoperability가  장점으로 보임

[Protocol Buffers]
  https://developers.google.com/protocol-buffers/

 What Are Protocol Buffers?

Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages – Java, C++, or Python.



[Quick Example]

 . https://developers.google.com/protocol-buffers/docs/overview)

Quick Example
You write a .proto file like this:
message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}
Then you compile it with protoc, the protocol buffer compiler, to produce code in C++, Java, or Python.
Then, if you are using C++, you use that code like this:
Person person;
person.set_id(123);
person.set_name("Bob");
person.set_email("bob@example.com");

fstream out("person.pb", ios::out | ios::binary | ios::trunc);
person.SerializeToOstream(&out);
out.close();
Or like this:
Person person;
fstream in("person.pb", ios::in | ios::binary);
if (!person.ParseFromIstream(&in)) {
  cerr << "Failed to parse person.pb." << endl;
  exit(1);
}

cout << "ID: " << person.id() << endl;
cout << "name: " << person.name() << endl;
if (person.has_email()) {
  cout << "e-mail: " << person.email() << endl;
}


사실 궁금한 것은 동일 language에서 동작하는 것 보다는 서로 다른 lanaguage에서 동작하는 지가 궁금한지라.. 


[다운로드 및 설치 방법] 

* 2.5.0 에서는 java library 빌드가 안되어 2.4.1로 빌드 및 설치

protobuf C/C++ library 빌드 및 설치 => README.txt 참고
 : (unix default) ./configure && make && make check && make install

protobuf java library 빌드 => java/README.txt 참고
 : Maven 설치 필요... sudo apt-get install maven2
 : mvn test && mvn install && mvn package
 : protobuf c/c++ library 빌디 및 설치 이후 빌드 가능


[example 빌드 및 실행]

- examples 폴더 내에서 make
 : Makefile내에서 javac_middleman 빌드 부분에서 classpath를 추가해줘야 한다.
  . cp ../java/target/*.jar .
  . Makefile에서 "javac AddPerson.java..."를 "javac -cp protobuf-java-2.4.1.jar:. AddPerson.java"로 수정
  . make

 haha@cs-portable:~/source/protobuf-2.4.1/examples$ make
protoc --cpp_out=. --java_out=. --python_out=. addressbook.proto
pkg-config --cflags protobuf  # fails if protobuf is not installed
-pthread -I/usr/local/include  
c++ add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`
pkg-config --cflags protobuf  # fails if protobuf is not installed
-pthread -I/usr/local/include  
c++ list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs protobuf`
javac -cp protobuf-java-2.4.1.jar:. AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
Writing shortcut script add_person_java...
Writing shortcut script list_people_java...
Writing shortcut script add_person_python...
Writing shortcut script list_people_python...


Sampled proto format

 protobuf-2.4.1/examples$ cat addressbook.proto
// See README.txt for information and build instructions.

package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
  required string name = 1;
  required int32 id = 2;        // Unique ID number for this person.
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person person = 1;


 다른 Language에서 serialize된 stream을 parse할 수 있음.

 haha@cs-portable:~/source/protobuf-2.4.1/examples$ ./add_person_cpp 
Usage:  ./add_person_cpp ADDRESS_BOOK_FILE
haha@cs-portable:~/source/protobuf-2.4.1/examples$ ./add_person_cpp test
test: File not found.  Creating a new file.
Enter person ID number: 1
Enter name: haha
Enter email address (blank for none): haha@haha.net
Enter a phone number (or leave blank to finish): 1111111
Is this a mobile, home, or work phone? mobile
Enter a phone number (or leave blank to finish): 

haha@cs-portable:~/source/protobuf-2.4.1/examples$ ./list_people_cpp test 
Person ID: 1
  Name: haha
  E-mail address: haha@haha.net
  Mobile phone #: 1111111

haha@cs-portable:~/source/protobuf-2.4.1/examples$ java -cp protobuf-java-2.4.1.jar:. ListPeople test 
Person ID: 1
  Name: haha
  E-mail address: haha@haha.net
  Mobile phone #: 1111111

일반적인 Application에서는 Native단과 Java단간의 data 교환시 정해진 data structure/object에 맞춰서 전달하겠지만 만약 JNI layer에서 공통된 format을 전달해야 한다고 한다면 protobuf를 사용해서
serialize된 data를 JNI layer를 통해 전달하고 각 layer에서 parse해서 사용한다면 간편할 듯..

2013년 3월 21일 목요일

Serialization between C++ and Java

이전 블로그에서 이전 함 (원본 글 2013/03/21 작성)

여러 모듈에서 사용되는 arguments들을 공통된 format을 사용하여 native의 data를 Java 단으로 올리기 위해서 방법을 찾아 보려 했었다...

JNI에서는 기본적인 primitive data type은 변환이 가능하고 간단한 object type으로 mapping이 가능하다. 

Table 3-1 Primitive Types and Native Equivalents

Java Type

Native Type

Description

boolean

jboolean

unsigned 8 bits

byte

jbyte

signed 8 bits

char

jchar

unsigned 16 bits

short

jshort

signed 16 bits

int

jint

signed 32 bits

long

jlong

signed 64 bits

float

jfloat

32 bits

double

jdouble

64 bits

void

void

N/A

 


하지만 하위 모듈들에서 어떤 type을 사용할지 모른다는 제약으로 인해 ...

naive하게 native단과 java단 사이에 전달될 data structure를 단순화 하고 
전달하는 값은 arguments들을 Serialization한 값을 사용하는게 어떨까 했었다..

일단 Serialization 관련 해서 찾아보니 다음과 같다.

C++
- boost serialization library
 . 깔끔 하고 사용하기 편하다. 
 . serialization을 한 값을 보면 꽤나 단순한 형태이다.
 . 다만 boost library의 version에 따른 호환성이 있을 수 도 있지 않을까.... 라는 택도 없는 생각이..

Java
 . 뭐 java야 기본으로 지원하니까...
 . 좀 더 자세히 보자면 : http://javapapers.com/core-java/java-serialization/


Protocol Buffers 
 . Google에서 제공하는 open source
 . protocol을 format에 맞춰 기술하고 사용 언어에 맞춰 이를 컴파일 하여 사용
 . C++, Java, Python을 지원
 . 이종 언어간 (C++, Java, Python) protocol Data를 공유하고자 할 경우
 . Andorid상에서 native library를 사용하여 공유하고자 할 경우 

What Are Protocol Buffers?

Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages – Java, C++, or Python.
The download provides the complete source code for the protocol buffer compiler and all the classes your generated code needs, together with building and installation instructions.
 우
SWIG
 . 사실 tutorial만 봐서는 사용할 수 있을지 모르겠다. 공통 interface description을 사용해서  여러 언어를 대상으로 코드를 생성 할 수 있을 것 같은데.... data의 변환 문제는 해결 할 수 없는 다른 범주의  solution 임

XX Library
. 찾다 보니 Java 진영쪽에서 C++ object들을 Java에서 사용할 수 있게끔 해주는 package가 있던데... 아직 완벽한것 같지 않고 제약이 있었던 것 같았다.. 
 . 링크를 다시 못찾아서 이렇게 정리만..



일단 간단하게 하려면 그냥 내가 serialization용 protocol을 만들어서 주고 받고 
공통의 container에 <name, value> 정도의 정보만 제공할 수 있을 것 같다...

좀 더 나아가면 가 종단에서는 Abstract factory를 만들어서 전달하고자 하는 data type에 따란
container object를 생성하되 각 object들은 Serialization interface를 구현하여 
JNI 단에서 전달하는 string을 parsing/serialize를 하는 방법도 있을 수 있겠다.

능력이 그거 밖에 안되네..

좀 심각하게 고민한다면 Protocol buffers를 고려해 볼 만 한데 그렇게 까지 중요한 부분이 아니라서....