PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/atlassian/uwc/converters/smf/AttachmentConverter.java

https://bitbucket.org/bowmanb1/universal-wiki-converter
Java | 245 lines | 206 code | 23 blank | 16 comment | 48 complexity | 1e28a1a94ea92ecb4fa1fe5348104386 MD5 | raw file
  1. package com.atlassian.uwc.converters.smf;
  2. import java.io.File;
  3. import java.io.FileFilter;
  4. import java.io.FileInputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.nio.channels.FileChannel;
  9. import java.util.Properties;
  10. import java.util.Vector;
  11. import java.util.regex.Matcher;
  12. import java.util.regex.Pattern;
  13. import org.apache.log4j.Logger;
  14. import com.atlassian.uwc.converters.BaseConverter;
  15. import com.atlassian.uwc.exporters.SMFExporter;
  16. import com.atlassian.uwc.hierarchies.MetaHierarchy;
  17. import com.atlassian.uwc.ui.Page;
  18. public class AttachmentConverter extends BaseConverter {
  19. private static final String PROPKEY_REMOVE = "attachment-chars-remove";
  20. private static final String PROPKEY_TOUNDERSCORE = "attachment-chars-to-underscore";
  21. Logger log = Logger.getLogger(this.getClass());
  22. public void convert(Page page) {
  23. Properties meta = null;
  24. try {
  25. meta = MetaHierarchy.getMeta(page);
  26. } catch (IOException e) {
  27. log.error("Problem getting meta data for file: " + page.getFile().getAbsolutePath());
  28. e.printStackTrace();
  29. return;
  30. }
  31. String delim = meta.getProperty("attachments.delim", SMFExporter.Data.ATTACH_DELIM);
  32. Vector<String> filepaths = getAttachmentPaths(meta.getProperty("attachments.location", ""), delim);
  33. Vector<String> tmppaths = createTmpPaths(meta.getProperty("attachments.name", ""), page.getFile().getParent(), delim);
  34. copyToTmp(filepaths, tmppaths);
  35. attach(page, tmppaths);
  36. }
  37. protected Vector<String> getAttachmentPaths(String attachments) {
  38. return getAttachmentPaths(attachments, SMFExporter.Data.ATTACH_DELIM);
  39. }
  40. protected Vector<String> getAttachmentPaths(String attachments, String delim) {
  41. String out = this.getAttachmentDirectory();
  42. return createPaths(attachments, out, delim);
  43. }
  44. private Vector<String> createPaths(String files, String parent, String delim) {
  45. Vector<String> paths = new Vector<String>();
  46. if (files == null || "".equals(files) || "null".equals(files)) return paths;
  47. String[] all = splitFiles(files, delim);
  48. if (!parent.endsWith(File.separator)) parent += File.separator;
  49. for (int i = 0; i < all.length; i++) {
  50. String att = all[i];
  51. att = att.trim();
  52. att = removeChars(att);
  53. att = toUnderscore(att);
  54. paths.add(parent + att);
  55. }
  56. return paths;
  57. }
  58. private String[] splitFiles(String files, String delim) {
  59. String[] all;
  60. if (delim == null) all = new String[] {files};
  61. else all = files.split(delim);
  62. return all;
  63. }
  64. private String toUnderscore(String att) {
  65. String toUnderscoreChars = getToUnderscoreChars();
  66. if (toUnderscoreChars != null && !"".equals(toUnderscoreChars)) {
  67. for (int j = 0; j < toUnderscoreChars.length(); j++) {
  68. String c = Character.toString(toUnderscoreChars.charAt(j));
  69. //can't use a char class. how do we know what to escape?
  70. att = att.replaceAll("\\Q"+c+"\\E", "_");
  71. }
  72. }
  73. return att;
  74. }
  75. private String removeChars(String att) {
  76. String removeChars = getRemoveChars();
  77. if (removeChars != null && !"".equals(removeChars)) {
  78. for (int j = 0; j < removeChars.length(); j++) {
  79. String c = Character.toString(removeChars.charAt(j));
  80. //can't use a char class. how do we know what to escape?
  81. att = att.replaceAll("\\Q"+c+"\\E", "");
  82. }
  83. }
  84. return att;
  85. }
  86. private String getRemoveChars() {
  87. Properties props = this.getProperties();
  88. if (props.containsKey(PROPKEY_REMOVE))
  89. return props.getProperty(PROPKEY_REMOVE, null);
  90. return null;
  91. }
  92. private String getToUnderscoreChars() {
  93. Properties props = this.getProperties();
  94. if (props.containsKey(PROPKEY_TOUNDERSCORE))
  95. return props.getProperty(PROPKEY_TOUNDERSCORE, null);
  96. return null;
  97. }
  98. protected Vector<String> createTmpPaths(String attachments, String gparent) {
  99. return createTmpPaths(attachments, gparent, SMFExporter.Data.ATTACH_DELIM);
  100. }
  101. protected Vector<String> createTmpPaths(String attachments, String gparent, String delim) {
  102. if (!gparent.endsWith(File.separator)) gparent += File.separator;
  103. String parent = gparent + "attachments";
  104. File parentFile = new File(parent);
  105. if (!parentFile.exists()) parentFile.mkdir();
  106. return createPaths(attachments, parent, delim);
  107. }
  108. protected void copyToTmp(Vector<String> filepaths, Vector<String> tmppaths) {
  109. if (filepaths == null || tmppaths == null) {
  110. String error = "Attachments vectors are null. Cannot copy attachments to tmp.";
  111. log.error(error);
  112. addError(Feedback.CONVERTER_ERROR, error, true);
  113. return;
  114. }
  115. if (filepaths.size() != tmppaths.size()) {
  116. String error = "Attachments vectors must be the same size. Cannot copy attachments to tmp.";
  117. log.error(error);
  118. addError(Feedback.CONVERTER_ERROR, error, true);
  119. return;
  120. }
  121. for (int i = 0; i < filepaths.size(); i++) {
  122. String from = filepaths.get(i);
  123. String to = tmppaths.get(i);
  124. if (from == null || to == null) {
  125. log.error("Problem copying attachment file: '" + from + "' to '" + to + "'. Skipping.");
  126. continue;
  127. }
  128. try {
  129. copyFile(new File(from), new File(to));
  130. } catch (IOException e) {
  131. log.warn("Problem copying attachment file: '" + from + "' to '" + to + "'." +
  132. " Attempting to find alternate attachment file.");
  133. //try to find the right attachment using the unique file id from the attachments dir
  134. try {
  135. from = getAlternateFilepath(from);
  136. copyFile(new File(from), new File(to));
  137. log.info("Correctly copied alternate attachment file: " + from);
  138. continue;
  139. } catch (IOException e1) {
  140. log.error("Could not find attachment file. Skipping.");
  141. e1.printStackTrace();
  142. }
  143. e.printStackTrace();
  144. continue;
  145. }
  146. }
  147. }
  148. /**
  149. * copies file to newFile
  150. * Note: copied from Jspwiki converter's ImageConverter
  151. * @param file
  152. * @param newFile
  153. * @throws FileNotFoundException
  154. * @throws IOException
  155. */
  156. protected void copyFile(File file, File newFile) throws FileNotFoundException, IOException {
  157. log.debug("Copying '" + file.getAbsolutePath() + "' to '" + newFile.getAbsolutePath() + "'");
  158. if (!file.exists()) log.debug("File doesn't exist. Cannot copy: " + file.getAbsolutePath());
  159. // Create channel on the source
  160. FileChannel srcChannel = new FileInputStream(file.getAbsolutePath()).getChannel();
  161. // Create channel on the destination
  162. FileChannel dstChannel = new FileOutputStream(newFile.getAbsolutePath()).getChannel();
  163. // Copy file contents from source to destination
  164. int buffersize = -1;
  165. try {
  166. //see if the user specified a buffer size
  167. String buffersizeStr = getProperties().getProperty("buffer-size", null);
  168. if (buffersizeStr != null) {
  169. try {
  170. buffersize = Integer.parseInt(buffersizeStr);
  171. }
  172. catch (NumberFormatException en) {
  173. log.error("Property buffer-size is not an integer. Using filesize.");
  174. }
  175. }
  176. if (buffersize > 0) { //user set buffersize - see Michael Grove's code in UWC-349
  177. long size = srcChannel.size();
  178. long position = 0;
  179. while (position < size) {
  180. position += srcChannel.transferTo(position, buffersize, dstChannel);
  181. }
  182. }
  183. else { //if no user specified buffer size, use filesize
  184. dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
  185. }
  186. } catch (FileNotFoundException e) {
  187. throw e;
  188. } catch (IOException e2) {
  189. throw e2;
  190. } catch (RuntimeException e3) {
  191. throw e3;
  192. } finally {
  193. // Close the channels
  194. srcChannel.close();
  195. dstChannel.close();
  196. if (!newFile.exists()) log.error("Copying file unsuccessful. New file does not exist: " + newFile.getAbsolutePath());
  197. }
  198. }
  199. Pattern fileid = Pattern.compile("\\/(\\d+)[^\\/]+$");
  200. private String getAlternateFilepath(String path) throws IOException {
  201. Matcher idFinder = fileid.matcher(path);
  202. final String fileid = (idFinder.find())?idFinder.group(1):null;
  203. if (fileid == null) throw new IOException("Couldn't find fileId in: " + path);
  204. File dir = new File(this.getAttachmentDirectory());
  205. File[] files = dir.listFiles(new FileFilter() {
  206. public boolean accept(File candidate) {
  207. return candidate.getName().startsWith(fileid + "_");
  208. }
  209. });
  210. if (files == null || files.length < 1) throw new IOException("Couldn't find fileId in: " + path);
  211. if (files.length > 1) log.warn("Found multiple files with unique id! Using first one.");
  212. return files[0].getAbsolutePath();
  213. }
  214. protected void attach(Page page, Vector<String> filepaths) {
  215. for (String path : filepaths) {
  216. File file = new File(path);
  217. if (!file.exists()) log.warn("Could not find attachment at location: " + path);
  218. if (!file.isFile()) log.warn("Attachment is not a file: " + path);
  219. page.addAttachment(file);
  220. }
  221. }
  222. }