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.java.bytecode;
021
022 import java.io.File;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.Collection;
026 import java.util.List;
027
028 import org.sonar.java.bytecode.asm.AsmClass;
029 import org.sonar.java.bytecode.asm.AsmClassProvider;
030 import org.sonar.java.bytecode.asm.AsmClassProviderImpl;
031 import org.sonar.java.bytecode.asm.AsmClassProvider.DETAIL_LEVEL;
032 import org.sonar.java.bytecode.visitor.AccessorVisitor;
033 import org.sonar.java.bytecode.visitor.BytecodeVisitor;
034 import org.sonar.java.bytecode.visitor.DITVisitor;
035 import org.sonar.java.bytecode.visitor.DeadCodeDetectionVisitor;
036 import org.sonar.java.bytecode.visitor.DependenciesVisitor;
037 import org.sonar.java.bytecode.visitor.LCOM4Visitor;
038 import org.sonar.java.bytecode.visitor.NOCVisitor;
039 import org.sonar.java.bytecode.visitor.RFCVisitor;
040 import org.sonar.squid.api.CodeScanner;
041 import org.sonar.squid.api.SourceClass;
042 import org.sonar.squid.api.SourceCode;
043 import org.sonar.squid.indexer.QueryByType;
044 import org.sonar.squid.indexer.SquidIndex;
045
046 public class BytecodeScanner extends CodeScanner<BytecodeVisitor> {
047
048 private SquidIndex indexer;
049
050 public BytecodeScanner(SquidIndex indexer) {
051 this.indexer = indexer;
052 }
053
054 public BytecodeScanner scan(Collection<File> bytecodeFilesOrDirectories) {
055 Collection<SourceCode> classes = indexer.search(new QueryByType(SourceClass.class));
056 return scan(classes, new AsmClassProviderImpl(ClassworldsClassLoader.create(bytecodeFilesOrDirectories)));
057 }
058
059 public BytecodeScanner scanDirectory(File bytecodeDirectory) {
060 return scan(Arrays.asList(bytecodeDirectory));
061 }
062
063 protected BytecodeScanner scan(Collection<SourceCode> classes, AsmClassProvider classProvider) {
064 loadByteCodeInformation(classes, classProvider);
065 notifyBytecodeVisitors(classes, classProvider);
066 return this;
067 }
068
069 private void notifyBytecodeVisitors(Collection<SourceCode> classes, AsmClassProvider classProvider) {
070 BytecodeVisitor[] visitorArray = getVisitors().toArray(new BytecodeVisitor[getVisitors().size()]);
071 for (SourceCode sourceCode : classes) {
072 AsmClass asmClass = classProvider.getClass(sourceCode.getKey(), DETAIL_LEVEL.STRUCTURE_AND_CALLS);
073 BytecodeVisitorNotifier visitorNotifier = new BytecodeVisitorNotifier(asmClass, visitorArray);
074 visitorNotifier.notifyVisitors();
075 }
076 }
077
078 private void loadByteCodeInformation(Collection<SourceCode> classes, AsmClassProvider classProvider) {
079 for (SourceCode sourceCode : classes) {
080 classProvider.getClass(sourceCode.getKey(), DETAIL_LEVEL.STRUCTURE_AND_CALLS);
081 }
082 }
083
084 @Override
085 public Collection<Class<? extends BytecodeVisitor>> getVisitorClasses() {
086 List<Class<? extends BytecodeVisitor>> visitorClasses = new ArrayList<Class<? extends BytecodeVisitor>>();
087 visitorClasses.add(AccessorVisitor.class);
088 visitorClasses.add(DITVisitor.class);
089 visitorClasses.add(RFCVisitor.class);
090 visitorClasses.add(NOCVisitor.class);
091 visitorClasses.add(LCOM4Visitor.class);
092 visitorClasses.add(DependenciesVisitor.class);
093 visitorClasses.add(DeadCodeDetectionVisitor.class);
094 return visitorClasses;
095 }
096 }