001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.api.checks.profiles;
021    
022    import com.thoughtworks.xstream.XStream;
023    import com.thoughtworks.xstream.converters.Converter;
024    import com.thoughtworks.xstream.converters.MarshallingContext;
025    import com.thoughtworks.xstream.converters.UnmarshallingContext;
026    import com.thoughtworks.xstream.io.HierarchicalStreamReader;
027    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
028    import com.thoughtworks.xstream.io.xml.CompactWriter;
029    import com.thoughtworks.xstream.io.xml.XppDriver;
030    import org.apache.commons.io.IOUtils;
031    import org.sonar.check.Priority;
032    
033    import java.io.InputStreamReader;
034    import java.io.Reader;
035    import java.io.Writer;
036    import java.util.Map;
037    
038    /**
039     * EXPERIMENTAL - will be used in version 2.3
040     */
041    public final class CheckProfileXmlMarshaller {
042    
043      public static void toXml(CheckProfile profile, Writer writer) {
044        getXStream().toXML(profile, writer);
045      }
046    
047      public static CheckProfile fromXml(Reader xml) {
048        return (CheckProfile) getXStream().fromXML(xml);
049      }
050    
051      public static CheckProfile fromXmlInClasspath(String pathToXml) {
052        return fromXmlInClasspath(pathToXml, CheckProfileXmlMarshaller.class);
053      }
054    
055      public static CheckProfile fromXmlInClasspath(String pathToXml, Class clazz) {
056        Reader reader = new InputStreamReader(clazz.getResourceAsStream(pathToXml));
057        try {
058          return fromXml(reader);
059        } finally {
060          IOUtils.closeQuietly(reader);
061        }
062      }
063    
064      private static XStream getXStream() {
065        XStream xstream = new XStream(new CompactDriver());
066        xstream.setClassLoader(CheckProfileXmlMarshaller.class.getClassLoader());
067        xstream.registerConverter(new CheckConverter());
068        xstream.alias("profile", CheckProfile.class);
069        xstream.alias("check", Check.class);
070        xstream.addImplicitCollection(CheckProfile.class, "checks");
071        return xstream;
072      }
073    
074      private static class CompactDriver extends XppDriver {
075        @Override
076        public HierarchicalStreamWriter createWriter(Writer out) {
077          return new XDataPrintWriter(out);
078        }
079      }
080    
081    
082      private static class XDataPrintWriter extends CompactWriter {
083        public XDataPrintWriter(Writer writer) {
084          super(writer, XML_1_0);
085        }
086      }
087    
088      private static class CheckConverter implements Converter {
089    
090        public boolean canConvert(Class clazz) {
091          return clazz.equals(Check.class);
092        }
093    
094        public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
095          Check check = (Check) value;
096          writer.startNode("repository");
097          writer.setValue(check.getRepositoryKey());
098          writer.endNode();
099          writer.startNode("template");
100          writer.setValue(check.getTemplateKey());
101          writer.endNode();
102          writer.startNode("priority");
103          writer.setValue(check.getPriority().toString());
104          writer.endNode();
105          for (Map.Entry<String, String> entry : check.getProperties().entrySet()) {
106            if (entry.getValue() != null) {
107              writer.startNode("property");
108              writer.startNode("key");
109              writer.setValue(entry.getKey());
110              writer.endNode();
111              writer.startNode("value");
112              // TODO is escaping automatically supported by xstream ?
113              writer.setValue(entry.getValue());
114              writer.endNode();
115              writer.endNode();
116            }
117          }
118        }
119    
120        public Object unmarshal(HierarchicalStreamReader reader,
121                                UnmarshallingContext context) {
122          Check check = new Check();
123          while (reader.hasMoreChildren()) {
124            reader.moveDown();
125            readValue(reader, check);
126            reader.moveUp();
127          }
128          return check;
129        }
130    
131        private void readValue(HierarchicalStreamReader reader, Check check) {
132          if (reader.getNodeName().equals("repository")) {
133            check.setRepositoryKey(reader.getValue());
134    
135          } else if (reader.getNodeName().equals("template")) {
136            check.setTemplateKey(reader.getValue());
137    
138          } else if (reader.getNodeName().equals("priority")) {
139            check.setPriority(Priority.valueOf(reader.getValue()));
140    
141          } else if (reader.getNodeName().equals("property")) {
142            reader.moveDown();
143            String key = reader.getValue();
144            reader.moveUp();
145    
146            reader.moveDown();
147            String value = reader.getValue();
148            reader.moveUp();
149            check.addProperty(key, value);
150          }
151        }
152    
153      }
154    }