001package org.dcm4che3.conf.api.upgrade; 002 003import org.dcm4che3.conf.api.DicomConfiguration; 004import org.dcm4che3.conf.core.api.*; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import java.util.Map; 009import java.util.Properties; 010 011/** 012 * Implement this interface to cover 013 * <ul> 014 * <li>transformation of configuration classes structure between releases</li> 015 * <li>conditional default config initialization</li> 016 * <li>migration of legacy configuration</li> 017 * </ul> 018 * <p/> 019 * Mark the implemented class with 020 * <code>@ org.dcm4che3.conf.api.upgrade.ScriptVersion</code> 021 * annotation to allow the upgrade runner to detect whether the script needs to be re-executed. 022 */ 023public interface UpgradeScript { 024 String NO_VERSION = "-NO_VERSION-"; 025 026 void upgrade(UpgradeContext upgradeContext) throws ConfigurationException; 027 028 class UpgradeContext { 029 030 private static final Logger log = LoggerFactory.getLogger(UpgradeContext.class); 031 032 private String fromVersion; 033 private String toVersion; 034 private Properties properties; 035 private Map<String, Object> scriptConfig; 036 private Configuration configuration; 037 private DicomConfiguration dicomConfiguration; 038 private UpgradeScriptMetadata upgradeScriptMetadata; 039 private ConfigurationMetadata configMetaData; 040 041 public UpgradeContext() { 042 } 043 044 public UpgradeContext(String fromVersion, String toVersion, Properties properties, Map<String, Object> scriptConfig, Configuration configuration, DicomConfiguration dicomConfiguration) { 045 this(fromVersion, toVersion, properties, scriptConfig, configuration, dicomConfiguration, null, null); 046 } 047 048 public UpgradeContext(String fromVersion, String toVersion, Properties properties, Map<String, Object> scriptConfig, Configuration configuration, DicomConfiguration dicomConfiguration, UpgradeScriptMetadata upgradeScriptMetadata) { 049 this(fromVersion, toVersion, properties, scriptConfig, configuration, dicomConfiguration, upgradeScriptMetadata, null); 050 } 051 052 public UpgradeContext(String fromVersion, String toVersion, Properties properties, Map<String, Object> scriptConfig, Configuration configuration, DicomConfiguration dicomConfiguration, UpgradeScriptMetadata upgradeScriptMetadata, ConfigurationMetadata configMetaData) { 053 this.fromVersion = fromVersion; 054 this.toVersion = toVersion; 055 this.properties = properties; 056 this.scriptConfig = scriptConfig; 057 this.configuration = configuration; 058 this.dicomConfiguration = dicomConfiguration; 059 this.upgradeScriptMetadata = upgradeScriptMetadata; 060 this.configMetaData = configMetaData; 061 } 062 063 064 public Object getFromVersion() { 065 return fromVersion; 066 } 067 068 public Object getToVersion() { 069 return toVersion; 070 } 071 072 public Configuration getConfiguration() { 073 return configuration; 074 } 075 076 public DicomConfiguration getDicomConfiguration() { 077 return dicomConfiguration; 078 } 079 080 public Properties getProperties() { 081 return properties; 082 } 083 084 public Map<String, Object> getScriptConfig() { 085 return scriptConfig; 086 } 087 088 public UpgradeScriptMetadata getUpgradeScriptMetadata() { 089 return upgradeScriptMetadata; 090 } 091 092 /** 093 * Allows to "fork" another script from the currently executed script.<br><br> 094 * This feature allows to refactor an existing script (script <b>A</b>) by extracting a part of it into a new script (script <b>B</b>). <br><br> 095 * To facilitate a simpler design, this method will pre-set some version for that new script (<b>B</b>), so the new script will "think" 096 * that it's not the first time it's executed. 097 * This covers the case when upgrading from an older version of <b>A</b> (when A+B was still a single script), so <b>B</b> will not think that it's a "clean installation" <br><br> 098 * <b>CAUTION:</b> It is important that <b>B</b> appears <i>after</i> <b>A</b> in upgrade-settings.json 099 * </b> 100 * 101 * @param forkedScript The <b>B</b> script. 102 * @param scriptVersion The version to set for the <b>B</b> script. 103 */ 104 public void forkScript(Class<? extends UpgradeScript> forkedScript, String scriptVersion) { 105 106 String scriptClass = forkedScript.getName(); 107 108 UpgradeScriptMetadata upgradeScriptMetadata = configMetaData.getMetadataOfUpgradeScripts().get(scriptClass); 109 110 if (upgradeScriptMetadata != null) { 111 log.warn("Attempted to fork script [" + scriptClass + "] that has already been executed (last executed version " + upgradeScriptMetadata.getLastVersionExecuted() + ")"); 112 return; 113 } 114 115 UpgradeScriptMetadata scriptMetadata = new UpgradeScriptMetadata(); 116 scriptMetadata.setLastVersionExecuted(scriptVersion); 117 118 configMetaData.getMetadataOfUpgradeScripts().put(scriptClass, scriptMetadata); 119 log.info("Forked upgrade script [" + scriptClass + "], initialized with version " + scriptVersion); 120 121 } 122 } 123 124 @ConfigurableClass 125 class UpgradeScriptMetadata { 126 127 /** 128 * The version of this upgrade script when it was last time executed, taken from @ScriptVersion 129 */ 130 @ConfigurableProperty(description = "The version of this upgrade script when it was last time executed") 131 String lastVersionExecuted; 132 133 public String getLastVersionExecuted() { 134 return lastVersionExecuted; 135 } 136 137 public void setLastVersionExecuted(String lastVersionExecuted) { 138 this.lastVersionExecuted = lastVersionExecuted; 139 } 140 } 141}