public static PrepareInstallResult prepareInstall()

in core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java [193:382]


    public static PrepareInstallResult prepareInstall(ManagementContext mgmt, ManagedBundle suppliedKnownBundleMetadata, ManagedBundle optionalAdditionalInferredMetadata,
                                                      Supplier<InputStream> zipInS, boolean force, @Nullable OsgiBundleInstallationResult resultObject) {
        InputStream zipIn = zipInS == null ? null : zipInS.get();
        PrepareInstallResult prepareInstallResult = new PrepareInstallResult();
        prepareInstallResult.resultObject = resultObject;
        try {
            Maybe<Bundle> existingOsgiInstalledBundle = Maybe.absent();
            Maybe<ManagedBundle> existingBrooklynInstalledBundle = Maybe.absent();
            OsgiManager osgiManager = ((ManagementContextInternal) mgmt).getOsgiManager().get();

            if (suppliedKnownBundleMetadata != null) {
                // Before even trying to find or download the bundle, check if it is supposed to be forcibly replaced.
                // If so, return the replacement (if any).
                if (optionalAdditionalInferredMetadata==null) {
                    optionalAdditionalInferredMetadata = suppliedKnownBundleMetadata;
                }

                if (suppliedKnownBundleMetadata.isNameResolved()) {
                    Maybe<VersionedName> forcedReplacementBundle = CatalogUpgrades.tryGetBundleForcedReplaced(mgmt, suppliedKnownBundleMetadata.getVersionedName());
                    if (forcedReplacementBundle.isPresent()) {
                        if (prepareInstallResult.resultObject==null) {
                            prepareInstallResult.resultObject = new OsgiBundleInstallationResult();
                        }
                        setResultForciblyRemovedResult(osgiManager, suppliedKnownBundleMetadata.getVersionedName(), optionalAdditionalInferredMetadata,
                                forcedReplacementBundle, prepareInstallResult.resultObject);
                        return prepareInstallResult;
                    }
                } else if (suppliedKnownBundleMetadata.getUrl() != null && suppliedKnownBundleMetadata.getUrl().toLowerCase().startsWith("mvn:")) {
                    // This inference is not guaranteed to get the right answer - you can put whatever
                    // you want in the MANIFEST.MF. Also, the maven-bundle-plugin does some surprising
                    // transforms, but we take a simpler approach here.
                    // If folk want it to work for such edge-cases, they should include the
                    // name:version explicitly in the `brooklyn.libraries list`.
                    Optional<VersionedName> inferredName = inferBundleNameFromMvnUrl(suppliedKnownBundleMetadata.getUrl());
                    if (inferredName.isPresent()) {
                        Maybe<VersionedName> forcedReplacementBundle = CatalogUpgrades.tryGetBundleForcedReplaced(mgmt, inferredName.get());
                        if (forcedReplacementBundle.isPresent()) {
                            if (prepareInstallResult.resultObject==null) {
                                prepareInstallResult.resultObject = new OsgiBundleInstallationResult();
                            }
                            setResultForciblyRemovedResult(osgiManager, inferredName.get(), optionalAdditionalInferredMetadata,
                                    forcedReplacementBundle, prepareInstallResult.resultObject);
                            return prepareInstallResult;
                        }
                    }
                }

                if (zipIn == null) {
                    // if no input stream (zipIn), look for a URL and/or a matching bundle
                    if (!suppliedKnownBundleMetadata.isNameResolved()) {
                        existingBrooklynInstalledBundle = Maybe.ofDisallowingNull(osgiManager.getManagedBundleFromUrl(suppliedKnownBundleMetadata.getUrl()));
                        if (existingBrooklynInstalledBundle.isPresent()) {
                            // user supplied just a URL (eg brooklyn.libraries), but we recognise it,
                            // so don't try to reload it, just record the info we know about it to retrieve the bundle
                            ((BasicManagedBundle) suppliedKnownBundleMetadata).setSymbolicName(existingBrooklynInstalledBundle.get().getSymbolicName());
                            ((BasicManagedBundle) suppliedKnownBundleMetadata).setVersion(existingBrooklynInstalledBundle.get().getSuppliedVersionString());
                        }
                    }
                    if (existingOsgiInstalledBundle.isAbsent() && suppliedKnownBundleMetadata.getOsgiUniqueUrl() != null) {
                        existingOsgiInstalledBundle = Osgis.bundleFinder(osgiManager.getFramework()).requiringFromUrl(suppliedKnownBundleMetadata.getOsgiUniqueUrl()).find();
                    }
                    if (existingOsgiInstalledBundle.isAbsent() && suppliedKnownBundleMetadata.getUrl() != null) {
                        existingOsgiInstalledBundle = Osgis.bundleFinder(osgiManager.getFramework()).requiringFromUrl(suppliedKnownBundleMetadata.getUrl()).find();
                    }
                    if (existingOsgiInstalledBundle.isAbsent() && suppliedKnownBundleMetadata.isNameResolved()) {
                        existingOsgiInstalledBundle = Osgis.bundleFinder(osgiManager.getFramework()).symbolicName(suppliedKnownBundleMetadata.getSymbolicName()).version(suppliedKnownBundleMetadata.getSuppliedVersionString()).find();
                    }
                    if (existingOsgiInstalledBundle.isPresent()) {
                        if (existingBrooklynInstalledBundle.isAbsent()) {
                            // try to find as brooklyn bundle based on knowledge of OSGi bundle
                            existingBrooklynInstalledBundle = Maybe.ofDisallowingNull(osgiManager.getManagedBundle(new VersionedName(existingOsgiInstalledBundle.get())));
                        }
                        if (suppliedKnownBundleMetadata.getUrl() == null) {
                            // installer did not supply a usable URL, just coords
                            // but bundle is installed at least to OSGi
                            if (existingBrooklynInstalledBundle.isPresent()) {
                                log.debug("Detected bundle " + suppliedKnownBundleMetadata + " installed to Brooklyn already; no URL or stream supplied, so re-using existing installation");
                                // if bundle is brooklyn-managed simply say "already installed"
                                //                            prepareInstallResult.existingBundleMetadata = existingBrooklynInstalledBundle.get();
                                if (prepareInstallResult.resultObject==null) {
                                    prepareInstallResult.resultObject = new OsgiBundleInstallationResult();
                                }
                                prepareInstallResult.resultObject.metadata = existingBrooklynInstalledBundle.get();
                                prepareInstallResult.resultObject.setIgnoringAlreadyInstalled();

                            } else {
                                // if bundle is not brooklyn-managed we want to make it be so
                                // and for that we need to find a URL.
                                // the getLocation() _might_ be usable, or might be totally opaque;
                                // in tests we rely on the block below (see system:file:) and things
                                // being explicitly set, but in live and rebind deployments the URL
                                // in practice with karaf how we package it is of the form mvn:...
                                // which _does_ work in this block, so we will be able to do most
                                // things which rely on taking osgi-installed bundles into brooklyn mgmt
                                // (and if not don't think it's a big deal, we just uninstall and reinstall
                                // sometimes or fail with a reasonable error message)
                                String candidateUrl = existingOsgiInstalledBundle.get().getLocation();
                                log.debug("Detected bundle " + suppliedKnownBundleMetadata + " installed to OSGi but not Brooklyn; trying to find a URL to get bundle binary, candidate " + candidateUrl);
                                if (Strings.isBlank(candidateUrl)) {
                                    throw new IllegalArgumentException("No input stream available and no URL could be found: no way to promote " + suppliedKnownBundleMetadata + " from " + existingOsgiInstalledBundle.get() + " to Brooklyn management");
                                }
                                try {
                                    // do this in special try block, not below, so we can give a better error
                                    // (the user won't understand the URL)
                                    zipIn = ResourceUtils.create(mgmt).getResourceFromUrl(candidateUrl);
                                    prepareInstallResult.isBringingExistingOsgiInstalledBundleUnderBrooklynManagement = true;
                                } catch (Exception e) {
                                    Exceptions.propagateIfFatal(e);
                                    throw new IllegalArgumentException("Could not find binary for already installed OSGi bundle " + existingOsgiInstalledBundle.get() + " (location " + candidateUrl + ") when trying to promote " + suppliedKnownBundleMetadata + " to Brooklyn management", e);
                                }
                            }
                        }
                    } else if (suppliedKnownBundleMetadata.getUrl() == null) {
                        // not installed anywhere and no URL
                        throw new IllegalArgumentException("No input stream available and no URL could be found: no way to install " + suppliedKnownBundleMetadata);
                    }

                    if (zipIn != null) {
                        // found input stream for existing osgi bundle

                    } else if (existingBrooklynInstalledBundle.isAbsent() || force) {
                        // reload
                        String url = suppliedKnownBundleMetadata.getUrl();
                        if (url == null) {
                            throw new IllegalStateException("should have found a stream or inferred a URL or already installed");
                        }
                        if (BrooklynVersion.isDevelopmentEnvironment() && url.startsWith("system:file:")) {
                            // in live dists the url is usually mvn: but in dev/test karaf will prefix it with system;
                            // leave the url alone so we correctly dedupe when considering whether to update, but create a zip file
                            // so that things work consistently in dev/test (in particular ClassLoaderUtilsTest passes).
                            // pretty sure we have to do this, even if not replacing the osgi bundle, because we need to
                            // get a handle on the zip file (although we could skip if not doing persistence - but that feels even worse than this!)
                            try {
                                url = Strings.removeFromStart(url, "system:");
                                File zipTemp = new BundleMaker(ResourceUtils.create(mgmt)).createJarFromClasspathDir(url);
                                zipIn = new FileInputStream(zipTemp);
                            } catch (FileNotFoundException e) {
                                throw Exceptions.propagate(e);
                            }
                        } else {
                            zipIn = ResourceUtils.create(mgmt).getResourceFromUrl(url, suppliedKnownBundleMetadata.getUrlCredential());
                        }
                    } else {
                        // already installed, not forced, just say already installed
                        // (even if snapshot as this is a reference by URL, not uploaded content)
                        //                    prepareInstallResult.existingBundleMetadata = existingBrooklynInstalledBundle.get();
                        if (prepareInstallResult.resultObject==null) {
                            prepareInstallResult.resultObject = new OsgiBundleInstallationResult();
                        }
                        prepareInstallResult.resultObject.metadata = existingBrooklynInstalledBundle.get();
                        prepareInstallResult.resultObject.setIgnoringAlreadyInstalled();

                    }
                }
            }

            prepareInstallResult.existingBundle = existingOsgiInstalledBundle.orNull();

            if (zipIn != null) {
                if (zipInS instanceof InputStreamSourceFromFile) {
                    prepareInstallResult.zipFile = new FileWithTempInfo<File>( ((InputStreamSourceFromFile) zipInS).getFile(), false );
                } else {
                    prepareInstallResult.zipFile = new FileWithTempInfo<File>( Os.newTempFile("brooklyn-bundle-transient-" + suppliedKnownBundleMetadata, "zip"), true );
                    try {
                        FileOutputStream fos = new FileOutputStream(prepareInstallResult.zipFile.getFile());
                        Streams.copyClose(zipIn, fos);
                        try (ZipFile zf = new ZipFile(prepareInstallResult.zipFile.getFile())) {
                            // validate it is a valid ZIP, otherwise errors are more obscure later.
                            // can happen esp if user supplies a file://path/to/folder/ as the URL.openStream returns a list of that folder (!)
                            // the error thrown by the below is useful enough, and caller will wrap with suppliedKnownBundleMetadata details
                            zf.entries();
                        }
                    } catch (Exception e) {
                        try {
                            prepareInstallResult.zipFile.deleteIfTemp();
                        } catch (Exception e2) {
                            Exceptions.propagateIfFatal(e2);
                            log.warn("Error deleting ZIP file but ignoring because handling error "+e+": "+e2);
                        }
                        throw Exceptions.propagate(e);
                    }
                }
            }
        } finally {
            Streams.closeQuietly(zipIn);
            zipIn = null;
        }

        return prepareInstallResult;
    }