2012년 2월 29일 수요일

Twitter4j 와 Esper를 이용한 타임라인 분석 기법

최근 구독한 Article에서 Twitter4j와 Esper(Complex Event Processing analytic tool)을 이용하여 Twitter 상에서 발생한는 Data feed에서 의미있는 정보를 도출하는 아이디어가 있어 정리해봅니다.

Esper는 CEP 분석 도구로는 가장 좋은 평가를 받고 있습니다. GPL 라이센스 적용을 받고 있어서 이를 이용한 sofeware는 모두 Open source로 공개 되어야 합니다. 저에게는 이게 발목을 잡아서 사용하지 못하였습니다.

Article의 목적은

*Twitter 타임라인에 행복한 사람이 얼마나 많은지 찾아본다.

타임라인에 “Happy” 글이 얼마나 자주 올라 오는지 알아봅니다. 복잡할건 하나도 없습니다. Esper가 다 해줍니다.

CEP을 이해하기 위해서는 Window라는 개념을 알아야 합니다. 간단하게 설명해 보기로 하겠습니다.

지금 밖에는 2줄기 비가 내립니다.
한 줄기는 시간 입니다.(초 단위)
다른 한줄기는 Twitter의 글들입니다.

1. 나는 지금 밖이 보고 싶어서 벽에 다가 창문을 뚫으려고 합니다.
2. 창문 높이는 2초 쯤 되고, 넓이는 2줄기 비를 볼 수 있을 정도를 뚫습니다.
3. 뚫린 창문으로 내리는 비를 지켜 봅니다.
4. 창문으로 보이는 Twitter 글 중에 “Happy” 라는 단어가 2번 이상 보입니다.
5. 사람들이 행복하다고 판단합니다.

위의 벽에 뚫린 창문이 CEP에서 Window라고 합니다. 밖에서 내리는 수많은 Event 중에서
내가 원하는 것만 보기 위해서 뚫어둔 창문입니다.

Esper에서는 창문을 뚫고 지켜보는 행동을 SQL 문장과 비슷하게 정의해서 등록하게 됩니다. 아래처럼.

select user, sum(ctr) from com.sybase.simple.HappyMessage.win:time(10 seconds) having sum(ctr) > 2


그런데 중요한 맹점이 하나 있는데. 아래 두 문장에 모두 “happy”가 들어가지만 의미는 반대라는 겁니다. 이런 문제는 문장 의미분석이 필요한 부분이겠습니다.

-> I'm happy.
-> I'm not happy.


보다 자세한 내용은 원문 전체를 읽어보시기 바랍니다.

원문 보기

2012년 2월 23일 목요일

안드로이드 플랫폼에서 애플리케이션 간 객체 전송을 개선하기 위한 메타서비스의 설계 및 구현


최근 안드로이드 기반의 스마트 폰이 널리 사용되고 있으며, 이를 이용한 다양한 응용이 개발중이다. 그 중 한 애플리케이션에서 생성한 데이터를 다른 애플리케이션으로 전달하는 경우가 빈번하게 발생한다. 그러므로 한 애플리케이션에서 발생하는 메타데이터를 다른 애플리케이션으로 쉽게 전달하거나 공유할 수 있는 방법이 필요하다.

안드로이드에서 애플리케이션이 생성한 메타데이터는 Java 객체로 만들어진다. 안드로이드에서 기존의 데이터 전달 방법으로는 클립보드와 인텐트 그리고 컨텐트 프로바이더가 있다. 하지만 이 방법들은 모두 레코드 형태로 데이터를 전달하도록 되어 있다. 그러므로 개발자는 객체를 전달하기 위해 마샬링과 언마샬링하는 과정을 직접 구현해야 한다. 본 논문에서는 애플리케이션에서 만든 임의의 타입의 객체를 전송할 수 있는 메타서비스를 설계하고 구현하였다. 메타서비스를 이용할 경우 클립보드와 컨텐트 프로바이더에서 객체를 전송하기 위해 구현해야하는 복잡한 과정을 줄여서 버그를 줄이고 코드를 간단히 작성할 수 있도록 하여 생산성을 증진 시킬 수 있도록 하였다.


문서보기

2012년 2월 22일 수요일

Android 촬영 사진의 회전 각 알아보기

Android에서 촬영한 사진이나 앨범에서 사진을 Server Side로 전송하는 부분을 개발하다 보니 Vender 마다 차이가 있었다.

무슨 문제가 있었던 것일까?

LG Phone
세로 모드로 사진 촬영: 정상
가로 모드로 사진 촬영: 정상

Sam Sung Phone
세로 모드로 사진 촬영: 90도 회전 된 이미지가 전송
가로 모드로 사진 촬영: 정상

How can we do it?

  1. Android에서 촬영된 사진은 “Orientation” 이라는 “Tag”가 존재하는데 이 Data로 사진을 촬영할 때의 Degree을 알 수 있습니다.
  2. “1”번으로 Degree을 알아 보고 그 각도만큼 회전 시킨 이미지를 생성하면 됩니다.

아래는 1,2 번에 해당되는 Code을 Googing  찾아봤습니다.

/**
* 이미지 회전 각도를 알아옴.
* @param filepath
* @return 각도
*/
public synchronized static int getPhotoOrientationDegree(String filepath)
{
int degree = 0;
ExifInterface exif = null;
try
{
exif = new ExifInterface(filepath);
}
catch (IOException e)
{
Log.d(PhotoUtil.class.getSimpleName(), "Error: "+e.getMessage());
}
if (exif != null)
{
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
if (orientation != -1)
{
switch(orientation)
{
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}

}
}
Log.d(PhotoUtil.class.getSimpleName(), "Photo Degree: "+degree);
return degree;
}

/**
* 이미지를 특정 각도로 회전
* @param bitmap
* @param degrees
* @return
*/
public synchronized static Bitmap getRotatedBitmap(Bitmap bitmap, int degrees)
{
if ( degrees != 0 && bitmap != null )
{
Matrix m = new Matrix();
m.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2 );
try
{
Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
if (bitmap != b2)
{
bitmap.recycle();
bitmap = b2;
}
}
catch (OutOfMemoryError e)
{
Log.d(PhotoUtil.class.getSimpleName(), "Error: "+e.getMessage());
}
}
return bitmap;
}

Issue
이런 문제도 있을수 있습니다.
요즘 스마트폰이 좋아 사진 한 장 당 크기가 2M를 넘어갑니다. 이 정도 크기를 Server Side로 전송하는데 시간이 많이 걸리고 요금도 무시 못하기기 때문에, iPhone 이든 Android 든 모든 이미지 압축을 하여 전송하게 됩니다. 그런데 이미지을 압축 하면 위의 Degree 값이 0이 됩니다.
압축 전에 원본을 돌려 놓고 압축해야 합니다.

2012년 2월 15일 수요일

20 Database Design Best Practices


100% 공감이 가는 내용이 있어 포스트 합니다.
원문 링크: http://www.javacodegeeks.com/2012/02/20-database-design-best-practices.html

대충 아래와 같은 내용입니다.

  1. 테이블과 컬럼에 잘 정의된 일관된 이름을 사용한다.
  2. 테이블 이름은 단수를 사용
  3. 테이블 이름에 공백을 사용하지 않는다.
  4. 테이블 이름에 불필요한 접미어, 접두어를 사용하지 않는다.
  5. 보안을 위해 비밀번호는 암호화를 유지, 복호화는 어플리케이션안에서 필요할 때 사용 한다.
  6. 모든 테이블에 Integer ID 필드를 사용한다. 당장은 필요 없더라도 앞으로 필요할 때가 반드시 있습니다.
  7. 인덱싱은 Integer 데이터 타입을 사용합니다. varchar 컬럼 인덱싱은 성능에 문제가 있습니다.
  8. Boolean 값은 bit 필드를 사용합니다. Integer또는 varchar을 사용하면 불필요한 공간을 더 사용하게 됩니다. 그리고 반드시 컬럼 이름은 “Is”로 시작합니다.
  9. 데이터베이스 접근을 위한 권한 인증에 신경씁니다. 모든 사용자에게 관리자 권한을 주어서는 절대 안됩니다.
  10. select 문장을 사용할 때 “*” 사용을 피해야 합니다. 반드시 컬럼명을 명시해서 사용해야만 보다 좋은 성능을 보장 받을수 있습니다.
  11. ORM(Object Relational Mapping) Framewokr을 사용하는 경우, 특히 어플리케이션에서 ORM Code 충분히 크다고 생각되는 경우, ORM Framework의 성능 이슈를 잘 파악하고 이에 대해 적절한 세부 설정을 처리해야 한다.
  12. 크고 사용하지 않거나, 좀처럼 사용하지 않는 테이블들은 서로 다른 물리적 스토리지에 나누어 사용하면 쿼리의 성능이 좋아집니다.(물리적 디스크 I/O을 고려해서 잘 사용하는 테이블을 적당히 나눠야 좋다는 이야기)
  13. 크고 민감한 중요한 데이터베이스 시스템은 장애조치 클러스터링, 재해복구 시스템, 자동 백업, 복제 등 같은 보안 서비스를 사용하는게 좋습니다.
  14. 데이터 무결성위한 제약 조건 foreign key, not null 등을 사용합니다. 어플리케이션 코드에서 이것을 무시할 수 있게 하면 안됩니다.
  15. 데이터베이스 문서화 부족은 악마와 같습니다. ER 스키마와 지침을 사용하여 데이터베이스 문서를 작성하고, 또한 주석 라인을 적극적으로 사용합니다.
  16. 큰 테이블에서 자주 사용되는 쿼리에 대해 인텍스를 사용합니다. 분석 도구를 사용하여 인덱스를 정의할 컬럼를 결정하는데 도움을 받습니다. row의 범위를 검색하는 쿼리의 경우 클러스터링 된 인덱스는 일반적으로 성능이 좋습니다. 그리고 point 쿼리의 경우 클러스터링이 안된 인덱스가 성능이 좋습니다.
  17. DB 서버와 Web 서버는 반드시 다른 머신에 설치되어야 합니다. 보안, CPU 성능, 메모리 성능 등 모든 면에서 좋습니다.
  18. 이미지나 BLOB 데이터는 자주 쿼리 되는 테이블에 정의해서는 안됩니다. 성능의 문제가 있을 수 있기 때문입니다. 이런 데이터는 테이블을 분리하고 데이터를 찾을 수 있는 포인터 정보를 자주 쿼리 되는 테이블에서 가지고 있게 해야 합니다. 
  19. 정규화(Normalizatioin)는 성능을 최적화 하기 위해서 필요에 따라 사용해야 합니다. 정규화가 잘 안되어 있으면 데이터의 과도한 중복(반복)을 초래하게 되고, 정규화가 너무 잘 되어 있으면 데이블간의 Join이 과도하게 생기게 됩니다. 이 둘은 모두 성능에 나쁜 영향을 미치게 됩니다.
  20. 데이터베이스의 모델링, 디자인에 충분한 시간을 투자 합니다. 그렇지 않으면 디자인 타임에 해결될 문제가 유지보수 시점까지 간다면 그 시간은 10배, 100배, 1000배 늘어나게 됩니다.

2012년 2월 13일 월요일

Json Java pasers / generators Benchmark




Mobile환경의 확대와 Open API 사용의 증가와 더불어 Json을 사용하는 프로젝트가 증가하고 있습니다. Json은 XML에 비해 장점을 많이 가지고 있지만 이 글에서는 장,단점을 논하지는  않겠습니다.

Json을 사용하는 프로젝트가 늘어난다는 것은 그만큼 현실성이 있기 때문일 것 입니다.
최근 Article 중에서 Json 라이브러리들의 성능을 비교한 자료가 있어 올려 봅니다.

원문 링크
http://blog.novoj.net/2012/02/05/json-java-parsers-generators-microbenchmark/

요약
테스트 대상 Libraries
  • FlexJson (2.1)
  • GSon (2.1)
  • Jackson (1.9.4)
  • JsonLib (2.4)
  • JsonMarshaller (0.21)
  • JsonSmart (2.0-beta2)
  • Protostuff JSON (1.0.4)
  • XStream (1.4.2)

성능 측정 방식
Serialization, Deserialization의 3000번 Loop을 250번 실행한 편균값을 측정하였음.

측정 결과
FlexJson
Serialization: 5.593ms / 1 PhotoAlbum, JSON file size 165KB
Deserialization: 14.663667ms / 1 PhotoAlbum

GSon
Serialization: 4.9683332ms / 1 PhotoAlbum, JSON file size 169KB
Deserialization: 9.558666ms / 1 PhotoAlbum

Jackson
Serialization: 1.286ms / 1 PhotoAlbum, JSON file size 165KB
Deserialization: 1.5566666ms / 1 PhotoAlbum

JSON-Lib
Serialization: 17.441668ms / 1 PhotoAlbum, JSON file size 168KB
Deserialization: 78.71367ms / 1 PhotoAlbum

JsonMarshaller
Serialization: 3.6623333ms / 1 PhotoAlbum, JSON file size 165KB
Deserialization: 6.372ms / 1 PhotoAlbum

Json Smart
Serialization: 3.8913333ms / 1 PhotoAlbum, JSON file size 172KB
Deserialization: -

Protostuff JSON
Serialization: 1.8266667ms / 1 PhotoAlbum, JSON file size 165KB
Deserialization: 1.2923334ms / 1 PhotoAlbum

XStream
Serialization: 76.84967ms / 1 PhotoAlbum, JSON file size 171KB
Deserialization: 26.361ms / 1 PhotoAlbum


2012년 2월 3일 금요일

Using the Tomcat 7 JDBC Connection Pool in Production

Tomcat 7에서는 기존에 사용하던 "commons-dbcp"가 다른 JDBC connection Pool로 변경 되었다고 합니다. "commons-dbcp"는 작고 traffic이 적은 어플리케이션에서는 훌륭하지만, 높은 동시 사용환경에서는 문제가 있는 것으로 알려져 있엇습니다.


기존의 "commons-dbcp"설정을 그대로 지원하기 때문에 새로운 JDBC connection Pool로 전환이 쉽다고 합니다.


이번 버전에는 추가된 기능을 보면

  1. ValidationInterval 기능이 있어 주기적(기본 30초)으로 Connection 상태를 Check 하게 됩니다.
  2. JDBC Interceptors 기능, tomcat의 특정 클래스를 직접 구현하고 " jdbcInterceptors" Property에 등록하여 사용가능.
  3. StatementFinalizer Intercepter, "createStatement", "prepareStatement", "prepareCall"에 의해서 statement가 create 될때 호출되는 Interceptor 기능
  4. 그 외 ConnectionState Interceptor, SlowQueryReport and SlowQueryReportJmx Interceptors 등.



Tomcat 7은 기존과 비교해서 발전하는건 좋은데 변화가 너무 많은게 독이 되는건 아닌지 모르겠습니다.




아래는 원문: http://www.tomcatexpert.com/blog/2012/01/24/using-tomcat-7-jdbc-connection-pool-production


One of the new features with Tomcat 7 is a replacement to the commons-dbcp connection pool. While the commons-dbcp connection pool works fine for small or low traffic applications, it is known to have problems in highly concurrent environments (think multi-core/multi-cpu).
Fortunately, this is where the JDBC Connection Pool excels. It is a completely new connection pool which has been written from the ground up, with a focus on highly concurrent environments and performance.
Given its focus on high concurrency and performance, many users are finding that the JDBC Connection Pool can be great for use in a production environment. This article will discuss the features and options which make using the JDBC Connection Pool a great choice.

The Basics

Getting started with the JDBC Connection Pool is very simple. It was purposefully designed as a drop-in replacement for commons-dbcp and as such, if you've ever used commons-dbcp you'll be immediately familiar with the configuration for the JDBC Connection Pool.
This means the most existing commons-dbcp users can switch to the JDBC Connection Pool by simply adding the following property to their configuration factory=”org.apache.tomcat.jdbc.pool.DataSourceFactory”.
What about the other commons-dbcp configuration options? You don't need to change them at all. Virtually all of the commons-dbcp configuration options are supported by the JDBC Connection Pool. Including but not limited to:testWhileIdle, testOnBorrow, testOnReturn, maxActive, minIdle, maxWait, initialSize, removeAbandoned, removeAbandonedTimeout and logAbandoned.

Connection Validation

How many users have seen this scenario before? You deploy a new application to production and it runs great all day, however the next morning you find that the application is dead. Upon examining the logs, you find that they are full of connection errors. What happened?
A common scenario at many companies is for a database to be briefly shutdown at night for maintenance (or backup). Unfortunately, when this occurs all of the connections in your application's connection pool are lost. Furthermore, because the connection was broken by the server, the connection pool does not know that the connection has been lost. As a result, the connection pool still thinks that the connection is valid, and will continue to distribute the connection to your application. Not until your application actually attempts to use the connection will it find out that the connection is bad.
Fortunately, there is an easy way to resolve this issue. You need the connection pool test each connection before it lends the connection to your application. With the JDBC Connection Pool, just like with commons-dbcp, this feature can be enabled by setting testOnBorrow to true and validationQuery to a simple test query like SELECT 1 or SELECT 1 FROM DUAL. Alternatively, the validatorClassName property can be used to indicate the full name of the class that will be used to validate connections. The class specified by validatorClassName will need to implement org.apache.tomcat.jdbc.pool.Validator, and can be used to implement any custom validation logic.
Unlike commons-dbcp, the JDBC Connection Pool provides an additional parameter called validationInterval. This parameter allows you to control how frequently a given validation query is executed. By default it is set to 30 seconds; therefore, the given validation query will only run once per connection every 30 seconds.
To illustrate the power of this feature, let's take a look at an example. You have a connection pool configured to validate connections and that pool hands out 10 connections per second to your application. Given this, the pool will execute 10 validation queries per second for a total of 300 queries over a 30 second period. However, if the validation interval is enabled and set to 30 seconds, that means only 10 queries will be run for the same 30 second time period, offering a reduction of 290 queries. Despite the fact that a typical validation query executes quickly, it is still easy to see how this can be a big savings for your application.
When deciding the value to use for the validationInterval property, the following rule can be helpful. Larger values offer better performance, while smaller values decrease the chance of a stale connection being presented to your application.
For example, a value of 60 seconds means that a validation query only needs to run once every 60 seconds for each connection. However, that also means that once a connection is validated it will not be revalidated for another 60 seconds. If a database connection were to be lost one second after it was validated then there would be a period of 59 seconds where the connection would still be considered valid by the connection pool. If a connection were to be borrowed while in this state, use of the connection would fail and the application would get a connection error.
As you can see from the example, picking a value for the validationInterval property is a trade-off and ultimately depends on what is acceptable for your application.

JDBC Interceptors

Another feature specific to the JDBC Connection Pool is the concept of a JDBC Interceptor. From the documentation, “An interceptor is a powerful way to enable, disable or modify functionality on a specific connection or its sub components”. At first glance this definition may seem a bit vague, but what this essentially means is that functionality can be added or removed from the connection pool with only a simple configuration adjustment. Even better, the code does not have to live inside the JDBC Connection Pool JAR. You can create and add custom JDBC Interceptors in the same manner as you would add an interceptor that is bundled with the connection pool.
Enabling an interceptor is easy; add the jdbcInterceptors property to your connection pool configuration and specify a semi-colon separated list containing the names of the interceptors to be used. For example,jdbcInterceptors=”ConnectionState;StatementFinalizer”.
If the interceptor that you are adding resides in the package org.apache.tomcat.jdbc.pool.interceptor specify the short name, as in the previous example. However, if you are adding an interceptor that resides in a difference package, like a custom interceptor, you would just reference the full class name of your interceptor. For example, com.mycompany.interceptors.MyCustomInterceptor.
With that in mind, let's take a look at some of the interceptors that come with the JDBC Connection Pool.

ConnectionState Interceptor

The ConnectionState interceptor is a simple interceptor which caches the properties autoCommitreadOnlytransationIsolation and catalog.
Normally when one of these properties is accessed, the connection must talk to the server and retrieve the requested value. Since this action results in communication over the network, access to these properties can be slow.
The benefit of the ConnectionState interceptor is that the values will be cached locally, allowing faster access and limiting network chatter.

StatementFinalizer Interceptor

The StatementFinalizer interceptor watches for any statement that is created by a connection with the createStatement, prepareStatement or prepareCall methods. It monitors the statements; when the connection is eventually returned to the pool, the interceptor ensures that any statements that were created are properly closed.
This interceptor comes in handy when dealing with legacy or third party applications where statement handling is problematic, but it is not possible for you to fix the code itself.

SlowQueryReport and SlowQueryReportJmx Interceptors

The SlowQueryReport and SlowQueryReportJmx interceptors monitor the amount of time that a query takes to execute, and flag any query that exceed a predefined threshold. The SlowQueryReport interceptor will log any slow queries at the WARN level, while the SlowQueryReportJmx interceptor will produce a JMX notification in addition to the WARN log statement.
I hope that the benefits to these interceptors are obvious. If you have an application in which performance is slow, you can enable this interceptor and automatically get profiling information about the SQL queries being executed by your application.

ResetAbandonedTimer Interceptor

The ResetAbandonedTimer interceptor works in conjunction with the removeAbandoned property. When the removeAbandoned property is enabled, the connection pool will attempt to reclaim connections which have been checked out of the pool for a long period of time. The rationale here is that connections checked out for an extended period of time are typically connections which have not been properly closed by a deployed application. TheremoveAbandoned setting will thus allow you to reclaim connections from badly behaving applications.
Most of the time this works just fine, however the abandoned timer can be tricked by a long running process. Let's say that you have a batch process that takes 20 minutes to execute. What happens when it is still running, but theremoveAbandoned timeout elapses? Unfortunately, the connection will still be reclaimed by the pool.
This is the benefit of the ResetAbandonedTimer interceptor. With it enabled, the abandoned timeout will be reset every time an SQL operation is executed on the connection. Thus enabling the removeAbandoned process to be more accurate, particularly for legitimate long running processes.

Summary

The JDBC Connection Pool is a fantastic addition to Tomcat 7. Not only does it provide an alternative connection pool, but one with superior performance and features. I would encourage any current users of commons-dbcp to give it a try and see how it can benefit their applications.
More information on the JDBC Connection Pool can be obtained from the Tomcat 7 documentation at the following link.



2012년 2월 1일 수요일

Android App interaction with Web

Mobile Device Framework을 구상하고 있다. iSO와 Android 양쪽에서 공통으로 지원하는 기능 들을 정리하고 있는데 그 중에 Web <-> App 간 Interaction 기능을 기술 해보기로 한다.
연동 방식은 App의 Native Code와 Web의 Javascript와 통신하는 방식이다. 때문에 WebView가 javaScript을 실행할 수 있게 설정이 되어 있어야 한다.

WebView.getSettings().setJavaScriptEnable(true);

조금 더 상세히 설명해보기로 해보자.

App에서 Web으로
App에서 “WebView”의 loadUrl을 이용해서 직접적으로 현재 Web Page 내의 JavaScript을 호출한다. App에서 Web 연동은 오직 이 방법 한 가지다.

현재 보고 있는 WebPage에 “f_addProfile()”이라는 JavaScript가 있다고 하면 아래처럼 사용한다.

WebView.loadUrl(“javascript:f_addProfile(‘전달할 인자’)”);

Web에서 App으로
Web에서 App을 호출 하는 방법은 두 가지 방법을 생각 할 수 있겠다. 하나는 정론적인 방식이고 다른 하나는 편법이다.

정론적인 방법
1. App에서 JavaScript에서 호출될 Method을 만든다.
JavaScript과 연동되는 Class는  별도로 Inner Class로 만든다.

private class WebInteractionBridge {
   private final Handler handler = new Handler();   
   public void callMe(final String arg) { // must be final
       handler.post(new Runnable() {
           public void run() {
                // 실행 로직
           }
       });
   }
}

2. WebView에 JavaScript Interface WebInteractionBridge 등록해준다. 여기선 callApp 이라는 이름으로 등록해본다.

WebView.addJavascriptInterface(new WebInteractionBridge(),"callApp");

3. WebPage의 JavaScript에서 호출 해본다. callApp은 JavaScript Interface에 등록된 이름, callMe는 Method 이름이다.

window.callApp.callMe(‘전달 인자’);

편법
WebView에 “shouldOverrideUrlLoading(WebView, String)” Method가 있는데 이는 WebPage 내의 <a href=>로 걸려 있는 Link을 클릭할 때 발생하게 되는 Callback Method다. Link URL은 Method의 String 인자로 전달 받게 됩니다.

1. Custom Link Pattern을 만들어 봅니다.
<a href="toApp://profileAlbum?userid=inter999" >
   - toApp:// → App을 호출한다는 의미
   - profileAlbum → 무엇을 하기 원한다는 의미
   -userid=inter999 → App으로 전달하려는 Data의 {Key=Value} 문자열

2. shouldOverrideUrlLoading(WebView, String)을 Override 합니다.

@Override
public boolean shouldOverrideUrlLoading(WebView view, String u) {

   if (u.startsWith("toApp://profileAlbum")) {
       String param=u.substring(u.lastIndexOf("?")+1);
       userId = param.substring(param.lastIndexOf("=")+1);
       photoUtil.doTakeProfileAlbumAction(); --> 하고자 하는 일
       return true;
   }
   return false;
}

저는 편법을 많이 사용합니다. 이유는? iSO와 Android 모두에게 동일하게 사용되는 WebPage을 만들기에 적합하기 때문입니다.

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...