0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.updater;
0043:
0044: import java.io.BufferedInputStream;
0045: import java.io.File;
0046: import java.io.FileFilter;
0047: import java.io.FileInputStream;
0048: import java.io.InputStream;
0049: import java.io.FileOutputStream;
0050: import java.io.OutputStream;
0051: import java.io.IOException;
0052: import java.io.PrintWriter;
0053: import java.util.*;
0054: import java.util.zip.CRC32;
0055: import org.w3c.dom.*;
0056: import org.xml.sax.InputSource;
0057:
0058: /** This class represents module updates tracking
0059: *
0060: * @author Ales Kemr
0061: */
0062: public final class UpdateTracking {
0063:
0064: /** Platform dependent file name separator */
0065: public static final String FILE_SEPARATOR = System
0066: .getProperty("file.separator");
0067: public static final String PATH_SEPARATOR = System
0068: .getProperty("path.separator");
0069:
0070: public static final String ELEMENT_MODULES = "installed_modules"; // NOI18N
0071: public static final String ELEMENT_MODULE = "module"; // NOI18N
0072: public static final String ATTR_CODENAMEBASE = "codename"; // NOI18N
0073: public static final String ELEMENT_VERSION = "module_version"; // NOI18N
0074: public static final String ATTR_VERSION = "specification_version"; // NOI18N
0075: public static final String ATTR_LAST = "last"; // NOI18N
0076: public static final String ATTR_INSTALL = "install_time"; // NOI18N
0077: public static final String ELEMENT_FILE = "file"; // NOI18N
0078: public static final String ATTR_FILE_NAME = "name"; // NOI18N
0079: public static final String ATTR_ORIGIN = "origin"; // NOI18N
0080: public static final String UPDATER_ORIGIN = "updater"; // NOI18N
0081: public static final String INSTALLER_ORIGIN = "installer"; // NOI18N
0082:
0083: private static final String ATTR_CRC = "crc"; // NOI18N
0084: private static final String NBM_ORIGIN = "nbm"; // NOI18N
0085:
0086: public static final String ELEMENT_ADDITIONAL = "module_additional"; // NOI18N
0087: public static final String ELEMENT_ADDITIONAL_MODULE = "module"; // NOI18N
0088: public static final String ATTR_ADDITIONAL_NBM_NAME = "nbm_name"; // NOI18N
0089: public static final String ATTR_ADDITIONAL_SOURCE = "source-display-name"; // NOI18N
0090:
0091: public static final String EXTRA_CLUSTER_NAME = "extra";
0092:
0093: private static final String LOCALE_DIR = FILE_SEPARATOR + "locale"
0094: + FILE_SEPARATOR; // NOI18N
0095:
0096: public static final String TRACKING_FILE_NAME = "update_tracking"; // NOI18N
0097: public static final String ADDITIONAL_INFO_FILE_NAME = "additional_information.xml"; // NOI18N
0098: private static final String XML_EXT = ".xml"; // NOI18N
0099: private static final String FORBID_AUTOUPDATE = ".noautoupdate"; // NOI18N
0100:
0101: /** maps root of clusters to tracking files. (File -> UpdateTracking) */
0102: private static final Map<File, UpdateTracking> trackings = new HashMap<File, UpdateTracking>();
0103: private static final Map<File, UpdateTracking.AdditionalInfo> infos = new HashMap<File, UpdateTracking.AdditionalInfo>();
0104:
0105: /** Mapping from files defining modules to appropriate modules objects.
0106: */
0107: private LinkedHashMap<File, Module> installedModules = new LinkedHashMap<File, Module>();
0108:
0109: private boolean pError = false;
0110: private final File directory;
0111: private final File trackingFile;
0112: private String origin = NBM_ORIGIN;
0113:
0114: /** Private constructor.
0115: */
0116: private UpdateTracking(File nbPath) {
0117: assert nbPath != null : "Path cannot be null";
0118:
0119: trackingFile = new File(nbPath + FILE_SEPARATOR
0120: + TRACKING_FILE_NAME);
0121: directory = nbPath;
0122: origin = UPDATER_ORIGIN;
0123: }
0124:
0125: //
0126: // Various factory and utility methods
0127: //
0128:
0129: /** Finds update tracking for given cluster root.
0130: * @path root of a cluster
0131: * @param createIfDoesNotExists should new tracking be created if it does not exists
0132: * @return the tracking for that cluster
0133: */
0134: public static UpdateTracking getTracking(File path,
0135: boolean createIfDoesNotExists) {
0136: synchronized (trackings) {
0137: UpdateTracking track = trackings.get(path);
0138: if (track == null) {
0139: File utFile = new File(path, TRACKING_FILE_NAME);
0140: if (!createIfDoesNotExists && !utFile.isDirectory()) {
0141: // if the update_tracking directory is missing
0142: // do not allow creation at all (only in userdir)
0143: return null;
0144: }
0145: File noAU = new File(path, FORBID_AUTOUPDATE); // NOI18N
0146: if (noAU.exists()) {
0147: // ok, this prevents autoupdate from accessing this
0148: // directory completely
0149: return null;
0150: }
0151:
0152: track = new UpdateTracking(path);
0153: trackings.put(path, track);
0154: track.read();
0155: track.scanDir();
0156: }
0157: return track;
0158: }
0159: }
0160:
0161: /** Finds update tracking for given cluster root.
0162: * @path root of a cluster
0163: * @return the additional information for that cluster
0164: */
0165: public static UpdateTracking.AdditionalInfo getAdditionalInformation(
0166: File path) {
0167: synchronized (infos) {
0168: UpdateTracking.AdditionalInfo additionalInfo = infos
0169: .get(path);
0170: if (additionalInfo == null) {
0171: getTracking(path, false);
0172: File downloadDir = new File(path,
0173: ModuleUpdater.DOWNLOAD_DIR);
0174: if (downloadDir.exists() && downloadDir.isDirectory()) {
0175: File addInfo = new File(downloadDir,
0176: ADDITIONAL_INFO_FILE_NAME);
0177: if (addInfo.exists()) {
0178: additionalInfo = new UpdateTracking.AdditionalInfo(
0179: addInfo);
0180: }
0181: }
0182: }
0183: return additionalInfo;
0184: }
0185: }
0186:
0187: /** Returns the platform installatiion directory.
0188: * @return the File directory.
0189: */
0190: public static File getPlatformDir() {
0191: String platform = System.getProperty("netbeans.home");
0192: return platform == null ? null : new File(platform); // NOI18N
0193: }
0194:
0195: public static File getUserDir() {
0196: // bugfix #50242: the property "netbeans.user" can return dir with non-normalized file e.g. duplicate //
0197: // and path and value of this property wrongly differs
0198: String user = System.getProperty("netbeans.user");
0199: File userDir = null;
0200: if (user != null) {
0201: userDir = new File(user);
0202: userDir = new File(userDir.toURI().normalize())
0203: .getAbsoluteFile();
0204: }
0205:
0206: return userDir;
0207: }
0208:
0209: /** Returns enumeration of Files that represent each possible install
0210: * directory.
0211: * @param includeUserDir whether to include also user dir
0212: * @return List<File>
0213: */
0214: public static List<File> clusters(boolean includeUserDir) {
0215: List<File> files = new ArrayList<File>();
0216:
0217: if (includeUserDir) {
0218: File ud = getUserDir();
0219: if (ud != null) {
0220: // this prevents autoupdate from accessing this
0221: // directory completely
0222: File noAU = new File(ud, FORBID_AUTOUPDATE); // NOI18N
0223: if (!noAU.exists()) {
0224: files.add(ud);
0225: }
0226: }
0227: }
0228:
0229: String dirs = System.getProperty("netbeans.dirs"); // NOI18N
0230: if (dirs != null) {
0231: Enumeration en = new StringTokenizer(dirs,
0232: File.pathSeparator);
0233: while (en.hasMoreElements()) {
0234: File f = new File((String) en.nextElement());
0235: // this prevents autoupdate from accessing this
0236: // directory completely
0237: File noAU = new File(f, FORBID_AUTOUPDATE); // NOI18N
0238: if (!noAU.exists()) {
0239: files.add(f);
0240: }
0241: }
0242: }
0243:
0244: File id = getPlatformDir();
0245: if (id != null) {
0246: // this prevents autoupdate from accessing this
0247: // directory completely
0248: File noAU = new File(id, FORBID_AUTOUPDATE); // NOI18N
0249: if (!noAU.exists()) {
0250: files.add(id);
0251: }
0252: }
0253:
0254: return java.util.Collections.unmodifiableList(files);
0255: }
0256:
0257: //
0258: // Useful search methods
0259: //
0260:
0261: /** Returns true if module with given code base is installed here
0262: * @param codeBase name of the module
0263: * @return true or false
0264: */
0265: public boolean isModuleInstalled(String codeBase) {
0266: for (Module m : installedModules.values()) {
0267: String mm = m.codenamebase;
0268: int indx = mm.indexOf('/');
0269: if (indx >= 0) {
0270: mm = mm.substring(0, indx);
0271: }
0272: if (codeBase.equals(mm)) {
0273: return true;
0274: }
0275: }
0276: return false;
0277: }
0278:
0279: //
0280: // Private impls
0281: //
0282:
0283: /** Scan through org.w3c.dom.Document document. */
0284: private void read() {
0285: /** org.w3c.dom.Document document */
0286: org.w3c.dom.Document document;
0287:
0288: File file;
0289: InputStream is;
0290: try {
0291: file = trackingFile;
0292:
0293: if (!file.isFile())
0294: return;
0295:
0296: is = new FileInputStream(file);
0297:
0298: InputSource xmlInputSource = new InputSource(is);
0299: document = XMLUtil.parse(xmlInputSource, false, false,
0300: new ErrorCatcher(), XMLUtil.createAUResolver());
0301: if (is != null)
0302: is.close();
0303: } catch (org.xml.sax.SAXException e) {
0304: System.out.println("Bad update_tracking"); // NOI18N
0305: e.printStackTrace();
0306: return;
0307: } catch (java.io.IOException e) {
0308: System.out.println("Missing update_tracking"); // NOI18N
0309: e.printStackTrace();
0310: return;
0311: }
0312:
0313: org.w3c.dom.Element element = document.getDocumentElement();
0314: if ((element != null)
0315: && element.getTagName().equals(ELEMENT_MODULES)) {
0316: scanElement_installed_modules(element);
0317: }
0318: }
0319:
0320: /** Scan through org.w3c.dom.Element named installed_modules. */
0321: void scanElement_installed_modules(org.w3c.dom.Element element) { // <installed_modules>
0322: // element.getValue();
0323: org.w3c.dom.NodeList nodes = element.getChildNodes();
0324: for (int i = 0; i < nodes.getLength(); i++) {
0325: org.w3c.dom.Node node = nodes.item(i);
0326: if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
0327: org.w3c.dom.Element nodeElement = (org.w3c.dom.Element) node;
0328: if (nodeElement.getTagName().equals(ELEMENT_MODULE)) {
0329: if (true)
0330: throw new IllegalStateException("What now!?");
0331: // XXX - should put the module into installedModules but do not know the key
0332: // modules.add( scanElement_module(nodeElement, fromuser) );
0333: }
0334: }
0335: }
0336: }
0337:
0338: /** Scan through org.w3c.dom.Element named module. */
0339: Module scanElement_module(org.w3c.dom.Element element) { // <module>
0340: Module module = new Module();
0341: org.w3c.dom.NamedNodeMap attrs = element.getAttributes();
0342: for (int i = 0; i < attrs.getLength(); i++) {
0343: org.w3c.dom.Attr attr = (org.w3c.dom.Attr) attrs.item(i);
0344: if (attr.getName().startsWith(ATTR_CODENAMEBASE)) {
0345: // <module codename="???"> or old version <module codenamebase="???">
0346: module.setCodenamebase(attr.getValue());
0347: }
0348: }
0349: org.w3c.dom.NodeList nodes = element.getChildNodes();
0350: for (int i = 0; i < nodes.getLength(); i++) {
0351: org.w3c.dom.Node node = nodes.item(i);
0352: if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
0353: org.w3c.dom.Element nodeElement = (org.w3c.dom.Element) node;
0354: if (nodeElement.getTagName().equals(ELEMENT_VERSION)) {
0355: scanElement_module_version(nodeElement, module);
0356: }
0357: }
0358: }
0359: return module;
0360: }
0361:
0362: /** Scan through org.w3c.dom.Element named module_version. */
0363: private void scanElement_module_version(
0364: org.w3c.dom.Element element, Module module) { // <module_version>
0365: Version version = new Version();
0366: org.w3c.dom.NamedNodeMap attrs = element.getAttributes();
0367: for (int i = 0; i < attrs.getLength(); i++) {
0368: org.w3c.dom.Attr attr = (org.w3c.dom.Attr) attrs.item(i);
0369: if (attr.getName().equals(ATTR_VERSION)) { // <module_version specification_version="???">
0370: version.setVersion(attr.getValue());
0371: }
0372: if (attr.getName().equals(ATTR_ORIGIN)) { // <module_version origin="???">
0373: version.setOrigin(attr.getValue());
0374: }
0375: if (attr.getName().equals(ATTR_LAST)) { // <module_version last="???">
0376: version.setLast(Boolean.valueOf(attr.getValue())
0377: .booleanValue());
0378: }
0379: if (attr.getName().equals(ATTR_INSTALL)) { // <module_version install_time="???">
0380: long li = 0;
0381: try {
0382: li = Long.parseLong(attr.getValue());
0383: } catch (NumberFormatException nfe) {
0384: }
0385: version.setInstall_time(li);
0386: }
0387: }
0388: org.w3c.dom.NodeList nodes = element.getChildNodes();
0389: for (int i = 0; i < nodes.getLength(); i++) {
0390: org.w3c.dom.Node node = nodes.item(i);
0391: if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
0392: org.w3c.dom.Element nodeElement = (org.w3c.dom.Element) node;
0393: if (nodeElement.getTagName().equals(ELEMENT_FILE)) {
0394: scanElement_file(nodeElement, version);
0395: }
0396: }
0397: }
0398: module.addOldVersion(version);
0399: }
0400:
0401: /** Scan through org.w3c.dom.Element named file. */
0402: void scanElement_file(org.w3c.dom.Element element, Version version) { // <file>
0403: ModuleFile file = new ModuleFile();
0404: org.w3c.dom.NamedNodeMap attrs = element.getAttributes();
0405: for (int i = 0; i < attrs.getLength(); i++) {
0406: org.w3c.dom.Attr attr = (org.w3c.dom.Attr) attrs.item(i);
0407: if (attr.getName().equals(ATTR_FILE_NAME)) { // <file name="???">
0408: file.setName(attr.getValue());
0409: }
0410: if (attr.getName().equals(ATTR_CRC)) { // <file crc="???">
0411: file.setCrc(attr.getValue());
0412: }
0413: if (attr.getName().equals(ATTR_VERSION)) {
0414: file.setLocaleversion(attr.getValue());
0415: }
0416: }
0417: version.addFile(file);
0418: }
0419:
0420: Module readModuleTracking(String codename, boolean create) {
0421: new File(directory, TRACKING_FILE_NAME).mkdirs();
0422: File file = new File(new File(directory, TRACKING_FILE_NAME),
0423: getTrackingName(codename) + XML_EXT);
0424:
0425: // fix for #34355
0426: try {
0427: if (file.exists() && file.length() == 0)
0428: file.delete();
0429: } catch (Exception e) {
0430: // ignore
0431: }
0432:
0433: if (!file.exists()) {
0434: if (create)
0435: return new Module(codename, file);
0436: else
0437: return null;
0438: }
0439:
0440: return readModuleFromFile(file, codename, create);
0441: }
0442:
0443: Version createVersion(String specversion) {
0444: Version ver = new Version();
0445: ver.setVersion(specversion);
0446: return ver;
0447: }
0448:
0449: private Module readModuleFromFile(File file, String codename,
0450: boolean create) {
0451:
0452: /** org.w3c.dom.Document document */
0453: org.w3c.dom.Document document;
0454: InputStream is;
0455: try {
0456: is = new FileInputStream(file);
0457:
0458: InputSource xmlInputSource = new InputSource(is);
0459: document = XMLUtil.parse(xmlInputSource, false, false,
0460: new ErrorCatcher(), XMLUtil.createAUResolver());
0461: if (is != null)
0462: is.close();
0463: } catch (org.xml.sax.SAXException e) {
0464: System.out.println("Bad update_tracking"); // NOI18N
0465: e.printStackTrace();
0466: return null;
0467: } catch (java.io.IOException e) {
0468: if (create)
0469: return new Module(codename, file);
0470: else
0471: return null;
0472: }
0473:
0474: org.w3c.dom.Element element = document.getDocumentElement();
0475: if ((element != null)
0476: && element.getTagName().equals(ELEMENT_MODULE)) {
0477:
0478: Module m = scanElement_module(element);
0479: m.setFile(file);
0480: installedModules.put(file, m);
0481: return m;
0482: }
0483: if (create)
0484: return new Module(codename, file);
0485: else
0486: return null;
0487: }
0488:
0489: private static String getTrackingName(String codename) {
0490: String trackingName = codename;
0491: int pos = trackingName.indexOf('/'); // NOI18N
0492: if (pos > -1)
0493: trackingName = trackingName.substring(0, pos);
0494: return trackingName.replace('.', '-'); // NOI18N
0495: }
0496:
0497: void deleteUnusedFiles() {
0498: List<Module> newModules = new ArrayList<Module>(
0499: installedModules.values());
0500: for (Module mod : newModules) {
0501: mod.deleteUnusedFiles();
0502: }
0503: scanDir();
0504: }
0505:
0506: public static long getFileCRC(File file) throws IOException {
0507: BufferedInputStream bsrc = null;
0508: CRC32 crc = new CRC32();
0509: try {
0510: bsrc = new BufferedInputStream(new FileInputStream(file));
0511: byte[] bytes = new byte[1024];
0512: int i;
0513: while ((i = bsrc.read()) != -1) {
0514: crc.update((byte) i);
0515: }
0516: } finally {
0517: if (bsrc != null)
0518: bsrc.close();
0519: }
0520: return crc.getValue();
0521: }
0522:
0523: private void scanDir() {
0524: File dir = new File(directory, TRACKING_FILE_NAME);
0525: File[] files = dir.listFiles(new FileFilter() {
0526: public boolean accept(File file) {
0527: if (!file.isDirectory()
0528: && file.getName().toUpperCase()
0529: .endsWith(".XML")) // NOI18N
0530: return true;
0531: else
0532: return false;
0533: }
0534: });
0535:
0536: if (files == null) {
0537: return;
0538: }
0539:
0540: for (int i = 0; i < files.length; i++) {
0541: if (!installedModules.containsKey(files[i])) {
0542: readModuleFromFile(files[i], null, true);
0543: }
0544:
0545: }
0546: }
0547:
0548: class Module extends Object {
0549:
0550: /** Holds value of property codenamebase. */
0551: private String codenamebase;
0552:
0553: /** Holds value of property versions. */
0554: private List<Version> versions = new ArrayList<Version>();
0555:
0556: private File file = null;
0557:
0558: public Module() {
0559: }
0560:
0561: public Module(String codenamebase, File file) {
0562: this .codenamebase = codenamebase;
0563: this .file = file;
0564: }
0565:
0566: private Version lastVersion = null;
0567: private Version newVersion = null;
0568:
0569: /** Getter for property codenamebase.
0570: * @return Value of property codenamebase.
0571: */
0572: String getCodenamebase() {
0573: return codenamebase;
0574: }
0575:
0576: /** Setter for property codenamebase.
0577: * @param codenamebase New value of property codenamebase.
0578: */
0579: void setCodenamebase(String codenamebase) {
0580: this .codenamebase = codenamebase;
0581: }
0582:
0583: /** Getter for property versions.
0584: * @return Value of property versions.
0585: */
0586: List<Version> getVersions() {
0587: return versions;
0588: }
0589:
0590: /** Setter for property versions.
0591: * @param versions New value of property versions.
0592: */
0593: void setVersions(List<Version> versions) {
0594: this .versions = versions;
0595: }
0596:
0597: private Version getNewOrLastVersion() {
0598: if (newVersion != null)
0599: return newVersion;
0600: else
0601: return lastVersion;
0602: }
0603:
0604: boolean hasNewVersion() {
0605: return newVersion != null;
0606: }
0607:
0608: void setFile(File file) {
0609: this .file = file;
0610: }
0611:
0612: public Version addNewVersion(String spec_version, String origin) {
0613: if (lastVersion != null)
0614: lastVersion.setLast(false);
0615: Version version = new Version();
0616: newVersion = version;
0617: version.setVersion(spec_version);
0618: version.setOrigin(origin);
0619: version.setLast(true);
0620: version.setInstall_time(System.currentTimeMillis());
0621: versions.add(version);
0622: return version;
0623: }
0624:
0625: void addOldVersion(Version version) {
0626: if (version.isLast())
0627: lastVersion = version;
0628:
0629: versions.add(version);
0630: }
0631:
0632: void addL10NVersion(Version l_version) {
0633: if (lastVersion != null)
0634: lastVersion.addL10NFiles(l_version.getFiles());
0635: else {
0636: l_version.setOrigin(origin);
0637: l_version.setLast(true);
0638: l_version.setInstall_time(System.currentTimeMillis());
0639: versions.add(l_version);
0640: }
0641: }
0642:
0643: void writeConfigModuleXMLIfMissing() {
0644: File configDir = new File(new File(directory,
0645: ModuleDeactivator.CONFIG),
0646: ModuleDeactivator.MODULES); // NOI18N
0647:
0648: String candidate = null;
0649: String oldCandidate = null;
0650: String newCandidate = null;
0651:
0652: String name = codenamebase;
0653: int indx = name.indexOf('/');
0654: if (indx > 0) {
0655: name = name.substring(0, indx);
0656: }
0657:
0658: // check module name from config file
0659: String replaced = name.replace('.', '-'); // NOI18N
0660: String searchFor;
0661:
0662: if (replaced.indexOf(ModuleDeactivator.MODULES) > 0) { // NOI18N
0663: // standard module
0664: searchFor = replaced + ".jar"; // NOI18N
0665: } else {
0666: // core module
0667: searchFor = replaced.substring(replaced
0668: .lastIndexOf('-') > 0 ? replaced
0669: .lastIndexOf('-') + 1 : 0)
0670: + ".jar"; // NOI18N
0671: }
0672:
0673: String dash = name.replace('.', '-');
0674:
0675: File config = new File(configDir, dash + ".xml"); // NOI18N
0676: if (config.isFile()) {
0677: // already written
0678: return;
0679: }
0680:
0681: config.getParentFile().mkdirs();
0682:
0683: Boolean isAutoload = null;
0684: Boolean isEager = null;
0685:
0686: java.util.Iterator it = newVersion.getFiles().iterator();
0687: boolean needToWrite = false;
0688:
0689: while (it.hasNext()) {
0690: ModuleFile f = (ModuleFile) it.next();
0691:
0692: String n = f.getName();
0693: String parentDir = new File(f.getName())
0694: .getParentFile().getName();
0695:
0696: needToWrite = needToWrite
0697: || n.indexOf(ModuleDeactivator.MODULES) >= 0;
0698:
0699: if (n.endsWith(".jar")) { // NOI18N
0700: // ok, module candidate
0701: candidate = f.getName();
0702:
0703: // the correct candidate looks as e.g. org.netbeans.modules.mymodule
0704: // if no jar looks as codenamebase then the jar file will be found as module's jar
0705: if (searchFor.endsWith(candidate)
0706: || candidate.endsWith(searchFor)) {
0707: newCandidate = candidate;
0708: oldCandidate = null;
0709:
0710: // autoload and eager will set by module's jar
0711: if ("autoload".equals(parentDir)) { // NOI18N
0712: isAutoload = Boolean.TRUE;
0713: } else {
0714: isAutoload = Boolean.FALSE;
0715: }
0716: if ("eager".equals(parentDir)) { // NOI18N
0717: isEager = Boolean.TRUE;
0718: } else {
0719: isEager = Boolean.FALSE;
0720: }
0721: } else {
0722: if (newCandidate == null) {
0723: oldCandidate = (oldCandidate == null ? ""
0724: : oldCandidate + ", ")
0725: + candidate; // NOI18N
0726: }
0727: }
0728: }
0729:
0730: // if no correct name found => set autoload/eager by the last jar file
0731: if (isAutoload == null && "autoload".equals(parentDir)) { // NOI18N
0732: isAutoload = Boolean.TRUE;
0733: }
0734: if (isEager == null && "eager".equals(parentDir)) { // NOI18N
0735: isEager = Boolean.TRUE;
0736: }
0737: }
0738:
0739: if (!needToWrite) {
0740: System.out
0741: .println("Warning: No config file written for module "
0742: + codenamebase
0743: + ". No jar file present in \"modules\" directory.");
0744: return;
0745: }
0746:
0747: assert newCandidate != null || oldCandidate != null : "No jar file present!";
0748: if (newCandidate == null) {
0749: // PENDING: should check but some NBM assumed wrong behaviour before bugfix 53316
0750: assert oldCandidate.equals(candidate) : "More files look as module: "
0751: + oldCandidate;
0752: // only temporary
0753: if (!oldCandidate.equals(candidate)) {
0754: System.out
0755: .println("NBM Error: More files look as module: "
0756: + oldCandidate);
0757: oldCandidate = candidate;
0758: }
0759: // end of temp
0760: }
0761:
0762: String moduleName = newCandidate == null ? oldCandidate
0763: : newCandidate;
0764:
0765: boolean autoload = isAutoload != null
0766: && isAutoload.booleanValue();
0767: boolean eager = isEager != null && isEager.booleanValue();
0768: boolean isEnabled = !autoload && !eager;
0769:
0770: String spec = newVersion.getVersion();
0771: OutputStream os;
0772: try {
0773: os = new FileOutputStream(config);
0774: PrintWriter pw = new PrintWriter(
0775: new java.io.OutputStreamWriter(os, "UTF-8"));
0776: // Please make sure formatting matches what the IDE actually spits
0777: // out; it could matter.
0778: pw
0779: .println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
0780: pw
0781: .println("<!DOCTYPE module PUBLIC \"-//NetBeans//DTD Module Status 1.0//EN\"");
0782: pw
0783: .println(" \"http://www.netbeans.org/dtds/module-status-1_0.dtd\">");
0784: pw.println("<module name=\"" + name + "\">");
0785: pw.println(" <param name=\"autoload\">" + autoload
0786: + "</param>");
0787: pw.println(" <param name=\"eager\">" + eager
0788: + "</param>");
0789: if (isEnabled) {
0790: pw.println(" <param name=\"enabled\">"
0791: + isEnabled + "</param>");
0792: }
0793: pw.println(" <param name=\"jar\">" + moduleName
0794: + "</param>");
0795: pw
0796: .println(" <param name=\"reloadable\">false</param>");
0797: pw.println(" <param name=\"specversion\">" + spec
0798: + "</param>");
0799: pw.println("</module>");
0800: pw.flush();
0801: pw.close();
0802: } catch (IOException ex) {
0803: ex.printStackTrace();
0804: }
0805:
0806: }
0807:
0808: void write() {
0809: Document document = XMLUtil.createDocument(ELEMENT_MODULE);
0810:
0811: Element e_module = document.getDocumentElement();
0812: Element e_version = null;
0813: Element e_file = null;
0814:
0815: e_module.setAttribute(ATTR_CODENAMEBASE, getCodenamebase());
0816: Iterator it2 = getVersions().iterator();
0817: while (it2.hasNext()) {
0818: Version ver = (Version) it2.next();
0819: e_version = document.createElement(ELEMENT_VERSION);
0820: if (ver.getVersion() != null)
0821: e_version.setAttribute(ATTR_VERSION, ver
0822: .getVersion());
0823: e_version.setAttribute(ATTR_ORIGIN, ver.getOrigin());
0824: e_version.setAttribute(ATTR_LAST, Boolean.valueOf(
0825: ver.isLast()).toString());
0826: e_version.setAttribute(ATTR_INSTALL, Long.toString(ver
0827: .getInstall_time()));
0828: e_module.appendChild(e_version);
0829: Iterator it3 = ver.getFiles().iterator();
0830: while (it3.hasNext()) {
0831: ModuleFile moduleFile = (ModuleFile) it3.next();
0832: e_file = document.createElement(ELEMENT_FILE);
0833: e_file.setAttribute(ATTR_FILE_NAME, moduleFile
0834: .getName());
0835: e_file.setAttribute(ATTR_CRC, moduleFile.getCrc());
0836: if (moduleFile.getLocaleversion() != null)
0837: e_file.setAttribute(ATTR_VERSION, moduleFile
0838: .getLocaleversion());
0839: e_version.appendChild(e_file);
0840: }
0841: }
0842:
0843: document.getDocumentElement().normalize();
0844:
0845: try {
0846: OutputStream os = new FileOutputStream(file);
0847: XMLUtil.write(document, os);
0848: os.close();
0849: } catch (Exception e) {
0850: e.printStackTrace();
0851: }
0852: }
0853:
0854: void deleteUnusedFiles() {
0855: if (lastVersion == null || newVersion == null)
0856: return;
0857: Iterator it = lastVersion.getFiles().iterator();
0858: while (it.hasNext()) {
0859: ModuleFile modFile = (ModuleFile) it.next();
0860: if (!newVersion.containsFile(modFile)
0861: && modFile.getName().indexOf(LOCALE_DIR) == -1)
0862: safeDelete(modFile);
0863: }
0864: }
0865:
0866: private void safeDelete(ModuleFile modFile) {
0867: // test file existence
0868: File f = new File(file.getParentFile().getParent()
0869: + FILE_SEPARATOR + modFile.getName());
0870: if (f.exists()) {
0871: // test crc
0872: try {
0873: if (!Long.toString(getFileCRC(f)).equals(
0874: modFile.getCrc()))
0875: return;
0876: } catch (IOException ioe) {
0877: return;
0878: }
0879:
0880: // test if file is referenced from other module
0881: scanDir();
0882: boolean found = false;
0883: Iterator<Module> it = installedModules.values()
0884: .iterator();
0885: while (!found && it.hasNext()) {
0886: Module mod = it.next();
0887: if (!mod.equals(this )) {
0888: Version v = mod.getNewOrLastVersion();
0889: if (v != null && v.containsFile(modFile))
0890: found = true;
0891: }
0892: }
0893: if (!found)
0894: f.delete();
0895: }
0896: }
0897:
0898: String getL10NSpecificationVersion(String jarpath) {
0899: String localever = null;
0900: Collections.<Version> sort(versions);
0901: for (Version ver : versions) {
0902: localever = ver.getLocaleVersion(jarpath);
0903: if (localever != null)
0904: return localever;
0905: }
0906: return null;
0907: }
0908: }
0909:
0910: public class Version extends Object implements Comparable<Version> {
0911:
0912: /** Holds value of property version. */
0913: private String version;
0914:
0915: /** Holds value of property origin. */
0916: private String origin;
0917:
0918: /** Holds value of property last. */
0919: private boolean last;
0920:
0921: /** Holds value of property install_time. */
0922: private long install_time = 0;
0923:
0924: /** Holds value of property files. */
0925: private List<ModuleFile> files = new ArrayList<ModuleFile>();
0926:
0927: /** Getter for property version.
0928: * @return Value of property version.
0929: */
0930: String getVersion() {
0931: return version;
0932: }
0933:
0934: /** Setter for property version.
0935: * @param version New value of property version.
0936: */
0937: void setVersion(String version) {
0938: this .version = version;
0939: }
0940:
0941: /** Getter for property origin.
0942: * @return Value of property origin.
0943: */
0944: String getOrigin() {
0945: return origin;
0946: }
0947:
0948: /** Setter for property origin.
0949: * @param origin New value of property origin.
0950: */
0951: void setOrigin(String origin) {
0952: this .origin = origin;
0953: }
0954:
0955: /** Getter for property last.
0956: * @return Value of property last.
0957: */
0958: boolean isLast() {
0959: return last;
0960: }
0961:
0962: /** Setter for property last.
0963: * @param last New value of property last.
0964: */
0965: void setLast(boolean last) {
0966: this .last = last;
0967: }
0968:
0969: /** Getter for property install_time.
0970: * @return Value of property install_time.
0971: */
0972: long getInstall_time() {
0973: return install_time;
0974: }
0975:
0976: /** Setter for property install_time.
0977: * @param install_time New value of property install_time.
0978: */
0979: void setInstall_time(long install_time) {
0980: this .install_time = install_time;
0981: }
0982:
0983: /** Getter for property files.
0984: * @return Value of property files.
0985: */
0986: List<ModuleFile> getFiles() {
0987: return files;
0988: }
0989:
0990: /** Setter for property files.
0991: * @param files New value of property files.
0992: */
0993: void addL10NFiles(List<ModuleFile> l10nfiles) {
0994: Iterator it = l10nfiles.iterator();
0995: while (it.hasNext()) {
0996: ModuleFile lf = (ModuleFile) it.next();
0997: String lname = lf.getName();
0998: for (int i = files.size() - 1; i >= 0; i--) {
0999: ModuleFile f = files.get(i);
1000: if (f.getName().equals(lname))
1001: files.remove(i);
1002: }
1003: }
1004: files.addAll(l10nfiles);
1005: }
1006:
1007: void addFile(ModuleFile file) {
1008: files.add(file);
1009: }
1010:
1011: public void addFileWithCrc(String filename, String crc) {
1012: ModuleFile file = new ModuleFile();
1013: file.setName(filename);
1014: file.setCrc(crc);
1015: files.add(file);
1016: }
1017:
1018: public void addL10NFileWithCrc(String filename, String crc,
1019: String specver) {
1020: ModuleFile file = new ModuleFile();
1021: file.setName(filename);
1022: file.setCrc(crc);
1023: file.setLocaleversion(specver);
1024: files.add(file);
1025: }
1026:
1027: boolean containsFile(ModuleFile file) {
1028: Iterator it = files.iterator();
1029: while (it.hasNext()) {
1030: ModuleFile f = (ModuleFile) it.next();
1031: if (f.getName().equals(file.getName()))
1032: return true;
1033: }
1034: return false;
1035: }
1036:
1037: ModuleFile findFile(String filename) {
1038: Iterator it = files.iterator();
1039: while (it.hasNext()) {
1040: ModuleFile f = (ModuleFile) it.next();
1041: if (f.getName().equals(filename))
1042: return f;
1043: }
1044: return null;
1045: }
1046:
1047: String getLocaleVersion(String filename) {
1048: String locver = null;
1049: ModuleFile f = findFile(filename);
1050: if (f != null) {
1051: locver = f.getLocaleversion();
1052: if (locver == null)
1053: locver = version;
1054: }
1055: return locver;
1056: }
1057:
1058: public int compareTo(Version oth) {
1059: if (install_time < oth.getInstall_time())
1060: return 1;
1061: else if (install_time > oth.getInstall_time())
1062: return -1;
1063: else
1064: return 0;
1065: }
1066: }
1067:
1068: class ModuleFile extends Object {
1069:
1070: /** Holds value of property name. */
1071: private String name;
1072:
1073: /** Holds value of property crc. */
1074: private String crc;
1075:
1076: /** Holds value of property localeversion. */
1077: private String localeversion = null;
1078:
1079: /** Getter for property name.
1080: * @return Value of property name.
1081: */
1082: String getName() {
1083: return name;
1084: }
1085:
1086: /** Setter for property name.
1087: * @param name New value of property name.
1088: */
1089: void setName(String name) {
1090: this .name = name;
1091: }
1092:
1093: /** Getter for property crc.
1094: * @return Value of property crc.
1095: */
1096: String getCrc() {
1097: return crc;
1098: }
1099:
1100: /** Setter for property crc.
1101: * @param crc New value of property crc.
1102: */
1103: void setCrc(String crc) {
1104: this .crc = crc;
1105: }
1106:
1107: /** Getter for property localeversion.
1108: * @return Value of property localeversion.
1109: *
1110: */
1111: public String getLocaleversion() {
1112: return this .localeversion;
1113: }
1114:
1115: /** Setter for property localeversion.
1116: * @param localeversion New value of property localeversion.
1117: *
1118: */
1119: public void setLocaleversion(String localeversion) {
1120: this .localeversion = localeversion;
1121: }
1122:
1123: }
1124:
1125: class ErrorCatcher implements org.xml.sax.ErrorHandler {
1126: private void message(String level,
1127: org.xml.sax.SAXParseException e) {
1128: pError = true;
1129: }
1130:
1131: public void error(org.xml.sax.SAXParseException e) {
1132: // normally a validity error
1133: pError = true;
1134: }
1135:
1136: public void warning(org.xml.sax.SAXParseException e) {
1137: //parseFailed = true;
1138: }
1139:
1140: public void fatalError(org.xml.sax.SAXParseException e) {
1141: pError = true;
1142: }
1143: }
1144:
1145: public static class AdditionalInfo extends Object {
1146: private Map<String, String> sources;
1147:
1148: private AdditionalInfo(File additionalInfoFile) {
1149: sources = readAdditionalInfoFile(additionalInfoFile);
1150: }
1151:
1152: public String getSource(String nbmFileName) {
1153: return sources != null ? sources.get(nbmFileName) : null;
1154: }
1155:
1156: private Map<String, String> readAdditionalInfoFile(File f) {
1157: if (f == null || !f.exists()) {
1158: throw new IllegalArgumentException(
1159: "AdditionalInfo file " + f + " must exists.");
1160: }
1161:
1162: Map<String, String> res = null;
1163:
1164: /** org.w3c.dom.Document document */
1165: org.w3c.dom.Document document;
1166:
1167: InputStream is = null;
1168: try {
1169: is = new FileInputStream(f);
1170: document = XMLUtil.parse(new InputSource(is), false,
1171: false, null, null);
1172: } catch (org.xml.sax.SAXException e) {
1173: System.out.println("Bad "
1174: + UpdateTracking.ADDITIONAL_INFO_FILE_NAME
1175: + " " + f); // NOI18N
1176: e.printStackTrace();
1177: return res;
1178: } catch (java.io.IOException e) {
1179: System.out.println("Missing "
1180: + UpdateTracking.ADDITIONAL_INFO_FILE_NAME
1181: + " " + f); // NOI18N
1182: e.printStackTrace();
1183: return res;
1184: } finally {
1185: if (is != null) {
1186: try {
1187: is.close();
1188: } catch (IOException ioe) {
1189: System.out
1190: .println("Cannot close stream for file "
1191: + f); // NOI18N
1192: ioe.printStackTrace();
1193: return res;
1194: }
1195: }
1196: }
1197:
1198: org.w3c.dom.Element element = document.getDocumentElement();
1199: if ((element != null)
1200: && element.getTagName().equals(ELEMENT_ADDITIONAL)) {
1201: res = scanModuleAdditional(element);
1202: }
1203:
1204: return res;
1205: }
1206:
1207: private Map<String, String> scanModuleAdditional(
1208: org.w3c.dom.Element element) {
1209: Map<String, String> res = new HashMap<String, String>();
1210: org.w3c.dom.NodeList nodes = element.getChildNodes();
1211: for (int i = 0; i < nodes.getLength(); i++) {
1212: org.w3c.dom.Node node = nodes.item(i);
1213: if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
1214: org.w3c.dom.Element nodeElement = (org.w3c.dom.Element) node;
1215: if (nodeElement.getTagName().equals(
1216: ELEMENT_ADDITIONAL_MODULE)) {
1217: String fileSpec = nodeElement
1218: .getAttribute(ATTR_ADDITIONAL_NBM_NAME);
1219: String source = nodeElement
1220: .getAttribute(ATTR_ADDITIONAL_SOURCE);
1221: res.put(fileSpec, source);
1222: }
1223: }
1224: }
1225: return res;
1226: }
1227: }
1228:
1229: }
|