package com.constellio.app.services.appManagement; import static com.constellio.app.services.extensions.plugins.pluginInfo.ConstellioPluginStatus.ENABLED; import static com.constellio.app.services.extensions.plugins.pluginInfo.ConstellioPluginStatus.INVALID; import static com.constellio.app.services.extensions.plugins.pluginInfo.ConstellioPluginStatus.READY_TO_INSTALL; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Serializable; import java.io.StringReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.io.FileUtils; import org.apache.commons.io.input.CountingInputStream; import org.apache.commons.lang3.StringUtils; import org.apache.tika.io.IOUtils; import org.jdom2.Document; import org.jdom2.JDOMException; import org.jdom2.input.SAXBuilder; import org.joda.time.LocalDate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.constellio.app.entities.modules.ProgressInfo; import com.constellio.app.services.appManagement.AppManagementServiceException.CannotSaveOldPlugins; import com.constellio.app.services.appManagement.AppManagementServiceRuntimeException.AppManagementServiceRuntimeException_SameVersionsInDifferentFolders; import com.constellio.app.services.appManagement.AppManagementServiceRuntimeException.WarFileNotFound; import com.constellio.app.services.appManagement.AppManagementServiceRuntimeException.WarFileVersionMustBeHigher; import com.constellio.app.services.extensions.plugins.ConstellioPluginManager; import com.constellio.app.services.extensions.plugins.InvalidPluginJarException; import com.constellio.app.services.extensions.plugins.JSPFPluginServices; import com.constellio.app.services.extensions.plugins.PluginServices; import com.constellio.app.services.extensions.plugins.pluginInfo.ConstellioPluginInfo; import com.constellio.app.services.extensions.plugins.utils.PluginManagementUtils; import com.constellio.app.services.factories.AppLayerFactory; import com.constellio.app.services.migrations.VersionValidator; import com.constellio.app.services.migrations.VersionsComparator; import com.constellio.app.services.recovery.ConstellioVersionInfo; import com.constellio.app.services.recovery.UpgradeAppRecoveryService; import com.constellio.app.services.systemSetup.SystemGlobalConfigsManager; import com.constellio.app.utils.GradleFileVersionParser; import com.constellio.data.io.services.facades.FileService; import com.constellio.data.io.services.facades.IOServices; import com.constellio.data.io.services.zip.ZipService; import com.constellio.data.io.services.zip.ZipServiceException; import com.constellio.data.io.streamFactories.StreamFactory; import com.constellio.data.utils.TimeProvider; import com.constellio.model.conf.FoldersLocator; import com.constellio.model.conf.FoldersLocatorMode; import com.constellio.model.conf.FoldersLocatorRuntimeException; import com.constellio.model.services.migrations.ConstellioEIMConfigs; public class AppManagementService { private static final Logger LOGGER = LoggerFactory.getLogger(AppManagementService.class); static final String TEMP_DEPLOY_FOLDER = "AppManagementService-TempDeployFolder"; static final String WRITE_WAR_FILE_STREAM = "AppManagementService-WriteWarFile"; public static final String UPDATE_COMMAND = "UPDATE"; public static final String RESTART_COMMAND = "RESTART"; //public static final String URL_CHANGELOG = "http://update.constellio.com/changelog5_1"; //public static final String URL_WAR = "http://update.constellio.com/constellio5_1.war"; private static String SERVER_URL = "http://updatecenter.constellio.com:8080"; private static final int MAX_VERSION_TO_KEEP = 4; private final PluginServices pluginServices; private final ConstellioPluginManager pluginManager; private final SystemGlobalConfigsManager systemGlobalConfigsManager; private final FileService fileService; private final ZipService zipService; private final IOServices ioServices; private final FoldersLocator foldersLocator; protected final ConstellioEIMConfigs eimConfigs; private final UpgradeAppRecoveryService upgradeAppRecoveryService; public AppManagementService(AppLayerFactory appLayerFactory, FoldersLocator foldersLocator) { this.systemGlobalConfigsManager = appLayerFactory.getSystemGlobalConfigsManager(); this.pluginManager = appLayerFactory.getPluginManager(); this.fileService = appLayerFactory.getModelLayerFactory().getIOServicesFactory().newFileService(); this.zipService = appLayerFactory.getModelLayerFactory().getIOServicesFactory().newZipService(); this.foldersLocator = foldersLocator; this.ioServices = appLayerFactory.getModelLayerFactory().getIOServicesFactory().newIOServices(); this.eimConfigs = new ConstellioEIMConfigs(appLayerFactory.getModelLayerFactory().getSystemConfigurationsManager()); this.upgradeAppRecoveryService = appLayerFactory.newUpgradeAppRecoveryService(); this.pluginServices = new JSPFPluginServices(ioServices); } public void restart() throws AppManagementServiceException { File commandFile = foldersLocator.getWrapperCommandFile(); LOGGER.info("Sending command '" + RESTART_COMMAND + "' to wrapper command file '" + commandFile.getAbsolutePath() + "'"); try { writeCommand(commandFile, RESTART_COMMAND); } catch (IOException e) { throw new AppManagementServiceException.CannotWriteInCommandFile(commandFile, e); } } public void update(ProgressInfo progressInfo) throws AppManagementServiceException { ConstellioVersionInfo currentInstalledVersionInfo = getCurrentInstalledVersionInfo(); File warFile = foldersLocator.getUploadConstellioWarFile(); File tempFolder = fileService.newTemporaryFolder(TEMP_DEPLOY_FOLDER); if (!warFile.exists()) { throw new WarFileNotFound(); } String task = "Updating web application using war '" + warFile.getAbsolutePath() + "' with size " + warFile.length(); progressInfo.reset(); progressInfo.setEnd(1); progressInfo.setTask(task); LOGGER.info(task); try { String currentStep = "Unzipping war in temp folder '" + tempFolder + "'"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); try { zipService.unzip(warFile, tempFolder); } catch (ZipServiceException e) { throw new RuntimeException(e); } String warVersion = findWarVersion(tempFolder); String currentWarVersion = getWarVersion(); if (currentWarVersion == null || currentWarVersion.equals("5.0.5")) { currentWarVersion = GradleFileVersionParser.getVersion(); } currentStep = "Based on jar file, the version of the new war is '" + warVersion + "', current version is '" + currentWarVersion + "'"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); if (VersionsComparator.isFirstVersionBeforeSecond(warVersion, currentWarVersion)) { LOGGER.warn("Trying to install lower version " + warVersion + "\n\tCurrent version is " + currentWarVersion); throw new WarFileVersionMustBeHigher(); } currentStep = "Saving existing plugins to new version directory"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); File oldPluginsFolder = foldersLocator.getPluginsJarsFolder(); copyCurrentPlugins(oldPluginsFolder, tempFolder); movePluginsToNewLib(oldPluginsFolder, tempFolder); updatePluginsWithThoseInWar(tempFolder); File currentAppFolder = foldersLocator.getConstellioWebappFolder().getAbsoluteFile(); File deployFolder = findDeployFolder(currentAppFolder.getParentFile(), warVersion); currentStep = "Moving new webapp version in '" + deployFolder + "'"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); tempFolder.renameTo(deployFolder); currentStep = "Deleting war file"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); warFile.delete(); if (eimConfigs.isCleanDuringInstall()) { currentStep = "Deleting older versions"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); keepOnlyLastFiveVersionsAndAtLeastOneVersionModifiedBeforeLastWeek(currentAppFolder.getParentFile(), deployFolder); } currentStep = "Updating wrapper conf to boot on new version"; progressInfo.setProgressMessage(currentStep); LOGGER.info(currentStep); updateWrapperConf(deployFolder); upgradeAppRecoveryService.afterWarUpload(currentInstalledVersionInfo, new ConstellioVersionInfo(warVersion, deployFolder.getAbsolutePath())); } catch (AppManagementServiceException e) { //FIXME delete deployFolder if created and revert to previous wrapper conf then throw exception throw e; } finally { fileService.deleteQuietly(tempFolder); } progressInfo.setCurrentState(1); } private void updatePluginsWithThoseInWar(File nextWebapp) { updatePlugins(nextWebapp); installPlugins(nextWebapp); } private void installPlugins(File nextWebapp) { File pluginsFolder = new File(nextWebapp, "plugins-to-install"); if (pluginsFolder.exists() && pluginsFolder.listFiles() != null) { for (File pluginFile : pluginsFolder.listFiles()) { if (pluginFile.getName().toLowerCase().endsWith(".jar")) { LOGGER.info(pluginsFolder.getName() + "/" + pluginFile.getName() + ".jar : installed"); pluginManager.prepareInstallablePluginInNextWebapp(pluginFile, nextWebapp); } } } } private void updatePlugins(File nextWebapp) { File pluginsFolder = new File(nextWebapp, "plugins-to-update"); if (pluginsFolder.exists() && pluginsFolder.listFiles() != null) { Set<String> alreadyInstalledPlugins = new HashSet<>(); for (ConstellioPluginInfo info : pluginManager.getPlugins(ENABLED, READY_TO_INSTALL, INVALID)) { alreadyInstalledPlugins.add(info.getCode()); } for (File pluginFile : pluginsFolder.listFiles()) { if (pluginFile.getName().toLowerCase().endsWith(".jar")) { try { ConstellioPluginInfo info = pluginServices.extractPluginInfo(pluginFile); if (alreadyInstalledPlugins.contains(info.getCode())) { LOGGER.info(pluginsFolder.getName() + "/" + pluginFile.getName() + ".jar : installed"); pluginManager.prepareInstallablePluginInNextWebapp(pluginFile, nextWebapp); } else { LOGGER.info(pluginsFolder.getName() + "/" + pluginFile.getName() + ".jar : deleted"); pluginFile.delete(); } } catch (InvalidPluginJarException e) { throw new RuntimeException(e); } } } } } private void movePluginsToNewLib(File oldPluginsFolder, File newWebAppFolder) throws CannotSaveOldPlugins { File newLibsFolder = foldersLocator.getLibFolder(newWebAppFolder); LOGGER.info("plugins : copy to lib " + newLibsFolder.getPath()); File pluginsToMoveFile = foldersLocator.getPluginsToMoveOnStartupFile(newWebAppFolder); PluginManagementUtils utils = new PluginManagementUtils(oldPluginsFolder, newLibsFolder, pluginsToMoveFile); try { utils.movePlugins(pluginManager.getPluginsOfEveryStatus()); } catch (IOException e) { throw new CannotSaveOldPlugins(e); } } private void copyCurrentPlugins(File oldPluginsFolder, File newWebAppFolder) throws CannotSaveOldPlugins { if (oldPluginsFolder.exists()) { try { LOGGER.info("plugins : copy to " + newWebAppFolder); LOGGER.info("plugins : copy from ", oldPluginsFolder.getPath() + "to " + foldersLocator.getPluginsJarsFolder(newWebAppFolder).getPath()); FileUtils.copyDirectory(oldPluginsFolder, foldersLocator.getPluginsJarsFolder(newWebAppFolder)); } catch (IOException e) { throw new CannotSaveOldPlugins(e); } } } private void keepOnlyLastFiveVersionsAndAtLeastOneVersionModifiedBeforeLastWeek(File webAppsFolder, File deployFolder) { Map<String, File> existingWebAppsMappedByVersion = getExistingVersionsFoldersMappedByVersion(webAppsFolder, deployFolder); if (existingWebAppsMappedByVersion.size() > MAX_VERSION_TO_KEEP) { Set<String> orderedVersions = new TreeSet<>(new VersionsComparator()); orderedVersions.addAll(existingWebAppsMappedByVersion.keySet()); int versionsToRemoveCount = existingWebAppsMappedByVersion.size() - MAX_VERSION_TO_KEEP; Iterator<String> versionsIterator = orderedVersions.iterator(); int handledVersions = 0; boolean atLeastOneVersionBeforeLastWeek = false; while (versionsIterator.hasNext()) { String version = versionsIterator.next(); handledVersions++; if (handledVersions > versionsToRemoveCount) { File webAppToRemove = existingWebAppsMappedByVersion.get(version); existingWebAppsMappedByVersion.remove(version); if (isModifiedBeforeLastWeek(webAppToRemove)) { atLeastOneVersionBeforeLastWeek = true; } } } if (!atLeastOneVersionBeforeLastWeek) { removeAllFilesAndKeepTheNewestOneBeforeLastWeek(existingWebAppsMappedByVersion.values()); } else { removeAllFiles(existingWebAppsMappedByVersion.values()); } } } private void removeAllFilesAndKeepTheNewestOneBeforeLastWeek(Collection<File> files) { List<File> filesList = new ArrayList<>(files); Collections.sort(filesList, new Comparator<File>() { @Override public int compare(File o1, File o2) { LocalDate modificationDate1 = new LocalDate(o1.lastModified()); LocalDate modificationDate2 = new LocalDate(o1.lastModified()); return modificationDate1.compareTo(modificationDate2); } }); for (int i = 0; i < filesList.size() - 1; i++) { File file = filesList.get(i); FileUtils.deleteQuietly(file); } File lastFile = filesList.get(filesList.size() - 1); if (!isModifiedBeforeLastWeek(lastFile)) { FileUtils.deleteQuietly(lastFile); } } private void removeAllFiles(Collection<File> files) { for (File file : files) { FileUtils.deleteQuietly(file); } } boolean isModifiedBeforeLastWeek(File webAppsFolder) { return new LocalDate(webAppsFolder.lastModified()).isBefore(TimeProvider.getLocalDate().minusDays(7)); } private Map<String, File> getExistingVersionsFoldersMappedByVersion(File webAppsFolder, File deployFolder) { Map<String, File> existingWebAppsMappedByVersion = new HashMap<>(); for (File webApp : webAppsFolder.listFiles(new WebAppFileNameFilter())) { String version = getWarVersionFromFileName(webApp); if (VersionValidator.isValidVersion(version) && !webApp.getName().equals(deployFolder.getName())) { File associatedWebAppFolder = existingWebAppsMappedByVersion.get(version); if (associatedWebAppFolder != null) { throw new AppManagementServiceRuntimeException_SameVersionsInDifferentFolders(version, webApp.getName(), associatedWebAppFolder.getName()); } else { existingWebAppsMappedByVersion.put(version, webApp); } } } return existingWebAppsMappedByVersion; } private void updateWrapperConf(File deployFolder) { LOGGER.info("New webapp path is '" + deployFolder.getAbsolutePath() + "'"); File wrapperConf = foldersLocator.getWrapperConf(); if (foldersLocator.getFoldersLocatorMode().equals(FoldersLocatorMode.PROJECT) && !wrapperConf.exists()) { return; } List<String> lines = fileService.readFileToLinesWithoutExpectableIOException(wrapperConf); for (int i = 0; i < lines.size(); i++) { String line = lines.get(i); if (line.startsWith("wrapper.java.classpath.2=")) { lines.set(i, "wrapper.java.classpath.2=" + deployFolder.getAbsolutePath() + "/WEB-INF/lib/*.jar"); } if (line.startsWith("wrapper.java.classpath.3=")) { lines.set(i, "wrapper.java.classpath.3=" + deployFolder.getAbsolutePath() + "/WEB-INF/classes"); } if (line.startsWith("wrapper.commandfile=")) { lines.set(i, "wrapper.commandfile=" + deployFolder.getAbsolutePath() + "/WEB-INF/command/cmd"); } } fileService.writeLinesToFile(wrapperConf, lines); } File findDeployFolder(File parent, String version) { File deployFolder = null; String mostRecentVersion = ""; for (File currentWebApp : parent.listFiles(new WebAppWithValidSubversionFilenameFilter(version))) { String currentVersion = StringUtils.substringAfter(currentWebApp.getName(), "webapp-"); if (mostRecentVersion.isEmpty()) { deployFolder = currentWebApp; mostRecentVersion = currentVersion; } else { if (VersionsComparator.isFirstVersionBeforeSecond(mostRecentVersion, currentVersion)) { deployFolder = currentWebApp; mostRecentVersion = currentVersion; } } } int nextSubVersion; if (mostRecentVersion.isEmpty()) { deployFolder = new File(parent, "webapp-" + version); nextSubVersion = 0; } else if (mostRecentVersion.contains("-")) { nextSubVersion = Integer.valueOf(mostRecentVersion.split("-")[1]); } else { nextSubVersion = 0; } nextSubVersion++; while (deployFolder.exists()) { deployFolder = new File(parent, "webapp-" + version + "-" + nextSubVersion); nextSubVersion++; } return deployFolder; } private String findWarVersion(File tempFolder) { File webInf = new File(tempFolder, "WEB-INF"); File libs = new File(webInf, "lib"); if (libs.listFiles() != null) { for (File lib : libs.listFiles()) { if (lib.getName().startsWith("core-model-")) { return lib.getName().replace("core-model-", "").replace(".jar", ""); } } } throw new RuntimeException("Cannot recover war version in " + libs.getAbsolutePath()); } private void writeCommand(File file, String command) throws IOException { fileService.replaceFileContent(file, command); } public boolean isWarFileUploaded() { File warFile = foldersLocator.getUploadConstellioWarFile(); return warFile.exists(); } public StreamFactory<OutputStream> getWarFileDestination() { File warFile = foldersLocator.getUploadConstellioWarFile(); return ioServices.newOutputStreamFactory(warFile, WRITE_WAR_FILE_STREAM); } public String getWarVersion() { return getWarVersion(null); } private String getWarVersion(File webAppFolder) { try { File webappLibs; if (webAppFolder == null) { webappLibs = foldersLocator.getLibFolder(); } else { webappLibs = foldersLocator.getLibFolder(webAppFolder); } if (webappLibs.exists()) { for (File lib : webappLibs.listFiles()) { if (lib.getName().startsWith("core-model-") && lib.getName().endsWith(".jar")) { return lib.getName().replace("core-model-", "").replace(".jar", ""); } } } } catch (FoldersLocatorRuntimeException.NotAvailableInGitMode e) { } return "5.0.0"; } private String getWarVersionFromFileName(File webAppFolder) { String folderName = webAppFolder.getName(); if (folderName.startsWith("webapp-")) { return StringUtils.substringAfter(folderName, "webapp-"); } else { return getWarVersion(webAppFolder); } } public String getChangelogURLFromServer() throws AppManagementServiceRuntimeException.CannotConnectToServer { String serverUrl = SERVER_URL + "/changelog/"; String changelogURL; try { changelogURL = sendPost(serverUrl, getInfosToSend()); } catch (IOException ioe) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(serverUrl); } return changelogURL; } public String getWarURLFromServer() throws AppManagementServiceRuntimeException.CannotConnectToServer { String serverUrl = SERVER_URL + "/url/"; String warURL; try { warURL = sendPost(serverUrl, getInfosToSend()); } catch (IOException ioe) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(serverUrl); } return warURL; } String getInfosToSend() { String delimiter = "*"; return getLicenseInfo().getSignature() + delimiter + getCurrentInstalledVersionInfo().getVersion(); } String sendPost(String url, String infoSent) throws IOException { StringBuilder response = new StringBuilder(); BufferedReader in = new BufferedReader(new InputStreamReader(getInputForPost(url, infoSent))); String inputLine; while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); return response.toString(); } InputStream getInputForPost(String url, String infoSent) throws IOException { URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); con.setDoOutput(true); DataOutputStream wr = new DataOutputStream(con.getOutputStream()); wr.writeBytes(infoSent); wr.flush(); wr.close(); return con.getInputStream(); } public String getChangelogFromServer() throws AppManagementServiceRuntimeException.CannotConnectToServer { String URL_CHANGELOG = getChangelogURLFromServer(); String changelog = ""; try { InputStream stream = getInputForPost(URL_CHANGELOG, getLicenseInfo().getSignature()); if (stream == null) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(URL_CHANGELOG); } BufferedReader in = new BufferedReader(new InputStreamReader(stream)); try { String inputLine; while ((inputLine = in.readLine()) != null) { changelog += inputLine; } if (this.isProxyPage(changelog)) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(URL_CHANGELOG); } } finally { IOUtils.closeQuietly(in); } } catch (IOException | RuntimeException io) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(URL_CHANGELOG, io); } return changelog; } public String getVersionFromServer() throws AppManagementServiceRuntimeException.CannotConnectToServer { String serverUrl = SERVER_URL + "/version/"; try { serverUrl = sendPost(serverUrl, getInfosToSend()); } catch (IOException ioe) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(serverUrl); } return serverUrl; } boolean isProxyPage(String changelog) { return !changelog.contains("<version>"); } public void getWarFromServer(ProgressInfo progressInfo) throws AppManagementServiceRuntimeException.CannotConnectToServer { String URL_WAR = getWarURLFromServer(); System.out.println("URL FOR WAR => " + URL_WAR); try { progressInfo.reset(); progressInfo.setTask("Getting WAR from server"); progressInfo.setEnd(1); progressInfo.setProgressMessage("Downloading WAR"); InputStream input = getInputForPost(URL_WAR, getLicenseInfo().getSignature()); if (input == null) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(URL_WAR); } CountingInputStream countingInputStream = new CountingInputStream(input); progressInfo.setProgressMessage("Creating WAR file"); OutputStream warFileOutput = getWarFileDestination().create("war upload"); try { progressInfo.setProgressMessage("Copying downloaded WAR"); byte[] buffer = new byte[8 * 1024]; int bytesRead; while ((bytesRead = countingInputStream.read(buffer)) != -1) { warFileOutput.write(buffer, 0, bytesRead); long totalBytesRead = countingInputStream.getByteCount(); String progressMessage = FileUtils.byteCountToDisplaySize(totalBytesRead); progressInfo.setProgressMessage(progressMessage); } } finally { IOUtils.closeQuietly(countingInputStream); IOUtils.closeQuietly(warFileOutput); } progressInfo.setCurrentState(1); } catch (IOException ioe) { throw new AppManagementServiceRuntimeException.CannotConnectToServer(URL_WAR, ioe); } } public String getWebappFolderName() { return foldersLocator.getConstellioWebappFolder().getName(); } public void markForReindexing() { systemGlobalConfigsManager.setMarkedForReindexing(true); } public boolean isLicensedForAutomaticUpdate() { return getLicenseInfo() != null; } public void storeLicense(File uploadLicenseFile) { File licenseFile = foldersLocator.getLicenseFile(); ioServices.copyFileWithoutExpectableIOException(uploadLicenseFile, licenseFile); } public LicenseInfo getLicenseInfo() { LicenseInfo license = null; try { String licenseString = ioServices.readFileToString(foldersLocator.getLicenseFile()); SAXBuilder builder = new SAXBuilder(); Document document = builder.build(new StringReader(licenseString)); String name = document.getRootElement().getChild("name").getContent().get(0).getValue(); LocalDate date = new LocalDate(document.getRootElement().getChild("date").getContent().get(0).getValue()); String signature = document.getRootElement().getChild("signature").getContent().get(0).getValue(); license = new LicenseInfo(name, date, signature); } catch (IOException ioe) { } catch (JDOMException joe) { } return license; } private ConstellioVersionInfo getCurrentInstalledVersionInfo() { File versionDirectory = foldersLocator.getConstellioWebappFolder(); String version = getWarVersion(versionDirectory); return new ConstellioVersionInfo(version, versionDirectory.getAbsolutePath()); } public void pointToVersionDuringApplicationStartup(ConstellioVersionInfo constellioVersionInfo) { updateWrapperConf(new File(constellioVersionInfo.getVersionDirectoryPath())); } private class WebAppFileNameFilter implements FilenameFilter { @Override public boolean accept(File dir, String name) { return name.startsWith("webapp-"); } } private class WebAppWithValidSubversionFilenameFilter implements FilenameFilter { final String version; public WebAppWithValidSubversionFilenameFilter( String version) { this.version = version; } @Override public boolean accept(File dir, String name) { if (name.equals("webapp-" + version)) { return true; } if (name.startsWith("webapp-" + version + "-")) { String currentVersion = StringUtils.substringAfter(name, "webapp-"); if (VersionValidator.isValidVersion(currentVersion)) { return true; } } return false; } } public static class LicenseInfo implements Serializable { private final String clientName; private final LocalDate expirationDate; private final String signature; public LicenseInfo(String clientName, LocalDate expirationDate, String signature) { this.clientName = clientName; this.expirationDate = expirationDate; this.signature = signature; } public String getClientName() { return clientName; } public LocalDate getExpirationDate() { return expirationDate; } public String getSignature() { return signature; } } }