001/* 002 * (C) Copyright 2011 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 * Julien Carsique 016 * 017 */ 018 019package org.nuxeo.connect.update.task.standalone.commands; 020 021import java.io.BufferedReader; 022import java.io.File; 023import java.io.FileReader; 024import java.io.IOException; 025import java.util.Map; 026 027import org.nuxeo.common.utils.FileUtils; 028import org.nuxeo.connect.update.PackageException; 029import org.nuxeo.connect.update.ValidationStatus; 030import org.nuxeo.connect.update.task.Command; 031import org.nuxeo.connect.update.task.Task; 032import org.nuxeo.connect.update.task.standalone.UninstallTask; 033import org.nuxeo.connect.update.util.IOUtils; 034import org.nuxeo.connect.update.xml.XmlWriter; 035import org.w3c.dom.Element; 036 037/** 038 * Rollback command for {@link Append} and {@link Copy} (with {@link Copy#append}=true) commands. 039 * 040 * @since 5.5 041 */ 042public class UnAppend extends AbstractCommand { 043 044 public static final String ID = "unappend"; 045 046 private static final String newLine = System.getProperty("line.separator"); 047 048 private File contentToRemove; 049 050 private File fromFile; 051 052 public UnAppend() { 053 this(ID); 054 } 055 056 protected UnAppend(String id) { 057 super(id); 058 } 059 060 /** 061 * @param contentToRemove File which content must be removed. 062 * @param fromFile Destination file from which content is removed. 063 */ 064 public UnAppend(File contentToRemove, File fromFile) { 065 this(ID); 066 this.contentToRemove = contentToRemove; 067 this.fromFile = fromFile; 068 } 069 070 @Override 071 public void writeTo(XmlWriter writer) { 072 writer.start(ID); 073 if (contentToRemove != null) { 074 writer.attr("contentToRemove", contentToRemove.getAbsolutePath()); 075 } 076 if (fromFile != null) { 077 writer.attr("fromFile", fromFile.getAbsolutePath()); 078 } 079 writer.end(); 080 } 081 082 @Override 083 protected Command doRun(Task task, Map<String, String> prefs) throws PackageException { 084 BufferedReader brToRemove = null, brFromFile = null; 085 File bak; 086 StringBuilder linesToKeep = new StringBuilder(); 087 StringBuilder linesToRemove = new StringBuilder(); 088 try { 089 try { 090 brToRemove = new BufferedReader(new FileReader(contentToRemove)); 091 String lineToRemove = brToRemove.readLine(); 092 brFromFile = new BufferedReader(new FileReader(fromFile)); 093 String lineToCheck; 094 boolean found = false; 095 while ((lineToCheck = brFromFile.readLine()) != null) { 096 097 if (lineToCheck.equals(lineToRemove)) { 098 // Maybe the line to remove, but let's check the next 099 // lines 100 found = true; 101 linesToRemove.append(lineToCheck + newLine); 102 lineToRemove = brToRemove.readLine(); 103 } else { 104 if (lineToRemove != null && found) { 105 // Previously found lines must finally be kept 106 found = false; 107 linesToKeep.append(linesToRemove.toString()); 108 linesToRemove = new StringBuilder(); 109 org.apache.commons.io.IOUtils.closeQuietly(brToRemove); 110 brToRemove = new BufferedReader(new FileReader(contentToRemove)); 111 } 112 linesToKeep.append(lineToCheck + newLine); 113 } 114 } 115 if (lineToRemove != null) { 116 throw new PackageException("All lines to remove were not found."); 117 } 118 } finally { 119 org.apache.commons.io.IOUtils.closeQuietly(brToRemove); 120 org.apache.commons.io.IOUtils.closeQuietly(brFromFile); 121 } 122 if (task instanceof UninstallTask) { 123 bak = null; 124 } else { 125 bak = IOUtils.backup(task.getPackage(), contentToRemove); 126 } 127 FileUtils.writeFile(fromFile, linesToKeep.toString()); 128 return new Append(bak, fromFile); 129 } catch (PackageException e) { 130 throw e; 131 } catch (IOException e) { 132 throw new PackageException(e); 133 } 134 } 135 136 @Override 137 protected void doValidate(Task task, ValidationStatus status) throws PackageException { 138 if (contentToRemove == null || fromFile == null) { 139 status.addError("Cannot execute command in installer." 140 + " Invalid unappend syntax: contentToRemove or fromFile was not specified."); 141 } 142 } 143 144 @Override 145 public void readFrom(Element element) throws PackageException { 146 String v = element.getAttribute("contentToRemove"); 147 if (v.length() > 0) { 148 contentToRemove = new File(v); 149 } 150 v = element.getAttribute("fromFile"); 151 if (v.length() > 0) { 152 fromFile = new File(v); 153 } 154 } 155 156}