private void extract()

in vault-core/src/main/java/org/apache/jackrabbit/vault/packaging/impl/JcrPackageImpl.java [371:552]


    private void extract(Set<PackageId> processed, ImportOptions options, boolean createSnapshot, boolean replaceSnapshot)
            throws RepositoryException, PackageException, IOException {
        getPackage();
        getDefinition();
        if (def != null) {
            processed.add(def.getId());
        }

        if (options.getDependencyHandling() != null && options.getDependencyHandling() != DependencyHandling.IGNORE) {
            installDependencies(processed, options, createSnapshot, replaceSnapshot);
        }

        // get a copy of the import options (bug 35164)
        ImportOptions opts = options.copy();
        // check for disable intermediate saves (GRANITE-1047)
        if (this.getDefinition().getBoolean(JcrPackageDefinition.PN_DISABLE_INTERMEDIATE_SAVE) ) {
            // MAX_VALUE disables saving completely, therefore we have to use a lower value!
            opts.setAutoSaveThreshold(Integer.MAX_VALUE - 1);
        }
        InstallContextImpl ctx = pack.prepareExtract(node.getSession(), opts, mgr.getSecurityConfig(), mgr.isStrictByDefault(),
                mgr.overwritePrimaryTypesOfFoldersByDefault(), mgr.getDefaultIdConflictPolicy());
        JcrPackage snap = null;
        if (!opts.isDryRun() && createSnapshot) {
            ExportOptions eOpts = new ExportOptions();
            eOpts.setListener(opts.getListener());
            snap = snapshot(eOpts, replaceSnapshot, opts.getAccessControlHandling());
        }
        List<String> subPackages = new ArrayList<>();
        pack.extract(ctx, subPackages);
        if (def != null && !opts.isDryRun()) {
            def.touchLastUnpacked();
        }

        // process sub packages
        Session s = node.getSession();
        List<JcrPackageImpl> subPacks = new LinkedList<>();
        // contains a value only if a more recent version of the package with the given id (from the key) is already installed
        Map<PackageId, PackageId> newerPackageIdPerSubPackage = new HashMap<>();
        for (String path: subPackages) {
            if (s.nodeExists(path)) {
                JcrPackageImpl p = new JcrPackageImpl(mgr, s.getNode(path));
                if (!p.isValid()) {
                    // check if package was included as pure .zip or .jar
                    try {
                        p.tryUnwrap();
                    } catch (Exception e) {
                        log.info("Sub package {} not valid: {}", path, e.getMessage());
                        log.debug("Sub package {} not valid", path, e);
                    }
                }
                if (p.isValid()) {
                    JcrPackageDefinitionImpl def = (JcrPackageDefinitionImpl) p.getDefinition();
                    PackageId pId = def.getId();

                    // check if package is at the correct location
                    String expectedPath = mgr.getInstallationPath(pId) + ".zip";
                    if (!expectedPath.equals(path)) {
                        if (s.nodeExists(expectedPath)) {
                            log.info("(Removed duplicated sub-package in {}. Still present at {}", path, expectedPath);
                            s.getNode(path).remove();
                            s.save();
                        } else {
                            log.info("Moving sub-package in place: {} -> {}", path, expectedPath);
                            s.getWorkspace().move(path, expectedPath);
                        }
                        path = expectedPath;
                        // re-acquire the package and definition
                        p.close();
                        p = new JcrPackageImpl(mgr, s.getNode(path));
                        def = (JcrPackageDefinitionImpl) p.getDefinition();
                    }

                    // ensure that sub package is marked as not-installed. it might contain wrong data in vlt:definition (JCRVLT-114)
                    def.clearLastUnpacked(false);

                    // add dependency to the parent package if required
                    Dependency[] oldDeps = def.getDependencies();
                    Dependency[] newDeps = DependencyUtil.addExact(oldDeps, pack.getId());
                    if (oldDeps != newDeps) {
                        def.setDependencies(newDeps, false);
                    }

                    String pName = pId.getName();
                    Version pVersion = pId.getVersion();

                    // get the list of packages available in the same group
                    JcrPackageManager pkgMgr = new JcrPackageManagerImpl(mgr);
                    List<JcrPackage> listPackages = pkgMgr.listPackages(pId.getGroup(), true);

                    // loop in the list of packages returned previously by package manager
                    for (JcrPackage listedPackage: listPackages) {
                        JcrPackageDefinition listedPackageDef = listedPackage.getDefinition();
                        if (listedPackageDef == null) {
                            continue;
                        }
                        PackageId listedPackageId = listedPackageDef.getId();
                        if (listedPackageId.equals(pId)) {
                            continue;
                        }
                        // check that the listed package is actually from same name (so normally only version would differ)
                        // if that package is valid, installed, and the version is more recent than the one in our sub package
                        // then we can stop the loop here
                        if (pName.equals(listedPackageId.getName()) && listedPackage.isValid() && listedPackage.isInstalled()
                                && listedPackageId.getVersion().compareTo(pVersion) > 0) {
                            newerPackageIdPerSubPackage.put(pId, listedPackageId);
                            break;
                        }
                    }
                    subPacks.add(p);
                }
            }
        }

        // don't extract sub packages if not recursive
        if (!opts.isNonRecursive() && !subPacks.isEmpty()) {
            try {
                DependencyUtil.sortPackages(subPacks);
            } catch (CyclicDependencyException e) {
                if (opts.isStrict(mgr.isStrictByDefault())) {
                    throw e;
                }
            }
            List<PackageId> subIds = new LinkedList<PackageId>();
            SubPackageHandling sb = pack.getSubPackageHandling();
            for (JcrPackageImpl p: subPacks) {
                boolean skip = false;
                PackageId id = p.getDefinition().getId();
                SubPackageHandling.Option option = sb.getOption(id);
                String msg = null;
                // should the package be skipped due to a newer version already installed?
                if (option == SubPackageHandling.Option.INSTALL || option == SubPackageHandling.Option.EXTRACT) {
                    PackageId newerPackageId = newerPackageIdPerSubPackage.get(id);
                    if (newerPackageId != null) {
                        msg = String.format(Locale.ENGLISH, "Skipping installation of subpackage '%s' due to newer installed version: '%s'", id, newerPackageId);
                        skip = true;
                    }
                }
                
                if (!skip) {
                    if (option == SubPackageHandling.Option.ADD || option == SubPackageHandling.Option.IGNORE) {
                        msg = "Skipping installation of subpackage " + id + " due to option " + option;
                        skip = true;
                    } else if (option == SubPackageHandling.Option.INSTALL || option == SubPackageHandling.Option.FORCE_INSTALL) {
                        msg = "Starting installation of subpackage " + id;
                    } else {
                        msg = "Starting extraction of subpackage " + id;
                    }
                }
                if (options.isDryRun()) {
                    msg = "Dry run: " + msg;
                }
                if (options.getListener() != null) {
                    options.getListener().onMessage(ProgressTrackerListener.Mode.TEXT, msg, "");
                } else {
                    log.debug(msg);
                }
                if (!skip) {
                    if (createSnapshot && (option == SubPackageHandling.Option.INSTALL || option == SubPackageHandling.Option.FORCE_INSTALL)) {
                        p.extract(options, true, true);
                        subIds.add(id);
                    } else {
                        p.extract(options, false, true);
                    }
                }
                p.close();
            }
            // register sub packages in snapshot and on package for uninstall
            if (snap != null) {
                ((JcrPackageDefinitionImpl) snap.getDefinition()).setSubPackages(subIds);
            }
            if (def != null) {
                def.setSubPackages(subIds);
            }
            s.save();
        }

        if (createSnapshot) {
            mgr.dispatch(PackageEvent.Type.INSTALL, def.getId(), null);
        } else {
            mgr.dispatch(PackageEvent.Type.EXTRACT, def.getId(), null);
        }
    }