/* * Sonar is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Sonar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Sonar; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ package org.codehaus.sonar.plugins.testability.xml; import org.codehaus.sonar.plugins.testability.client.model.MethodTestabilityCostDetail; import org.codehaus.sonar.plugins.testability.client.model.ViolationCostDetail; import org.codehaus.sonar.plugins.testability.measurers.MethodTestabilityCostMeasurer; import org.codehaus.staxmate.SMInputFactory; import org.codehaus.staxmate.in.SMEvent; import org.codehaus.staxmate.in.SMInputCursor; import org.sonar.api.batch.SensorContext; import org.sonar.api.measures.Measure; import org.sonar.api.resources.JavaFile; import org.sonar.api.resources.Resource; import org.sonar.api.utils.XmlParserException; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import java.io.File; import static org.codehaus.sonar.plugins.testability.TestabilityMetrics.*; public class TestabilityStaxParser { private static final String REASON_ATTR = "reason"; private static final String LINE_ATTR = "line"; private static final String NEEDS_WORK_ATTR = "needsWork"; private static final String GOOD_ATTR = "good"; private static final String EXCELLENT_ATTR = "excellent"; private static final String OVERALL_ATTR = "overall"; private static final String LOD_ATTR = "lod"; private static final String GLOBAL_ATTR = "global"; private static final String CYCLOMATIC_ATTR = "cyclomatic"; private static final String CLASS_TAG = "class"; private static final String METHOD_TAG = "method"; private static final String COST_TAG = "cost"; public void parse(File file, SensorContext context) { SMInputFactory inf = new SMInputFactory(XMLInputFactory.newInstance()); try { SMInputCursor cursor = inf.rootElementCursor(file).advance(); parseTestability(cursor, context); cursor.getStreamReader().closeCompletely(); } catch (XMLStreamException e) { throw new XmlParserException(e); } } private void parseTestability(SMInputCursor cursor, SensorContext context) throws XMLStreamException { context.saveMeasure(EXCELLENT_CLASSES, StaxMateHelper.getDoubleValue(cursor, EXCELLENT_ATTR)); context.saveMeasure(ACCEPTABLE_CLASSES, StaxMateHelper.getDoubleValue(cursor, GOOD_ATTR)); context.saveMeasure(NEEDSWORK_CLASSES, StaxMateHelper.getDoubleValue(cursor, NEEDS_WORK_ATTR)); context.saveMeasure(TESTABILITY_COST, StaxMateHelper.getDoubleValue(cursor, OVERALL_ATTR)); parseClasses(cursor, context); } private void parseClasses(SMInputCursor cursor, SensorContext context) throws XMLStreamException { SMInputCursor classCursor = cursor.descendantElementCursor(CLASS_TAG); SMEvent event; while ((event = classCursor.getNext()) != null) { if (event.compareTo(SMEvent.START_ELEMENT) == 0) { Resource<?> resource = new JavaFile(StaxMateHelper.getStringValue(classCursor, CLASS_TAG)); context.saveMeasure(resource, new Measure(TESTABILITY_COST, StaxMateHelper.getDoubleValue(classCursor, COST_TAG))); MethodTestabilityCostMeasurer measurer = new MethodTestabilityCostMeasurer(); parseMethods(classCursor, measurer); context.saveMeasure(resource, measurer.build()); } } } private void parseMethods(SMInputCursor cursor, MethodTestabilityCostMeasurer measurer) throws XMLStreamException { SMInputCursor methodCursor = cursor.descendantElementCursor(METHOD_TAG); SMEvent event; while ((event = methodCursor.getNext()) != null) { if (event.compareTo(SMEvent.START_ELEMENT) == 0) { addMethodCostToMeasurer(methodCursor, measurer); parseViolations(methodCursor, measurer); } } } private void addMethodCostToMeasurer(SMInputCursor cursor, MethodTestabilityCostMeasurer measurer) { MethodTestabilityCostDetail methodCostDetail = new MethodTestabilityCostDetail(); methodCostDetail.setCyclomaticComplexity(StaxMateHelper.getIntValue(cursor, CYCLOMATIC_ATTR)); methodCostDetail.setGlobal(StaxMateHelper.getIntValue(cursor, GLOBAL_ATTR)); methodCostDetail.setLawOfDemeter(StaxMateHelper.getIntValue(cursor, LOD_ATTR)); methodCostDetail.setOverall(StaxMateHelper.getIntValue(cursor, OVERALL_ATTR)); measurer.addMethodCost(StaxMateHelper.getIntValue(cursor, LINE_ATTR) - 1, methodCostDetail); } private void parseViolations(SMInputCursor cursor, MethodTestabilityCostMeasurer measurer) throws XMLStreamException { SMInputCursor violationCursor = cursor.descendantElementCursor(COST_TAG); SMEvent event; while ((event = violationCursor.getNext()) != null) { if (event.compareTo(SMEvent.START_ELEMENT) == 0) { addViolationCostToMeasurer(violationCursor, measurer); } } } private void addViolationCostToMeasurer(SMInputCursor violationCursor, MethodTestabilityCostMeasurer measurer) { ViolationCostDetail violationCostDetail = new ViolationCostDetail(); violationCostDetail.setCyclomaticComplexity(StaxMateHelper.getIntValue(violationCursor, CYCLOMATIC_ATTR)); violationCostDetail.setGlobal(StaxMateHelper.getIntValue(violationCursor, GLOBAL_ATTR)); violationCostDetail.setLawOfDemeter(StaxMateHelper.getIntValue(violationCursor, LOD_ATTR)); violationCostDetail.setOverall(StaxMateHelper.getIntValue(violationCursor, OVERALL_ATTR)); violationCostDetail.setReason(StaxMateHelper.getStringValue(violationCursor, REASON_ATTR)); measurer.addViolationCost(StaxMateHelper.getIntValue(violationCursor, LINE_ATTR), violationCostDetail); } }