1 package org.xmlBlaster.util;
  2 
  3 import java.io.File;
  4 import java.io.FileOutputStream;
  5 import java.io.IOException;
  6 import java.util.Properties;
  7 import java.util.logging.Logger;
  8 
  9 import org.xmlBlaster.util.def.Constants;
 10 import org.xmlBlaster.util.def.ErrorCode;
 11 import org.xmlBlaster.util.key.KeyData;
 12 import org.xmlBlaster.util.qos.QosData;
 13 
 14 /**
 15  * Dump message to file. 
 16  * The XML is in XmlScript format and can be refed.
 17  * <pre>
 18  * Configuration:
 19  * xmlBlaster/FileDumper/directoryName  -> ${user.home}/FileDumper
 20  * xmlBlaster/FileDumper/forceBase64    -> false
 21  * </pre>
 22  * @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>
 23  */
 24 public class FileDumper {
 25    private static String ME = "FileDumper";
 26    private static Logger log = Logger.getLogger(FileDumper.class.getName());
 27    private Global glob;
 28    private String directoryName;
 29    /** forceBase64==false: ASCII dump for content if possible (XML embedable) */
 30    private boolean forceBase64 = false;
 31    
 32    public FileDumper(Global glob) throws XmlBlasterException {
 33      this(glob, null, glob.getProperty().get("xmlBlaster/FileDumper/forceBase64", false));
 34    }
 35    
 36    public FileDumper(Global glob, String dirName, boolean forceBase64) throws XmlBlasterException {
 37       this.glob = glob;
 38       this.forceBase64 = forceBase64;
 39       if (dirName == null) {
 40         this.directoryName = glob.getProperty().get("xmlBlaster/FileDumper/directoryName", System.getProperty("user.home") + System.getProperty("file.separator") + "FileDumper");
 41           log.info("Created FileDumper instance forceBase64=" + this.forceBase64 + " to dump messages to directory xmlBlaster/FileDumper/directoryName=" + this.directoryName);
 42           //log.info("Dumping occurrences of topic '" + Constants.OID_DEAD_LETTER + "' forceBase64=" + this.forceBase64 + " to directory " + this.directoryName);
 43       }
 44       else {
 45         this.directoryName = dirName;
 46           log.info("Created FileDumper instance forceBase64=" + this.forceBase64 + " to dump messages to directory " + this.directoryName);
 47       }
 48       initDirectory(null, "directoryName", this.directoryName);
 49    }
 50 
 51    public String dumpMessage(KeyData keyData, byte[] content, QosData qosData) {
 52       return dumpMessage(keyData, content, qosData, true);
 53    }
 54 
 55    /**
 56     * Dump dead message to hard disk. The file name is the receive timestamp of
 57     * the message, for example
 58     * <tt>/home/xmlblast/tmp/2004-10-23_18_52_39_87.xml</tt>
 59     * 
 60     * @param qosData
 61     *           may not be null
 62     * @return fileName
 63     */                     
 64    public String dumpMessage(KeyData keyData, byte[] content, QosData qosData, boolean verbose) {
 65       String fnStr = "";
 66       try {
 67          if (content == null)
 68             content = new byte[0];
 69          String fn = (qosData == null) ? new Timestamp().toString() : qosData.getRcvTimestampNotNull().toString();
 70          String key = (keyData == null) ? "" : keyData.toXml();
 71          Properties props = new Properties();
 72          if (!forceBase64)
 73           props.put(Constants.TOXML_FORCEREADABLE, ""+true);
 74          String qos = (qosData == null) ? "" : qosData.toXml("", props);
 75          String oid = (keyData == null) ? "" : keyData.getOid();
 76 
 77          fn = Global.getStrippedString(fn); // Strip chars like ":" so that fn is usable as a file name
 78          fn = fn + ".xml";
 79 
 80          initDirectory(null, "directoryName", this.directoryName); // In case somebody has removed it
 81          File to_file = new File(this.directoryName, fn);
 82 
 83          fnStr = to_file.getAbsolutePath();
 84          
 85          FileOutputStream to = new FileOutputStream(to_file);
 86          if (verbose)
 87           log.info("Dumping message to  '" + to_file.toString() + "'" );
 88 
 89          StringBuffer sb = new StringBuffer(qos.length() + key.length() + 1024);
 90          //sb.append("<?xml version='1.0' encoding='iso-8859-1'?>");
 91          //sb.append("<?xml version='1.0' encoding='utf-8' ?>");
 92 
 93          sb.append("\n  <!-- Dump of topic '").append(oid).append("' -->");
 94          sb.append("\n<xmlBlaster>");
 95          sb.append("\n <publish>");
 96          to.write(sb.toString().getBytes());
 97          sb.setLength(0);
 98 
 99          {
100             sb.append(qos);
101             sb.append(key);
102             to.write(sb.toString().getBytes());
103             sb.setLength(0);
104 
105             // TODO: Potential charset problem when not Base64 protected
106             boolean doEncode = forceBase64;
107             if (!forceBase64) {
108                int len = content.length - 2;
109                for (int i=0; i<len; i++) {
110                   if (content[i] == (byte)']' && content[i+1] == (byte)']' && content[i+2] == (byte)'>') {
111                      doEncode = true;
112                      break;
113                   }
114                }
115             }
116 
117             if (doEncode) {
118                EncodableData data = new EncodableData("content", null, Constants.TYPE_BLOB, Constants.ENCODING_BASE64);
119                data.setValue(content);
120                data.setSize(content.length);
121                to.write(data.toXml(" ").getBytes());
122             }
123             else {
124                EncodableData data = new EncodableData("content", null, null, null);
125                //String charSet = "UTF-8"; // "ISO-8859-1", "US-ASCII"
126                //data.setValue(new String(content, charSet), null);
127                data.setValueRaw(new String(content));
128                data.forceCdata(true);
129                data.setSize(content.length);
130                to.write(data.toXml(" ").getBytes());
131             }
132          }
133          {
134             //MsgUnitRaw msg = new MsgUnitRaw(key, content, qos);
135             //msg.toXml(" ", to);
136          }
137 
138          sb.append("\n </publish>");
139          sb.append("\n</xmlBlaster>");
140          to.write(sb.toString().getBytes());
141          to.close();
142       }
143       catch (Throwable e) {
144          log.severe("Dumping of message failed: " + (qosData == null ? "" : qosData.toXml())
145                + (keyData == null ? "" : keyData.toXml()) + new String(content));
146       }
147       return fnStr;
148    }
149 
150    /**
151     * Returns the specified directory or null or if needed it will create one
152     * @param parent
153     * @param propName For logging only
154     * @param dirName
155     * @return
156     * @throws XmlBlasterException
157     */
158    private File initDirectory(File parent, String propName, String dirName) throws XmlBlasterException {
159       File dir = null;
160       if (dirName != null) {
161          File tmp = new File(dirName);
162          if (tmp.isAbsolute() || parent == null) {
163             dir = new File(dirName);
164          }
165          else {
166             dir = new File(parent, dirName);
167          }
168          if (!dir.exists()) {
169             String absDirName  = null; 
170             try {
171                absDirName = dir.getCanonicalPath();
172             }
173             catch (IOException ex) {
174                absDirName = dir.getAbsolutePath();
175             }
176             log.info("Constructor: directory '" + absDirName + "' does not yet exist. I will create it");
177             boolean ret = dir.mkdir();
178             if (!ret)
179                throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_FILEIO, ME, "could not create directory '" + absDirName + "'");
180          }
181          if (!dir.isDirectory()) {
182             throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_FILEIO, ME, "'" + dir.getAbsolutePath() + "' is not a directory");
183          }
184          if (!dir.canRead())
185             throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_FILEIO, ME + ".constructor", "no rights to read from the directory '" + dir.getAbsolutePath() + "'");
186          if (!dir.canWrite())
187             throw new XmlBlasterException(this.glob, ErrorCode.RESOURCE_FILEIO, ME + ".constructor", "no rights to write to the directory '" + dir.getAbsolutePath() + "'");
188       }
189       else {
190          log.info("Constructor: the '" + propName + "' property is not set. Instead of moving concerned entries they will be deleted");
191       }
192       return dir;
193    }
194 
195 public boolean isForceBase64() {
196    return forceBase64;
197 }
198 
199 public void setForceBase64(boolean forceBase64) {
200    this.forceBase64 = forceBase64;
201 }
202 
203 }


syntax highlighted by Code2HTML, v. 0.9.1