* Annotation
코드에 관한 데이터를 제공하며, 효용성으로는 문서화, 컴파일러 체크, 코드분석에서 사용한다.

annotation은 데코레이션, 클래스, 인터페이스, 필드에 적용되어 툴과 라이브러리를 활용할 수 있게 함으로써, 코드에 명시적 프로그래밍을 줄이고 좀 더 많은 선언문을 제공한다.   annotation은 프로그램의 의미적인 부분에 직접 영향을 주지 않고, 툴이 프로그램을 어떻게 다루어야 하는지에 알려준다. 툴이 실행 중인 프로그램의 의미적인 부분에 영향을 줄 수 있다.
annotation은 런타임에 소스 파일 또는 클래스 파일 등에서 읽을 수 있다. annotation은 javadoc 태그의 기능을 보안하고 있다. 마크업을 문서 생성시 필요한 정보를 제공하기 위해 사용하고자 할 경우, javadoc 태크 또는 annotation을 사용해야 한다. 일반적으로 어플리케이션 프로그래머는 annotation 타입을 정의하는 경우가 거의 없지만, annotation 타입을 정의하는작업은 어렵지 않다.

  1. 컴파일러가 에러를 탐지하거나 경고등을 무시하는 등등의 용도
  2. 컴파일 또는 설치시에 소프트웨어 도구가 코드, XML 파일 등을 처리하기 위한 용도
  3. 실행시 별도의 처리 루틴이 필요한 경우(실행 루틴 점검 등과 같은)


* Annotation의 종류
  Marker Annotation : 이름으로 구분하기 위하여 사용하며 추가적인 데이터를 필요하지 않음
  Single-Value Annotation : 간단한 신텍스를 사용하며 단일 데이터를 필요로 함
  Full Annotation : 복잡한 신텍스이며, 다중 데이터를 사용하며 name=value 형태를 취함
   --> 데이터가 Array 인 경우 "{ }"를 이용


* Annotation Type의 정의

  1. Annotation 타입 선언은 인터페이스를 선언하는 방법과 유사하다.
  2. Annotation 타입 선언 시에는 interface 키워드 앞에 @ 기호를 붙인다.
  3. 메소드는 파라메터를 가질 수 없다.
  4. 메소드는 throws 절을 가질 수 없다.
  5. 메소드의 리턴 타입 : 프리미티브(Primitive), String, Class, 열거형(Enum), annotation, 앞에서 열거한 타입들의 배열
  6. 메소드는 기본값(Default Value)를 가질 수 있다.


* 기본 Annotation
  @Deprecated : 더 이상 사용하지 말아야할 메소드를 알림 (비추천 메소드)
  @Documented
  @Retention(RetentionPolicy.RUNTIME)
  public @interface Deprecated {

   }

  @Override : 상위 요소를 오버라이드 할 것임을 알림
  @Target(ElementType.METHOD)
  @Retention(RetentionPolicy.SOURCE)
   public @interface Override {

   }


  @SuppressWarnings : 경고를 하지 않도록 억제 시킴
     - unchecked : 비확인
     - deprecate : 비사용


   @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
   @Retention(RetentionPolicy.SOURCE)
   public @interface SuppressWarnings {
       String[] value();
   }



* Built-in Annotation
  Target : Annotation의 대상을 무엇으로 할 것인지를 기록 (CONSTRUCTOR, FIELD, METHOD, PACKAGE, ...)
   - ANNOTATION_TYPE : annotation 타입(Annotation Type)선언
    - CONSTRUCTOR : 생성자 함수 선언
    - FIELD : 필드 선언(enum 상수 포함)
   - LOCAL_VARIABLE : 로컬 변수 선언
    - METHOD : 메소드 선언
    - PACKAGE : package 선언
    - PARAMETER : parameter 선언
    - TYPE : 클래스, 인터페이스 (annotation타입(AnnotationType)포함), enum선언


   @Documented
   @Retention(RetentionPolicy.RUNTIME)
   @Target(ElementType.ANNOTATION_TYPE)
   public @interface Target {
       ElementType[] value();
   }


  Retention : 어느 과정에서 Annotation을 사용할 것인지를 기록 (여러개의 값 중 선택 가능) (SOURCE, CLASS, RUNTIME)
   - SOURCE : 소스파일에서만 사용하며 컴파일 이후는 사용하지 않음
    - CLASS : 컴파일 과정까지 사용하며 Runtime에서는 사용하지 않음
    - RUNTIME : Runtime에서까지 사용함


   @Documented
   @Retention(RetentionPolicy.RUNTIME)
   @Target(ElementType.ANNOTATION_TYPE)
   public @interface Retention {
      RetentionPolicy value();
   }

  Documented : Javadoc에 포함(문서화)되어야 함을 알리는 Marker Annotation

   @Documented
   @Retention(RetentionPolicy.RUNTIME)
   @Target(ElementType.ANNOTATION_TYPE)
   public @interface Documented {
   }


  Inherited : 하위 클래스에 상속되어야 함을 알리는 Marker Annotation

   @Documented
   @Retention(RetentionPolicy.RUNTIME)
   @Target(ElementType.ANNOTATION_TYPE)
   public @interface Inherited {

   }



* Custom Annotation
  개발자가 정의하는 어노테이션으로 class 형태로 만들어진다. 어노테이션의 선언은 @interface 로 한다.
  이름 앞에 '@'문자가 오는 것 외에는 기본적으로 인터페이스를 선언하는 것과 동일(메소드들의 내용은 없고 형태만 선언)하다.
  default 가 찍히지 않은 메소드는 필수로 입력해야 한다

   @Retention(RetentionPolicy.RUNTIME)
   public @interface Maker {
       int num();
       String id();
       String name();
       String date() default "unsigned";
   }



   @Maker(num=1, id="dryang", name="junsun.yang")
   public class UseMaker {
        ...
   }

'Program > Java' 카테고리의 다른 글

About JAXB  (0) 2009.12.27
StringUtils  (0) 2009.12.22
XML 파싱  (0) 2009.12.15
아파치 미나  (0) 2009.12.15
Triple DES Java  (0) 2009.12.02
dom4j를 이용하여 쉽게 XML을 파싱 할 수 있습니다.
[ 예제 코드 ]
import java.net.URL;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
public class Foo {
    public Document parse(URL url) throws DocumentException {
        SAXReader reader = new SAXReader();
        Document document = reader.read(url);
        return document;
    }
}

Iterator 사용하기
"document"(SAXReader나 DocumentHelper를 통해 만들어진 XML객체)는 자바의 표준 Iterator를 이용하여 다양한 방법으로 네비게이션 할 수 있다.
[ 예제 코드 ]
public void bar(Document document) throws DocumentException {

        Element root = document.getRootElement();

        // 루트 엘리먼트의 자식노드 반복
        for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
            Element element = (Element) i.next();
            // do something
        }

        // 루트의 엘리먼트 중 "foo"라는 이름을 갖는엘리먼트의 자식노드 반복
        for ( Iterator i = root.elementIterator( "foo" ); i.hasNext(); ) {
            Element foo = (Element) i.next();
            // do something
        }

        // 루트의 어트리뷰트 반복
        for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
            Attribute attribute = (Attribute) i.next();
            // do something
        }
     }

XPath를 이용한 강력한 네비게이션
dom4j의 XPath 표현들로 document 트리 내 어떤 노드들도 접근할 수 있다.(Attribute, Element or ProcessingInstruction).
복잡한 네비게이션을 한줄로 할 수 있다.

[ 예제 코드 ]
public void bar(Document document) {
    List list = document.selectNodes( "//foo/bar" );
    Node node = document.selectSingleNode( "//foo/bar/author" );
    String name = node.valueOf( "@name" );
}

XHTML 문서의 링크 네이게이션 예

[ 예제 코드 ]
public void findLinks(Document document) throws DocumentException {
    List list = document.selectNodes( "//a/@href" );
    for (Iterator iter = list.iterator(); iter.hasNext(); ) {
        Attribute attribute = (Attribute) iter.next();
        String url = attribute.getValue();
    }
}

XPath를 배우려면 Zvon tutorial 튜토리얼 참조하세요.  


빠른 반복

커다란 XML tree 전체 iterator를 만들어 가면서 네비게이션 하려면 성능이 떨어지기 때문에 빠른 반복을 할 수 있는 메소드를 사용한다. (treeWalk를 주목)
[ 예제 코드 ]
public void bar(Document document) {
    List list = document.selectNodes( "//foo/bar" );
    Node node = document.selectSingleNode( "//foo/bar/author" );
    String name = node.valueOf( "@name" );
}
public void treeWalk(Document document) {
    treeWalk( document.getRootElement() );
}
public void treeWalk(Element element) {
    for ( int i = 0, size = element.nodeCount(); i < size; i++ ) {
        Node node = element.node(i);
        if ( node instanceof Element ) {
            treeWalk( (Element) node );
        }
        else {
            // do something....
        }
    }
}

새 XML문서 생성
[ 예제 코드 ]
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
public class Foo {
    public Document createDocument() {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement( "root" );
        Element author1 = root.addElement( "author" )
            .addAttribute( "name", "James" )
            .addAttribute( "location", "UK" )
            .addText( "James Strachan" );
        
        Element author2 = root.addElement( "author" )
            .addAttribute( "name", "Bob" )
            .addAttribute( "location", "US" )
            .addText( "Bob McWhirter" );
        return document;
    }
}


문서를 파일로 쓰기
Document나 어떤 노드에서도 write()메소드를 이용하여 FileWriter로 쓸수 있다.
FileWriter out = new FileWriter( "foo.xml" );
document.write( out );
XMLWriter를 이용하여 출력 포맷을 변경할 수 있다.


[ 예제 코드 ]
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
public class Foo {
    public void write(Document document) throws IOException {
        // lets write to a file
        XMLWriter writer = new XMLWriter(
            new FileWriter( "output.xml" )
        );
        writer.write( document );
        writer.close();

        // Pretty print the document to System.out
        OutputFormat format = OutputFormat.createPrettyPrint();
        writer = new XMLWriter( System.out, format );
        writer.write( document );
        // Compact format to System.out
        format = OutputFormat.createCompactFormat();
        writer = new XMLWriter( System.out, format );
        writer.write( document );
    }
}

Document를 문자열로 문자열을 Document로
Document나 어떤 노드에서나 asXML()메소드를 호출하여 쉽게 xml문자열을 추출할 수 있다.
Document document = ...;
String text = document.asXML();    

또한 valid한 xml문자열을 DocumentHelper를 이용하여 Document 객체로 만들수 있다.

String text = "<person> <name>James</name> </person>";
Document document = DocumentHelper.parseText(text);
XSLT를 이용한 문서 스타일 적용
Sun의 JAXP API를 사용하여 쉽게 XSLT를 적용할 수 있다.
Xalan, SAXON과 같은 어떠한 XSLT을 가지고도 작업 할수 있다.


[ 예제 코드 ]
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import org.dom4j.Document;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
public class Foo {
    public Document styleDocument(
        Document document,
        String stylesheet
    ) throws Exception {
        // load the transformer using JAXP
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(
            new StreamSource( stylesheet )
        );
        // now lets style the given document
        DocumentSource source = new DocumentSource( document );
        DocumentResult result = new DocumentResult();
        transformer.transform( source, result );
        // return the transformed document
        Document transformedDoc = result.getDocument();
        return transformedDoc;
    }
}

'Program > Java' 카테고리의 다른 글

StringUtils  (0) 2009.12.22
Annotation (since tiger / 1.5)  (0) 2009.12.15
아파치 미나  (0) 2009.12.15
Triple DES Java  (0) 2009.12.02
알아야 할 용어 정리  (0) 2009.11.30
아파치에서 제공하는 lib 일종으로 한국 사람이 개발한 미나

관련 샘플 소스와 문서

'Program > Java' 카테고리의 다른 글

Annotation (since tiger / 1.5)  (0) 2009.12.15
XML 파싱  (0) 2009.12.15
Triple DES Java  (0) 2009.12.02
알아야 할 용어 정리  (0) 2009.11.30
Stuts2 설정 - struts.properties  (0) 2009.10.09
Triple DES Security Java 소스이다.
다른 소스와 다른 점은 NoSuchAlgorithm이 날 경우에 SunJCE를 설치하여 Exception을 없앤 소스라는 것...


/*

 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.com/javaexamples2.
 */

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

/**
 * This class defines methods for encrypting and decrypting using the Triple DES
 * algorithm and for generating, reading and writing Triple DES keys. It also
 * defines a main() method that allows these methods to be used from the command
 * line.
 */
public class TripleDES {
  /**
   * The program. The first argument must be -e, -d, or -g to encrypt,
   * decrypt, or generate a key. The second argument is the name of a file
   * from which the key is read or to which it is written for -g. The -e and
   * -d arguments cause the program to read from standard input and encrypt or
   * decrypt to standard output.
   */
  public static void main(String[] args) {
    try {
      // Check to see whether there is a provider that can do TripleDES
      // encryption. If not, explicitly install the SunJCE provider.
      try {
        Cipher c = Cipher.getInstance("DESede");
      } catch (Exception e) {
        // An exception here probably means the JCE provider hasn't
        // been permanently installed on this system by listing it
        // in the $JAVA_HOME/jre/lib/security/java.security file.
        // Therefore, we have to install the JCE provider explicitly.
        System.err.println("Installing SunJCE provider.");
        Provider sunjce = new com.sun.crypto.provider.SunJCE();
        Security.addProvider(sunjce);
      }

      // This is where we'll read the key from or write it to
      File keyfile = new File(args[1]);

      // Now check the first arg to see what we're going to do
      if (args[0].equals("-g")) { // Generate a key
        System.out.print("Generating key. This may take some time...");
        System.out.flush();
        SecretKey key = generateKey();
        writeKey(key, keyfile);
        System.out.println("done.");
        System.out.println("Secret key written to " + args[1]
            + ". Protect that file carefully!");
      } else if (args[0].equals("-e")) { // Encrypt stdin to stdout
        SecretKey key = readKey(keyfile);
        encrypt(key, System.in, System.out);
      } else if (args[0].equals("-d")) { // Decrypt stdin to stdout
        SecretKey key = readKey(keyfile);
        decrypt(key, System.in, System.out);
      }
    } catch (Exception e) {
      System.err.println(e);
      System.err.println("Usage: java " + TripleDES.class.getName()
          + " -d|-e|-g <keyfile>");
    }
  }

  /** Generate a secret TripleDES encryption/decryption key */
  public static SecretKey generateKey() throws NoSuchAlgorithmException {
    // Get a key generator for Triple DES (a.k.a DESede)
    KeyGenerator keygen = KeyGenerator.getInstance("DESede");
    // Use it to generate a key
    return keygen.generateKey();
  }

  /** Save the specified TripleDES SecretKey to the specified file */
  public static void writeKey(SecretKey key, File f) throws IOException,
      NoSuchAlgorithmException, InvalidKeySpecException {
    // Convert the secret key to an array of bytes like this
    SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
    DESedeKeySpec keyspec = (DESedeKeySpec) keyfactory.getKeySpec(key,
        DESedeKeySpec.class);
    byte[] rawkey = keyspec.getKey();

    // Write the raw key to the file
    FileOutputStream out = new FileOutputStream(f);
    out.write(rawkey);
    out.close();
  }

  /** Read a TripleDES secret key from the specified file */
  public static SecretKey readKey(File f) throws IOException,
      NoSuchAlgorithmException, InvalidKeyException,
      InvalidKeySpecException {
    // Read the raw bytes from the keyfile
    DataInputStream in = new DataInputStream(new FileInputStream(f));
    byte[] rawkey = new byte[(int) f.length()];
    in.readFully(rawkey);
    in.close();

    // Convert the raw bytes to a secret key like this
    DESedeKeySpec keyspec = new DESedeKeySpec(rawkey);
    SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
    SecretKey key = keyfactory.generateSecret(keyspec);
    return key;
  }

  /**
   * Use the specified TripleDES key to encrypt bytes from the input stream
   * and write them to the output stream. This method uses CipherOutputStream
   * to perform the encryption and write bytes at the same time.
   */
  public static void encrypt(SecretKey key, InputStream in, OutputStream out)
      throws NoSuchAlgorithmException, InvalidKeyException,
      NoSuchPaddingException, IOException {
    // Create and initialize the encryption engine
    Cipher cipher = Cipher.getInstance("DESede");
    cipher.init(Cipher.ENCRYPT_MODE, key);

    // Create a special output stream to do the work for us
    CipherOutputStream cos = new CipherOutputStream(out, cipher);

    // Read from the input and write to the encrypting output stream
    byte[] buffer = new byte[2048];
    int bytesRead;
    while ((bytesRead = in.read(buffer)) != -1) {
      cos.write(buffer, 0, bytesRead);
    }
    cos.close();

    // For extra security, don't leave any plaintext hanging around memory.
    java.util.Arrays.fill(buffer, (byte) 0);
  }

  /**
   * Use the specified TripleDES key to decrypt bytes ready from the input
   * stream and write them to the output stream. This method uses uses Cipher
   * directly to show how it can be done without CipherInputStream and
   * CipherOutputStream.
   */
  public static void decrypt(SecretKey key, InputStream in, OutputStream out)
      throws NoSuchAlgorithmException, InvalidKeyException, IOException,
      IllegalBlockSizeException, NoSuchPaddingException,
      BadPaddingException {
    // Create and initialize the decryption engine
    Cipher cipher = Cipher.getInstance("DESede");
    cipher.init(Cipher.DECRYPT_MODE, key);

    // Read bytes, decrypt, and write them out.
    byte[] buffer = new byte[2048];
    int bytesRead;
    while ((bytesRead = in.read(buffer)) != -1) {
      out.write(cipher.update(buffer, 0, bytesRead));
    }

    // Write out the final bunch of decrypted bytes
    out.write(cipher.doFinal());
    out.flush();
  }
}

'Program > Java' 카테고리의 다른 글

Annotation (since tiger / 1.5)  (0) 2009.12.15
XML 파싱  (0) 2009.12.15
아파치 미나  (0) 2009.12.15
알아야 할 용어 정리  (0) 2009.11.30
Stuts2 설정 - struts.properties  (0) 2009.10.09

+ Recent posts