sonarqube – 코드 최적화하기

2분안에 설정하는 소나큐브

현재 진행중인 안드로이드 프로젝트를 개선하기 위해 소나큐브(http://www.sonarqube.org/)를 사용해보록 하겠습니다.

소나큐브는 프로젝트의 품질을 관리할 수 있도록 여러가지 모니터링 툴을 제공하는 오픈소스 플랫폼입니다. Java를 포함한 20가지가 넘는 프로그래밍 언어 (예: C#, C/C++, Javascript 등)로 제작된 프로젝트의 모니터링을 제공합니다.

참조

현재 환경은
OS : macOS sierra version 10.12.1
JAVA : 1.8


서버 다운로드 링크

https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.1.zip

스캐너 다운로드 링크

https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.8.zip

예제 파일 링크

https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.8.zip

위 파일을 다운로드 후 압축을 풀어준다.

소나큐브 서버 설치하기

$ mkdir ~/sonar
$ cd sonar
$ wget https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-6.1.zip
$ unzip sonarqube-6.1.zip
$ rm sonarqube-6.1.zip

소나큐브 스캐너 설치하기

$ cd ~/sonar
$ wget https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-2.8.zip
$ unzip sonar-scanner-2.8.zip
$ rm sonar-scanner-2.8.zip

소나큐브 샘플 파일 설치하기

$ cd ~/sonar
$ wget https://github.com/SonarSource/sonar-examples/archive/master.zip
$ unzip master.zip
$ rm master.zip

환경변수 설정하기

$ emacs ~/.bashrc

아래 항목들을 파일에 추가해준다.

#sonar-qube
export PATH=/Users/username/sonar/sonarqube-6.1/bin/macosx-universal-64:$PATH
export PATH=/Users/username/sonar/sonar-scanner-2.8/bin:$PATH

소나큐브 서버 시작하기

$ sonar.sh console

소나큐브 프로젝트 스캔하기

프로젝트 위치에서 아래의 명령을 실행해주자.
!아래의 명령은 코드 분석을 시작하는 것이므로 프로젝트에는 이전에 프로젝트 설정파일이 포함되어 있어야 한다.

$ sonar-scanner

소나큐브 프로젝트 파일 생성하기

$ cat project/sonar-project.properties

위 파일안에 아래의 내용들을 추가해주자.

sonar.projectKey=my:project
# this is the name displayed in the SonarQube UI
sonar.projectName=Linkpay
sonar.projectVersion=1.0

# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# Since SonarQube 4.2, this property is optional if sonar.modules is set.
# If not set, SonarQube starts looking for source code from the directory containing
# the sonar-project.properties file.
sonar.sources=.
sonar.exclusions=**/*$$ViewBinder.java,**/*R.java

# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8

sonar.projectKey : 소나큐브 사이트 URL에 포함될 키
sonar.projectName : 소나큐브 사이트에서 보여질 프로젝트 이름
sonar.projectVersion : 소나큐브 사이트에서 보여질 프로젝트 버전
sonar.sources : 프로젝트 경로
sonar.exclusions : 분석 제외할 파일 패턴

끝.

AWS – 이미지 업로드하기 위한 플러그인 설치 및 기타 등등

너무 방대하다 보니 자료가 찾기 힘들더라.
그래서 이와 같이 정리를 한다.

AWS Toolkit for Eclipse
내가 설명한 내용은 간단하게 이클립스 플러그인 설치와 간단한 사용법에 대해서 서술한다.

이클립스가 설치되었다면 이제 플로그인을 설치해보자.
1. Help > Install New Software 선택
2. “Work with”필드에 http://aws.amazon.com/eclipse 입력
3. 조금 기다려보면 AWS Toolkit for Eclipse 항목들이 활성화 되는데 필요한 항목을 선택 후 Next 선택

이렇게 하면 플러그인에 대한 설치가 끝이 난다.

AWS 관련 자료 링크
http://www.slideshare.net/awskorea

Android > 언제 발생 할 지 모르는 오류를 대처하기 위해 파일로 로그를 남기자

상품을 안정화 시키기 위해 여러 가지 방법 중 하나인 로그를 파일로 작성하여, 그 파일을 분석/활용하여 상품 생산성을 높여보자.

이는 실 상품에 적용하기에는 어느 정도 제한이 있고 베타 버전에 적용하도록 한다.


참조

1. 아래 코드는 단순하게 아무 옵션 없이 파일로 작성하고 있다.

public void appendLog(String text) { File logFile = new File("sdcard/log.file"); if (!logFile.exists()) { try { logFile.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { //BufferedWriter for performance, true to set append to file flag BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); buf.append(text); buf.newLine(); buf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }

2. microlog4android 라이브러리를 이용해보자.

사용하기 쉽고 다양한 옵션을 제공한다.

다운로드 및 설명

  1. 메인 액티비티에 아래와 같이 선언해주자.
private static final Logger logger = LoggerFactory.getLogger();
  1. onCreate() 메서드에 아래와 같이 코드를 넣어주자. 이는 환경 설정을 읽어드린다.
PropertyConfigurator.getConfigurator(this).configure();
  1. /assets 폴더에 microlog.properties라는 이름으로 파일을 작성하자. 이 파일은 옵션을 작성하기 위한 파일이다. 그리고 아래와 같이 입력해주자.
    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  2. 실제 로그를 입력하는 방법은 아래와 같다.

logger.debug("M4A");
  1. 퍼미션을 잊지 말자. 이는 파일을 작성하기 위해 권한을 얻는다.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

OS X > 자바 버전 변경하기

아 짜잉나짜잉나짜잉나~~ 환경이 바뀌었어~ 나도 모르는 사이에


Android를 개발할 때는 기본적으로 자바 SDK 1.6을 사용하였지만 Google Appengine을 사용할때는 또 1.7버전이 필요했다.

이것저것 너무 귀찮은 작업의 연속이다. 머 어쩔 수 있나.

바꿔야지

일단 나의 환경은

OS X Mavericks 이다.

일단 자신의 컴퓨터에 어떠한 버전이 설치되어있는지 확인을 해야한다.

# java -version

만약 버전이 낮다면 원하는 버전을 다운받고 나같은 경우는 1.7이 필요하다.

Download Link for the Java 7 JDK

아래는 OS 자체 업데이트 시 설치되는 Java의 경로이다. 기존의 심볼릭 링크를 이용하여 버전을 바뀌는 걸 아래의 해당 경로에서 확인할 수 있다.

# cd /System/Library/Frameworks/JavaVM.framework/Versions/

기존 링크를 백업해두고 아니면 아예 변경해도 무방하다.

# ln -s /Library/Java/JavaVirtualMachines/jdk1.7.0_xx.jdk/Contents/ CurrentJDK

이상.

android – multi touch

구글에 멀티 터치 관련하여 자료를 검색해보면 좌표 반환에 대한 예제는 많이 나옵니다.
그 예제를 이용하여 내가 선택한 위젯(버튼, 뷰 등등), 멀티 위젯 처리를 하는 방법을 소개합니다.

멀티 터치가 아닌 원 터치 콜백 리스너로 기본 (View, Event) 인스턴스를 제공합니다.
그렇다면 멀티 터치에 대한 모든 View들은 어떻게 반환 받을 수 있을가요?

네 저도 모릅니다. 자세하게 찾아보지는 않았지만 저는 터치 좌표값과 뷰의 좌표값을 비교하여 처리하도록 하였습니다.

여기서 주의 할것은 뷰의 구조에 따라 좌표값이 틀리다는 것입니다.
이점 주의하시고 코딩하셔야합니다.

좌표를 얻기 위한 Touch 콜백 메서드
[sourcecode language=”java”]
private final int TOUCH_MAX_NUM = 3;
@Override
public boolean onTouch(View v, MotionEvent event) {
float xEvent[] = new float[ TOUCH_MAX_NUM ];
float yEvent[] = new float[ TOUCH_MAX_NUM ];
switch( event.getPointerCount() ) {
case 1:
xEvent[ 0 ] = event.getX( 0 );
yEvent[ 0 ] = event.getY( 0 );

switch( event.getAction() ) {
case MotionEvent.ACTION_DOWN:
collision(xEvent[0], yEvent[0]);
return true;
default: return super.onTouchEvent( event );
}

case 2:
for (int i=0; i < TOUCH_MAX_NUM; i++) {
xEvent[i] = event.getX(i);
yEvent[i] = event.getY(i);
}
int touchCnt = event.getPointerCount();

switch( event.getAction() ) {
case MotionEvent.ACTION_POINTER_1_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
case MotionEvent.ACTION_POINTER_3_DOWN:
for (int i=0; i < touchCnt; i++) {
collision(xEvent[i], yEvent[i]);
}
break;
default: return super.onTouchEvent( event );
}
default: return false;
}
}
[/sourcecode]
위 함수를 이용하여 x[],y[] 좌표값을 얻어올수 있습니다.
그리고 collision 메서드는 충돌 체크 메서드입니다.

아래는 충돌을 체크하는 메서드
[sourcecode language=”java”]
// getLocationInWindow는 int형 타입의 배열2개를 인자로 받습니다.
private boolean isViewContains(View view, float rx, float ry) {
int[] l = new int[2];
view.getLocationInWindow(l);
int x = l[0];
int y = l[1];
int w = view.getWidth();
int h = view.getHeight();
if (rx < x || rx > x + w || ry < y || ry > y + h) {
return false;
}
return true;
}
[/sourcecode]
위 메서드는 3개의 인자를 받습니다.
View : 두번째 세번째 인자가 해당 뷰에 포함이 되는지 체크하기 위한 인스턴스
x, y : 터치 좌표값
이상입니다.
끝.

참조
android-get-bounding-rectangle-of-a-view
how-to-code-for-multitouch
Making Sense of Multitouch

java – google app engine for xmpp

출처 : http://blog.softwaregeeks.org/archives/530
위 글이 원본이며, 본인 보기 좋게 바꾸었습니다. :)

XMPP

(eXtensible Messaging and Presence Protocol)
사용 사례
– Google Talk
– Facebook

XMPP 참고 자료

* XMPP 샘플

inbound service address
xmpp_message /_ah/xmpp/message/chat/
xmpp_presence /_ah/xmpp/presence/available/
/_ah/xmpp/presence/unavailable/
/_ah/xmpp/presence/probe/
xmpp_subscribe /_ah/xmpp/subscription/subscribe/
/_ah/xmpp/subscription/subscribed/
/_ah/xmpp/subscription/unsubscribe/
/_ah/xmpp/subscription/unsubscribed/

위 테이블은 /war/WEB-INF/web.xml에 들어갈 매핑 URL로 매핑이 되었을 때 해당 서블릿으로 요청을 하게 됩니다.

사용자 등록, 삭제 처리

/war/WEB-INF/web.xml 파일에 서블릿 추가.
[sourcecode language=”xml”]
<servlet>
<servlet-name>SubscriptionServlet</servlet-name>
<servlet-class>com.ezcocoa.xmpp.SubscriptionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SubscriptionServlet</servlet-name>
<url-pattern>/_ah/xmpp/subscription/subscribe/</url-pattern>
</servlet-mapping>
[/sourcecode]

SubscriptionServlet.java
[sourcecode language=”java”]
@SuppressWarnings("serial")
public class SubscriptionServlet extends HttpServlet {

XMPPService xmppService = XMPPServiceFactory.getXMPPService();

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
doPost(request,response);
}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Subscription subscription = xmppService.parseSubscription(request);
String from = subscription.getFromJid().getId();
String to = subscription.getToJid().getId();

System.out.println("From : " + from);
System.out.println("To : " + to);
}
}
[/sourcecode]

구글앱엔진에서 XMPP를 쉽게 처리 하기 위해 XMPPService라는 인터페이스를 제공하며, XMPPServiceFactory를 사용하여 실제 객체를 얻어 사용합니다.

이렇게 해서 하나의 서블릿이 완성되었고, 테스트를 하기 위해 자체 웹서버를 동작시켜 생성된 URL로 접속하시면 테스트가 가능합니다.
[code]
http://localhost:8888/_ah/admin/xmpp
[/code]

java – decompile

자바 디컴파일일 하는 방법을 소개하도록 하겠습니다.

디컴파일을 위해 3가지 Tool 이 필요합니다.
1. AJXMLPrinter2 (Prints XML document from binary XML file – with correct namespace handing & attribute formatting)
위 라이브러리는 바이너리로 된 XML 파일을 사람이 인식할 수 있는 파일로 출력해줍니다.
사용법
[code]java -jar AXMLPrinter2.jar file.xml > output[/code]
2. Undx
위 라이브러리는 .dex 파일을 jar로 변환해주는 역할을 합니다.
사용법
[code]$ java -DASDKLoc={Location of dexdump} -jar undx.jar -f {apkname.apk}[/code]

3. JAD (Java Decompiler)
위 라이브러리는 class파일을 java파일로 변환해주는 역할을 합니다.
사용법
[code]jad -sjava java *[/code]

! decompile 해봅시다.
ex) Android로 예로 들자면 안드로이드는 빌드 후 .apk를 생성하게 됩니다.
사실 .apk파일이나 .jar나 보시면 다 압축(파일의 모음)파일입니다.

압축을 풀고 계층 구조를 보면 아래와 같습니다.
.
|____AndroidManifest.xml
|____Animation.apk
|____classes.dex
|____META-INF
| |____CERT.RSA
| |____CERT.SF
| |____MANIFEST.MF
|____res
| |____anim
| | |____in_from_right.xml
| |____drawable-hdpi
| | |____icon.png
| |____drawable-ldpi
| | |____icon.png
| |____drawable-mdpi
| | |____icon.png
| |____layout
| | |____first_view.xml
| | |____main.xml
| | |____second_view.xml
|____resources.arsc

위 파일들에서 필요한 파일은 classes.dex 파일과 Androidmanifest.xml파일입니다.
classes.dex파일은 파일명 그대로 class파일 모음입니다.
.dex파일은 undx 라이브러리를 이용하여 푸시면 되고
Androidmanifest.xml 바이너리 파일은 AXMLPrinter2 라이브러리를 이용하시면 됩니다.

좀 더 자세한 내용을 남기고 싶었으나 시간 관계로 이만 쓰도록 하겠습니다.
막히는 부분이나 좀더 자세한 설명을 원하시는 경우 글 남겨주세요.

Android – Customize Tab

출처 : http://bakhtiyor.com/2009/10/iphonish-tabs/

안드로이드 탭 호스트를 커스터마이징하는 방법을 소개합니다.

실제 아래로를 보시면 기존 탭 위젯을 숨기고 RadioGroup 위젯을 덧씌우는 방법을 이용하였습니다.
아래는 layout xml 소스입니다.
[sourcecode languagecode=”xml”]
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<FrameLayout android:id="@android:id/tabcontent"
android:layout_width="fill_parent" android:layout_height="0dip"
android:layout_weight="1" android:padding="20dip" android:background="#fff"/>
<RadioGroup android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="horizontal"
android:checkedButton="@+id/first" android:id="@+id/states">
<RadioButton android:id="@+id/first" android:background="@drawable/button_radio"
android:width="80dip" android:height="70dip" />
<RadioButton android:id="@+id/second" android:background="@drawable/button_radio"
android:width="80dip" android:height="70dip" />
<RadioButton android:id="@+id/third" android:background="@drawable/button_radio"
android:width="80dip" android:height="70dip" />
<RadioButton android:id="@+id/fourth" android:background="@drawable/button_radio"
android:width="80dip" android:height="70dip" />
</RadioGroup>
<TabWidget android:id="@android:id/tabs"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_weight="0" android:visibility="gone" />
</LinearLayout>
</TabHost>
[/sourcecode]

layout xml파일안에서 RadioButton 위젯의 버튼을 그리기 위한 방법은 없습니다. 그래서 아래와 같이 Activity에서 설정하도록 하겠습니다.

[sourcecode language=”java”]
private void setupUI() {
RadioButton rbFirst = (RadioButton) findViewById(R.id.first);
RadioButton rbSecond = (RadioButton) findViewById(R.id.second);
RadioButton rbThird = (RadioButton) findViewById(R.id.third);
RadioButton rbFourth = (RadioButton) findViewById(R.id.fourth);
rbFirst.setButtonDrawable(R.drawable.ebay);
rbSecond.setButtonDrawable(R.drawable.flickr);
rbThird.setButtonDrawable(R.drawable.skype);
rbFourth.setButtonDrawable(R.drawable.you_tube);
RadioGroup rg = (RadioGroup) findViewById(R.id.states);
rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, final int checkedId) {
switch (checkedId) {
case R.id.first:
getTabHost().setCurrentTab(0);
break;
case R.id.second:
getTabHost().setCurrentTab(1);
break;
case R.id.third:
getTabHost().setCurrentTab(2);
break;
case R.id.fourth:
getTabHost().setCurrentTab(3);
break;
}
}
});
}
[/sourcecode]

————————–

Iphone-Tab-in-Android