KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > poi > hpsf > examples > WriteAuthorAndTitle


1 /* ====================================================================
2    Copyright 2002-2004 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.poi.hpsf.examples;
18
19 import java.io.ByteArrayInputStream JavaDoc;
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileNotFoundException JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Map JavaDoc;
29
30 import org.apache.poi.hpsf.HPSFRuntimeException;
31 import org.apache.poi.hpsf.MarkUnsupportedException;
32 import org.apache.poi.hpsf.MutablePropertySet;
33 import org.apache.poi.hpsf.MutableSection;
34 import org.apache.poi.hpsf.NoPropertySetStreamException;
35 import org.apache.poi.hpsf.PropertySet;
36 import org.apache.poi.hpsf.PropertySetFactory;
37 import org.apache.poi.hpsf.SummaryInformation;
38 import org.apache.poi.hpsf.Util;
39 import org.apache.poi.hpsf.Variant;
40 import org.apache.poi.hpsf.WritingNotSupportedException;
41 import org.apache.poi.hpsf.wellknown.PropertyIDMap;
42 import org.apache.poi.poifs.eventfilesystem.POIFSReader;
43 import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
44 import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener;
45 import org.apache.poi.poifs.filesystem.DirectoryEntry;
46 import org.apache.poi.poifs.filesystem.DocumentInputStream;
47 import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
48 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
49
50 /**
51  * <p>This class is a sample application which shows how to write or modify the
52  * author and title property of an OLE 2 document. This could be done in two
53  * different ways:</p>
54  *
55  * <ul>
56  *
57  * <li><p>The first approach is to open the OLE 2 file as a POI filesystem
58  * (see class {@link POIFSFileSystem}), read the summary information property
59  * set (see classes {@link SummaryInformation} and {@link PropertySet}), write
60  * the author and title properties into it and write the property set back into
61  * the POI filesystem.</p></li>
62  *
63  * <li><p>The second approach does not modify the original POI filesystem, but
64  * instead creates a new one. All documents from the original POIFS are copied
65  * to the destination POIFS, except for the summary information stream. The
66  * latter is modified by setting the author and title property before writing
67  * it to the destination POIFS. It there are several summary information streams
68  * in the original POIFS - e.g. in subordinate directories - they are modified
69  * just the same.</p></li>
70  *
71  * </ul>
72  *
73  * <p>This sample application takes the second approach. It expects the name of
74  * the existing POI filesystem's name as its first command-line parameter and
75  * the name of the output POIFS as the second command-line argument. The
76  * program then works as described above: It copies nearly all documents
77  * unmodified from the input POI filesystem to the output POI filesystem. If it
78  * encounters a summary information stream it reads its properties. Then it sets
79  * the "author" and "title" properties to new values and writes the modified
80  * summary information stream into the output file.</p>
81  *
82  * <p>Further explanations can be found in the HPSF HOW-TO.</p>
83  *
84  * @author Rainer Klute <a
85  * HREF="mailto:klute@rainer-klute.de">&lt;klute@rainer-klute.de&gt;</a>
86  * @version $Id: WriteAuthorAndTitle.java,v 1.7 2005/01/25 20:08:18 klute Exp $
87  * @since 2003-09-01
88  */

89 public class WriteAuthorAndTitle
90 {
91     /**
92      * <p>Runs the example program.</p>
93      *
94      * @param args Command-line arguments. The first command-line argument must
95      * be the name of a POI filesystem to read.
96      * @throws IOException if any I/O exception occurs.
97      */

98     public static void main(final String JavaDoc[] args) throws IOException JavaDoc
99     {
100         /* Check whether we have exactly two command-line arguments. */
101         if (args.length != 2)
102         {
103             System.err.println("Usage: " + WriteAuthorAndTitle.class.getName() +
104                                " originPOIFS destinationPOIFS");
105             System.exit(1);
106         }
107         
108         /* Read the names of the origin and destination POI filesystems. */
109         final String JavaDoc srcName = args[0];
110         final String JavaDoc dstName = args[1];
111
112         /* Read the origin POIFS using the eventing API. The real work is done
113          * in the class ModifySICopyTheRest which is registered here as a
114          * POIFSReader. */

115         final POIFSReader r = new POIFSReader();
116         final ModifySICopyTheRest msrl = new ModifySICopyTheRest(dstName);
117         r.registerListener(msrl);
118         r.read(new FileInputStream JavaDoc(srcName));
119         
120         /* Write the new POIFS to disk. */
121         msrl.close();
122     }
123
124
125
126     /**
127      * <p>This class does all the work. As its name implies it modifies a
128      * summary information property set and copies everything else unmodified
129      * to the destination POI filesystem. Since an instance of it is registered
130      * as a {@link POIFSReader} its method {@link
131      * #processPOIFSReaderEvent(POIFSReaderEvent) is called for each document in
132      * the origin POIFS.</p>
133      */

134     static class ModifySICopyTheRest implements POIFSReaderListener
135     {
136         String JavaDoc dstName;
137         OutputStream JavaDoc out;
138         POIFSFileSystem poiFs;
139
140
141         /**
142          * <p>The constructor of a {@link ModifySICopyTheRest} instance creates
143          * the target POIFS. It also stores the name of the file the POIFS will
144          * be written to once it is complete.</p>
145          *
146          * @param dstName The name of the disk file the destination POIFS is to
147          * be written to.
148          * @throws FileNotFoundException
149          */

150         public ModifySICopyTheRest(final String JavaDoc dstName)
151         {
152             this.dstName = dstName;
153             poiFs = new POIFSFileSystem();
154         }
155
156
157         /**
158          * <p>The method is called by POI's eventing API for each file in the
159          * origin POIFS.</p>
160          */

161         public void processPOIFSReaderEvent(final POIFSReaderEvent event)
162         {
163             /* The following declarations are shortcuts for accessing the
164              * "event" object. */

165             final POIFSDocumentPath path = event.getPath();
166             final String JavaDoc name = event.getName();
167             final DocumentInputStream stream = event.getStream();
168
169             Throwable JavaDoc t = null;
170
171             try
172             {
173                 /* Find out whether the current document is a property set
174                  * stream or not. */

175                 if (PropertySet.isPropertySetStream(stream))
176                 {
177                     /* Yes, the current document is a property set stream.
178                      * Let's create a PropertySet instance from it. */

179                     PropertySet ps = null;
180                     try
181                     {
182                         ps = PropertySetFactory.create(stream);
183                     }
184                     catch (NoPropertySetStreamException ex)
185                     {
186                         /* This exception will not be thrown because we already
187                          * checked above. */

188                     }
189
190                     /* Now we know that we really have a property set. The next
191                      * step is to find out whether it is a summary information
192                      * or not. */

193                     if (ps.isSummaryInformation())
194                         /* Yes, it is a summary information. We will modify it
195                          * and write the result to the destination POIFS. */

196                         editSI(poiFs, path, name, ps);
197                     else
198                         /* No, it is not a summary information. We don't care
199                          * about its internals and copy it unmodified to the
200                          * destination POIFS. */

201                         copy(poiFs, path, name, ps);
202                 }
203                 else
204                     /* No, the current document is not a property set stream. We
205                      * copy it unmodified to the destination POIFS. */

206                     copy(poiFs, event.getPath(), event.getName(), stream);
207             }
208             catch (MarkUnsupportedException ex)
209             {
210                 t = ex;
211             }
212             catch (IOException JavaDoc ex)
213             {
214                 t = ex;
215             }
216             catch (WritingNotSupportedException ex)
217             {
218                 t = ex;
219             }
220
221             /* According to the definition of the processPOIFSReaderEvent method
222              * we cannot pass checked exceptions to the caller. The following
223              * lines check whether a checked exception occured and throws an
224              * unchecked exception. The message of that exception is that of
225              * the underlying checked exception. */

226             if (t != null)
227             {
228                 throw new HPSFRuntimeException
229                     ("Could not read file \"" + path + "/" + name +
230                      "\". Reason: " + Util.toString(t));
231             }
232         }
233
234
235         /**
236          * <p>Receives a summary information property set modifies (or creates)
237          * its "author" and "title" properties and writes the result under the
238          * same path and name as the origin to a destination POI filesystem.</p>
239          *
240          * @param poiFs The POI filesystem to write to.
241          * @param path The original (and destination) stream's path.
242          * @param name The original (and destination) stream's name.
243          * @param si The property set. It should be a summary information
244          * property set.
245          */

246         public void editSI(final POIFSFileSystem poiFs,
247                            final POIFSDocumentPath path,
248                            final String JavaDoc name,
249                            final PropertySet si)
250             throws WritingNotSupportedException, IOException JavaDoc
251         {
252             /* Get the directory entry for the target stream. */
253             final DirectoryEntry de = getPath(poiFs, path);
254
255             /* Create a mutable property set as a copy of the original read-only
256              * property set. */

257             final MutablePropertySet mps = new MutablePropertySet(si);
258             
259             /* Retrieve the section containing the properties to modify. A
260              * summary information property set contains exactly one section. */

261             final MutableSection s =
262                 (MutableSection) mps.getSections().get(0);
263
264             /* Set the properties. */
265             s.setProperty(PropertyIDMap.PID_AUTHOR, Variant.VT_LPSTR,
266                           "Rainer Klute");
267             s.setProperty(PropertyIDMap.PID_TITLE, Variant.VT_LPWSTR,
268                           "Test");
269
270             /* Create an input stream containing the bytes the property set
271              * stream consists of. */

272             final InputStream JavaDoc pss = mps.toInputStream();
273
274             /* Write the property set stream to the POIFS. */
275             de.createDocument(name, pss);
276         }
277
278
279         /**
280          * <p>Writes a {@link PropertySet} to a POI filesystem. This method is
281          * simpler than {@link #editSI} because the origin property set has just
282          * to be copied.</p>
283          *
284          * @param poiFs The POI filesystem to write to.
285          * @param path The file's path in the POI filesystem.
286          * @param name The file's name in the POI filesystem.
287          * @param ps The property set to write.
288          */

289         public void copy(final POIFSFileSystem poiFs,
290                          final POIFSDocumentPath path,
291                          final String JavaDoc name,
292                          final PropertySet ps)
293             throws WritingNotSupportedException, IOException JavaDoc
294         {
295             final DirectoryEntry de = getPath(poiFs, path);
296             final MutablePropertySet mps = new MutablePropertySet(ps);
297             de.createDocument(name, mps.toInputStream());
298         }
299
300
301
302         /**
303          * <p>Copies the bytes from a {@link DocumentInputStream} to a new
304          * stream in a POI filesystem.</p>
305          *
306          * @param poiFs The POI filesystem to write to.
307          * @param path The source document's path.
308          * @param stream The stream containing the source document.
309          */

310         public void copy(final POIFSFileSystem poiFs,
311                          final POIFSDocumentPath path,
312                          final String JavaDoc name,
313                          final DocumentInputStream stream) throws IOException JavaDoc
314         {
315             final DirectoryEntry de = getPath(poiFs, path);
316             final ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
317             int c;
318             while ((c = stream.read()) != -1)
319                 out.write(c);
320             stream.close();
321             out.close();
322             final InputStream JavaDoc in =
323                 new ByteArrayInputStream JavaDoc(out.toByteArray());
324             de.createDocument(name, in);
325         }
326
327
328         /**
329          * <p>Writes the POI file system to a disk file.</p>
330          *
331          * @throws FileNotFoundException
332          * @throws IOException
333          */

334         public void close() throws FileNotFoundException JavaDoc, IOException JavaDoc
335         {
336             out = new FileOutputStream JavaDoc(dstName);
337             poiFs.writeFilesystem(out);
338             out.close();
339         }
340
341
342
343         /** Contains the directory paths that have already been created in the
344          * output POI filesystem and maps them to their corresponding
345          * {@link org.apache.poi.poifs.filesystem.DirectoryNode}s. */

346         private final Map JavaDoc paths = new HashMap JavaDoc();
347
348
349
350         /**
351          * <p>Ensures that the directory hierarchy for a document in a POI
352          * fileystem is in place. When a document is to be created somewhere in
353          * a POI filesystem its directory must be created first. This method
354          * creates all directories between the POI filesystem root and the
355          * directory the document should belong to which do not yet exist.</p>
356          *
357          * <p>Unfortunately POI does not offer a simple method to interrogate
358          * the POIFS whether a certain child node (file or directory) exists in
359          * a directory. However, since we always start with an empty POIFS which
360          * contains the root directory only and since each directory in the
361          * POIFS is created by this method we can maintain the POIFS's directory
362          * hierarchy ourselves: The {@link DirectoryEntry} of each directory
363          * created is stored in a {@link Map}. The directories' path names map
364          * to the corresponding {@link DirectoryEntry} instances.</p>
365          *
366          * @param poiFs The POI filesystem the directory hierarchy is created
367          * in, if needed.
368          * @param path The document's path. This method creates those directory
369          * components of this hierarchy which do not yet exist.
370          * @return The directory entry of the document path's parent. The caller
371          * should use this {@link DirectoryEntry} to create documents in it.
372          */

373         public DirectoryEntry getPath(final POIFSFileSystem poiFs,
374                                       final POIFSDocumentPath path)
375         {
376             try
377             {
378                 /* Check whether this directory has already been created. */
379                 final String JavaDoc s = path.toString();
380                 DirectoryEntry de = (DirectoryEntry) paths.get(s);
381                 if (de != null)
382                     /* Yes: return the corresponding DirectoryEntry. */
383                     return de;
384
385                 /* No: We have to create the directory - or return the root's
386                  * DirectoryEntry. */

387                 int l = path.length();
388                 if (l == 0)
389                     /* Get the root directory. It does not have to be created
390                      * since it always exists in a POIFS. */

391                     de = poiFs.getRoot();
392                 else
393                 {
394                     /* Create a subordinate directory. The first step is to
395                      * ensure that the parent directory exists: */

396                     de = getPath(poiFs, path.getParent());
397                     /* Now create the target directory: */
398                     de = de.createDirectory(path.getComponent
399                                             (path.length() - 1));
400                 }
401                 paths.put(s, de);
402                 return de;
403             }
404             catch (IOException JavaDoc ex)
405             {
406                 /* This exception will be thrown if the directory already
407                  * exists. However, since we have full control about directory
408                  * creation we can ensure that this will never happen. */

409                 ex.printStackTrace(System.err);
410                 throw new RuntimeException JavaDoc(ex.toString());
411                 /* FIXME (2): Replace the previous line by the following once we
412                  * no longer need JDK 1.3 compatibility. */

413                 // throw new RuntimeException(ex);
414
}
415         }
416     }
417
418 }
419
Popular Tags