'분류 전체보기'에 해당되는 글 2491건

  1. 2010.10.19 Eclipse Helios와 JDK 6u21를 사용할 때 OutOfMemory 오류가 발생하는 문제
  2. 2010.10.19 [jQuery 기본 강좌]1-3 jquery 자동완성 autocomplete 기능 쉽게 적용하기
  3. 2010.10.19 Javascript에서 String을 Number타입으로 바꾸기
  4. 2010.10.18 웹서비스 관련
  5. 2010.10.18 안드로이드 UI 디자인 패턴
  6. 2010.10.18 안드로이드 UI 개발 노하우 및 트렌드 분석
  7. 2010.10.11 1.XHTML1.1 에서 사용하면 안되는 것들
  8. 2010.10.11 input 안에 'autocomplete' 사용시 w3c 에 위배되는거 수정...
  9. 2010.10.06 Lucy-XSS Filter 1
  10. 2010.10.05 Markup Validation Service
  11. 2010.09.27 ip address 가 맞는지 확인 정규식 표현을 이용해..
  12. 2010.09.27 isValidEmailAddress 이메일 형식이맞는지 확인
  13. 2010.09.27 FilterLog.java 1
  14. 2010.09.24 WebService] Apache Axis2 사용하기
  15. 2010.09.24 AXIS2를 이용한 웹서비스 개발
  16. 2010.09.24 RESTful Web services: The basics 1
  17. 2010.09.24 Java에서 RESTful 웹 서비스 구현하기
  18. 2010.09.24 GET방식의 RESTful 웹서비스 구현하기 2
  19. 2010.09.24 [Android] 웹서버에서 이미지 파싱해오기 간단예제 ! 2
  20. 2010.09.24 Ejb, Android and Web Services
  21. 2010.09.24 How-to: Pure Html Android Application
  22. 2010.09.24 How-to: Android as a RESTful Client
  23. 2010.09.09 jQuery 싸이트 모음
  24. 2010.09.02 IntelliJ IDEA
  25. 2010.09.02 Jetty를 사용하여 Windows Azure에서 JSP 사이트 구축하기
  26. 2010.09.02 Hdiv 2
  27. 2010.09.02 HDIV HTTP Data Integrity Validator
  28. 2010.08.26 FreeMarker 확장자 FTL 사용법
  29. 2010.08.26 freemarker 설명 및 기본 예제, 확장자 FTL
  30. 2010.08.20 Facebook의 실시간 웹 프레임워크 ‘Tornado’
56. Eclipse Etc.../Eclipse2010. 10. 19. 16:23
반응형
지난 6월 23일에 발표된 Eclipse 3.6 Helios 를 슬슬 사용해 보려고 새로운 마음으로 JDK도 JDK 6 Update 21 을 다운받아서 설치하고 기존에 사용하던 프로젝트를 저장소에서 Checkout받자 프로젝트를 생성하던 도중 이클립스가 죽어버리는 현상이 발생했습니다. (Subclipse, m2eclipse 사용중)

기존에도 종종 이클립스는 메모리오류가 발생하였기 때문에 아무생각없이 eclipse.ini파일을 수정하여 주었지만 좀처럼 해결되지 않고 계속 프로젝트를 받아오다가 번번히 죽어버렸습니다. 로그파일을 확인하니(.log파일은 workplace안에 .metadata폴더 안에 있습니다.) 아래와 같은 오류가 발생하였습니다.

java.lang.OutOfMemoryError: PermGen space


기존의 eclipse.ini파일의 수정으로는 도저히 해결이 되지 않아서 Helios가 안정적이지 않은 것으로 막연히 생각하고 있었는데 트위터를 통해서 해당 문제에 대한 해결책 을 얻을 수 있었습니다.

이 문제는 JDK 6u21에서 발생하는 문제인데 6u21에서 vendor명이 기존의 Sun에서 Oracle로 변경이 되었습니다. Eclipse 런처가 JVM의 벤더를 읽어서 Sun JVM일 경우에는 추가적으로 이클립스의 동작을 위해 필요한 XX:MaxPermSize 설정을 추가하는데 6u21에서는 Sun이 아닌 Oracle로 변경이 되어 이 설정이 먹히지 않는 것입니다. 이 내용은 이클립스의 버그로 등록은 되었지만 9월에 예정된 Helios SR1에서 수정될 예정은 없어보인다고 합니다.

이클립스의 폴더안에 있는 eclipse.ini파일을 열어서 아래의 부분을 삭제합니다.

--launcher.XXMaxPermSize
256m

그 다음에 -Xmx설정뒤에 -XX:MaxPermSize=512m 를 추가하면 위의 OutOfMemoryError를 피할 수 있습니다.

아래 내용은 참고용으로 올리는 저의 eclipse.ini파일입니다.
  1. -startup  
  2. plugins/org.eclipse.equinox.launcher_1.1.0.v20100507.jar  
  3. --launcher.library  
  4. plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.0.v20100503  
  5. -product  
  6. org.eclipse.epp.package.jee.product  
  7. --launcher.defaultAction  
  8. openFile  
  9. --launcher.XXMaxPermSize  
  10. 128M  
  11. -showsplash  
  12. org.eclipse.platform  
  13. -vm  
  14. C:\Program Files\Java\jdk1.6.0_21\bin\  
  15. --launcher.defaultAction  
  16. openFile  
  17. -vmargs  
  18. -Dosgi.requiredJavaVersion=1.5  
  19. -Xms40m  
  20. -Xmx512m  
  21. -XX:MaxPermSize=256m  

이 문제는 Windows플랫폼에서만 발생한다고 합니다.



추가로 봄싹 의 김성호님이 공유해 주신 이클립스 위키에 위 문제의 해결법 에 대해서 잘 나와있습니다.

  1. 6u20으로 다운그래이드
  2. eclipse.ini에  -XX:MaxPermSize=256m 추가
  3. 수정된된 이클립스용 dll을 다운받아 사용
이렇게 3가지 방법숭 하나를 사용하라고 권하고 있습니다.


출처 : http://blog.outsider.ne.kr/497?category=34
Posted by 1010
반응형
 


네이버나 포탈사이트 등을 방문 하다보면 위와같이

앞글자 혹은 중간글자만 쳐도 나머지 글자들이 나오는 화면을 볼수있는데

이를 자동완성기능 혹은 autocomplete 라고 한다..

기본적으로 브라우저내에서 자동완성기능을 지원하긴 하지만

DB와 연동해서 뿌려주는 기능은 별도 제작을 해야한다.

캐릭터셋이 utf-8 이냐 euc kr 이냐에 따라서도 사용방법이 약간은 다르다.

아래는 간단한 예제와 샘플파일이다.


위 파일은 autocomplete 기능을 사용하게 해주는 plug in 이며

jquery.com 의 plugins 에서도 다운이 가능하다.

우선 jquery 스크립트를 넣어준 뒤 위 플러그인을 삽입해주면 된다.

<?include "data_js.php";?>

<SCRIPT type="text/javascript" src="../jquery/jquery-1.4.2.min.js"></script>
<link rel="stylesheet" type="text/css" href="./autocomplete/jquery.autocomplete.css"/>
<script type="text/javascript" src="./autocomplete/jquery.autocomplete.js"></script>

<script type="text/javascript">
$(document).ready(function() {
 $("#search").autocomplete(goods,{
  matchContains: true
 });
});
</script>

<input type="text" id="search" autocomplete="off">

* 상세소스는 http://jaweb.co.kr/jstudy/18.php 접속후 소스보기하면 다 나오는데
위의 소스만으로도 구동에는 전혀 문제가 없다.


위 내용은 search 라는 id 필드는 autocomplete 기능을 사용할 것이고

데이터는 goods 데이터를 기반으로 내용중 일부라도 맞는경우 (matchContains: true)

보여지게 하겠다는 속성이다.

데이터(goods)를 가져올때는 여러가지 방법이 있는데

난 DB에서 데이터 이용방법과 js 파일 생성방식 두가지로 선택했다.


data_js.php 파일은  단순하게 파일내에 입력을 하게되면 알아서 적용된다. (내용이 간단하니 파일을 참고하면 좋다.)


data_db.php 파일은 db셋팅이 되어있는 파일내에서 어느부분인지를 선택 한 뒤 작업을 해주면 된다.

헌데 소스내용을 보면 굳이 urlencode 를 해서 array_push로 배열안에 값을 넣고

실제 뿌려줄때는 urldecode 를 해서 json 방식으로 다시 인코딩 한 뒤 값을 뿌려준다.

urlencode 의 사용목적은 바로 한글문제..

utf-8 환경에선 urlencode 없이도 무리없이 정상작동 하지만

euckr 환경에선 글씨가 깨져서 들어가거나

null값으로 출력이되어 오류가 나게 된다.


그럴때 json으로 인코딩을 하기 전 urlencode 로 한번 인코딩을 해주고

실제 뿌려줄때 decode를 안하게되면 %45%D 이런식으로 문자가 깨져서 보이기에

글씨 깨짐을 방지하기 위해서 위와같이 작업을 한것이다.


autocomplete 플러그인 내에서는 지원하는 기능이 내가 설명한 정도보다는 훨씬 많다.

줄에 맞춰서 값을 가져오거나

key값에 따라 값을 뿌려주는 기능...

이미지를 이용 출력해는 기능 등~   (참고 : http://jaweb.nayana.com/search.php   우측상단 펫 검색란에 1,2 등을 치거나 펫 이름을 치면 결과가 나오는데.. jquery 처음 배울때 작업한 것이라 소스가 상당히 조잡한 편이다.)

쓸데가 상당히 많아보이는 플러그인이니 공부할때 참고하면 좋을 것 같다.


출처 : http://jaweb.tistory.com/159

------------------------------------------------------

Ajax AutoComplete for jQuery

AutoComplete is like Magic!

Ajax Autocomplete for jQuery allows you to easily create autocomplete/autosuggest boxes for text input fields.

It is built with focus on performance. Results for every query are cached and pulled from local cache for the same repeating query. If there are no results for particular query it stops sending requests to the server for other queries with the same root.

Demo

Ajax autosuggest sample (start typing country name):


Local(no ajax) autosuggest sample (start typing month name):

Suggest:   

Note: Delimiter support has been added in v1.0.5. Try separate countries by "," or ";".

What's New in 1.1

$('#query').autocomplete(options) now returns an Autocomplete instance only for the first matched element.

Autocomplete functionality can be disabled or enabled programmatically.

var ac = $('#query').autocomplete(options);
ac.disable();
ac.enable();

Options can be changed programmatically at any time, only options that are passed get set:

ac.setOptions({ zIndex: 1001 });

If you need to pass additional parameters, you can set them via setOptions too:

ac.setOptions({ params: { first:'John', last:'Doe' } });

New parameters when initializing autocomplete. They can also be set via setOptions.

- zIndex: default value is 9999.

- fnFormatResult: function that formats values that are displayed in the autosuggest list. It takes three parameters: suggested value, data and current query value. Default function for this:

var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');

function fnFormatResult(value, data, currentValue) {
  var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
  return value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
}

Installation

Include jQuery in your header. After its included, add autocomplete script.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.autocomplete.js"></script>

How to Use

Here is an Ajax Autocomplete sample for the text field with id "query"

<input type="text" name="q" id="query" />

Create an instance of the Autocomplete object. You can have multiple instances on a single page.

Important: Autocomplete must be initialized after DOM has finished loading. Otherwise you will get an error in IE.

var options, a;
jQuery(function(){
  options = { serviceUrl:'service/autocomplete.ashx' };
  a = $('#query').autocomplete(options);
});

You can add extra options:

  var a = $('#query').autocomplete({ 
    serviceUrl:'service/autocomplete.ashx',
    minChars:2, 
    delimiter: /(,|;)\s*/, // regex or character
    maxHeight:400,
    width:300,
    zIndex: 9999,
    deferRequestBy: 0, //miliseconds
    params: { country:'Yes' }, //aditional parameters
    noCache: false, //default is false, set to true to disable caching
    // callback function:
    onSelect: function(value, data){ alert('You selected: ' + value + ', ' + data); },
    // local autosugest options:
    lookup: ['January', 'February', 'March', 'April', 'May'] //local lookup values 
  });

Use lookup option only if you prefer to inject an array of autocompletion options, rather than sending Ajax queries.

Web page that provides data for Ajax Autocomplete, in our case autocomplete.ashx will receive GET request with querystring ?query=Li, and it must return JSON data in the following format:

{
 query:'Li',
 suggestions:['Liberia','Libyan Arab Jamahiriya','Liechtenstein','Lithuania'],
 data:['LR','LY','LI','LT']
}

Notes:

  • query - original query value
  • suggestions - comma separated array of suggested values
  • data (optional) - data array, that contains values for callback function when data is selected.

Styling

Script generates the following HTML (sample query Li). Active element when you navigate up and down is marked with class "selected". You can style it any way you wish.

<div class="autocomplete-w1">
  <div style="width:299px;" id="Autocomplete_1240430421731" class="autocomplete">
    <div><strong>Li</strong>beria</div>
    <div><strong>Li</strong>byan Arab Jamahiriya</div>
    <div><strong>Li</strong>echtenstein</div>
    <div class="selected"><strong>Li</strong>thuania</div>
  </div>
</div>

Here is style used in the sample above:

.autocomplete-w1 { background:url(img/shadow.png) no-repeat bottom right; position:absolute; top:0px; left:0px; margin:6px 0 0 6px; /* IE6 fix: */ _background:none; _margin:1px 0 0 0; }
.autocomplete { border:1px solid #999; background:#FFF; cursor:default; text-align:left; max-height:350px; overflow:auto; margin:-6px 6px 6px -6px; /* IE6 specific: */ _height:350px;  _margin:0; _overflow-x:hidden; }
.autocomplete .selected { background:#F0F0F0; }
.autocomplete div { padding:2px 5px; white-space:nowrap; overflow:hidden; }
.autocomplete strong { font-weight:normal; color:#3399FF; }

If you will use this CSS, please make sure to correct path to the shadow.png image. Image is included in the package. It uses CSS Drop Shadow technique by Sergio Villarreal.

Download

Download Ajax AutoComplete for jQuery

Download DevBridge Ajax Autocomplete v1.1.3 for jQuery

Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.

Currently supported browsers: IE 7+, FF 2+, Safari 3+, Opera 9+


Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Posted by 1010
반응형
누가 물어봐서 찾아본 김에 그냥 정리합니다. 아시다시피 Javascript는 명시적인 타입정의가 없습니다. int나 String같이 타입을 명시해서 변수를 정의하지 않고 그냥 var타입으로 정의하면 Javascript가 알아서 적절한 타입을 지정합니다. 명시적인 타입이 없다는건 때론 타입때문에 헷갈리기도 하고 원치 않는 결과가 나타나기도 합니다.

그래서 보통은 약간 편법적인 방법으로 String을 Number로 바꾼다던지 Number를 String으로 바꾼다던지 합니다.

  1. // 숫자를 스트링로 바꾸기  
  2. var tt = 2  
  3. tt += "";  
  4. alert(typeof tt);   // Result : string  
  5.  
  6. // 스트링을 숫자로 바꾸기  
  7. tt = "2" 
  8. tt *= 1;  
  9. alert(typeof tt);    // Result : number  

위의 방법이 가장 간단하게 형변환을 하는 방법입니다. 쉽게 자바스크립트의 자동형변환을 이용한 겁니다. 숫자타입에 문자열을 더하면 결과가 문자열이 되고 문자열에 숫자를 곱하면 숫자타입이 되는 특성을 이용해서 결과는 달라지지 않게 타입만 변환되도록 한 것입니다.

해본 사람을 보면 알기는 하겠지만 잘 모르는 사람이 보면 어떤 의도로 한 소스인지 명확하지 않은 단점이 있기도 하고 좀더 명시적으로 타입변환이 필요할 때가 있습니다.

  1. // 숫자를 스트링로 바꾸기  
  2. var tt = 2  
  3. alert(typeof tt);    // Result : number  
  4. tt = String(tt);  
  5. alert(typeof tt);    // Result : string  
  6.  
  7. // 스트링을 숫자로 바꾸기  
  8. tt = "2" 
  9. alert(typeof tt);    // Result : string  
  10. tt = Number(tt);  
  11. alert(typeof tt);    // Result : number  

타입변환을 하는 함수인 Number()와 String()을 이용한 소스입니다.



또한 아래처럼 parseInt()나 parseFloat()를 이용해서도 형변환을 할 수 있습니다. 함수명에서 알 수 있듯이 parseInt()는 Integer타입으로 변환을 하고 parseFloat()는 Float타입으로 변환을 합니다.
  1. var tt = "2" 
  2. alert(typeof tt);    // Result : string  
  3. tt = parseInt(tt);  
  4. alert(typeof tt);    // Result : number  
  5.               
  6. tt = "2" 
  7. alert(typeof tt);    // Result : string  
  8. tt = parseFloat(tt);  
  9. alert(typeof tt);    // Result : number  

parseInt()나 parseFloat()는 형변환 자체가 목적은 아니기 때문에 얘기가 나온 김에 좀 더 살펴보겠습니다. parseIn()와 parseFloat()는 정수와 실수로 파싱해 주는 역할을 하고 있습니다.

parseInt(string, radix)
parseFloat(string)

API정의를 보면 위처럼 정의되어 있습니다. parseInt()에서 radix는 기수로 parse할 때 기준이 되는 진수입니다. 정수로 파싱하는 parseInt에만 정의되어 있습니다. 2~ 36진수까지를 정의할 수 있고 optional값으로 없을 경우 10진수로 parse합니다.

  1. parseInt("123.456");        // 123  
  2. parseInt("100mile");        // 100  
  3. parseInt("w25");               // NaN  
  4. parseInt("05");                  // 5  
  5. parseInt("09");                  // 0  
  6. parseInt("0x35");              // 53  
  7. parseInt("1101", 2);         // 13  
  8. parseInt("09", 10);            // 9  
  9. parseInt("10", 8);              // 8  
  10.  
  11. parseFloat("123.456");       // 123.456  
  12. parseFloat("100.5mile");    // 100.5  
  13. parseFloat("w25");               // NaN  
  14. parseFloat("05");                  // 5  
  15. parseFloat("09");                  // 9  
  16. parseFloat("0x35");              // 0  

Javascript에서 "0"으로 시작하는 숫자는 8진수 "0x"로 시작하는 숫자는 16진수로 정의되고 있기 때문에 5번라인에서 9가 8진수에서 사용할 수 없기 때문에 의도하지 않은 0이 나왔습니다.


출처 : http://blog.outsider.ne.kr/361
Posted by 1010
01.JAVA/Java2010. 10. 18. 15:13
반응형
Posted by 1010
04.Anddoid/UI2010. 10. 18. 11:16
반응형

안드로이드 UI 디자인 패턴

이 세션에서는 안드로이드 UX팀이 훌륭한 안드로이드 어플리케이션을 작성하기 위해 사용할수 있는 패턴의 유형을 보여줄 것이다. 인터엑티브한 Titlebar, 빠른 주소록, Bottom bar 와 같은 google I/O에서만 볼수 있는 몇가지 새로운 패턴들을 어떡해 사용하는지를 살펴 볼 것이다.

참가자 요구사항 : 자바에 능숙하고 안드로이드 기본 개념을 명확히 이해해야 한다.

첨부파일 (1)

Posted by 1010
04.Anddoid/UI2010. 10. 18. 11:15
반응형
Posted by 1010
반응형
  1. XHTML1.1 에서 사용하면 안되는 것들
    1. 일반적으로 범하기 쉬운 오류
      1. 닫히지 않은 빈요소 - Not closing empty elements (elements without closing tags)
      2. 닫히지 않은 꽉 찬 요소 - Not closing non-empty elements
      3. 부적합한 함유 요소 - Improperly nesting elements (elements must be closed in reverse order)
      4. 대체 텍스트가 기술되지 않음 - Not specifying alternate text for images (using the alt attribute, which helps make pages accessible for devices that don't load images or screen-readers for the blind)
      5. 본문에 직접 텍스트를 삽입 - Putting text directly in the body of the document
      6. 인라인 요소에 블록-레벨 요소를 포함 - Nesting block-level elements within inline elements
      7. 속성 값을 인용부호로 감싸지 않음 - Not putting quotation marks around attribute values
      8. '&' 문자를 직접 사용 ('&amp;'로 대체) - Using the ampersand outside of entities (use &amp; to display the ampersand character)
      9. 태그 이름이나 태그 속성에 대문자를 사용 - Using uppercase tag names and/or tag attributes
      10. 간소화된 속성 사용 - Attribute minimization
    2. 그 외의 오류들
      1. <form 에 name속성 사용하지 못함 - 2009/02/21 07:28:08
      2. <style> 사용 불가능
      3. URL 주소에서도 '&' 문자를 직접 사용하면 안됨.
      4. <form 에서 method="POST/post"
      5. width= 엘리먼트 허용하지 않음

 

XHTML1.1 에서 사용하면 안되는 것들#

 XHTML에서 사용하면 안되는 것들이 있다. 여기에 나열해 보자.

 

일반적으로 범하기 쉬운 오류#

 아래는 일반적으로 범하기 쉬운 오류로 위키백과에 소개된 내용이다. - http://ko.wikipedia.org/wiki/XHTML

 

닫히지 않은 빈요소 - Not closing empty elements (elements without closing tags)#
  • 틀림: <br>
  • 옳음: <br />

 

닫히지 않은 꽉 찬 요소 - Not closing non-empty elements#
  • 틀림: <p>This is a paragraph.<p>This is another paragraph.
  • 옳음: <p>This is a paragraph.</p><p>This is another paragraph.</p>

 

부적합한 함유 요소 - Improperly nesting elements (elements must be closed in reverse order)#
  • 틀림: <em><strong>This is some text.</em></strong>
  • 옳음: <em><strong>This is some text.</strong></em>

 

대체 텍스트가 기술되지 않음 - Not specifying alternate text for images (using the alt attribute, which helps make pages accessible for devices that don't load images or screen-readers for the blind)#
  • 틀림: <img src="/skins/common/images/poweredby_mediawiki_88x31.png" />
  • 옳음: <img src="/skins/common/images/poweredby_mediawiki_88x31.png" alt="MediaWiki" />

 

본문에 직접 텍스트를 삽입 - Putting text directly in the body of the document#
  • 틀림: <body>Welcome to my page.</body>
  • 옳음: <body><p>Welcome to my page.</p></body>

 

인라인 요소에 블록-레벨 요소를 포함 - Nesting block-level elements within inline elements#
  • 틀림: <em><h2>Introduction</h2></em>
  • 옳음: <h2><em>Introduction</em></h2>

 

속성 값을 인용부호로 감싸지 않음 - Not putting quotation marks around attribute values#
  • 틀림: <td rowspan=3>
  • 옳음: <td rowspan="3">

 

'&' 문자를 직접 사용 ('&amp;'로 대체) - Using the ampersand outside of entities (use &amp; to display the ampersand character)#
  • 틀림: <title>Cars & Trucks</title>
  • 옳음: <title>Cars &amp; Trucks</title>

 

태그 이름이나 태그 속성에 대문자를 사용 - Using uppercase tag names and/or tag attributes#
  • 틀림: <BODY><P>The Best Page Ever</P></BODY>
  • 옳음: <body><p>The Best Page Ever</p></body>

 

간소화된 속성 사용 - Attribute minimization#
  • 틀림: <textarea readonly>READ-ONLY</textarea>
  • 옳음: <textarea readonly="readonly">READ-ONLY</textarea>

 

 

그 외의 오류들#

 그 외에 직접 작정하면서 오류가 났던 부분을 정리한다.

 

<form 에 name속성 사용하지 못함 - 2009/02/21 07:28:08#
  • 흔히 <form name="fname" ... 이런식으로 정의해서 사용하지만 form에 name속성은 원래 허용하지 않는 속성인가보다. id속성은 무관하니 id로 해결해야 겠다.

 

<style> 사용 불가능#
  • css파일 이외의 style은 사용불가능 하다. 대신 inline style은 허용하니 inline 아니면 css파일로 스타일을 정의해야 한다.

 

URL 주소에서도 '&' 문자를 직접 사용하면 안됨.#
  • URL 링크를 생성하는데에도.. &문자를 바로 사용불가능함.
  • & => &amp; 바꾸어야함.

 

<form 에서 method="POST/post"#
  • form 태그에서 method정의시 대문자를 입력하면 안된 post/get과 같이 소문자로만 입력해야 함

 

td width= 어트리뷰트 허용하지 않음#
  • 보통 <td width 이런식으로 너비를 정하지만 이렇게 정의하지 못하게 되어 있음
  • <td>태그에서는 width 어트리뷰트를 허용하지 않음
  • Attribute "width" exists, but can not be used for this element. 에러를 낸다.



출처 : http://bequietzero.springnote.com/pages/2758810

 

Posted by 1010
반응형
<input type="text" autocomplete="off"/> <- 직접 기술한 건 잘못된 예


<input type="text" onfocus="this.setAttribute('autocomplete', 'off');"   /> <- 올바른 방법

Posted by 1010
90.개발관련문서2010. 10. 6. 13:38
반응형

Lucy-XSS Filter

Overview

Lucy-XSS Filter는 악의적인 XSS 코드의 위험으로부터 웹 어플리케이션을 보호하기 위해 필요한 기능을 White-List 설정방식으로 구현해놓은 Java 기반의 필터 라이브러리입니다. Lucy-XSS Filter의 사용으로 어플리케이션 개발자는 XSS코드의 위험성에 대한 고민 없이 Business Logic에만 집중하여 서비스를 개발할 수 있습니다.

Benefit

  • 효과적인 악의적 XSS 코드 제거
한번의 설정으로 XSS 코드를 필터링 할 수 있으므로 개발자는 XSS 보안에 대해 신경쓸 필요 없이 비즈니스 로직에만 집중하여 개발할 수 있습니다.
  • 일관된 필터링 규칙 적용
Case 별로 XSS 필터링을 로직에서 처리할 필요 없이 설정을 통해 필터링 규칙을 추가/제거할 수 있으며, 이를 통해 보안 관련 부서에서 일괄적인 방식으로 보안 필터 관리가 가능합니다.

Feature

  • 악의적인 XSS 코드가 포함된 데이터에 대한 보안 필터링 수행.
  • Java 기반 라이브러리 제공
  • 필터링 규칙을 설정방식(xml 파일 형식)으로 지원: HTML 4 스펙에 기반한 표준 설정 파일 제공
  • 사용자 정의 코드 삽입 기능 제공
Posted by 1010
반응형
Posted by 1010
01.JAVA/Java2010. 9. 27. 16:18
반응형
import java.util.regex.Pattern;

/**
 * A collection of utilities relating to InetAddresses.
 */
public class InetAddressUtils {

    private InetAddressUtils() {
    }
   
    private static final Pattern IPV4_PATTERN = 
        Pattern.compile(
                "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");

    private static final Pattern IPV6_STD_PATTERN = 
        Pattern.compile(
                "^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");

    private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = 
        Pattern.compile(
                "^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");

    public static boolean isIPv4Address(final String input) {
        return IPV4_PATTERN.matcher(input).matches();
    }

    public static boolean isIPv6StdAddress(final String input) {
        return IPV6_STD_PATTERN.matcher(input).matches();
    }
   
    public static boolean isIPv6HexCompressedAddress(final String input) {
        return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
    }
   
    public static boolean isIPv6Address(final String input) {
        return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
    }

}

Posted by 1010
01.JAVA/Java2010. 9. 27. 16:16
반응형
public class Main {

  public static void main(String[] args) {
    System.out.println("isValid = " + isValidEmailAddress("user@domain.com"));
  }

  static boolean isValidEmailAddress(String email) {
    String EMAIL_REGEX = "^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$";

    return email.matches(EMAIL_REGEX);
  }
}
Posted by 1010
01.JAVA/Java2010. 9. 27. 15:48
반응형
/*
* CDDL HEADER START
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://www.sun.com/cddl/cddl.html and legal/CDDLv1.0.txt
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright 2007 Sun Microsystems Inc. All Rights Reserved
* CDDL HEADER END
*/


package com.sun.portal.search.robot;

import java.lang.*;
import java.io.*;
import java.util.*;
import java.text.*;



public class FilterLog
{
    public static DateFormat df = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
    public static DateFormat listdf = new SimpleDateFormat("dd/MMM -  HH:mm:ss");
    protected ArrayList runList = new ArrayList();
    protected PrintWriter debug = null;
    private String dateStr = null;
    private String reasonStr = null;
    private int reasonIndex = -1;
    private Hashtable ExReasons = new Hashtable();
    private ArrayList ExReasonsArray = new ArrayList();
    private ArrayList FilteredList = new ArrayList();
    private int total = 0;

    static public void main(String[] args) {
FilterLog filterLog = null;
        if (args.length == 1) {
            filterLog= new FilterLog(args[0]);
        }
        else if (args.length == 2) {
            filterLog = new FilterLog(args[0], args[1]);
        }
        else if (args.length == 3) {
            filterLog = new FilterLog(args[0], args[1], args[2]);
        }
        else {
   System.out.println("Usage:FilterLog filterLogPath [selectedDate [selectedReason]]");
   return;
        }

        filterLog.printResult(System.out);
    }

    public FilterLog(String file, PrintWriter out)
    {
        debug=out;
        out.println("FilterLog debug enabled");
        parserFilterLog(file);
    }
    public FilterLog(String file, String date, PrintWriter out)
    {
        debug=out;
        dateStr = date;
        out.println("FilterLog debug enabled");
        parserFilterLog(file);
    }

    public FilterLog(String file, String date, String reason, PrintWriter out)
    {
        debug=out;
        dateStr = date;
        reasonStr = reason;
        out.println("FilterLog debug enabled");
        parserFilterLog(file);
    }

    public FilterLog(String file)
    {
        parserFilterLog(file);
    }
    public FilterLog(String file, String date)
    {
        dateStr = date;
        parserFilterLog(file);
    }
    public FilterLog(String file, String date, String reason)
    {
        dateStr = date;
        reasonStr = reason;
        parserFilterLog(file);
    }
    public FilterLog(String file, String date, int reason)
    {
        dateStr = date;
        reasonIndex = reason;
        parserFilterLog(file);
    }


    public void parserFilterLog(String filterlog_path)
    {
BufferedReader in = null;
String oldline = null;
String line = null;
        String preLine = null;
        Date date = null;
        boolean inSelectedDate = false;
        boolean inSelectedReason = false;
        int lineNum = 0;    // line number starts with 1
try {
   in = new BufferedReader(new InputStreamReader(new FileInputStream(filterlog_path), "ISO-8859-1"));
   while ((oldline=in.readLine()) != null) {
                lineNum ++;
try {
   line = new String(oldline.getBytes("ISO-8859-1"), "UTF-8");
} catch (Exception e) {
   continue;
}
                // expecting
                //[22/Jan/2002:10:48:19]  9883@001: Filter log started
                if ( line.startsWith("[") /*|| line.startsWith("Time:")*/) {
                    int start = line.indexOf('[');
                    int end = line.indexOf(']');
                    if (start >=0 && end > start) {
                        String datestr = line.substring(start+1, end);
                        try {
                            date = df.parse(datestr);
                            if (debug != null) {
                                debug.println("add date : " + df.format(date));
                            }
                            runList.add(date);
                            if (dateStr != null && datestr.compareTo(dateStr)==0) {
                                inSelectedDate = true;
                            }
                            else {
                                inSelectedDate = false;
                            }
                        } catch (ParseException e) {
                            if (debug != null) {
                                debug.println("ParseException at position(" + e.getErrorOffset() + ")");
                                debug.println(line);
                            } else {
                                System.out.println("ParseException at position(" + e.getErrorOffset() + ")");
                                System.out.println(line);
                            }
                        }
                    }
                }
                else  if (inSelectedDate && line.startsWith("Hint:")) {
                    String hint = line.substring(5).trim();
                    if (hint.startsWith("File Not Found.")) {
                        hint = "File Not Found.";
                    }
                    if (preLine != null) {
                        int c = 1;
                        if (ExReasons.containsKey(hint)) {
                            Integer count =(Integer)ExReasons.get(hint);
                            c = count.intValue();
                            c++;
   ExReasons.put(hint, new Integer(c));
                        }
else {
   ExReasons.put(hint, new Integer(c));
   ExReasonsArray.add(hint);
}
                        total++;
                        if ((reasonStr != null && reasonStr.compareToIgnoreCase(hint) == 0) || ((reasonIndex >= 0 && ExReasonsArray.size() > reasonIndex && ((String)ExReasonsArray.get(reasonIndex)).compareToIgnoreCase(hint) == 0))) {
                            FilteredList.add(preLine);
                        }
                        preLine = null;
                    }
                }
                else if (inSelectedDate) {
                    preLine = line;
                }
   }
}
catch(IOException e) {
            if (debug != null) {
                debug.println("IOException:" + e.getMessage()  + " at line# " + lineNum);
            }
            else {
                System.out.println("IOException:" + e.getMessage() + " at line# " + lineNum);
            }
}
    }
/*    public void printRunList(PrintWriter out)
    {
        for (int i=0; i < runList.size(); i++) {
            out.println(i + " run - " + listdf.format((Date)runList.get(i)) );
        }
    }
*/

    public void printResult(PrintStream out)
    {
        for (int i=0; i < runList.size(); i++) {
            out.println(i + " run - " + listdf.format((Date)runList.get(i)) );
        }
        if (dateStr != null) {
            Enumeration e = ExReasons.keys();
            while(e.hasMoreElements()) {
                String reason = (String)e.nextElement();
                Integer count = (Integer) ExReasons.get(reason);
                out.println(reason + ":" + count);
            }
            if (reasonStr != null) {
                for (int i=0; i < FilteredList.size(); i++) {
                    out.println((String)FilteredList.get(i));
                }
            }
        }

    }

    public Object[] getRunArray()
    {
        return runList.toArray();
    }

    public ArrayList getRunArrayList()
    {
        return runList;
    }

    public void setDebug(PrintWriter out)
    {
        debug=out;
    }

    public String[] getReasons() {
return (String[]) ExReasonsArray.toArray(new String[0]);
    }

    public int getReasonSubTotal(String reason) {
        if (ExReasons != null) {
            Integer count = (Integer)ExReasons.get(reason);
            return count.intValue();
        }
        return 0;
    }

    public  ArrayList getFilteredURL() {
        return FilteredList;
    }

    public String getReason() {
        return reasonStr;
    }
    public String getReasonByIndex(int index) {
try {
   return (String) ExReasonsArray.get(index);
} catch (Exception e) {
   return null;
}
    }

    public int getTotal() {
        return total;
    }
}
Posted by 1010
반응형
갑자기 듣도 보도 못 한 웹서비스를 하게 됐다. 이건 언제 해본적도 없는 녀석이라 처음부터 잔뜩 겁먹고 시작.. 아니나 다를까.. 인수인계도 제대로 되지 않아서 아무도 모른다. 주변에 있는 사람들도 웹서비스를 해본 사람이 거의 없다. 나 오뜨케~~ @ㅅ@

일단, 기존 소스에 기능을 추가할 생각으로 JAX-RPC를 사용하려 했는데.. JAX-WS로 변경되는 바람에 기존에 쓰던 코드 조차 어찌 배포해야 하는지 아무도 모른다. =ㅅ=;;; 샘플이나 예제를 찾아봐도 그다지 도움이 되지 않네 그려.. 하루를 삽질하다가 GG치고 JAX-RPC 보다는 조금 더 사용하기 쉬운 Apache Axis2를 사용하기로 했다. Axis는 샘플도 많고, apache 사이트의 참조할 내용도 잘 되어 있다. 무엇보다 좋은건 Eclipse WTP에서 손쉽게 구현하는 기능이 있다!! 잇힝~~

java 소스를 먼저 만들고 wsdl 쪽으로 구성하는 bottom up 방법과, wsdl을 먼저 만들고 그에 따라 java 소스를 만드는 top down 방법이 있다. bottom up 방법은 한글로 너무나 이쁘게 정리가 되어 있는 포스팅이 있어서 엄청 도움이 됐다. 예전 버전이라 화면이 조금 다르지만 그냥 따라하면 술술 넘어가며 알아서 만들어 진다.


출처 : http://entireboy.egloos.com/4342149

Posted by 1010
반응형
Posted by 1010
01.JAVA/Java2010. 9. 24. 17:18
반응형

The basics

REST defines a set of architectural principles by which you can design Web services that focus on a system's resources, including how resource states are addressed and transferred over HTTP by a wide range of clients written in different languages. If measured by the number of Web services that use it, REST has emerged in the last few years alone as a predominant Web service design model. In fact, REST has had such a large impact on the Web that it has mostly displaced SOAP- and WSDL-based interface design because it's a considerably simpler style to use.

REST didn't attract this much attention when it was first introduced in 2000 by Roy Fielding at the University of California, Irvine, in his academic dissertation, "Architectural Styles and the Design of Network-based Software Architectures," which analyzes a set of software architecture principles that use the Web as a platform for distributed computing (see Resources for a link to this dissertation). Now, years after its introduction, major frameworks for REST have started to appear and are still being developed because it's slated, for example, to become an integral part of Java™ 6 through JSR-311.

This article suggests that in its purest form today, when it's attracting this much attention, a concrete implementation of a REST Web service follows four basic design principles:

  • Use HTTP methods explicitly.
  • Be stateless.
  • Expose directory structure-like URIs.
  • Transfer XML, JavaScript Object Notation (JSON), or both.

The following sections expand on these four principles and propose a technical rationale for why they might be important for REST Web service designers.


Use HTTP methods explicitly

One of the key characteristics of a RESTful Web service is the explicit use of HTTP methods in a way that follows the protocol as defined by RFC 2616. HTTP GET, for instance, is defined as a data-producing method that's intended to be used by a client application to retrieve a resource, to fetch data from a Web server, or to execute a query with the expectation that the Web server will look for and respond with a set of matching resources.

REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping:

  • To create a resource on the server, use POST.
  • To retrieve a resource, use GET.
  • To change the state of a resource or to update it, use PUT.
  • To remove or delete a resource, use DELETE.

An unfortunate design flaw inherent in many Web APIs is in the use of HTTP methods for unintended purposes. The request URI in an HTTP GET request, for example, usually identifies one specific resource. Or the query string in a request URI includes a set of parameters that defines the search criteria used by the server to find a set of matching resources. At least this is how the HTTP/1.1 RFC describes GET. But there are many cases of unattractive Web APIs that use HTTP GET to trigger something transactional on the server—for instance, to add records to a database. In these cases the GET request URI is not used properly or at least not used RESTfully. If the Web API uses GET to invoke remote procedures, it looks like this:

GET /adduser?name=Robert HTTP/1.1

It's not a very attractive design because the Web method above supports a state-changing operation over HTTP GET. Put another way, the HTTP GET request above has side effects. If successfully processed, the result of the request is to add a new user—in this example, Robert—to the underlying data store. The problem here is mainly semantic. Web servers are designed to respond to HTTP GET requests by retrieving resources that match the path (or the query criteria) in the request URI and return these or a representation in a response, not to add a record to a database. From the standpoint of the intended use of the protocol method then, and from the standpoint of HTTP/1.1-compliant Web servers, using GET in this way is inconsistent.

Beyond the semantics, the other problem with GET is that to trigger the deletion, modification, or addition of a record in a database, or to change server-side state in some way, it invites Web caching tools (crawlers) and search engines to make server-side changes unintentionally simply by crawling a link. A simple way to overcome this common problem is to move the parameter names and values on the request URI into XML tags. The resulting tags, an XML representation of the entity to create, may be sent in the body of an HTTP POST whose request URI is the intended parent of the entity (see Listings 1 and 2).


Listing 1. Before
GET /adduser?name=Robert HTTP/1.1
            


Listing 2. After
POST /users HTTP/1.1
Host: myserver
Content-Type: application/xml
<?xml version="1.0"?>
<user>
  <name>Robert</name>
</user>
            

The method above is exemplary of a RESTful request: proper use of HTTP POST and inclusion of the payload in the body of the request. On the receiving end, the request may be processed by adding the resource contained in the body as a subordinate of the resource identified in the request URI; in this case the new resource should be added as a child of /users. This containment relationship between the new entity and its parent, as specified in the POST request, is analogous to the way a file is subordinate to its parent directory. The client sets up the relationship between the entity and its parent and defines the new entity's URI in the POST request.

A client application may then get a representation of the resource using the new URI, noting that at least logically the resource is located under /users, as shown in Listing 3.


Listing 3. HTTP GET request
GET /users/Robert HTTP/1.1
Host: myserver
Accept: application/xml

Using GET in this way is explicit because GET is for data retrieval only. GET is an operation that should be free of side effects, a property also known as idempotence.

A similar refactoring of a Web method also needs to be applied in cases where an update operation is supported over HTTP GET, as shown in Listing 4.


Listing 4. Update over HTTP GET
GET /updateuser?name=Robert&newname=Bob HTTP/1.1

This changes the name attribute (or property) of the resource. While the query string can be used for such an operation, and Listing 4 is a simple one, this query-string-as-method-signature pattern tends to break down when used for more complex operations. Because your goal is to make explicit use of HTTP methods, a more RESTful approach is to send an HTTP PUT request to update the resource, instead of HTTP GET, for the same reasons stated above (see Listing 5).


Listing 5. HTTP PUT request
PUT /users/Robert HTTP/1.1
Host: myserver
Content-Type: application/xml
<?xml version="1.0"?>
<user>
  <name>Bob</name>
</user>

Using PUT to replace the original resource provides a much cleaner interface that's consistent with REST's principles and with the definition of HTTP methods. The PUT request in Listing 5 is explicit in the sense that it points at the resource to be updated by identifying it in the request URI and in the sense that it transfers a new representation of the resource from client to server in the body of a PUT request instead of transferring the resource attributes as a loose set of parameter names and values on the request URI. Listing 5 also has the effect of renaming the resource from Robert to Bob, and in doing so changes its URI to /users/Bob. In a REST Web service, subsequent requests for the resource using the old URI would generate a standard 404 Not Found error.

As a general design principle, it helps to follow REST guidelines for using HTTP methods explicitly by using nouns in URIs instead of verbs. In a RESTful Web service, the verbs—POST, GET, PUT, and DELETE—are already defined by the protocol. And ideally, to keep the interface generalized and to allow clients to be explicit about the operations they invoke, the Web service should not define more verbs or remote procedures, such as /adduser or /updateuser. This general design principle also applies to the body of an HTTP request, which is intended to be used to transfer resource state, not to carry the name of a remote method or remote procedure to be invoked.


Be stateless

REST Web services need to scale to meet increasingly high performance demands. Clusters of servers with load-balancing and failover capabilities, proxies, and gateways are typically arranged in a way that forms a service topology, which allows requests to be forwarded from one server to the other as needed to decrease the overall response time of a Web service call. Using intermediary servers to improve scale requires REST Web service clients to send complete, independent requests; that is, to send requests that include all data needed to be fulfilled so that the components in the intermediary servers may forward, route, and load-balance without any state being held locally in between requests.

A complete, independent request doesn't require the server, while processing the request, to retrieve any kind of application context or state. A REST Web service application (or client) includes within the HTTP headers and body of a request all of the parameters, context, and data needed by the server-side component to generate a response. Statelessness in this sense improves Web service performance and simplifies the design and implementation of server-side components because the absence of state on the server removes the need to synchronize session data with an external application.

Figure 1 illustrates a stateful service from which an application may request the next page in a multipage result set, assuming that the service keeps track of where the application leaves off while navigating the set. In this stateful design, the service increments and stores a previousPage variable somewhere to be able to respond to requests for next.


Figure 1. Stateful design
Stateful Design

Stateful services like this get complicated. In a Java Platform, Enterprise Edition (Java EE) environment stateful services require a lot of up-front consideration to efficiently store and enable the synchronization of session data across a cluster of Java EE containers. In this type of environment, there's a problem familiar to servlet/JavaServer Pages (JSP) and Enterprise JavaBeans (EJB) developers who often struggle to find the root causes of java.io.NotSerializableException during session replication. Whether it's thrown by the servlet container during HttpSession replication or thrown by the EJB container during stateful EJB replication, it's a problem that can cost developers days in trying to pinpoint the one object that doesn't implement Serializable in a sometimes complex graph of objects that constitute the server's state. In addition, session synchronization adds overhead, which impacts server performance.

Stateless server-side components, on the other hand, are less complicated to design, write, and distribute across load-balanced servers. A stateless service not only performs better, it shifts most of the responsibility of maintaining state to the client application. In a RESTful Web service, the server is responsible for generating responses and for providing an interface that enables the client to maintain application state on its own. For example, in the request for a multipage result set, the client should include the actual page number to retrieve instead of simply asking for next (see Figure 2).


Figure 2. Stateless design
Stateless Design

A stateless Web service generates a response that links to the next page number in the set and lets the client do what it needs to in order to keep this value around. This aspect of RESTful Web service design can be broken down into two sets of responsibilities as a high-level separation that clarifies just how a stateless service can be maintained:

Server

  • Generates responses that include links to other resources to allow applications to navigate between related resources. This type of response embeds links. Similarly, if the request is for a parent or container resource, then a typical RESTful response might also include links to the parent's children or subordinate resources so that these remain connected.
  • Generates responses that indicate whether they are cacheable or not to improve performance by reducing the number of requests for duplicate resources and by eliminating some requests entirely. The server does this by including a Cache-Control and Last-Modified (a date value) HTTP response header.

Client application

  • Uses the Cache-Control response header to determine whether to cache the resource (make a local copy of it) or not. The client also reads the Last-Modified response header and sends back the date value in an If-Modified-Since header to ask the server if the resource has changed. This is called Conditional GET, and the two headers go hand in hand in that the server's response is a standard 304 code (Not Modified) and omits the actual resource requested if it has not changed since that time. A 304 HTTP response code means the client can safely use a cached, local copy of the resource representation as the most up-to-date, in effect bypassing subsequent GET requests until the resource changes.
  • Sends complete requests that can be serviced independently of other requests. This requires the client to make full use of HTTP headers as specified by the Web service interface and to send complete representations of resources in the request body. The client sends requests that make very few assumptions about prior requests, the existence of a session on the server, the server's ability to add context to a request, or about application state that is kept in between requests.

This collaboration between client application and service is essential to being stateless in a RESTful Web service. It improves performance by saving bandwidth and minimizing server-side application state.


Expose directory structure-like URIs

From the standpoint of client applications addressing resources, the URIs determine how intuitive the REST Web service is going to be and whether the service is going to be used in ways that the designers can anticipate. A third RESTful Web service characteristic is all about the URIs.

REST Web service URIs should be intuitive to the point where they are easy to guess. Think of a URI as a kind of self-documenting interface that requires little, if any, explanation or reference for a developer to understand what it points to and to derive related resources. To this end, the structure of a URI should be straightforward, predictable, and easily understood.

One way to achieve this level of usability is to define directory structure-like URIs. This type of URI is hierarchical, rooted at a single path, and branching from it are subpaths that expose the service's main areas. According to this definition, a URI is not merely a slash-delimited string, but rather a tree with subordinate and superordinate branches connected at nodes. For example, in a discussion threading service that gathers topics ranging from Java to paper, you might define a structured set of URIs like this:

http://www.myservice.org/discussion/topics/{topic}

The root, /discussion, has a /topics node beneath it. Underneath that there are a series of topic names, such as gossip, technology, and so on, each of which points to a discussion thread. Within this structure, it's easy to pull up discussion threads just by typing something after /topics/.

In some cases, the path to a resource lends itself especially well to a directory-like structure. Take resources organized by date, for instance, which are a very good match for using a hierarchical syntax.

This example is intuitive because it is based on rules:

http://www.myservice.org/discussion/2008/12/10/{topic}

The first path fragment is a four-digit year, the second path fragment is a two-digit day, and the third fragment is a two-digit month. It may seem a little silly to explain it that way, but this is the level of simplicity we're after. Humans and machines can easily generate structured URIs like this because they are based on rules. Filling in the path parts in the slots of a syntax makes them good because there is a definite pattern from which to compose them:

http://www.myservice.org/discussion/{year}/{day}/{month}/{topic}

Some additional guidelines to make note of while thinking about URI structure for a RESTful Web service are:

  • Hide the server-side scripting technology file extensions (.jsp, .php, .asp), if any, so you can port to something else without changing the URIs.
  • Keep everything lowercase.
  • Substitute spaces with hyphens or underscores (one or the other).
  • Avoid query strings as much as you can.
  • Instead of using the 404 Not Found code if the request URI is for a partial path, always provide a default page or resource as a response.

URIs should also be static so that when the resource changes or the implementation of the service changes, the link stays the same. This allows bookmarking. It's also important that the relationship between resources that's encoded in the URIs remains independent of the way the relationships are represented where they are stored.


Transfer XML, JSON, or both

A resource representation typically reflects the current state of a resource, and its attributes, at the time a client application requests it. Resource representations in this sense are mere snapshots in time. This could be a thing as simple as a representation of a record in a database that consists of a mapping between column names and XML tags, where the element values in the XML contain the row values. Or, if the system has a data model, then according to this definition a resource representation is a snapshot of the attributes of one of the things in your system's data model. These are the things you want your REST Web service to serve up.

The last set of constraints that goes into a RESTful Web service design has to do with the format of the data that the application and service exchange in the request/response payload or in the HTTP body. This is where it really pays to keep things simple, human-readable, and connected.

The objects in your data model are usually related in some way, and the relationships between data model objects (resources) should be reflected in the way they are represented for transfer to a client application. In the discussion threading service, an example of connected resource representations might include a root discussion topic and its attributes, and embed links to the responses given to that topic.


Listing 6. XML representation of a discussion thread
<?xml version="1.0"?>
<discussion date="{date}" topic="{topic}">
  <comment>{comment}</comment>
  <replies>
    <reply from="joe@mail.com" href="/discussion/topics/{topic}/joe"/>
    <reply from="bob@mail.com" href="/discussion/topics/{topic}/bob"/>
  </replies>
</discussion>

And last, to give client applications the ability to request a specific content type that's best suited for them, construct your service so that it makes use of the built-in HTTP Accept header, where the value of the header is a MIME type. Some common MIME types used by RESTful services are shown in Table 1.


Table 1. Common MIME types used by RESTful services
MIME-Type Content-Type
JSON application/json
XML application/xml
XHTML application/xhtml+xml

This allows the service to be used by a variety of clients written in different languages running on different platforms and devices. Using MIME types and the HTTP Accept header is a mechanism known as content negotiation, which lets clients choose which data format is right for them and minimizes data coupling between the service and the applications that use it.


Conclusion

REST is not always the right choice. It has caught on as a way to design Web services with less dependence on proprietary middleware (for example, an application server) than the SOAP- and WSDL-based kind. And in a sense, REST is a return to the Web the way it was before the age of the big application server, through its emphasis on the early Internet standards, URI and HTTP. As you've examined in the so-called principles of RESTful interface design, XML over HTTP is a powerful interface that allows internal applications, such as Asynchronous JavaScript + XML (Ajax)-based custom user interfaces, to easily connect, address, and consume resources. In fact, the great fit between Ajax and REST has increased the amount of attention REST is getting these days.

Exposing a system's resources through a RESTful API is a flexible way to provide different kinds of applications with data formatted in a standard way. It helps to meet integration requirements that are critical to building systems where data can be easily combined (mashups) and to extend or build on a set of base, RESTful services into something much bigger. This article touches on just the basics here but hopefully in a way that has enticed you to continue exploring the subject.


Resources

Learn

Get products and technologies

Discuss

Posted by 1010
01.JAVA/Java2010. 9. 24. 17:05
반응형

이번 테크팁에서는 Java에서 JAX-RS: Java API for RESTful Web Services (JSR-311) 사양을 따르는 RESTful 웹 서비스를 작성하는 방법과 그 참조 구현인 Jersey를 소개한다. REST(Representational State Transfer)의 기본 원리 몇 가지와 JAX-RS 및 Jersey에 대해 학습하게 된다.

이 팁에서는 JAX-RS 개념과 기술을 보여 주기 위해 샘플 애플리케이션을 사용한다. Jersey 다운로드 페이지에서 최신 버전의 Jersey 스냅샷을 다운로드하여 샘플을 구할 수 있다. 이 팁의 코드 예제는 다운로드 패키지에 포함된 샘플의 소스 코드에서 따온 것이다.

RESTful 웹 서비스 소개

REST는 WWW와 같은 분산형 시스템을 위한 소프트웨어 아키텍처 스타일 중 하나이다. 이 용어는 2000년에 Roy Fielding의 박사 논문에서 소개되었으며, 그 이후 네트워킹 커뮤니티에서 널리 사용되어 왔다. REST에서 중요한 개념 중 하나는 리소스의 존재인데, 각 리소스는 전역 식별자인 URI를 사용하여 참조할 수 있다. 이 리소스를 조작하기 위해 네트워크, 클라이언트 및 서버 구성 요소가 HTTP와 같은 표준화된 인터페이스를 사용하여 통신하고 이 리소스의 표현을 교환한다.

RESTful 웹 서비스는 RESTful 아키텍처 스타일을 사용하여 작성한 서비스이다. RESTful 방식의 웹 서비스 작성은 SOAP 기반 기술을 사용하여 인터넷에서 서비스를 배포하는 방법의 대안으로 새롭게 각광받고 있는데, 가벼울 뿐 아니라 직접 HTTP를 통해 데이터를 보낼 수 있기 때문이다.

RESTful 웹 서비스의 원리

RESTful 웹 서비스의 기본 원리는 다음과 같다.

  • 리소스(Resource)와 표현(Representation). 특정 웹 서비스에 단 하나의 종단점을 제공하고 그 종단점이 여러 작업을 수행하게 하지 않고 리소스에 대한 액세스를 제공한다. 리소스는 여러분이 클라이언트로 하여금 액세스할 수 있게 해주는 웹 애플리케이션의 한 부분이다. 이 리소스는 네트워크를 통해 전송할 수 없으므로 "이 리소스를 제공한다"는 것은 그 상태의 표현을 전달하는 것을 의미한다.

  • 주소 지정 가능성(Addressability)과 연결성(Connectedness). 리소스는 표현을 갖지만, 그 주소를 지정할 수 없다면 리소스의 표현을 전달하더라도 쓸모 없다. REST에서는 모든 리소스가 하나 이상의 주소, 즉 URI를 가져야 한다. 리소스 주소를 지정하려면 URI를 지정하면 된다. 이러한 개념을 "주소 지정 가능성"이라고 한다. 웹 애플리케이션을 게시하면 서로 연결된 많은 URI를 제시하게 된다. 그 연결성 덕분에 "부트스트랩 URI"라고 부르는 URI 하나만 클라이언트에게 전달하면 된다.

  • 동일한 인터페이스(Uniform interface) URI와 표현을 통해 클라이언트와 서버 간에 리소스를 주고 받을 수 있게 하더라도 아직 통신을 설정할 수는 없다. 사용할 통신 프로토콜/인터페이스가 필요하다. REST 아키텍처에서는 그러한 인터페이스가 동일해야 한다. 즉 어떤 URI에 액세스하더라도 인터페이스가 같아야 한다. 예를 들어, WWW에서는 어떤 URI(리소스 주소)에 들어가더라도 웹 브라우저에서는 HTTP GET 메소드를 사용하여 해당 웹 페이지(리소스 표현)를 읽어들여 표시한다.

  • 상태 비보존성(Statelessness). 상태 비보존성이란 웹 애플리케이션이 클라이언트의 상태에 대한 정보를 보관하지 않는다는 것이다. REST에서는 HTTP 세션의 개념을 수용하지 않는다. 클라이언트는 필요하다면 자신의 작업을 추적할 책임이 있다. 서비스는 리소스를 유지하면서 클라이언트에게 동일한 인터페이스를 제공한다.

JAX-RS와 Jersey

JAX-RS는 Java에서 RESTful 웹 서비스를 작성할 수 있는 표준화된 API를 제공한다. 이 API는 기본적으로 주석 그리고 관련된 클래스 및 인터페이스의 모음을 제공한다. 주석을 POJO(Plain Old Java Object)에 적용하면 웹 리소스를 공개할 수 있다. API는 아직 완성되지 않았다. 최종 버전은 Java EE 6에 포함될 것이다. JAX-RS에 대한 자세한 내용은 jsr311 프로젝트에서 확인할 수 있다.

Jersey는 JAX-RS의 참조 구현 중 하나이다. Jersey 프로젝트 다운로드 페이지에서 다운로드 가능한 Jersey 배포판을 구할 수 있다. 최신 Jersey 스냅샷을 선택하고 압축을 풀면 Jersey 구현이 그 사용법을 알려주는 몇 가지 예제와 함께 번들되어 있음을 알 수 있다. 그 예제 중 하나를 살펴보도록 하자.

JAX-RS 사용 예: 북마크 애플리케이션

Jersey와 함께 배포되는 예제 중 하나가 북마크 애플리케이션이다. examples/Bookmark 하위 디렉토리에 있는 이 애플리케이션에서는 JAX-RS API를 사용하여 사용자가 저장한 북마크에 대한 정보를 유지 관리한다. 이 애플리케이션을 실행하고 특정 사용자를 지정하면 그 애플리케이션은 다음과 비슷한 데이터를 반환한다.

   {sdesc":"test desc","userid":"testuserid","uri":
   "http://java.sun.com","ldesc":"long test description"}

이 애플리케이션은 JSON(JavaScript Object Notation) 형식으로 데이터를 반환한다.

examples/Bookmark 하위 디렉토리 아래의 resources 하위 디렉토리까지 이동하면 이 애플리케이션의 다음 리소스를 볼 수 있다.

  • UsersResource: 사용자 목록을 나타낸다.
  • UserResource: 특정 사용자를 나타낸다.
  • BookmarksResource: 특정 사용자의 북마크 목록을 나타낸다.
  • BookmarkResource: 특정 북마크를 나타낸다.

다시 말하자면 REST에서 어떤 리소스를 주소 지정하려면 URI를 지정한다. 그러나 리소스와 통신하기 위해서는 HTTP와 같은 통신 프로토콜도 지정해야 한다. 다음은 북마크 애플리케이션의 리소스에 해당하는 URI와 HTTP 메소드이다.

리소스
URI 경로
HTTP 메소드
UsersResource
/users
GET
UserResource
/users/{userid}
GET, PUT, DELETE
BookmarksResource
/users/{userid}/bookmarks
GET, POST
BookmarkResource
/users/{userid}/bookmarks/{bmid}
GET, PUT, DELETE
 

JAX-RS의 기본 원리를 이해하기 위해 이 리소스 중 두 가지를 살펴보자. UsersResourceUserResource이다.

UsersResource

다음은 UsersResource 클래스 소스 코드 중 일부이다.

   @UriTemplate("/users/")

   public class UsersResource {
     
       @HttpContext UriInfo uriInfo;    

       @PersistenceUnit(unitName = "BookmarkPU")
       EntityManagerFactory emf;

       /** Creates a new instance of Users */
       public UsersResource() {
       }
   
       public List<UserEntity> getUsers() {
           return emf.createEntityManager().createQuery(
                  "SELECT u from UserEntity u").getResultList();
       }
   
       @UriTemplate("{userid}/")
       public UserResource getUser(@UriParam("userid")
              String userid) {
           return new UserResource(
                  uriInfo, emf.createEntityManager(), userid);
       }

       @HttpMethod("GET")
       @ProduceMime("application/json")
       public JSONArray getUsersAsJsonArray() {
           JSONArray uriArray = new JSONArray();
           UriBuilder ub = null;
           for (UserEntity userEntity : getUsers()) {
               ub = (ub == null) ?
                      uriInfo.getBuilder() : ub.clone();
               URI userUri = ub.
                       path(userEntity.getUserid()).
                       build();
               uriArray.put(userUri.toString());
           }
           return uriArray;
       }
   }

UsersResource 클래스에는 @UriTemplate("/users/") 주석이 있다. @UriTemplate는 리소스의 URI 경로를 식별하는 JAX-RS 주석이다. 여기서 주석은 URI 경로를 /users/로 식별한다.

   @UriTemplate("/users/")

클래스에 @UriTemplate 주석을 추가하면 클래스는 "루트 리소스 클래스"가 된다. 또한 /users/ URI 경로에 액세스하는 클라이언트 요청의 경우 이 리소스가 적합한 응답을 제공해야 함을 의미한다. 또한 /users/ URI 경로가 북마크 웹 애플리케이션 전체에서 부트스트랩 URI 경로이다.

UsersResource 클래스에 포함된 또 다른 JSR-311 주석이 @HttpContext이다.

   @HttpContext UriInfo uriInfo;

이 주석은 클래스 필드 또는 메소드 매개 변수에 정보를 주입한다. UsersResource 클래스에서 @HttpContext는 URI에 대한 정보를 uriInfo 변수에 주입하고, 이는 URI 관련 정보를 제공할 때 사용할 수 있다.

UsersResource 메소드

UsersResource 클래스는 getUsergetUsersAsJsonArray라는 두 메소드를 갖는다. 일단 getUser를 건너뛰고 getUsersAsJsonArray를 집중적으로 살펴보도록 한다. getUsersAsJsonArray 메소드는 모든 사용자 리소스에 대한 URI를 반환한다. 이 메소드에는 두 개의 JSR 311 주석, 즉 @HttpMethod@ProduceMime이 추가되었다. @HttpMethod 주석은 주석이 추가된 메소드가 HTTP 요청 처리에 사용되어야 함을 의미한다. 또한 이 주석은 메소드가 응답할 HTTP 요청의 유형도 지정한다. 이 예제에서 이 주석은 getUsersAsJsonArray 메소드가 HTTP GET 요청을 서비스하도록 지정한다.

   @HttpMethod("GET")

이와 같이 REST 요청을 서비스하는 메소드를 "리소스 메소드"라고 부른다.

@ProduceMime 주석은 메소드가 생성할 수 있는 MIME 형식을 지정한다. 여기서 이 주석은 getUsersAsJsonArray 메소드가 기존의 모든 사용자 리소스의 URI 어레이를 포함하는 JSONArray 개체를 반환하도록 지정한다.

   @ProduceMime("application/json")


사용자 리소스 가져오기
사용자 리소스 가져오기

이 메소드는 다음과 같은 JSON 어레이 개체를 클라이언트에 반환한다.

   ["http://localhost:8080/Bookmark/resources/users/joe",
   "http://localhost:8080/Bookmark/resources/users/mary"]

JSON 어레이는 URI, 즉 두 사용자 리소스인 joemary의 링크를 포함한다.

getUser 메소드는 특정 사용자에 대한 정보를 가져온다. 예를 들어, 클라이언트가 사용자 joe에 대한 정보를 얻으려면 그 URI에서 리소스에 액세스한다. 여기서는 http://localhost:8080/Bookmark/resources/users/joe이다. UsersResource 클래스는 joe의 URI 경로(/users/joe)를 비롯해 /users/로 시작하는 경로에 대한 모든 요청을 서비스한다.

여기서 getUser 메소드에 @UriTemplate("{userid}/") 주석이 붙는 것이 중요하다. 그러면 메소드가 "하위 리소스 로케이터"가 된다. 또한 getUser 메소드에는 @UriParam 주석이 붙는다. 따라서 getUser 메소드가 호출되면 현재 요청 URI 경로의 사용자 ID가 userid 매개변수에 주입되는 것이다.

getUser 메소드에는 @HttpMethod 주석이 연결되지 않는다. 따라서 이 메소드의 출력은 리소스 클래스 개체로 간주한다. 즉 요청 처리가 리소스 클래스에 위임되며 거기서 알맞은 @HttpMethod-annotated 메소드를 찾을 것이다. getUser 메소드는 UserResource 개체를 반환하므로

   public UserResource getUser(@UriParam("userid")
                 String userid) {
           return new UserResource(...)

UserResource 클래스에서 알맞은 메소드가 호출된다.

사용자 삽입 이미지
사용자 리소스 가져오기


UserResource

언급한 대로 UsersResource 클래스의 getUser 메소드의 요청 처리는 새로 인스턴스화된 UserResource 개체의 메소드로 위임된다. 다음은 UserResource 클래스 코드 중 일부로 그 메소드 중 하나인 getUser를 보여 준다.

   @HttpMethod("GET")
   @ProduceMime("application/json")
   public JSONObject getUser() throws JSONException {
       if (null == userEntity) {
           throw new NotFoundException(
                  "userid " + userid + "does not exist!");
       }
       return new JSONObject()
           .put("userid", userEntity.getUserid())
           .put("username", userEntity.getUsername())
           .put("email", userEntity.getEmail())
           .put("password", userEntity.getPassword())
           .put("bookmarks",
                uriInfo.getBuilder().path("bookmarks").build());
    }

이 메소드 역시 @HttpMethod("GET")@ProduceMime("application/json") 주석이 붙는다. 여기서 getUsers 메소드는 HTTP GET 요청을 서비스하고 JSONObject 개체를 반환한다. JSONObject 개체는 특정 사용자의 표현(예: useridjoe인 사용자의 표현)을 포함한다.

UserResource에서 소스 코드의 나머지를 살펴볼 수 있다. @ConsumeMime와 같이 메소드가 수용할 수 있는 MIME 형식을 식별하는 JSR 311 주석을 더 볼 수 있다.

샘플 코드 빌드 및 배포

이 팁의 샘플 코드는 NetBeans 프로젝트로 사용 가능하다. NetBeans IDE 또는 명령줄에서 샘플을 빌드하고 배포할 수 있다. 어떤 경우에서든

  1. GlassFish V2를 다운로드하지 않았다면 다운로드하여 설치한다.

  2. Jersey 다운로드 페이지에서 최신 Jersey 스냅샷을 다운로드하고 그 압축을 푼다. 새로 추출된 디렉토리가 <sample_install_dir>/jersey로 나타나는데, 여기서 <sample_install_dir>은 샘플 애플리케이션을 설치한 디렉토리이다. 예를 들어, Windows 시스템에서 C:\에 압축을 풀었다면 새로 생성된 디렉토리는 C:\jersey이다.

NetBeans에서의 샘플 코드 빌드 및 배포

  1. NetBeans 5.5.1 IDE가 없으면 다운로드하여 설치한다.

  2. NetBeans IDE를 시작한다. 아직 하지 않았다면 다음과 같이 NetBeans에서 GlassFish V2를 등록한다.

    • Runtime 창에서 Servers 노드를 오른쪽 클릭한다.
    • Add Server를 선택한다.
    • 서버를 Sun Java System Application Server로 둔다.
    • Next 버튼을 클릭한다.
    • Browse 버튼을 클릭하고 GlassFish V2를 설치한 위치로 이동한다.
    • Choose 버튼을 클릭한다.
    • Next 버튼을 클릭한다.
    • GlassFish에 다른 암호를 선택하지 않았다면 Admin Password를 기본값인 adminadmin으로 설정한다.
    • Finish 버튼을 클릭한다.

  3. 다음과 같이 Bookmark 프로젝트를 연다.

    • File 메뉴에서 Open Project를 선택한다.
    • Bookmark 하위 디렉토리로 이동한다.
    • Open Project Folder 버튼을 클릭한다.

  4. 다음과 같이 Bookmark 프로젝트를 빌드하고 배포한다.

    • Projects 창에서 Bookmark 프로젝트 노드를 오른쪽 클릭한다.
    • Deploy Project를 선택하거나 F6(기본 프로젝트 실행)을 누른다.

명령줄에서의 샘플 코드 빌드 및 배포

  1. AS_HOME 환경 변수를 GlassFish v2 설치 디렉토리로 설정한다. 예를 들면 (여기서는 bash 구문임)

          export AS_HOME= <GF_install_dir>

    이다. 여기서 <GF_install_dir>은 GlassFish v2를 설치한 디렉토리이다.

  2. <sample_install_dir>/jersey 디렉토리 아래 /examples/Bookmark 디렉토리로 이동한다. 명령줄에 다음 명령을 입력하여 Bookmark 애플리케이션을 빌드한다(bash 구문).

          AS_HOME/lib/ant/bin/ant run-on-glassfish

샘플 코드 실행하기

다음과 같이 배포된 Bookmark 애플리케이션을 명령줄 HTTP 도구인 Curl을 사용하여 실행할 수 있다.

  1. Curl을 다운로드하지 않았다면 다운로드한다.

  2. 명령줄에 다음 명령을 입력하여 새 사용자를 추가한다(포맷팅 때문에 지금과 이후 단계에서 명령은 여러 행으로 표시한다).

          curl -i --data "{\"userid\":\"techtip\",\"username\":
          \"TechTip User\",\"email\":\"techtip@example.com\",
          \"password\":\"TEST\"}" -H Content-type:application/json
          -X PUT
          http://localhost:8080/Bookmark/resources/users/techtip/

    그러면 HTTP GET 요청이 UsersResource 클래스의 getUser 메소드로 디스패치되고, 이는 새 UserResource 개체를 인스턴스화한다. 이 요청은 다시 putUser 메소드에 디스패치된다.

    다음과 같은 출력이 나타나야 한다.

          HTTP/1.1 204 No Content
          X-Powered-By: Servlet/2.5
          Server: Sun Java System Application Server 9.1_01
          Date: Thu, 01 Nov 2007 14:31:53 GMT

  3. 명령줄에 다음 명령을 입력하여 사용자 목록을 가져온다.

          curl -i -X GET
          http://localhost:8080/Bookmark/resources/users/

    그러면 UsersResource 클래스의 getUsersListAsJson 메소드를 호출한다.

    다음과 비슷한 출력이 나타난다.

          HTTP/1.1 200 OK
          X-Powered-By: Servlet/2.5
          Server: Sun Java System Application Server 9.1_01
          Content-Type: application/json
          Transfer-Encoding: chunked
          Date: Thu, 01 Nov 2007 14:34:07 GMT

          ["http:\/\/localhost:8080\/Bookmark\/resources\/users\
          /techtip"]

  4. 명령줄에 다음 명령을 입력하여 사용자의 표현을 가져온다.

          curl -i -X GET
          http://localhost:8080/Bookmark/resources/users/techtip/

    그 결과 작업은 2단계와 비슷하다.

    다음과 같은 출력이 나타나야 한다.

          HTTP/1.1 200 OK
          X-Powered-By: Servlet/2.5
          Server: Sun Java System Application Server 9.1_01
          Content-Type: application/json
          Transfer-Encoding: chunked
          Date: Thu, 01 Nov 2007 14:35:38 GMT

          {"userid":"techtip","username":"TechTip User",
          "email":"techtip@example.com","password":"TEST",
          "bookmarks":"http:\/\/localhost:8080\/Bookmark\/resources
          \/users\/techtip\/bookmarks"}

요약

이 팁에서는 Java에서 JSR-311(Java API for RESTful Web Services) 사양에 부합하는 RESTful 웹 서비스를 작성하는 방법을 소개했다. JAX-RS에 대한 자세한 내용은 jsr311 프로젝트에서 확인할 수 있다. JAX-RS의 참조 구현인 Jersey에 대해서는 Jersey 프로젝트에서 확인할 수 있다.

저자 정보

Jakub Podlesak는 Jersey 프로젝트 팀원이다. 그는 GlassFish v2 웹 서비스 스택인 Metro 개발에 참여한 바 있다.

Paul Sandoz는 JSR 311: Java API for RESTful Web Services의 공동 사양 책임자 겸 구현 책임자이다. 그는 W3C, ISO 및 ITU-T 표준화 기구에서 일한 바 있으며, GlassFish 웹 서비스 스택, 특히 Fast Infoset의 표준화, 구현, 통합 및 상호 운용성 분야에서 성능과 관련된 여러 기술 개발 및 향상에 기여했다.


이 아티클의 영문 원본은
http://java.sun.com/mailers/techtips/enterprise/2007/TechTips_Nov07.html
에서 볼 수 있습니다.


출처: http://blog.sdnkorea.com/blog/471
Posted by 1010
04.Anddoid2010. 9. 24. 16:50
반응형
Posted by 1010
04.Anddoid2010. 9. 24. 16:37
반응형
안녕하세요 오늘은 웹서버에서 이미지를 파싱해보려고합니다.
아주간단한 예제입니다.
필요하신분들은 참고하세요 :D



그냥 실행해보시면 퍼미션에러가 납니다. 꼭 AndroidManifest.xml 파일에다가 다음내용을 추가해주세요 !!
  1. <uses-permission 
  2.     android:name="android.permission.INTERNET"/> 


아주 미약한 실력이지만 주석달아놨습니다.
실수가 있을수있으니 실수가 있다면 태클 걸어주시기 바랍니다.

WebImageParse.java 소스입니다.
  1. package com.j0ker.parsing;  
  2.  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.net.HttpURLConnection;  
  6. import java.net.MalformedURLException;  
  7. import java.net.URL;  
  8. import java.util.HashMap;  
  9. import java.util.Map;  
  10. import java.util.Random;  
  11.  
  12. import android.app.Activity;  
  13. import android.os.Bundle;  
  14. import android.graphics.Bitmap;  
  15. import android.graphics.BitmapFactory;  
  16. import android.util.Log;  
  17. import android.view.View;  
  18. import android.widget.Button;  
  19. import android.widget.EditText;  
  20. import android.widget.ImageView;  
  21.  
  22.  
  23. public class WebImageParse extends Activity   
  24. {  
  25.     ImageView imView;  
  26.     String imageUrl = "http://j0ker.dothome.co.kr/"; // 이미지를 파싱해올 URL  
  27.     Random r; // 사진을 랜덤으로 불러오기위한 랜덤변수   
  28.       
  29.     /** Called when the activity is first created. */ 
  30.     @Override 
  31.     public void onCreate(Bundle savedInstanceState)   
  32.     {  
  33.         super.onCreate(savedInstanceState);  
  34.         setContentView(R.layout.main);  
  35.         r = new Random(); // 랜덤을 초기화 합니다.   
  36.           
  37.           
  38.         Button bt3 = (Button)findViewById(R.id.get_imagebt); // 버튼을 연결시켜줍니다.  
  39.         bt3.setOnClickListener(getImgListener); // 버튼에  클릭이벤트를 감지할 리스너를 설치해줍니다.  
  40.         imView = (ImageView)findViewById(R.id.imview); // 이미지를 읽어들일 이미지뷰를 연결해줍니다.  
  41.           
  42.     }  
  43.       
  44.     // 클릭이벤트가 발생했을경우 의 처리를 해주는 함수입니다.  
  45.     View.OnClickListener getImgListener = new View.OnClickListener()   
  46.     {  
  47.           
  48.         @Override 
  49.         public void onClick(View v) // 클릭이 일어났을경우    
  50.         {  
  51.             // TODO Auto-generated method stub  
  52.             int i = r.nextInt()%4+1; // i 에 랜덤한 숫자를 생성시켜줍니다.   
  53.             downloadFile(imageUrl+i+".png"); // 해당파일을 다운로드 합니다.   
  54.             Log.i("im url",imageUrl+i+".png"); // 디버깅을 위한 Log를 설정해줍니다.   
  55.         }  
  56.     };  
  57.       
  58.       
  59.     Bitmap bmImg; // 비트맵을처리할 변수를 생성합니다.  
  60.      // 이미지를 다운로드하는 함수입니다. 파라미터는 String형  
  61.     // fileUrl 이 들어갑니다.   
  62.     void downloadFile(String fileUrl)   
  63.     {  
  64.         URL myFileUrl = null; // URL 타입의 myFileUrl을  NULL로 초기화 시켜줍니다.   
  65.           
  66.         try 
  67.         {  
  68.             myFileUrl = new URL(fileUrl); //  파라미터로 넘어온 Url을 myFileUrl에 대입합니다.  
  69.               
  70.         }  
  71.         catch(MalformedURLException e) // 예외처리를 해줍니다.  
  72.         {  
  73.             // Todo Auto-generated catch block  
  74.             e.printStackTrace();  
  75.         }  
  76.         try 
  77.         {  
  78.             // 실질적인 통신이 이루어지는 부분입니다.  
  79.             // myFileUrl 로 접속을 시도합니다.   
  80.             HttpURLConnection conn = (HttpURLConnection)myFileUrl.openConnection();  
  81.             conn.setDoInput(true);  
  82.             conn.connect();  
  83.             int length = conn.getContentLength(); // 받아온 컨텐츠의 길이를 length 변수에 저장합니다.  
  84.             InputStream is = conn.getInputStream(); // InputStream is 변수에 받아온 InputStream을 저장합니다.  
  85.               
  86.             bmImg = BitmapFactory.decodeStream(is); // 받아온 이미지를 bmImg에 넣어둡니다.  
  87.             imView.setImageBitmap(bmImg); // imView에 이미지를 셋팅합니다.  
  88.         }  
  89.         catch(IOException e) // 예외처리를 해줍니다.  
  90.         {  
  91.             e.printStackTrace();   
  92.         }  
  93.     }  
  94. }  




Main.xml 내용입니다.
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     > 
  7.       
  8.    <TextView   
  9.         android:layout_width="fill_parent" 
  10.         android:layout_height="wrap_content" 
  11.         android:text="간단한 이미지파싱예제입니다. !"/> 
  12.       
  13.    <Button   
  14.         android:id="@+id/get_imagebt" 
  15.         android:layout_width="wrap_content" 
  16.         android:layout_height="wrap_content" 
  17.         android:text="Get an image" 
  18.         android:layout_gravity="center" 
  19.     />    
  20.       
  21.     <ImageView   
  22.         android:id="@+id/imview" 
  23.         android:layout_width="wrap_content" 
  24.         android:layout_height="wrap_content" 
  25.         android:layout_gravity="center" 
  26.      />    
  27.  </LinearLayout> 


Posted by 1010
04.Anddoid2010. 9. 24. 16:29
반응형

This week, I tried to build a simple system where I combine EJB and Android technologies. The idea was simple, I would have an EJB application at server-side which has an Entity Bean to fetch some data and using a Session Bean I would forward this data to a Dynamic Web Application (a Local JSP Client). And another Remote Android Client would show this data too.

To begin my experiment, I first installed JBoss5 Application Server, XDoclet, Eclipse Java EE and its related plugins.

After lots of experiments and trying to follow this tutorial, I was able to create an Dynamic Web Project having a JSP which gets it data from an EJB Project’s Session Bean. Before I began to connect a database to this EJB Project using an Entity Bean, I tried to bind a Remote Android Client to this EJB. But, unfortunately there was no sources for this at web and I couldn’t get it done myself. Also from what I read at blogs, It seems that it’ll be wise to use Web Service approach instead of EJB.

So, I tried to implement a Web Service using my EJB Project. But, it was also another mystery for me. There is no good documentation/tutorial about how to create anything using Eclipse. Using Murat’s previous notes, I tried to generate my EJB based Web Service but, It was also another failure. So I simply create a regular Web Service using regular Java Classes.

But there is also a problem about Web Service approach. Android SDK doesn’t support a high level remote protocol like SOAP. To have SOAP support, we must use kSoap2 engine, which I had no time to look up.

This week was most of a failure for me, next week I’m planning to reach my regular Web services using Android with kSoap2.

Posted by 1010
04.Anddoid2010. 9. 24. 16:28
반응형

How-to: Pure Html Android Application

Cansin

In this tutorial I’ll talk about creating an Android application which will get all it’s data from Http requests. To develop the application, I used WebView and WebViewClient classes of the Webkit.

This is rather a straight forward tutorial. To show a WebView in our application we need to add a WebView to our /res/layout/main.xml file. Simply add the following element under <LinearLayout> tag.

<WebView
    android:id="@+id/webView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>

Then we need to access this WebView at our onCreate method and make necessary manipulations. We can get our view by R.findViewById(R.id.webview). To have a native look, we disabled some functionalities of WebView object.

The important part of our code is to listen URL loadings. By default, when you click a HTML link in a WebView, page is loaded at Browser. We want to override this behavior so that when we click a link it will be loaded at our WebView. It’s pretty simple actually. All we have to do is to set a WebViewClient object to our WebView and implement its shouldOverrideUrlLoading(WebView,String) method. We can even send Get request by doing so. Actually we can’t add any get request to our url. If we try to use loadUrl function to do this, we’ll loose our previous post/get objects which are sent to the url. But if you don’t have any previous request objects, it’s safe to use loadUrl to manipulate it.

So here is the source code of the tutorial. Hope, it’ll be useful.

P.s: Don’t forget to add following field to AndroidManifest.xml to have an internet connection.

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
package praeda.muzikmekan;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
public class Index extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        WebView web = (WebView) findViewById(R.id.webView);
        web.getSettings().setJavaScriptEnabled(true); 
        web.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
        web.getSettings().setPluginsEnabled(false);
        web.getSettings().setSupportMultipleWindows(false);
        web.getSettings().setSupportZoom(false);
        web.setVerticalScrollBarEnabled(false);
        web.setHorizontalScrollBarEnabled(false);
 
        //Our application's main page will be loaded
        web.loadUrl("http://senior.ceng.metu.edu.tr/2009/praeda/");
 
        web.setWebViewClient(new WebViewClient() {
            @Override public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return false;
            }
        });
    }
}

출처: http://senior.ceng.metu.edu.tr/2009/praeda/2009/01/11/how-to-pure-html-android-application/
Posted by 1010
04.Anddoid2010. 9. 24. 16:27
반응형

How-to: Android as a RESTful Client

Cansin

This is a how-to focused on creating a RESTful java object at Android. I’ve used HTTPClient, HTTPEntry, HTTPGet, HTTPResponse, JSONArray and JSONObject classes. I think it’ll be useful if we need to use a web-service from client application.

I’ve implemented a simple Java Object called RestClient which connects to a given Rest-JSON service. After connection, this object prints response content. Using this content, a JSONObject created. Then, RestClient prints the JSONObject’s content, parses all values of this object and prints them as well. And as a last job, RestClient pushes a sample value to the JSONObject.

I’ve uploaded RestClient. Hope it’ll be useful.

P.s: To get access to internet at Android, following field must be included to AndroidManifest.xml file of the project.

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
package praeda.muzikmekan;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
import android.util.Log;
 
public class RestClient {
 
    private static String convertStreamToString(InputStream is) {
        /*
         * To convert the InputStream to String we use the BufferedReader.readLine()
         * method. We iterate until the BufferedReader return null which means
         * there's no more data to read. Each line will appended to a StringBuilder
         * and returned as String.
         */
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
 
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
 
    /* This is a test function which will connects to a given
     * rest service and prints it's response to Android Log with
     * labels "Praeda".
     */
    public static void connect(String url)
    {
 
        HttpClient httpclient = new DefaultHttpClient();
 
        // Prepare a request object
        HttpGet httpget = new HttpGet(url); 
 
        // Execute the request
        HttpResponse response;
        try {
            response = httpclient.execute(httpget);
            // Examine the response status
            Log.i("Praeda",response.getStatusLine().toString());
 
            // Get hold of the response entity
            HttpEntity entity = response.getEntity();
            // If the response does not enclose an entity, there is no need
            // to worry about connection release
 
            if (entity != null) {
 
                // A Simple JSON Response Read
                InputStream instream = entity.getContent();
                String result= convertStreamToString(instream);
                Log.i("Praeda",result);
 
                // A Simple JSONObject Creation
                JSONObject json=new JSONObject(result);
                Log.i("Praeda","<jsonobject>\n"+json.toString()+"\n</jsonobject>");
 
                // A Simple JSONObject Parsing
                JSONArray nameArray=json.names();
                JSONArray valArray=json.toJSONArray(nameArray);
                for(int i=0;i<valArray.length();i++)
                {
                    Log.i("Praeda","<jsonname"+i+">\n"+nameArray.getString(i)+"\n</jsonname"+i+">\n"
                            +"<jsonvalue"+i+">\n"+valArray.getString(i)+"\n</jsonvalue"+i+">");
                }
 
                // A Simple JSONObject Value Pushing
                json.put("sample key", "sample value");
                Log.i("Praeda","<jsonobject>\n"+json.toString()+"\n</jsonobject>");
 
                // Closing the input stream will trigger connection release
                instream.close();
            }
 
 
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
}

출처 : http://senior.ceng.metu.edu.tr/2009/praeda/2009/01/11/a-simple-restful-client-at-android/
Posted by 1010
반응형
http://jquerylist.com/
http://jqueryui.com/


Posted by 1010
반응형
IntelliJ IDEA

소개

주요 링크

특징

  • 기능이 다양하며 이클립스 보다 안정적임
  • 플러그인 설치가 편리함
  • SVN, Git를 포함한 각종 VCM 플러그인이 기본으로 설치되어 있음
  • 9 버전(maia) 새 기능: http://www.jetbrains.com/idea/whatsnew/index.html

사용법

Posted by 1010
98..Etc/Etc...2010. 9. 2. 13:50
반응형

Windows Azure에서 Java 기반의 응용프로그램을 만들고 호스트할 수 있다는 이야기는 지속적으로 제시되어왔었습니다. 하지만, JSP 서블릿 페이지도 Windows Azure에서 호스트할 수 있을까요? Microsoft Architect로 활동 중인 David Chou가 작성한 블로그 포스트에 답이 있습니다. 오늘 제가 올리는 블로그 포스트는 다음 포스트에 대한 설명을 기초로 중요한 부분을 추출한 것임을 밝힙니다. (http://blogs.msdn.com/b/dachou/archive/2010/03/21/run-java-with-jetty-in-windows-azure.aspx)

Jetty (http://jetty.codehaus.org/) 프로젝트는 자바 기반의 오픈 소스 웹 서버로, HTTP 서버로서의 역할과 서블릿 컨테이너의 기능을 제공합니다. 정적, 동적 컨텐츠를 모두 지원하고, 독립적으로 실행할 수도 있고, 다른 프로세스에 부착되어 실행되는 기능 또한 제공됩니다. 이러한 특성을 바탕으로, Apache Project의 ActiveMQ, Cocoon, Hadoop, Maven Project, BEA Web Logic Event Server, Eucalyptus, FioranoMQ Java Messaging Server, Google AppEngine 및 안드로이드, Eclipse용 웹 툴킷 플러그인, 레드햇 J보스, Sonic MQ, 스프링 프레임워크, 사이베이스 EA서버, 짐브라 데스크톱 등 광범위하게 Jetty가 채택되고 있습니다.

Jetty 프로젝트는 아래와 같은 기능들을 제공합니다.

  • 비동기 HTTP 서버
  • 표준 지향의 서블릿 컨테이너
  • 웹 소켓 서버
  • 비동기 HTTP 클라이언트
  • OSGi, JNDI, JMX, JASPI, AJP 지원

응용프로그램 컨테이너의 관점에서 보면, Jetty는 전통적인 Java 기반의 Web Application Server들 (Tomcat과 같은)을 대치하는 배포 방법으로 사용될 수 있으며, 스프링 프레임워크 및 관련된 모든 파생 프로젝트들, EJB 컨테이너 등 대부분의 일반적인 웹 기반 자바 어플리케이션을 손쉽게 제공할 수 있는 것이 특징입니다.

Windows Azure에서의 Java 기술 지원

PDC'09 이후로 http://code.msdn.microsoft.com/winazuretomcat 웹 사이트를 통하여 Windows Azure 환경 위에서 Tomcat을 이용하여 JSP 기반 웹 응용프로그램의 구동 가능 여부와 샘플 코드를 지속적으로 홍보해왔었습니다. 그리고 이러한 사실을 바탕으로 http://blogs.msdn.com/jonbox/archive/2009/11/17/domino-s-demonstrates-tomcat-site-on-windows-azure.aspx 에서는 도미노 피자의 기존 피자 온라인 주문 웹 서비스를 Windows Azure 환경에서 구동하는 사례도 선보였습니다. 아래는 그동안 언급되거나 발표되어왔던 Windows Azure 환경에서의 Java 구동 방법에 관한 간략한 리스트입니다.

  • http://code.msdn.microsoft.com/winazuretomcat
  • http://www.interoperabilitybridges.com/projects/windows-azure-sdk-for-java.aspx
  • http://microsoftpdc.com/Sessions/SVC50
  • http://blogs.msdn.com/jonbox/archive/2009/11/17/domino-s-demonstrates-tomcat-site-on-windows-azure.aspx
  • 그러나 위에서 언급하는 Tomcat만이 Windows Azure 환경에서 사용할 수 있는 유일한 Web Application Server의 종류는 아닙니다. 사실, 위의 접근 방법들은 모두 Windows Azure Role에 함께 첨부되어 배포되는 Java 실행 환경 (JRE)를 기초로 하는 것이고, 그러므로 어떤 종류의 Java 패키지이든 관계없이 명령줄을 통하여 Classpath를 명시하는 방식으로 실행될 수 있습니다. 대개의 경우, 작업자 역할 (Worker Role) 패키지 위에서 실행되도록 디자인되고, Windows Azure 환경으로 배포될 수 있습니다. 그리고, 당연한 이야기이지만 Java와 Fast CGI를 결합하고, IIS 7.x를 기반으로 Fast CGI를 지원하는 Web Role을 이용할 수도 있습니다. 이 부분은 나중에 좀 더 자세히 소개하도록 하겠습니다.

    Windows Azure 환경에서 Jetty 실행

    아래는 실제 Windows Azure 환경에서 Jetty를 기반으로 실행하는 Windows Azure Worker Role의 구동 예시입니다.

    위와 같이 구현하기 위한 방법을 지금부터 차례대로 따라해보기로 하겠습니다.

    1. Windows Azure Worker Role 프로젝트를 만들고, Worker Role 진입점 메서드인 Run 메서드의 중심부에 다음과 같이 프로그래밍합니다.

    string response = "";
    try
    {
        System.IO.StreamReader sr;
        string port = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["HttpIn"].IPEndpoint.Port.ToString();
        string roleRoot = Environment.GetEnvironmentVariable("RoleRoot");
        string jettyHome = roleRoot + @"\approot\app\jetty7";
        string jreHome = roleRoot + @"\approot\app\jre6";
        Process proc = new Process();
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.StartInfo.FileName = String.Format("\"{0}\\bin\\java.exe\"", jreHome);
        proc.StartInfo.Arguments = String.Format("-Djetty.port={0} -Djetty.home=\"{1}\" -jar \"{1}\\start.jar\"", port, jettyHome);
        proc.EnableRaisingEvents = false;
        proc.Start();
        sr = proc.StandardOutput;
        response = sr.ReadToEnd();
    }
    catch (Exception ex)
    {
        response = ex.Message;
        Trace.TraceError(response);
    }

    제가 이전에 게시한 글 "[Software Development/Windows Azure] - Windows Azure 들여다보기"에서 언급한 내용들을 참조하여 위의 코드를 보시면 이해하기 쉽습니다. 몇 가지 Windows Azure 환경에서 기본으로 제공되는 환경 변수, 디렉터리 설정 등을 바탕으로 Jetty 프로세스를 Java VM (java.exe)를 통하여 실행하도록 명령어를 구성하고 실행한 다음, 표준 출력의 내용을 Windows Azure Worker Role Process로 가져오도록 만드는 것을 볼 수 있습니다.

    2. Jetty 프로젝트와 Java VM의 최신 버전을 Windows Azure Worker Role 프로젝트에 추가합니다.

    다음 그림과 같이 폴더를 구성하면 되겠습니다. jetty7 폴더와 jre6 폴더 아래에 직접 해당 프레임워크 및 시스템의 실제 디렉터리 구조가 오도록 맞추면 문제 없습니다. 참고로, 확실하게 동작할 수 있도록 만들기 위하여 Java VM의 경우는 특별히 Windows Platform을 기반으로하는 x64 아키텍처 버전을 다운로드하여 아래 그림과 같이 넣어두어야 합니다. (중요)

    3. ServiceDefinition.csdef 파일 수정하기

    1단계에서 사용한 HttpIn이라는 설정을 Worker Role에 추가해야 하므로, ServiceDefinition.csdef 파일을 찾아 "WorkerRole" 요소 아래에 다음과 같이 내용을 추가하고 저장합니다. 참고로 이 설정은 Windows Azure Worker Role이 80번 TCP 포트 통신이 필요함을 Windows Azure 환경 내의 방화벽에게 통지하기 위한 목적으로 사용됩니다.

    <Endpoints>
      <InputEndpoint name="HttpIn" port="80" protocol="tcp" />
    </Endpoints>

    4. Windows Azure에서 사용할 수 있도록 Jetty 환경 설정

    Jetty가 사용되거나 환경 설정을 만드는 방법은 Windows Azure 환경에서 여러 가지가 있을 수 있지만, 특별히 이와 같이 Worker Role 위에서 Standalone Server로 동작하기 위하여 필요한 환경 설정이 있어서 이를 소개합니다. Windows Azure 환경에서는 Jetty가 기본으로 사용하는 NIO ChannelConnector 대신 BIO SocketConnector를 사용하도록 구성해야 합니다. NIO ChannelConnector에서는 내부적으로 루프백 연결을 기초로 하지만 Windows Azure 환경에서는 이것이 가로막혀있기 때문이라는 것이 David Chou의 설명입니다.

    이러한 설정을 수정하기 위해서는 Jetty 패키지 디렉터리 아래의 etc 디렉터리의 jetty.xml 파일을 수정해야 하며, <New> 태그의 class attribute를 org.eclipse.jetty.server.nio.SelectChannelConnector 대신 org.eclipse.jetty.server.bio.SocketConnector로 변경하고, NIO ChannelConnector에만 한정되는 몇 가지 옵션을 제거하는 방법으로 변경이 가능하며 정리하면 다음과 같습니다.

    <Call name="addConnector">
      <Arg>
        <New class="org.eclipse.jetty.server.bio.SocketConnector">
          <Set name="host"><SystemProperty name="jetty.host" /></Set>
          <Set name="port"><SystemProperty name="jetty.port" default="8080" /></Set>
          <Set name="maxIdleTime">300000</Set>
        </New>
      </Arg>
    </Call>

    그리고 좀 더 최적화된 설정을 위하여, Jetty가 자체 로그를 기록하지 않도록, etc 디렉터리의 jetty.xml 파일에서 RequestLog 핸들러 부분을 주석으로 처리하고, 확장자가 war인 패키지의 압축을 풀지 않도록 etc 디렉터리의 jetty.xml 파일에서 addBean "org.eclipse.jetty.deploy.WebAppDeployer"의 "extract" 프로퍼티의 값을 "false"로 지정하고, contexts 디렉터리의 test.xml 파일에서 <Set name="extractWAR"> 부분의 프로퍼티 값을 "false"로 지정하였다는 것이 저자의 설명입니다.

    이러한 설정들이 모두 적용된 실제 샘플은 http://cid-b43074894ffe6264.skydrive.live.com/self.aspx/.Public/Projects/JettyCloudService.zip 에서 다운로드받아보실 수 있습니다. :-)

    마무리

    Windows Azure Platform이 Microsoft의 기술이므로 철저히 .NET Framework 기반의 응용프로그램 개발만을 지원할 것이라는 편견은 종합적으로 "잘못된 것입니다." Windows Server 2008 R2의 기술을 기반으로 하고 있기 때문에, 여러분의 응용프로그램이 Windows Server 2008 R2, 그리고 64비트 환경에서 성공적으로 수행될 수 있는 조건을 갖추고 있다면 Windows Azure Platform은 성공적으로 여러분들의 클라우드 컴퓨팅으로의 계획을 이끌어 줄 수 있을 것입니다.

    만약 좀 더 심층적인 예제나, Tomcat 기반의 Windows Azure 구동 사례를 보기 원하신다면, http://code.msdn.microsoft.com/winazuretomcat 를 방문하셔서 샘플 코드와 문서를 다운로드하시기를 권합니다.

    감사합니다. :-)


    출처 : http://www.rkttu.com/402

    Posted by 1010
    반응형
    Hdiv 
    애플리케이션 보안 프레임워크, 프로그램 설명서, 다운로드 등 제공.
    http://www.hdiv.org/ 컴퓨터, 인터넷 > 소프트웨어 > 라이센스 > 오픈 소스
    Posted by 1010
    반응형

    In order to solve web application vulnerabilities we have created HDIV (HTTP Data Integrity Validator) open source project.

    We can briefly define HDIV as a Java Web Application Security Framework. HDIV extends web applications’ behaviour by adding Security functionalities, maintaining the API and the framework specification. This implies that we can use HDIV in applications developed in Struts 1.x, Struts 2.x, Spring MVC and JSTL in a transparent way to the programmer and without adding any complexity to the application development. It is possible to use HDIV in applications that don’t use Struts 1.x, Struts 2.x, Spring MVC or JSTL, but in this case it is necessary to modify the application (JSP pages).

    The security functionalities added to the web applications are these:

    INTEGRITY: HDIV guarantees integrity (no data modification) of all the data generated by the server which should not be modified by the client (links, hidden fields, combo values, radio buttons, destiny pages, etc.). Thanks to this property HDIV helps to eliminate most of the vulnerabilities based on the parameter tampering.

    EDITABLE DATA VALIDATION: HDIV eliminates to a large extent the risk originated by attacks of type Cross-site scripting (XSS) and SQL Injection using generic validations of the editable data (text and textarea).

    CONFIDENTIALITY: HDIV guarantees the confidentiality of the non editable data as well. Usually lots of the data sent to the client has key information for the attackers such as database registry identifiers, column or table names, web directories, etc. All these values are hidden by HDIV to avoid a malicious use of them. For example a link of this type, http://www.host.com?data1=12&data2=24 is replaced by http://www.host.com?data1=0&data2=1, guaranteeing confidentiality of the values representing database identifiers.

    ANTI-CROSS SITE REQUEST FORGERY (CSRF) TOKEN: Random string called a token is placed in each form and link of the HTML response, ensuring that this value will be submitted with the next request. This random string provides protection because not only does the compromised site need to know the URL of the target site and a valid request format for the target site, it also must know the random string which changes for each visited page.

    Posted by 1010
    51.Struts22010. 8. 26. 15:09
    반응형

    FreeMarker

    # 이 문서는 오라클클럽에서 작성하였습니다.
    # 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
    # 출처 : http://www.gurubee.net/display/SWDEV/FreeMarker?



    3.1 FreeMarker




    * 아래 내용은 http://blog.daum.net/younwoomom/6685378 의 내용을 정리한 자료 입니다.

    Freemarker 사용법

    1. @macro

    프리마커 템플릿 전역에서 공통으로 사용되는 UI 디펜던트한 함수는 매크로로 만들어 여러 ftl에서 사용할 수 있도록 해준다. 샘플을 참고하도록 한다.

    형식 : <@매크로명 변수1, 변수2, ... />

    샘플1) 긴 문자열을 적당한 크기로 자르는 기능의 매크로

    *사용법 :

    <@trimX item.title, 20 />

    *매크로 :
    <#macro trimX src max><#compress>
    <#if src?length &gt; max>
    ${src[OSF:0..max-1]}
    <#else>
    ${src}
    </#if>
    </#compress></#macro>

    샘플2) YYYYMMDD 형식의 문자열을 YYYY.MM.DD 형식으로 변환하는 매크로

    *사용법 :

    <@parseDay item.regdate />

    *매크로 :
    <#macro parseDay src><#compress>
    <#if src?length == 8>
    ${src[OSF:0..3]}.${src[OSF:4..5]?number}.${src[OSF:6..7]?number}
    <#else>
    ${src}
    </#if>
    </#compress></#macro>



    2. #list

    배열 형식의 오브젝트를 루핑 처리할때 사용하는 프리마커 지시자이다. "로컬엘리어스_index" 라는 변수는 0부터 시작하는 시퀀스번호이다.

    형식 : <#list 배열객체 as 로컬엘리어스명></#list>

    샘플1)

    <#list LIST as item>
    번호 : ${item_index+1} | 이름 : ${item.name} | 아이디 : ${item.id}
    </#list>



    3. #if

    프리마커 조건문에 사용되는 지시자이다.

    형식 : <#if 조건식></#if>

    샘플1) string 비교

    <#if ENTITY.usergrade == "A" >......</#if>

    샘플2) number 비교

    <#if ENTITY.userclass?number == 3>.....</#if>

    샘플3) boolean 비교

    <#if ENTITY.isAuth()>.....</#if>



    4. #break

    Loop문을 중단하고 다음 스크립트로 넘어가려고 할때 사용되는 지시자이다.

    형식 : <#break>

    샘플1) 루프문을 실행하는 중 5번째에서 escape 하는 예

    <#list LIST as item>
    <#if item_index &gt; 3><#break></#if>
    </#list>



    5. #assign

    프리마커내에서 사용자 정의 로컬변수가 필요할 때 사용하는 지시자이다.

    형식 : <#assign 로컬변수명 = 초기화값>

    샘플1)
    <#assign CHECK = item_index>



    6. [OSF: x...y]

    문자열의 일정 범위를 자를때 사용하는 함수

    형식 :

     ${문자열[OSF: 1..5 ]} 

    샘플1)
    ${item.name[OSF:1..5]}



    7. ?has_content

    리스트형 오브젝트가 null이 아니고 최소 1개 이상의 컨텐츠를 가지고 있는지 체크하는 함수로써 ?has_content는 ?exists와 ?size>0 두가지 체크를 동시에 해주는 함수이다.

    형식 : 리스트오브젝트?has_content

    샘플1)
    <#if LIST?has_content>.....</#if>



    8. ?exists

    NULL체크 함수. if_exists는 <#if 지시자 없이도 사용할 수 있게 해주는 표현식이다.

    형식 : 오브젝트?exists

    샘플1)
    <#if ENTITY.username?exists>${ENTITY.username?substring(0, 5)}</#if>

    샘플2)
    <#if LIST?exists && LIST?size &gt; 0>.....</#if>

    샘플3)
    ${ENTITY.username?if_exists}



    9. ?default

    NULL값을 대체해주는 함수

    형식 : 오브젝트?default(디폴트값)

    샘플1)
    ${item.userclass?default("99")}

    샘플2)
    ${item.age?default(20)}



    10. ?string

    문자열로 형변환하는 함수

    형식 : 오브젝트?string

    샘플1)
    <#if item.age?string == "29">.....</#if>

    샘플2)
    ${item.regdate?string("yyyy/MM/dd HH:mm")}

    샘플3) 숫자를 통화표시로 나타내는 예

    <#assign MONEY = 1234567>
    ${MONEY?string(",##0")}



    11. ?number

    숫자로 형변환하는 함수

    형식 : 오브젝트?number

    샘플1)
    <#if item.userclass?number &gt; 3>.....</#if>

    샘플2)
    ${LIST_POINTS[OSF:item.gid?number].entityname?default("")}



    12. ?js_string

    문자열을 자바스크립트에 유효하도록 필터링해주는 함수.
    문자열내에 싱글쿼테이션(')등이 포함되어 스크립트에 오류가 나는것을 방지하기 위하여 사용되는 함수이다.
    화면상에는 HTML 태그로 취급된다.

    형식 : 오브젝트?js_string

    샘플1)

    문자열 <img src='/image/enterprise.gif'>을 js_string으로 처리했을때 소스보기를 하면 <img src=\'/image/enterprise.gif\'>으로 출력된다.

    샘플2)
    <a href="javascript:getName('${item.homeurl?js_string}');">



    13. ?html

    문자열을 HTML Symbolic Entity로 필터링해주는 함수. 문자열내의 HTML태그등을 깨뜨려 화면상으로 출력되도록 할때 사용하는 함수이다. 화면상에 HTML태그가 아닌 일반 문자열로 취급된다.

    형식 : 오브젝트?html

    샘플1)

    문자열 <img src='/image/enterprise.gif'>을 html로 처리하면 화면상에 <img src='/image/enterprise.gif'> 로 출력되고 
    소스보기를 하면 &lt;img src='/image/enterprise.gif'&gt;로 출력된다.



    14. ?index_of

    특정 문자(열)가 시작되는 위치를 정수형으로 반환한다. 인덱스는 0부터 시작됨.

    형식 : 오브젝트?index_of(특정문자)

    샘플1)
    "abcde"?index_of("c") 는 2를 반환한다.



    15. ?replace

    문자열의 일부를 주어진 문자로 대체하는 함수

    형식 : 오브젝트?replace(찾을문자열, 대체할문자열)

    샘플1)
    ${item.content?replace(">", "&gt;")}



    16. item_has_next

    리스트 객체의 다음 컨텐츠가 존재하는지(EOF) 체크하는 함수

    형식 : 리스트엘리어스이름_has_next

    샘플1) 이름과 이름사이에 , 를 찍어주되 마지막은 찍지 않는 경우의 예

    <#list LIST as item>
    ${item.name?default("")}<#if item_has_next>,</#if>
    </#list>

    문서에 대하여

    • 이 문서는 http://blog.daum.net/younwoomom/6685378 의 내용을 참고하여 작성하였습니다.
    • 최초작성자 : 김정식
    • 최초작성일 : 2008년 1월 15일
    • 이 문서를 다른 블로그나 홈페이지에 퍼가실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^

    # 이 문서는 오라클클럽에서 작성하였습니다.
    # 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
    # 출처 : http://www.gurubee.net/display/SWDEV/FreeMarker?
    Posted by 1010
    51.Struts22010. 8. 26. 15:05
    반응형

    freemarker 설명 및 기본 예제

    # 이 문서는 오라클클럽에서 작성하였습니다.
    # 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
    # 출처 : http://www.gurubee.net/pages/viewpage.action?pageId=1343682&



    1 FreeMarker 란?

    • 프리마커는 자바 서블릿을 위한 오픈소스 HTML 템플릿 엔진이다.
    • 프리마커에서는 HTML을 템플릿으로 저장하는데 이들은 결국 템플릿 객체로 컴파일 된다.
    • 이 템플릿 객체들은 서블리셍서 제공하는 데이터들을 이용하여 HTML을 동적으로 생성한다.
    • 프리마커 객체들은 서블릿에서 제공하는 데이터들을 이용하여 HTML을 동적으로 생성한다.
      [*.java]Servlet \+Template[*.ftl] = [*.html]Output

    2 FreeMarker 구조

    • FreeMarker는 표현의 결과물을 HTML(템플릿)로 관리하고 여기에 자바 객체를 연결하여 최종적인 결과를 만들어낸다.

    3 FreeMarker 셋팅

    3.1 다운로드

    3.2 설치

    • freemarker.jar 파일을 WEB-INF/lib 안에 넣는다.
    • ecilpse에서는 프로젝트 마다 lib안에 import 시킨다.

    3.3 Java 코딩시

    import freemarker.template.*;
    • FreemarkerServlet를 extends 한 후 Java coding 해주면 된다.

    4 FreeMaker 문법

    • FreeMarker의 메뉴얼 : http://www.freemarker.org/docs/
      FTL tag 
      <# > 
      
      
      주석 
      <#--주석달기--> 
      
      
      반복문 
      1. 
      <#list [Object code에서 key값 ]  as  [별칭할 값]> 
       
      2. for(int i=0;i<10;i++)
      <#list  1..10  as i > 
            ${i}
         <#assign i=i+1?int>
       
      3. 사이즈를 알고 싶을때.. Key 값이 list 인 경우
       
      <#assign size=list?size>
       
      4. 다른 변수로 정의하고 싶을때에는 
      <#setting [새로]=[기존]>
      
       
      5. 변수선언 
      
      <#assign x=0>   <#--x에 0를 할당해 준것이다. --> 
      x값을 출력하고자 할때 --> ${x} 
      
      
      6. <#macro green> 
      "<@green>"이런식으로 쓴다. 
      주로 변하지 않는 변수를 이렇게 선언해서 쓴다. 
       
      7. 조건문 
      <#if> 
       
      8. int형으로 선언해 주고 싶은때에는
      <#assign x=0 ? int>

    5 FreeMarker 예제

    5.1 TLD 파일

    • fmtag.tld (WEB-INF 아래 위치)
      <?xml version="1.0" encoding="ISO-8859-1" ?>
      <!DOCTYPE taglib
            PUBLIC "-Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
            "http://java.sun.com/j2ee/dtds/web-jsptaglib_1_1.dtd">
      <taglib>
        <tlibversion>2.0<.tlibversion>
        <jspversion>1.1</jspversion>
        <shortname>FreeMarker JSP Support</shortname>
      
        <tag>
         <name>template</name>
         <tagclass>freemarker.ext.jsp.FreemarkerTag</tagclass>
         <bodycontent>tagdependent</bodycontent>
         <info>Allow evaluation of FreeMarker templates inside JSP</info>
         <attribute>
          <name>cashing</name>
          <required>false</required>
         </attribute>
        </tag>
      </taglib>

    5.2 java 파일

    • SimpleBean.java (WEB-INF/classes/freemarker/examples/jsp)
    • Custom Tag 수행을 위한 Tag Handler Class
      package freemarker.examples.jsp;
      
      public class SimpleBean
      {
        private static String[] arr = {"a","b","c","d"};
        private String theString = "Hello from " + toString();
      
        public void setString(String foo)
        {
          theString = foo;
        }
      
        public String getString()
        {
          return theString;
        }
      
        public String[] getArray()
        {
          return arr;
        }
      }

    5.3 jsp 파일

    • freemarker2.jsp (View 파일)
      <%@ page contentType="text/html; charset=euc-kr" %>
      <%@ taglib uri="/WEB-INF/fmtag.tld" prefix="fm" %>
      
      <jsp:useBean id="mybean" class="freemarker.examples.jsp.SimpleBean"/>
      <jsp:useBean id="mybeanreq" class="freemarker.examples.jsp.SimpleBean" scope="request" />
      
      <fm:template>
      <html>
      <body>
       <h1>FreeMarker JSP example</h1>
       <hr>
       <p>JSP 페이지</p>
      
       <#assign mybean = page.mybean>
       <#assign mybeanreq = request.mybeanreq>
      
       <p>page : ${mybean.string}
       <#list mybean.array as item>
        <br>${item}
       </#list>
      
       <p><b>Note:</b>
      </body>
      </html>
      </fm.template>



    # 이 문서는 오라클클럽에서 작성하였습니다.
    # 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
    # 출처 : http://www.gurubee.net/pages/viewpage.action?pageId=1343682&
    Posted by 1010
    98..Etc/Etc...2010. 8. 20. 15:53
    반응형
    Facebook의 실시간 웹 프레임워크 ‘Tornado’


    실시간 업데이트는 요즘 웹 어플리케이션의 대세가 된지 오래다. 예전 채팅의 진보한 형태라 할 수 있는 실시간 웹 어플리케이션은 채팅과 달리 공개 대화 중심이란 점과 기술적으로 단방향 push 라는 한계가 있지만 이를 극복하기 위한 여러가지 새로운 시도가 진행되고 있다.

    그 중 오늘 Facebook 개발자 블로그에 올라온 글을 보면 최근 Facebook이 실시간(real-time) 업데이트를 위한 여러가지 시도를 하고 있고(real-time news feed 와 같은) 이를 위해 얼마전 인수한 FriendFeed의 기술을 채택할 예정이라고 한다.

    Jim Norris, Paul Buchheit등 구글 출신의 python 구루로 이뤄진 FriendFeed가 개발한 이 기술은 Tornado라고 불리우는 python 웹 서버다. 매우 단순한 구조로 이뤄졌으며 non-blocking HTTP 서버, low-level I/O 모듈을 통해 real-time에 이상적으로 설계했다고 한다.

    그래서 이런 High performance를 낸다는 말이다. 실시간이 대세가 되면서 성능이 주요한 쟁점으로 떠올랐다. Java로 대표되는 “구조”적인 문제는 더 이상 논의 대상이 되지 않는다.

    전통적인 LAMP 방식으로는 더 이상 Facebook이나 FriendFeed와 같은 실시간 어플리케이션을 만들긴 힘들다고 지적한다. 앞으로는 지금 소개한 Tornado와 함께 Cassandra, Hive, memcache, Scribe, Thrift와 같은 새로운 컴포넌트들이 웹의 혁신을 이끌 것이다.

    Facebook은 여러 오픈 소스 프로젝트를 진행하는 것으로도 유명한데, 여기에 FriendFeed의 원군을 얻었으니 날개를 단 격이다. 앞으로 더욱 적극적인 오픈소스 프로젝트 전개가 예상된다.

    FriendFeed의 CEO인 Bret Taylor가 Tornado에 대해 다시 한번 자세히 언급했다.

    1 comment

    Twisted가 있는데 Tornado를 만든 것은 FriendFeed의 멍청한 삽질이라고밖에는 생각되지 않습니다.

    Twisted 개발자의 평입니다.
    http://glyph.twistedmatrix.com/2009/09/what-i-wish-tornado-were.html

    Twisted를 사용하는 FluidDB의 CEO의 평입니다.
    http://blogs.fluidinfo.com/terry/2009/09/12/facebook-release-tornado-and-its-not-based-on-twisted/

    Twisted 사용자 중 한명이 하루만에 Tornado의 low-level IO를 모두 걷어내고 (1300줄 삭제) Twisted로 대체했습니다. 저는 FriendFeed가 이 패치를 받아들이기를 바랍니다.
    http://dustin.github.com/2009/09/12/tornado.html


    출처: http://www.likejazz.com/archives/778

    Posted by 1010