001/* 002 * (C) Copyright 2006-2009 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo 016 */ 017 018package org.nuxeo.ecm.platform.publisher.impl.localfs; 019 020import java.io.BufferedReader; 021import java.io.BufferedWriter; 022import java.io.File; 023import java.io.FileReader; 024import java.io.FileWriter; 025import java.io.IOException; 026import java.util.ArrayList; 027import java.util.List; 028import java.util.Map; 029 030import org.apache.commons.io.FileUtils; 031import org.nuxeo.ecm.core.api.CoreSession; 032import org.nuxeo.ecm.core.api.DocumentLocation; 033import org.nuxeo.ecm.core.api.DocumentModel; 034import org.nuxeo.ecm.core.api.NuxeoException; 035import org.nuxeo.ecm.platform.publisher.api.AbstractBasePublicationTree; 036import org.nuxeo.ecm.platform.publisher.api.PublicationNode; 037import org.nuxeo.ecm.platform.publisher.api.PublicationTree; 038import org.nuxeo.ecm.platform.publisher.api.PublishedDocument; 039import org.nuxeo.ecm.platform.publisher.api.PublishedDocumentFactory; 040 041public class LocalFSPublicationTree extends AbstractBasePublicationTree implements PublicationTree { 042 private static final long serialVersionUID = 1L; 043 044 public static final String INDEX_FILENAME = "fspublication.index"; 045 046 public static final String INDEX_FILENAME_TMP = INDEX_FILENAME + ".tmp"; 047 048 @Override 049 public void initTree(String sid, CoreSession coreSession, Map<String, String> parameters, 050 PublishedDocumentFactory factory, String configName, String title) { 051 super.initTree(sid, coreSession, parameters, factory, configName, title); 052 try { 053 rootNode = new FSPublicationNode(rootPath, getTreeConfigName(), sid); 054 } catch (IllegalArgumentException e) { 055 throw new NuxeoException(e); 056 } 057 } 058 059 @Override 060 protected PublishedDocumentFactory getDefaultFactory() { 061 return new FSPublishedDocumentFactory(); 062 } 063 064 @Override 065 protected String getDefaultRootPath() { 066 return "/"; 067 } 068 069 protected void findDocs(List<PublishedDocument> pubDocs, File container, DocumentLocation docLoc) { 070 for (File child : container.listFiles()) { 071 if (child.isDirectory()) { 072 findDocs(pubDocs, child, docLoc); 073 } else { 074 try { 075 PublishedDocument pubDoc = new FSPublishedDocument(child); 076 if (pubDoc.getSourceRepositoryName().equals(docLoc.getServerName()) 077 && pubDoc.getSourceDocumentRef().equals(docLoc.getDocRef())) { 078 pubDocs.add(pubDoc); 079 } 080 } catch (NotFSPublishedDocumentException e) { 081 // NOP 082 } 083 } 084 } 085 } 086 087 public List<PublishedDocument> getExistingPublishedDocument(DocumentLocation docLoc) { 088 List<PublishedDocument> pubDocs = null; 089 pubDocs = loadExistingPublishedDocumentFromIndex(docLoc); 090 if (pubDocs == null) { 091 pubDocs = new ArrayList<PublishedDocument>(); 092 File root = new File(getPath()); 093 findDocs(pubDocs, root, docLoc); 094 095 // create the index 096 createIndex(pubDocs); 097 } 098 return pubDocs; 099 } 100 101 private List<PublishedDocument> loadExistingPublishedDocumentFromIndex(DocumentLocation docLoc) 102 { 103 File indexFile = new File(rootPath, INDEX_FILENAME); 104 if (!indexFile.exists() || !indexFile.isFile()) { 105 return null; 106 } 107 108 List<PublishedDocument> pubDocs = new ArrayList<PublishedDocument>(); 109 BufferedReader reader = null; 110 try { 111 reader = new BufferedReader(new FileReader(indexFile)); 112 String filePath; 113 while ((filePath = reader.readLine()) != null) { 114 File file = new File(filePath); 115 if (file.exists()) { 116 PublishedDocument pubDoc = new FSPublishedDocument(file); 117 if (pubDoc.getSourceRepositoryName().equals(docLoc.getServerName()) 118 && pubDoc.getSourceDocumentRef().equals(docLoc.getDocRef())) { 119 pubDocs.add(pubDoc); 120 } 121 } 122 } 123 } catch (IOException e) { 124 throw new NuxeoException(e); 125 } finally { 126 if (reader != null) { 127 try { 128 reader.close(); 129 } catch (IOException e) { 130 } 131 } 132 } 133 134 return pubDocs; 135 } 136 137 private void createIndex(List<PublishedDocument> pubDocs) { 138 File indexFile = new File(rootPath, INDEX_FILENAME); 139 BufferedWriter writer = null; 140 try { 141 writer = new BufferedWriter(new FileWriter(indexFile)); 142 for (PublishedDocument pubDoc : pubDocs) { 143 writer.write(pubDoc.getPath()); 144 writer.newLine(); 145 } 146 } catch (IOException e) { 147 throw new NuxeoException(e); 148 } finally { 149 if (writer != null) { 150 try { 151 writer.flush(); 152 writer.close(); 153 } catch (IOException e) { 154 } 155 } 156 } 157 } 158 159 private void addToIndex(PublishedDocument pubDoc) { 160 File fileIndex = new File(rootPath, INDEX_FILENAME); 161 File fileIndexTmp = new File(rootPath, INDEX_FILENAME_TMP); 162 163 BufferedReader reader = null; 164 BufferedWriter writer = null; 165 try { 166 if (!fileIndex.exists()) { 167 fileIndex.createNewFile(); 168 } 169 170 reader = new BufferedReader(new FileReader(fileIndex)); 171 writer = new BufferedWriter(new FileWriter(fileIndexTmp)); 172 String pathToAdd = pubDoc.getPath(); 173 String line; 174 boolean pathAlreadyFound = false; 175 while ((line = reader.readLine()) != null) { 176 if (line.equals(pathToAdd)) { 177 pathAlreadyFound = true; 178 } 179 writer.write(line); 180 writer.newLine(); 181 } 182 if (!pathAlreadyFound) { 183 writer.write(pathToAdd); 184 writer.newLine(); 185 } 186 } catch (IOException e) { 187 throw new NuxeoException(e); 188 } finally { 189 if (reader != null) { 190 try { 191 reader.close(); 192 } catch (IOException e) { 193 } 194 } 195 196 if (writer != null) { 197 try { 198 writer.flush(); 199 writer.close(); 200 } catch (IOException e) { 201 } 202 } 203 } 204 205 // move the tmp index file to the index file after closing both stream 206 if (fileIndex.delete()) { 207 moveFile(fileIndexTmp, fileIndex); 208 } 209 } 210 211 private void moveFile(File srcFile, File destFile) { 212 try { 213 FileUtils.moveFile(srcFile, destFile); 214 } catch (IOException e) { 215 throw new NuxeoException(e); 216 } 217 } 218 219 private void removeFromIndex(PublishedDocument pubDoc) { 220 File fileIndex = new File(rootPath, INDEX_FILENAME); 221 File fileIndexTmp = new File(rootPath, INDEX_FILENAME_TMP); 222 223 BufferedReader reader = null; 224 BufferedWriter writer = null; 225 try { 226 reader = new BufferedReader(new FileReader(fileIndex)); 227 writer = new BufferedWriter(new FileWriter(fileIndexTmp)); 228 String pathToRemove = pubDoc.getPath(); 229 String line; 230 while ((line = reader.readLine()) != null) { 231 if (!pathToRemove.equals(line)) { 232 writer.write(line); 233 writer.newLine(); 234 } 235 } 236 } catch (IOException e) { 237 throw new NuxeoException(e); 238 } finally { 239 if (reader != null) { 240 try { 241 reader.close(); 242 } catch (IOException e) { 243 } 244 } 245 246 if (writer != null) { 247 try { 248 writer.flush(); 249 writer.close(); 250 } catch (IOException e) { 251 } 252 } 253 } 254 255 // move the tmp index file to the index file after closing both stream 256 if (fileIndex.delete()) { 257 moveFile(fileIndexTmp, fileIndex); 258 } 259 } 260 261 public PublicationNode getNodeByPath(String path) { 262 return new FSPublicationNode(path, getTreeConfigName(), getSessionId()); 263 } 264 265 @Override 266 public PublishedDocument publish(DocumentModel doc, PublicationNode targetNode) { 267 PublishedDocument pubDoc = super.publish(doc, targetNode); 268 addToIndex(pubDoc); 269 return pubDoc; 270 } 271 272 @Override 273 public PublishedDocument publish(DocumentModel doc, PublicationNode targetNode, Map<String, String> params) 274 { 275 PublishedDocument pubDoc = super.publish(doc, targetNode, params); 276 addToIndex(pubDoc); 277 return pubDoc; 278 } 279 280 public void unpublish(DocumentModel doc, PublicationNode targetNode) { 281 File container = new File(targetNode.getPath()); 282 for (File child : container.listFiles()) { 283 try { 284 unpublish(doc, child); 285 } catch (NotFSPublishedDocumentException e) { 286 // NOP 287 } 288 } 289 } 290 291 private void unpublish(DocumentModel doc, File file) throws NotFSPublishedDocumentException { 292 FSPublishedDocument pubDoc = new FSPublishedDocument(file); 293 if (pubDoc.getSourceRepositoryName().equals(doc.getRepositoryName()) 294 && pubDoc.getSourceDocumentRef().equals(doc.getRef())) { 295 new File(pubDoc.getPersistPath()).delete(); 296 removeFromIndex(pubDoc); 297 } 298 } 299 300 public void unpublish(PublishedDocument pubDoc) { 301 if (!accept(pubDoc)) { 302 return; 303 } 304 FSPublishedDocument fsPublishedDocument = (FSPublishedDocument) pubDoc; 305 new File(fsPublishedDocument.getPersistPath()).delete(); 306 removeFromIndex(pubDoc); 307 } 308 309 public void release() { 310 } 311 312 protected boolean accept(PublishedDocument publishedDocument) { 313 return publishedDocument instanceof FSPublishedDocument; 314 } 315 316}