/*
* Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com]
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.ks.version;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import de.ks.SubclassInstantiator;
import de.ks.launch.Launcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Versioning {
private static final Logger log = LoggerFactory.getLogger(Versioning.class);
public static final String VERSION_PACKAGES = "version.packages";
public static final String VERSION_PROPERTIES_FILENAME = "version.properties";
public static final String PACKAGE_SEPARATOR = Launcher.PACKAGE_SEPARATOR;
public static final String APP_VERSION = "app.version";
private final ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newCachedThreadPool(new ThreadFactoryBuilder().setDaemon(true).setNameFormat("versioning-%d").build());
private final File versionFile;
private final Class<?> owner;
private final VersionInfo versionInfo;
private final SubclassInstantiator instantiator;
public Versioning(File versionFile, Class<?> owner) {
this.versionFile = versionFile;
this.owner = owner;
versionInfo = new VersionInfo(owner);
executorService.setKeepAliveTime(1, TimeUnit.SECONDS);
instantiator = new SubclassInstantiator(executorService, getClass().getPackage(), VERSION_PROPERTIES_FILENAME, VERSION_PACKAGES, PACKAGE_SEPARATOR);
}
public boolean isInitialImport() {
return getLastVersion() == -1;
}
public int getCurrentVersion() {
return versionInfo.getVersion();
}
public VersionInfo getVersionInfo() {
return versionInfo;
}
public int getLastVersion() {
try (FileInputStream stream = new FileInputStream(versionFile)) {
Properties properties = new Properties();
properties.load(stream);
String value = properties.getProperty(APP_VERSION, "-1");
return Integer.valueOf(value);
} catch (IOException e) {
log.warn("No {} present, will assume version -1", versionFile);
return -1;
}
}
public void writeLastVersion(int version) {
if (!versionFile.exists()) {
try {
versionFile.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
try (FileOutputStream fileOutputStream = new FileOutputStream(versionFile)) {
Properties properties = new Properties();
properties.setProperty(APP_VERSION, String.valueOf(version));
properties.store(fileOutputStream, "42");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void upgradeToCurrentVersion() {
if (isInitialImport()) {
getInitialImportRunners().forEach(r -> r.performInitialImport());
writeLastVersion(getCurrentVersion());
} else if (getLastVersion() < getCurrentVersion()) {
List<VersionUpgrade> upgraders = getVersionUpgrades();
Collections.sort(upgraders);
upgraders.stream().filter(upgrader -> upgrader.getVersion() > getLastVersion()).forEach(upgrader -> {
log.info("Performing upgrade from version {} to {} using {}", getLastVersion(), upgrader.getVersion(), upgrader.getClass().getSimpleName());
upgrader.performUpgrade();
});
writeLastVersion(getCurrentVersion());
} else {
log.debug("no upgrade nessessary");
}
}
protected List<InitialImport> getInitialImportRunners() {
List<InitialImport> importers = instantiator.instantiateSubclasses(InitialImport.class);
log.debug("Found {} initial importers: {}", importers.size(), importers);
return importers;
}
protected List<VersionUpgrade> getVersionUpgrades() {
List<VersionUpgrade> upgraders = instantiator.instantiateSubclasses(VersionUpgrade.class);
log.debug("Found {} initial importers: {}", upgraders.size(), upgraders);
return upgraders;
}
}