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