Executable jar 를 메이븐 exec:exec 로 실행 하기

Executable JAR 빌드 후 메이븐 exec:exec 로 실행하고 싶다면 exec-maven-plugin 을 사용할 수 있다.
<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>exec-maven-plugin</artifactId>
   <version>1.4.0</version>
   <executions>
     <execution>
       <id>default-cli</id>
       <goals>
           <goal>exec</goal>
       </goals>
       <configuration>
         <executable>java</executable>
         <!-- optional -->
         <workingDirectory>/tmp</workingDirectory>
         <arguments>
           <argument>-jar</argument>
           <argument>${basedir}/target/${project.artifactId}-${project.version}.jar</argument>
         </arguments>
       </configuration>                        
     </execution>
   </executions>
 </plugin>


mvn exec:exec 가 아닌 mvn exec:java 로 컴파일 output 디렉토리에서 main class를 바로 실행하고 싶다면 다음과 같이 설정한다.
<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>exec-maven-plugin</artifactId>
   <version>1.4.0</version>
   <executions>
     <executions>
       <execution>
         <goals>
             <goal>java</goal>
         </goals>
       </execution>
       <configuration>
         <mainClass>com.app.MainClass</mainClass>
         <arguments></arguments>
       </configuration>
     </executions>
   </executions>
 </plugin> 
2016/02/18 14:35 2016/02/18 14:35
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

메이븐 레파지토리에 없는 jar 추가하고 manifest 에 기술하기

IBM DB2를 가지고 개발할 일이 생겼다.
늘 하던대로 executeable-jar 형식으로 빌딩을 수행하는 메이븐 프로젝트를 구성하는데.. 으잉? DB2의 jdbc 드라이버 db2jcc4.jar가 메이븐센트럴에 등록되어있지 않는것이다. 뭐지.. 이건?
회사 넥서스에 등록하고 땡겨쓰면 되긴 하지만 넥서스같은 로컬 메이븐 레파지토리가 없는 환경에서 이런경우는 어떻게 해야하는지 궁금했다.
귀찮겠지만 빌드하고 라이브러리 폴더에 jar를 복사해도 되긴하지만 문제는 POM파일에 기술되지 않으면 dependancy 관리가 안된다는것. 곧 IDE에서 클래스를 참조할 수 없다는 치명적인 문제가 발생한다.

이럴때를 대비해 메이븐은 dependencies.dependency.scope 속성 값으로 system을 제공하고 있고 <scope>system</scope> 를 사용한 경우 추가로 systemPath 속성을 정의할 수 있다.

이렇게 말이지..
     <dependencies>
         <dependency>
             <groupId>ibm.db2</groupId>
             <artifactId>db2jcc4</artifactId>
             <version>10.5</version>
             <scope>system</scope>
             <systemPath>${basedir}/lib/db2jcc4.jar</systemPath>
         </dependency>
     </dependencies>
 

이제, 코드를 짤 수 있고 라이브러리 참조도 된다. 그런데.. 문제가 하나 있는데 <scope>system</scope> 속성은 메이븐 빌드 시 <scope>provided</scope> 와 마찬가지로 라이브러리를 빌드 결과물에 포함시키기 않는다.
이 현상은 maven-dependency-plugin의 configuration 조정을 통해 우회할 수 있다.
plugins.plugin.executions.execution.configuration.includeScope 속성을 추가하고 그 값으로 system 을 설정한다.
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-dependency-plugin</artifactId>
                 <version>2.10</version>
                 <executions>
                     <execution>
                         <id>copy-dependencies</id>
                         <phase>package</phase>
                         <goals>
                             <goal>copy-dependencies</goal>
                         </goals>
                         <configuration>
                             <outputDirectory>${project.build.directory}/lib</outputDirectory>
                             <overWriteReleases>false</overWriteReleases>
                             <overWriteSnapshots>false</overWriteSnapshots>
                             <overWriteIfNewer>true</overWriteIfNewer>
                             <includeScope>system</includeScope>
                         </configuration>
                     </execution>
                 </executions>
             </plugin>

이제 빌드를 수행하면 system 스코프로 설정된 db2jcc4.jar 가 /lib/db2jcc4-10.5.jar 란 이름으로 이쁘게 들어와 있는걸 확인할 수 있다.

나는 이 프로그램을 executeable-jar 로 뽑을거라서 maven-jar-plugin 을 사용한다. 그런데 빌드 후 jar 내부의 MENIFEST 파일을 까 보니 Class-Path 정의에 db2jcc4-10.5.jar 가 기술되어 있지 않다... maven-dependency-plugin을 통해 복사까진 어떻게 처리했는데 메니페스트를 만드는건 maven-jar-plugin 역할이니 당연한건지도 모르겠다.
이제 마지막으로 /lib/db2jcc4-10.5.jar 에 들어온 jar를 메니페스트의 class path에 꾸겨넣어보자.
 plugin.configuration.archive.manifestEntries.Class-Path 속성을 사용했다.

    <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <version>2.6</version>
         <configuration>
             <archive>
                 <manifest>
                     <addClasspath>true</addClasspath>
                     <addExtensions>true</addExtensions> 
                     <mainClass>com.usbcopy.repository.DBProcess</mainClass>
                     <classpathPrefix>lib/</classpathPrefix>                            
                 </manifest>
                 <!--MANIFEST  with systemPath-->
                 <manifestEntries>
                     <Class-Path>lib/db2jcc4-10.5.jar</Class-Path>
                 </manifestEntries>
             </archive>
         </configuration>
     </plugin>

이제 빌드하고 java -jar app.jar 로 실행도 잘 된다.
2015/10/22 19:19 2015/10/22 19:19
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

ZIP/JAR 엔트리의 생성 제어하기

2007/06/28 15:36

서비 JAVA , ,

JAR 관련 클래스는 ZIP 관련 클래스의 하위 클래스이므로 이 팁에서는 ZipOutputStreamjava.util.zip 패키지에 대해 구체적으로 다룬다.

ZIP 또는 JAR 파일의 생성을 살펴보기 전에 그 목적을 언급하는 것이 중요하다. ZIP 파일은 패키징 메커니즘을 제공하여 여러 파일을 하나의 파일로 묶을 수 있게 한다. 따라서 파일 그룹을 웹에서 다운로드해야 할 경우 이 파일들을 하나의 ZIP 파일로 패키지하여 단일 파일로 쉽게 전송할 수 있다. 이 패키지 파일은 디렉토리 계층구조 같은 추가 정보를 포함할 수 있으므로 압축을 풀 때 애플리케이션 또는 시리즈의 자원에 필요한 경로를 유지할 수 있다.

이 팁에서는 ZIP 파일 사용의 세 가지 측면을 다룬다. 즉, ZIP 파일 생성, ZIP 파일에 파일 추가 및 해당 추가 파일 압축에 대해 다룬다.

우선 ZIP 파일을 생성할 때는 ZIP 스트림이 생성된다. ZipOutputStream은 송신 바이트 압축을 위한 스트림을 제공한다. 다른 OutputStream을 받는 ZipOutputStream의 단일 구성자가 있다.

public ZipOutputStream(OutputStream out)

구성자 인수가 FileOutputStream 유형이면 ZipOutputStream이 작성한 압축 바이트는 파일에 저장된다. 하지만 ZipOutputStream을 파일과 관련해서만 사용할 수 있는 것은 아니다. 소켓 연결 또는 기타 일부 비파일 중심 스트림으로부터 나오는 OutputStream을 사용할 수도 있다. 따라서 파일 중심 ZipOutputStream의 경우 일반적인 사용법은 다음과 같다.

String path = "afile.zip";
FileOutputStream fos = new FileOutputStream(path);
ZipOutputStream zos = new ZipOutputStream(fos);

생성된 후에는 ZipOutputStream에 바이트를 작성하는 것으로 충분하지 않다. 대신 출력 스트림을 구성요소의 컬렉션으로 다루어야 한다. ZipOutputStream의 각 구성요소는 ZipEntry와 쌍을 이룬다. 이 ZipEntry를 생성하고 ZipOutputStream에 추가한 후에 해당 컨텐츠를 스트림에 실제로 작성해야 한다.

String name = ...;
ZipEntry entry = new ZipEntry(name);
zos.putNextEntry(entry);
zos.write(<< all the bytes for entry >>);

각 엔트리는 전체 스트림에서 마커 역할을 하며 라이브러리 파일에서 엔트리와 관련된 바이트를 찾을 수 있다. ZIP 파일이 생성된 후 엔트리 컨텐츠를 도로 가져와야 할 경우 관련 입력 스트림을 요청하기만 하면 된다.

ZipFile zip = "afile.zip";
ZipEntry entry = zip.getEntry("anEntry.name");
InputStream is = zip.getInputStream(entry);

ZIP 파일을 생성하고 해당 파일에 엔트리를 추가하는 방법을 살펴본 이 시점에서 java.util.zip 라이브러리가 ZipOutputStream의 추가 엔트리에 대해 일정 수준의 제어를 제공한다는 것을 지적할 필요가 있다. 먼저, 엔트리를 ZipOutputStream에 추가하는 순서는 엔트리가 .zip 파일에 실제로 위치하는 순서이다. ZipFileentries() 메소드에 의해 반환된 엔트리의 열거를 조작하여 영문자 또는 크기 순서대로 목록을 생성할 수도 있지만 엔트리는 출력 스트림에 작성된 순서대로 저장되어 있다.

ZIP/JAR 파일에 추가된 파일은 개별적으로 압축된다. 라이브러리 패키지를 전체적으로 압축하는 Microsoft CAB 파일과 달리, ZIP/JAR 파일 내의 파일들은 각각 별도로 압축되거나 압축되지 않는다. ZipOutputStreamZipEntry를 추가하기 전에 해당 연관 바이트의 압축 여부를 결정해야 한다. ZipEntrysetMethod 메소드를 사용하면 두 가지 사용 가능 압축 형식 중에서 어떤 형식을 사용할지 지정할 수 있다. 압축되지 않은 파일을 원하면 ZipEntry의 STORED 상수를 사용하고, 압축된 버전을 원하면 DEFLATED 설정을 사용한다. 압축 효율성은 제어할 수 없다. 이는 연관 엔트리의 데이터 유형에 좌우된다. 일반 텍스트는 원래 크기의 80% 정도까지 쉽게 압축할 수 있지만 MP3 또는 JPEG 데이터의 압축률은 이보다 현저히 떨어진다.

모든 파일을 압축하는 게 당연하다고 생각할 수도 있지만 파일을 압축하고 푸는 데에는 시간이 소요된다. 생성 시점에서 압축 작업에 너무 많은 시간과 자원이 소요될 경우 전체 파일 데이터를 STORED 형식으로 저장하여 원시 바이트를 저장하는 것이 나은 경우가 있다. 압축 해제의 경우에도 마찬가지이다. 물론, 압축되지 않은 파일은 용량이 더 크므로 파일 전송 시 더 많은 대역폭을 사용하고 더 많은 디스크 공간을 차지하므로 이에 따른 비용을 지불해야 한다. ZipFile 전체가 아니라 각 엔트리에 대한 설정을 변경해야 한다는 것을 유념한다. 하지만 각 엔트리에 대해 각기 다른 설정을 사용하는 것보다 전체 ZipFile을 압축 또는 비압축하는 것이 보다 일반적이다.

압축 방법으로 STORED 상수를 사용할 경우 알아 두어야 할 한 가지 사항이 있다. 엔트리가 압축될 때 자동으로 설정되는 ZipEntry의 특정 속성을 명시적으로 설정해야 한다. 해당 속성은 엔트리의 입력 스트림에 대한 체크섬, 압축 크기 및 크기이다. 입력 파일인 경우 크기 및 압축 크기는 바로 파일 크기가 될 수 있다. 체크섬을 계산하려면 ava.util.zip 패키지의 CRC32 클래스를 사용한다. checksum 값을 무시하기 위해 단순히 0 또는 -1을 전달할 수는 없다. ZIP 파일을 작성하고 나중에 해당 파일을 읽을 때 입력사항을 검증하기 위해 CRC 값이 사용된다.

ZipEntry entry = new ZipEntry(name);
entry.setMethod(ZipEntry.STORED);
entry.setCompressedSize(file.length());
entry.setSize(file.length());
CRC32 crc = new CRC32();
crc.update(<< all the bytes for entry >>);
entry.setCrc(crc.getValue());
zos.putNextEntry(entry);

예 를 들어, 다음 프로그램은 STORED 압축 메소드를 사용하여 일련의 파일을 결합한다. 프로그램의 첫 번째 인수는 생성할 ZIP 파일이 된다. 나머지 인수는 추가할 파일을 나타낸다. 생성할 ZIP 파일이 이미 존재하면 프로그램은 파일을 수정하지 않고 종료된다. 존재하지 않는 파일을 ZIP 파일에 추가하는 경우 프로그램은 존재하지 않는 파일을 건너뛰고 나머지 명령줄 인수를 생성된 ZIP에 추가한다.

  1. import java.util.zip.*;
  2. import java.io.*;
  3. public class ZipIt {
  4.     public static void main(String args[]) throws IOException {
  5.         if (args.length < 2) {
  6.             System.err.println("usage: java ZipIt Zip.zip file1 file2 file3");
  7.             System.exit(-1);
  8.         }
  9.         File zipFile = new File(args[0]);
  10.         if (zipFile.exists()) {
  11.             System.err.println("Zip file already exists, please try another");
  12.             System.exit(-2);
  13.         }
  14.         FileOutputStream fos = new FileOutputStream(zipFile);
  15.         ZipOutputStream zos = new ZipOutputStream(fos);
  16.         int bytesRead;
  17.         byte[] buffer = new byte[1024];
  18.         CRC32 crc = new CRC32();
  19.         for (int i=1, n=args.length; i < n; i++) {
  20.             String name = args[i];
  21.             File file = new File(name);
  22.             if (!file.exists()) {
  23.                 System.err.println("Skipping: " + name);
  24.                 continue;
  25.             }
  26.             BufferedInputStream bis = new BufferedInputStream(
  27.                 new FileInputStream(file));
  28.             crc.reset();
  29.             while ((bytesRead = bis.read(buffer)) != -1) {
  30.                 crc.update(buffer, 0, bytesRead);
  31.             }
  32.             bis.close();
  33.             // Reset to beginning of input stream
  34.             bis = new BufferedInputStream(
  35.                 new FileInputStream(file));
  36.             ZipEntry entry = new ZipEntry(name);
  37.             entry.setMethod(ZipEntry.STORED);
  38.             entry.setCompressedSize(file.length());
  39.             entry.setSize(file.length());
  40.             entry.setCrc(crc.getValue());
  41.             zos.putNextEntry(entry);
  42.             while ((bytesRead = bis.read(buffer)) != -1) {
  43.                 zos.write(buffer, 0, bytesRead);
  44.             }
  45.             bis.close();
  46.         }
  47.         zos.close();
  48.     }
  49. }


JAR 파일의 봉합 및 버전 지정을 비롯한 자세한 내용을 보려면 The Java Tutorial(새 창으로 열기)의 JAR Files 단원에서 Packing Programs를 참조한다.

원문 출처 : http://www.sdnkorea.com/blog/398(새 창으로 열기)

2007/06/28 15:36 2007/06/28 15:36
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

jar 파일 포맷의 힘

2007/05/14 18:48

서비 JAVA ,

원문 출처 : http://www-128.ibm.com/developerworks/kr/library/j-jar/
* 본 글은 저의 저작물이 아니며 그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않습니다. *

대부분의 자바 프로그래머들은 JAR 파일의 기본 작동에 익숙하다. 하지만 JAR 파일 포맷의 막강한 힘을 아는 개발자는 드물다.

JAR 파일

JAR 파일 포맷은 대중적인 ZIP 파일 포맷을 근간으로 하여 많은 파일들을 하나로 모으는데 사용된다. ZIP 파일과는 달리 JAR 파일은 압축과 디스트리뷰션 뿐만 아니라 라이브러리, 컴포넌트, 플러그인 등의 전개와 캡슐화에도 사용되며 컴파일러나 JVM 같은 툴이 직접 사용하기도 한다. 전개 디스크립터 같이 JAR에 포함된 특별한 파일은 특정 JAR가 취급되는 방법을 툴에 지시한다.

JAR 파일은 다음과 같은 데에 사용된다:

JAR 파일 포맷은 많은 혜택과 기능을 제공하며 ZIP 또는 TAR 같은 전통적인 아카이브 포맷이 줄 수 없는 많은 것들을 제공한다. 이를 테면:

JAR의 압축과 압축풀기

jar 툴( jar 참조)은 파일을 기본적으로 압축한다. 압축이 풀린 JAR 파일은 압축된 JAR 파일 보다 더 빠르게 로딩될 수 있다. 로딩 시간 동안 파일의 압축 풀기 시간이 줄어들기 때문이다. 하지만 네트워크를 통한 다운로드 시간은 압축이 풀린 파일이 더 길다.

META-INF 디렉토리

대부분의 JAR 파일에는 META-INF 디렉토리가 포함되어 있는데 이는 패키지의 저장과 보안 및 버저닝 정보 같은 확장 설정 데이터를 저장하는데 사용된다. META-INF 디렉토리의 파일과 디렉토리는 Java2platform에서 인식 및 인터프리팅되어 애플리케이션, 확장, 클래스 로더를 설정한다:

jar 툴

JAR 파일로 기본적인 태스크를 수행하려면 자바 개발 킷의 일부로 제공되는 Java Archive Tool (jar 툴)을 사용한다. jar 툴을 jar 명령어로 호출한다. 표 1은 일반 애플리케이션이다:

표 1. jar 툴의 일반적인 사용

기능 명령어
개별 파일에서 JAR 파일 만들기 jar cf jar-file input-file...
디렉토리에서 JAR 파일 만들기 jar cf jar-file dir-name
압축 풀린 JAR 파일 만들기 jar cf0 jar-file dir-name
JAR 파일 업데이트 jar uf jar-file input-file...
JAR 파일 내용보기 jar tf jar-file
JAR 파일 내용 추출하기 jar xf jar-file
JAR 파일에서 특정 파일 추출하기 jar xf jar-file archived-file...
실행 JAR 파일로 패키지된 애플리케이션 실행하기 java -jar app.jar



위로


실행 JAR 파일

실행 JAR 파일은 특별히 설정된 JAR 파일에 저장된 독립적인 자바 애플리케이션이다. 파일을 추출하거나 클래스 경로를 설정하지 않고 JVM에 의해 직접 실행될 수 있다. 비 실행 JAR에 저장된 애플리케이션을 구동하려면 이를 클래스 경로에 추가하고 애플리케이션의 메인 클래스를 이름별로 호출해야한다. 하지만 실행 JAR 파일을 사용하면 이를 추출하거나 메인 엔트리 포인트를 알 필요 없이 애플리케이션을 실행할 수 있다.

실행 JAR 파일 만들기

실행 JAR 파일을 만들기는 쉽다. 모든 애플리케이션 코드를 하나의 디렉토리에 놓는 것으로 시작한다. 애플리케이션의 메인 클래스가 com.mycompany.myapp.Sample이라고 가정해보자. 애플리케이션 코드를 포함하고 메인 클래스를 구분하는 JAR 파일 생성이 필요하다. 이를 위해 라는 manifest 파일을 어딘가에(애플리케이션 디렉토리는 아니다) 만들고 여기에 다음 행을 추가한다:


Main-Class: com.mycompany.myapp.Sample

그런 다음 JAR 파일을 다음과 같이 만든다:


jar cmf manifest ExecutableJar.jar application-dir

실행 JAR 파일 시작하기

애플리케이션을 ExecutableJar.jar라는 실행 JAR 파일로 묶었으므로 다음 명령어를 사용하여 파일에서 직접 애플리케이션을 시작할 수 있다:


java -jar ExecutableJar.jar




위로


패키지 실링(sealing)

JAR 파일안에 패키지를 봉합(sealing)한다는 것은 이 패키지에 정의된 모든 클래스가 같은 JAR 파일에서 찾아져야 한다는 것을 의미한다. 이로서 패키지 작성자는 패키지된 클래스들의 버전 영속성을 강화할 수 있다. 봉합은 보안 조치도 제공하여 코드 탬퍼링을 탐지한다.

패키지를 봉합하려면 패키지용 Name 헤더를 추가한다. 그 뒤에 Sealed 헤더 값을 JAR manifest 파일에 대해 "true"로 한다. 실행 JAR 파일과 마찬가지로 manifest 파일을 적절한 헤더 엘리먼트로 지정하여 JAR를 봉합할 수 있다:


Name: com/samplePackage/
Sealed: true

Name 헤더는 패키지의 관련 경로명을 정한다. 파일이름과 구별되도록 "/"로 끝난다. Name 헤더에 뒤따르는 모든 헤더는 공백 라인 없이 Name 헤더에 지정된 파일이나 패키지에 붙는다. 위 예제에서 Sealed 헤더가 공백 라인 없이 Name 헤더 다음에 발생했기 때문에 Sealed 헤더는 com/samplePackage 패키지에만 붙는것으로 인터프리팅된다.

확장 패키징

확장은 자바 플랫폼에 기능을 추가한다. 확장 메커니즘은 JAR 파일 포맷에 구현된다. 확장 메커니즘으로 JAR 파일이 다른 필요한 JAR 파일들을 Class-Path 헤더를 통해 manifest 파일에 지정할 수 있다.

extension1.jar와 extension2.jar가 같은 디렉토리 안의 두 개의 JAR 파일에 있다고 가정해보자. extension1.jar의 manifest는 다음 헤더를 포함하고 있다:


Class-Path: extension2.jar

이 헤더는 extension2.jar의 클래스들이 extension1.jar의 클래스를 목표에 맞춘 확장 클래스로서 작용한다는 것을 나타내고 있다. extension1.jar의 클래스들은 extension2.jar가 클랫의 경로의 일부가 될 필요 없이 extension2.jar의 클래스를 호출할 수 있다.

예를 들어 ExtensionDemo 클래스를 레퍼런싱하는 ExtensionClient 클래스가 ExtensionClient.jar라고 하는 JAR 파일에 번들되었고 ExtensionDemo 클래스가 ExtensionDemo.jar에 번들되었다고 가정해보자. ExtensionDemo.jar가 확장으로 취급되기 위해서는 ExtensionDemo.jar는 ExtensionClient.jar의 manifest 안의 Class-Path 헤더에 리스트되어야 한다:


Manifest-Version: 1.0
Class-Path: ExtensionDemo.jar




위로


JAR 파일의 보안

JAR 파일은 jarsigner 툴을 사용하거나 java.security API를 통해서 직접 서명될 수 있다. 서명된 JAR 파일은 원래 JAR 파일과 정확히 같다. manifest만이 업데이트 된 것과 두 개의 추가 파일들이 META-INF 디렉토리에 추가된 것을 제외하고.

Keystore 데이터베이스에 저장된 인증을 사용하여 JAR 파일은 서명된다. Keystore에 저장된 인증은 패스워드로 보호된다.


그림 1. Keystore 데이터베이스
Keystore Database

JAR의 각 서명자는 JAR 파일의 META-INF 디렉토리안에 있는 .SF 확장자가 붙은 서명으로 표현된다. 이 파일의 포맷은 manifest 파일과 비슷하다. 메인 섹션과 개별 엔트리들로 구성되어 있다. 서명된 JAR에서 오는 파일을 확인하기 위해 서명 파일의 다이제스트 값은 JAR 파일의 상응 엔트리에 대비하여 계산된 다이제스트와 비교된다.


Listing 1. Manifest와 서명 파일

Contents of signature file META-INF/MANIFEST.MF

Manifest-Version: 1.0
Created-By: 1.3.0 (Sun Microsystems Inc.)

Name: Sample.java
SHA1-Digest: 3+DdYW8INICtyG8ZarHlFxX0W6g=

Name: Sample.class
SHA1-Digest: YJ5yQHBZBJ3SsTNcHJFqUkfWEmI=

Contents of signature file META-INF/JAMES.SF

Signature-Version: 1.0
SHA1-Digest-Manifest: HBstZOJBuuTJ6QMIdB90T8sjaOM=
Created-By: 1.3.0 (Sun Microsystems Inc.)

Name: Sample.java
SHA1-Digest: qipMDrkurQcKwnyIlI3Jtrnia8Q=

Name: Sample.class
SHA1-Digest: pT2DYby8QXPcCzv2NwpLxd8p4G4=

디지틀 서명

디지틀 서명은 .SF 서명 파일의 서명완료된 버전이다. 디지틀 서명 파일은 바이너리 파일이며 .SF 파일과 같은 파일이름을 갖고 있지만 다른 확장이다. 확장은 디지틀 서명 유형에 따라 다양하고 (RSA, DSA, PGP). JAR 서명에 사용된 인증 유형에 따라 다르다.

Keystore

JAR 파일에 서명하려면 프라이빗 키를 가져야 한다. 프라이빗 키와 관련 퍼블릭 키 인증은 패스워드로 보호된 데이터베이스(keystores)에 저장된다. JDK는 Keystore를 구현 및 변경하는 툴을 포함하고 있다. Keystore의 각 키는 앨리어스에 의해 구분되는데 전형적으로 키를 소유한 서명자의 이름이다.

모든 Keystore 엔트리들은 고유 앨리어스로 액세스된다. 앨리어스는 Keystore에 엔터티를 추가할 때 keytool -genkey 명령어를 사용하여 지정되어 키 쌍을 만든다. 뒤따르는 keytool 명령어는 이와 같은 앨리어스를 사용하여 엔터티를 언급해야 한다.

예를 들어 "james"라는 앨리어스로 새로운 퍼블릭/프라이빗 키 쌍을 만들고 퍼블릭 키를 자가 서명된 인증으로 래핑하려면 다음 명령어를 사용한다:


keytool -genkey -alias james -keypass jamespass
-validity 80 -keystore jamesKeyStore
-storepass jamesKeyStorePass

jarsigner 툴

jarsigner 툴은 Keystore를 사용하여 JAR 파일에 대한 디지틀 서명을 만들거나 확인한다.

위 예제에서 처럼 "jamesKeyStore" Keystore를 만들었고 여기에 "james" 앨리어스와 키를 포함하고 있다고 가정해보자. 다음 명령어로 JAR 파일에 서명할 수 있다:


jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
-keypass jamespass -signedjar SSample.jar Sample.jar james

이 명령어는 앨리어스가 "james"이고 패스워드가 "jamespass"인 키를 보내 Sample.jar 파일에 서명하고 SSample.jar라는 서명된 JAR를 만든다.


jarsigner -verify SSample.jar




위로


JAR 인덱싱(indexing)

애플리케이션 또는 애플릿이 다중의 JAR 파일들로 번들된다면 클래스 로더는 단순한 리니어 검색 알고리즘을 사용하여 클래스 경로의 엘리먼트를 검색한다. 클래스 로더가 존재하지 않은 리소스를 찾으려고 하면 애플리케이션 또는 애플릿 내의 모든 JAR 파일들은 다운로드 되어야한다. 큰 네트워크 애플리케이션과 애플릿의 경우 늦은 시작, 지연된 응답, 네트워크 대역 낭비를 초래한다.

JDK 1.3 이후 JAR 파일 포맷은 인덱싱(indexing)을 지원하여 네트워크 애플리케이션(특히 애플릿)의 클래스 검색 프로세스를 최적화했다. JarIndex 메커니즘은 애플릿 또는 애플리케이션에 정의된 모든 JAR 파일의 내용을 모아 첫 번째 JAR 파일의 인덱스 파일에 이 정보를 저장한다. 첫 번째 JAR 파일이 다운로드된 후에 애플릿 클래스 로더는 모아진 콘텐트 정보를 사용하여 JAR 파일을 효율적으로 다운로드한다. 이 디렉토리 정보는 INDEX.LIST라는 이름으로 간단한 텍스트 파일로 저장된다.(META-INF 디렉토리).

JarIndex 만들기


그림 2. JarIndex
JarIndex Demo

다음 명령어를 사용하여 JarIndex_Main.jar, JarIndex_test.jar, JarIndex_test1.jar용 인덱스 파일을 만든다:


jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar

INDEX.LIST 파일은 간단한 포맷을 갖고 있으며 색인된 JAR 파일에 저장된 패키지 또는 클래스 이름을 포함하고 있다.(Listing 2):


Listing 2. JarIndex INDEX.LIST 파일

JarIndex-Version: 1.0

JarIndex_Main.jar
sp

JarIndex_test.jar
Sample

SampleDir/JarIndex_test1.jar
org
org/apache
org/apache/xerces
org/apache/xerces/framework
org/apache/xerces/framework/xml4j



2007/05/14 18:48 2007/05/14 18:48
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다