001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.updater;
043:
044: import java.io.*;
045: import java.util.*;
046: import javax.swing.SwingUtilities;
047:
048: /**
049: * @author Jiri Rechtacek
050: */
051: public final class ModuleDeactivator extends Object {
052:
053: public static final String TO_UNINSTALL = "to_uninstall.txt"; // NOI18N
054: public static final String TO_DISABLE = "to_disable.txt"; // NOI18N
055:
056: public static final String CONFIG = "config"; // NOI18N
057: public static final String MODULES = "Modules"; // NOI18N
058:
059: private ModuleDeactivator() {
060: }
061:
062: public static void delete() {
063: assert !SwingUtilities.isEventDispatchThread() : "Cannot run in EQ";
064: UpdaterFrame.setLabel(Localization
065: .getBrandedString("CTL_DeletingFiles"));
066: Collection<File> allFiles = new HashSet<File>();
067: for (File cluster : UpdateTracking.clusters(true)) {
068: boolean modified = allFiles
069: .addAll(readFilesMarkedForDeleteInCluster(cluster));
070: modified = modified
071: || allFiles
072: .add(getControlFileForMarkedForDelete(cluster));
073: modified = modified
074: || allFiles.add(getDeactivateLater(cluster));
075: if (modified) {
076: UpdaterDispatcher.touchLastModified(cluster);
077: }
078: }
079: UpdaterFrame.setProgressRange(0, allFiles.size());
080: int i = 0;
081: for (File f : allFiles) {
082: doDelete(f);
083: UpdaterFrame.setProgressValue(i++);
084: }
085: }
086:
087: public static void disable() {
088: assert !SwingUtilities.isEventDispatchThread() : "Cannot run in EQ";
089: UpdaterFrame.setLabel(Localization
090: .getBrandedString("CTL_DisablingFiles"));
091: Collection<File> allControlFiles = new HashSet<File>();
092: for (File cluster : UpdateTracking.clusters(true)) {
093: allControlFiles
094: .addAll(readFilesMarkedForDisableInCluster(cluster));
095: doDelete(getControlFileForMarkedForDisable(cluster));
096: doDelete(getDeactivateLater(cluster));
097: }
098: UpdaterFrame.setProgressRange(0, allControlFiles.size());
099: int i = 0;
100: for (File f : allControlFiles) {
101: doDisable(f);
102: UpdaterFrame.setProgressValue(i++);
103: }
104: }
105:
106: public static boolean hasModulesForDelete(File updateDir) {
107: File deactivateDir = new File(updateDir,
108: UpdaterDispatcher.DEACTIVATE_DIR);
109: return deactivateDir.exists()
110: && deactivateDir.isDirectory()
111: && Arrays.asList(deactivateDir.list()).contains(
112: TO_UNINSTALL);
113: }
114:
115: public static boolean hasModulesForDisable(File updateDir) {
116: File deactivateDir = new File(updateDir,
117: UpdaterDispatcher.DEACTIVATE_DIR);
118: return deactivateDir.exists()
119: && deactivateDir.isDirectory()
120: && Arrays.asList(deactivateDir.list()).contains(
121: TO_DISABLE);
122: }
123:
124: public static File getDeactivateLater(File cluster) {
125: File file = new File(cluster, UpdaterDispatcher.UPDATE_DIR
126: + // update
127: UpdateTracking.FILE_SEPARATOR
128: + UpdaterDispatcher.DEACTIVATE_DIR
129: + // update/deactivate
130: UpdateTracking.FILE_SEPARATOR
131: + UpdaterDispatcher.DEACTIVATE_LATER); // deactivate_later.xml
132: return file;
133: }
134:
135: public static File getControlFileForMarkedForDelete(File cluster) {
136: File file = new File(cluster, UpdaterDispatcher.UPDATE_DIR
137: + // update
138: UpdateTracking.FILE_SEPARATOR
139: + UpdaterDispatcher.DEACTIVATE_DIR
140: + // update/deactivate
141: UpdateTracking.FILE_SEPARATOR
142: + ModuleDeactivator.TO_UNINSTALL); // to_uninstall.txt
143: return file;
144: }
145:
146: public static File getControlFileForMarkedForDisable(File cluster) {
147: File file = new File(cluster, UpdaterDispatcher.UPDATE_DIR
148: + // update
149: UpdateTracking.FILE_SEPARATOR
150: + UpdaterDispatcher.DEACTIVATE_DIR
151: + // update/deactivate
152: UpdateTracking.FILE_SEPARATOR
153: + ModuleDeactivator.TO_DISABLE); // to_disable.txt
154: return file;
155: }
156:
157: // utils
158: public static void writeStringToFile(String content, File file) {
159: BufferedWriter writer = null;
160: try {
161: try {
162: writer = new BufferedWriter(new FileWriter(file));
163: writer.write(content);
164: } finally {
165: if (writer != null)
166: writer.close();
167: }
168: } catch (FileNotFoundException fnfe) {
169: System.out.println("Error: Writing " + file + " throws "
170: + fnfe);
171: } catch (IOException ioe) {
172: System.out.println("Error: Writing " + file + " throws "
173: + ioe);
174: }
175: }
176:
177: public static String readStringFromFile(File file) {
178: StringBuffer fileData = null;
179: BufferedReader reader = null;
180: try {
181: try {
182: fileData = new StringBuffer();
183: reader = new BufferedReader(new FileReader(file));
184: char[] buf = new char[1024];
185: int numRead = 0;
186: while ((numRead = reader.read(buf)) != -1) {
187: String readData = String.valueOf(buf, 0, numRead);
188: fileData.append(readData);
189: buf = new char[1024];
190: }
191: } finally {
192: if (reader != null)
193: reader.close();
194: }
195: } catch (FileNotFoundException fnfe) {
196: System.out.println("Error: Reading " + file + " throws "
197: + fnfe);
198: } catch (IOException ioe) {
199: System.out.println("Error: Reading " + file + " throws "
200: + ioe);
201: }
202:
203: return fileData == null ? "" : fileData.toString();
204: }
205:
206: // private methods
207: // delete file and empty dirs too
208: private static void doDelete(File f) {
209: assert f != null : "Invalid file " + f + " for delete.";
210: if (f.exists() && !f.delete()) {
211: assert false : f + " cannot be deleted";
212: f.deleteOnExit();
213: }
214: f = f.getParentFile();
215: while (f != null && f.delete()) {
216: f = f.getParentFile(); // remove empty dirs too
217: }
218: }
219:
220: private static Set<File> readFilesMarkedForDeleteInCluster(
221: File cluster) {
222:
223: File mark4deleteFile = getControlFileForMarkedForDelete(cluster);
224: if (!mark4deleteFile.exists()) {
225: return Collections.emptySet();
226: }
227:
228: Set<File> toDelete = new HashSet<File>();
229:
230: String content = readStringFromFile(mark4deleteFile);
231: StringTokenizer tokenizer = new StringTokenizer(content,
232: UpdateTracking.PATH_SEPARATOR);
233: while (tokenizer.hasMoreElements()) {
234: String filePath = tokenizer.nextToken();
235: File f = new File(filePath);
236: if (f.exists()) {
237: toDelete.add(f);
238: }
239: }
240:
241: return toDelete;
242: }
243:
244: private static Set<File> readFilesMarkedForDisableInCluster(
245: File cluster) {
246:
247: File mark4disableFile = getControlFileForMarkedForDisable(cluster);
248: if (!mark4disableFile.exists()) {
249: return Collections.emptySet();
250: }
251:
252: Set<File> toDisable = new HashSet<File>();
253:
254: String content = readStringFromFile(mark4disableFile);
255: StringTokenizer tokenizer = new StringTokenizer(content,
256: UpdateTracking.PATH_SEPARATOR);
257: while (tokenizer.hasMoreElements()) {
258: String filePath = tokenizer.nextToken();
259: File f = new File(filePath);
260: if (f.exists()) {
261: toDisable.add(f);
262: }
263: }
264:
265: return toDisable;
266: }
267:
268: private static String ENABLE_TAG = "<param name=\"enabled\">true</param>";
269: private static String DISABLE_TAG = "<param name=\"enabled\">false</param>";
270:
271: private static void doDisable(File f) {
272: String content = readStringFromFile(f);
273: int pos = content.indexOf(ENABLE_TAG);
274: assert pos != -1 : ENABLE_TAG + " must be contained in "
275: + content;
276: int shift = ENABLE_TAG.length();
277: String pre = content.substring(0, pos);
278: String post = content.substring(pos + shift);
279: String res = pre + DISABLE_TAG + post;
280: File configDir = new File(new File(UpdateTracking.getUserDir(),
281: CONFIG), MODULES);
282: configDir.mkdirs();
283: File dest = new File(configDir, f.getName());
284: writeStringToFile(res, dest);
285: }
286:
287: }
|