001package org.dcm4che3.conf.api.upgrade;
002
003import org.dcm4che3.conf.core.api.ConfigurationException;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007import java.lang.reflect.Method;
008import java.util.Map;
009import java.util.TreeMap;
010
011public class VersionDrivenUpgradeScript implements UpgradeScript {
012
013    private static Logger log = LoggerFactory.getLogger(VersionDrivenUpgradeScript.class);
014
015
016    private UpgradeContext upgradeContext;
017
018    protected UpgradeContext getUpgradeContext() {
019        return upgradeContext;
020    }
021
022    @Override
023    public void upgrade(UpgradeContext upgradeContext) throws ConfigurationException {
024
025        init(upgradeContext);
026
027        if (firstTimeRun()) {
028            Method firstRunMethod = getFirstRunMethod();
029            log.info("Running upgrade script " + this.getClass().getName() + " for the first time - invoking method " + firstRunMethod.getName());
030            invokeMethod(firstRunMethod);
031
032        } else
033            runFixUps(MMPVersion.fromStringVersion(getUpgradeContext().getUpgradeScriptMetadata().getLastVersionExecuted()));
034    }
035
036    public void init(UpgradeContext upgradeContext) {
037        this.upgradeContext = upgradeContext;
038    }
039
040    private void runFixUps(MMPVersion lastExVer) {
041        TreeMap<MMPVersion, Method> methods = getFixUpMethods(lastExVer);
042
043        for (Map.Entry<MMPVersion, Method> methodEntry : methods.entrySet()) {
044            log.info("[" + this.getClass().getName() + "] Invoking fix-up method " + methodEntry.getValue().getName() + " (fixUpTo " + methodEntry.getKey() + ")");
045            invokeMethod(methodEntry.getValue());
046        }
047    }
048
049
050    public Method getFirstRunMethod() {
051        for (Method method : this.getClass().getDeclaredMethods()) {
052            if (method.getAnnotation(UpgradeGoalFromScratch.class) != null) {
053                return method;
054            }
055        }
056        throw new RuntimeException("Method annotated with 'UpgradeGoalFromScratch' not found in " + this.getClass().getName());
057    }
058
059    public TreeMap<MMPVersion, Method> getFixUpMethods(MMPVersion lastExVer) {
060        // Fix-ups are ran ordered according to @FixUpTo's values thus TreeMap
061        TreeMap<MMPVersion, Method> methods = new TreeMap<MMPVersion, Method>();
062
063        for (Method method : this.getClass().getDeclaredMethods()) {
064            FixUpTo annotation = method.getAnnotation(FixUpTo.class);
065
066            if (annotation != null) {
067
068                MMPVersion mmpVersion = MMPVersion.fromFixUpToAnno(annotation);
069
070                if (mmpVersion.compareTo(lastExVer) <= 0)
071                    methods.put(mmpVersion, method);
072            }
073        }
074        return methods;
075    }
076
077    private void invokeMethod(Method m) {
078        try {
079            m.invoke(this);
080        } catch (Exception e) {
081            throw new RuntimeException("Cannot invoke a method of an upgrade script " + this.getClass().getName() + " . " + m.getName(), e);
082        }
083    }
084
085    private boolean firstTimeRun() {
086        try {
087            return getUpgradeContext().getUpgradeScriptMetadata().getLastVersionExecuted().equals(NO_VERSION);
088        } catch (NullPointerException e) {
089            return true;
090        }
091    }
092
093}