001package ca.uhn.fhir.jpa.migrate.tasks.api;
002
003/*-
004 * #%L
005 * HAPI FHIR Server - SQL Migration
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.i18n.Msg;
024import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask;
025import com.google.common.collect.Multimap;
026import com.google.common.collect.MultimapBuilder;
027import org.apache.commons.lang3.EnumUtils;
028import org.apache.commons.lang3.Validate;
029import org.flywaydb.core.api.MigrationVersion;
030
031import javax.annotation.Nonnull;
032import java.util.ArrayList;
033import java.util.Collection;
034import java.util.List;
035
036public class BaseMigrationTasks<T extends Enum> {
037        MigrationVersion lastVersion;
038        private Multimap<T, BaseTask> myTasks = MultimapBuilder.hashKeys().arrayListValues().build();
039
040        @SuppressWarnings("unchecked")
041        public List<BaseTask> getTasks(@Nonnull T theFrom, @Nonnull T theTo) {
042                Validate.notNull(theFrom);
043                Validate.notNull(theTo);
044                Validate.isTrue(theFrom.ordinal() < theTo.ordinal(), "From version must be lower than to version");
045
046                List<BaseTask> retVal = new ArrayList<>();
047                for (Object nextVersion : EnumUtils.getEnumList(theFrom.getClass())) {
048                        if (((T) nextVersion).ordinal() <= theFrom.ordinal()) {
049                                continue;
050                        }
051                        if (((T) nextVersion).ordinal() > theTo.ordinal()) {
052                                continue;
053                        }
054
055                        Collection<BaseTask> nextValues = myTasks.get((T) nextVersion);
056                        if (nextValues != null) {
057                                retVal.addAll(nextValues);
058                        }
059                }
060
061                return retVal;
062        }
063
064        public Builder forVersion(T theRelease) {
065                IAcceptsTasks sink = theTask -> {
066                        theTask.validate();
067                        myTasks.put(theRelease, theTask);
068                };
069                return new Builder(toReleaseName(theRelease), sink);
070        }
071
072        @Nonnull
073        protected String toReleaseName(T theRelease) {
074                return theRelease.name();
075        }
076
077        public List<BaseTask> getAllTasks(T[] theVersionEnumValues) {
078                List<BaseTask> retval = new ArrayList<>();
079                for (T nextVersion : theVersionEnumValues) {
080                        Collection<BaseTask> nextValues = myTasks.get(nextVersion);
081                        if (nextValues != null) {
082                                validate(nextValues);
083                                retval.addAll(nextValues);
084                        }
085                }
086
087                return retval;
088        }
089
090        protected BaseTask getTaskWithVersion(String theFlywayVersion) {
091                return myTasks.values().stream()
092                        .filter(task -> theFlywayVersion.equals(task.getFlywayVersion()))
093                        .findFirst()
094                        .get();
095        }
096
097        void validate(Collection<BaseTask> theTasks) {
098                for (BaseTask task : theTasks) {
099                        task.validateVersion();
100                        String version = task.getFlywayVersion();
101                        MigrationVersion migrationVersion = MigrationVersion.fromVersion(version);
102                        if (lastVersion != null) {
103                                if (migrationVersion.compareTo(lastVersion) <= 0) {
104                                        throw new IllegalStateException(Msg.code(51) + "Migration version " + migrationVersion + " found after migration version " + lastVersion + ".  Migrations need to be in order by version number.");
105                                }
106                        }
107                        lastVersion = migrationVersion;
108                }
109        }
110
111        public interface IAcceptsTasks {
112                void addTask(BaseTask theTask);
113        }
114}