001/* 002 * Copyright 2023 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.plugins.admin.migration; 017 018import java.time.Instant; 019import java.util.Map.Entry; 020 021import org.apache.avalon.framework.service.ServiceException; 022import org.apache.avalon.framework.service.ServiceManager; 023 024import org.ametys.core.migration.MigrationEngine; 025import org.ametys.core.migration.MigrationEngine.ActionData; 026import org.ametys.core.migration.MigrationEngine.MigrationComponent; 027import org.ametys.core.migration.MigrationEngine.VersionList; 028import org.ametys.core.migration.MigrationEngine.Versions; 029import org.ametys.core.migration.MigrationException; 030import org.ametys.core.migration.MigrationExtensionPoint; 031import org.ametys.core.migration.action.ActionConfiguration; 032import org.ametys.core.migration.action.ActionExtensionPoint; 033import org.ametys.core.migration.version.Version; 034import org.ametys.core.ui.Callable; 035import org.ametys.core.ui.StaticClientSideElement; 036 037/** 038 * Client side element with callables for migrations actions 039 */ 040public class MigrationsActionsClientSideElement extends StaticClientSideElement 041{ 042 private MigrationEngine _migrationEngine; 043 private MigrationExtensionPoint _migrationExtensionPoint; 044 private MigrationExtensionPoint _migrationDataExtensionPoint; 045 private ActionExtensionPoint _upgradeEP; 046 047 @Override 048 public void service(ServiceManager manager) throws ServiceException 049 { 050 super.service(manager); 051 052 _migrationEngine = (MigrationEngine) manager.lookup(MigrationEngine.ROLE); 053 _migrationExtensionPoint = (MigrationExtensionPoint) manager.lookup(MigrationExtensionPoint.ROLE); 054 _migrationDataExtensionPoint = (MigrationExtensionPoint) manager.lookup(MigrationExtensionPoint.ROLE + "/internal"); 055 _upgradeEP = (ActionExtensionPoint) manager.lookup(ActionExtensionPoint.ROLE_UPGRADE); 056 } 057 058 /** 059 * Marks a version as done 060 * @param componentId the main component id 061 * @param internal true if the component is from internel migration 062 * @param versionListId the id of the {@link VersionList} 063 * @param versionNumber the number of the version to be deleted 064 * @param comment the comment associated to this operation 065 * @throws MigrationException if an error occurs while storing version 066 */ 067 @Callable (rights = "Runtime_Rights_Admin_Access", context = "/admin") 068 public void acknowledge(String componentId, boolean internal, String versionListId, String versionNumber, String comment) throws MigrationException 069 { 070 MigrationComponent component = internal ? _migrationDataExtensionPoint.getExtension(componentId) : _migrationExtensionPoint.getExtension(componentId); 071 072 VersionList versionList = _getVersionList(component, versionListId); 073 074 Version version = new Version(component, versionList.componentId(), component.versionStorage(), versionList.storageConfiguration(), versionNumber, Instant.now(), comment); 075 component.versionStorage().storeVersion(version); 076 } 077 078 /** 079 * Deletes a version from storage 080 * @param componentId the main component id 081 * @param internal true if the component is from internel migration 082 * @param versionListId the id of the {@link VersionList} 083 * @param versionNumber the number of the version to be deleted 084 * @throws MigrationException if an error occurs while deleting version 085 */ 086 @Callable (rights = "Runtime_Rights_Admin_Access", context = "/admin") 087 public void deleteVersion(String componentId, boolean internal, String versionListId, String versionNumber) throws MigrationException 088 { 089 MigrationComponent component = internal ? _migrationDataExtensionPoint.getExtension(componentId) : _migrationExtensionPoint.getExtension(componentId); 090 091 VersionList versionList = _getVersionList(component, versionListId); 092 093 component.versionStorage().removeVersion(versionList.componentId(), versionNumber, versionList.storageConfiguration()); 094 } 095 096 /** 097 * Deletes all versions of a component from storage 098 * @param componentId the main component id 099 * @param internal true if the component is from internel migration 100 * @param versionListId the id of the {@link VersionList} 101 * @throws MigrationException if an error occurs while deleting versions 102 */ 103 @Callable (rights = "Runtime_Rights_Admin_Access", context = "/admin") 104 public void deleteAllVersions(String componentId, boolean internal, String versionListId) throws MigrationException 105 { 106 MigrationComponent component = internal ? _migrationDataExtensionPoint.getExtension(componentId) : _migrationExtensionPoint.getExtension(componentId); 107 108 VersionList versionList = _getVersionList(component, versionListId); 109 110 component.versionStorage().removeAllVersions(versionList.componentId(), versionList.storageConfiguration()); 111 } 112 113 /** 114 * (Re-)plays a migration action, optionnaly storing a new version 115 * @param componentId the main component id 116 * @param internal true if the component is from internel migration 117 * @param versionListId the id of the {@link VersionList} 118 * @param upgradeNumber the number of the action to be executed 119 * @param store if the version should be stored after execution 120 * @param comment the comment associated to this operation 121 * @return true if the action needs a restart after its execution 122 * @throws MigrationException if an error occurs while executing action 123 */ 124 @Callable (rights = "Runtime_Rights_Admin_Access", context = "/admin") 125 public boolean doAction(String componentId, boolean internal, String versionListId, String upgradeNumber, boolean store, String comment) throws MigrationException 126 { 127 MigrationComponent component = internal ? _migrationDataExtensionPoint.getExtension(componentId) : _migrationExtensionPoint.getExtension(componentId); 128 129 ActionConfiguration actionConfiguration = component.upgrades().stream() 130 .filter(ac -> ac.getVersionNumber().equals(upgradeNumber)) 131 .findFirst() 132 .orElseThrow(() -> new MigrationException("no such upgrade: " + upgradeNumber)); 133 134 VersionList versionList = _getVersionList(component, versionListId); 135 136 Version version = new Version(component, versionList.componentId(), component.versionStorage(), versionList.storageConfiguration(), null, null, null); 137 138 if (versionList.additionalValues() != null) 139 { 140 for (Entry<String, Object> entry : versionList.additionalValues().entrySet()) 141 { 142 version.addAdditionalValue(entry.getKey(), entry.getValue()); 143 } 144 } 145 146 boolean requiresRestart = _migrationEngine.doAction(new ActionData(version, null, actionConfiguration, versionList.id()), _upgradeEP); 147 148 if (store) 149 { 150 // first remove the already stored version 151 component.versionStorage().removeVersion(versionList.componentId(), upgradeNumber, versionList.storageConfiguration()); 152 153 version.setComment(comment); 154 version.setExecutionInstant(Instant.now()); 155 version.setVersionNumber(upgradeNumber); 156 157 component.versionStorage().storeVersion(version); 158 } 159 160 return requiresRestart; 161 } 162 163 private VersionList _getVersionList(MigrationComponent component, String versionListId) throws MigrationException 164 { 165 Versions versions = _migrationEngine.getVersions(component); 166 VersionList versionList = _migrationEngine.getVersionList(versions, versionListId); 167 168 if (versionList == null) 169 { 170 throw new MigrationException("There's no version list for id: " + versionListId + " in component: " + component); 171 } 172 173 return versionList; 174 } 175}