001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.store.kahadb.scheduler.legacy;
018
019import java.io.File;
020import java.io.IOException;
021import java.util.List;
022import java.util.Set;
023
024import org.apache.activemq.store.kahadb.data.KahaAddScheduledJobCommand;
025import org.apache.activemq.store.kahadb.scheduler.JobSchedulerStoreImpl;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * Used to upgrade a Legacy Job Scheduler store to the latest version this class
031 * loads a found legacy scheduler store and generates new add commands for all
032 * jobs currently in the store.
033 */
034public class LegacyStoreReplayer {
035
036    static final Logger LOG = LoggerFactory.getLogger(LegacyStoreReplayer.class);
037
038    private LegacyJobSchedulerStoreImpl store;
039    private final File legacyStoreDirectory;
040
041    /**
042     * Creates a new Legacy Store Replayer with the given target store
043     * @param directory
044     */
045    public LegacyStoreReplayer(File directory) {
046        this.legacyStoreDirectory = directory;
047    }
048
049    /**
050     * Loads the legacy store and prepares it for replay into a newer Store instance.
051     *
052     * @throws IOException if an error occurs while reading in the legacy store.
053     */
054    public void load() throws IOException {
055
056        store = new LegacyJobSchedulerStoreImpl();
057        store.setDirectory(legacyStoreDirectory);
058        store.setFailIfDatabaseIsLocked(true);
059
060        try {
061            store.start();
062        } catch (IOException ioe) {
063            LOG.warn("Legacy store load failed: ", ioe);
064            throw ioe;
065        } catch (Exception e) {
066            LOG.warn("Legacy store load failed: ", e);
067            throw new IOException(e);
068        }
069    }
070
071    /**
072     * Unloads a previously loaded legacy store to release any resources associated with it.
073     *
074     * Once a store is unloaded it cannot be replayed again until it has been reloaded.
075     * @throws IOException
076     */
077    public void unload() throws IOException {
078
079        if (store != null) {
080            try {
081                store.stop();
082            } catch (Exception e) {
083                LOG.warn("Legacy store unload failed: ", e);
084                throw new IOException(e);
085            } finally {
086                store = null;
087            }
088        }
089    }
090
091    /**
092     * Performs a replay of scheduled jobs into the target JobSchedulerStore.
093     *
094     * @param targetStore
095     *      The JobSchedulerStore that will receive the replay events from the legacy store.
096     *
097     * @throws IOException if an error occurs during replay of the legacy store.
098     */
099    public void startReplay(JobSchedulerStoreImpl targetStore) throws IOException {
100        checkLoaded();
101
102        if (targetStore == null) {
103            throw new IOException("Cannot replay to a null store");
104        }
105
106        try {
107            Set<String> schedulers = store.getJobSchedulerNames();
108            if (!schedulers.isEmpty()) {
109
110                for (String name : schedulers) {
111                    LegacyJobSchedulerImpl scheduler = store.getJobScheduler(name);
112                    LOG.info("Replay of legacy store {} starting.", name);
113                    replayScheduler(scheduler, targetStore);
114                }
115            }
116
117            LOG.info("Replay of legacy store complate.");
118        } catch (IOException ioe) {
119            LOG.warn("Failed during replay of legacy store: ", ioe);
120            throw ioe;
121        } catch (Exception e) {
122            LOG.warn("Failed during replay of legacy store: ", e);
123            throw new IOException(e);
124        }
125    }
126
127    private final void replayScheduler(LegacyJobSchedulerImpl legacy, JobSchedulerStoreImpl target) throws Exception {
128        List<LegacyJobImpl> jobs = legacy.getAllJobs();
129
130        String schedulerName = legacy.getName();
131
132        for (LegacyJobImpl job : jobs) {
133            LOG.trace("Storing job from legacy store to new store: {}", job);
134            KahaAddScheduledJobCommand newJob = new KahaAddScheduledJobCommand();
135            newJob.setScheduler(schedulerName);
136            newJob.setJobId(job.getJobId());
137            newJob.setStartTime(job.getStartTime());
138            newJob.setCronEntry(job.getCronEntry());
139            newJob.setDelay(job.getDelay());
140            newJob.setPeriod(job.getPeriod());
141            newJob.setRepeat(job.getRepeat());
142            newJob.setNextExecutionTime(job.getNextExecutionTime());
143            newJob.setPayload(job.getPayload());
144
145            target.store(newJob);
146        }
147    }
148
149    private final void checkLoaded() throws IOException {
150        if (this.store == null) {
151            throw new IOException("Cannot replay until legacy store is loaded.");
152        }
153    }
154}