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.apache.commons.io.IOUtils; 035import org.nuxeo.connect.update.PackageException; 036import org.nuxeo.connect.update.xml.XmlWriter; 037import org.w3c.dom.Document; 038import org.w3c.dom.Element; 039import org.w3c.dom.Node; 040import org.xml.sax.SAXException; 041 042/** 043 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 044 */ 045public class RegistrySerializer extends XmlWriter { 046 047 private final static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 048 049 /** 050 * @since 5.7 051 */ 052 public RegistrySerializer() { 053 super(" "); 054 } 055 056 /** 057 * Serializes the given registry into the given file. 058 * 059 * @param registry 060 * @param file 061 * @throws IOException 062 */ 063 public static void store(Map<String, Entry> registry, File file) throws IOException { 064 RegistrySerializer serializer = new RegistrySerializer(); 065 serializer.write(registry); 066 serializer.write(file); 067 } 068 069 /** 070 * De-serializes the given file into a Nuxeo packages registry 071 * 072 * @param file 073 * @return The Nuxeo packages registry described by the given file 074 */ 075 public static Map<String, Entry> load(File file) throws PackageException, IOException { 076 RegistrySerializer serializer = new RegistrySerializer(); 077 return serializer.read(file); 078 } 079 080 protected Map<String, Entry> read(File file) throws PackageException, IOException { 081 FileInputStream in = new FileInputStream(file); 082 try { 083 HashMap<String, Entry> registry = new HashMap<String, Entry>(); 084 factory.setNamespaceAware(true); 085 DocumentBuilder builder = factory.newDocumentBuilder(); 086 Document document = builder.parse(in); 087 read(document.getDocumentElement(), registry); 088 return registry; 089 } catch (ParserConfigurationException | SAXException e) { 090 throw new RuntimeException(e); 091 } finally { 092 IOUtils.closeQuietly(in); 093 } 094 } 095 096 protected void read(Element element, Map<String, Entry> registry) throws PackageException { 097 Node node = element.getFirstChild(); 098 while (node != null) { 099 if (node.getNodeType() == Node.ELEMENT_NODE && "entry".equals(node.getNodeName())) { 100 Entry entry = readEntryElement((Element) node); 101 registry.put(entry.getKey(), entry); 102 } 103 node = node.getNextSibling(); 104 } 105 } 106 107 protected Entry readEntryElement(Element element) throws PackageException { 108 Entry entry = new Entry(readKeyAttr(element)); 109 Node node = element.getFirstChild(); 110 while (node != null) { 111 if (node.getNodeType() == Node.ELEMENT_NODE) { 112 String name = node.getNodeName(); 113 if ("version".equals(name)) { 114 Version v = readVersionElement((Element) node); 115 entry.addVersion(v); 116 } else if ("base-version".equals(name)) { 117 Version v = readVersionElement((Element) node); 118 entry.setBaseVersion(v); 119 } 120 } 121 node = node.getNextSibling(); 122 } 123 return entry; 124 } 125 126 protected String readKeyAttr(Element element) throws PackageException { 127 String key = element.getAttribute("key"); 128 if (key.length() == 0) { 129 throw new PackageException("Invalid entry. No 'key' attribute found!"); 130 } 131 return key; 132 } 133 134 protected String readNameAttr(Element element) throws PackageException { 135 String version = element.getAttribute("name"); 136 if (version.length() == 0) { 137 throw new PackageException("Invalid version entry. No 'name' attribute found!"); 138 } 139 return version; 140 } 141 142 protected String readPathAttr(Element element) throws PackageException { 143 String path = element.getAttribute("path"); 144 if (path.length() == 0) { 145 throw new PackageException("Invalid version entry. No 'path' attribute found!"); 146 } 147 return path; 148 } 149 150 protected Version readVersionElement(Element element) throws PackageException { 151 Version v = new Version(readNameAttr(element)); 152 v.setPath(readPathAttr(element)); 153 Node node = element.getFirstChild(); 154 while (node != null) { 155 if (node.getNodeType() == Node.ELEMENT_NODE && "package".equals(node.getNodeName())) { 156 UpdateOptions opt = new UpdateOptions(); 157 opt.pkgId = ((Element) node).getTextContent().trim(); 158 opt.upgradeOnly = Boolean.parseBoolean(((Element) node).getAttribute("upgradeOnly")); 159 v.addPackage(opt); 160 } 161 node = node.getNextSibling(); 162 } 163 return v; 164 } 165 166 protected void write(Map<String, Entry> registry) { 167 writeXmlDecl(); 168 start("registry"); 169 startContent(); 170 for (Entry entry : registry.values()) { 171 writeEntry(entry); 172 } 173 end("registry"); 174 } 175 176 protected void writeEntry(Entry entry) { 177 start("entry"); 178 attr("key", entry.getKey()); 179 startContent(); 180 if (entry.hasBaseVersion()) { 181 writeBaseVersion(entry.getBaseVersion()); 182 } 183 for (Version v : entry) { 184 writeVersion(v); 185 } 186 end("entry"); 187 } 188 189 protected void writeBaseVersion(Version version) { 190 start("base-version"); 191 attr("name", version.getVersion()); 192 attr("path", version.getPath()); 193 end(); 194 } 195 196 protected void writeVersion(Version version) { 197 start("version"); 198 attr("name", version.getVersion()); 199 attr("path", version.getPath()); 200 startContent(); 201 Map<String, UpdateOptions> packages = version.getPackages(); 202 for (UpdateOptions opt : packages.values()) { 203 start("package"); 204 if (opt.upgradeOnly) { 205 attr("upgradeOnly", "true"); 206 } 207 // Missing methods to properly append the following without indent 208 text(">" + opt.pkgId + "</package>\n"); 209 // startContent(false); 210 // text(opt.pkgId); 211 // end("package", false); 212 } 213 end("version"); 214 } 215 216 /** 217 * @param file Output file 218 * @throws IOException 219 * @since 5.7 220 */ 221 protected void write(File file) throws IOException { 222 Writer writer = new OutputStreamWriter(new FileOutputStream(file)); 223 try { 224 writer.write(sb.toString()); 225 } finally { 226 IOUtils.closeQuietly(writer); 227 } 228 } 229 230}