All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.autoupdate.services.Utilities Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.modules.autoupdate.services;

import java.io.*;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.security.CodeSigner;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.PKIXParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.PKIXRevocationChecker.Option;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import java.util.regex.Pattern;
import org.netbeans.Module;
import org.netbeans.ModuleManager;
import org.netbeans.api.autoupdate.UpdateElement;
import org.netbeans.api.autoupdate.UpdateManager;
import org.netbeans.api.autoupdate.UpdateUnit;
import org.netbeans.core.startup.AutomaticDependencies;
import org.netbeans.core.startup.Main;
import org.netbeans.core.startup.TopLogging;
import org.netbeans.modules.autoupdate.updateprovider.DummyModuleInfo;
import org.netbeans.modules.autoupdate.updateprovider.InstalledModuleProvider;
import org.netbeans.modules.autoupdate.updateprovider.UpdateItemImpl;
import org.netbeans.spi.autoupdate.KeyStoreProvider;
import org.netbeans.spi.autoupdate.KeyStoreProvider.TrustLevel;
import org.netbeans.spi.autoupdate.UpdateItem;
import org.netbeans.updater.ModuleDeactivator;
import org.netbeans.updater.ModuleUpdater;
import org.netbeans.updater.UpdateTracking;
import org.netbeans.updater.UpdaterDispatcher;
import org.openide.filesystems.FileUtil;
import org.openide.modules.*;
import org.openide.util.*;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author Jiri Rechtacek, Radek Matous
 */
public class Utilities {
    public static final String N_A = "N/A";
    public static final String UNSIGNED = "UNSIGNED";
    public static final String SIGNATURE_UNVERIFIED = "SIGNATURE_UNVERIFIED";
    public static final String SIGNATURE_VERIFIED = "SIGNATURE_VERIFIED";
    public static final String TRUSTED = "TRUSTED";
    public static final String MODIFIED = "MODIFIED";

    private Utilities() {}

    public static final String UPDATE_DIR = "update"; // NOI18N
    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
    public static final String DOWNLOAD_DIR = UPDATE_DIR + FILE_SEPARATOR + "download"; // NOI18N
    public static final String RUNNING_DOWNLOAD_DIR = UPDATE_DIR + FILE_SEPARATOR + "download-in-progress"; // NOI18N
    public static final String NBM_EXTENTSION = ".nbm";
    public static final String JAR_EXTENSION = ".jar"; //OSGi bundle
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat ("yyyy/MM/dd"); // NOI18N
    public static final String ATTR_ESSENTIAL = "AutoUpdate-Essential-Module";

    private static final String PLUGIN_MANAGER_FIRST_CLASS_MODULES = "plugin.manager.first.class.modules"; // NOI18N

    private static final String USER_KS_KEY = "userKS";
    private static final String USER_KS_FILE_NAME = "user.ks";
    private static final String KS_USER_PASSWORD = "open4user";
    private static Lookup.Result keyStoreLookupResult;
    private static Map> keystoreCache = Collections.synchronizedMap(new HashMap<>());
    private static final Logger err = Logger.getLogger(Utilities.class.getName ());

    public static Collection getKeyStore (TrustLevel trustLevel) {
        if (keyStoreLookupResult == null) {
            keyStoreLookupResult = Lookup.getDefault().lookupResult(KeyStoreProvider.class);
            keyStoreLookupResult.addLookupListener(new KeyStoreProviderListener());
        }

        List result = keystoreCache.get(trustLevel);

        if (result == null) {
            Collection c = keyStoreLookupResult.allInstances();
            if (c == null || c.isEmpty()) {
                return Collections.emptyList();
            }
            List kss = new ArrayList<>();

            for (KeyStoreProvider provider : c) {
                if (provider.getTrustLevel() == trustLevel) {
                    KeyStore ks = provider.getKeyStore();
                    if (ks != null) {
                        kss.add(ks);
                    }
                }
            }

            result = Collections.unmodifiableList(kss);

            keystoreCache.put(trustLevel, result);
        }

        return result;
    }

    /**
     *
     * @param archiveCertPath
     * @param trustedCertificates
     * @return
     */
    public static String verifyCertificates(CodeSigner archiveCertPath,
        Collection trustedCertificates,
        Set trustedCACertificates,
        Collection validateCertificates,
        Set validationCACertificates) {
        assert archiveCertPath != null;

        List archiveCertificates = archiveCertPath.getSignerCertPath().getCertificates();

        if(archiveCertificates.isEmpty()) {
            return UNSIGNED;
        }

        // Case 1: We have direct trust into one of the certificates of the
        //         certificate chain
        if(isChainTrusted(archiveCertificates, trustedCertificates)) {
            return TRUSTED;
        }

        // Case 2: We trust the CA, that issued a certificate - do the
        //         normal CertPathValidation
        if(verifyCACertificatePath(trustedCACertificates, archiveCertPath)) {
            return TRUSTED;
        }

        // Case 3: We have a list of certificates, that we directly mark as
        //         valid
        if(isChainTrusted(archiveCertificates, validateCertificates)) {
            return SIGNATURE_VERIFIED;
        }

        // Case 4: We trust the CA to do validation
        if (verifyCACertificatePath(validationCACertificates, archiveCertPath)) {
            return SIGNATURE_VERIFIED;
        }

        // Case 5: File is not signed
        return SIGNATURE_UNVERIFIED;
    }

    private static boolean verifyCACertificatePath(Set trustedCACertificates, CodeSigner archiveCertPath) {
        if(trustedCACertificates.isEmpty()) {
            return false;
        }
        try {
            CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
            PKIXParameters verificationParameters = new PKIXParameters(trustedCACertificates);
            PKIXRevocationChecker rc = (PKIXRevocationChecker) cpv.getRevocationChecker();
            rc.setOptions(EnumSet.of(Option.SOFT_FAIL));
            verificationParameters.addCertPathChecker(rc);
            if (archiveCertPath.getTimestamp() != null) {
                cpv.validate(archiveCertPath.getSignerCertPath(), verificationParameters);
                verificationParameters.setDate(archiveCertPath.getTimestamp().getTimestamp());
            }
            // validate raises a CertPathValidatorException if validation failed
            cpv.validate(archiveCertPath.getSignerCertPath(), verificationParameters);
            return true;
        } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException ex) {
            // InvalidAlgorithmParameterException - Should not get here - trustAnchor cannot be null -> collection cannot be empty
            // NoSuchAlgorithmException - Should not get here - "PKIX" is proper algorythm
            err.log(Level.SEVERE, "Certificate verification failed - " + ex.getMessage(), ex);
            //SIGNATURE_UNVERIFIED - result = 0;
        } catch (CertPathValidatorException ex) {
            // CertPath cannot be validated
            err.log(Level.INFO, "Cannot validate certificate path - " + ex.getMessage(), ex);
            //SIGNATURE_UNVERIFIED - result = 0;
        }
        return false;
    }

    private static boolean isChainTrusted(Collection archiveCertificates, Collection trustedCertificates) {
        Collection c = new HashSet<>(trustedCertificates);
        c.retainAll(archiveCertificates);
        return ! c.isEmpty();
    }

    /**
     * Establishes an order for verificication result strings. Only the values
     * 
    *
  • {@code null}
  • *
  • {@link #UNSIGNED}
  • *
  • {@link #SIGNATURE_UNVERIFIED}
  • *
  • {@link #SIGNATURE_VERIFIED}
  • *
  • {@link #TRUSTED}
  • *
*/ public static final Comparator VERIFICATION_RESULT_COMPARATOR = new Comparator() { @Override public int compare(String o1, String o2) { int i1 = mapVerificationResultToInt(o1); int i2 = mapVerificationResultToInt(o2); return i1 - i2; } }; private static int mapVerificationResultToInt(String input) { if(input == null) { return 0; } switch(input) { case UNSIGNED: return 1; case SIGNATURE_UNVERIFIED: return 2; case SIGNATURE_VERIFIED: return 3; case TRUSTED: return 4; default: throw new IllegalArgumentException("Unmappable value: " + input); } } public static Collection getCertificates (KeyStore keyStore) throws KeyStoreException { Set certs = new HashSet<> (); for (String alias: Collections.list (keyStore.aliases ())) { Certificate[] certificateChain = keyStore.getCertificateChain(alias); if (certificateChain != null) { certs.addAll(Arrays.asList(certificateChain)); } certs.add(keyStore.getCertificate(alias)); } return certs; } public static Collection getTrustAnchor (KeyStore keyStore) throws KeyStoreException { Set certs = new HashSet<> (); for (String alias: Collections.list (keyStore.aliases ())) { Certificate[] certificateChain = keyStore.getCertificateChain(alias); if (certificateChain != null) { for(Certificate cert: certificateChain) { if(cert instanceof X509Certificate) { certs.add(new TrustAnchor((X509Certificate) cert, null)); } } } Certificate aliasCert = keyStore.getCertificate(alias); if(aliasCert instanceof X509Certificate) { certs.add(new TrustAnchor((X509Certificate) aliasCert, null)); } } return certs; } /** * Get entries packed with pack200 in given NBM file. * * @param nbmFile the file to scan * @return names of entries * @throws IOException in case of I/O error */ static List getNbmPack200Entries(File nbmFile) throws IOException { List pack200Entries = new ArrayList<>(); try (JarFile jf = new JarFile(nbmFile)) { for (JarEntry entry : Collections.list(jf.entries())) { if (entry.getName().endsWith(".pack.gz")) { pack200Entries.add(entry.getName()); } } } return pack200Entries; } /** * Get the certpaths that were used to sign the NBM content. * * @param nbmFile file of nbm * @return collection of CodeSigners, that were used to sign the non-signature * entries of the NBM * @throws IOException * @throws SecurityException if JAR was tampered with or if the certificate * chains are not consistent */ public static Collection getNbmCertificates (File nbmFile) throws IOException, SecurityException { Set certs = null; // Empty means only the MANIFEST.MF is present - special cased to be in // line with established behaviour boolean empty = true; // The idea: // - iterate over all JAR entries // - read each entry (as required by the JarFile specificiation for verification) // - extract the certificate paths, that were used to sign the // entry // - compare it with the previously read entries. If they are not // identical, raise a SecurityException. // // Excluded from the above algorithm are: // - directory entries // - files that are part of the signature (each entry in META-INF, that // ends with .SF, .DSA, .RSA or .EC try (JarFile jf = new JarFile(nbmFile)) { for (JarEntry entry : Collections.list(jf.entries())) { verifyEntry(jf, entry); if ((! entry.isDirectory()) && (! isSignatureEntry(entry))) { if(! entry.getName().equals("META-INF/MANIFEST.MF")) { empty = false; } Set entryCerts = new HashSet<>(); CodeSigner[] codeSigners = entry.getCodeSigners(); if (codeSigners != null) { for (CodeSigner cs : entry.getCodeSigners()) { entryCerts.add(cs); } } if(certs == null) { certs = entryCerts; } else if (! certs.equals(entryCerts)) { throw new SecurityException("Inconsistent certificate paths used for signing"); } } } } return empty ? null : certs; } private static final Pattern SIGNATURE_PATTERN = Pattern.compile("META-INF/([^/]+)\\.(SF|DSA|RSA|EC)"); private static boolean isSignatureEntry(JarEntry je) { return SIGNATURE_PATTERN.matcher(je.getName()).matches(); } /** * @throws SecurityException */ @SuppressWarnings("empty-statement") private static void verifyEntry (JarFile jf, JarEntry je) throws IOException, SecurityException { InputStream is = null; try { is = jf.getInputStream (je); byte[] buffer = new byte[8192]; while ((is.read (buffer, 0, buffer.length)) != -1); } finally { if (is != null) is.close (); } } private static class KeyStoreProviderListener implements LookupListener { private KeyStoreProviderListener () { } @Override public void resultChanged (LookupEvent ev) { keystoreCache.clear(); } } private static final String ATTR_NAME = "name"; // NOI18N private static final String ATTR_SPEC_VERSION = "specification_version"; // NOI18N private static final String ATTR_SIZE = "size"; // NOI18N private static final String ATTR_NBM_NAME = "nbm_name"; // NOI18N private static File getInstallLater(File root) { File file = new File(root.getPath() + FILE_SEPARATOR + DOWNLOAD_DIR + FILE_SEPARATOR + ModuleUpdater.LATER_FILE_NAME); return file; } public static void deleteAllDoLater() { List clusters = UpdateTracking.clusters(true); assert clusters != null : "Clusters cannot be empty."; // NOI18N for (File cluster : clusters) { for (File doLater : findDoLater (cluster)) { doLater.delete (); } } } private static Collection findDoLater (File cluster) { if (! cluster.exists ()) { return Collections.emptySet (); } else { Collection res = new HashSet (); if (getInstallLater (cluster).exists ()) { res.add (getInstallLater (cluster)); } if (ModuleDeactivator.getDeactivateLater (cluster).exists ()) { res.add (ModuleDeactivator.getDeactivateLater (cluster)); } return res; } } public static void writeInstallLater (Map updates) { // loop for all clusters and write if needed List clusters = UpdateTracking.clusters(true); assert clusters != null : "Clusters cannot be empty."; // NOI18N for (File cluster : clusters) { writeInstallLaterToCluster (cluster, updates); } } private static void writeInstallLaterToCluster (File cluster, Map updates) { Document document = XMLUtil.createDocument(UpdateTracking.ELEMENT_MODULES, null, null, null); Element root = document.getDocumentElement(); if (updates.isEmpty ()) { return ; } boolean isEmpty = true; for (Map.Entry entry : updates.entrySet ()) { UpdateElementImpl elementImpl = entry.getKey(); File c = entry.getValue(); // pass this module to given cluster ? if (cluster.equals (c)) { Element module = document.createElement(UpdateTracking.ELEMENT_MODULE); module.setAttribute(UpdateTracking.ATTR_CODENAMEBASE, elementImpl.getCodeName()); module.setAttribute(ATTR_NAME, elementImpl.getDisplayName()); module.setAttribute(ATTR_SPEC_VERSION, elementImpl.getSpecificationVersion().toString()); module.setAttribute(ATTR_SIZE, Long.toString(elementImpl.getDownloadSize())); module.setAttribute(ATTR_NBM_NAME, InstallSupportImpl.getDestination(cluster, elementImpl.getCodeName(), elementImpl.getInstallInfo().getDistribution()).getName()); root.appendChild( module ); isEmpty = false; } } if (isEmpty) { return ; } writeXMLDocumentToFile (document, getInstallLater (cluster)); } private static void writeXMLDocumentToFile (Document doc, File dest) { doc.getDocumentElement ().normalize (); dest.getParentFile ().mkdirs (); InputStream is = null; ByteArrayOutputStream bos = new ByteArrayOutputStream (); OutputStream fos = null; try { try { XMLUtil.write (doc, bos, "UTF-8"); // NOI18N bos.close (); fos = new FileOutputStream (dest); is = new ByteArrayInputStream (bos.toByteArray ()); FileUtil.copy (is, fos); } finally { if (is != null) { is.close (); } if (fos != null) { fos.close (); } bos.close (); } } catch (java.io.FileNotFoundException fnfe) { Exceptions.printStackTrace (fnfe); } catch (java.io.IOException ioe) { Exceptions.printStackTrace (ioe); } finally { try { bos.close (); } catch (IOException x) { Exceptions.printStackTrace (x); } } } public static void writeDeactivateLater (Collection files) { File userdir = InstallManager.getUserDir (); assert userdir != null && userdir.exists (): "Userdir " + userdir + " found and exists."; // NOI18N writeMarkedFilesToFile (files, ModuleDeactivator.getDeactivateLater (userdir)); } public static void writeFileMarkedForDelete (Collection files) { writeMarkedFilesToFile (files, ModuleDeactivator.getControlFileForMarkedForDelete (InstallManager.getUserDir ())); } public static void writeFileMarkedForDisable (Collection files) { writeMarkedFilesToFile (files, ModuleDeactivator.getControlFileForMarkedForEnableDisable(InstallManager.getUserDir (), false)); } public static void writeFileMarkedForEnable (Collection files) { writeMarkedFilesToFile (files, ModuleDeactivator.getControlFileForMarkedForEnableDisable(InstallManager.getUserDir (), true)); } private static void writeMarkedFilesToFile (Collection files, File dest) { // don't forget for content written before StringBuilder content = new StringBuilder(); if (dest.exists ()) { content.append(ModuleDeactivator.readStringFromFile (dest)); } for (File f : files) { content.append(f.getAbsolutePath ()); content.append(UpdateTracking.PATH_SEPARATOR); } if (content.length () == 0) { return ; } dest.getParentFile ().mkdirs (); assert dest.getParentFile ().exists () && dest.getParentFile ().isDirectory () : "Parent of " + dest + " exists and is directory."; InputStream is = null; OutputStream fos = null; try { try { fos = new FileOutputStream (dest); is = new ByteArrayInputStream (content.toString().getBytes()); FileUtil.copy (is, fos); } finally { if (is != null) is.close(); if (fos != null) fos.close(); } } catch (java.io.FileNotFoundException fnfe) { Exceptions.printStackTrace(fnfe); } catch (java.io.IOException ioe) { Exceptions.printStackTrace(ioe); } } public static void writeAdditionalInformation (Map updates) { // loop for all clusters and write if needed List clusters = UpdateTracking.clusters (true); assert clusters != null : "Clusters cannot be empty."; // NOI18N for (File cluster : clusters) { writeAdditionalInformationToCluster (cluster, updates); } } public static File locateUpdateTracking (ModuleInfo m) { String fileNameToFind = UpdateTracking.TRACKING_FILE_NAME + '/' + m.getCodeNameBase ().replace ('.', '-') + ".xml"; // NOI18N return InstalledFileLocator.getDefault ().locate (fileNameToFind, m.getCodeNameBase (), false); } public static String readSourceFromUpdateTracking (ModuleInfo m) { String res = null; File ut = locateUpdateTracking (m); if (ut != null) { Node n = getModuleConfiguration (ut); if (n != null) { Node attrOrigin = n.getAttributes ().getNamedItem (UpdateTracking.ATTR_ORIGIN); assert attrOrigin != null : "ELEMENT_VERSION must contain ATTR_ORIGIN attribute."; if (! (UpdateTracking.UPDATER_ORIGIN.equals (attrOrigin.getNodeValue ()) || UpdateTracking.INSTALLER_ORIGIN.equals (attrOrigin.getNodeValue ()))) { // ignore default value res = attrOrigin.getNodeValue (); } } } return res; } public static Date readInstallTimeFromUpdateTracking (ModuleInfo m) { Date res = null; String time = null; File ut = locateUpdateTracking (m); if (ut != null) { Node n = getModuleConfiguration (ut); if (n != null) { Node attrInstallTime = n.getAttributes ().getNamedItem (UpdateTracking.ATTR_INSTALL); assert attrInstallTime != null : "ELEMENT_VERSION must contain ATTR_INSTALL attribute."; time = attrInstallTime.getNodeValue (); } } if (time != null) { try { long lTime = Long.parseLong (time); res = new Date (lTime); } catch (NumberFormatException nfe) { getLogger ().log (Level.INFO, nfe.getMessage (), nfe); } } return res; } static void writeUpdateOfUpdaterJar (JarEntry updaterJarEntry, File zipFileWithUpdater, File targetCluster) throws IOException { JarFile jf = new JarFile(zipFileWithUpdater); String entryPath = updaterJarEntry.getName(); String entryName = entryPath.contains("/") ? entryPath.substring(entryPath.lastIndexOf("/") + 1) : entryPath; File dest = new File (targetCluster, UpdaterDispatcher.UPDATE_DIR + // updater UpdateTracking.FILE_SEPARATOR + UpdaterDispatcher.NEW_UPDATER_DIR + // new_updater UpdateTracking.FILE_SEPARATOR + entryName ); dest.getParentFile ().mkdirs (); assert dest.getParentFile ().exists () && dest.getParentFile ().isDirectory () : "Parent of " + dest + " exists and is directory."; InputStream is = null; OutputStream fos = null; try { try { fos = new FileOutputStream (dest); is = jf.getInputStream (updaterJarEntry); FileUtil.copy (is, fos); } finally { if (is != null) is.close(); if (fos != null) fos.close(); jf.close(); } } catch (java.io.FileNotFoundException fnfe) { getLogger ().log (Level.SEVERE, fnfe.getLocalizedMessage (), fnfe); } catch (java.io.IOException ioe) { getLogger ().log (Level.SEVERE, ioe.getLocalizedMessage (), ioe); } } static void cleanUpdateOfUpdaterJar () { // loop for all clusters and clean if needed List clusters = UpdateTracking.clusters (true); assert clusters != null : "Clusters cannot be empty."; // NOI18N for (File cluster : clusters) { File updaterDir = new File (cluster, UpdaterDispatcher.UPDATE_DIR + UpdateTracking.FILE_SEPARATOR + UpdaterDispatcher.NEW_UPDATER_DIR); if (updaterDir.exists () && updaterDir.isDirectory ()) { for (File f : updaterDir.listFiles ()) { f.delete (); } updaterDir.delete (); } } } static Module toModule(UpdateUnit uUnit) { return getModuleInstance(uUnit.getCodeName(), null); // XXX } public static Module toModule(String codeNameBase) { ModuleInfo mi = ModuleCache.getInstance().find(codeNameBase); if (mi instanceof Module) { return (Module)mi; } return null; } public static Module toModule(String codeNameBase, SpecificationVersion specificationVersion) { return getModuleInstance(codeNameBase, specificationVersion); } public static Module toModule (ModuleInfo info) { Module m = getModuleInstance (info.getCodeNameBase(), info.getSpecificationVersion ()); if (m == null && info instanceof Module) { m = (Module)info; } return m; } public static boolean isFixed (ModuleInfo info) { Module m = toModule (info); assert ! info.isEnabled () || m != null : "Module found for enabled " + info; return m == null ? false : m.isFixed (); } public static boolean isValid (ModuleInfo info) { Module m = toModule (info); assert ! info.isEnabled () || m != null : "Module found for enabled " + info; return m == null ? false : m.isValid (); } static UpdateUnit toUpdateUnit(Module m) { return UpdateManagerImpl.getInstance().getUpdateUnit(m.getCodeNameBase()); } static UpdateUnit toUpdateUnit(String codeNameBase) { return UpdateManagerImpl.getInstance().getUpdateUnit(codeNameBase); } public static Set findRequiredUpdateElements (UpdateElement element, Collection infos, Set brokenDependencies, boolean topAggressive, Collection recommended) { Set retval = new HashSet (); switch (element.getUpdateUnit().getType ()) { case KIT_MODULE : case MODULE : boolean avoidRecommended = recommended != null && ! recommended.isEmpty(); ModuleUpdateElementImpl el = (ModuleUpdateElementImpl) Trampoline.API.impl(element); Set deps = new HashSet (el.getModuleInfo ().getDependencies ()); Set availableInfos = new HashSet (infos); maybeAddImplicitHostDependency(element, deps); int max_counter = el.getType().equals(UpdateManager.TYPE.KIT_MODULE) ? 2 : 1; int counter = max_counter; boolean aggressive = topAggressive && counter > 0; Set all = new HashSet(); for (;;) { Set newones = processDependencies(deps, retval, availableInfos, brokenDependencies, element, aggressive, recommended, avoidRecommended); newones.removeAll(all); //issue #247884 Autoupdate should force restart when a new module enables module which is a fragment of other module for (Dependency dep : deps) { UpdateUnit uu = toUpdateUnit(dep.getName()); if (uu != null && uu.getInstalled() != null) { ModuleUpdateElementImpl em = (ModuleUpdateElementImpl) Trampoline.API.impl(uu.getInstalled()); // fragments which are installed, but not enabled yet, and have live host module will cause // restart if (em.getInstallInfo().getUpdateItemImpl().isFragment() && !uu.getInstalled().isEnabled()) { String fh = em.getInstallInfo().getUpdateItemImpl().getFragmentHost(); Module m = Utilities.toModule(fh); if (m != null && m.isEnabled()) { el.getInstallInfo().getUpdateItemImpl().setNeedsRestart(true); } } } } if (newones.isEmpty()) { break; } all.addAll(newones); deps = newones; } Set moreBroken = new HashSet (); Set tmp = new HashSet (availableInfos); Set more; counter = max_counter; aggressive = topAggressive && counter > 0; while (retval.addAll (more = handleBackwardCompatability (tmp, moreBroken, aggressive))) { if (! moreBroken.isEmpty ()) { brokenDependencies.addAll (moreBroken); break; } for (UpdateElement e : more) { //infos.addAll (Trampoline.API.impl (el).getModuleInfos ()); tmp.add (((ModuleUpdateElementImpl) Trampoline.API.impl (e)).getModuleInfo ()); } aggressive = aggressive && (counter--) > 0; } if (! moreBroken.isEmpty ()) { brokenDependencies.addAll (moreBroken); } break; case STANDALONE_MODULE : case FEATURE : FeatureUpdateElementImpl feature = (FeatureUpdateElementImpl) Trampoline.API.impl(element); aggressive = topAggressive; for (ModuleUpdateElementImpl module : feature.getContainedModuleElements ()) { retval.addAll (findRequiredUpdateElements (module.getUpdateElement (), infos, brokenDependencies, aggressive, recommended)); } break; case CUSTOM_HANDLED_COMPONENT : getLogger ().log (Level.INFO, "CUSTOM_HANDLED_COMPONENT doesn't care about required elements."); // XXX break; default: assert false : "Not implement for type " + element.getUpdateUnit() + " of UpdateElement " + element; } return retval; } private static Reference>> cachedInfo2RequestedReference = null; private static Set handleBackwardCompatability4ModuleInfo (ModuleInfo mi, Set forInstall, Set brokenDependencies, boolean aggressive) { if (cachedInfo2RequestedReference != null && cachedInfo2RequestedReference.get() != null) { Set requested = cachedInfo2RequestedReference.get().get(mi); if (requested != null) { return requested; } } UpdateUnit u = UpdateManagerImpl.getInstance().getUpdateUnit(mi.getCodeNameBase()); Set moreRequested = new HashSet(); // invalid codenamebase (in unit tests) if (u == null) { return moreRequested; } // not installed, not need to handle backward compatability UpdateElement i = u.getInstalled(); if (i == null) { return moreRequested; } // Dependency.TYPE_MODULE Collection dependencies = new HashSet(); dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, mi.getCodeName())); SortedSet newTokens = new TreeSet(Arrays.asList(mi.getProvides())); SortedSet oldTokens = new TreeSet(Arrays.asList(((ModuleUpdateElementImpl) Trampoline.API.impl(i)).getModuleInfo().getProvides())); oldTokens.removeAll(newTokens); // handle diff for (String tok : oldTokens) { // don't care about provider of platform dependency here if (tok.startsWith("org.openide.modules.os") || tok.startsWith("org.openide.modules.jre")) { // NOI18N continue; } dependencies.addAll(Dependency.create(Dependency.TYPE_REQUIRES, tok)); dependencies.addAll(Dependency.create(Dependency.TYPE_NEEDS, tok)); } for (Dependency d : dependencies) { DependencyAggregator deco = DependencyAggregator.getAggregator(d); int type = d.getType(); String name = d.getName(); Collection dependings = deco.getDependening(); synchronized (dependings) { for (ModuleInfo depMI : dependings) { Module depM = getModuleInstance(depMI.getCodeNameBase(), depMI.getSpecificationVersion()); if (depM == null) { continue; } if (!depM.getProblems().isEmpty()) { // skip this module because it has own problems already continue; } for (Dependency toTry : depM.getDependencies()) { // check only relevant deps if (type == toTry.getType() && name.equals(toTry.getName()) && !DependencyChecker.checkDependencyModule(toTry, mi)) { UpdateUnit tryUU = UpdateManagerImpl.getInstance().getUpdateUnit(depM.getCodeNameBase()); if (!tryUU.getAvailableUpdates().isEmpty()) { UpdateElement tryUE = tryUU.getAvailableUpdates().get(0); ModuleInfo tryUpdated = ((ModuleUpdateElementImpl) Trampoline.API.impl(tryUE)).getModuleInfo(); Set deps = new HashSet(tryUpdated.getDependencies()); Set availableInfos = new HashSet(forInstall); Set newones; maybeAddImplicitHostDependency(tryUE, deps); while (!(newones = processDependencies(deps, moreRequested, availableInfos, brokenDependencies, tryUE, aggressive, null, false)).isEmpty()) { deps = newones; } moreRequested.add(tryUE); } } } } } } if (cachedInfo2RequestedReference == null || cachedInfo2RequestedReference.get() == null) { cachedInfo2RequestedReference = new WeakReference>> (new HashMap>()); } cachedInfo2RequestedReference.get().put(mi, moreRequested); return moreRequested; } private static Reference> cachedInfosReference = null; private static Reference> cachedResultReference = null; private static Set handleBackwardCompatability (Set forInstall, Set brokenDependencies, boolean aggressive) { if (cachedInfosReference != null) { Set cir = cachedInfosReference.get(); if (cir != null && cir.equals(forInstall) ) { if (cachedResultReference != null) { Set crr = cachedResultReference.get(); if (crr != null) { return crr; } } } } cachedInfosReference = new WeakReference>(forInstall); err.finest("calling handleBackwardCompatability(size: " + forInstall.size() + ")"); Set moreRequested = new HashSet (); // backward compatibility for (ModuleInfo mi : forInstall) { moreRequested.addAll(handleBackwardCompatability4ModuleInfo(mi, forInstall, brokenDependencies, aggressive)); } cachedResultReference = new WeakReference>(moreRequested); return moreRequested; } private static boolean maybeAddImplicitHostDependency(UpdateElement el, Set deps) { // check fragment, add implicit dependencies UpdateElementImpl elImpl = Trampoline.API.impl(el); UpdateItemImpl uiImpl = elImpl.getInstallInfo().getUpdateItemImpl(); if (!uiImpl.isFragment()) { return false; } String fhost = uiImpl.getFragmentHost(); Collection hostDep = Dependency.create(Dependency.TYPE_MODULE, fhost); err.fine(hostDep.toString()); return deps.addAll(hostDep); } private static Set processDependencies (final Set original, Set retval, Set availableInfos, Set brokenDependencies, UpdateElement el, boolean agressive, Collection recommended, boolean avoidRecommended) { Set res = new HashSet (); AutomaticDependencies.Report rep = AutomaticDependencies.getDefault().refineDependenciesAndReport(el.getCodeName(), original); if (rep.isModified()) { err.fine(rep.toString()); } for (Dependency dep : original) { if (Dependency.TYPE_RECOMMENDS == dep.getType() && avoidRecommended) { continue; } Collection requestedElements = handleDependency (el, dep, availableInfos, brokenDependencies, agressive); if (requestedElements != null) { if (Dependency.TYPE_RECOMMENDS == dep.getType()) { if (recommended != null) { recommended.addAll(requestedElements); } } for (UpdateElement req : requestedElements) { ModuleUpdateElementImpl reqM = (ModuleUpdateElementImpl) Trampoline.API.impl (req); availableInfos.add (reqM.getModuleInfo ()); retval.add (req); res.addAll (reqM.getModuleInfo ().getDependencies ()); maybeAddImplicitHostDependency(req, res); } } } res.removeAll (original); return res; } public static Collection handleDependency (UpdateElement el, Dependency dep, Collection availableInfos, Set brokenDependencies, boolean beAggressive) { Collection requested = new HashSet (); switch (dep.getType ()) { case Dependency.TYPE_JAVA : if (! DependencyChecker.matchDependencyJava (dep)) { brokenDependencies.add (dep); } break; case Dependency.TYPE_PACKAGE : if (! DependencyChecker.matchPackageDependency (dep)) { brokenDependencies.add (dep); } break; case Dependency.TYPE_MODULE : Collection reqUnits = DependencyAggregator.getRequested (dep); assert reqUnits == null || reqUnits.isEmpty() || reqUnits.size() == 1 : dep + " returns null, empty or only once module, but returns " + reqUnits; boolean matched = false; UpdateUnit u = reqUnits == null || reqUnits.isEmpty() ? null : reqUnits.iterator().next(); if (u != null) { boolean aggressive = beAggressive; if (aggressive && (isFirstClassModule(el) || u.getType() == UpdateManager.TYPE.KIT_MODULE)) { aggressive = false; } // follow aggressive updates strategy // if new module update is available, promote it even though installed one suites all the dependendencies if (u.getInstalled() != null) { UpdateElementImpl reqElImpl = Trampoline.API.impl(u.getInstalled()); matched = DependencyChecker.checkDependencyModule(dep, ((ModuleUpdateElementImpl) reqElImpl).getModuleInfo()); } if (!matched) { for (ModuleInfo m : availableInfos) { if (DependencyChecker.checkDependencyModule(dep, m)) { matched = true; break; } } } if (aggressive || !matched) { UpdateElement reqEl = u.getAvailableUpdates().isEmpty() ? null : u.getAvailableUpdates().get(0); if (reqEl != null) { UpdateElementImpl reqElImpl = Trampoline.API.impl(reqEl); ModuleUpdateElementImpl reqModuleImpl = (ModuleUpdateElementImpl) reqElImpl; ModuleInfo info = reqModuleImpl.getModuleInfo(); if (DependencyChecker.checkDependencyModule(dep, info)) { if (!availableInfos.contains(info)) { requested.add(reqEl); matched = true; } } } } } else { for (ModuleInfo m : availableInfos) { if (DependencyChecker.checkDependencyModule(dep, m)) { matched = true; break; } } } if (!matched) { brokenDependencies.add(dep); } break; case Dependency.TYPE_REQUIRES : case Dependency.TYPE_NEEDS : case Dependency.TYPE_RECOMMENDS : if (DummyModuleInfo.TOKEN_MODULE_FORMAT1.equals (dep.getName ()) || DummyModuleInfo.TOKEN_MODULE_FORMAT2.equals (dep.getName ())) { // these tokens you can ignore here break; } Collection requestedUnits = DependencyAggregator.getRequested (dep); boolean passed = false; if (requestedUnits == null || requestedUnits.isEmpty()) { // look on availableInfos as well for (ModuleInfo m : availableInfos) { if (Arrays.asList (m.getProvides ()).contains (dep.getName ())) { passed = true; break; } } } else { passed = true; for (UpdateUnit uu : requestedUnits) { if (! uu.getAvailableUpdates ().isEmpty ()) { requested.add(uu.getAvailableUpdates ().get (0)); } } } if (! passed && Dependency.TYPE_RECOMMENDS != dep.getType ()) { brokenDependencies.add (dep); } break; } return requested; } static Set getBrokenDependencies (UpdateElement element, List infos) { assert element != null : "UpdateElement cannot be null"; Set brokenDependencies = new HashSet (); // create init collection of brokenDependencies Utilities.findRequiredUpdateElements (element, infos, brokenDependencies, false, new HashSet()); // backward compatibility for (ModuleInfo mi : infos) { UpdateUnit u = UpdateManagerImpl.getInstance ().getUpdateUnit (mi.getCodeNameBase ()); // invalid codenamebase (in unit tests) if (u == null) { continue; } // not installed, not need to handle backward compatability UpdateElement i = u.getInstalled (); if (i == null) { continue; } // maybe newer version is processed as a update if (! u.getAvailableUpdates ().isEmpty ()) { UpdateElement ue = u.getAvailableUpdates ().get (0); ModuleInfo newerMI = ((ModuleUpdateElementImpl) Trampoline.API.impl (ue)).getModuleInfo (); if (infos.contains (newerMI)) { continue; } } // Dependency.TYPE_MODULE for (Dependency d : Dependency.create (Dependency.TYPE_MODULE, mi.getCodeName ())) { DependencyAggregator deco = DependencyAggregator.getAggregator (d); Collection dependings = deco.getDependening(); synchronized (dependings) { for (ModuleInfo depMI : dependings) { //Module depM = Utilities.toModule (depMI); Module depM = getModuleInstance(depMI.getCodeNameBase(), depMI.getSpecificationVersion()); if (depM == null) { continue; } if (! depM.getProblems ().isEmpty ()) { // skip this module because it has own problems already continue; } for (Dependency toTry : depM.getDependencies ()) { // check only relevant deps if (deco.equals (DependencyAggregator.getAggregator (toTry)) && ! DependencyChecker.checkDependencyModule (toTry, mi)) { brokenDependencies.add (toTry); } } } } } // Dependency.TYPE_REQUIRES // Dependency.TYPE_NEEDS SortedSet newTokens = new TreeSet (Arrays.asList (mi.getProvides ())); SortedSet oldTokens = new TreeSet (Arrays.asList (((ModuleUpdateElementImpl) Trampoline.API.impl (i)).getModuleInfo ().getProvides ())); oldTokens.removeAll (newTokens); // handle diff for (String tok : oldTokens) { Collection deps = new HashSet (Dependency.create (Dependency.TYPE_REQUIRES, tok)); deps.addAll (Dependency.create (Dependency.TYPE_NEEDS, tok)); for (Dependency d : deps) { DependencyAggregator deco = DependencyAggregator.getAggregator (d); Collection dependings = deco.getDependening(); synchronized (dependings) { for (ModuleInfo depMI : dependings) { //Module depM = Utilities.toModule (depMI); Module depM = getModuleInstance(depMI.getCodeNameBase(), depMI.getSpecificationVersion()); if (depM == null) { continue; } if (! depM.getProblems ().isEmpty ()) { // skip this module because it has own problems already continue; } for (Dependency toTry : depM.getDependencies ()) { // check only relevant deps if (deco.equals (DependencyAggregator.getAggregator (toTry))) { brokenDependencies.add (toTry); } } } } } } } Set retval = new HashSet (brokenDependencies.size ()); for (Dependency dep : brokenDependencies) { retval.add (dep.toString ()); } return retval; } static Set getBrokenDependenciesInInstalledModules (UpdateElement element) { assert element != null : "UpdateElement cannot be null"; Set deps = new HashSet (); for (ModuleInfo m : getModuleInfos (Collections.singleton (element))) { deps.addAll (DependencyChecker.findBrokenDependenciesTransitive (m, InstalledModuleProvider.getInstalledModules ().values (), new HashSet ())); } Set retval = new HashSet (); for (Dependency dep : deps) { retval.add (dep.toString ()); } return retval; } private static List getModuleInfos (Collection elements) { List infos = new ArrayList (elements.size ()); for (UpdateElement el : elements) { if (el.getUpdateUnit () != null && el.getUpdateUnit ().isPending ()) { // cannot depend of UpdateElement in pending state continue; } UpdateElementImpl impl = Trampoline.API.impl (el); infos.addAll (impl.getModuleInfos ()); } return infos; } private static Module getModuleInstance(String codeNameBase, SpecificationVersion specificationVersion) { ModuleInfo mi = ModuleCache.getInstance().find(codeNameBase); if (mi instanceof Module) { Module m = (Module)mi; if (specificationVersion == null) { err.log(Level.FINE, "no module {0} for null version", m); return m; } else { SpecificationVersion version = m.getSpecificationVersion(); if (version == null) { err.log(Level.FINER, "No version for {0}", m); return null; } final int res = version.compareTo(specificationVersion); err.log(Level.FINER, "Comparing versions: {0}.compareTo({1}) = {2}", new Object[]{version, specificationVersion, res}); return res >= 0 ? m : null; } } return null; } public static boolean isAutomaticallyEnabled(String codeNameBase) { Module m = getModuleInstance(codeNameBase, null); return m != null ? (m.isAutoload() || m.isEager() || m.isFixed()) : false; } public static ModuleInfo takeModuleInfo (UpdateElement el) { UpdateElementImpl impl = Trampoline.API.impl (el); assert impl instanceof ModuleUpdateElementImpl; return ((ModuleUpdateElementImpl) impl).getModuleInfo (); } private static String productVersion = null; public static String getProductVersion () { if (productVersion == null) { String buildNumber = System.getProperty ("netbeans.buildnumber"); // NOI18N productVersion = NbBundle.getMessage (TopLogging.class, "currentVersion", buildNumber); // NOI18N } return productVersion; } private static Node getModuleConfiguration (File moduleUpdateTracking) { Document document; InputStream is; try { is = new BufferedInputStream (new FileInputStream (moduleUpdateTracking)); InputSource xmlInputSource = new InputSource (is); document = XMLUtil.parse (xmlInputSource, false, false, null, org.openide.xml.EntityCatalog.getDefault ()); is.close (); } catch (SAXException saxe) { getLogger ().log (Level.INFO, "SAXException when reading " + moduleUpdateTracking, saxe); return null; } catch (IOException ioe) { getLogger ().log (Level.INFO, "IOException when reading " + moduleUpdateTracking, ioe); return null; } assert document.getDocumentElement () != null : "File " + moduleUpdateTracking + " must contain element."; if (document.getDocumentElement () == null) { return null; } return getModuleElement (document.getDocumentElement ()); } private static Node getModuleElement (Element element) { Node lastElement = null; assert UpdateTracking.ELEMENT_MODULE.equals (element.getTagName ()) : "The root element is: " + UpdateTracking.ELEMENT_MODULE + " but was: " + element.getTagName (); NodeList listModuleVersions = element.getElementsByTagName (UpdateTracking.ELEMENT_VERSION); for (int i = 0; i < listModuleVersions.getLength (); i++) { lastElement = getModuleLastVersion (listModuleVersions.item (i)); if (lastElement != null) { break; } } return lastElement; } private static Node getModuleLastVersion (Node version) { Node attrLast = version.getAttributes ().getNamedItem (UpdateTracking.ATTR_LAST); assert attrLast != null : "ELEMENT_VERSION must contain ATTR_LAST attribute."; if (Boolean.valueOf (attrLast.getNodeValue ())) { return version; } else { return null; } } private static File getAdditionalInformation (File root) { File file = new File (root.getPath () + FILE_SEPARATOR + DOWNLOAD_DIR + FILE_SEPARATOR + UpdateTracking.ADDITIONAL_INFO_FILE_NAME); return file; } private static void writeAdditionalInformationToCluster (File cluster, Map updates) { if (updates.isEmpty ()) { return ; } Document document = XMLUtil.createDocument (UpdateTracking.ELEMENT_ADDITIONAL, null, null, null); Element root = document.getDocumentElement (); boolean isEmpty = true; for (Map.Entry entry : updates.entrySet ()) { UpdateElementImpl impl = entry.getKey (); File c = entry.getValue(); // pass this module to given cluster ? if (cluster.equals (c)) { Element module = document.createElement (UpdateTracking.ELEMENT_ADDITIONAL_MODULE); module.setAttribute(ATTR_NBM_NAME, InstallSupportImpl.getDestination (cluster, impl.getCodeName(), impl.getInstallInfo().getDistribution()).getName ()); module.setAttribute (UpdateTracking.ATTR_ADDITIONAL_SOURCE, impl.getSource ()); root.appendChild( module ); isEmpty = false; } } if (isEmpty) { return ; } writeXMLDocumentToFile (document, getAdditionalInformation (cluster)); } public static UpdateItem createUpdateItem (UpdateItemImpl impl) { assert Trampoline.SPI != null; return Trampoline.SPI.createUpdateItem (impl); } public static UpdateItemImpl getUpdateItemImpl (UpdateItem item) { assert Trampoline.SPI != null; return Trampoline.SPI.impl (item); } public static boolean canDisable (Module m) { return m != null && m.isEnabled () && ! isEssentialModule (m) && ! m.isAutoload () && ! m.isEager (); } public static boolean canEnable (Module m) { return m != null && !m.isEnabled () && ! m.isAutoload () && ! m.isEager (); } @SuppressWarnings("null") public static boolean isElementInstalled (UpdateElement el) { assert el != null : "Invalid call isElementInstalled with null parameter."; if (el == null) { return false; } return el.equals (el.getUpdateUnit ().getInstalled ()); } public static boolean isKitModule (ModuleInfo mi) { return Main.getModuleSystem().isShowInAutoUpdateClient(mi); } public static boolean isEssentialModule (ModuleInfo mi) { Object o = mi.getAttribute (ATTR_ESSENTIAL); return isFixed (mi) || (o != null && Boolean.parseBoolean (o.toString ())); } public static boolean isFirstClassModule (UpdateElement ue) { String codeName = ue.getCodeName(); String names = System.getProperty (PLUGIN_MANAGER_FIRST_CLASS_MODULES); if (names == null || names.length () == 0) { UpdateElementImpl ueImpl = Trampoline.API.impl(ue); return ueImpl.isPreferredUpdate(); } else { StringTokenizer en = new StringTokenizer(names, ","); // NOI18N while (en.hasMoreTokens()) { if (en.nextToken().trim().equals(codeName)) { return true; } } } return false; } private static Logger getLogger () { return err; } /** Finds modules depending on given module. * @param m a module to start from; may be enabled or not, but must be owned by this manager * @return a set (possibly empty) of modules managed by this manager, never including m */ public static Set findRequiredModules (Module m, ModuleManager mm, Map> m2reqs) { Set res; if (m2reqs != null) { res = m2reqs.get (m); if (res == null) { res = mm.getModuleInterdependencies(m, false, false, true); m2reqs.put (m, res); } } else { res = mm.getModuleInterdependencies(m, false, false, true); } return res; } /** Finds for modules given module depends upon. * @param m a module to start from; may be enabled or not, but must be owned by this manager * @return a set (possibly empty) of modules managed by this manager, never including m */ public static Set findDependingModules (Module m, ModuleManager mm, Map> m2deps) { Set res; if (m2deps != null) { res = m2deps.get (m); if (res == null) { res = filterDependingOnOtherProvider(m, mm.getModuleInterdependencies(m, true, false, true)); m2deps.put (m, res); } } else { res = filterDependingOnOtherProvider(m, mm.getModuleInterdependencies(m, true, false, true)); } return res; } private static Set filterDependingOnOtherProvider(Module m, Set modules) { Set alive = new HashSet (); for (String token : m.getProvides()) { for (Module depM : modules) { for (Dependency dep : depM.getDependencies()) { if (dep.getType() == Dependency.TYPE_REQUIRES || dep.getType() == Dependency.TYPE_NEEDS) { if (token.equals(dep.getName())) { // check other installed providers assert UpdateManagerImpl.getInstance().getInstalledProviders(token).contains(m) : "Provides of token " + token + " " + UpdateManagerImpl.getInstance().getInstalledProviders(token) + " contains " + m; if (UpdateManagerImpl.getInstance().getInstalledProviders(token).size() > 1) { alive.add(depM); } } } } } } modules.removeAll(alive); return modules; } public static String formatDate(Date date) { synchronized(DATE_FORMAT) { return DATE_FORMAT.format(date); } } public static Date parseDate(String date) throws ParseException { synchronized(DATE_FORMAT) { return DATE_FORMAT.parse(date); } } @SuppressWarnings("null") public static boolean canWriteInCluster (File cluster) { assert cluster != null : "dir cannot be null"; if (cluster == null) { return false; } if (cluster.exists () && cluster.isDirectory ()) { File dir4test; File update = new File (cluster, UPDATE_DIR); File download = new File (cluster, DOWNLOAD_DIR); if (download.exists ()) { dir4test = download; } else if (update.exists ()) { dir4test = update; } else { dir4test = cluster; } // workaround the bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4420020 if (dir4test.canWrite () && dir4test.canRead ()) { boolean canWrite = canWrite (dir4test); getLogger ().log (Level.FINE, "Can write into {0}? {1}", new Object[]{dir4test, canWrite}); return canWrite; } else { getLogger ().log (Level.FINE, "Can write into {0}? {1}", new Object[]{dir4test, dir4test.canWrite ()}); return dir4test.canWrite (); } } cluster.mkdirs (); getLogger ().log (Level.FINE, "Can write into new cluster {0}? {1}", new Object[]{cluster, cluster.canWrite ()}); return cluster.canWrite (); } public static boolean canWrite (File f) { // workaround the bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4420020 if (org.openide.util.Utilities.isWindows ()) { if (f.isFile ()) { FileWriter fw = null; try { fw = new FileWriter (f, true); getLogger ().log (Level.FINE, "{0} has write permission", f); } catch (IOException ioe) { // just check of write permission getLogger ().log (Level.FINE, f + " has no write permission", ioe); return false; } finally { try { if (fw != null) { fw.close (); } } catch (IOException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } } return true; } else { try { File dummy = File.createTempFile ("dummy", null, f); dummy.delete (); getLogger ().log (Level.FINE, "{0} has write permission", f); } catch (IOException ioe) { getLogger ().log (Level.FINE, f + " has no write permission", ioe); return false; } return true; } } else { return f.canWrite (); } } public static KeyStore loadKeyStore () { String fileName = getPreferences ().get (USER_KS_KEY, null); if (fileName == null) { return null; } else { InputStream is = null; KeyStore ks = null; try { File f = new File (getCacheDirectory (), fileName); if (! f.exists ()) { return null; } is = new BufferedInputStream (new FileInputStream (f)); ks = KeyStore.getInstance (KeyStore.getDefaultType ()); ks.load (is, KS_USER_PASSWORD.toCharArray ()); } catch (IOException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } catch (NoSuchAlgorithmException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } catch (CertificateException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } catch (KeyStoreException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } finally { try { if (is != null) { is.close (); } } catch (IOException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } } return ks; } } private static void storeKeyStore (KeyStore ks) { OutputStream os = null; try { File f = new File (getCacheDirectory (), USER_KS_FILE_NAME); os = new BufferedOutputStream (new FileOutputStream (f)); ks.store (os, KS_USER_PASSWORD.toCharArray ()); getPreferences ().put (USER_KS_KEY, USER_KS_FILE_NAME); } catch (KeyStoreException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } catch (IOException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } catch (NoSuchAlgorithmException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } catch (CertificateException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } finally { try { if (os != null) { os.close (); } } catch (IOException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } } } public static void addCertificates (Collection certs) { KeyStore ks = loadKeyStore (); if (ks == null) { try { ks = KeyStore.getInstance (KeyStore.getDefaultType ()); ks.load (null, KS_USER_PASSWORD.toCharArray ()); } catch (IOException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); return ; } catch (NoSuchAlgorithmException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); return ; } catch (CertificateException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); return ; } catch (KeyStoreException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); return ; } } for (Certificate c : certs) { try { // don't add certificate twice if (ks.getCertificateAlias (c) != null) { continue; } // Find free alias name String alias = null; for (int i = 0; i < 9999; i++) { alias = "genAlias" + i; // NOI18N if (! ks.containsAlias (alias)) { break; } } if (alias == null) { getLogger ().log (Level.INFO, "Too many certificates with {0}", c); } ks.setCertificateEntry (alias, c); } catch (KeyStoreException ex) { getLogger ().log (Level.INFO, ex.getLocalizedMessage (), ex); } } storeKeyStore (ks); } public static void writeFirstClassModule(String moduleCodeName) { if (moduleCodeName == null) { getPreferences().put(PLUGIN_MANAGER_FIRST_CLASS_MODULES, ""); return ; } String names = getPreferences().get(PLUGIN_MANAGER_FIRST_CLASS_MODULES, ""); names = names.isEmpty() ? moduleCodeName : names + "," + moduleCodeName; getPreferences().put(PLUGIN_MANAGER_FIRST_CLASS_MODULES, names); } private static File getCacheDirectory () { return Places.getCacheSubdirectory("catalogcache"); } private static Preferences getPreferences() { return NbPreferences.root ().node ("/org/netbeans/modules/autoupdate"); // NOI18N } public static String hexEncode(byte[] input) { StringBuilder sb = new StringBuilder(input.length * 2); for(byte b: input) { sb.append(Character.forDigit((b & 0xF0) >> 4, 16)); sb.append(Character.forDigit((b & 0x0F), 16)); } return sb.toString(); } public static byte[] hexDecode(String input) { int length = input.length() / 2; byte[] result = new byte[length]; for(int i = 0; i < length; i++) { int b = Character.digit(input.charAt(i * 2), 16) << 4; b |= Character.digit(input.charAt(i * 2 + 1), 16); result[i] = (byte) (b & 0xFF); } return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy