From c3d8055cedf08ed4a28573f3ea043876c7c96780 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 15 Nov 2012 14:56:05 +0100 Subject: [PATCH] improve upgrade procedure --- .../sonia/scm/upgrade/UpgradeHandler.java | 62 ++++ .../java/sonia/scm/ScmContextListener.java | 3 +- .../java/sonia/scm/ScmUpgradeHandler.java | 327 ------------------ .../scm/upgrade/TimestampUpgradeHandler.java | 226 ++++++++++++ .../sonia/scm/upgrade/UpgradeManager.java | 255 ++++++++++++++ .../sonia/scm/upgrade/XmlUpgradeHandler.java | 137 ++++++++ 6 files changed, 682 insertions(+), 328 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/upgrade/UpgradeHandler.java delete mode 100644 scm-webapp/src/main/java/sonia/scm/ScmUpgradeHandler.java create mode 100644 scm-webapp/src/main/java/sonia/scm/upgrade/TimestampUpgradeHandler.java create mode 100644 scm-webapp/src/main/java/sonia/scm/upgrade/UpgradeManager.java create mode 100644 scm-webapp/src/main/java/sonia/scm/upgrade/XmlUpgradeHandler.java diff --git a/scm-core/src/main/java/sonia/scm/upgrade/UpgradeHandler.java b/scm-core/src/main/java/sonia/scm/upgrade/UpgradeHandler.java new file mode 100644 index 0000000000..3abd5ba660 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/upgrade/UpgradeHandler.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.upgrade; + +//~--- non-JDK imports -------------------------------------------------------- + +import sonia.scm.plugin.PluginVersion; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; + +/** + * Handle upgrades from one SCM-Manager version to an other. + * + * @author Sebastian Sdorra + * @since 1.23 + */ +public interface UpgradeHandler +{ + + /** + * Handle upgrade of SCM-Manager + * + * + * @param homeDirectory home directory + * @param configDirectory config directory + * @param oldVersion old version + * @param newVersion new version + */ + public void doUpgrade(File homeDirectory, File configDirectory, + PluginVersion oldVersion, PluginVersion newVersion); +} diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index 2a876502a2..4c421e60a0 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -49,6 +49,7 @@ import sonia.scm.plugin.DefaultPluginLoader; import sonia.scm.plugin.PluginLoader; import sonia.scm.repository.RepositoryManager; import sonia.scm.store.StoreFactory; +import sonia.scm.upgrade.UpgradeManager; import sonia.scm.user.UserManager; import sonia.scm.util.IOUtil; import sonia.scm.web.security.AuthenticationManager; @@ -119,7 +120,7 @@ public class ScmContextListener extends GuiceServletContextListener if (SCMContext.getContext().getStartupError() == null) { - ScmUpgradeHandler upgradeHandler = new ScmUpgradeHandler(); + UpgradeManager upgradeHandler = new UpgradeManager(); upgradeHandler.doUpgrade(); } diff --git a/scm-webapp/src/main/java/sonia/scm/ScmUpgradeHandler.java b/scm-webapp/src/main/java/sonia/scm/ScmUpgradeHandler.java deleted file mode 100644 index cc29b2b5d9..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/ScmUpgradeHandler.java +++ /dev/null @@ -1,327 +0,0 @@ -/** - * Copyright (c) 2010, Sebastian Sdorra - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://bitbucket.org/sdorra/scm-manager - * - */ - - - -package sonia.scm; - -//~--- non-JDK imports -------------------------------------------------------- - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import org.xml.sax.SAXException; - -import sonia.scm.util.IOUtil; -import sonia.scm.util.Util; - -//~--- JDK imports ------------------------------------------------------------ - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.OutputStream; - -import java.text.MessageFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; - -import java.util.Date; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -/** - * - * @author Sebastian Sdorra - */ -public class ScmUpgradeHandler -{ - - /** the logger for ScmUpgradeHandler */ - private static final Logger logger = - LoggerFactory.getLogger(ScmUpgradeHandler.class); - - //~--- methods -------------------------------------------------------------- - - /** - * Method description - * - */ - public void doUpgrade() - { - File baseDirectory = SCMContext.getContext().getBaseDirectory(); - File configDirectory = new File(baseDirectory, "config"); - File versionFile = new File(configDirectory, "version.txt"); - - if (configDirectory.exists()) - { - - // pre version 1.2 - if (!versionFile.exists()) - { - if (logger.isInfoEnabled()) - { - logger.info("upgrade to version {}", - SCMContext.getContext().getVersion()); - } - - fixDate(baseDirectory, configDirectory); - } - - // fresh installation - } - else - { - IOUtil.mkdirs(configDirectory); - } - - writeVersionFile(versionFile); - } - - /** - * Method description - * - * - * @param value - * - * @return - */ - private String convertDate(String value) - { - if (Util.isNotEmpty(value)) - { - try - { - Date date = Util.parseDate(value); - - if (date != null) - { - value = Long.toString(date.getTime()); - } - } - catch (ParseException ex) - { - logger.warn("could not parse date", ex); - } - } - - return value; - } - - /** - * Method description - * - * - * @param baseDirectory - * @param note - * - * @return - */ - private File createBackupDirectory(File baseDirectory, String note) - { - String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); - File backupDirectory = - new File(baseDirectory, "backups".concat(File.separator).concat(date)); - - IOUtil.mkdirs(backupDirectory); - - FileWriter writer = null; - - note = MessageFormat.format(note, SCMContext.getContext().getVersion()); - - try - { - writer = new FileWriter(new File(backupDirectory, "note.txt")); - writer.write(note); - } - catch (IOException ex) - { - logger.error("could not write note.txt for backup", ex); - } - finally - { - IOUtil.close(writer); - } - - return backupDirectory; - } - - /** - * Method description - * - * - * - * @param baseDirectory - * @param configDirectory - */ - private void fixDate(File baseDirectory, File configDirectory) - { - try - { - DocumentBuilder builder = - DocumentBuilderFactory.newInstance().newDocumentBuilder(); - File backupDirectory = createBackupDirectory(baseDirectory, - "upgrade to version {0}"); - - fixDate(builder, configDirectory, backupDirectory, "users.xml"); - fixDate(builder, configDirectory, backupDirectory, "groups.xml"); - fixDate(builder, configDirectory, backupDirectory, "repositories.xml"); - } - catch (Exception ex) - { - logger.error("could not parse document", ex); - } - } - - /** - * Method description - * - * - * @param builder - * @param configDirectory - * @param backupDirectory - * @param filename - * - * @throws IOException - * @throws SAXException - * @throws TransformerConfigurationException - * @throws TransformerException - */ - private void fixDate(DocumentBuilder builder, File configDirectory, - File backupDirectory, String filename) - throws SAXException, IOException, TransformerConfigurationException, - TransformerException - { - File configFile = new File(configDirectory, filename); - File backupFile = new File(backupDirectory, filename); - - IOUtil.copy(configFile, backupFile); - - if (configFile.exists()) - { - if (logger.isInfoEnabled()) - { - logger.info("fix date elements of {}", configFile.getPath()); - } - - Document document = builder.parse(configFile); - - fixDate(document, "lastModified"); - fixDate(document, "creationDate"); - fixDate(document, "creationTime"); - writeDocument(document, configFile); - } - } - - /** - * Method description - * - * - * @param document - * @param element - */ - private void fixDate(Document document, String element) - { - NodeList nodes = document.getElementsByTagName(element); - - if (nodes != null) - { - for (int i = 0; i < nodes.getLength(); i++) - { - Node node = nodes.item(i); - String value = node.getTextContent(); - - value = convertDate(value); - node.setTextContent(value); - } - } - } - - /** - * Method description - * - * - * @param document - * @param configFile - * - * @throws TransformerConfigurationException - * @throws TransformerException - */ - private void writeDocument(Document document, File configFile) - throws TransformerConfigurationException, TransformerException - { - Transformer transformer = TransformerFactory.newInstance().newTransformer(); - - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.transform(new DOMSource(document), - new StreamResult(configFile)); - } - - /** - * Method description - * - * - * @param versionFile - */ - private void writeVersionFile(File versionFile) - { - OutputStream output = null; - - try - { - output = new FileOutputStream(versionFile); - output.write(SCMContext.getContext().getVersion().getBytes()); - } - catch (IOException ex) - { - logger.error("could not write version file", ex); - } - finally - { - IOUtil.close(output); - } - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/upgrade/TimestampUpgradeHandler.java b/scm-webapp/src/main/java/sonia/scm/upgrade/TimestampUpgradeHandler.java new file mode 100644 index 0000000000..dcc5582ddf --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/upgrade/TimestampUpgradeHandler.java @@ -0,0 +1,226 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.upgrade; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.base.Strings; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.xml.sax.SAXException; + +import sonia.scm.SCMContext; +import sonia.scm.plugin.PluginVersion; +import sonia.scm.util.IOUtil; +import sonia.scm.util.Util; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.IOException; + +import java.text.ParseException; + +import java.util.Date; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; + +/** + * + * @author Sebastian Sdorra + */ +public class TimestampUpgradeHandler extends XmlUpgradeHandler +{ + + /** + * the logger for TimestampUpgradeHandler + */ + private static final Logger logger = + LoggerFactory.getLogger(TimestampUpgradeHandler.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param homeDirectory + * @param configDirectory + * @param oldVersion + * @param newVersion + */ + @Override + public void doUpgrade(File homeDirectory, File configDirectory, + PluginVersion oldVersion, PluginVersion newVersion) + { + if (oldVersion.isOlder("1.2")) + { + if (logger.isInfoEnabled()) + { + logger.info("data format is older than 1.2, upgrade to version {}", + SCMContext.getContext().getVersion()); + } + + fixDate(homeDirectory, configDirectory); + } + } + + /** + * Method description + * + * + * @param value + * + * @return + */ + private String convertDate(String value) + { + if (!Strings.isNullOrEmpty(value)) + { + try + { + Date date = Util.parseDate(value); + + if (date != null) + { + value = Long.toString(date.getTime()); + } + } + catch (ParseException ex) + { + logger.warn("could not parse date", ex); + } + } + + return value; + } + + /** + * Method description + * + * + * + * @param baseDirectory + * @param configDirectory + */ + private void fixDate(File baseDirectory, File configDirectory) + { + try + { + DocumentBuilder builder = + DocumentBuilderFactory.newInstance().newDocumentBuilder(); + File backupDirectory = createBackupDirectory(baseDirectory, + "upgrade to version {0}"); + + fixDate(builder, configDirectory, backupDirectory, "users.xml"); + fixDate(builder, configDirectory, backupDirectory, "groups.xml"); + fixDate(builder, configDirectory, backupDirectory, "repositories.xml"); + } + catch (Exception ex) + { + logger.error("could not parse document", ex); + } + } + + /** + * Method description + * + * + * @param builder + * @param configDirectory + * @param backupDirectory + * @param filename + * + * @throws IOException + * @throws SAXException + * @throws TransformerConfigurationException + * @throws TransformerException + */ + private void fixDate(DocumentBuilder builder, File configDirectory, + File backupDirectory, String filename) + throws SAXException, IOException, TransformerConfigurationException, + TransformerException + { + File configFile = new File(configDirectory, filename); + File backupFile = new File(backupDirectory, filename); + + IOUtil.copy(configFile, backupFile); + + if (configFile.exists()) + { + if (logger.isInfoEnabled()) + { + logger.info("fix date elements of {}", configFile.getPath()); + } + + Document document = builder.parse(configFile); + + fixDate(document, "lastModified"); + fixDate(document, "creationDate"); + fixDate(document, "creationTime"); + writeDocument(document, configFile); + } + } + + /** + * Method description + * + * + * @param document + * @param element + */ + private void fixDate(Document document, String element) + { + NodeList nodes = document.getElementsByTagName(element); + + if (nodes != null) + { + for (int i = 0; i < nodes.getLength(); i++) + { + Node node = nodes.item(i); + String value = node.getTextContent(); + + value = convertDate(value); + node.setTextContent(value); + } + } + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/upgrade/UpgradeManager.java b/scm-webapp/src/main/java/sonia/scm/upgrade/UpgradeManager.java new file mode 100644 index 0000000000..f5335c334e --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/upgrade/UpgradeManager.java @@ -0,0 +1,255 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.upgrade; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.base.Charsets; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.io.Files; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.SCMContext; +import sonia.scm.plugin.PluginVersion; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.util.List; + +/** + * + * @author Sebastian Sdorra + */ +public class UpgradeManager +{ + + /** the logger for ScmUpgradeHandler */ + private static final Logger logger = + LoggerFactory.getLogger(UpgradeManager.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @throws IOException + */ + public void doUpgrade() + { + File baseDirectory = SCMContext.getContext().getBaseDirectory(); + File configDirectory = new File(baseDirectory, "config"); + + if (configDirectory.exists()) + { + boolean writeVersionFile = false; + + String newVersion = SCMContext.getContext().getVersion(); + + File versionFile = new File(configDirectory, "version.txt"); + + if (versionFile.exists()) + { + + String oldVersion = getVersionString(versionFile); + + if (!Strings.isNullOrEmpty(oldVersion) &&!oldVersion.equals(newVersion)) + { + if (!newVersion.equals(oldVersion)) + { + writeVersionFile = doUpgradesForOldVersion(baseDirectory, + configDirectory, oldVersion, newVersion); + } + } + + } + else + { + writeVersionFile = doUpgradesForOldVersion(baseDirectory, + configDirectory, "1.1", newVersion); + } + + if (writeVersionFile) + { + writeVersionFile(versionFile); + logger.info("upgrade to version {} was successful", newVersion); + } + + } + else + { + + // fresh installation + IOUtil.mkdirs(configDirectory); + } + } + + /** + * Method description + * + * + * @return + */ + private List collectUpgradeHandlers() + { + + List upgradeHandlers = Lists.newArrayList(); + + upgradeHandlers.add(new TimestampUpgradeHandler()); + + // TODO find upgrade handlers on classpath + return upgradeHandlers; + } + + /** + * Method description + * + * + * @param baseDirectory + * @param configDirectory + * @param versionString + * @param oldVersionString + * @param newVersionString + * + * @return + */ + private boolean doUpgradesForOldVersion(File baseDirectory, + File configDirectory, String oldVersionString, String newVersionString) + { + logger.info("start upgrade from version \"{}\" to \"{}\"", + oldVersionString, newVersionString); + + boolean writeVersionFile = false; + + try + { + PluginVersion oldVersion = PluginVersion.createVersion(oldVersionString); + PluginVersion newVersion = PluginVersion.createVersion(newVersionString); + + doUpgradesForOldVersion(baseDirectory, configDirectory, oldVersion, + newVersion); + writeVersionFile = true; + } + catch (Exception ex) + { + logger.error("error upgrade failed", ex); + } + + return writeVersionFile; + } + + /** + * Method description + * + * + * @param baseDirectory + * @param configDirectory + * @param version + * @param oldVersion + * @param newVersion + */ + private void doUpgradesForOldVersion(File baseDirectory, + File configDirectory, PluginVersion oldVersion, PluginVersion newVersion) + { + List upgradeHandlers = collectUpgradeHandlers(); + + for (UpgradeHandler upgradeHandler : upgradeHandlers) + { + logger.trace("call upgrade handler {}", upgradeHandler.getClass()); + upgradeHandler.doUpgrade(baseDirectory, configDirectory, oldVersion, + newVersion); + } + + } + + /** + * Method description + * + * + * @param versionFile + */ + private void writeVersionFile(File versionFile) + { + OutputStream output = null; + + try + { + output = new FileOutputStream(versionFile); + output.write(SCMContext.getContext().getVersion().getBytes()); + } + catch (IOException ex) + { + logger.error("could not write version file", ex); + } + finally + { + IOUtil.close(output); + } + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Method description + * + * + * @param versionFile + * + * @return + */ + private String getVersionString(File versionFile) + { + String version = null; + + try + { + version = Files.toString(versionFile, Charsets.UTF_8).trim(); + } + catch (IOException ex) + { + logger.error("could not read version file", ex); + } + + return version; + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/upgrade/XmlUpgradeHandler.java b/scm-webapp/src/main/java/sonia/scm/upgrade/XmlUpgradeHandler.java new file mode 100644 index 0000000000..e4bdf87b32 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/upgrade/XmlUpgradeHandler.java @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of SCM-Manager; + * nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.upgrade; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.w3c.dom.Document; + +import sonia.scm.SCMContext; +import sonia.scm.util.IOUtil; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import java.text.MessageFormat; +import java.text.SimpleDateFormat; + +import java.util.Date; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +/** + * + * @author Sebastian Sdorra + */ +public abstract class XmlUpgradeHandler implements UpgradeHandler +{ + + /** + * the logger for XmlUpgradeHandler + */ + private static final Logger logger = + LoggerFactory.getLogger(XmlUpgradeHandler.class); + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param baseDirectory + * @param note + * + * @return + */ + protected File createBackupDirectory(File baseDirectory, String note) + { + String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + File backupDirectory = new File(baseDirectory, + "backups".concat(File.separator).concat(date)); + + IOUtil.mkdirs(backupDirectory); + + FileWriter writer = null; + + note = MessageFormat.format(note, SCMContext.getContext().getVersion()); + + try + { + writer = new FileWriter(new File(backupDirectory, "note.txt")); + writer.write(note); + } + catch (IOException ex) + { + logger.error("could not write note.txt for backup", ex); + } + finally + { + IOUtil.close(writer); + } + + return backupDirectory; + } + + /** + * Method description + * + * + * @param document + * @param configFile + * + * @throws TransformerConfigurationException + * @throws TransformerException + */ + protected void writeDocument(Document document, File configFile) + throws TransformerConfigurationException, TransformerException + { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.STANDALONE, "yes"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.transform(new DOMSource(document), + new StreamResult(configFile)); + } +}