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