/* * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed 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. * * Contributors: * Nuxeo */ package org.nuxeo.ecm.admin.operation; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.utils.ExceptionUtils; import org.nuxeo.connect.client.we.StudioSnapshotHelper; import org.nuxeo.connect.connector.ConnectServerError; import org.nuxeo.connect.data.DownloadablePackage; import org.nuxeo.connect.data.DownloadingPackage; import org.nuxeo.connect.packages.PackageManager; import org.nuxeo.connect.packages.dependencies.TargetPlatformFilterHelper; import org.nuxeo.connect.update.LocalPackage; import org.nuxeo.connect.update.PackageException; import org.nuxeo.connect.update.PackageState; import org.nuxeo.connect.update.PackageUpdateService; import org.nuxeo.connect.update.ValidationStatus; import org.nuxeo.connect.update.task.Task; import org.nuxeo.ecm.admin.runtime.PlatformVersionHelper; import org.nuxeo.ecm.automation.core.Constants; import org.nuxeo.ecm.automation.core.annotations.Context; import org.nuxeo.ecm.automation.core.annotations.Operation; import org.nuxeo.ecm.automation.core.annotations.OperationMethod; import org.nuxeo.ecm.automation.core.annotations.Param; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.core.api.NuxeoPrincipal; import org.nuxeo.runtime.api.Framework; /** * Operation to trigger a Hot reload of the Studio Snapshot package. You must be an administrator to trigger it. * * @since 8.2 */ @Operation(id = HotReloadStudioSnapshot.ID, category = Constants.CAT_SERVICES, label = "Hot Reload Studio Snapshot Package", description = "Updates Studio project with latest snapshot.") public class HotReloadStudioSnapshot { public static final String ID = "Service.HotReloadStudioSnapshot"; protected static boolean updateInProgress = false; private static final Log log = LogFactory.getLog(HotReloadStudioSnapshot.class); @Context protected CoreSession session; @Context protected PackageManager pm; @Param(name = "validate", required = false) protected boolean validate = true; @OperationMethod public void run() throws Exception { if (updateInProgress) { return; } if (!((NuxeoPrincipal) session.getPrincipal()).isAdministrator()) { throw new NuxeoException("Must be Administrator to use this function"); } if (!Framework.isDevModeSet()) { throw new NuxeoException("You must enable Dev mode to Hot reload your Studio Snapshot package."); } List<DownloadablePackage> pkgs = pm.listRemoteAssociatedStudioPackages(); DownloadablePackage snapshotPkg = StudioSnapshotHelper.getSnapshot(pkgs); if (snapshotPkg == null) { throw new NuxeoException("No Snapshot Package was found."); } try { updateInProgress = true; hotReloadPackage(snapshotPkg); } finally { updateInProgress = false; } } public void hotReloadPackage(DownloadablePackage remotePkg) { if (validate) { pm.flushCache(); String targetPlatform = PlatformVersionHelper.getPlatformFilter(); if (!TargetPlatformFilterHelper.isCompatibleWithTargetPlatform(remotePkg, targetPlatform)) { throw new NuxeoException( String.format("This package is not validated for your current platform: %s", targetPlatform)); } } // Effective install try { PackageUpdateService pus = Framework.getLocalService(PackageUpdateService.class); String packageId = remotePkg.getId(); LocalPackage pkg = pus.getPackage(packageId); // Uninstall and/or remove if needed if (pkg != null) { removePackage(pus, pkg); } // Download DownloadingPackage downloadingPkg = pm.download(packageId); while (!downloadingPkg.isCompleted()) { log.debug("Downloading studio snapshot package: " + packageId); Thread.sleep(100); } // Install log.info("Installing " + packageId); pkg = pus.getPackage(packageId); if (pkg == null || PackageState.DOWNLOADED != pkg.getPackageState()) { throw new NuxeoException("Error while downloading studio snapshot " + pkg); } Task installTask = pkg.getInstallTask(); try { performTask(installTask); } catch (PackageException e) { installTask.rollback(); throw e; } } catch (InterruptedException e) { ExceptionUtils.checkInterrupt(e); throw new NuxeoException("Error while downloading studio snapshot", e); } catch (PackageException | ConnectServerError e) { throw new NuxeoException("Error while installing studio snapshot", e); } } protected static void removePackage(PackageUpdateService pus, LocalPackage pkg) throws PackageException { log.info(String.format("Removing package %s before update...", pkg.getId())); if (pkg.getPackageState().isInstalled()) { // First remove it to allow SNAPSHOT upgrade log.info("Uninstalling " + pkg.getId()); Task uninstallTask = pkg.getUninstallTask(); try { performTask(uninstallTask); } catch (PackageException e) { uninstallTask.rollback(); throw e; } } pus.removePackage(pkg.getId()); } protected static void performTask(Task task) throws PackageException { ValidationStatus validationStatus = task.validate(); if (validationStatus.hasErrors()) { throw new PackageException( "Failed to validate package " + task.getPackage().getId() + " -> " + validationStatus.getErrors()); } if (validationStatus.hasWarnings()) { log.warn("Got warnings on package validation " + task.getPackage().getId() + " -> " + validationStatus.getWarnings()); } task.run(null); } }