KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > cluster > deploy > FileMessageFactory


1 /*
2  * Copyright 1999,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.catalina.cluster.deploy;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.FileNotFoundException JavaDoc;
24
25 /**
26  * This factory is used to read files and write files by splitting them up into
27  * smaller messages. So that entire files don't have to be read into memory.
28  * <BR>
29  * The factory can be used as a reader or writer but not both at the same time.
30  * When done reading or writing the factory will close the input or output
31  * streams and mark the factory as closed. It is not possible to use it after
32  * that. <BR>
33  * To force a cleanup, call cleanup() from the calling object. <BR>
34  * This class is not thread safe.
35  *
36  * @author Filip Hanik
37  * @version 1.0
38  */

39 public class FileMessageFactory {
40     /*--Static Variables----------------------------------------*/
41     public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
42             .getLog(FileMessageFactory.class);
43
44     /**
45      * The number of bytes that we read from file
46      */

47     public static final int READ_SIZE = 1024 * 10; //10kb
48

49     /**
50      * The file that we are reading/writing
51      */

52     protected File JavaDoc file = null;
53
54     /**
55      * True means that we are writing with this factory. False means that we are
56      * reading with this factory
57      */

58     protected boolean openForWrite;
59
60     /**
61      * Once the factory is used, it can not be reused.
62      */

63     protected boolean closed = false;
64
65     /**
66      * When openForWrite=false, the input stream is held by this variable
67      */

68     protected FileInputStream JavaDoc in;
69
70     /**
71      * When openForWrite=true, the output stream is held by this variable
72      */

73     protected FileOutputStream JavaDoc out;
74
75     /**
76      * The number of messages we have read or written
77      */

78     protected int nrOfMessagesProcessed = 0;
79
80     /**
81      * The total size of the file
82      */

83     protected long size = 0;
84
85     /**
86      * The total number of packets that we split this file into
87      */

88     protected long totalNrOfMessages = 0;
89
90     /**
91      * The bytes that we hold the data in, not thread safe.
92      */

93     protected byte[] data = new byte[READ_SIZE];
94
95     /**
96      * Private constructor, either instantiates a factory to read or write. <BR>
97      * When openForWrite==true, then a the file, f, will be created and an
98      * output stream is opened to write to it. <BR>
99      * When openForWrite==false, an input stream is opened, the file has to
100      * exist.
101      *
102      * @param f
103      * File - the file to be read/written
104      * @param openForWrite
105      * boolean - true means we are writing to the file, false means
106      * we are reading from the file
107      * @throws FileNotFoundException -
108      * if the file to be read doesn't exist
109      * @throws IOException -
110      * if the system fails to open input/output streams to the file
111      * or if it fails to create the file to be written to.
112      */

113     private FileMessageFactory(File JavaDoc f, boolean openForWrite)
114             throws FileNotFoundException JavaDoc, IOException JavaDoc {
115         this.file = f;
116         this.openForWrite = openForWrite;
117         if (log.isDebugEnabled())
118             log.debug("open file " + f + " write " + openForWrite);
119         if (openForWrite) {
120             if (!file.exists())
121                 file.createNewFile();
122             out = new FileOutputStream JavaDoc(f);
123         } else {
124             size = file.length();
125             totalNrOfMessages = (size / READ_SIZE) + 1;
126             in = new FileInputStream JavaDoc(f);
127         }//end if
128

129     }
130
131     /**
132      * Creates a factory to read or write from a file. When opening for read,
133      * the readMessage can be invoked, and when opening for write the
134      * writeMessage can be invoked.
135      *
136      * @param f
137      * File - the file to be read or written
138      * @param openForWrite
139      * boolean - true, means we are writing to the file, false means
140      * we are reading from it
141      * @throws FileNotFoundException -
142      * if the file to be read doesn't exist
143      * @throws IOException -
144      * if it fails to create the file that is to be written
145      * @return FileMessageFactory
146      */

147     public static FileMessageFactory getInstance(File JavaDoc f, boolean openForWrite)
148             throws FileNotFoundException JavaDoc, IOException JavaDoc {
149         return new FileMessageFactory(f, openForWrite);
150     }
151
152     /**
153      * Reads file data into the file message and sets the size, totalLength,
154      * totalNrOfMsgs and the message number <BR>
155      * If EOF is reached, the factory returns null, and closes itself, otherwise
156      * the same message is returned as was passed in. This makes sure that not
157      * more memory is ever used. To remember, neither the file message or the
158      * factory are thread safe. dont hand off the message to one thread and read
159      * the same with another.
160      *
161      * @param f
162      * FileMessage - the message to be populated with file data
163      * @throws IllegalArgumentException -
164      * if the factory is for writing or is closed
165      * @throws IOException -
166      * if a file read exception occurs
167      * @return FileMessage - returns the same message passed in as a parameter,
168      * or null if EOF
169      */

170     public FileMessage readMessage(FileMessage f)
171             throws IllegalArgumentException JavaDoc, IOException JavaDoc {
172         checkState(false);
173         int length = in.read(data);
174         if (length == -1) {
175             cleanup();
176             return null;
177         } else {
178             f.setData(data, length);
179             f.setTotalLength(size);
180             f.setTotalNrOfMsgs(totalNrOfMessages);
181             f.setMessageNumber(++nrOfMessagesProcessed);
182             return f;
183         }//end if
184
}
185
186     /**
187      * Writes a message to file. If (msg.getMessageNumber() ==
188      * msg.getTotalNrOfMsgs()) the output stream will be closed after writing.
189      *
190      * @param msg
191      * FileMessage - message containing data to be written
192      * @throws IllegalArgumentException -
193      * if the factory is opened for read or closed
194      * @throws IOException -
195      * if a file write error occurs
196      * @return returns true if the file is complete and outputstream is closed,
197      * false otherwise.
198      */

199     public boolean writeMessage(FileMessage msg)
200             throws IllegalArgumentException JavaDoc, IOException JavaDoc {
201         if (!openForWrite)
202             throw new IllegalArgumentException JavaDoc(
203                     "Can't write message, this factory is reading.");
204         if (log.isDebugEnabled())
205             log.debug("Message " + msg + " data " + msg.getData()
206                     + " data length " + msg.getDataLength() + " out " + out);
207         if (out != null) {
208             out.write(msg.getData(), 0, msg.getDataLength());
209             nrOfMessagesProcessed++;
210             out.flush();
211             if (msg.getMessageNumber() == msg.getTotalNrOfMsgs()) {
212                 out.close();
213                 cleanup();
214                 return true;
215             }//end if
216
} else {
217             if (log.isWarnEnabled())
218                 log.warn("Receive Message again -- Sender ActTimeout to short [ path: "
219                                 + msg.getContextPath()
220                                 + " war: "
221                                 + msg.getFileName()
222                                 + " data: "
223                                 + msg.getData()
224                                 + " data length: " + msg.getDataLength() + " ]");
225         }
226         return false;
227     }//writeMessage
228

229     /**
230      * Closes the factory, its streams and sets all its references to null
231      */

232     public void cleanup() {
233         if (in != null)
234             try {
235                 in.close();
236             } catch (Exception JavaDoc ignore) {
237             }
238         if (out != null)
239             try {
240                 out.close();
241             } catch (Exception JavaDoc ignore) {
242             }
243         in = null;
244         out = null;
245         size = 0;
246         closed = true;
247         data = null;
248         nrOfMessagesProcessed = 0;
249         totalNrOfMessages = 0;
250     }
251
252     /**
253      * Check to make sure the factory is able to perform the function it is
254      * asked to do. Invoked by readMessage/writeMessage before those methods
255      * proceed.
256      *
257      * @param openForWrite
258      * boolean
259      * @throws IllegalArgumentException
260      */

261     protected void checkState(boolean openForWrite)
262             throws IllegalArgumentException JavaDoc {
263         if (this.openForWrite != openForWrite) {
264             cleanup();
265             if (openForWrite)
266                 throw new IllegalArgumentException JavaDoc(
267                         "Can't write message, this factory is reading.");
268             else
269                 throw new IllegalArgumentException JavaDoc(
270                         "Can't read message, this factory is writing.");
271         }
272         if (this.closed) {
273             cleanup();
274             throw new IllegalArgumentException JavaDoc("Factory has been closed.");
275         }
276     }
277
278     /**
279      * Example usage.
280      *
281      * @param args
282      * String[], args[0] - read from filename, args[1] write to
283      * filename
284      * @throws Exception
285      */

286     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
287
288         System.out
289                 .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
290         System.out
291                 .println("Usage: This will make a copy of the file on the local file system");
292         FileMessageFactory read = getInstance(new File JavaDoc(args[0]), false);
293         FileMessageFactory write = getInstance(new File JavaDoc(args[1]), true);
294         FileMessage msg = new FileMessage(null, args[0], args[0]);
295         msg = read.readMessage(msg);
296         System.out.println("Expecting to write " + msg.getTotalNrOfMsgs()
297                 + " messages.");
298         int cnt = 0;
299         while (msg != null) {
300             write.writeMessage(msg);
301             cnt++;
302             msg = read.readMessage(msg);
303         }//while
304
System.out.println("Actually wrote " + cnt + " messages.");
305     }///main
306

307     public File JavaDoc getFile() {
308         return file;
309     }
310
311 }
Popular Tags