삽질2011.02.20 05:59

요즘 화두가 되고 있는 NoSQL 제품중에서 유명한 Cassandra 를 한번 사용해 보기 위해 관련 자료를 찾았으나 다 이전 버전에 관한 내용만 있더군요. 어렵사리 0.7.x에서 동작하는 예제를 만들어 보았습니다. 저는 0.7.2 버전을 사용하였습니다.

Cassandra에 대한 설명은 : 다른 사이트나 http://blog.naver.com/PostView.nhn?blogId=naverdev&logNo=120116325495&redirect=Dlog&widgetTypeCall=true 를 참고해주세요. 단 예제는 제외!!

본격적으로 삽질을 해보니 이전버전에 비하여 XML 설정에서 YAML 기반 설정으로 바뀌었고 API의 사용법이 바뀌었습니다. 
코딩에 앞서 몇 가지 라이브러리를 클래스 패스에 추가해야 합니다. 모두 cassandra의 lib 디렉토리에 있습니다.

apache-cassandra-0.7.2.jar
libthrift-0.5.jar
log4j-1.2.16.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.1.jar

아래는 예제 소스입니다.

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
import org.apache.cassandra.thrift.ColumnParent;
import org.apache.cassandra.thrift.ColumnPath;
import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.thrift.NotFoundException;
import org.apache.cassandra.thrift.TimedOutException;
import org.apache.cassandra.thrift.UnavailableException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

public class CassandraTest {

        private TTransport framedTransport;
        private Cassandra.Client client;
        
    	private String keyspace = "ggungs";
		private String columnFamily = "friend";
		
        // Cassandra에 연결 후 Client 저장 
        private void open() throws InvalidRequestException, TException {
        	this.framedTransport = new TFramedTransport(new TSocket("localhost", 9160));
			TProtocol framedProtocol = new TBinaryProtocol(framedTransport);
			this.client = new Cassandra.Client(framedProtocol);
			framedTransport.open();
			
			client.set_keyspace(keyspace);
        }
        
        private void close() {
        	framedTransport.close();
        }
        
        public void insert() throws InvalidRequestException, UnavailableException, TimedOutException, TException, NotFoundException {
        	byte[] Key = getUTF8("김동동");
        	long timestamp = System.currentTimeMillis();
			
			ColumnParent cp = new ColumnParent(columnFamily);
			Column c1 = new Column(ByteBuffer.wrap(getUTF8("주소")), ByteBuffer.wrap(getUTF8("서울")), timestamp);
			Column c2 = new Column(ByteBuffer.wrap(getUTF8("핸드폰")), ByteBuffer.wrap(getUTF8("010-0000-0000")), timestamp);
			
			client.insert(ByteBuffer.wrap(Key), cp, c1, ConsistencyLevel.ONE);
			client.insert(ByteBuffer.wrap(Key), cp, c2, ConsistencyLevel.ONE);
        }
        
        public void get() throws InvalidRequestException, UnavailableException, TimedOutException, TException, NotFoundException {
        	byte[] userIDKey = getUTF8("김동동");
        	
			ColumnPath cPath = new ColumnPath(columnFamily);
			cPath.setColumn(ByteBuffer.wrap(getUTF8("주소")));

			ColumnOrSuperColumn cos = client.get(ByteBuffer.wrap(userIDKey), cPath, ConsistencyLevel.ONE);
			Column col=cos.column;
			
			System.out.println("Name : " + getString(col.getName()));
			System.out.println("Value : " + getString(col.getValue()));
        }
        
        private byte[] getUTF8(String s) { 
        	try {
				return s.getBytes("utf-8");
			} catch (UnsupportedEncodingException e) {
				return null;
			}
        }
        
        private String getString(byte[] b) {
        	try {
				return new String(b, "utf-8");
			} catch (UnsupportedEncodingException e) {
				return null;
			}        	
        }
        
        public static void main(String[] args) {
        	try {
        		CassandraTest ct = new CassandraTest();
        		ct.open();
        		ct.insert();
        		ct.get();
        		ct.close();
        	} catch(Exception e) {
        		e.printStackTrace();
        	}
        }
}
이렇게 하고 나면 아마 keyspace가 존재하지 않는다는 예외가 발생합니다. keyspace를 만들지 않았기 때문인데요. cassandra-cli를 실행하여 keyspace 및 column family를 생성하면 됩니다.


connect localhost/9160;
create keyspace ggungs;
use ggungs;
create column family friend;

로컬호스트에 연결하여 ggungs keyspace를 생성하고 생성한 keyspace를 이용합니다. 그리고 friend라는 column family를 생성하는 것입니다.

이렇게 keyspace와 column family를 생성하고 나면 예외없이 주소에 대한 값이 출력될 것입니다.

cli에서는 어떻게 보일까요? list 명령어로 확인하면 아래와 같이 내용이 나옵니다.


첫번째 컬럼은 주소, 두번째 컬럼은 핸드폰에 대한 내용이겠군요!! 


저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2010.03.11 17:38
Windows Mobile 6 SDK로 IE 임베딩된 어플리케이션을 개발하는 도중

웹브라우저의 이벤트에 맞춰 프로그램을 할일 이있어서 웹브라우저 COM 객체에 Advise 하려고 했다.

DTM_BROWSERDISPATCH 메시지로 브라우저 컨트롤의 Dispatch 인터페이스를 얻을 수 있다고 MSDN에 나와있어서

적용해 보았다. (http://msdn.microsoft.com/en-us/library/bb415471.aspx)
		CComQIPtr m_spDispatch;
		CComQIPtr m_spWebBrowser;
		this->m_view.GetBrowserDispatch(&m_spDispatch);
		HRESULT hr = m_spDispatch->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);

당연히 웹브라우저 인터페이스를 얻을 거라는 예상과 달리

hr 의 값은 E_NOINTERFACE 였다.

그래서 구글신께 여쭈어 보았더니 나와 같은 문제를 겪고 있는사람이 아주 많았다. 그리고 뚜렷한 해결책도 없었다.

고민하던 중 다행이 HTML 컨트롤이 제공하는 몇가지 Notify 메세지를 이용하여 처리를 하긴 했지만, 그래도 좀

마음에 걸린다.



저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.09.30 09:41

JSON 라이브러리중 json-simple를 사용했습니다.

다음 도서 검색 OpenAPI를 사용하는 예입니다.
URL url = new URL("http://apis.daum.net/search/book?q=Java&apikey=OEPNAPI_KEY&searchType=title&output=json&result=5pageno=1");
// 한글 처리를 위해 InputStreamReader를 UTF-8 인코딩으로 감싼다.
InputStreamReader isr = new InputStreamReader(url.openConnection().getInputStream(), "UTF-8");

// JSON을 Parsing 한다. 문법오류가 날 경우 Exception 발생, without Exception -> parse 메소드
JSONObject object = (JSONObject)JSONValue.parseWithException(isr);
// 객체
JSONObject channel = (JSONObject)(object.get("channel"));
// item 배열
JSONArray items = (JSONArray)channel.get("item");

for(int i = 0 ; i < items.size(); i++) {
	JSONObject obj1 = (JSONObject)items.get(i);			
	System.out.println(obj1.get("title").toString());
}
json-simple 은 그 이름 자체로 간단하게 json을 사용할 수 있었습니다. 한글 처리 때문에 삽질을 좀 하긴 했지만.....
저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.08.07 15:29

AJAX 비동기 처리를 위한 IXMLHTTPRequest, COM 인터페이스의 하나이기 때문에 웹 브라우저 안에서 뿐 아니라 윈도우즈어플리케이션으로도 구현이 가능합니다.

더욱이 IXMLHTTPRequest는 Windows CE기반의 Windows Mobile에서도 구현이 되어있을 뿐 아니라, IXMLDOMDocument와 같은 XML DOM 인터페이스와도 바로 연결이 가능하므로 윈도우즈 어플리케이션에서 복잡한 Socket처리나, WinInet라이브러리를 별도로 사용하지 않아도 쉽게 웹의 OpenAPI를 사용할 수 있습니다. ( 내부적으로는 WinInet, Socket을 사용합니다. )

http://msdn.microsoft.com/en-us/library/aa924919.aspx : IXMLHTTPRequest 인터페이스 설명

웹의 AJAX와 같이 동기, 비동기 방식을 모두사용 가능할 뿐만아니라 모든 메소드를 제공하고 IStream 방식으로 받아 아래의 포스팅과 같이 파일로 저장할 수도있습니다.

CComQIPtr pDispatch;
CComPtr pXMLHTTP;
CComPtr pXMLDoc;
		
const CComVariant VAL_NULL = NULL;
const CComVariant VAL_FALSE = FALSE;
long length_posts = 0;
CComBSTR bstr;
HRESULT hr;
		
pXMLHTTP.CoCreateInstance(CLSID_XMLHTTP);
		
pXMLHTTP->open(CComBSTR("GET"), CComBSTR("http://me2day.net/api/get_posts/ggungs"), VAL_FALSE , VAL_NULL , VAL_NULL);
hr = pXMLHTTP->send(VAL_NULL);
if(hr != S_OK) {
	//MessageBox(L"전송실패");
	return;
}
			
hr = pXMLHTTP->get_responseXML(&pDispatch);
if(hr == E_PENDING) {
	//MessageBox(L"PENDING");
	return;
}
		
pDispatch->QueryInterface(IID_IXMLDOMDocument, (void **)&pXMLDoc);
pDispatch.Release();

if(pNodeList) { pNodeList.Release(); }
pXMLDoc->selectNodes(L"/posts/post", &pNodeList);
pNodeList->get_length(&length_posts);
		
 ..... // XML 처리
		
pXMLDoc.Release();
pXMLHTTP.Release();

 

위의 예는 동기 방식으로 미투데이 OpenAPI에 접속하여 XML 데이터를 가져와서 XML 파싱하는 예입니다.

물론 AJAX의 꽃인 비동기 처리로 onreadystatechange에 자바스크립트처럼 함수가 호출되도록 할 수 있지만 VC++ 에서는 좀 복잡하게 처리해야 할듯 합니다.
(http://www.ookii.org/post/using_ixmlhttprequestonreadystatechange_from_c.aspx 참고)

IXMLHTTPRequest 인터페이스를 잘 사용하면 HTTP 프로토콜 로직 처리를 안해도 되기 때문에 빠르게 개발가능합니다.

저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.08.04 00:24

SHCreateStreamOnFile 함수로 지정된 파일에 대한 IStream 인터페이스를 얻은 다음 CopyTo 메소드로 스트림을 복사합니다. (http://msdn.microsoft.com/en-us/library/bb759864(VS.85).aspx)

	pStreamSrc = ........

	STATSTG StatInfo;
	CComPtr pStreamDest;
	hr = SHCreateStreamOnFile(L"C:\\profile.png", STGM_WRITE | STGM_CREATE, &pStreamDest) ;
	pStream->Stat(&StatInfo, STATFLAG_NONAME );
	pStream->CopyTo(pStreamDest, StatInfo.cbSize, NULL, NULL);
	pStreamDest->Commit(0);

Windows Mobile 에서는 SHCreateStreamOnFile 함수가 없어서 직접 구현해야 합니다.

http://www.pocketpcdn.com/articles/articles.php?&atb.set(a_id)=6211&atb.set(c_id)=57&atb.perform(details)

참고해주세요.

저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.07.11 23:39

처음 Windows Mobile에서 Common Dialog Box 를 사용하시는 분들이라면 메세지 처리를 한번 보셔야 할 것 같습니다.

당연히 일어나야 할 것 같은 메세지가 일어나지 않는다면 의심해 보세요. 현재 Windows Mobile 에서는 2개의 Common Dialog Box 메세지 만을 제공합니다.

CDM_SETDEFEXT

This message sets the default filename extension for an Explorer-style Open or Save As common dialog box.

CDN_TYPECHANGE

This message is sent by an Explorer-style Open or Save As common dialog box when the user selects a new file type from the file types combo box.


위에는 메세지고 밑에껏은 Notify 메세지 입니다. 둘 다 File Dialog Box에서 쓰이는 군요.

http://msdn.microsoft.com/en-us/library/aa931534.aspx

저는 당연히 Dialog Box 가 초기화 되면 Notify Message가 발생할 줄 알고 잘못된 점이 제 코드 인줄 알고 WTL 소스를 뒤지기 시작하는 가 하면 ( WTL은 Overriding 으로 편하게 File Dialog Message를 처리할 수 있습니다. ) Remote Spy++ 까지 써가면서 관찰했는데 메세지 자체가 안일어 나는 것 같아서 찾아보니 이렇네요.

저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.06.15 23:03

하루종일 삽질 삽질을 거듭하여 샘플정도로 간단하게 만들어 봤습니다.

CComPtr m_pImgFactory;
CComPtr image;
m_pImgFactory->CreateImageFromFile(filename, &image);

CComQIPtr pBitmap;
CComPtr pBitmapOps;

// 불러온 Iimage로 IBitmapImage 생성
m_pImgFactory->CreateBitmapFromImage(image, 0, 0, PixelFormatDontCare, InterpolationHintNearestNeighbor, &pBitmap);
pBitmap->QueryInterface(IID_IBasicBitmapOps, (void**)&pBitmapOps);
pBitmap.Release();

// 이미지 90도 회전
pBitmapOps->Rotate(90, InterpolationHintNearestNeighbor, &pBitmap);
image.Release();
pBitmapOps.Release();

pBitmap->QueryInterface(IID_IImage, (void**)&image);
		
// 인코딩 코덱 찾기
ImageCodecInfo * codecinfo;
UINT count;
CLSID clsid;
m_pImgFactory->GetInstalledEncoders(&count, &codecinfo);

for(UINT i = 0; i < count ; i++) {
	// JPEG 코덱 찾기
	if(wcscmp(codecinfo[i].MimeType, _T("image/jpeg")) == 0) {
		clsid = codecinfo[i].Clsid;
				
		break;
	}
}
free(codecinfo);

// 인코딩할 파일 저장
CComPtr pEncoder;
m_pImgFactory->CreateImageEncoderToFile(&clsid, _T("파일명"), &pEncoder);

// 인코딩할 이미지 싱크 생성
CComPtr pImgSink;
pEncoder->GetEncodeSink(&pImgSink);
// 기존의 이미지를 이미지 싱크로 보냄
image->PushIntoSink(pImgSink); 
pImgSink.Release();
// 인코딩 종료
pEncoder->TerminateEncoder();
pEncoder.Release();

 

회전 한 파일이 파일명으로 바로 저장됩니다.

저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.06.14 20:06
WindowsMobile 에서만 쓸수있는 SHLoadImageFile 이라는 함수가 있습니다. 이 함수는 편리하게 파일 이름만 넣으면 PNG, JPG, GIF등을 지원해서 편리하게 HBITMAP 형식으로 리턴해 줍니다. 하지만 파일 전체를 무조건 로드합니다.

http://msdn.microsoft.com/en-us/library/aa455003.aspx

윈도우즈 모바일 5 부터 사용할 수 있다고 하지만 그 전에도 undocumented function 으로 사용가능 했던 것 같습니다.(구글신 검색결과)


		// 사진 파일을 지정
		HBITMAP h = ::SHLoadImageFile(filename);
		if(h != NULL) {
			m_photoImage.Attach(h);
		}
		else {
			MessageBox(_T("사진 파일을 불러오지 못했습니다."), _T("Me2PocketUploader"), MB_ICONWARNING);
		}

용량이 큰(실험 결과 1Mbyte 정도) 이상의 파일을 SHLoadImageFile로 로드하면 무조건 NULL이 리턴되었습니다. 

GetLastError로 조사해도 핸들이 잘못되었다는 메시지만 출력합니다. 어리 둥절했던 것은 에뮬레이터에서는 불러오다가 못불러오다가 했습니다. 생각해보니 메모리 용량 때문인거 같습니다. JPG파일 200kb 정도라도 실제 BITMAP으로 디코딩 될때의 메모리 점유는 3Mbyte에 육박 했습니다. 그래서 구글신께 여쭈어서 찾고 찾은것이 Windows CE의 Image API 입니다.

IImagingFactory의 CreateImageFromFile http://msdn.microsoft.com/en-us/library/aa452215.aspx , 로 얻은 IImage 인터페이스의 GetThumbnail함수로 썸네일을 바로 가져왔습니다. 큰 이미지 파일이라도 썸네일로 크기에 맞가 가져오므로 부담이 적습니다. 그래서 메모리 사용량도 상당히 줄었습니다.

저는 WTL을 사용해서 프로그래밍 했기 때문에ATL의 편리한 CComPtr이나 CComQIPtr등 COM이용에 편리한 클래스를 사용 했습니다.

#include 
#include 
#include 

CComPtr m_pImgFactory;
CComPtr m_pImage;
RECT m_photoRect;

// ImageFactory 생성
m_pImgFactory.CoCreateInstance(CLSID_ImagingFactory);

CComPtr image;
m_pImgFactory->CreateImageFromFile(filename, &image);

// 썸네일 생성	
if(image->GetThumbnail(m_photoRect.right - m_photoRect.left, m_photoRect.bottom - m_photoRect.top, &m_pImage) == S_OK) {
	m_photoFilename = filename;
	InvalidateRect(NULL); // OnPaint
}

// 지정된 DC와 영역에 그림을 그림
::GetWindowRect(GetDlgItem(IDC_PHOTO), &m_photoRect);
m_pImage->Draw(hDC, &m_photoRect, NULL);


Image API의 IBasicBitmapOps인터페이스(http://msdn.microsoft.com/en-us/library/ms939536.aspx)를 사용하면


Grouping Methods
Color Control AdjustBrightness

AdjustContrast

AdjustGamma

Manipulation Clone

Flip

Resize

Rotate


이런 것들을 할 수 있네요. 나중에 해봐야 겠습니다. +_+
저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
삽질2009.06.08 20:37

Me2PocketUploader 윈도우즈 모바일 버전을 개발하면서 마블(이전은 인텔)의 PXA시리즈 CPU에서는 잘 동작하는 기능이 퀄컴의 MSM시리즈(MSM7200)칩에서는 의도하지 않은 동작을 하였습니다. 어차피 둘다 태생은 ARM 아키텍처 이지만 말입니다. 그것도 무적전설님이 알려주기 전까지는 몰랐습니다.
문제의 코드는 다음과 같습니다.
		// 댓글 닫기
		if(setCloseComment) {
			m_HTTP->AddGetData("close_comment", "true");
		}

 

setCloseCommnet 값이 BOOL값이라 BOOL값은 또 int로 정의되어 있기에 저렇게 작성했었는데, 퀄컴의 MSM CPU에서는 계속 댓글이 닫히는 문제가 생기는 것입니다. setCloseCommnet값이 FALSE라도 실행이 되어버렸던 것이지요. 전 이문제를 단순히 CPU의 아키텍처가 틀려서 라고 생각을 하고 있다가, 다음과 같이 명확하게 TRUE값을 검사했습니다.

		// 댓글 닫기
		if(setCloseComment == TRUE) {
			m_HTTP->AddGetData("close_comment", "true");
		}

 

잘 되는군요... 문제는 역시 저의 코딩 버릇이었습니다. 좀더 명확한 코드를 작성하도록 노력해야겠습니다.!! 테스트 해주신 무적전설님 감사합니다.

저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
TAG C, IF, msm7200, PXA, WM
삽질2009.05.29 21:02
http://sourceforge.net/project/shownotes.php?release_id=680959&group_id=109071

- changed version number
- updated CPL link in headers
- fixed warning for _vstprintf
- added wizard setup programs for VS2008

WTL 8.1이 출시 되었네요.

다운로드는 : http://sourceforge.net/project/showfiles.php?group_id=109071&package_id=321560&release_id=680959

WTL 개발을 쉽게 해주는 WtlWiz, WTL Helper 가 2008 용으로 나왔으면 좋겠습니다. ( 이것때문에 2005를 아직 쓰고 있어요!! )

WTL Helper 는 코드 프로젝으에 소스가 공개되어있어서 2008용으로 어느 용자분깨서 바꾸어 주신게 있지만, WTL Helper와 궁합을 맞추는 WtlWiz는 소스가 공개되어있지 않아서 2008용이 없네요.

http://salos.narod.ru/eng/WtlWiz/WtlWiz.html : 제작자 홈페이지, 바쁘신듯 업데이트가 없네요.
저작자 표시 비영리 변경 금지
신고
Posted by 꿍스
TAG WTL