Recently I had a task where I needed to add custom properties into lots of Microsoft Word documents. I could find plenty on changing the standard metadata set (thanks Ray
), but nothing on custom metadata.
As part of my coldfusion script, I needed to, among other things, add custom properties into the document. If you are looking at doing this, the Apache POI libraries are great. The way we went about this was to build a custom java class, load it in dynamically using Mark Mandel’s javaloader (a fellow Aussie
), and then execute it in the coldfusion script.
You’ll need to remember to load in the POI libraries when you build the java class. You can download the latest version from here.
Kudos goes to a guy called Rainer Klute, whos code helped to shape this method.
(Edit: the module to show the code makes the comments look funny, however it should still work when you put it into eclipse {or your favourite IDE})
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import org.apache.poi.hpsf.CustomProperties;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.MarkUnsupportedException;
import org.apache.poi.hpsf.NoPropertySetStreamException;
import org.apache.poi.hpsf.PropertySet;
import org.apache.poi.hpsf.PropertySetFactory;
import org.apache.poi.hpsf.SummaryInformation;
import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
import org.apache.poi.hpsf.WritingNotSupportedException;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class ModifyDocumentSummaryInformation
{
public static void main(String theFile, String customProperty, String customPropertyValue) throws IOException,
NoPropertySetStreamException, MarkUnsupportedException,
UnexpectedPropertySetTypeException, WritingNotSupportedException
{
/* Takes the full path of the file */
File poiFilesystem = new File(theFile);
/* Open the POI filesystem. */
InputStream is = new FileInputStream(poiFilesystem);
POIFSFileSystem poifs = new POIFSFileSystem(is);
is.close();
/* Read the summary information. */
DirectoryEntry dir = poifs.getRoot();
SummaryInformation si;
try
{
DocumentEntry siEntry = (DocumentEntry)
dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
DocumentInputStream dis = new DocumentInputStream(siEntry);
PropertySet ps = new PropertySet(dis);
dis.close();
si = new SummaryInformation(ps);
}
catch (FileNotFoundException ex)
{
/* There is no summary information yet. We have to create a new
* one. */
si = PropertySetFactory.newSummaryInformation();
}
/* Read the document summary information. */
DocumentSummaryInformation dsi;
try
{
DocumentEntry dsiEntry = (DocumentEntry)
dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
PropertySet ps = new PropertySet(dis);
dis.close();
dsi = new DocumentSummaryInformation(ps);
}
catch (FileNotFoundException ex)
{
/* There is no document summary information yet. We have to create a
* new one. */
dsi = PropertySetFactory.newDocumentSummaryInformation();
}
CustomProperties customProperties = dsi.getCustomProperties();
if (customProperties == null)
customProperties = new CustomProperties();
/* Insert some custom properties into the container. */
customProperties.put(customProperty, customPropertyValue);
/* Write the custom properties back to the document summary
* information. */
dsi.setCustomProperties(customProperties);
/* Write the summary information and the document summary information
* to the POI filesystem. */
si.write(dir, SummaryInformation.DEFAULT_STREAM_NAME);
dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
/* Write the POI filesystem back to the original file. Please note that
* in production code you should never write directly to the origin
* file! In case of a writing error everything would be lost. */
OutputStream out = new FileOutputStream(poiFilesystem);
poifs.writeFilesystem(out);
out.close();
}
}
Once you have built this into a jar file, you can then load it in to coldfusion through the javaloader
<cfset jarpath = expandPath(".")>
<cfset paths = []>
<cfdirectory action="list" name="files" directory="#jarpath#" filter="*.jar" recurse="true">
<cfloop query="files">
<cfset arrayAppend(paths, directory & "/" & name)>
</cfloop>
<cfset variables.loader = createObject("component", "javaloader.JavaLoader").init(paths)>
Then call the functions. This takes a full file path, custom property name, and custom property value.
<cfset test = loader.create("ModifyDocumentSummaryInformation").init()>
<cfdump var="#test#">
<cfscript>
writeOutput(test.main("C:\temp\Doc5.doc","007","Richard"));
</cfscript>
I realise that this will be only useful for a few specific purposes. But you never know