001/* 002 * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * bstefanescu, jcarsique 016 */ 017package org.nuxeo.connect.update.task.update; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.FileOutputStream; 022import java.io.IOException; 023import java.io.OutputStreamWriter; 024import java.io.Writer; 025import java.util.HashMap; 026import java.util.Map; 027 028import javax.xml.parsers.DocumentBuilder; 029import javax.xml.parsers.DocumentBuilderFactory; 030import javax.xml.parsers.ParserConfigurationException; 031 032import org.apache.commons.io.IOUtils; 033import org.nuxeo.connect.update.PackageException; 034import org.nuxeo.connect.update.xml.XmlWriter; 035import org.w3c.dom.Document; 036import org.w3c.dom.Element; 037import org.w3c.dom.Node; 038import org.xml.sax.SAXException; 039 040/** 041 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 042 */ 043public class RegistrySerializer extends XmlWriter { 044 045 private final static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 046 047 /** 048 * @since 5.7 049 */ 050 public RegistrySerializer() { 051 super(" "); 052 } 053 054 /** 055 * Serializes the given registry into the given file. 056 * 057 * @param registry 058 * @param file 059 * @throws IOException 060 */ 061 public static void store(Map<String, Entry> registry, File file) throws IOException { 062 RegistrySerializer serializer = new RegistrySerializer(); 063 serializer.write(registry); 064 serializer.write(file); 065 } 066 067 /** 068 * De-serializes the given file into a Nuxeo packages registry 069 * 070 * @param file 071 * @return The Nuxeo packages registry described by the given file 072 */ 073 public static Map<String, Entry> load(File file) throws PackageException, IOException { 074 RegistrySerializer serializer = new RegistrySerializer(); 075 return serializer.read(file); 076 } 077 078 protected Map<String, Entry> read(File file) throws PackageException, IOException { 079 FileInputStream in = new FileInputStream(file); 080 try { 081 HashMap<String, Entry> registry = new HashMap<String, Entry>(); 082 factory.setNamespaceAware(true); 083 DocumentBuilder builder = factory.newDocumentBuilder(); 084 Document document = builder.parse(in); 085 read(document.getDocumentElement(), registry); 086 return registry; 087 } catch (ParserConfigurationException | SAXException e) { 088 throw new RuntimeException(e); 089 } finally { 090 IOUtils.closeQuietly(in); 091 } 092 } 093 094 protected void read(Element element, Map<String, Entry> registry) throws PackageException { 095 Node node = element.getFirstChild(); 096 while (node != null) { 097 if (node.getNodeType() == Node.ELEMENT_NODE && "entry".equals(node.getNodeName())) { 098 Entry entry = readEntryElement((Element) node); 099 registry.put(entry.getKey(), entry); 100 } 101 node = node.getNextSibling(); 102 } 103 } 104 105 protected Entry readEntryElement(Element element) throws PackageException { 106 Entry entry = new Entry(readKeyAttr(element)); 107 Node node = element.getFirstChild(); 108 while (node != null) { 109 if (node.getNodeType() == Node.ELEMENT_NODE) { 110 String name = node.getNodeName(); 111 if ("version".equals(name)) { 112 Version v = readVersionElement((Element) node); 113 entry.addVersion(v); 114 } else if ("base-version".equals(name)) { 115 Version v = readVersionElement((Element) node); 116 entry.setBaseVersion(v); 117 } 118 } 119 node = node.getNextSibling(); 120 } 121 return entry; 122 } 123 124 protected String readKeyAttr(Element element) throws PackageException { 125 String key = element.getAttribute("key"); 126 if (key.length() == 0) { 127 throw new PackageException("Invalid entry. No 'key' attribute found!"); 128 } 129 return key; 130 } 131 132 protected String readNameAttr(Element element) throws PackageException { 133 String version = element.getAttribute("name"); 134 if (version.length() == 0) { 135 throw new PackageException("Invalid version entry. No 'name' attribute found!"); 136 } 137 return version; 138 } 139 140 protected String readPathAttr(Element element) throws PackageException { 141 String path = element.getAttribute("path"); 142 if (path.length() == 0) { 143 throw new PackageException("Invalid version entry. No 'path' attribute found!"); 144 } 145 return path; 146 } 147 148 protected Version readVersionElement(Element element) throws PackageException { 149 Version v = new Version(readNameAttr(element)); 150 v.setPath(readPathAttr(element)); 151 Node node = element.getFirstChild(); 152 while (node != null) { 153 if (node.getNodeType() == Node.ELEMENT_NODE && "package".equals(node.getNodeName())) { 154 UpdateOptions opt = new UpdateOptions(); 155 opt.pkgId = ((Element) node).getTextContent().trim(); 156 opt.upgradeOnly = Boolean.parseBoolean(((Element) node).getAttribute("upgradeOnly")); 157 v.addPackage(opt); 158 } 159 node = node.getNextSibling(); 160 } 161 return v; 162 } 163 164 protected void write(Map<String, Entry> registry) { 165 writeXmlDecl(); 166 start("registry"); 167 startContent(); 168 for (Entry entry : registry.values()) { 169 writeEntry(entry); 170 } 171 end("registry"); 172 } 173 174 protected void writeEntry(Entry entry) { 175 start("entry"); 176 attr("key", entry.getKey()); 177 startContent(); 178 if (entry.hasBaseVersion()) { 179 writeBaseVersion(entry.getBaseVersion()); 180 } 181 for (Version v : entry) { 182 writeVersion(v); 183 } 184 end("entry"); 185 } 186 187 protected void writeBaseVersion(Version version) { 188 start("base-version"); 189 attr("name", version.getVersion()); 190 attr("path", version.getPath()); 191 end(); 192 } 193 194 protected void writeVersion(Version version) { 195 start("version"); 196 attr("name", version.getVersion()); 197 attr("path", version.getPath()); 198 startContent(); 199 Map<String, UpdateOptions> packages = version.getPackages(); 200 for (UpdateOptions opt : packages.values()) { 201 start("package"); 202 if (opt.upgradeOnly) { 203 attr("upgradeOnly", "true"); 204 } 205 // Missing methods to properly append the following without indent 206 text(">" + opt.pkgId + "</package>\n"); 207 // startContent(false); 208 // text(opt.pkgId); 209 // end("package", false); 210 } 211 end("version"); 212 } 213 214 /** 215 * @param file Output file 216 * @throws IOException 217 * @since 5.7 218 */ 219 protected void write(File file) throws IOException { 220 Writer writer = new OutputStreamWriter(new FileOutputStream(file)); 221 try { 222 writer.write(sb.toString()); 223 } finally { 224 IOUtils.closeQuietly(writer); 225 } 226 } 227 228}