1 package rydeen.io;
2
3 import rydeen.Destination;
4 import rydeen.ProcessTarget;
5
6 import java.io.File;
7 import java.io.FileOutputStream;
8 import java.io.FilterOutputStream;
9 import java.io.IOException;
10 import java.io.OutputStream;
11 import java.util.jar.JarOutputStream;
12 import java.util.jar.Manifest;
13 import java.util.zip.ZipEntry;
14
15 /**
16 * Jarファイルを出力先とする{@link Destination <code>Destination</code>}の実装クラスです.
17 *
18 * @author Haruaki Tamada
19 */
20 public class JarFileDestination extends AbstractDestination{
21 private File file;
22 private JarOutputStream jarOut;
23 private boolean closed = false;
24 private Manifest manifest;
25
26 /**
27 * 出力先のファイルを指定してオブジェクトを構築します.
28 * @param file 出力するjarファイルのパス.
29 */
30 public JarFileDestination(File file){
31 this.file = file;
32 }
33
34 /**
35 * 出力先のファイルとマニフェストを指定してオブジェクトを構築します.
36 * @param file 出力するjarファイルのパス.
37 * @param manifest 出力するjarファイルのマニフェストファイル.
38 */
39 public JarFileDestination(File file, Manifest manifest){
40 this.file = file;
41 this.manifest = manifest;
42 }
43
44 /**
45 * <p>
46 * 引数で与えられた文字列に出力するための出力ストリームを作成して,返します.
47 * 返される出力ストリームに必要なデータを出力し終えたら,閉じてください.
48 * </p><p>
49 * 引数に「/」が含まれていれば,jarファイル内のディレクトリ階層として扱われます.
50 * ディレクトリが存在しない場合は,自動的に作成されます.
51 * </p><p>
52 * 既に出力ストリームが閉じられていた場合
53 * ({@link #close <code>close</code>}メソッドが呼び出されていた場合)
54 * はIOExceptionが投げられます.
55 * 引数にnullが与えられた場合はNullPointerExceptionが投げられます.
56 * </p>
57 *
58 * @param name 出力するファイル名(jarファイルのエントリ).
59 * @throws IOException 既にcloseメソッドが呼ばれ,出力ストリームが閉じられたとき.
60 */
61 @Override
62 public OutputStream getOutput(String name) throws IOException{
63 if(closed){
64 throw new IOException("already closed");
65 }
66 if(name == null){
67 throw new NullPointerException();
68 }
69 if(jarOut == null){
70 if(manifest != null){
71 jarOut = new JarOutputStream(new FileOutputStream(file), manifest);
72 } else{
73 jarOut = new JarOutputStream(new FileOutputStream(file));
74 }
75 }
76 ZipEntry entry = new ZipEntry(name);
77 jarOut.putNextEntry(entry);
78 return new FilterOutputStream(jarOut){
79 @Override
80 public void close() throws IOException{
81 jarOut.closeEntry();
82 }
83 };
84 }
85
86 /**
87 * <p>
88 * 引数で与えられたProcessTargetを出力するための出力ストリームを作成して,返します.
89 * 返される出力ストリームに必要なデータを出力し終えたら,閉じてください.
90 * </p><p>
91 * targetの{@link ProcessTarget#getName <code>getName</code>}
92 * メソッドで得られる文字列をもとに出力先が決められます.
93 * 引数に「/」が含まれていれば,jarファイル内のディレクトリ階層として扱われます.
94 * ディレクトリが存在しない場合は,自動的に作成されます.
95 * </p><p>
96 * 既に出力ストリームが閉じられていた場合
97 * ({@link #close <code>close</code>}メソッドが呼び出されていた場合)
98 * はIOExceptionが投げられます.
99 * 引数にnullが与えられた場合はNullPointerExceptionが投げられます.
100 * </p>
101 *
102 * @param target 出力するファイル名(jarファイルのエントリ).
103 * @throws IOException 既にcloseメソッドが呼ばれ,出力ストリームが閉じられているとき.
104 */
105 @Override
106 public OutputStream getOutput(ProcessTarget target) throws IOException{
107 return getOutput(target.getName());
108 }
109
110 /**
111 * 出力するjarファイルを閉じて,出力を完了します.
112 * このメソッド呼び出し以降,このオブジェクトの全てのメソッドはIOExceptionが投げられるようになります.
113 * @throws IOException クローズ時にI/Oエラーが発生した場合,もしくは既にcloseメソッドが呼び出されている場合.
114 */
115 @Override
116 public synchronized void close() throws IOException{
117 if(closed){
118 throw new IOException("already closed");
119 }
120 if(jarOut != null && !closed){
121 jarOut.close();
122 closed = true;
123 }
124 }
125
126 /**
127 * このメソッドが閉じられているかを返します.
128 * このメソッドがtrueを返す場合,他のメソッドの動作は保証されません.
129 * @return この出力先が閉じられていればtrue,出力可能であればfalseを返す.
130 */
131 public boolean isClosed(){
132 return closed;
133 }
134 }