/******************************************************************************* * Copyright 2006 - 2012 Vienna University of Technology, * Department of Software Technology and Interactive Systems, IFS * * 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 eu.scape_project.planning.xml; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.commons.digester3.Digester; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import eu.scape_project.planning.model.PlatoException; import eu.scape_project.planning.utils.FileUtils; public class PlanMigrator { private static final Logger log = LoggerFactory.getLogger(PlanMigrator.class); /** * Used by digester */ private String fileVersion; /** * Detect the version of the given XML representation of plans. If the * version of the XML representation is not up to date, necessary * transformations are applied. * * @param importData * @return null if the transformation fails, otherwise an up to date XML * representation * @throws IOException * if parsing the XML representation fails * @throws SAXException * if parsing the XML representation fails */ public String getCurrentVersionData(final InputStream in, final String tempPath, final List<String> appliedTransformations) throws PlatoException { String originalFile = tempPath + "_original.xml"; try { FileUtils.writeToFile(in, new FileOutputStream(originalFile)); /** check for the version of the file **/ // The version of the read xml file is unknown, so it is not possible to // validate it // moreover, in old plans the version attribute was on different // nodes(project, projects), // with a different name (fileVersion) // to be backwards compatible we create rules for all these attributes fileVersion = "xxx"; SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(false); Digester d = new Digester(factory.newSAXParser()); d.setValidating(false); // StrictErrorHandler errorHandler = new StrictErrorHandler(); // d.setErrorHandler(errorHandler); d.push(this); // to read the version we have to support all versions: d.addSetProperties("*/projects", "version", "fileVersion"); // manually migrated projects may have the file version in the node // projects/project d.addSetProperties("*/projects/project", "version", "fileVersion"); // pre V1.3 version info was stored in the project node d.addSetProperties("*/project", "version", "fileVersion"); // since V1.9 the root node is plans: d.addSetProperties("plans", "version", "fileVersion"); InputStream inV = new FileInputStream(originalFile); d.parse(inV); inV.close(); /** this could be more sophisticated, but for now this is enough **/ String version = "1.0"; if (fileVersion != null) { version = fileVersion; } String fileTo = originalFile; String fileFrom = originalFile; boolean success = true; if ("xxx".equals(version)) { fileFrom = fileTo; fileTo = fileFrom + "_V1.3.xml"; /** this is an old export file, transform it to the 1.3 schema **/ success = transformXmlData(fileFrom, fileTo, "data/xslt/Vxxx-to-V1.3.xsl"); appliedTransformations.add("Vxxx-to-V1.3.xsl"); version = "1.3"; } if (success && "1.3".equals(version)) { fileFrom = fileTo; fileTo = fileFrom + "_V1.9.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V1.3-to-V1.9.xsl"); appliedTransformations.add("V1.3-to-V1.9.xsl"); version = "1.9"; } // with release of Plato 2.0 and its schema ProjectExporter creates // documents with version 2.0 if (success && "1.9".equals(version)) { version = "2.0"; } if (success && "2.0".equals(version)) { // transform the document to version 2.1 fileFrom = fileTo; fileTo = fileFrom + "_V2.1.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.0-to-V2.1.xsl"); appliedTransformations.add("V2.0-to-V2.1.xsl"); version = "2.1"; } if (success && "2.1".equals(version)) { // transform the document to version 2.1.2 fileFrom = fileTo; fileTo = fileFrom + "_V2.1.2.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1-to-V2.1.2.xsl"); appliedTransformations.add("V2.1-to-V2.1.2.xsl"); version = "2.1.2"; } if (success && "2.1.1".equals(version)) { // transform the document to version 2.1.2 fileFrom = fileTo; fileTo = fileFrom + "_V2.1.2.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1.1-to-V2.1.2.xsl"); appliedTransformations.add("V2.1.1-to-V2.1.2.xsl"); version = "2.1.2"; } if (success && "2.1.2".equals(version)) { // transform the document to version 3.0.0 fileFrom = fileTo; fileTo = fileFrom + "_V3.0.0.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1.2-to-V3.0.0.xsl"); appliedTransformations.add("V2.1.2-to-V3.0.0.xsl"); version = "3.0.0"; } if (success && "3.0.0".equals(version)) { // transform the document to version 3.0.1 fileFrom = fileTo; fileTo = fileFrom + "_V3.0.1.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.0.0-to-V3.0.1.xsl"); appliedTransformations.add("V3.0.0-to-V3.0.1.xsl"); version = "3.0.1"; } if (success && "3.0.1".equals(version)) { // transform the document to version 3.9.0 fileFrom = fileTo; fileTo = fileFrom + "_V3.9.0.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.0.1-to-V3.9.0.xsl"); appliedTransformations.add("V3.0.1-to-V3.9.0.xsl"); version = "3.9.0"; } if (success && "3.9.0".equals(version)) { // transform the document to version 3.9.9 fileFrom = fileTo; fileTo = fileFrom + "_V3.9.9.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.9.0-to-V3.9.9.xsl"); appliedTransformations.add("V3.9.0-to-V3.9.9.xsl"); version = "3.9.9"; } if (success && "3.9.9".equals(version)) { // transform the document to version 4.0.0 fileFrom = fileTo; fileTo = fileFrom + "_V4.0.1.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V3.9.9-to-V4.0.1.xsl"); appliedTransformations.add("V3.9.9-to-V4.0.1.xsl"); version = "4.0.1"; } if (success && "4.0.1".equals(version)) { // transform the document to version 4.0.0 fileFrom = fileTo; fileTo = fileFrom + "_V4.0.2.xml"; success = transformXmlData(fileFrom, fileTo, "data/xslt/V4.0.1-to-V4.0.2.xsl"); appliedTransformations.add("V4.0.1-to-V4.0.2.xsl"); version = "4.0.2"; } if (success) { return fileTo; } else { return null; } } catch (Exception e) { throw new PlatoException("Failed to update plan to current version.", e); } } public boolean transformXmlData(final String fromFile, final String toFile, final String xslFile) throws IOException { try { InputStream xsl = Thread.currentThread().getContextClassLoader().getResourceAsStream(xslFile); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(new StreamSource(xsl)); OutputStream transformedOut = new FileOutputStream(toFile); Result outputTarget = new StreamResult(transformedOut); Source xmlSource = new StreamSource(new FileInputStream(fromFile)); transformer.transform(xmlSource, outputTarget); transformedOut.close(); return true; } catch (TransformerConfigurationException e) { log.debug(e.getMessage(), e); } catch (TransformerFactoryConfigurationError e) { log.debug(e.getMessage(), e); } catch (TransformerException e) { log.debug(e.getMessage(), e); } return false; } public void setFileVersion(final String fileVersion) { this.fileVersion = fileVersion; } }