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.2
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        Reader reader = new InputStreamReader(CheckProfileXmlMarshaller.class.getResourceAsStream(pathToXml));
053        try {
054          return fromXml(reader);
055        } finally {
056          IOUtils.closeQuietly(reader);
057        }
058      }
059    
060      private static XStream getXStream() {
061        XStream xstream = new XStream(new CompactDriver());
062        xstream.registerConverter(new CheckConverter());
063        xstream.alias("profile", CheckProfile.class);
064        xstream.alias("check", Check.class);
065        xstream.addImplicitCollection(CheckProfile.class, "checks");
066        return xstream;
067      }
068    
069      private static class CompactDriver extends XppDriver {
070        @Override
071        public HierarchicalStreamWriter createWriter(Writer out) {
072          return new XDataPrintWriter(out);
073        }
074      }
075    
076    
077      private static class XDataPrintWriter extends CompactWriter {
078        public XDataPrintWriter(Writer writer) {
079          super(writer, XML_1_0);
080        }
081      }
082    
083      private static class CheckConverter implements Converter {
084    
085        public boolean canConvert(Class clazz) {
086          return clazz.equals(Check.class);
087        }
088    
089        public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
090          Check check = (Check) value;
091          writer.startNode("repository");
092          writer.setValue(check.getRepositoryKey());
093          writer.endNode();
094          writer.startNode("template");
095          writer.setValue(check.getTemplateKey());
096          writer.endNode();
097          writer.startNode("priority");
098          writer.setValue(check.getPriority().toString());
099          writer.endNode();
100          for (Map.Entry<String, String> entry : check.getProperties().entrySet()) {
101            if (entry.getValue() != null) {
102              writer.startNode("property");
103              writer.startNode("key");
104              writer.setValue(entry.getKey());
105              writer.endNode();
106              writer.startNode("value");
107              // TODO is escaping automatically supported by xstream ?
108              writer.setValue(entry.getValue());
109              writer.endNode();
110              writer.endNode();
111            }
112          }
113        }
114    
115        public Object unmarshal(HierarchicalStreamReader reader,
116                                UnmarshallingContext context) {
117          Check check = new Check();
118          while (reader.hasMoreChildren()) {
119            reader.moveDown();
120            readValue(reader, check);
121            reader.moveUp();
122          }
123          return check;
124        }
125    
126        private void readValue(HierarchicalStreamReader reader, Check check) {
127          if (reader.getNodeName().equals("repository")) {
128            check.setRepositoryKey(reader.getValue());
129    
130          } else if (reader.getNodeName().equals("template")) {
131            check.setTemplateKey(reader.getValue());
132    
133          } else if (reader.getNodeName().equals("priority")) {
134            check.setPriority(Priority.valueOf(reader.getValue()));
135    
136          } else if (reader.getNodeName().equals("property")) {
137            reader.moveDown();
138            String key = reader.getValue();
139            reader.moveUp();
140    
141            reader.moveDown();
142            String value = reader.getValue();
143            reader.moveUp();
144            check.addProperty(key, value);
145          }
146        }
147    
148      }
149    }