2011년 6월 22일 수요일

Android에서 Httpclient와 WebView간 HttpSession 공유

요즘은 Mobile Application를 Hybrid Type으로 개발하는 것이 대세인 것 같습니다. App과 Web의 이동을 원활하게 하기 위해서 HttpSession를 사용하는 경우가 있습니다.
이 번 글에서는 Android에서 Httpclient와 WebView간 Session(사실은 Cookie)를 공유(사실은 Copy)하는 방법을 알아보겠습니다.

Example Case
  1. 기존 사용 중이던 Web Site을 최소한의 개발로 Mobile로 이식하길 원한다.
  2. Web Site는 사용자 인증를 거치게 되면 사용자 인증 정보를 HttpSession에 저장하게 되어 있다.
  3. 사용자 인증 부분은 Mobile App으로 개발한다. 사용자 인증을 위해 Login RESTful API을 신규로 개발한다.
  4. 그 외 화면은 Web Site 기존 Web Application을 최대한 활용하여 Mobile Web Application을 만든다.

Mobile App에서 사용자인증은 Httpclient이용하여  진행되고,  Mobile Web은 WebView내에서 호출된다. 이 두가지 는 동일한 App에 있지만 마치 한 PC 두 개의 Browser 처럼 Cookie을 공유하지 못하지만 Cookie을 Copy 해주면 해결 됩니다.

Cookie Copy

HttpResponse response = httpclient.execute(httppost);

List<Cookie> cookies = httpclient.getCookieStore().getCookies();
if (!HMGWServiceHelper.cookies.isEmpty()) {

CookieSyncManager.createInstance(LoginActivity.this);
CookieManager cookieManager = CookieManager.getInstance();

Cookie sessionInfo = null;
for (Cookie cookie : cookies ) {
sessionInfo = cookie;
String cookieString = sessionInfo.getName() + "="
+ sessionInfo.getValue() + "; path="
+ sessionInfo.getPath();

cookieManager.setCookie(sessionInfo.getDomain(),cookieString);
CookieSyncManager.getInstance().sync();
}
}

Httpclient을 사용하여 Response가 온 이후에 httpclient.getCookieStore().getCookies();
로 Cookie을 가져옵니다.

CookieSyncManager.createInstance(LoginActivity.this);
CookieManager cookieManager = CookieManager.getInstance();
CookieManager는 App에서 관리되는 Cookie 저장소입니다. cookieManager에 Cookie을 복사할때는 문자열로 변경하여 저장해야 합니다.

WebView에서 사용방법
특별한게 없습니다. URL을 호출하면 됩니다.

Conclusion
Hybrid App에서 App과 Web 사이를 이동할 경우에 Session을 유지할 수 있는 방법을 살펴봤습니다. 하지만 우리는 중요한 문제에 대해서 고민 하지 않았습니다.

“Hybrid Web에서 HttpSession을 사용하는게 좋은가?”

저는 절대 추전하지 않겠습니다. 이유를 들자면..
  • Mobile 환경에서 Device의 할당 IP는 언제든지 변경될 소지가 있는데 이 경우 HttpSession은 IP에 따라 Bind 되기에 영속적일 수 없다.
  • App이 Background 상태에 있을 때 HttpSession이 만료된 경우 처리가 복잡하다.
  • Device와 WebServer 사이에 보안을 위해 Proxy나 Gateway을 둘 경우 HttpSession 사용 자체가 힘들다.(Domain이 Proxy나 Gateway을 바라보게 됩니다.)

제가 추천하는 방법은 사용자 인증 코드 전달 방식 입니다. Server로부터 사용자 코드를 부여 받고 WebURL 호출시 사용자 코드를 Header나 Parameter 넣는 방식입니다. 이런 방식은 나중에 보안 적용에도 유연합니다.

2011년 6월 20일 월요일

RESTful Web Service 쉽게 만들기

많은 Java 개발자들이 RESTful Web Service을 배우는데 흥미를 가지고 있습니다. 하지만 많은 튜토리얼들이 과도하게 복잡하기만 합니다.
본 글에서는 JDK와 간단한 Notepad같은 Text Editor만 가지고 RESTful Web Service을 개발하는 방법을 설명합니다. 마지막에 배포를 위해서 Tomcat 7는 설치합니다.

모두가 다 아는 이야기를 약간 하고 넘어가겠습니다. RESTful Web Service는 HTTP Protocol 상에서 서비스되게 디자인되어 있습니다. 가장 큰 특징은 HTTP Protocol의 4가지 Method인 “PUT”, “GET”, “POST”, “DELETE”가 Data을 조작하기 위한 Create, Read, Update, Delete에 Match되게 디자인 되어있다는 것입니다.

RESTful Web Service API을 개발할 때는 재일 먼저 API을 URL+Method로 정확히 정의하고 시작해야 합니다. 여기서 다룰 아주 간단한 API라도 말입니다.

“Hello world”  Webservice → “http://localhost:8080/restful/resources/helloworld”, GET
  • http://localhost:8080: Tomcat 7 WAS
  • resetful: 배포될 WAR 명에 따라 변경 됨
  • resources: web.xml에 등록된 RESTful 지원 Servlet URL pattern
  • API 별로 정의해야할 것은 “helloworld”, “GET” 이 두가지 입니다.


JSR-311 Reference 구현 라이브러리: Jersey(http://jersey.java.net)
RESTful Web Service는 JSR-311로 Spec이 발표되었고 이를 구현한 많은 구현 라이브러리가 있습니다. 여기서는 Jersey을 사용하도록 하겠습니다. 이 글을 쓰고 있는 현재 Jersey 버전은 1.7입니다.(JSR-311 버전 1.1을 구현한 라이브러리를 사용합니다.)

jersey을 받고 아래 jar 파일들을 “WEB-INF/lib”에 넣습니다.
  • asm-3.1.jar
  • jackson-core-asl-1.7.1.jar
  • jackson-jaxrs-1.7.1.jar
  • jackson-mapper-asl-1.7.1.jar
  • jackson-xc-1.7.1.jar
  • jersey-client-1.7.jar
  • jersey-core-1.7.jar
  • jersey-json-1.7.jar
  • jersey-server-1.7.jar
  • jettison-1.1.jar
  • jsr311-api-1.1.1.jar



Code 작성 하기
위에서 URI을 지정할때 API별로 지정할수 있었던 2가지를 여기서 정의해줍니다.


package com.mcnz.ws;
import javax.ws.rs.*;
@Path("helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String getMessage() {
    return "Rest Never Sleeps";
}
}

“@Produces”는 Return의 MIME-TYPE을 정의하는 것입니다. 여기서는 Plain text 형태를 지정하였습니다.

Compile 하기
C:\> c:\_jdk1.6\bin\javac -classpath "C:\_restful\WEB-INF\lib\*"
C:\_restful\WEB-INF\classes\com\mcnz\ws\*.java



web.xml에 Jersey 설정하기
“WEB-INF” 밑에 web.xml 파일을 만들고 아래 내용을 입력합니다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://java.sun.com/xml/ns/javaee" version="3.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 <servlet>
<servlet-name>RestfulContainer</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>com.mcnz.ws</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
<servlet-name>RestfulContainer</servlet-name>
<url-pattern>/resources/*</url-pattern>
 </servlet-mapping>
</web-app>

URL 호출 중 “/resources/”을 포함한 경우는 RESTful Web Service을 호출하는거라 판단합니다.

Deployment and Testing

WAR 파일 만들기
C:\_restful> %JAVA_HOME%\bin\jar -cvf
C:\_tomcat\webapps\restful.war *.*

설치된 Tomcat에 배포


정의한 URL로 호출해 봅니다.

당신의 개발팀에 동기부여하는 5가지 방법

Five ways to motivate your development team

1. Give your developers the resources they need.
월급 천만원 받는 개발자를 고용하면서 486 수준의 하드웨어에서 일하게 하는가? 대부분의 개발자들은 하드웨어지원이 충분하다면 소프트웨어 지원이 느린것 쯤은 불평하지 않습니다.

2. Recognize a job well done.
칭찬은 기적을 동반합니다. 자부심은 동기부여에 요소가 됩니다. Milestone이 히트를 치거나 사용자가 만족한다면 개발팀은 그에 대해 인식하고 자부심을 가져야 합니다.

3. Get rid of dead wood
팀 내부에서 누군가 생산적이지 않다면 그들을 제거해야 합니다. 긴 프로젝트에서  얼마나 빠른 생산성을 가지느냐는 그들에 의해서 결정됩니다.

4. Push for new software release.
개발자들은 7년전의 Java 버전이 아닌, Java 7으로 개발하고 싶어 합니다. 새로운걸 배우고, 새로운 지식을 적용하는 것은 개발자에게 자주 동기부여을 해줍니다. 이전 소프트웨어를 사용하는 것은 그들에게 녹슬어가는 느낌을 줍니다. 항상 최신 버전을 사용하는 것은 위험요소를 내포하고 있지만, 이것은 최고의 도구와 기술을 얻기 위한 도전이라 생각해야 합니다.

5. Let developers develop
의사소통이 의사소통 이상의 되면 안됩니다. 프로젝트 매니저가 하찮은 것 까지 개발자를 스케줄링 할 필요가 없습니다. 지나친 Communication은 좋지 못합니다.

Easy java Persistence

EJP(Ease Java Persistence)는 관계형 데이터베이스 사용을 쉽게해주는 강력한 Java API 입니다.
EJP는 Mapping Annotation이나 XML Configuration이 필요 없으며, 특정 클래스를 상속 받거나 인터페이스를 구현할 필요가 없습니다.

하지만 “Automatic O-R Mapping” 이 부분을 생각 해보니 문제가 있을 수 있겠습니다.
EJP에서는 ORM(O-R Mapping)를 위해 Class명과 Table 명 사이, Method 명과 Tablet Column명 사이에 규칙을 지쳐야 하는데 Object의 “name”은 DB에서 “.*name.* 형태이어야 한다는 것 입니다. 그 외 Lazy Object Loading, 상속 관계에 있는 Object Query 등의 지원은 아쉽습니다.

한 가지 명심해야 할 것은 EJP는 JDBC 기반으로 만들어 졌으며,  JPA 구현 라이브러리가 아니며,  둘 사이는 아무런 관계가 없다는 것입니다.

지원하는 Databases
  • MySQL
  • DB2
  • Oracle
  • Derby
  • HSQL
  • PostgreSQL
  • H2


간단한 사용법

Database Connecting
dbm = new DatabaseManager("mydb", 5, "com.mysql.jdbc.Driver", "jdbc:mysql://localhost/mydb");

또는

dbm = new DatabaseManager("mydb", 5, "jndiPath");

POJO Class “Customer” 정의

public class Customer
 {
   String username;
   String firstName;
   List support;     //association
   List orders;      //association
   ...
   // getters/setters
   ...
 }


Loading a Customer
Customer customer = dbm.loadObject(new Customer("johnsmith"));

Loading all Customers
List<Customer> customers = dbm.loadObjects(new ArrayList<Customer>(), Customer.class);

Updating Customer
customer.setLastName("Smithman");
dbm.saveObject(customer);


내부적으로는 아래와 같은 Update SQL이 생성될 것 입니다.
update customers set last_name = 'SmithMan' where username = 'johnsmith';

Insert Customer
Customer customer = new Customer("Johnjones", "John", "Jones");
dbm.saveObject(customer);

Update와 Insert 모두 “saveObject”을 호출 합니다. EJP는 customer Object가 새로 생성된 것인지 변경된 것인지 알아서 판단해줍니다.

SQL 일부 사용
Customer customer = new Customer();

// find all customers where last name = Smith
customer.setLastName("Smith");
dbm.loadObject(customer);


dbm.loadObject(new Customer(), "where :lastName = ?", "Smith");

SQL 일부을 loadObject Method에서 사용하여  특정 Object을 쉽게 찾을 수 있습니다. 또한 “%”와 같은 Wiildcard도 사용이 가능합니다.
또한 Object Find 조건이 여러가지라면 아래와 같이 사용할 수도 있습니다.

customer.setFirstName("John");
customer.setLastName("Smith");


또는

dbm.loadObject(new Customer(), "where :firstName = ? and :lastName = ?", "John", "Smith");

Conclusion
EJP을 사용하기 위해서는 알아야 할 것은 명명규칙 뿐 다른 건 알 필요가 없습니다. 개발자를 충분히 편하고 게으르게 해줄 수 있을 것 같습니다. 하지만 보다 많은 것을 바란다면 JPA 구현 라이브러리를 권장합니다.

2011년 6월 17일 금요일

web.xml 이 더이상 필요 없는 Spring 3.1 Web MVC

최근에 Spring Framework 3.1 M2가 Release 되었습니다.
여기에는 M1에서 시작한 기능과 몇몇 기능의 구현이 완료 되었고 현재 RC 단계에 있습니다.

그 중에 눈에 띄는 기능이 web.xml 없는 Spring MVC 입니다.
이 것은 이미 Servlet 3.0 스팩에서 web.xml 없이 Webapplication을 배포할수 있게 정의 되어 있어 가능해졌습니다. 작성한 Servlet에 "@WebServlet" Annotation을 정의하면 되는 것입니다.

Spring 3.1 이전 버전에서는 DispatcherServlet을 web.xml에 필히 등록해주어야 하지만 3.1 부터는 WebApplicationInitializer라는게 알아서 한다고 합니다.

Alvor - SQL checker for Java

Java Program에서 SQL 문장은 보통 문자열로 표현됩니다.  SQL 문장의 오류는 컴파일에서 걸러지지 못하고 Runtime 시에 확인 할 수 있습니다. 게다가 SQL 문장이 조건에 의해 조합 된다면 Client site에서 실행되고 나서야 버그가 발생될 가능성도 있습니다.
Alvor(알보르)는 Eclipse JDT plug-in 으로 컴파일 때 SQL 문장의 오류를 Check해 주는 Open source Project 입니다.
아직은 BETA 버전이지만 앞으로 기대가 되는 프로젝트입니다.

설치 환경


사용 예
Alvor는 아래와 같은 SQL 문장에서 두 가지 오류를 Check 하게 됩니다.
  1. persons 과 where 사이의 공백이 없음.
  2. “first_naem” 문장이 틀림.




관련 사이트
http://code.google.com/p/alvor/

대용량, 클라우드 서버 환경에서 DBMS가 고민해야할 문제

facebook으로 대표되는 Social Network Service는 정보가 만들어지고 쌓이는 속도를 몇배 증가 시켰다. 빠르게 쌓이고 변화하는 정보에 능동적으로 대처하기 위해 클라우드 컴퓨팅이 뒤늦게 주목 받는다.
최근의 변화는 어느날 갑자기 불어온 것이 아니라 차근차근 쌓이던 눈이 무너져 내린 것이다. 하지만 수십년 간에 데이터 처리의 중추적 역할을 담당해온 DBMS는 변화를 못 쫓아갔다.
...

차세대 DBMS의 고민

  • 대용량 데이터
  • 잦은 장애
  • 서비스 작성의 편의성
  • 기능적 요구 사항
  • 수평적 확장
  • 병렬 처리
  • 짧은 장애 복구 시간
  • SQL 지원
  • Multi-row Transaction 지원

Download

2011년 6월 16일 목요일

Android Inter-App Communication

이번 튜토리얼에서는 두 개의 Process 사이에서  하나가 다른 Process의 Service을 호출하는 방법에 대하여 설명하고 있습니다.

본 문서에서는 다음 내용을 다룹니다.
  • Invocation Handler을 작성하는 방법
  • Remote Service을 Bind 하는 방법
  • Invocation을 호출한 Process에게 Value Return 하는 방법


Step 1: Create the Service
Invocation될 Service을 만듭니다. Service에는반드시 IBinder 객체를 Return하는 onBind Method을 Override해야 합니다.
Service에서는 Messenger 컴포넌트를 사용합니다. 이 Messenger 컴포넌트는 내부 Process 간 Communication 이 가능하게 해줍니다.
public class RemoteService extends Service
{
private Messenger messenger; //receives remote invocations

@Override
public IBinder onBind(Intent intent)
{
if(this.messenger == null)
{
synchronized(RemoteService.class)
{
if(this.messenger == null)
{
this.messenger = new Messenger(new IncomingHandler());
}
}
}
//Return the proper IBinder instance
return this.messenger.getBinder();
}


Step 2: Implement the Handler
Handler는 Messenger을 등록할수 있는 컴포넌트 입니다. 이 컴포넌트는 Remote Invocation을 받을 수 있는 컴포너트 중 하나 입니다.
Handler는 들어온 요청의 Messenger에 따라 요청을 처리하고 응답을 보내게 되어있습니다.
private class IncomingHandler extends Handler
{
@Override
               public void handleMessage(Message msg)
{
System.out.println("*****************************************");
System.out.println("Remote Service successfully invoked!!!!!!");
System.out.println("*****************************************");

int what = msg.what;

Toast.makeText(RemoteService.this.getApplicationContext(), "Remote Service invoked-("+what+")", Toast.LENGTH_LONG).show();

//Setup the reply message
Message message = Message.obtain(null, 2, 0, 0);
try
{
//make the RPC invocation
Messenger replyTo = msg.replyTo;
replyTo.send(message);
}
catch(RemoteException rme)
{
//Show an Error Message
Toast.makeText(RemoteService.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();
}
   }
}


아래는 RemoterService Application의 Full Source입니다.

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.openmobster.remote.service.android.app"
     android:versionCode="1"
     android:versionName="1.0">
   <application android:label="@string/app_name" android:icon="@drawable/icon">
       <activity android:name="org.openmobster.app.MainActivity"
                 android:label="@string/app_name">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
           <intent-filter>
               <action android:name="android.intent.action.VIEW" />
           </intent-filter>
       </activity>
       
       <service android:name="org.openmobster.app.RemoteService" android:exported="true">
       </service>
   </application>
   <uses-permission android:name="android.permission.INTERNET" />
</manifest>

“org.openmobster.app.MainActivity”는 Hello world 수준으로 만들어 줍니다.

RemoteService
package org.openmobster.app;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.widget.Toast;

public class RemoteService extends Service
{
private Messenger messenger; //receives remote invocations

@Override
public IBinder onBind(Intent intent)
{
if(this.messenger == null)
{
synchronized(RemoteService.class)
{
if(this.messenger == null)
{
this.messenger = new Messenger(new IncomingHandler());
}
}
}
//Return the proper IBinder instance
return this.messenger.getBinder();
}

private class IncomingHandler extends Handler
{
@Override
       public void handleMessage(Message msg)
{
System.out.println("*****************************************");
System.out.println("Remote Service successfully invoked!!!!!!");
System.out.println("*****************************************");

int what = msg.what;

Toast.makeText(RemoteService.this.getApplicationContext(), "Remote Service invoked-("+what+")", Toast.LENGTH_LONG).show();

//Setup the reply message
Message message = Message.obtain(null, 2, 0, 0);
try
{
//make the RPC invocation
Messenger replyTo = msg.replyTo;
replyTo.send(message);
}
catch(RemoteException rme)
{
//Show an Error Message
Toast.makeText(RemoteService.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();
}
       }
}
}


Step 3: Create a Client ServiceConnection Object
Client가 Service에 바인딩하는 경우 이 호출은 비동기 방식입니다. 시스템은 클라이언트에게 ServiceConnection 같은 Callback 메커니즘을 제공하고 있습니다.
클라이언트는 제공된 IBinder 인스턴스를 사용하여 Messenger 객체를 설정합니다.
private class RemoteServiceConnection implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName component, IBinder binder)
{
MainActivity.this.messenger = new Messenger(binder);

MainActivity.this.isBound = true;
}

@Override
public void onServiceDisconnected(ComponentName component)
{
MainActivity.this.messenger = null;

MainActivity.this.isBound = false;
}
}


Step 4: Bind to the Remote Service
Intent을 생성하고 Invoke될 Service을 가리키는 ClassName을 지정합니다.
@Override
protected void onStart()
{
super.onStart();

//Bind to the remote service
Intent intent = new Intent();
intent.setClassName("org.openmobster.remote.service.android.app", "org.openmobster.app.RemoteService");

this.bindService(intent, this.connection, Context.BIND_AUTO_CREATE);
}


Step 5: Make the Remote Invocation
Message.obtain을 이용하여 Message 객체를 생성합니다. message.replyTo에 Local Messenger를 담습니다. Messenger에 Message을 담아 Send합니다.
//Setup the message for invocation
Message message = Message.obtain(null, 1, 0, 0);
try
{
//Set the ReplyTo Messenger for processing the invocation response
message.replyTo = MainActivity.this.replyTo;

//Make the invocation
MainActivity.this.messenger.send(message);
}
catch(RemoteException rme)
{
//Show an Error Message
Toast.makeText(MainActivity.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();
}


아래는 RemoteClient Full Source입니다.

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.openmobster.app"
     android:versionCode="1"
     android:versionName="1.0">
   <application android:label="@string/app_name" android:icon="@drawable/icon">
       <activity android:name=".MainActivity"
                 android:label="@string/app_name">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
           <intent-filter>
               <action android:name="android.intent.action.VIEW" />
           </intent-filter>
       </activity>
   </application>
   <uses-permission android:name="android.permission.INTERNET" />
</manifest>


/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">

<Button android:id="@+id/invoke"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="Invoke Remote Service" />                                                                           
</LinearLayout>


MainActivity
package org.openmobster.app;

import java.lang.reflect.Field;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity
{
private Messenger messenger = null; //used to make an RPC invocation
private boolean isBound = false;
private ServiceConnection connection;//receives callbacks from bind and unbind invocations
private Messenger replyTo = null; //invocation replies are processed by this Messenger

public MainActivity()
{

}

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.connection = new RemoteServiceConnection();
this.replyTo = new Messenger(new IncomingHandler());
}

@Override
protected void onStart()
{
super.onStart();

//Bind to the remote service
Intent intent = new Intent();
intent.setClassName("org.openmobster.remote.service.android.app", "org.openmobster.app.RemoteService");

this.bindService(intent, this.connection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStop()
{
super.onStop();

//Unbind if it is bound to the service
if(this.isBound)
{
this.unbindService(connection);
this.isBound = false;
}
}

@Override
protected void onResume()
{
try
{
super.onResume();

//render the main screen
String layoutClass = this.getPackageName()+".R$layout";
String main = "main";
Class clazz = Class.forName(layoutClass);
Field field = clazz.getField(main);
int screenId = field.getInt(clazz);
this.setContentView(screenId);

//Invoke Remote button
Button invokeButton = (Button)findViewById(R.id.invoke);
invokeButton.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View button)
{
if(MainActivity.this.isBound)
{
//Setup the message for invocation
Message message = Message.obtain(null, 1, 0, 0);
try
{
//Set the ReplyTo Messenger for processing the invocation response
message.replyTo = MainActivity.this.replyTo;

//Make the invocation
MainActivity.this.messenger.send(message);
}
catch(RemoteException rme)
{
//Show an Error Message
Toast.makeText(MainActivity.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();
}
}
else
{
Toast.makeText(MainActivity.this, "Service is Not Bound!!", Toast.LENGTH_LONG).show();
}
}
 }
);
}
catch(Exception e)
{
e.printStackTrace(System.out);
}
}

private class RemoteServiceConnection implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName component, IBinder binder)
{
MainActivity.this.messenger = new Messenger(binder);

MainActivity.this.isBound = true;
}

@Override
public void onServiceDisconnected(ComponentName component)
{
MainActivity.this.messenger = null;

MainActivity.this.isBound = false;
}
}

private class IncomingHandler extends Handler
{
@Override
       public void handleMessage(Message msg)
{
System.out.println("*****************************************");
System.out.println("Return successfully received!!!!!!");
System.out.println("*****************************************");

int what = msg.what;

Toast.makeText(MainActivity.this.getApplicationContext(), "Remote Service replied-("+what+")", Toast.LENGTH_LONG).show();
       }
}
}

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

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