001/*
002 * (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.runtime.migration;
020
021/**
022 * Migration Service.
023 *
024 * @since 9.3
025 */
026public interface MigrationService {
027
028    /**
029     * Interface for the implementation of status change notification.
030     *
031     * @since 9.3
032     */
033    interface StatusChangeNotifier {
034
035        /**
036         * Allows notification of running step or new state.
037         */
038        void notifyStatusChange();
039    }
040
041    /**
042     * Interface for the implementation of a migration step.
043     *
044     * @since 9.3
045     */
046    interface Migrator {
047
048        /**
049         * Runs the migration.
050         * <p>
051         * This method should periodically check for {@link MigrationContext#isShutdownRequested} and
052         * {@link Thread#isInterrupted} and return if {@code true}.
053         *
054         * @param migrationContext the migration context.
055         */
056        void run(MigrationContext migrationContext);
057    }
058
059    /**
060     * Interface for a migration context, passed to the {@link Migrator}.
061     *
062     * @since 9.3
063     */
064    interface MigrationContext {
065
066        /**
067         * Notifies the migration context of the current progress.
068         *
069         * @param message an informative message about what is being migrated
070         * @param num the current number of things migrated
071         * @param total the total number of things to migrate, or {@code -1} if unknown
072         */
073        void reportProgress(String message, long num, long total);
074
075        /**
076         * Requests a shutdown. Called internally by the migration service when the server shuts down.
077         */
078        void requestShutdown();
079
080        /**
081         * Checks if shutdown has been requested.
082         * <p>
083         * This should be checked periodically by the migrator, and when {@code true} the migrator should return as soon
084         * as possible, even if its work is not complete.
085         * <p>
086         * This is a "nice" version of thread interruption, which will follow a short while later, and should also be
087         * checked by the migrator.
088         *
089         * @return {@code true} if migration should be stopped as soon as possible
090         */
091        boolean isShutdownRequested();
092    }
093
094    /**
095     * The status of a migration.
096     * <p>
097     * A migration is either running or not. When not running, it just has a state.
098     * <p>
099     * When running, it has a step, start time, and progress information (message, num, total, last ping time).
100     *
101     * @since 9.3
102     */
103    public class MigrationStatus {
104
105        protected final String state;
106
107        protected final String step;
108
109        protected final long startTime;
110
111        protected final long pingTime;
112
113        protected final String progressMessage;
114
115        protected final long progressNum;
116
117        protected final long progressTotal;
118
119        public MigrationStatus(String state) {
120            this.state = state;
121            step = null;
122            startTime = 0;
123            pingTime = 0;
124            progressMessage = null;
125            progressNum = 0;
126            progressTotal = 0;
127        }
128
129        public MigrationStatus(String step, long startTime, long pingTime, String progressMessage, long progressNum,
130                long progressTotal) {
131            state = null;
132            this.step = step;
133            this.startTime = startTime;
134            this.pingTime = pingTime;
135            this.progressMessage = progressMessage;
136            this.progressNum = progressNum;
137            this.progressTotal = progressTotal;
138        }
139
140        /**
141         * Checks whether the migration is running.
142         *
143         * @return {@code true} if a migration is running, or {@code false} otherwise
144         */
145        public boolean isRunning() {
146            return state == null;
147        }
148
149        /**
150         * Gets the state of the migration, if it's not running.
151         */
152        public String getState() {
153            return state;
154        }
155
156        /**
157         * Gets the step of the migration, if it's running.
158         */
159        public String getStep() {
160            return step;
161        }
162
163        /**
164         * Gets the start time of the migration, if it's running.
165         */
166        public long getStartTime() {
167            return startTime;
168        }
169
170        /**
171         * Gets the ping time of the migration, if it's running.
172         */
173        public long getPingTime() {
174            return pingTime;
175        }
176
177        /**
178         * Gets the progress message of the migration, if it's running.
179         */
180        public String getProgressMessage() {
181            return progressMessage;
182        }
183
184        /**
185         * Gets the progress "num" of the migration, if it's running.
186         */
187        public long getProgressNum() {
188            return progressNum;
189        }
190
191        /**
192         * Gets the progress "total" of the migration, if it's running.
193         */
194        public long getProgressTotal() {
195            return progressTotal;
196        }
197    }
198
199    /**
200     * Gets the current status for a migration.
201     *
202     * @param id the migration id
203     * @return the status, or {@code null} if the migration is unknown
204     */
205    MigrationStatus getStatus(String id);
206
207    /**
208     * Runs a migration step for a migration.
209     * <p>
210     * This launches the migration asynchronously. The status of the migration can be checked with {@link #getStatus}.
211     *
212     * @param id the migration id
213     * @param step the step id
214     */
215    void runStep(String id, String step);
216
217}