Linux2013.04.08 18:56

오랜만에 블로그에 글을 남겨보고자 합니다.

얼마전에 회사를 옮기고 나서, 요즘 한참 개발환경을 설치하느라 정신이 없습니다.ㅠㅠ 

그런데 중요한 건 이곳에서의 개발환경이 실서버가 아닌 클라우드에서 할당받은 VM 인스턴스라는 것입니다. 

이제 클라우드가 우리의 생활속에 많이 활용되고 있다는 사실을 개발현장에도 느낄 수 있었습니다.


오늘은 Java를 여러버전을 설치하고서 Linux에서 기본으로 쓰는 Java Version을 선택해 주는 alternatives에 대해 글을 올려볼까 합니다. 매일 Ubuntu만 쓰다가 이곳에 와서 Red Hat을 쓰려니 어색하고 생소하네요~!! 그래도 같은 리눅스니 설치 명령어를 제외하고 나머지 일반적인 명령어들은 모두 같답니다. ^^  


alternatives 라는 명령어를 그냥 실행해 보면 아래와 같이 Help를 확인할 수 있다. 

# alternatives

대체 버전 1.3.13.5.EL4 - Copyright (C) 2001 Red Hat, Inc.

이 프로그램은 GNU Public License를 따른다는 조건 하에서 이 문서를

자유롭게 재배포하실 수 있습니다.

사용법: alternatives --install <link> <name> <path> <priority>

                    [--initscript <service>]

                    [--slave <link> <name> <path>]*

       alternatives --remove <name> <path>

       alternatives --auto <name>

       alternatives --config <name>

       alternatives --display <name>

       alternatives --set <name> <path>

 

일반 옵션들: --verbose --test --help --usage --version

                --altdir <directory> --admindir <directory>


# 사용가능한 자바목록에 Java Version 추가

# alternatives --install /usr/bin/java java /user/wh/jdk1.6.0_35/bin/java 100


# Default Java로 설정 변경

# alternatives --config java

 

4 개의 프로그램이 'java'를 제공합니다.

 

  선택    명령

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

*+ 1           /usr/lib/jvm/jre-1.4.2-gcj/bin/java

   2           /user/wh/jdk1.6.0_35/bin/java

   3           /user/wh/jdk1.6.0_35/bin/jar

   4           /user/wh/jdk1.6.0_35/bin/javac

 

현재 선택[+]을 유지하시려면 엔터키를 누르십시오. 그렇지 않으면선택 번호를 입력해 주십시오:2


# java -version

java version "1.6.0_35"

Java(TM) SE Runtime Environment (build 1.6.0_35-b10)

Java HotSpot(TM) Server VM (build 20.10-b01, mixed mode)


# 자바목록에서 Java Version 삭제

# alternatives --remove java /user/wh/jdk1.6.0_35/bin/jar



위에 나열한 3가지는 정말 자주 사용하는 alternatives의 옵션들이다. 예전에는 이 명령어를 몰라서 자바를 찾아서 일일이 삭제하고 다시 설치했는데, 이 명령어를 알고는 내 자신이 얼마나 바보같은 짓을 했는지 알수 있었다. 검색엔진에서 한번만 찾아보았어도 이런 삽질은 하지 않았을 것이다. 

저작자 표시 비영리 변경 금지
신고
Posted by 나리 짱!!! naleejang
Java2012.03.06 15:05
Java에서 Rest API로 가장 많이 사용하는 것은 Apache CXF이다. CXF는 Server모듈을 만들수 있고, 쉽게 client 프로그래밍을 할 수 있다. 그런데 Java가 아닌 다른 언어로 제공되는 Rest를 사용할 경우, 다른 서버의 url을 바로 호출할 경우 사용 할수 있는 것이 바로  HttpClient이다.

HttpClient 객체에는 HttpGet, HttpHead, HttpPost, HttpPut, HttpDelete가 있는데, 이 메소드들은 Android에서도 많이 사용되고 있는 통신 방법이다. 어떻게 보면 CXF Restful과도 같아 보인다.

- HttpGet : 데이터를 조회할 때 주로 사용한다.
- HttpHead : 조회하고자 하는 데이터의 메타데이터나 인증정보, 혹은 세션값을 확인 할 때 사용한다.
- HttpPost : 데이터의 메타데이터 등을 수정할 때 사용한다.
- HttpPut : 새로운 데이터를 생성할 때 사용한다.
- HttpDelete : 데이터 삭제시 사용하는 메소드이다.
 
그럼 이제 OpenStack Swift Client Java API 예제와 함께 자주 사용하는 HttpClient 메소드들을 알아보도록 하자.

** 아래 예제 샘플은  http://wiki.openstack.org/SwiftAPI 에 가면 다운로드 받을 수 있다.




HttpGet 

/**
 로그인된 Account의 Container 리스트를 조회하는 메소드로 HttpGet을 사용하였다.
*/

public List<FilesContainer> listContainers(int limit, String marker) throws IOException, HttpException, FilesException

{
        //로그인이 되었는지를 체크한다. 

if (!this.isLoggedin()) {

    throw new FilesAuthorizationException("You must be logged in", null, null);

}

HttpGet method = null;

try {

LinkedList<NameValuePair> parameters = new LinkedList<NameValuePair>();

    if(limit > 0) {
                        //파라메터로 받은 limit를 추가한다. 

parameters.add(new BasicNameValuePair("limit", String.valueOf(limit)));

}

    if(marker != null) {
                        //파라메터로 받은 marker를 추가한다.  

parameters.add(new BasicNameValuePair("marker", marker));

}

    //위에서 생성한 parameters는 URI를 생성할때 사용이 된다.

    String uri = parameters.size() > 0 ? makeURI(storageURL, parameters) : storageURL;
                //위에서 선언한 HttpGet 객체를 생성한다.

method = new HttpGet(uri);

method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);
                //헤더에 인증 Token를 추가한다.  

method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);
                
                //여기서 사용되는 FilesResponse는  HttpClient로 실행한 결과값을 담아놓는 HttpResponse로 보                    면 된다.

FilesResponse response = new FilesResponse(client.execute(method));

    if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {

//상태코드가 401로 인증되지 않았을 경우 

}

if (response.getStatusCode() == HttpStatus.SC_OK)

{

//상태코드가 200으로 성공했을 경우

}

else if (response.getStatusCode() == HttpStatus.SC_NO_CONTENT)

{

//상태코드 204 로 새로운 정보가 없을 경우

}

else if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND)

{

//상태코드가 404 Not Found가 나왔을 경우

}

else {

//응답코드가 없을 경우

}

}

catch (Exception ex) {

ex.printStackTrace();

throw new FilesException("Unexpected error, probably parsing Server XML", ex);

}

finally {

if (method != null) method.abort();

}

} 


HttpHead

 /**
 로그인된 Account의 MetaData 정보를 조회할 때 HttpHead를 사용하였다.
*/ 
public FilesAccountInfo getAccountInfo() throws IOException, HttpException, FilesAuthorizationException, FilesException

{
        //로그인이 되었을 경우에만 아래 프로세스를 수행한다. 

if (this.isLoggedin()) {

HttpHead method = null;


try {

method = new HttpHead(storageURL);

method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);

method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);
                        //해당 storageURL의 MetaData를 조회한다.

FilesResponse response = new FilesResponse(client.execute(method));
 

if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
                                //401 인증이 되지 않았을경우 Header를 삭제하고 다시 로그인을 한다.

method.removeHeaders(FilesConstants.X_AUTH_TOKEN);

if(login()) {

method.abort();

method = new HttpHead(storageURL);

method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);

method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);
                                        //다시 해당 storageURL의 MetaData를 조회한다. 

response = new FilesResponse(client.execute(method));

}

else {
                                        //인증이 되지 않으면 오류처리한다. 

throw new FilesAuthorizationException("Re-login failed", response.getResponseHeaders(), response.getStatusLine());

}

}

                        // 기존 정보와 변동이 없으면 기존 정보를 조회하여 리턴한다. 

if (response.getStatusCode() == HttpStatus.SC_NO_CONTENT)

{

int nContainers = response.getAccountContainerCount();

long totalSize  = response.getAccountBytesUsed();

return new FilesAccountInfo(totalSize,nContainers);

}

else {

throw new FilesException("Unexpected return from server", response.getResponseHeaders(), response.getStatusLine());

}

}

finally {

if (method != null) method.abort();

}

}

else {

    throw new FilesAuthorizationException("You must be logged in", null, null);

}

}


HttpPost

 /**
 Object Metadata 정보를 수정할 때 HttpPost를 사용한다.
*/  
public boolean updateObjectMetadataAndManifest(String container, String object, 

Map<String,String> metadata, String manifest) throws FilesAuthorizationException, 

HttpException, IOException, FilesInvalidNameException {

        FilesResponse response;

        //로그인이 되어 있는지 체크한다.

if (!isLoggedin) {

    throw new FilesAuthorizationException("You must be logged in", 

    null, null);

}
        //수정될 Container가 있는지 체크한다. 

if (!isValidContainerName(container))

throw new FilesInvalidNameException(container);     
 
       //수정될 Object가 있는지 체크한다.

if (!isValidObjectName(object))

           throw new FilesInvalidNameException(object);


//Post 될 Url를 생성한다.

String postUrl = storageURL + "/"+FilesClient.sanitizeForURI(container) +

"/"+FilesClient.sanitizeForURI(object);

HttpPost method = null;

try {

          method = new HttpPost(postUrl);

        if (manifest != null){

        method.setHeader(FilesConstants.MANIFEST_HEADER, manifest);

        }

  method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);

  method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);
                //HttpPost에 파라메터, 헤더, metadata값을 추가한다. 

  if (!(metadata == null || metadata.isEmpty())) {

  for(String key:metadata.keySet())

  method.setHeader(FilesConstants.X_OBJECT_META+key, 

  FilesClient.sanitizeForURI(metadata.get(key)));

  }
                //HttpPost를 HttpClient로 실행한다. 

HttpResponse resp = client.execute(method);

response = new FilesResponse(resp);

if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
                        //인증이 되지 않았으면 처음부터 다시 실행한다. 

method.abort(); 

if(login()) {

method = new HttpPost(postUrl);

  method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);

  method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);

  if (!(metadata == null || metadata.isEmpty())) {

  for(String key:metadata.keySet())

  method.setHeader(FilesConstants.X_OBJECT_META+key, 

  FilesClient.sanitizeForURI(metadata.get(key)));

  }

    client.execute(method);

}

}

return true;

} finally {

if (method != null) 

method.abort();

}

}


HttpPut

 /**
 Container를 생성할 때 HttpPut 메소드를 사용한다.
*/   
public void createContainer(String name) throws IOException, HttpException, FilesAuthorizationException, FilesException

{
        //우선 로그인이 되었는지 먼저 체크한다. 

if (this.isLoggedin())

{
                //생성가능한 container명인지 체크한다. 

if (isValidContainerName(name))

{
                        //해당 storageUrl로 container 생성을 요청할 준비를 한다.

HttpPut method = new HttpPut(storageURL+"/"+sanitizeForURI(name));

method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);

method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);

try {
                                // 준비된 요청을 실행한다.

FilesResponse response = new FilesResponse(client.execute(method));    

              if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {

              // 402 인증이 안되었을 경우

            }


          if (response.getStatusCode() == HttpStatus.SC_CREATED)

         {
                                        //  201 Container 생성 성공

          return;

         }

         else if (response.getStatusCode() == HttpStatus.SC_ACCEPTED)

         {

         // 202 이미 Container가 있을 경우

         }

         else {

        // 기타는 에러로 간주

         }

}

finally {

method.abort();

}

}

else

{

throw new FilesInvalidNameException(name);

}

}

else {

    throw new FilesAuthorizationException("You must be logged in", null, null);

}

}



HttpDelete

  /**
 Container를 삭제할 때 HttpDelete 메소드를 사용한다.
*/  
public boolean deleteContainer(String name) throws IOException, HttpException, FilesAuthorizationException, FilesInvalidNameException, FilesNotFoundException, FilesContainerNotEmptyException

{
        //로그인이 되었는지 체크한다. 

if (this.isLoggedin())

{
                //삭제 가능한 Container명인지 체크한다. 

if (isValidContainerName(name))

{
                        // 해당 storageURL로 container를 삭제할 준비를 한다. 

HttpDelete method = new HttpDelete(storageURL+"/"+sanitizeForURI(name));

try {

method.getParams().setIntParameter("http.socket.timeout", connectionTimeOut);

  method.setHeader(FilesConstants.X_AUTH_TOKEN, authToken);
                                // 준비된 요청을 실행한다.

        FilesResponse response = new FilesResponse(client.execute(method));


          if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {

        // 402 인증이 안되었을 경우 

        }


          if (response.getStatusCode() == HttpStatus.SC_NO_CONTENT)

       {

       // container가 삭제되었다.

         return true;

       }

       else if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND)

       {
                           //삭제 할 container가 없을 경우 

       logger.debug ("Container does not exist !");

       

       }

       else if (response.getStatusCode() == HttpStatus.SC_CONFLICT)

       {
                           //삭제 할 container가 empty가 아닐 경우 에러를 발생한다.

       logger.debug ("Container is not empty, can not delete a none empty container !");

       }

}

finally {

method.abort();

}

}

else

{

        throw new FilesInvalidNameException(name);

}

}

else

{

    throw new FilesAuthorizationException("You must be logged in", null, null);

}

return false;

}


 
저작자 표시 비영리 변경 금지
신고
Posted by 나리 짱!!! naleejang
Java2012.02.08 12:57
요즘은 Restful이 유행이다. 통신을 하기 위해서 가장  부하가 적은 웹서비스이기 때문이다. Java에서 요즘 가장 많이 사용하는 것이 Spring Framework 와 함께 Apache CXF를 가장 많이 사용한다. 그다음에 사용하는 WebService로는 Apache AXIS 이다. 둘다 Apache에서 나온 프로젝트이기 때문에 오픈소스라고 볼 수 있다. 라이센스는 걱정하지 않고 사용하기만 하면 되는 것이다. 

Apache CXF : http://cxf.apache.org

위의 Apache CXF 홈페이지를 방문하면 다운로드 뿐만 아니라 좀 더 자세한 정보를 알아 낼 수 있다. 

Apache AXIS :  http://axis.apache.org/axis2/java/core/ 

AXIS 역시 홈페이지를 방문하면 Install 가이드 및 자세한 정보를 확인 할 수 있다.
 
Apache CXF 설치

Eclipse에서 Maven Project를 생성 후 Pom.xml에 Apache CXF 를 추가한다.



환경설정

Web.xml에 다음과 같이 Servlet을 추가합니다.

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>SimpleJaxs</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/beans.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>

<servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
</web-app> 



web.xml 환경설정이 끝나면 beans.xml를 생성한다.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns:jaxrs="http://cxf.apache.org/jaxrs"

  xmlns:cxf="http://cxf.apache.org/core"

  xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://cxf.apache.org/jaxrs

http://cxf.apache.org/schemas/jaxrs.xsd

http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">


  <import resource="classpath:META-INF/cxf/cxf.xml" />

  <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />

  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />


 <jaxrs:server id="CxfService" address="/Service">

    <jaxrs:serviceBeans>

    <ref bean="DemoBean" />

    </jaxrs:serviceBeans>

  </jaxrs:server>

  

  

  <bean id="DemoBean" class="demo.jaxrs.server. DemoCxf " />


Server 프로그램 샘플
 
그럼 이번에는 Server Program 를 생성해 보도록 하겠다.

package demo.jaxrs.server;
import javax.ws.rs.Consumes;

import javax.ws.rs.DELETE;

import javax.ws.rs.GET;

import javax.ws.rs.POST;

import javax.ws.rs.PUT;

import javax.ws.rs.Path;

import javax.ws.rs.PathParam;

import javax.ws.rs.Produces;

import javax.ws.rs.core.Response;
 

@Path("/DemoCxf/")

public class  DemoCxf {

        @GET

@Path("/getMsg/{gubun}")

public String getMsg(@PathParam("gubun") String _gubun)
        {

return "hi"+ _gubun;

}

        @POST
        @Path("/AddData/{gubun}/{data}")
        public String addData(@PathParam("gubun") String _gubun, @PathParam("data") String _data)

        {
                String data = _data;
                return "true";
        }



Client 프로그램 샘플

Server 프로그램을 생성했으면 Client 프로그램을 생성해야 한다.

import org.apache.cxf.jaxrs.client.WebClient;

 public class DemoCxfClient {
       public String getMsgClient( String serverUrl) 

{

WebClient client = WebClient.create(serverUrl);

                String gubun = "1"; 

String result = client.path("/CxfService/DemoCxf/getMsg").accept("application/xml").get(gubun);

return result;

}

        public String addDataClient( String serverUrl, String data) 

{

WebClient client = WebClient.create(serverUrl);
                String gubun = "1"; 
                String data = "test_data";   

String result = client.path("/CxfService/DemoCxf/addDataClient").accept("application/xml").post(gubun, data);

return result;

}

 
 
샘플 코드에서 나는 Rest의 두가지를  샘플로 코딩하였다. 바로 @GET 과 @POST이다. 이번에는 Rest 방식에 대하여 설명하도록 하겠다.

@GET 
   특정 구분자에 의한 값을 조회할때 
@POST
   새로운 데이터를 저장하거나 생성할 때
@PUT
   저장되어 있는 데이터를 변경할 때
@DELETE
   저장되어 있는 데이터를 삭제할 때
@HEAD
   조회하고자 하는 데이터의 메타데이터를 확인 할 때
@OPTION 
   지원 메소드를 체크할 때 
저작자 표시 비영리 변경 금지
신고
Posted by 나리 짱!!! naleejang