001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
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.plugins.squid.bridges;
021    
022    import com.google.common.collect.Lists;
023    import org.sonar.api.measures.CoreMetrics;
024    import org.sonar.api.measures.Measure;
025    import org.sonar.api.measures.PersistenceMode;
026    import org.sonar.api.resources.Qualifiers;
027    import org.sonar.api.resources.Resource;
028    import org.sonar.java.bytecode.asm.AsmField;
029    import org.sonar.java.bytecode.asm.AsmMethod;
030    import org.sonar.java.bytecode.asm.AsmResource;
031    import org.sonar.squid.api.SourceFile;
032    import org.sonar.squid.measures.Metric;
033    
034    import java.util.Collections;
035    import java.util.Comparator;
036    import java.util.List;
037    import java.util.Set;
038    
039    public class Lcom4BlocksBridge extends Bridge {
040    
041      protected Lcom4BlocksBridge() {
042        super(true);
043      }
044    
045      @Override
046      public void onFile(SourceFile squidFile, Resource sonarFile) {
047        List<Set<AsmResource>> blocks = (List<Set<AsmResource>>) squidFile.getData(Metric.LCOM4_BLOCKS);
048    
049        // This measure includes AsmResource objects and it is used only by this bridge, so
050        // it can be removed from memory.
051        squidFile.removeMeasure(Metric.LCOM4_BLOCKS);
052    
053        if (blocks != null && !blocks.isEmpty()) {
054          Measure measure = new Measure(CoreMetrics.LCOM4_BLOCKS, serialize(blocks));
055          measure.setPersistenceMode(PersistenceMode.DATABASE);
056          context.saveMeasure(sonarFile, measure);
057        }
058      }
059    
060      protected void sortBlocks(List<Set<AsmResource>> blocks) {
061        Collections.sort(blocks, new Comparator<Set>() {
062          public int compare(Set set1, Set set2) {
063            return set1.size() - set2.size();
064          }
065        });
066      }
067    
068      protected String serialize(List<Set<AsmResource>> blocks) {
069        sortBlocks(blocks);
070    
071        StringBuilder sb = new StringBuilder();
072        sb.append('[');
073    
074        for (int indexBlock = 0; indexBlock < blocks.size(); indexBlock++) {
075          blocks.get(indexBlock);
076          Set<AsmResource> block = blocks.get(indexBlock);
077          if (!block.isEmpty()) {
078            if (indexBlock > 0) {
079              sb.append(',');
080            }
081            sb.append('[');
082            serializeBlock(block, sb);
083            sb.append(']');
084          }
085        }
086        sb.append(']');
087        return sb.toString();
088      }
089    
090      private void serializeBlock(Set<AsmResource> block, StringBuilder sb) {
091        List<AsmResource> sortedResources = sortResourcesInBlock(block);
092        int indexResource = 0;
093        for (AsmResource resource : sortedResources) {
094          if (indexResource++ > 0) {
095            sb.append(',');
096          }
097          serializeResource(resource, sb);
098        }
099      }
100    
101      private void serializeResource(AsmResource resource, StringBuilder sb) {
102        sb.append("{\"q\":\"");
103        sb.append(toQualifier(resource));
104        sb.append("\",\"n\":\"");
105        sb.append(resource.toString());
106        sb.append("\"}");
107      }
108    
109      protected List<AsmResource> sortResourcesInBlock(Set<AsmResource> block) {
110        List<AsmResource> result = Lists.newArrayList();
111        result.addAll(block);
112    
113        Collections.sort(result, new Comparator<AsmResource>() {
114          public int compare(AsmResource asmResource1, AsmResource asmResource2) {
115            int result = compareType(asmResource1, asmResource2);
116            if (result == 0) {
117              result = asmResource1.toString().compareTo(asmResource2.toString());
118            }
119            return result;
120          }
121    
122          private int compareType(AsmResource asmResource1, AsmResource asmResource2) {
123            if (asmResource1 instanceof AsmField) {
124              return (asmResource2 instanceof AsmField) ? 0 : -1;
125            }
126            return (asmResource2 instanceof AsmMethod) ? 0 : 1;
127          }
128        });
129    
130        return result;
131      }
132    
133      private static String toQualifier(AsmResource asmResource) {
134        if (asmResource instanceof AsmField) {
135          return Qualifiers.FIELD;
136        }
137        if (asmResource instanceof AsmMethod) {
138          return Qualifiers.METHOD;
139        }
140        throw new IllegalArgumentException("Wrong ASM resource: " + asmResource.getClass());
141      }
142    }