├── .gitignore ├── .hgignore ├── README.md ├── license.txt ├── nbactions.xml ├── pom.xml └── src ├── docs └── images │ ├── actionPlan.png │ ├── configuration.png │ ├── contextMenu.png │ ├── custom.png │ ├── issues.png │ ├── ruleDialog.png │ ├── sourcesMenu.png │ └── summary.png ├── main ├── java │ └── qubexplorer │ │ ├── AuthorizationException.java │ │ ├── Classifier.java │ │ ├── ClassifierSummary.java │ │ ├── ClassifierType.java │ │ ├── ConfigurationFactory.java │ │ ├── GenericSonarQubeProjectConfiguration.java │ │ ├── IssueType.java │ │ ├── IssuesContainer.java │ │ ├── MvnModelFactory.java │ │ ├── MvnModelInputException.java │ │ ├── NoSuchProjectException.java │ │ ├── PassEncoder.java │ │ ├── PlainDirectoryProject.java │ │ ├── ProjectNotFoundException.java │ │ ├── RadarIssue.java │ │ ├── ResourceKey.java │ │ ├── Rule.java │ │ ├── Severity.java │ │ ├── SonarMvnProject.java │ │ ├── SonarQubeProjectConfiguration.java │ │ ├── SonarQubeProjectException.java │ │ ├── Summary.java │ │ ├── SummaryOptions.java │ │ ├── UserCredentials.java │ │ ├── filter │ │ ├── AssigneesFilter.java │ │ ├── IssueFilter.java │ │ ├── RuleFilter.java │ │ ├── SeverityFilter.java │ │ └── TypeFilter.java │ │ ├── runner │ │ ├── Module.java │ │ ├── SonarRunnerCancelledException.java │ │ ├── SonarRunnerClassifierSummary.java │ │ ├── SonarRunnerException.java │ │ ├── SonarRunnerProccess.java │ │ ├── SonarRunnerResult.java │ │ ├── SourcesNotFoundException.java │ │ ├── VersionConfig.java │ │ ├── VersionConfigLessThan4.java │ │ ├── VersionConfigLessThan5Point2.java │ │ ├── VersionConfigMoreThan5Point2.java │ │ └── ui │ │ │ ├── SonarRunnerAction.java │ │ │ └── SonarRunnerTask.java │ │ ├── server │ │ ├── Component.java │ │ ├── ComponentSearchResult.java │ │ ├── IssuesSearchResult.java │ │ ├── Paging.java │ │ ├── Resource.java │ │ ├── RuleResult.java │ │ ├── ServerStatus.java │ │ ├── SimpleClassifierSummary.java │ │ ├── SonarQube.java │ │ ├── Version.java │ │ └── ui │ │ │ ├── CustomServerIssuesAction.java │ │ │ ├── ServerConnectionDialog.form │ │ │ ├── ServerConnectionDialog.java │ │ │ ├── ServerIssuesAction.java │ │ │ ├── SonarQubeFactory.java │ │ │ ├── SummarySettingsDialog.form │ │ │ └── SummarySettingsDialog.java │ │ └── ui │ │ ├── AuthDialog.form │ │ ├── AuthDialog.java │ │ ├── FileOpenedNotifier.java │ │ ├── IssueEditorAnnotationAttacher.java │ │ ├── PopupAction.java │ │ ├── ProjectContext.java │ │ ├── ProjectRenderer.java │ │ ├── RuleDialog.form │ │ ├── RuleDialog.java │ │ ├── RuleTask.java │ │ ├── SeverityIconRenderer.java │ │ ├── SonarIssuesTopComponent.form │ │ ├── SonarIssuesTopComponent.java │ │ ├── SonarQubeOptionsPanel.form │ │ ├── SonarQubeOptionsPanel.java │ │ ├── SonarQubeOptionsPanelController.java │ │ ├── UserCredentialsRepository.java │ │ ├── issues │ │ ├── FileObjectOpenedListener.java │ │ ├── IssueLocation.java │ │ ├── IssuesTableModel.java │ │ ├── IssuesTask.java │ │ ├── LocationRenderer.java │ │ └── SonarQubeEditorAnnotation.java │ │ ├── summary │ │ ├── ClassifierSummaryModel.java │ │ ├── SummaryTask.java │ │ └── SummaryTreeCellRenderer.java │ │ └── task │ │ ├── Task.java │ │ ├── TaskExecutionException.java │ │ └── TaskExecutor.java ├── nbm │ └── manifest.mf └── resources │ └── qubexplorer │ ├── server │ └── ui │ │ └── Bundle.properties │ ├── sonarqubeexplorer │ ├── Bundle.properties │ ├── blocker-annotation.xml │ ├── critical-annotation.xml │ ├── info-annotation.xml │ ├── layer.xml │ ├── major-annotation.xml │ └── minor-annotation.xml │ └── ui │ ├── Bundle.properties │ ├── images │ ├── application_view_list.png │ ├── arrow_refresh_small.png │ ├── blocker.png │ ├── critical.png │ ├── eye.png │ ├── info.png │ ├── information.png │ ├── major.png │ ├── minor.png │ ├── page_gear.png │ └── stop.png │ ├── options │ └── Bundle.properties │ └── summary │ └── Bundle.properties └── test └── java └── qubexplorer ├── PassEncoderTest.java ├── ResourceKeyTest.java ├── runner └── SonarRunnerProccessTest.java ├── server ├── SimpleClassifierSummaryTest.java └── VersionTest.java └── ui ├── AuthenticationRepositoryTest.java └── task └── TaskExecutorTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /nbproject/ -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | \.orig$ 2 | \.orig\..*$ 3 | \.chg\..*$ 4 | \.rej$ 5 | \.conflict\~$ 6 | ^hs_err_pid6512\.log$ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Radar 2 | 3 | Radar is a plugin for Netbeans to navigate directly from the issue to the code without leaving your IDE. 4 | 5 | You can retrieve issues from a server or you can run a local analysis. 6 | 7 | ## Configuration 8 | 9 | ![Configuration](src/docs/images/configuration.png) 10 | 11 | You can configure the url of your SonarQube server (default is localhost, port 9000). 12 | 13 | For local analysis, you can choose if you want to use preview or incremental mode. See more information about SonarQube Runner analysis mode in: http://docs.codehaus.org/display/SONAR/Concepts#Concepts-AnalysisModes 14 | 15 | Also, you can set JVM arguments for sonar runner proccess (For example, max memory heap space). 16 | 17 | ## Seeing issues 18 | 19 | To see the SonarQube issues just invoke the contextual menu in your Java project and choose how you get your issues. 20 | 21 | ![Contextual Menu](src/docs/images/contextMenu.png) 22 | 23 | These are the ways to retrieve the issues: 24 | 25 | ### Get Issues From Server 26 | 27 | Get the issues from a remote server. The analysis was previous done and statistics are already in the server. Uses the url already configured. 28 | The key of the project is automatically generated from the maven pom. 29 | 30 | For a multimodule project you have to invoke the action in the main parent project. 31 | 32 | ### Get Issues From Server ... 33 | 34 | Same as previous but a dialog appears that allows you to use a different server url and choose a different project key in the server. 35 | 36 | ![Custom Connection](src/docs/images/custom.png) 37 | 38 | Same note for multimodule project applies too. 39 | 40 | ### Get Issues with Sonar Runner 41 | 42 | This analysis is made locally with SonarQube Runner. A connection to the server is yet required to download the quality profile. 43 | 44 | ## See the issues 45 | 46 | So, after choosing the way to retrieve issues and some processing, a count of your issues will appear. The count is shown by severity and by rule. 47 | 48 | ![Summary](src/docs/images/summary.png) 49 | 50 | Note: For remote retrieving of issues, you can filter your issues by action plan if there is any. 51 | 52 | ![Action Plan](src/docs/images/actionPlan.png) 53 | 54 | To see the issues for a particular category, select and click in List issues and a table with the issues will be shown. From here you can go to the code 55 | right-clicking a row. 56 | 57 | ![Issues](src/docs/images/issues.png) 58 | 59 | If you wanna see more information about a rule, select it from the Summary view and click the button *Show Information*. A dialog will open and show more documentation about the rule. 60 | 61 | ![Rule Dialog](src/docs/images/ruleDialog.png) 62 | 63 | # Notes 64 | 65 | Before calling Sonar runner from this plugin, clean and build the project. 66 | 67 | The plugin uses de web service API of sonar for remote retrieving of issues, so there can be some limitations on amount of displayed information. For example, at this moment, the maximum number of retrieved issues per request is 10,000. 68 | 69 | It works from SonarQube 3.7 to SonarQube 6.2. 70 | 71 | # Download 72 | 73 | You can download Radar [Here](http://plugins.netbeans.org/plugin/51532/radar-netbeans here) 74 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright [2013] [Victor Hugo Herrera Maldonado] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CUSTOM-Sonar 5 | Sonar 6 | 7 | sonar:sonar 8 | 9 | 10 | 11 | CUSTOM-Clean & Run 12 | Clean & Run 13 | 14 | clean 15 | install 16 | nbm:cluster 17 | nbm:run-ide 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/docs/images/actionPlan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/actionPlan.png -------------------------------------------------------------------------------- /src/docs/images/configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/configuration.png -------------------------------------------------------------------------------- /src/docs/images/contextMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/contextMenu.png -------------------------------------------------------------------------------- /src/docs/images/custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/custom.png -------------------------------------------------------------------------------- /src/docs/images/issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/issues.png -------------------------------------------------------------------------------- /src/docs/images/ruleDialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/ruleDialog.png -------------------------------------------------------------------------------- /src/docs/images/sourcesMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/sourcesMenu.png -------------------------------------------------------------------------------- /src/docs/images/summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/docs/images/summary.png -------------------------------------------------------------------------------- /src/main/java/qubexplorer/AuthorizationException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class AuthorizationException extends RuntimeException{ 8 | 9 | public AuthorizationException() { 10 | } 11 | 12 | public AuthorizationException(Throwable thrwbl) { 13 | super(thrwbl); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/Classifier.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import javax.swing.Icon; 4 | import qubexplorer.filter.IssueFilter; 5 | 6 | /** 7 | * 8 | * @author Víctor 9 | */ 10 | public interface Classifier { 11 | 12 | IssueFilter createFilter(); 13 | 14 | Icon getIcon(); 15 | 16 | String getUserDescription(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ClassifierSummary.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * 7 | * @author Victor 8 | */ 9 | public interface ClassifierSummary{ 10 | 11 | int getCount(T classifier); 12 | 13 | int getCount(Rule rule); 14 | 15 | int getCount(); 16 | 17 | Set getRules(T classifier); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ClassifierType.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 7 | * @author Víctor 8 | */ 9 | public interface ClassifierType { 10 | 11 | T valueOf(RadarIssue issue); 12 | 13 | List getValues(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ConfigurationFactory.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import org.netbeans.api.project.Project; 4 | 5 | /** 6 | * 7 | * @author Victor 8 | */ 9 | public final class ConfigurationFactory { 10 | 11 | private ConfigurationFactory() { 12 | } 13 | 14 | public static SonarQubeProjectConfiguration createDefaultConfiguration(Project project) { 15 | if (SonarMvnProject.isMvnProject(project)) { 16 | return new SonarMvnProject(project); 17 | } else { 18 | return new PlainDirectoryProject(project); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/GenericSonarQubeProjectConfiguration.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Properties; 4 | import org.netbeans.api.project.Project; 5 | 6 | 7 | public class GenericSonarQubeProjectConfiguration implements SonarQubeProjectConfiguration { 8 | private String name; 9 | private ResourceKey key; 10 | private String version; 11 | 12 | public GenericSonarQubeProjectConfiguration(String name, ResourceKey key, String version) { 13 | this.name = name; 14 | this.key = key; 15 | this.version = version; 16 | } 17 | 18 | public GenericSonarQubeProjectConfiguration() { 19 | } 20 | 21 | public void setName(String name) { 22 | this.name = name; 23 | } 24 | 25 | public void setKey(ResourceKey key) { 26 | this.key = key; 27 | } 28 | 29 | public void setVersion(String version) { 30 | this.version = version; 31 | } 32 | 33 | @Override 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | @Override 39 | public ResourceKey getKey() { 40 | return key; 41 | } 42 | 43 | @Override 44 | public String getVersion() { 45 | return version; 46 | } 47 | 48 | @Override 49 | public SonarQubeProjectConfiguration createConfiguration(Project subproject) { 50 | throw new UnsupportedOperationException(); 51 | } 52 | 53 | @Override 54 | public Properties getProperties() { 55 | throw new UnsupportedOperationException(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/IssueType.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import javax.swing.Icon; 6 | import qubexplorer.filter.IssueFilter; 7 | import qubexplorer.filter.TypeFilter; 8 | 9 | /** 10 | * 11 | * @author Victor 12 | */ 13 | public enum IssueType implements Classifier { 14 | 15 | BUG("Bug"), 16 | VULNERABILITY("Vulnerability"), 17 | CODE_SMELL("Code smell"); 18 | 19 | private final String userDescription; 20 | 21 | private IssueType(String userDescription) { 22 | this.userDescription = userDescription; 23 | } 24 | 25 | @Override 26 | public IssueFilter createFilter() { 27 | return new TypeFilter(this); 28 | } 29 | 30 | @Override 31 | public Icon getIcon() { 32 | return null; 33 | } 34 | 35 | @Override 36 | public String getUserDescription() { 37 | return userDescription; 38 | } 39 | 40 | public static ClassifierType getType() { 41 | return INSTANCE; 42 | } 43 | 44 | private static final ClassifierType INSTANCE=new IssueTypeClassifier(); 45 | 46 | private static class IssueTypeClassifier implements ClassifierType{ 47 | 48 | @Override 49 | public IssueType valueOf(RadarIssue issue) { 50 | return IssueType.valueOf(issue.type().toUpperCase()); 51 | } 52 | 53 | @Override 54 | public List getValues() { 55 | return Arrays.asList(IssueType.values()); 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/IssuesContainer.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.List; 4 | import qubexplorer.filter.IssueFilter; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public interface IssuesContainer { 11 | 12 | List getIssues(UserCredentials auth, ResourceKey projectKey, List filters); 13 | 14 | ClassifierSummary getSummary(ClassifierType classifierType, UserCredentials authentication, ResourceKey projectKey, List filters); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/MvnModelFactory.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.Reader; 7 | import org.apache.maven.model.Model; 8 | import org.apache.maven.model.io.xpp3.MavenXpp3Reader; 9 | import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 10 | import org.netbeans.api.project.Project; 11 | import org.openide.filesystems.FileObject; 12 | 13 | /** 14 | * 15 | * @author Victor 16 | */ 17 | public class MvnModelFactory { 18 | 19 | public Model createModel(Project project) throws MvnModelInputException{ 20 | return createModel(project.getProjectDirectory()); 21 | } 22 | 23 | public Model createModel(FileObject projectDir) throws MvnModelInputException { 24 | FileObject pomFile = projectDir.getFileObject("pom.xml"); 25 | MavenXpp3Reader mavenreader = new MavenXpp3Reader(); 26 | try(Reader reader=new InputStreamReader(pomFile.getInputStream())){ 27 | Model model = mavenreader.read(reader); 28 | model.setPomFile(new File(pomFile.getPath())); 29 | return model; 30 | }catch(XmlPullParserException | IOException ex) { 31 | throw new MvnModelInputException(ex); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/MvnModelInputException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class MvnModelInputException extends Exception{ 8 | 9 | public MvnModelInputException(Throwable cause) { 10 | super(cause); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/NoSuchProjectException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class NoSuchProjectException extends RuntimeException{ 8 | private final ResourceKey projectKey; 9 | 10 | public NoSuchProjectException(ResourceKey projectKey) { 11 | this.projectKey = projectKey; 12 | } 13 | 14 | public ResourceKey getProjectKey() { 15 | return projectKey; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/PassEncoder.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import org.apache.commons.codec.binary.Base64; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public final class PassEncoder { 11 | 12 | private PassEncoder() { 13 | 14 | } 15 | 16 | public static char[] encode(char[] chars){ 17 | return new String(Base64.encodeBase64(new String(chars).getBytes(StandardCharsets.UTF_8))).toCharArray(); 18 | } 19 | 20 | public static char[] decode(char[] chars){ 21 | return decodeAsString(chars).toCharArray(); 22 | } 23 | 24 | public static String decodeAsString(char[] chars){ 25 | return new String(Base64.decodeBase64(new String(chars).getBytes()), StandardCharsets.UTF_8); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/PlainDirectoryProject.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.Properties; 8 | import org.netbeans.api.project.Project; 9 | import org.netbeans.api.project.ProjectUtils; 10 | import org.openide.filesystems.FileObject; 11 | 12 | public class PlainDirectoryProject implements SonarQubeProjectConfiguration { 13 | 14 | private final Project project; 15 | private Properties properties; 16 | 17 | public PlainDirectoryProject(Project project){ 18 | this.project = project; 19 | try { 20 | loadProjectProperties(); 21 | } catch (IOException ex) { 22 | throw new SonarQubeProjectException(ex); 23 | } 24 | } 25 | 26 | private void loadProjectProperties() throws IOException { 27 | properties = new Properties(); 28 | FileObject fileObject = project.getProjectDirectory().getFileObject("sonar.properties"); 29 | if (fileObject != null) { 30 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(fileObject.getInputStream(), StandardCharsets.UTF_8))) { 31 | properties.load(reader); 32 | } 33 | } 34 | } 35 | 36 | @Override 37 | public String getName() { 38 | return properties.getProperty(SonarMvnProject.PROPERTY_NAME, ProjectUtils.getInformation(project).getName()); 39 | } 40 | 41 | @Override 42 | public ResourceKey getKey() { 43 | String propertyValue = properties.getProperty(SonarMvnProject.PROPERTY_KEY); 44 | if (propertyValue != null) { 45 | return ResourceKey.valueOf(propertyValue); 46 | } else { 47 | return new ResourceKey(getName()); 48 | } 49 | } 50 | 51 | @Override 52 | public String getVersion() { 53 | return properties.getProperty(SonarMvnProject.PROPERTY_VERSION, "1.0"); 54 | } 55 | 56 | @Override 57 | public SonarQubeProjectConfiguration createConfiguration(Project subproject) { 58 | return new PlainDirectoryProject(subproject); 59 | } 60 | 61 | @Override 62 | public Properties getProperties() { 63 | return properties; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ProjectNotFoundException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class ProjectNotFoundException extends RuntimeException{ 8 | private final String shortProjectKey; 9 | 10 | public ProjectNotFoundException(String shortProjectKey) { 11 | this.shortProjectKey = shortProjectKey; 12 | } 13 | 14 | public String getShortProjectKey() { 15 | return shortProjectKey; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/RadarIssue.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import java.util.Collections; 6 | import java.util.Date; 7 | import java.util.Map; 8 | import qubexplorer.ui.issues.IssueLocation; 9 | 10 | /** 11 | * 12 | * @author Victor 13 | */ 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | public class RadarIssue { 16 | 17 | private String key; 18 | @JsonProperty("component") 19 | private String componentKey; 20 | private Integer line; 21 | private String message; 22 | private String severity; 23 | @JsonProperty("rule") 24 | private String ruleKey; 25 | private String status; 26 | private Date creationDate; 27 | private Date updateDate; 28 | private Rule rule; 29 | private String type; 30 | 31 | public RadarIssue() { 32 | } 33 | 34 | public void setKey(String key) { 35 | this.key = key; 36 | } 37 | 38 | public void setComponentKey(String componentKey) { 39 | this.componentKey = componentKey; 40 | } 41 | 42 | public void setLine(Integer line) { 43 | this.line = line; 44 | } 45 | 46 | public void setMessage(String message) { 47 | this.message = message; 48 | } 49 | 50 | public void setSeverity(String severity) { 51 | this.severity = severity; 52 | } 53 | 54 | public void setRuleKey(String ruleKey) { 55 | this.ruleKey = ruleKey; 56 | } 57 | 58 | public void setStatus(String status) { 59 | this.status = status; 60 | } 61 | 62 | public void setCreationDate(Date creationDate) { 63 | this.creationDate = creationDate; 64 | } 65 | 66 | public void setUpdateDate(Date updateDate) { 67 | this.updateDate = updateDate; 68 | } 69 | 70 | public String key() { 71 | return key; 72 | } 73 | 74 | public String componentKey() { 75 | return componentKey; 76 | } 77 | 78 | public String projectKey() { 79 | throw new UnsupportedOperationException("Not yet implemented"); 80 | } 81 | 82 | public String ruleKey() { 83 | return ruleKey; 84 | } 85 | 86 | public String severity() { 87 | return severity; 88 | } 89 | 90 | public String message() { 91 | return message; 92 | } 93 | 94 | public Integer line() { 95 | return line; 96 | } 97 | 98 | public String status() { 99 | return status; 100 | } 101 | 102 | public String resolution() { 103 | return ""; 104 | } 105 | 106 | public String reporter() { 107 | return ""; 108 | } 109 | 110 | public String assignee() { 111 | return ""; 112 | } 113 | 114 | public String author() { 115 | return ""; 116 | } 117 | 118 | public String actionPlan() { 119 | return ""; 120 | } 121 | 122 | public Date creationDate() { 123 | return creationDate; 124 | } 125 | 126 | public Date updateDate() { 127 | return updateDate; 128 | } 129 | 130 | public Date closeDate() { 131 | return null; 132 | } 133 | 134 | public String attribute(String key) { 135 | return ""; 136 | } 137 | 138 | public Map attributes() { 139 | return Collections.emptyMap(); 140 | } 141 | 142 | public Long componentId() { 143 | return 0L; 144 | } 145 | 146 | public String debt() { 147 | return ""; 148 | } 149 | 150 | public void setRule(Rule rule) { 151 | this.rule = rule; 152 | } 153 | 154 | public Rule rule() { 155 | return rule; 156 | } 157 | 158 | public Severity severityObject() { 159 | return Severity.valueOf(severity()); 160 | } 161 | 162 | public IssueLocation getLocation() { 163 | int lineNumber = line() == null ? 0 : line(); 164 | return new IssueLocation(componentKey(), lineNumber); 165 | } 166 | 167 | public String type() { 168 | return type; 169 | } 170 | 171 | public void setType(String type) { 172 | this.type = type; 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ResourceKey.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.io.Serializable; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public class ResourceKey implements Serializable { 11 | 12 | private final String[] parts; 13 | 14 | public ResourceKey(String... parts) { 15 | this.parts = parts; 16 | } 17 | 18 | public String getPart(int index) { 19 | return parts[index]; 20 | } 21 | 22 | public int getPartsCount() { 23 | return parts.length; 24 | } 25 | 26 | public String toString(int begin, int end) { 27 | StringBuilder builder = new StringBuilder(); 28 | for (int i = begin; i < end; i++) { 29 | if (builder.length() > 0) { 30 | builder.append(':'); 31 | } 32 | builder.append(parts[i]); 33 | } 34 | return builder.toString(); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return toString(0, parts.length); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Arrays.hashCode(parts); 45 | } 46 | 47 | @Override 48 | public boolean equals(Object obj) { 49 | if (!(obj instanceof ResourceKey)) { 50 | return false; 51 | } 52 | ResourceKey anotherKey = (ResourceKey) obj; 53 | return Arrays.equals(parts, anotherKey.parts); 54 | } 55 | 56 | public String getLastPart() { 57 | return parts[parts.length - 1]; 58 | } 59 | 60 | public ResourceKey subkey(int start, int end) { 61 | return new ResourceKey(Arrays.copyOfRange(parts, start, end)); 62 | } 63 | 64 | public ResourceKey concat(ResourceKey tempKey) { 65 | String[] newKeyParts=new String[parts.length+tempKey.parts.length]; 66 | System.arraycopy(parts, 0, newKeyParts, 0, parts.length); 67 | System.arraycopy(tempKey.parts, 0, newKeyParts, parts.length, tempKey.parts.length); 68 | return new ResourceKey(newKeyParts); 69 | } 70 | 71 | public static ResourceKey valueOf(String key) { 72 | return new ResourceKey(key.split(":")); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/Rule.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import java.util.Objects; 6 | 7 | /** 8 | * 9 | * @author Víctor 10 | */ 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | public class Rule { 13 | private String key; 14 | private String name; 15 | @JsonProperty("htmlDesc") 16 | private String description; 17 | 18 | public Rule(String key) { 19 | this.key = key; 20 | } 21 | 22 | public Rule() { 23 | } 24 | 25 | public String getKey() { 26 | return key; 27 | } 28 | 29 | public void setKey(String key) { 30 | this.key = key; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public void setName(String name) { 38 | this.name = name; 39 | } 40 | 41 | public String getDescription() { 42 | return description; 43 | } 44 | 45 | public void setDescription(String description) { 46 | this.description = description; 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | int hash = 5; 52 | hash = 17 * hash + Objects.hashCode(this.key); 53 | return hash; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object obj) { 58 | if (this == obj) { 59 | return true; 60 | } 61 | if (obj == null) { 62 | return false; 63 | } 64 | if (getClass() != obj.getClass()) { 65 | return false; 66 | } 67 | final Rule other = (Rule) obj; 68 | if (!Objects.equals(this.key, other.key)) { 69 | return false; 70 | } 71 | return true; 72 | } 73 | 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/Severity.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import javax.swing.Icon; 6 | import javax.swing.ImageIcon; 7 | import qubexplorer.filter.IssueFilter; 8 | import qubexplorer.filter.SeverityFilter; 9 | 10 | /** 11 | * 12 | * @author Victor 13 | */ 14 | public enum Severity implements Classifier { 15 | 16 | BLOCKER("Blocker", "/qubexplorer/ui/images/blocker.png"), 17 | CRITICAL("Critical", "/qubexplorer/ui/images/critical.png"), 18 | MAJOR("Major", "/qubexplorer/ui/images/major.png"), 19 | MINOR("Minor", "/qubexplorer/ui/images/minor.png"), 20 | INFO("Info", "/qubexplorer/ui/images/info.png"); 21 | 22 | private final String userDescription; 23 | private final String resourcePath; 24 | 25 | private Severity(String userDescription, String resourcePath) { 26 | this.userDescription = userDescription; 27 | this.resourcePath = resourcePath; 28 | } 29 | 30 | @Override 31 | public IssueFilter createFilter() { 32 | return new SeverityFilter(this); 33 | } 34 | 35 | @Override 36 | public Icon getIcon() { 37 | return new ImageIcon(getClass().getResource(resourcePath)); 38 | } 39 | 40 | @Override 41 | public String getUserDescription() { 42 | return userDescription; 43 | } 44 | 45 | public static ClassifierType getType() { 46 | return TYPE; 47 | } 48 | 49 | private static final SeverityType TYPE=new SeverityType(); 50 | 51 | private static class SeverityType implements ClassifierType { 52 | 53 | @Override 54 | public Severity valueOf(RadarIssue issue) { 55 | return Severity.valueOf(issue.severity().toUpperCase()); 56 | } 57 | 58 | @Override 59 | public List getValues() { 60 | return Arrays.asList(Severity.values()); 61 | } 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/SonarMvnProject.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.Reader; 7 | import java.util.Map; 8 | import java.util.Properties; 9 | import org.apache.maven.model.Build; 10 | import org.apache.maven.model.Model; 11 | import org.apache.maven.model.io.xpp3.MavenXpp3Reader; 12 | import org.apache.maven.project.MavenProject; 13 | import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 14 | import org.netbeans.api.project.Project; 15 | import org.openide.filesystems.FileObject; 16 | import org.openide.filesystems.FileUtil; 17 | 18 | /** 19 | * 20 | * @author Victor 21 | */ 22 | public class SonarMvnProject implements SonarQubeProjectConfiguration { 23 | 24 | public static final String PROPERTY_NAME = "sonar.projectName"; 25 | public static final String PROPERTY_VERSION = "sonar.projectVersion"; 26 | public static final String PROPERTY_KEY = "sonar.projectKey"; 27 | 28 | private final Model model; 29 | 30 | public SonarMvnProject(Project project) { 31 | try { 32 | this.model = createModel(project); 33 | } catch (MvnModelInputException ex) { 34 | throw new SonarQubeProjectException(ex); 35 | } 36 | } 37 | 38 | @Override 39 | public String getName() { 40 | String projectName = model.getProperties().getProperty(PROPERTY_NAME); 41 | if (projectName != null) { 42 | return projectName; 43 | } 44 | return model.getName() != null ? model.getName() : model.getArtifactId(); 45 | } 46 | 47 | @Override 48 | public ResourceKey getKey() { 49 | String projectKey = model.getProperties().getProperty(PROPERTY_KEY); 50 | if (projectKey != null) { 51 | return ResourceKey.valueOf(projectKey); 52 | } 53 | String groupId = model.getGroupId(); 54 | if (groupId == null && model.getParent() != null) { 55 | groupId = model.getParent().getGroupId(); 56 | } 57 | return new ResourceKey(groupId, model.getArtifactId()); 58 | } 59 | 60 | @Override 61 | public String getVersion() { 62 | String projectVersion = model.getProperties().getProperty(PROPERTY_VERSION); 63 | if (projectVersion != null) { 64 | return projectVersion; 65 | } 66 | String version = model.getVersion(); 67 | if (version == null && model.getParent() != null) { 68 | version = model.getParent().getVersion(); 69 | } 70 | return version; 71 | } 72 | 73 | public static Model createModel(Project project) throws MvnModelInputException { 74 | FileObject pomFile = getPomFileObject(project); 75 | MavenXpp3Reader mavenreader = new MavenXpp3Reader(); 76 | try (Reader reader = new InputStreamReader(pomFile.getInputStream())) { 77 | Model model = mavenreader.read(reader); 78 | model.setPomFile(new File(pomFile.getPath())); 79 | return model; 80 | } catch (XmlPullParserException | IOException ex) { 81 | throw new MvnModelInputException(ex); 82 | } 83 | } 84 | 85 | public static boolean isMvnProject(Project project) { 86 | return getPomFileObject(project) != null; 87 | } 88 | 89 | public static FileObject getPomFileObject(Project project) { 90 | return project.getProjectDirectory().getFileObject("pom.xml"); 91 | } 92 | 93 | public static MavenProject createMavenProject(Project project) throws MvnModelInputException { 94 | return new MavenProject(createModel(project)); 95 | } 96 | 97 | public static File getOutputDirectory(Project project) throws MvnModelInputException { 98 | MavenProject mavenProject = SonarMvnProject.createMavenProject(project); 99 | Build build = mavenProject.getBuild(); 100 | String path = null; 101 | if (build != null) { 102 | path = build.getDirectory(); 103 | } 104 | File outputDirectory; 105 | if (path != null) { 106 | outputDirectory = FileUtil.normalizeFile(new File(path)); 107 | } else { 108 | outputDirectory = new File(project.getProjectDirectory().getPath(), "target"); 109 | } 110 | return outputDirectory; 111 | } 112 | 113 | @Override 114 | public SonarQubeProjectConfiguration createConfiguration(Project subproject) { 115 | return new SonarMvnProject(subproject); 116 | } 117 | 118 | @Override 119 | public Properties getProperties() { 120 | Properties properties = new Properties(); 121 | for (Map.Entry entry : model.getProperties().entrySet()) { 122 | if (entry.getKey().toString().startsWith("sonar.")) { 123 | properties.put(entry.getKey(), entry.getValue()); 124 | } 125 | } 126 | return properties; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/SonarQubeProjectConfiguration.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Properties; 4 | import org.netbeans.api.project.Project; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public interface SonarQubeProjectConfiguration { 11 | 12 | String getName(); 13 | 14 | ResourceKey getKey(); 15 | 16 | String getVersion(); 17 | 18 | SonarQubeProjectConfiguration createConfiguration(Project subproject); 19 | 20 | Properties getProperties(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/SonarQubeProjectException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class SonarQubeProjectException extends RuntimeException{ 8 | 9 | public SonarQubeProjectException(Throwable thrwbl) { 10 | super(thrwbl); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/Summary.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * 7 | * @author Victor 8 | */ 9 | public interface Summary { 10 | 11 | int getCount(Severity severity); 12 | 13 | int getCount(Rule rule); 14 | 15 | int getCount(); 16 | 17 | Set getRules(Severity severity); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/SummaryOptions.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.List; 4 | import qubexplorer.filter.IssueFilter; 5 | 6 | /** 7 | * 8 | * @author Víctor 9 | */ 10 | public class SummaryOptions { 11 | private ClassifierType classifierType; 12 | private List filters; 13 | 14 | public SummaryOptions(ClassifierType classifierType, List filters) { 15 | this.classifierType = classifierType; 16 | this.filters = filters; 17 | } 18 | 19 | public ClassifierType getClassifierType() { 20 | return classifierType; 21 | } 22 | 23 | public void setClassifierType(ClassifierType classifierType) { 24 | this.classifierType = classifierType; 25 | } 26 | 27 | public List getFilters() { 28 | return filters; 29 | } 30 | 31 | public void setFilters(List filters) { 32 | this.filters = filters; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/UserCredentials.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * 7 | * @author Victor 8 | */ 9 | public class UserCredentials { 10 | private final String username; 11 | private char[] password; 12 | 13 | public UserCredentials(String username, char[] password) { 14 | Objects.requireNonNull(username, "username is null"); 15 | Objects.requireNonNull(password, "password is null"); 16 | this.username = username; 17 | this.password = PassEncoder.encode(password); 18 | } 19 | 20 | public String getUsername() { 21 | return username; 22 | } 23 | 24 | public char[] getPassword() { 25 | if(password == null) { 26 | throw new IllegalStateException("password has been cleaned"); 27 | } 28 | return password.clone(); 29 | } 30 | 31 | public void done(){ 32 | for (int i = 0; i < password.length; i++) { 33 | password[i]=0; 34 | } 35 | password=null; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/filter/AssigneesFilter.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.filter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | import qubexplorer.RadarIssue; 10 | 11 | /** 12 | * 13 | * @author Víctor 14 | */ 15 | public class AssigneesFilter implements IssueFilter { 16 | 17 | private final Set assignees; 18 | 19 | public AssigneesFilter(Set asignees) { 20 | this.assignees = asignees; 21 | } 22 | 23 | public AssigneesFilter(String... asignees) { 24 | this.assignees=new HashSet<>(Arrays.asList(asignees)); 25 | } 26 | 27 | public Set getAssignees() { 28 | return assignees; 29 | } 30 | 31 | @Override 32 | public void apply(Map> params) { 33 | params.put("assignees", new ArrayList<>(assignees)); 34 | } 35 | 36 | @Override 37 | public String getDescription() { 38 | return "Assignees: " + String.join(", ", assignees); 39 | } 40 | 41 | @Override 42 | public boolean isValid(RadarIssue issue) { 43 | return assignees.contains(issue.assignee()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/filter/IssueFilter.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.filter; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import qubexplorer.RadarIssue; 6 | 7 | /** 8 | * 9 | * @author Victor 10 | */ 11 | public interface IssueFilter { 12 | 13 | void apply(Map> params); 14 | 15 | String getDescription(); 16 | 17 | boolean isValid(RadarIssue issue); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/filter/RuleFilter.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.filter; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Objects; 7 | import qubexplorer.RadarIssue; 8 | import qubexplorer.Rule; 9 | 10 | /** 11 | * 12 | * @author Victor 13 | */ 14 | public class RuleFilter implements IssueFilter { 15 | 16 | private final Rule rule; 17 | 18 | public RuleFilter(Rule rule) { 19 | Objects.requireNonNull(rule, "rule is null"); 20 | this.rule = rule; 21 | } 22 | 23 | @Override 24 | public void apply(Map> params) { 25 | params.put("rules", Arrays.asList(rule.getKey())); 26 | } 27 | 28 | @Override 29 | public boolean isValid(RadarIssue issue) { 30 | return issue.ruleKey().equals(rule.getKey()); 31 | } 32 | 33 | @Override 34 | public String getDescription() { 35 | return "Rule: " + rule.getName(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/filter/SeverityFilter.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.filter; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Objects; 7 | import qubexplorer.RadarIssue; 8 | import qubexplorer.Severity; 9 | 10 | /** 11 | * 12 | * @author Victor 13 | */ 14 | public class SeverityFilter implements IssueFilter { 15 | 16 | private final Severity severity; 17 | 18 | public SeverityFilter(Severity severity) { 19 | Objects.requireNonNull(severity, "severity is null"); 20 | this.severity = severity; 21 | } 22 | 23 | @Override 24 | public void apply(Map> params) { 25 | params.put("severities", Arrays.asList(severity.toString().toUpperCase())); 26 | } 27 | 28 | @Override 29 | public boolean isValid(RadarIssue issue) { 30 | return issue.severity().equalsIgnoreCase(severity.toString()); 31 | } 32 | 33 | @Override 34 | public String getDescription() { 35 | return "Severity: " + severity.toString(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/filter/TypeFilter.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.filter; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.Map; 6 | import qubexplorer.IssueType; 7 | import qubexplorer.RadarIssue; 8 | 9 | 10 | public class TypeFilter implements IssueFilter { 11 | private final IssueType type; 12 | 13 | public TypeFilter(IssueType type) { 14 | this.type = type; 15 | } 16 | 17 | @Override 18 | public void apply(Map> params) { 19 | params.put("types", Arrays.asList(type.toString().toUpperCase())); 20 | } 21 | 22 | @Override 23 | public String getDescription() { 24 | return "Type: "+type; 25 | } 26 | 27 | @Override 28 | public boolean isValid(RadarIssue issue) { 29 | return issue.type().equalsIgnoreCase(type.toString()); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/Module.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.util.Map; 6 | import java.util.Properties; 7 | import org.netbeans.api.java.classpath.ClassPath; 8 | import org.netbeans.api.java.project.JavaProjectConstants; 9 | import org.netbeans.api.java.queries.BinaryForSourceQuery; 10 | import org.netbeans.api.java.queries.UnitTestForSourceQuery; 11 | import org.netbeans.api.project.Project; 12 | import org.netbeans.api.project.ProjectUtils; 13 | import org.netbeans.api.project.SourceGroup; 14 | import org.netbeans.api.project.Sources; 15 | import org.openide.filesystems.FileObject; 16 | import org.openide.filesystems.FileUtil; 17 | import org.openide.util.Utilities; 18 | import qubexplorer.MvnModelInputException; 19 | import qubexplorer.SonarMvnProject; 20 | import qubexplorer.SonarQubeProjectConfiguration; 21 | import qubexplorer.server.Version; 22 | import qubexplorer.ui.ProjectContext; 23 | 24 | /** 25 | * 26 | * @author Victor 27 | */ 28 | public class Module { 29 | 30 | private final ProjectContext projectContext; 31 | private final ProjectContext parentProjectContext; 32 | 33 | private Module(ProjectContext parentProjectContext, ProjectContext projectContext) { 34 | this.parentProjectContext = parentProjectContext; 35 | this.projectContext = projectContext; 36 | } 37 | 38 | public boolean isRootProject() { 39 | return parentProjectContext == null; 40 | } 41 | 42 | public String getName() { 43 | return isRootProject() ? null : projectContext.getProject().getProjectDirectory().getNameExt(); 44 | } 45 | 46 | public boolean containsSources() { 47 | return getMainSourceGroup() != null; 48 | } 49 | 50 | public SourceGroup getMainSourceGroup() { 51 | Sources sources = ProjectUtils.getSources(projectContext.getProject()); 52 | SourceGroup[] sourceGroups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); 53 | SourceGroup mainSourceGroup = null; 54 | if (sourceGroups != null && sourceGroups.length != 0) { 55 | for (SourceGroup sGroup : sourceGroups) { 56 | URL[] sourcesForUnitTest = UnitTestForSourceQuery.findSources(sGroup.getRootFolder()); 57 | if (sourcesForUnitTest == null || sourcesForUnitTest.length == 0) { 58 | mainSourceGroup = sGroup; 59 | break; 60 | } 61 | } 62 | } 63 | return mainSourceGroup; 64 | } 65 | 66 | public void loadExternalProperties(Properties properties) { 67 | Properties projectProperties = projectContext.getConfiguration().getProperties(); 68 | for (Map.Entry entry : projectProperties.entrySet()) { 69 | properties.put(entry.getKey(), entry.getValue()); 70 | } 71 | } 72 | 73 | private String getPropertyName(String property) { 74 | if (!isRootProject()) { 75 | return getName() + "." + property; 76 | } 77 | return property; 78 | } 79 | 80 | protected void configureSourcesAndBinariesProperties(Version sonarQubeVersion, Properties properties) { 81 | SourceGroup mainSourceGroup = getMainSourceGroup(); 82 | if (mainSourceGroup != null) { 83 | String sourcePath = mainSourceGroup.getRootFolder().getPath(); 84 | if (SonarMvnProject.isMvnProject(projectContext.getProject()) && sonarQubeVersion.compareTo(4, 5) >= 0) { 85 | sourcePath = "pom.xml," + sourcePath; 86 | } 87 | ClassPath classPath = ClassPath.getClassPath(projectContext.getProject().getProjectDirectory(), ClassPath.COMPILE); 88 | if (classPath != null) { 89 | properties.setProperty(getPropertyName("sonar.java.libraries"), getLibrariesPath(classPath)); 90 | } 91 | properties.setProperty(getPropertyName("sonar.sources"), sourcePath); 92 | URL[] roots = BinaryForSourceQuery.findBinaryRoots(mainSourceGroup.getRootFolder().toURL()).getRoots(); 93 | if (roots.length > 0) { 94 | properties.setProperty(getPropertyName("sonar.java.binaries"), Utilities.toFile(roots[0]).getPath()); 95 | } 96 | URL[] testSources = UnitTestForSourceQuery.findUnitTests(mainSourceGroup.getRootFolder()); 97 | if (testSources != null && testSources.length != 0) { 98 | File testsDir = FileUtil.archiveOrDirForURL(testSources[0]); 99 | if (testsDir.exists()) { 100 | properties.setProperty(getPropertyName("sonar.tests"), testsDir.getPath()); 101 | } 102 | } 103 | } 104 | } 105 | 106 | public void addModuleProperties(Version sonarQubeVersion, Properties properties) throws MvnModelInputException { 107 | SonarQubeProjectConfiguration projectConfiguration = projectContext.getConfiguration(); 108 | configureSourcesAndBinariesProperties(sonarQubeVersion, properties); 109 | properties.setProperty(getPropertyName("sonar.projectName"), projectConfiguration.getName()); 110 | properties.setProperty(getPropertyName("sonar.projectKey"), projectConfiguration.getKey().toString()); 111 | if (containsSources()) { 112 | properties.setProperty(getPropertyName("sonar.projectBaseDir"), projectContext.getProject().getProjectDirectory().getPath()); 113 | } 114 | } 115 | 116 | public Module createSubmodule(Project subproject) { 117 | return new Module(projectContext, new ProjectContext(subproject, projectContext.getConfiguration().createConfiguration(subproject))); 118 | } 119 | 120 | public static Module createMainModule(ProjectContext projectContext) { 121 | return new Module(null, projectContext); 122 | } 123 | 124 | private static String getLibrariesPath(ClassPath classPath) { 125 | StringBuilder librariesPath = new StringBuilder(); 126 | for (FileObject root : classPath.getRoots()) { 127 | if (librariesPath.length() > 0) { 128 | librariesPath.append(','); 129 | } 130 | FileObject archiveFile = FileUtil.getArchiveFile(root); 131 | if (archiveFile != null) { 132 | librariesPath.append(archiveFile.getPath()); 133 | } 134 | } 135 | return librariesPath.toString(); 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/SonarRunnerCancelledException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class SonarRunnerCancelledException extends SonarRunnerException { 8 | 9 | public SonarRunnerCancelledException() { 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/SonarRunnerClassifierSummary.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import qubexplorer.Classifier; 8 | import qubexplorer.ClassifierSummary; 9 | import qubexplorer.Rule; 10 | import qubexplorer.runner.SonarRunnerResult.IntWrapper; 11 | 12 | /** 13 | * 14 | * @author Victor 15 | */ 16 | public class SonarRunnerClassifierSummary implements ClassifierSummary { 17 | private Map countsByClassifier; 18 | private Map countsByRule; 19 | private Map> rules; 20 | 21 | SonarRunnerClassifierSummary(Map countsBySeverity, Map countsByRule, Map> rules) { 22 | this.countsByClassifier = countsBySeverity; 23 | this.countsByRule = countsByRule; 24 | this.rules=rules; 25 | } 26 | 27 | public SonarRunnerClassifierSummary() { 28 | this(new HashMap(), new HashMap(), new HashMap>()); 29 | } 30 | 31 | @Override 32 | public int getCount(T classifier) { 33 | IntWrapper count = countsByClassifier.get(classifier); 34 | return count != null? count.getInt(): 0; 35 | } 36 | 37 | @Override 38 | public int getCount(Rule rule) { 39 | IntWrapper count = countsByRule.get(rule.getKey()); 40 | return count != null? count.getInt(): 0; 41 | } 42 | 43 | @Override 44 | public int getCount(){ 45 | int suma=0; 46 | for (Map.Entry entry : countsByClassifier.entrySet()) { 47 | suma+=entry.getValue().getInt(); 48 | } 49 | return suma; 50 | } 51 | 52 | @Override 53 | public Set getRules(T classifier) { 54 | if(rules.containsKey(classifier)) { 55 | return rules.get(classifier); 56 | }else{ 57 | return Collections.emptySet(); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/SonarRunnerException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class SonarRunnerException extends RuntimeException{ 8 | 9 | public SonarRunnerException() { 10 | } 11 | 12 | public SonarRunnerException(String message) { 13 | super(message); 14 | } 15 | 16 | public SonarRunnerException(Throwable thrwbl) { 17 | super(thrwbl); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/SourcesNotFoundException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class SourcesNotFoundException extends RuntimeException{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/VersionConfig.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.util.Properties; 4 | import qubexplorer.server.Version; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | interface VersionConfig { 11 | 12 | boolean applies(Version sonarQubeVersion); 13 | 14 | void apply(SonarRunnerProccess proccess, Properties properties); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/VersionConfigLessThan4.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.util.Properties; 4 | import qubexplorer.server.Version; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | class VersionConfigLessThan4 implements VersionConfig { 11 | 12 | @Override 13 | public boolean applies(Version sonarQubeVersion) { 14 | return sonarQubeVersion.getMajor() < 4; 15 | } 16 | 17 | @Override 18 | public void apply(SonarRunnerProccess proccess, Properties properties) { 19 | properties.setProperty("sonar.dryRun", "true"); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/VersionConfigLessThan5Point2.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.util.Properties; 4 | import qubexplorer.server.Version; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | class VersionConfigLessThan5Point2 implements VersionConfig { 11 | 12 | @Override 13 | public boolean applies(Version sonarQubeVersion) { 14 | return sonarQubeVersion.getMajor() >= 4 && sonarQubeVersion.compareTo(5, 2) <= 0; 15 | } 16 | 17 | @Override 18 | public void apply(SonarRunnerProccess proccess, Properties properties) { 19 | properties.setProperty("sonar.analysis.mode", proccess.getAnalysisMode().toString().toLowerCase()); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/VersionConfigMoreThan5Point2.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.util.Properties; 4 | import qubexplorer.server.Version; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | class VersionConfigMoreThan5Point2 implements VersionConfig { 11 | 12 | @Override 13 | public boolean applies(Version sonarQubeVersion) { 14 | return sonarQubeVersion.compareTo(5, 2) >= 0; 15 | } 16 | 17 | @Override 18 | public void apply(SonarRunnerProccess proccess, Properties properties) { 19 | properties.setProperty("sonar.analysis.mode", "issues"); 20 | properties.setProperty("sonar.report.export.path", SonarRunnerProccess.JSON_FILENAME); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/ui/SonarRunnerAction.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner.ui; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.ActionListener; 5 | import org.netbeans.api.project.Project; 6 | import org.openide.awt.ActionID; 7 | import org.openide.awt.ActionRegistration; 8 | import org.openide.util.NbBundle; 9 | import org.openide.util.NbPreferences; 10 | import qubexplorer.ConfigurationFactory; 11 | import qubexplorer.ui.ProjectContext; 12 | import qubexplorer.ui.SonarQubeOptionsPanel; 13 | import qubexplorer.ui.task.TaskExecutor; 14 | 15 | /** 16 | * 17 | * @author Victor 18 | */ 19 | @ActionID( 20 | category = "SonarQube", 21 | id = "qubexplorer.ui.SonarRunnerAction") 22 | @ActionRegistration( 23 | displayName = "#CTL_SonarRunnerAction") 24 | @NbBundle.Messages("CTL_SonarRunnerAction=Get Issues with Sonar Runner") 25 | public class SonarRunnerAction implements ActionListener { 26 | 27 | private final Project context; 28 | 29 | public SonarRunnerAction(Project context) { 30 | this.context = context; 31 | } 32 | 33 | @Override 34 | public void actionPerformed(ActionEvent ae) { 35 | String serverUrl = NbPreferences.forModule(SonarQubeOptionsPanel.class).get("address", "http://localhost:9000"); 36 | TaskExecutor.execute(new SonarRunnerTask(new ProjectContext(context, ConfigurationFactory.createDefaultConfiguration(context)), serverUrl)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/runner/ui/SonarRunnerTask.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner.ui; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import javax.swing.AbstractAction; 8 | import javax.swing.Action; 9 | import javax.swing.ImageIcon; 10 | import org.openide.DialogDisplayer; 11 | import org.openide.NotifyDescriptor; 12 | import org.openide.util.Exceptions; 13 | import org.openide.util.NbPreferences; 14 | import org.openide.windows.IOContainer; 15 | import org.openide.windows.IOProvider; 16 | import org.openide.windows.InputOutput; 17 | import org.openide.windows.WindowManager; 18 | import org.sonar.runner.api.PrintStreamConsumer; 19 | import qubexplorer.MvnModelInputException; 20 | import qubexplorer.ResourceKey; 21 | import qubexplorer.Severity; 22 | import qubexplorer.SonarQubeProjectConfiguration; 23 | import qubexplorer.SummaryOptions; 24 | import qubexplorer.runner.SonarRunnerCancelledException; 25 | import qubexplorer.runner.SonarRunnerProccess; 26 | import qubexplorer.runner.SonarRunnerResult; 27 | import qubexplorer.runner.SourcesNotFoundException; 28 | import qubexplorer.ui.ProjectContext; 29 | import qubexplorer.ui.SonarIssuesTopComponent; 30 | import qubexplorer.ui.SonarQubeOptionsPanel; 31 | import qubexplorer.ui.issues.IssueLocation; 32 | import qubexplorer.ui.task.Task; 33 | import qubexplorer.ui.task.TaskExecutionException; 34 | 35 | /** 36 | * 37 | * @author Victor 38 | */ 39 | public class SonarRunnerTask extends Task{ 40 | private InputOutput io; 41 | private boolean stopped=false; 42 | private final Action stopAction=new AbstractAction("Stop Sonar-runner", new ImageIcon(getClass().getResource("/qubexplorer/ui/images/stop.png"))) { 43 | 44 | { 45 | putValue(Action.SHORT_DESCRIPTION, "Stops sonar-runner"); 46 | } 47 | 48 | @Override 49 | public void actionPerformed(ActionEvent ae) { 50 | stopped=true; 51 | setEnabled(false); 52 | } 53 | 54 | }; 55 | 56 | public SonarRunnerTask(ProjectContext projectContext, String serverUrl) { 57 | super(projectContext, serverUrl); 58 | } 59 | 60 | @Override 61 | protected void init() { 62 | SonarIssuesTopComponent sonarTopComponent = (SonarIssuesTopComponent) WindowManager.getDefault().findTopComponent("SonarIssuesTopComponent"); 63 | sonarTopComponent.setSummaryOptions(new SummaryOptions<>(Severity.getType(), Collections.emptyList())); 64 | sonarTopComponent.resetState(); 65 | stopAction.setEnabled(true); 66 | if(io == null) { 67 | io = IOProvider.getDefault().getIO("Sonar-runner", true, new Action[]{stopAction}, IOContainer.getDefault()); 68 | } 69 | try { 70 | io.getOut().reset(); 71 | io.getErr().reset(); 72 | } catch (IOException ex) { 73 | Exceptions.printStackTrace(ex); 74 | } 75 | io.select(); 76 | io.getOut().println("Starting sonar-runner"); 77 | } 78 | 79 | @Override 80 | public SonarRunnerResult execute() throws TaskExecutionException { 81 | try { 82 | PrintStreamConsumer out = new PrintStreamConsumer(null){ 83 | 84 | @Override 85 | public void consumeLine(String line) { 86 | io.getOut().println(line); 87 | } 88 | 89 | }; 90 | 91 | PrintStreamConsumer err = new PrintStreamConsumer(null){ 92 | 93 | @Override 94 | public void consumeLine(String line) { 95 | io.getErr().println(line); 96 | } 97 | 98 | }; 99 | SonarRunnerProccess sonarRunnerProccess = new SonarRunnerProccess(getServerUrl(), getProjectContext()); 100 | SonarRunnerProccess.AnalysisMode defaulAnalysisMode = SonarRunnerProccess.getDefaultAnalysisMode(); 101 | String preferedAnalysisMode = NbPreferences.forModule(SonarQubeOptionsPanel.class).get("runner.analysisMode", defaulAnalysisMode.getFriendlyName()); 102 | try{ 103 | sonarRunnerProccess.setAnalysisMode(SonarRunnerProccess.AnalysisMode.valueOfFriendlyName(preferedAnalysisMode)); 104 | }catch(IllegalArgumentException ex) { 105 | sonarRunnerProccess.setAnalysisMode(defaulAnalysisMode); 106 | } 107 | String jvmArguments = NbPreferences.forModule(SonarQubeOptionsPanel.class).get("runner.jvmArguments", ""); 108 | sonarRunnerProccess.setJvmArguments(Arrays.asList(jvmArguments.split(" +"))); 109 | sonarRunnerProccess.setOutConsumer(out); 110 | sonarRunnerProccess.setErrConsumer(err); 111 | return sonarRunnerProccess.executeRunner(getUserCredentials(), () -> stopped); 112 | } catch (MvnModelInputException ex) { 113 | throw new TaskExecutionException(ex); 114 | } 115 | } 116 | 117 | @Override 118 | protected void success(SonarRunnerResult result) { 119 | SonarIssuesTopComponent sonarTopComponent = (SonarIssuesTopComponent) WindowManager.getDefault().findTopComponent("SonarIssuesTopComponent"); 120 | sonarTopComponent.setProjectContext(getProjectContext()); 121 | sonarTopComponent.setProjectKeyChecker(new SonarRunnerChecker()); 122 | sonarTopComponent.setIssuesContainer(result); 123 | sonarTopComponent.open(); 124 | sonarTopComponent.requestVisible(); 125 | SummaryOptions summaryOptions=new SummaryOptions(Severity.getType(), Collections.emptyList()); 126 | sonarTopComponent.showSummary(summaryOptions, result.getClassifierSummaryBySeverity()); 127 | } 128 | 129 | @Override 130 | protected void fail(Throwable cause) { 131 | if(cause instanceof SourcesNotFoundException) { 132 | String message = org.openide.util.NbBundle.getMessage(SonarRunnerTask.class, "SourcesNotFound"); 133 | DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(message, NotifyDescriptor.WARNING_MESSAGE)); 134 | }else if(cause instanceof SonarRunnerCancelledException){ 135 | io.getOut().println(org.openide.util.NbBundle.getMessage(SonarRunnerTask.class, "SonarRunner.cancelled")); 136 | }else{ 137 | io.getErr().println(org.openide.util.NbBundle.getMessage(SonarRunnerTask.class, "SonarRunner.error")); 138 | Exceptions.printStackTrace(cause); 139 | } 140 | } 141 | 142 | @Override 143 | protected void destroy() { 144 | stopAction.setEnabled(false); 145 | io.getOut().close(); 146 | io.getErr().close(); 147 | } 148 | 149 | private static class SonarRunnerChecker implements IssueLocation.ProjectKeyChecker { 150 | 151 | public ResourceKey getShortProjectKey(ResourceKey key) { 152 | return key.subkey(1, key.getPartsCount()); 153 | } 154 | 155 | @Override 156 | public boolean equals(SonarQubeProjectConfiguration configuration, ResourceKey projectKeyIssue, boolean isSubmodule) { 157 | ResourceKey tmpKey = isSubmodule ? getShortProjectKey(projectKeyIssue) : projectKeyIssue; 158 | return configuration.getKey().equals(tmpKey); 159 | } 160 | 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/Component.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | /** 6 | * 7 | * @author Víctor 8 | */ 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class Component { 11 | private String name; 12 | private String key; 13 | private String version; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public String getKey() { 24 | return key; 25 | } 26 | 27 | public void setKey(String key) { 28 | this.key = key; 29 | } 30 | 31 | public String getVersion() { 32 | return version; 33 | } 34 | 35 | public void setVersion(String version) { 36 | this.version = version; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/ComponentSearchResult.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import java.util.List; 5 | 6 | /** 7 | * 8 | * @author Víctor 9 | */ 10 | @JsonIgnoreProperties(ignoreUnknown = true) 11 | public class ComponentSearchResult { 12 | 13 | private Paging paging; 14 | private List components; 15 | 16 | public Paging getPaging() { 17 | return paging; 18 | } 19 | 20 | public void setPaging(Paging paging) { 21 | this.paging = paging; 22 | } 23 | 24 | public List getComponents() { 25 | return components; 26 | } 27 | 28 | public void setComponents(List components) { 29 | this.components = components; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/IssuesSearchResult.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import java.util.List; 6 | import qubexplorer.RadarIssue; 7 | 8 | /** 9 | * 10 | * @author Víctor 11 | */ 12 | @JsonIgnoreProperties(ignoreUnknown = true) 13 | public class IssuesSearchResult { 14 | private Paging paging; 15 | private List issues; 16 | 17 | public Paging getPaging() { 18 | return paging; 19 | } 20 | 21 | public void setPaging(Paging paging) { 22 | this.paging = paging; 23 | } 24 | 25 | public List getIssues() { 26 | return issues; 27 | } 28 | 29 | public void setIssues(List issues) { 30 | this.issues = issues; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/Paging.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * 7 | * @author Víctor 8 | */ 9 | public class Paging { 10 | 11 | private Integer pageIndex; 12 | private Integer pageSize; 13 | @JsonProperty(value = "total") 14 | private Integer totalNumberOfResults; 15 | 16 | public Integer getPageIndex() { 17 | return pageIndex; 18 | } 19 | 20 | public void setPageIndex(Integer pageIndex) { 21 | this.pageIndex = pageIndex; 22 | } 23 | 24 | public Integer getPageSize() { 25 | return pageSize; 26 | } 27 | 28 | public void setPageSize(Integer pageSize) { 29 | this.pageSize = pageSize; 30 | } 31 | 32 | public Integer getTotalNumberOfResults() { 33 | return totalNumberOfResults; 34 | } 35 | 36 | public void setTotalNumberOfResults(Integer totalNumberOfResults) { 37 | this.totalNumberOfResults = totalNumberOfResults; 38 | } 39 | 40 | public int getTotalPageCount() { 41 | return (int) Math.ceil(totalNumberOfResults / pageSize.doubleValue()); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/Resource.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | /** 6 | * 7 | * @author Víctor 8 | */ 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class Resource { 11 | private String name; 12 | private String key; 13 | private String version; 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public String getKey() { 24 | return key; 25 | } 26 | 27 | public void setKey(String key) { 28 | this.key = key; 29 | } 30 | 31 | public String getVersion() { 32 | return version; 33 | } 34 | 35 | public void setVersion(String version) { 36 | this.version = version; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/RuleResult.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import qubexplorer.Rule; 5 | 6 | /** 7 | * 8 | * @author Víctor 9 | */ 10 | @JsonIgnoreProperties(ignoreUnknown = true) 11 | public class RuleResult { 12 | private Rule rule; 13 | 14 | public Rule getRule() { 15 | return rule; 16 | } 17 | 18 | public void setRule(Rule rule) { 19 | this.rule = rule; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/ServerStatus.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | /** 6 | * 7 | * @author Víctor 8 | */ 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public class ServerStatus { 11 | private String id; 12 | private String version; 13 | private String status; 14 | 15 | public String getId() { 16 | return id; 17 | } 18 | 19 | public void setId(String id) { 20 | this.id = id; 21 | } 22 | 23 | public String getVersion() { 24 | return version; 25 | } 26 | 27 | public void setVersion(String version) { 28 | this.version = version; 29 | } 30 | 31 | public String getStatus() { 32 | return status; 33 | } 34 | 35 | public void setStatus(String status) { 36 | this.status = status; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/SimpleClassifierSummary.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import qubexplorer.Classifier; 8 | import qubexplorer.Rule; 9 | import qubexplorer.ClassifierSummary; 10 | 11 | /** 12 | * 13 | * @author Victor 14 | */ 15 | public class SimpleClassifierSummary implements ClassifierSummary { 16 | 17 | private final Map> countsByClassifier=new HashMap<>(); 18 | 19 | public SimpleClassifierSummary() { 20 | 21 | } 22 | 23 | public void increment(T clasifier, Rule rule, int increment) { 24 | Map countByRule = countsByClassifier.get(clasifier); 25 | if(countByRule == null ){ 26 | countByRule=new HashMap<>(); 27 | countsByClassifier.put(clasifier, countByRule); 28 | } 29 | Integer count = countByRule.get(rule); 30 | if (count == null) { 31 | count = increment; 32 | } else { 33 | count = count + increment; 34 | } 35 | countByRule.put(rule, count); 36 | } 37 | 38 | @Override 39 | public int getCount(T classifier) { 40 | Map map = countsByClassifier.get(classifier); 41 | if (map == null) { 42 | return 0; 43 | } else { 44 | int sum=0; 45 | for (Map.Entry entry : map.entrySet()) { 46 | sum+=entry.getValue(); 47 | } 48 | return sum; 49 | } 50 | } 51 | 52 | @Override 53 | public int getCount(Rule rule) { 54 | int count = 0; 55 | for (Map countByRule : countsByClassifier.values()) { 56 | if (countByRule.containsKey(rule)) { 57 | count = countByRule.get(rule); 58 | break; 59 | } 60 | } 61 | return count; 62 | } 63 | 64 | @Override 65 | public int getCount() { 66 | int suma = 0; 67 | for (Map countByRule : countsByClassifier.values()) { 68 | for (Integer ruleCount : countByRule.values()) { 69 | suma += ruleCount; 70 | } 71 | } 72 | return suma; 73 | } 74 | 75 | @Override 76 | public Set getRules(T classifier) { 77 | if (countsByClassifier.containsKey(classifier)) { 78 | return countsByClassifier.get(classifier).keySet(); 79 | } else { 80 | return Collections.emptySet(); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/Version.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | /** 4 | * 5 | * @author Victor 6 | */ 7 | public class Version { 8 | private final String versionString; 9 | private final String[] tokens; 10 | 11 | public Version(String versionString) { 12 | this.versionString = versionString; 13 | tokens=versionString.split("\\."); 14 | } 15 | 16 | public int getMajor(){ 17 | if (tokens.length >= 1) { 18 | return Integer.parseInt(tokens[0]); 19 | } else { 20 | throw new IllegalArgumentException("Problem getting major version in " + versionString); 21 | } 22 | } 23 | 24 | public int getMinor(){ 25 | if (tokens.length >= 2) { 26 | return Integer.parseInt(tokens[1]); 27 | } else { 28 | throw new IllegalArgumentException("Problem getting minor version in " + versionString); 29 | } 30 | } 31 | 32 | public int getTokenCount(){ 33 | return tokens.length; 34 | } 35 | 36 | public String getToken(int index){ 37 | return tokens[index]; 38 | } 39 | 40 | @Override 41 | public String toString(){ 42 | return versionString; 43 | } 44 | 45 | public int compareTo(int major, int minor){ 46 | if(getMajor() > major){ 47 | return 1; 48 | } 49 | if(getMajor() < major) { 50 | return -1; 51 | } 52 | String minorToken = getTokenCount() >= 2 ? getToken(1): "0"; 53 | return minorToken.compareTo(String.valueOf(minor)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/ui/CustomServerIssuesAction.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server.ui; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.ActionListener; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Properties; 8 | import org.netbeans.api.project.Project; 9 | import org.openide.awt.ActionID; 10 | import org.openide.awt.ActionRegistration; 11 | import org.openide.util.NbBundle.Messages; 12 | import org.openide.util.NbPreferences; 13 | import org.openide.windows.WindowManager; 14 | import qubexplorer.ConfigurationFactory; 15 | import qubexplorer.ResourceKey; 16 | import qubexplorer.SonarQubeProjectConfiguration; 17 | import qubexplorer.SummaryOptions; 18 | import qubexplorer.UserCredentials; 19 | import qubexplorer.filter.AssigneesFilter; 20 | import qubexplorer.filter.IssueFilter; 21 | import qubexplorer.server.SonarQube; 22 | import qubexplorer.ui.ProjectContext; 23 | import qubexplorer.ui.SonarQubeOptionsPanel; 24 | import qubexplorer.ui.summary.SummaryTask; 25 | import qubexplorer.ui.task.TaskExecutor; 26 | 27 | @ActionID( 28 | category = "SonarQube", 29 | id = "qubexplorer.ui.SonarDialogAction2") 30 | @ActionRegistration( 31 | displayName = "#CTL_SonarDialogAction2") 32 | @Messages("CTL_SonarDialogAction2=Get Issues from Server ...") 33 | public final class CustomServerIssuesAction implements ActionListener { 34 | 35 | private final Project context; 36 | 37 | public CustomServerIssuesAction(Project context) { 38 | this.context = context; 39 | } 40 | 41 | @Override 42 | public void actionPerformed(ActionEvent ev) { 43 | ServerConnectionDialog serverConnectionDialog=new ServerConnectionDialog(WindowManager.getDefault().getMainWindow(), true); 44 | serverConnectionDialog.setSelectedUrl(NbPreferences.forModule(SonarQubeOptionsPanel.class).get("address", "http://localhost:9000")); 45 | if(serverConnectionDialog.showDialog() == ServerConnectionDialog.Option.ACCEPT) { 46 | SonarQubeProjectConfiguration fixed = serverConnectionDialog.getSelectedProject(); 47 | SonarQubeProjectConfiguration real = ConfigurationFactory.createDefaultConfiguration(context); 48 | final ProjectContext projectContext = new ProjectContext(context, new FixedKey(fixed, real)); 49 | final SonarQube sonarQube = new SonarQube(serverConnectionDialog.getSelectedUrl()); 50 | List filters=new LinkedList<>(); 51 | String[] asignees = serverConnectionDialog.getAsignees(); 52 | if(asignees.length != 0) { 53 | filters.add(new AssigneesFilter(asignees)); 54 | } 55 | SummaryTask summaryTask = new SummaryTask(sonarQube, projectContext, new SummaryOptions<>(serverConnectionDialog.getClassifierType(), filters)); 56 | UserCredentials userCredentials = serverConnectionDialog.getUserCredentials(); 57 | if(userCredentials != null) { 58 | summaryTask.setUserCredentials(userCredentials); 59 | } 60 | TaskExecutor.execute(summaryTask); 61 | } 62 | } 63 | 64 | public static class FixedKey implements SonarQubeProjectConfiguration{ 65 | private final SonarQubeProjectConfiguration fixed; 66 | private final SonarQubeProjectConfiguration real; 67 | 68 | public FixedKey(SonarQubeProjectConfiguration fixed, SonarQubeProjectConfiguration real) { 69 | this.fixed = fixed; 70 | this.real = real; 71 | } 72 | 73 | @Override 74 | public String getName() { 75 | return fixed.getName(); 76 | } 77 | 78 | @Override 79 | public ResourceKey getKey() { 80 | return fixed.getKey(); 81 | } 82 | 83 | @Override 84 | public String getVersion() { 85 | return fixed.getVersion(); 86 | } 87 | 88 | @Override 89 | public SonarQubeProjectConfiguration createConfiguration(Project subproject) { 90 | return real.createConfiguration(subproject); 91 | } 92 | 93 | @Override 94 | public Properties getProperties() { 95 | return real.getProperties(); 96 | } 97 | 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/ui/ServerIssuesAction.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server.ui; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.ActionListener; 5 | import java.util.Collections; 6 | import org.netbeans.api.project.Project; 7 | import org.openide.awt.ActionID; 8 | import org.openide.awt.ActionRegistration; 9 | import org.openide.util.NbBundle.Messages; 10 | import qubexplorer.ConfigurationFactory; 11 | import qubexplorer.Severity; 12 | import qubexplorer.SonarQubeProjectConfiguration; 13 | import qubexplorer.SummaryOptions; 14 | import qubexplorer.server.SonarQube; 15 | import qubexplorer.ui.ProjectContext; 16 | import qubexplorer.ui.summary.SummaryTask; 17 | import qubexplorer.ui.task.TaskExecutor; 18 | 19 | @ActionID( 20 | category = "SonarQube", 21 | id = "qubexplorer.ui.SonarDialogAction") 22 | @ActionRegistration( 23 | displayName = "#CTL_SonarDialogAction") 24 | @Messages("CTL_SonarDialogAction=Get Issues from Server") 25 | public final class ServerIssuesAction implements ActionListener { 26 | 27 | private final Project context; 28 | 29 | public ServerIssuesAction(Project context) { 30 | this.context = context; 31 | } 32 | 33 | @Override 34 | public void actionPerformed(ActionEvent ev) { 35 | SonarQubeProjectConfiguration configuration = ConfigurationFactory.createDefaultConfiguration(context); 36 | if (configuration != null) { 37 | final ProjectContext projectContext = new ProjectContext(context, configuration); 38 | final SonarQube sonarQube = SonarQubeFactory.createForDefaultServerUrl(); 39 | TaskExecutor.execute(new SummaryTask(sonarQube, projectContext, new SummaryOptions<>(Severity.getType(), Collections.emptyList()))); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/ui/SonarQubeFactory.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server.ui; 2 | 3 | import org.openide.util.NbPreferences; 4 | import qubexplorer.server.SonarQube; 5 | import qubexplorer.ui.SonarQubeOptionsPanel; 6 | 7 | /** 8 | * 9 | * @author Victor 10 | */ 11 | public final class SonarQubeFactory { 12 | 13 | private SonarQubeFactory(){ 14 | } 15 | 16 | public static SonarQube createForDefaultServerUrl(){ 17 | String serverUrl=NbPreferences.forModule(SonarQubeOptionsPanel.class).get("address", "http://localhost:9000"); 18 | return new SonarQube(serverUrl); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/server/ui/SummarySettingsDialog.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server.ui; 2 | 3 | import qubexplorer.ClassifierType; 4 | import qubexplorer.IssueType; 5 | import qubexplorer.Severity; 6 | 7 | /** 8 | * 9 | * @author Victor 10 | */ 11 | public class SummarySettingsDialog extends javax.swing.JDialog { 12 | 13 | public enum Option { 14 | ACCEPT, 15 | CANCEL 16 | } 17 | 18 | private Option option; 19 | 20 | /** 21 | * Creates new form ProyectChooser 22 | */ 23 | public SummarySettingsDialog(java.awt.Frame parent, boolean modal) { 24 | super(parent, modal); 25 | initComponents(); 26 | } 27 | 28 | public Option showDialog() { 29 | setLocationRelativeTo(getParent()); 30 | setVisible(true); 31 | return option; 32 | } 33 | 34 | public String[] getAssignees() { 35 | return assigneesTextfield.getText().split("\\s*,\\s*"); 36 | } 37 | 38 | public void setAssignees(String[] asignees) { 39 | assigneesTextfield.setText(String.join(", ", asignees)); 40 | } 41 | 42 | public void setClassifierType(ClassifierType type) { 43 | if(Severity.getType().getClass().isInstance(type)) { 44 | groupBySeverityButton.setSelected(true); 45 | }else if(IssueType.getType().getClass().isInstance(type)) { 46 | groupByTypeButton.setSelected(true); 47 | } 48 | } 49 | 50 | public ClassifierType getClassifierType() { 51 | return groupBySeverityButton.isSelected() ? Severity.getType() : IssueType.getType(); 52 | } 53 | 54 | 55 | /** 56 | * This method is called from within the constructor to initialize the form. 57 | * WARNING: Do NOT modify this code. The content of this method is always 58 | * regenerated by the Form Editor. 59 | */ 60 | @SuppressWarnings("unchecked") 61 | // //GEN-BEGIN:initComponents 62 | private void initComponents() { 63 | 64 | buttonGroupRetrieval = new javax.swing.ButtonGroup(); 65 | jButton1 = new javax.swing.JButton(); 66 | okButton = new javax.swing.JButton(); 67 | credentialsWarning = new javax.swing.JLabel(); 68 | jLabel5 = new javax.swing.JLabel(); 69 | groupBySeverityButton = new javax.swing.JRadioButton(); 70 | groupByTypeButton = new javax.swing.JRadioButton(); 71 | assigneesTextfield = new org.jdesktop.swingx.JXTextField(); 72 | 73 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); 74 | setTitle(org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.title")); // NOI18N 75 | setModal(true); 76 | addWindowListener(new java.awt.event.WindowAdapter() { 77 | public void windowClosing(java.awt.event.WindowEvent evt) { 78 | formWindowClosing(evt); 79 | } 80 | }); 81 | 82 | org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.jButton1.text")); // NOI18N 83 | jButton1.addActionListener(new java.awt.event.ActionListener() { 84 | public void actionPerformed(java.awt.event.ActionEvent evt) { 85 | jButton1ActionPerformed(evt); 86 | } 87 | }); 88 | 89 | org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.okButton.text")); // NOI18N 90 | okButton.addActionListener(new java.awt.event.ActionListener() { 91 | public void actionPerformed(java.awt.event.ActionEvent evt) { 92 | okButtonActionPerformed(evt); 93 | } 94 | }); 95 | 96 | credentialsWarning.setForeground(new java.awt.Color(204, 0, 0)); 97 | credentialsWarning.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); 98 | org.openide.awt.Mnemonics.setLocalizedText(credentialsWarning, org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.credentialsWarning.text")); // NOI18N 99 | 100 | org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.jLabel5.text")); // NOI18N 101 | 102 | buttonGroupRetrieval.add(groupBySeverityButton); 103 | groupBySeverityButton.setSelected(true); 104 | org.openide.awt.Mnemonics.setLocalizedText(groupBySeverityButton, org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.groupBySeverityButton.text")); // NOI18N 105 | 106 | buttonGroupRetrieval.add(groupByTypeButton); 107 | org.openide.awt.Mnemonics.setLocalizedText(groupByTypeButton, org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.groupByTypeButton.text")); // NOI18N 108 | 109 | assigneesTextfield.setText(org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.assigneesTextfield.text")); // NOI18N 110 | assigneesTextfield.setPrompt(org.openide.util.NbBundle.getMessage(SummarySettingsDialog.class, "SummarySettingsDialog.assigneesTextfield.prompt")); // NOI18N 111 | 112 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 113 | getContentPane().setLayout(layout); 114 | layout.setHorizontalGroup( 115 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 116 | .addGroup(layout.createSequentialGroup() 117 | .addContainerGap() 118 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 119 | .addGroup(layout.createSequentialGroup() 120 | .addGap(0, 0, Short.MAX_VALUE) 121 | .addComponent(okButton) 122 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 123 | .addComponent(jButton1)) 124 | .addGroup(layout.createSequentialGroup() 125 | .addComponent(jLabel5) 126 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 127 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 128 | .addGroup(layout.createSequentialGroup() 129 | .addComponent(groupBySeverityButton) 130 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 131 | .addComponent(groupByTypeButton) 132 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 133 | .addComponent(credentialsWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 188, Short.MAX_VALUE)) 134 | .addComponent(assigneesTextfield, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) 135 | .addContainerGap()) 136 | ); 137 | layout.setVerticalGroup( 138 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 139 | .addGroup(layout.createSequentialGroup() 140 | .addContainerGap() 141 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 142 | .addComponent(jLabel5) 143 | .addComponent(assigneesTextfield, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 144 | .addGap(11, 11, 11) 145 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 146 | .addComponent(credentialsWarning) 147 | .addComponent(groupBySeverityButton) 148 | .addComponent(groupByTypeButton)) 149 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 138, Short.MAX_VALUE) 150 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 151 | .addComponent(jButton1) 152 | .addComponent(okButton)) 153 | .addContainerGap()) 154 | ); 155 | 156 | pack(); 157 | }// //GEN-END:initComponents 158 | 159 | private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed 160 | option = Option.ACCEPT; 161 | setVisible(false); 162 | }//GEN-LAST:event_okButtonActionPerformed 163 | 164 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed 165 | option = Option.CANCEL; 166 | setVisible(false); 167 | }//GEN-LAST:event_jButton1ActionPerformed 168 | 169 | private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing 170 | option = Option.CANCEL; 171 | }//GEN-LAST:event_formWindowClosing 172 | 173 | // Variables declaration - do not modify//GEN-BEGIN:variables 174 | private org.jdesktop.swingx.JXTextField assigneesTextfield; 175 | private javax.swing.ButtonGroup buttonGroupRetrieval; 176 | private javax.swing.JLabel credentialsWarning; 177 | private javax.swing.JRadioButton groupBySeverityButton; 178 | private javax.swing.JRadioButton groupByTypeButton; 179 | private javax.swing.JButton jButton1; 180 | private javax.swing.JLabel jLabel5; 181 | private javax.swing.JButton okButton; 182 | // End of variables declaration//GEN-END:variables 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/AuthDialog.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 |
131 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/AuthDialog.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.awt.Frame; 4 | import qubexplorer.UserCredentials; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public class AuthDialog extends javax.swing.JDialog { 11 | private transient UserCredentials authentication; 12 | 13 | /** 14 | * Creates new form AuthDialog 15 | */ 16 | public AuthDialog(java.awt.Frame parent, boolean modal) { 17 | super(parent, modal); 18 | initComponents(); 19 | getRootPane().setDefaultButton(acceptButton); 20 | } 21 | 22 | public UserCredentials getAuthentication() { 23 | return authentication; 24 | } 25 | 26 | /** 27 | * This method is called from within the constructor to initialize the form. 28 | * WARNING: Do NOT modify this code. The content of this method is always 29 | * regenerated by the Form Editor. 30 | */ 31 | @SuppressWarnings("unchecked") 32 | // //GEN-BEGIN:initComponents 33 | private void initComponents() { 34 | 35 | jLabel1 = new javax.swing.JLabel(); 36 | usernameField = new javax.swing.JTextField(); 37 | jLabel2 = new javax.swing.JLabel(); 38 | passwordField = new javax.swing.JPasswordField(); 39 | acceptButton = new javax.swing.JButton(); 40 | cancelButton = new javax.swing.JButton(); 41 | 42 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); 43 | setTitle(org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.title")); // NOI18N 44 | addWindowListener(new java.awt.event.WindowAdapter() { 45 | public void windowClosing(java.awt.event.WindowEvent evt) { 46 | formWindowClosing(evt); 47 | } 48 | }); 49 | 50 | org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.jLabel1.text")); // NOI18N 51 | 52 | usernameField.setText(org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.usernameField.text")); // NOI18N 53 | 54 | org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.jLabel2.text")); // NOI18N 55 | 56 | passwordField.setText(org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.passwordField.text")); // NOI18N 57 | 58 | org.openide.awt.Mnemonics.setLocalizedText(acceptButton, org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.acceptButton.text")); // NOI18N 59 | acceptButton.addActionListener(new java.awt.event.ActionListener() { 60 | public void actionPerformed(java.awt.event.ActionEvent evt) { 61 | acceptButtonActionPerformed(evt); 62 | } 63 | }); 64 | 65 | org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(AuthDialog.class, "AuthDialog.cancelButton.text")); // NOI18N 66 | cancelButton.addActionListener(new java.awt.event.ActionListener() { 67 | public void actionPerformed(java.awt.event.ActionEvent evt) { 68 | cancelButtonActionPerformed(evt); 69 | } 70 | }); 71 | 72 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 73 | getContentPane().setLayout(layout); 74 | layout.setHorizontalGroup( 75 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 76 | .addGroup(layout.createSequentialGroup() 77 | .addContainerGap() 78 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 79 | .addGroup(layout.createSequentialGroup() 80 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 81 | .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 82 | .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 83 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 84 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 85 | .addComponent(usernameField) 86 | .addComponent(passwordField))) 87 | .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 88 | .addGap(0, 141, Short.MAX_VALUE) 89 | .addComponent(acceptButton) 90 | .addGap(18, 18, 18) 91 | .addComponent(cancelButton))) 92 | .addContainerGap()) 93 | ); 94 | layout.setVerticalGroup( 95 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 96 | .addGroup(layout.createSequentialGroup() 97 | .addContainerGap() 98 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 99 | .addComponent(jLabel1) 100 | .addComponent(usernameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 101 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 102 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 103 | .addComponent(jLabel2) 104 | .addComponent(passwordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 105 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 16, Short.MAX_VALUE) 106 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 107 | .addComponent(acceptButton) 108 | .addComponent(cancelButton)) 109 | .addContainerGap()) 110 | ); 111 | 112 | pack(); 113 | }// //GEN-END:initComponents 114 | 115 | private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed 116 | authentication=null; 117 | setVisible(false); 118 | }//GEN-LAST:event_cancelButtonActionPerformed 119 | 120 | private void acceptButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_acceptButtonActionPerformed 121 | authentication=new UserCredentials(usernameField.getText(), passwordField.getPassword()); 122 | setVisible(false); 123 | }//GEN-LAST:event_acceptButtonActionPerformed 124 | 125 | private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing 126 | authentication=null; 127 | }//GEN-LAST:event_formWindowClosing 128 | 129 | public static UserCredentials showAuthDialog(Frame frame) { 130 | AuthDialog authDialog = new AuthDialog(frame, true); 131 | authDialog.setLocationRelativeTo(frame); 132 | authDialog.setVisible(true); 133 | UserCredentials auth = authDialog.getAuthentication(); 134 | authDialog.dispose(); 135 | return auth; 136 | } 137 | 138 | // Variables declaration - do not modify//GEN-BEGIN:variables 139 | javax.swing.JButton acceptButton; 140 | javax.swing.JButton cancelButton; 141 | javax.swing.JLabel jLabel1; 142 | javax.swing.JLabel jLabel2; 143 | javax.swing.JPasswordField passwordField; 144 | javax.swing.JTextField usernameField; 145 | // End of variables declaration//GEN-END:variables 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/FileOpenedNotifier.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.beans.PropertyChangeEvent; 4 | import java.beans.PropertyChangeListener; 5 | import java.util.Collections; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | import java.util.concurrent.CopyOnWriteArrayList; 12 | import org.openide.filesystems.FileObject; 13 | import org.openide.loaders.DataObject; 14 | import org.openide.windows.TopComponent; 15 | import org.openide.windows.WindowManager; 16 | import qubexplorer.ui.issues.FileObjectOpenedListener; 17 | 18 | /** 19 | * 20 | * @author Victor 21 | */ 22 | public class FileOpenedNotifier implements PropertyChangeListener { 23 | 24 | private final Map> listenersByFilepath = new ConcurrentHashMap<>(); 25 | 26 | public void init() { 27 | WindowManager.getDefault().getRegistry().addPropertyChangeListener(this); 28 | } 29 | 30 | public void registerFileOpenedListener(FileObject fileObject, FileObjectOpenedListener listener) { 31 | List listeners = listenersByFilepath.get(fileObject.getPath()); 32 | if (listeners == null) { 33 | listeners = new CopyOnWriteArrayList<>(); 34 | listenersByFilepath.put(fileObject.getPath(), listeners); 35 | } 36 | listeners.add(listener); 37 | } 38 | 39 | public void unregisterCurrentFileOpenedListeners() { 40 | listenersByFilepath.clear(); 41 | } 42 | 43 | public void fireFileOpenedNotification(FileObject fileOpened) { 44 | getFileOpenedListeners(fileOpened).forEach((listener) -> { 45 | listener.fileOpened(fileOpened); 46 | }); 47 | } 48 | 49 | public List getFileOpenedListeners(FileObject fileObject) { 50 | List listeners = listenersByFilepath.get(fileObject.getPath()); 51 | if (listeners == null) { 52 | listeners = Collections.emptyList(); 53 | } 54 | return listeners; 55 | } 56 | 57 | @Override 58 | public void propertyChange(PropertyChangeEvent event) { 59 | if (TopComponent.Registry.PROP_OPENED.equals(event.getPropertyName())) { 60 | for (TopComponent newOpenedComponent : getNewOpenedComponents(event)) { 61 | FileObject fileObject = getFileObject(newOpenedComponent); 62 | if (fileObject != null) { 63 | fireFileOpenedNotification(fileObject); 64 | } 65 | } 66 | } else if (TopComponent.Registry.PROP_ACTIVATED.equals(event.getPropertyName())) { 67 | TopComponent activatedComponent = (TopComponent) event.getNewValue(); 68 | FileObject fileObject = getFileObject(activatedComponent); 69 | if (fileObject != null) { 70 | fireFileOpenedNotification(fileObject); 71 | } 72 | } 73 | } 74 | 75 | private Set getNewOpenedComponents(PropertyChangeEvent event) { 76 | HashSet newOpenedComponents = (HashSet) event.getNewValue(); 77 | HashSet oldOpenedComponents = (HashSet) event.getOldValue(); 78 | newOpenedComponents.removeAll(oldOpenedComponents); 79 | return newOpenedComponents; 80 | } 81 | 82 | private FileObject getFileObject(TopComponent topComponent) { 83 | FileObject fileObject = null; 84 | DataObject dataObject = topComponent.getLookup().lookup(DataObject.class); 85 | if (dataObject != null) { 86 | fileObject = dataObject.getPrimaryFile(); 87 | } 88 | return fileObject; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/IssueEditorAnnotationAttacher.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CopyOnWriteArrayList; 5 | import javax.swing.SwingUtilities; 6 | import org.openide.cookies.LineCookie; 7 | import org.openide.filesystems.FileObject; 8 | import org.openide.loaders.DataObject; 9 | import org.openide.loaders.DataObjectNotFoundException; 10 | import org.openide.text.Annotation; 11 | import org.openide.text.Line; 12 | import org.openide.util.Lookup; 13 | import qubexplorer.ProjectNotFoundException; 14 | import qubexplorer.RadarIssue; 15 | import qubexplorer.ui.issues.FileObjectOpenedListener; 16 | import qubexplorer.ui.issues.IssueLocation; 17 | 18 | /** 19 | * 20 | * @author Víctor 21 | */ 22 | public class IssueEditorAnnotationAttacher { 23 | 24 | private final List attachedAnnotations = new CopyOnWriteArrayList<>(); 25 | private final FileOpenedNotifier fileOpenedNotifier = new FileOpenedNotifier(); 26 | private ProjectContext projectContext; 27 | private IssueLocation.ProjectKeyChecker projectKeyChecker; 28 | private boolean attached; 29 | 30 | public void init() { 31 | fileOpenedNotifier.init(); 32 | } 33 | 34 | public void setProjectContext(ProjectContext projectContext) { 35 | this.projectContext = projectContext; 36 | } 37 | 38 | public void setProjectKeyChecker(IssueLocation.ProjectKeyChecker projectKeyChecker) { 39 | this.projectKeyChecker = projectKeyChecker; 40 | } 41 | 42 | public boolean isAttached() { 43 | return attached; 44 | } 45 | 46 | public void attachAnnotations(RadarIssue[] issues) { 47 | attached=true; 48 | for (RadarIssue issue : issues) { 49 | try { 50 | if (issue.line() != null) { 51 | tryToAtachEditorAnnotation(issue); 52 | } 53 | } catch (DataObjectNotFoundException ex) { 54 | ; 55 | } 56 | } 57 | } 58 | 59 | private void tryToAtachEditorAnnotation(RadarIssue issue) throws DataObjectNotFoundException { 60 | IssueLocation issueLocation = issue.getLocation(); 61 | try { 62 | FileObject fileObject = issueLocation.getFileObject(projectContext, projectKeyChecker); 63 | if (fileObject != null) { 64 | if (isFileOpen(fileObject)) { 65 | Annotation atachedAnnotation = issue.getLocation().attachAnnotation(issue, fileObject); 66 | if (atachedAnnotation != null) { 67 | attachedAnnotations.add(atachedAnnotation); 68 | } 69 | } else { 70 | fileOpenedNotifier.registerFileOpenedListener(fileObject, new FileAnnotationAttacher(issue)); 71 | } 72 | } 73 | } catch (ProjectNotFoundException ex) { 74 | } 75 | } 76 | 77 | private boolean isFileOpen(FileObject fileObject) throws DataObjectNotFoundException { 78 | DataObject dataObject = DataObject.find(fileObject); 79 | Lookup lookup = dataObject.getLookup(); 80 | LineCookie lineCookie = lookup.lookup(LineCookie.class); 81 | Line.Set lineSet = lineCookie.getLineSet(); 82 | return !lineSet.getLines().isEmpty(); 83 | } 84 | 85 | public void detachAnnotations() { 86 | attached=false; 87 | fileOpenedNotifier.unregisterCurrentFileOpenedListeners(); 88 | attachedAnnotations.forEach((annotation) -> { 89 | annotation.detach(); 90 | }); 91 | attachedAnnotations.clear(); 92 | } 93 | 94 | public class FileAnnotationAttacher implements FileObjectOpenedListener { 95 | 96 | private final RadarIssue issue; 97 | private boolean attached; 98 | 99 | public FileAnnotationAttacher(RadarIssue issue) { 100 | this.issue = issue; 101 | } 102 | 103 | @Override 104 | public void fileOpened(final FileObject fileOpened) { 105 | if (!attached) { 106 | SwingUtilities.invokeLater(() -> { 107 | try { 108 | IssueLocation issueLocation = issue.getLocation(); 109 | Annotation attachedAnnotation = issueLocation.attachAnnotation(issue, fileOpened); 110 | if (attachedAnnotation != null) { 111 | attachedAnnotations.add(attachedAnnotation); 112 | attached = true; 113 | } 114 | } catch (DataObjectNotFoundException ex) { 115 | ; 116 | } 117 | }); 118 | } 119 | } 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/PopupAction.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.awt.event.ActionEvent; 4 | import java.awt.event.ActionListener; 5 | import java.util.List; 6 | import javax.swing.AbstractAction; 7 | import javax.swing.Action; 8 | import javax.swing.JMenu; 9 | import javax.swing.JMenuItem; 10 | import org.openide.awt.ActionID; 11 | import org.openide.awt.ActionReference; 12 | import org.openide.awt.ActionReferences; 13 | import org.openide.awt.ActionRegistration; 14 | import org.openide.util.NbBundle.Messages; 15 | import org.openide.util.Utilities; 16 | import org.openide.util.actions.Presenter; 17 | 18 | @ActionID( 19 | category = "Build", 20 | id = "qubexplorer.ui.SonarQube" 21 | ) 22 | @ActionRegistration( 23 | displayName = "#CTL_SonarQubePopupAction", lazy = false 24 | ) 25 | @ActionReferences({ 26 | @ActionReference(path = "Projects/Actions") 27 | // @ActionReference(path = "Menu/Source", position = 8964, separatorBefore = 8956, separatorAfter = 8968) 28 | }) 29 | @Messages("CTL_SonarQubePopupAction=SonarQube") 30 | public final class PopupAction extends AbstractAction implements ActionListener, Presenter.Popup { 31 | 32 | @Override 33 | public void actionPerformed(ActionEvent e) { 34 | 35 | } 36 | 37 | @Override 38 | public JMenuItem getPopupPresenter() { 39 | JMenu main = new JMenu(Bundle.CTL_SonarQubePopupAction()); 40 | List actionsForPath = Utilities.actionsForPath("Actions/SonarQube"); 41 | for (Action action : actionsForPath) { 42 | main.add(action); 43 | } 44 | return main; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/ProjectContext.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import org.netbeans.api.project.Project; 4 | import qubexplorer.SonarQubeProjectConfiguration; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public class ProjectContext { 11 | private final Project project; 12 | private SonarQubeProjectConfiguration configuration; 13 | 14 | public ProjectContext(Project project, SonarQubeProjectConfiguration configuration) { 15 | this.project = project; 16 | this.configuration = configuration; 17 | } 18 | 19 | // TODO: Maybe not used anymore 20 | public ProjectContext(Project project) { 21 | this.project = project; 22 | } 23 | 24 | public Project getProject() { 25 | return project; 26 | } 27 | 28 | public SonarQubeProjectConfiguration getConfiguration() { 29 | return configuration; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/ProjectRenderer.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.awt.Component; 4 | import javax.swing.DefaultListCellRenderer; 5 | import javax.swing.JLabel; 6 | import javax.swing.JList; 7 | import qubexplorer.SonarQubeProjectConfiguration; 8 | 9 | /** 10 | * 11 | * @author Victor 12 | */ 13 | public class ProjectRenderer extends DefaultListCellRenderer{ 14 | 15 | @Override 16 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean hasFocus) { 17 | JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, hasFocus); 18 | if (value instanceof SonarQubeProjectConfiguration) { 19 | SonarQubeProjectConfiguration project=(SonarQubeProjectConfiguration) value; 20 | label.setText(toString(project)); 21 | } 22 | return label; 23 | } 24 | 25 | public static String toString(SonarQubeProjectConfiguration project){ 26 | return String.format("%s (%s)", project.getName(), project.getKey()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/RuleDialog.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/RuleDialog.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.awt.Frame; 4 | import qubexplorer.Rule; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public class RuleDialog extends javax.swing.JDialog { 11 | 12 | /** 13 | * Creates new form RuleDialog 14 | */ 15 | public RuleDialog(java.awt.Frame parent, boolean modal) { 16 | super(parent, modal); 17 | initComponents(); 18 | getRootPane().setDefaultButton(closeButton); 19 | } 20 | 21 | public void setRule(Rule rule) { 22 | ruleTitle.setText(rule.getName()); 23 | description.setText(rule.getDescription()); 24 | description.setCaretPosition(0); 25 | } 26 | 27 | /** 28 | * This method is called from within the constructor to initialize the form. 29 | * WARNING: Do NOT modify this code. The content of this method is always 30 | * regenerated by the Form Editor. 31 | */ 32 | @SuppressWarnings("unchecked") 33 | // //GEN-BEGIN:initComponents 34 | private void initComponents() { 35 | 36 | ruleTitle = new javax.swing.JLabel(); 37 | closeButton = new javax.swing.JButton(); 38 | jScrollPane1 = new javax.swing.JScrollPane(); 39 | description = new javax.swing.JEditorPane(); 40 | 41 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); 42 | setTitle(org.openide.util.NbBundle.getMessage(RuleDialog.class, "RuleDialog.title")); // NOI18N 43 | setModal(true); 44 | addWindowListener(new java.awt.event.WindowAdapter() { 45 | public void windowOpened(java.awt.event.WindowEvent evt) { 46 | formWindowOpened(evt); 47 | } 48 | }); 49 | 50 | ruleTitle.setFont(ruleTitle.getFont().deriveFont(ruleTitle.getFont().getSize()+5f)); 51 | ruleTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); 52 | org.openide.awt.Mnemonics.setLocalizedText(ruleTitle, org.openide.util.NbBundle.getMessage(RuleDialog.class, "RuleDialog.ruleTitle.text_1")); // NOI18N 53 | 54 | org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(RuleDialog.class, "RuleDialog.closeButton.text")); // NOI18N 55 | closeButton.addActionListener(new java.awt.event.ActionListener() { 56 | public void actionPerformed(java.awt.event.ActionEvent evt) { 57 | closeButtonActionPerformed(evt); 58 | } 59 | }); 60 | 61 | description.setEditable(false); 62 | description.setContentType("text/html"); // NOI18N 63 | jScrollPane1.setViewportView(description); 64 | 65 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 66 | getContentPane().setLayout(layout); 67 | layout.setHorizontalGroup( 68 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 69 | .addGroup(layout.createSequentialGroup() 70 | .addContainerGap() 71 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 72 | .addComponent(jScrollPane1) 73 | .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() 74 | .addGap(0, 427, Short.MAX_VALUE) 75 | .addComponent(closeButton)) 76 | .addComponent(ruleTitle, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 77 | .addContainerGap()) 78 | ); 79 | layout.setVerticalGroup( 80 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 81 | .addGroup(layout.createSequentialGroup() 82 | .addContainerGap() 83 | .addComponent(ruleTitle) 84 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 85 | .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE) 86 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 87 | .addComponent(closeButton) 88 | .addContainerGap()) 89 | ); 90 | 91 | pack(); 92 | }// //GEN-END:initComponents 93 | 94 | private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed 95 | setVisible(false); 96 | }//GEN-LAST:event_closeButtonActionPerformed 97 | 98 | private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened 99 | getRootPane().setDefaultButton(closeButton); 100 | }//GEN-LAST:event_formWindowOpened 101 | 102 | public static void showRule(Frame owner, Rule rule) { 103 | RuleDialog dialog=new RuleDialog(owner, true); 104 | dialog.setLocationRelativeTo(owner); 105 | dialog.setRule(rule); 106 | int minWidth = Math.max(dialog.getWidth(), dialog.ruleTitle.getMinimumSize().width); 107 | dialog.setSize(minWidth+50, dialog.getHeight()); 108 | dialog.setVisible(true); 109 | dialog.dispose(); 110 | } 111 | 112 | // Variables declaration - do not modify//GEN-BEGIN:variables 113 | private javax.swing.JButton closeButton; 114 | private javax.swing.JEditorPane description; 115 | private javax.swing.JScrollPane jScrollPane1; 116 | private javax.swing.JLabel ruleTitle; 117 | // End of variables declaration//GEN-END:variables 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/RuleTask.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import org.openide.windows.WindowManager; 4 | import qubexplorer.Rule; 5 | import qubexplorer.server.SonarQube; 6 | import qubexplorer.ui.task.Task; 7 | 8 | /** 9 | * 10 | * @author Victor 11 | */ 12 | public class RuleTask extends Task{ 13 | private final SonarQube sonarQube; 14 | private final Rule rule; 15 | 16 | public RuleTask(SonarQube sonarQube, Rule rule, ProjectContext projectContext) { 17 | super(projectContext, sonarQube.getServerUrl()); 18 | this.sonarQube=sonarQube; 19 | this.rule=rule; 20 | } 21 | 22 | @Override 23 | public Rule execute() { 24 | return sonarQube.getRule(getUserCredentials(), rule.getKey()); 25 | } 26 | 27 | @Override 28 | protected void success(Rule ruleInServer) { 29 | rule.setDescription(ruleInServer.getDescription()); 30 | RuleDialog.showRule(WindowManager.getDefault().getMainWindow(), ruleInServer); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/SeverityIconRenderer.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.awt.Component; 4 | import javax.swing.JLabel; 5 | import javax.swing.JTable; 6 | import javax.swing.table.DefaultTableCellRenderer; 7 | import qubexplorer.Classifier; 8 | 9 | /** 10 | * Render in the issues table. 11 | * 12 | * @author Victor 13 | */ 14 | public class SeverityIconRenderer extends DefaultTableCellRenderer{ 15 | 16 | @Override 17 | public Component getTableCellRendererComponent(JTable jtable, Object o, boolean bln, boolean bln1, int i, int i1) { 18 | JLabel component = (JLabel) super.getTableCellRendererComponent(jtable, o, bln, bln1, i, i1); 19 | component.setText(null); 20 | component.setIcon(((Classifier)o).getIcon()); 21 | component.setIconTextGap(0); 22 | component.setBorder(null); 23 | return component; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/SonarQubeOptionsPanel.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/SonarQubeOptionsPanel.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.prefs.Preferences; 6 | import javax.swing.DefaultComboBoxModel; 7 | import org.openide.util.NbPreferences; 8 | import qubexplorer.runner.SonarRunnerProccess; 9 | 10 | public final class SonarQubeOptionsPanel extends javax.swing.JPanel { 11 | 12 | private final transient SonarQubeOptionsPanelController controller; 13 | private final Set analysisModes=new HashSet<>(); 14 | 15 | SonarQubeOptionsPanel(SonarQubeOptionsPanelController controller) { 16 | this.controller = controller; 17 | analysisModes.add(SonarRunnerProccess.AnalysisMode.INCREMENTAL.getFriendlyName()); 18 | analysisModes.add(SonarRunnerProccess.AnalysisMode.PREVIEW.getFriendlyName()); 19 | initComponents(); 20 | DefaultComboBoxModel model = (DefaultComboBoxModel)analysisModeCombo.getModel(); 21 | analysisModes.forEach((mode) -> { 22 | model.addElement(mode); 23 | }); 24 | } 25 | 26 | /** 27 | * This method is called from within the constructor to initialize the form. 28 | * WARNING: Do NOT modify this code. The content of this method is always 29 | * regenerated by the Form Editor. 30 | */ 31 | // //GEN-BEGIN:initComponents 32 | private void initComponents() { 33 | 34 | jLabel1 = new javax.swing.JLabel(); 35 | serverAddress = new javax.swing.JTextField(); 36 | jLabel2 = new javax.swing.JLabel(); 37 | analysisModeCombo = new javax.swing.JComboBox(); 38 | jLabel3 = new javax.swing.JLabel(); 39 | jLabel4 = new javax.swing.JLabel(); 40 | tJvmArguments = new org.jdesktop.swingx.JXTextField(); 41 | editorAnnotationsEnabled = new javax.swing.JCheckBox(); 42 | 43 | org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.jLabel1.text")); // NOI18N 44 | 45 | serverAddress.setText(org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.serverAddress.text")); // NOI18N 46 | 47 | org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.jLabel2.text")); // NOI18N 48 | 49 | jLabel3.setFont(jLabel3.getFont().deriveFont((jLabel3.getFont().getStyle() | java.awt.Font.ITALIC), jLabel3.getFont().getSize()-1)); 50 | org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.jLabel3.text")); // NOI18N 51 | 52 | org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.jLabel4.text")); // NOI18N 53 | 54 | tJvmArguments.setText(org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.tJvmArguments.text")); // NOI18N 55 | tJvmArguments.setPrompt(org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.tJvmArguments.prompt")); // NOI18N 56 | 57 | org.openide.awt.Mnemonics.setLocalizedText(editorAnnotationsEnabled, org.openide.util.NbBundle.getMessage(SonarQubeOptionsPanel.class, "SonarQubeOptionsPanel.editorAnnotationsEnabled.text")); // NOI18N 58 | 59 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); 60 | this.setLayout(layout); 61 | layout.setHorizontalGroup( 62 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 63 | .addGroup(layout.createSequentialGroup() 64 | .addContainerGap() 65 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 66 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 67 | .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 68 | .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 69 | .addGroup(layout.createSequentialGroup() 70 | .addGap(4, 4, 4) 71 | .addComponent(jLabel4))) 72 | .addGap(18, 18, 18) 73 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 74 | .addGroup(layout.createSequentialGroup() 75 | .addComponent(editorAnnotationsEnabled) 76 | .addGap(0, 0, Short.MAX_VALUE)) 77 | .addGroup(layout.createSequentialGroup() 78 | .addGap(6, 6, 6) 79 | .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 514, Short.MAX_VALUE)) 80 | .addComponent(analysisModeCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 81 | .addComponent(serverAddress) 82 | .addComponent(tJvmArguments, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 83 | .addContainerGap()) 84 | ); 85 | layout.setVerticalGroup( 86 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 87 | .addGroup(layout.createSequentialGroup() 88 | .addContainerGap() 89 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 90 | .addComponent(jLabel1) 91 | .addComponent(serverAddress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 92 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 93 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 94 | .addComponent(analysisModeCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 95 | .addComponent(jLabel2)) 96 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 97 | .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE) 98 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 99 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 100 | .addComponent(jLabel4) 101 | .addComponent(tJvmArguments, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 102 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) 103 | .addComponent(editorAnnotationsEnabled) 104 | .addContainerGap(101, Short.MAX_VALUE)) 105 | ); 106 | }// //GEN-END:initComponents 107 | 108 | protected void load() { 109 | Preferences nbPreferences = NbPreferences.forModule(SonarQubeOptionsPanel.class); 110 | serverAddress.setText(nbPreferences.get("address", "http://localhost:9000")); 111 | SonarRunnerProccess.AnalysisMode defaultAnalysisMode=SonarRunnerProccess.getDefaultAnalysisMode(); 112 | String analysisMode = nbPreferences.get("runner.analysisMode", defaultAnalysisMode.getFriendlyName()); 113 | if(!analysisModes.contains(analysisMode)){ 114 | analysisMode=defaultAnalysisMode.getFriendlyName(); 115 | } 116 | analysisModeCombo.setSelectedItem(analysisMode); 117 | tJvmArguments.setText(nbPreferences.get("runner.jvmArguments", "")); 118 | editorAnnotationsEnabled.setSelected(nbPreferences.getBoolean("editorAnnotations.enabled", true)); 119 | } 120 | 121 | protected void store() { 122 | final Preferences nbPreferences = NbPreferences.forModule(SonarQubeOptionsPanel.class); 123 | nbPreferences.put("address", serverAddress.getText()); 124 | nbPreferences.put("runner.analysisMode", analysisModeCombo.getSelectedItem().toString()); 125 | nbPreferences.put("runner.jvmArguments", tJvmArguments.getText()); 126 | nbPreferences.putBoolean("editorAnnotations.enabled", editorAnnotationsEnabled.isSelected()); 127 | } 128 | 129 | boolean valid() { 130 | return true; 131 | } 132 | 133 | // Variables declaration - do not modify//GEN-BEGIN:variables 134 | private javax.swing.JComboBox analysisModeCombo; 135 | private javax.swing.JCheckBox editorAnnotationsEnabled; 136 | private javax.swing.JLabel jLabel1; 137 | private javax.swing.JLabel jLabel2; 138 | private javax.swing.JLabel jLabel3; 139 | private javax.swing.JLabel jLabel4; 140 | private javax.swing.JTextField serverAddress; 141 | private org.jdesktop.swingx.JXTextField tJvmArguments; 142 | // End of variables declaration//GEN-END:variables 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/SonarQubeOptionsPanelController.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.beans.PropertyChangeListener; 4 | import java.beans.PropertyChangeSupport; 5 | import javax.swing.JComponent; 6 | import javax.swing.SwingUtilities; 7 | import org.netbeans.spi.options.OptionsPanelController; 8 | import org.openide.util.HelpCtx; 9 | import org.openide.util.Lookup; 10 | import org.openide.windows.WindowManager; 11 | 12 | @OptionsPanelController.SubRegistration( 13 | location = "Advanced", 14 | displayName = "#AdvancedOption_DisplayName_SonarQube", 15 | keywords = "#AdvancedOption_Keywords_SonarQube", 16 | keywordsCategory = "Advanced/SonarQube") 17 | @org.openide.util.NbBundle.Messages({"AdvancedOption_DisplayName_SonarQube=SonarQube", "AdvancedOption_Keywords_SonarQube=sonar"}) 18 | public final class SonarQubeOptionsPanelController extends OptionsPanelController { 19 | 20 | private SonarQubeOptionsPanel panel; 21 | private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); 22 | private boolean changed; 23 | 24 | @Override 25 | public void update() { 26 | getPanel().load(); 27 | changed = false; 28 | } 29 | 30 | @Override 31 | public void applyChanges() { 32 | getPanel().store(); 33 | changed = false; 34 | SwingUtilities.invokeLater(() -> { 35 | SonarIssuesTopComponent sonarTopComponent = (SonarIssuesTopComponent) WindowManager.getDefault().findTopComponent("SonarIssuesTopComponent"); 36 | sonarTopComponent.refreshEditorAnnotationsStatus(); 37 | }); 38 | } 39 | 40 | @Override 41 | public void cancel() { 42 | // need not do anything special, if no changes have been persisted yet 43 | } 44 | 45 | @Override 46 | public boolean isValid() { 47 | return getPanel().valid(); 48 | } 49 | 50 | @Override 51 | public boolean isChanged() { 52 | return changed; 53 | } 54 | 55 | @Override 56 | public HelpCtx getHelpCtx() { 57 | return null; 58 | } 59 | 60 | @Override 61 | public JComponent getComponent(Lookup masterLookup) { 62 | return getPanel(); 63 | } 64 | 65 | @Override 66 | public void addPropertyChangeListener(PropertyChangeListener l) { 67 | pcs.addPropertyChangeListener(l); 68 | } 69 | 70 | @Override 71 | public void removePropertyChangeListener(PropertyChangeListener l) { 72 | pcs.removePropertyChangeListener(l); 73 | } 74 | 75 | private SonarQubeOptionsPanel getPanel() { 76 | if (panel == null) { 77 | panel = new SonarQubeOptionsPanel(this); 78 | } 79 | return panel; 80 | } 81 | 82 | void changed() { 83 | if (!changed) { 84 | changed = true; 85 | pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true); 86 | } 87 | pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/UserCredentialsRepository.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import qubexplorer.ResourceKey; 6 | import qubexplorer.UserCredentials; 7 | 8 | /** 9 | * 10 | * @author Victor 11 | */ 12 | public class UserCredentialsRepository { 13 | private static UserCredentialsRepository repository; 14 | private final Map> cache = new HashMap<>(); 15 | 16 | public UserCredentials getUserCredentials(String serverUrl, ResourceKey resourceKey) { 17 | if (cache.containsKey(serverUrl)) { 18 | if (cache.get(serverUrl).containsKey(resourceKey)) { 19 | return cache.get(serverUrl).get(resourceKey); 20 | } else { 21 | return cache.get(serverUrl).get(null); 22 | } 23 | } else { 24 | return null; 25 | } 26 | } 27 | 28 | public void saveUserCredentials(String serverUrl, ResourceKey resourceKey, UserCredentials authentication) { 29 | if (!cache.containsKey(serverUrl)) { 30 | cache.put(serverUrl, new HashMap()); 31 | } 32 | cache.get(serverUrl).put(null, authentication); 33 | if (resourceKey != null) { 34 | cache.get(serverUrl).put(resourceKey, authentication); 35 | } 36 | } 37 | 38 | public static synchronized UserCredentialsRepository getInstance() { 39 | if (repository == null) { 40 | repository = new UserCredentialsRepository(); 41 | } 42 | return repository; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/issues/FileObjectOpenedListener.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.issues; 2 | 3 | import org.openide.filesystems.FileObject; 4 | 5 | /** 6 | * 7 | * @author Victor 8 | */ 9 | public interface FileObjectOpenedListener { 10 | 11 | void fileOpened(FileObject fileOpened); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/issues/IssueLocation.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.issues; 2 | 3 | import qubexplorer.ProjectNotFoundException; 4 | import java.io.File; 5 | import java.util.Comparator; 6 | import java.util.Set; 7 | import org.netbeans.api.java.project.JavaProjectConstants; 8 | import org.netbeans.api.project.FileOwnerQuery; 9 | import org.netbeans.api.project.Project; 10 | import org.netbeans.api.project.ProjectUtils; 11 | import org.netbeans.api.project.SourceGroup; 12 | import org.netbeans.api.project.Sources; 13 | import org.openide.cookies.EditorCookie; 14 | import org.openide.filesystems.FileObject; 15 | import org.openide.filesystems.FileUtil; 16 | import org.openide.loaders.DataObject; 17 | import org.openide.loaders.DataObjectNotFoundException; 18 | import org.openide.text.Annotation; 19 | import org.openide.text.Line; 20 | import org.openide.util.Lookup; 21 | import qubexplorer.RadarIssue; 22 | import qubexplorer.ResourceKey; 23 | import qubexplorer.SonarQubeProjectConfiguration; 24 | import qubexplorer.ui.ProjectContext; 25 | 26 | /** 27 | * 28 | * @author Victor 29 | */ 30 | public class IssueLocation { 31 | 32 | private final ResourceKey componentKey; 33 | private final int lineNumber; 34 | private static final String DEFAULT_EXTENSION = ".java"; 35 | 36 | public IssueLocation(String componentKey, int lineNumber) { 37 | this.lineNumber = lineNumber; 38 | this.componentKey = ResourceKey.valueOf(componentKey); 39 | } 40 | 41 | public String getComponentPath() { 42 | return componentKey.getLastPart(); 43 | } 44 | 45 | public String getSimpleComponentName() { 46 | String extension = ""; 47 | char pathSeparator; 48 | String componentPath = getComponentPath(); 49 | if (componentPath.contains("/")) { 50 | pathSeparator = '/'; 51 | } else { 52 | extension = DEFAULT_EXTENSION; 53 | pathSeparator = '.'; 54 | } 55 | int index = componentPath.lastIndexOf(pathSeparator); 56 | if (index < componentPath.length() - 1) { 57 | return componentPath.substring(index + 1) + extension; 58 | } else { 59 | return ""; 60 | } 61 | } 62 | 63 | public Integer getLineNumber() { 64 | return lineNumber; 65 | } 66 | 67 | public ResourceKey getProjectKey() { 68 | return componentKey.subkey(0, componentKey.getPartsCount() - 1); 69 | } 70 | 71 | public Project getProjectOwner(ProjectContext projectContext, ProjectKeyChecker projectKeyChecker) { 72 | FileObject projectDir = findProjectDir(projectContext, getProjectKey(), projectKeyChecker); 73 | if (projectDir != null) { 74 | return FileOwnerQuery.getOwner(projectDir); 75 | } else { 76 | return null; 77 | } 78 | } 79 | 80 | public File getFile(ProjectContext projectContext, ProjectKeyChecker projectKeyChecker) { 81 | Project projectOwner = getProjectOwner(projectContext, projectKeyChecker); 82 | if (projectOwner == null) { 83 | throw new ProjectNotFoundException(getProjectKey().toString()); 84 | } 85 | File file; 86 | String componentPath = getComponentPath(); 87 | if (isFilePath(componentPath)) { 88 | /* It's a relative file path. Relative to project directory? 89 | Example: src/main/java/victor/simpleproject/Persona.java */ 90 | // Use project.directory or sources group? 91 | file = new File(projectOwner.getProjectDirectory().getPath(), componentPath); 92 | } else { 93 | /* 94 | It's an element name. Assume is a java file. 95 | Example: package.subpackage.ClassA 96 | */ 97 | String filePath = componentPath.replace(".", "/") + DEFAULT_EXTENSION; 98 | Sources sources = ProjectUtils.getSources(projectOwner); 99 | SourceGroup[] sourceGroups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); 100 | file = new File(sourceGroups[0].getRootFolder().getPath(), filePath); 101 | } 102 | return file; 103 | } 104 | 105 | private static boolean isFilePath(String componentPath) { 106 | return componentPath.contains("/"); 107 | } 108 | 109 | public FileObject getFileObject(ProjectContext projectContext, ProjectKeyChecker projectKeyChecker) { 110 | return FileUtil.toFileObject(getFile(projectContext, projectKeyChecker)); 111 | } 112 | 113 | public Annotation attachAnnotation(RadarIssue radarIssue, FileObject fileObject) throws DataObjectNotFoundException { 114 | Annotation ann = null; 115 | EditorCookie editorCookie = getEditorCookie(fileObject); 116 | if (editorCookie != null) { 117 | Line line = getLine(editorCookie); 118 | if (line != null) { 119 | ann = new SonarQubeEditorAnnotation(radarIssue.severityObject(), radarIssue.message()); 120 | ann.attach(line); 121 | } 122 | } 123 | return ann; 124 | } 125 | 126 | public Line getLine(EditorCookie editorCookie) { 127 | Line.Set lineSet = editorCookie.getLineSet(); 128 | int effectiveLineNumber = getLineNumber() <= 0 ? 1 : getLineNumber(); 129 | int index = Math.min(effectiveLineNumber, lineSet.getLines().size()) - 1; 130 | return lineSet.getCurrent(index); 131 | } 132 | 133 | @Override 134 | public String toString() { 135 | if (lineNumber <= 0) { 136 | return componentKey.toString(); 137 | } else { 138 | return componentKey.toString() + " [" + lineNumber + "]"; 139 | } 140 | } 141 | 142 | public static EditorCookie getEditorCookie(FileObject fileObject) throws DataObjectNotFoundException { 143 | DataObject dataObject = DataObject.find(fileObject); 144 | Lookup lookup = dataObject.getLookup(); 145 | return lookup.lookup(EditorCookie.class); 146 | } 147 | 148 | private static FileObject findProjectDir(ProjectContext projectContext, ResourceKey issueProjectKey, ProjectKeyChecker projectKeyChecker) { 149 | if (projectKeyChecker.equals(projectContext.getConfiguration(), issueProjectKey, false) ) { 150 | return projectContext.getProject().getProjectDirectory(); 151 | } 152 | Set subprojects = ProjectUtils.getContainedProjects(projectContext.getProject(), true); 153 | if (subprojects != null) { 154 | for (Project subproject : subprojects) { 155 | SonarQubeProjectConfiguration subprojectInfo = projectContext.getConfiguration().createConfiguration(subproject); 156 | if (projectKeyChecker.equals(subprojectInfo, issueProjectKey, true) ) { 157 | return subproject.getProjectDirectory(); 158 | } 159 | } 160 | } 161 | return null; 162 | } 163 | 164 | public static class IssueLocationComparator implements Comparator { 165 | 166 | @Override 167 | public int compare(IssueLocation t, IssueLocation t1) { 168 | int result = t.getComponentPath().compareTo(t1.getComponentPath()); 169 | if (result != 0) { 170 | return result; 171 | } else { 172 | return Integer.compare(t.getLineNumber(), t1.getLineNumber()); 173 | } 174 | } 175 | 176 | } 177 | 178 | public static interface ProjectKeyChecker { 179 | 180 | boolean equals(SonarQubeProjectConfiguration configuration, ResourceKey projectKeyIssue, boolean isSubmodule); 181 | 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/issues/IssuesTableModel.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.issues; 2 | 3 | import javax.swing.table.DefaultTableModel; 4 | import qubexplorer.RadarIssue; 5 | import qubexplorer.Severity; 6 | 7 | /** 8 | * 9 | * @author Victor 10 | */ 11 | public class IssuesTableModel extends DefaultTableModel { 12 | private static final Class[] COLUMN_TYPES = new Class[]{ 13 | Severity.class, java.lang.Object.class, java.lang.String.class, java.lang.String.class, Severity.class, java.lang.String.class, String.class 14 | }; 15 | 16 | private static final String[] COLUMN_NAMES = new String [] {"", "Location", "Message", "Rule", "Severity", "Project Key", "Full Path"}; 17 | 18 | private transient RadarIssue[] issues; 19 | 20 | public IssuesTableModel() { 21 | super(new Object [][] {}, COLUMN_NAMES); 22 | } 23 | 24 | public void add(RadarIssue issue) { 25 | addRow(createRowData(issue)); 26 | } 27 | 28 | public Object[] createRowData(RadarIssue issue){ 29 | IssueLocation issueLocation=issue.getLocation(); 30 | return new Object[]{issue.severityObject(), issueLocation, issue.message(), issue.rule().getName(), issue.severityObject(), issueLocation.getProjectKey().toString(), issueLocation.getComponentPath()}; 31 | } 32 | 33 | public void setIssues(RadarIssue[] issues) { 34 | this.issues=issues; 35 | while (getRowCount() > 0) { 36 | removeRow(0); 37 | } 38 | for (RadarIssue issue : issues) { 39 | add(issue); 40 | } 41 | } 42 | 43 | public RadarIssue[] getIssues() { 44 | return issues; 45 | } 46 | 47 | public RadarIssue getIssue(int row) { 48 | return issues[row]; 49 | } 50 | 51 | public IssueLocation getIssueLocation(int row) { 52 | return (IssueLocation) getValueAt(row, 1); 53 | } 54 | 55 | @Override 56 | public Class getColumnClass(int columnIndex) { 57 | return COLUMN_TYPES[columnIndex]; 58 | } 59 | 60 | @Override 61 | public boolean isCellEditable(int rowIndex, int columnIndex) { 62 | return false; 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/issues/IssuesTask.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.issues; 2 | 3 | import java.util.List; 4 | import org.openide.windows.WindowManager; 5 | import qubexplorer.IssuesContainer; 6 | import qubexplorer.RadarIssue; 7 | import qubexplorer.filter.IssueFilter; 8 | import qubexplorer.server.SonarQube; 9 | import qubexplorer.ui.ProjectContext; 10 | import qubexplorer.ui.SonarIssuesTopComponent; 11 | import qubexplorer.ui.task.Task; 12 | 13 | /** 14 | * 15 | * @author Victor 16 | */ 17 | public class IssuesTask extends Task> { 18 | 19 | private final IssuesContainer issuesContainer; 20 | private final List filters; 21 | 22 | public IssuesTask(ProjectContext projectContext, IssuesContainer issuesContainer, List filters) { 23 | super(projectContext, issuesContainer instanceof SonarQube ? ((SonarQube) issuesContainer).getServerUrl() : null); 24 | this.issuesContainer = issuesContainer; 25 | this.filters = filters; 26 | } 27 | 28 | @Override 29 | public List execute() { 30 | return issuesContainer.getIssues(getUserCredentials(), getProjectContext().getConfiguration().getKey(), filters); 31 | } 32 | 33 | @Override 34 | protected void success(List result) { 35 | SonarIssuesTopComponent sonarTopComponent = (SonarIssuesTopComponent) WindowManager.getDefault().findTopComponent("SonarIssuesTopComponent"); 36 | sonarTopComponent.open(); 37 | sonarTopComponent.requestVisible(); 38 | sonarTopComponent.setProjectContext(getProjectContext()); 39 | sonarTopComponent.showIssues(filters, result.toArray(new RadarIssue[0])); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/issues/LocationRenderer.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.issues; 2 | 3 | import java.awt.Component; 4 | import javax.swing.JTable; 5 | import javax.swing.table.DefaultTableCellRenderer; 6 | 7 | /** 8 | * 9 | * @author Victor 10 | */ 11 | public class LocationRenderer extends DefaultTableCellRenderer{ 12 | 13 | @Override 14 | public Component getTableCellRendererComponent(JTable jtable, Object o, boolean bln, boolean bln1, int i, int i1) { 15 | Object value; 16 | if(o instanceof IssueLocation){ 17 | IssueLocation location = (IssueLocation)o; 18 | if(location.getLineNumber() > 0){ 19 | value=String.format("%4d:%s", location.getLineNumber(), location.getSimpleComponentName()); 20 | }else{ 21 | value=String.format(" %s", location.getSimpleComponentName()); 22 | } 23 | }else{ 24 | value=o; 25 | } 26 | return super.getTableCellRendererComponent(jtable, value, bln, bln1, i, i1); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/issues/SonarQubeEditorAnnotation.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.issues; 2 | 3 | import org.openide.text.Annotation; 4 | import qubexplorer.Severity; 5 | 6 | /** 7 | * 8 | * @author Victor 9 | */ 10 | public class SonarQubeEditorAnnotation extends Annotation{ 11 | private final Severity severity; 12 | private final String description; 13 | 14 | public SonarQubeEditorAnnotation(Severity severity, String message) { 15 | this.severity = severity; 16 | this.description=severity+": "+message; 17 | } 18 | 19 | @Override 20 | public String getAnnotationType() { 21 | return "sonarqube-"+severity.name().toLowerCase()+"-annotation"; 22 | } 23 | 24 | @Override 25 | public String getShortDescription() { 26 | return description; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/summary/ClassifierSummaryModel.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.summary; 2 | 3 | import java.util.Arrays; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import org.jdesktop.swingx.treetable.AbstractTreeTableModel; 7 | import qubexplorer.Classifier; 8 | import qubexplorer.ClassifierSummary; 9 | import qubexplorer.ClassifierType; 10 | import qubexplorer.Rule; 11 | 12 | /** 13 | * 14 | * @author Victor 15 | */ 16 | public class ClassifierSummaryModel extends AbstractTreeTableModel { 17 | 18 | private final ClassifierType classifierType; 19 | private boolean skipEmptySeverity = false; 20 | private List classifiers; 21 | 22 | public ClassifierSummaryModel(ClassifierType classifierType, ClassifierSummary summary, boolean skip) { 23 | super(summary); 24 | this.classifierType=classifierType; 25 | skipEmptySeverity = skip; 26 | setClassifiers(); 27 | } 28 | 29 | public boolean isSkipEmptySeverity() { 30 | return skipEmptySeverity; 31 | } 32 | 33 | public void setSkipEmptySeverity(boolean skipEmptySeverity) { 34 | this.skipEmptySeverity = skipEmptySeverity; 35 | setClassifiers(); 36 | } 37 | 38 | private void setClassifiers() { 39 | List classifierValues = classifierType.getValues(); 40 | if (skipEmptySeverity) { 41 | List tmp = new LinkedList<>(); 42 | for (T classifier : classifierValues) { 43 | if (getSummary().getCount(classifier) > 0) { 44 | tmp.add(classifier); 45 | } 46 | } 47 | classifiers = tmp; 48 | } else { 49 | classifiers = classifierValues; 50 | } 51 | } 52 | 53 | @Override 54 | public int getColumnCount() { 55 | return 2; 56 | } 57 | 58 | @Override 59 | public Object getValueAt(Object node, int i) { 60 | ClassifierSummary summary = getSummary(); 61 | Object value = null; 62 | if (node instanceof ClassifierSummary) { 63 | if (i == 0) { 64 | value = "Issues"; 65 | } else { 66 | value = summary.getCount(); 67 | } 68 | } else if (node instanceof Classifier) { 69 | if (i == 0) { 70 | value = ((Classifier) node).getUserDescription(); 71 | } else { 72 | value = summary.getCount((T) node); 73 | } 74 | } else if (node instanceof Rule) { 75 | if (i == 0) { 76 | value = ((Rule) node).getDescription(); 77 | } else { 78 | value = summary.getCount((Rule) node); 79 | } 80 | } 81 | return value; 82 | } 83 | 84 | @Override 85 | public String getColumnName(int column) { 86 | if (column == 0) { 87 | return ""; 88 | } else { 89 | return "Count"; 90 | } 91 | } 92 | 93 | @Override 94 | public Object getChild(Object parent, int i) { 95 | if (parent instanceof ClassifierSummary) { 96 | return classifiers.get(i); 97 | } else if (parent instanceof Classifier) { 98 | ClassifierSummary summary = getSummary(); 99 | Rule[] rules = summary.getRules((T) parent).toArray(new Rule[0]); 100 | Arrays.sort(rules, (Rule t, Rule t1) -> { 101 | int count1 = summary.getCount(t); 102 | int count2 = summary.getCount(t1); 103 | return count2 - count1; 104 | }); 105 | return rules[i]; 106 | } else { 107 | throw new AssertionError("Unknown parent object"); 108 | } 109 | } 110 | 111 | public ClassifierSummary getSummary() { 112 | return (ClassifierSummary) getRoot(); 113 | } 114 | 115 | @Override 116 | public int getChildCount(Object parent) { 117 | if (parent instanceof ClassifierSummary) { 118 | return classifiers.size(); 119 | } else if (parent instanceof Classifier) { 120 | return getSummary().getRules((T) parent).size(); 121 | } else { 122 | return 0; 123 | } 124 | } 125 | 126 | @Override 127 | public int getIndexOfChild(Object parent, Object o1) { 128 | if (parent instanceof ClassifierSummary) { 129 | return Arrays.asList(classifiers).indexOf(o1); 130 | } else if (parent instanceof Classifier) { 131 | return -1; 132 | } else { 133 | return -1; 134 | } 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/summary/SummaryTask.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.summary; 2 | 3 | import qubexplorer.server.ui.CustomServerIssuesAction; 4 | import org.openide.windows.WindowManager; 5 | import qubexplorer.ClassifierSummary; 6 | import qubexplorer.ConfigurationFactory; 7 | import qubexplorer.IssuesContainer; 8 | import qubexplorer.NoSuchProjectException; 9 | import qubexplorer.ResourceKey; 10 | import qubexplorer.SonarQubeProjectConfiguration; 11 | import qubexplorer.SummaryOptions; 12 | import qubexplorer.server.SonarQube; 13 | import qubexplorer.ui.UserCredentialsRepository; 14 | import qubexplorer.ui.ProjectContext; 15 | import qubexplorer.server.ui.ServerConnectionDialog; 16 | import qubexplorer.ui.SonarIssuesTopComponent; 17 | import qubexplorer.ui.issues.IssueLocation; 18 | import qubexplorer.ui.task.Task; 19 | import qubexplorer.ui.task.TaskExecutor; 20 | 21 | /** 22 | * 23 | * @author Victor 24 | */ 25 | public class SummaryTask extends Task { 26 | 27 | private final IssuesContainer issuesContainer; 28 | private final SummaryOptions summaryOptions; 29 | 30 | public SummaryTask(IssuesContainer issuesContainer, ProjectContext projectContext, SummaryOptions summaryOptions) { 31 | super(projectContext, issuesContainer instanceof SonarQube ? ((SonarQube) issuesContainer).getServerUrl() : null); 32 | this.issuesContainer = issuesContainer; 33 | this.summaryOptions=summaryOptions; 34 | } 35 | 36 | @Override 37 | protected void init() { 38 | SonarIssuesTopComponent sonarTopComponent = (SonarIssuesTopComponent) WindowManager.getDefault().findTopComponent("SonarIssuesTopComponent"); 39 | sonarTopComponent.setSummaryOptions(summaryOptions); 40 | sonarTopComponent.resetState(); 41 | } 42 | 43 | @Override 44 | public ClassifierSummary execute() { 45 | return issuesContainer.getSummary(summaryOptions.getClassifierType(), getUserCredentials(), getProjectContext().getConfiguration().getKey(), summaryOptions.getFilters()); 46 | } 47 | 48 | @Override 49 | protected void success(ClassifierSummary summary) { 50 | SonarIssuesTopComponent sonarTopComponent = (SonarIssuesTopComponent) WindowManager.getDefault().findTopComponent("SonarIssuesTopComponent"); 51 | sonarTopComponent.setProjectContext(getProjectContext()); 52 | sonarTopComponent.setProjectKeyChecker(new SimpleChecker()); 53 | sonarTopComponent.setIssuesContainer(issuesContainer); 54 | sonarTopComponent.showSummary(summaryOptions, summary); 55 | sonarTopComponent.open(); 56 | sonarTopComponent.requestVisible(); 57 | } 58 | 59 | @Override 60 | protected void fail(Throwable cause) { 61 | if (cause instanceof NoSuchProjectException) { 62 | assert issuesContainer instanceof SonarQube; 63 | String serverUrl = ((SonarQube) issuesContainer).getServerUrl(); 64 | if (getUserCredentials() != null) { 65 | UserCredentialsRepository.getInstance().saveUserCredentials(serverUrl, null, getUserCredentials()); 66 | } 67 | ServerConnectionDialog connectionDialog = new ServerConnectionDialog(WindowManager.getDefault().getMainWindow(), true); 68 | connectionDialog.setSelectedUrl(serverUrl); 69 | connectionDialog.loadProjectKeys(); 70 | if (connectionDialog.showDialog() == ServerConnectionDialog.Option.ACCEPT) { 71 | SonarQubeProjectConfiguration fixed = connectionDialog.getSelectedProject(); 72 | SonarQubeProjectConfiguration real = ConfigurationFactory.createDefaultConfiguration(getProjectContext().getProject()); 73 | ProjectContext newProjectContext = new ProjectContext(getProjectContext().getProject(), new CustomServerIssuesAction.FixedKey(fixed, real)); 74 | TaskExecutor.execute(new SummaryTask(new SonarQube(connectionDialog.getSelectedUrl()), newProjectContext, summaryOptions)); 75 | } 76 | } else { 77 | super.fail(cause); 78 | } 79 | } 80 | 81 | private static class SimpleChecker implements IssueLocation.ProjectKeyChecker { 82 | 83 | @Override 84 | public boolean equals(SonarQubeProjectConfiguration configuration, ResourceKey projectKeyIssue, boolean isSubmodule) { 85 | return configuration.getKey().equals(projectKeyIssue); 86 | } 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/summary/SummaryTreeCellRenderer.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.summary; 2 | 3 | import java.awt.Component; 4 | import javax.swing.JTree; 5 | import javax.swing.tree.DefaultTreeCellRenderer; 6 | import qubexplorer.Classifier; 7 | import qubexplorer.ClassifierSummary; 8 | import qubexplorer.Rule; 9 | 10 | /** 11 | * Render in the tree table 12 | * 13 | * @author Victor 14 | */ 15 | public class SummaryTreeCellRenderer extends DefaultTreeCellRenderer { 16 | 17 | @Override 18 | public Component getTreeCellRendererComponent(JTree jtree, Object o, boolean bln, boolean bln1, boolean bln2, int i, boolean bln3) { 19 | Component c = super.getTreeCellRendererComponent(jtree, o, bln, bln1, bln2, i, bln3); 20 | if (o instanceof Classifier) { 21 | setText(((Classifier)o).getUserDescription()); 22 | setIcon(((Classifier)o).getIcon()); 23 | }else if(o instanceof Rule) { 24 | setIcon(null); 25 | setText(((Rule)o).getName()); 26 | }else if(o instanceof ClassifierSummary){ 27 | setIcon(null); 28 | setText("Issues"); 29 | } 30 | return c; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/task/Task.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.task; 2 | 3 | import org.openide.util.Exceptions; 4 | import qubexplorer.UserCredentials; 5 | import qubexplorer.ui.ProjectContext; 6 | 7 | /** 8 | * 9 | * @author Victor 10 | */ 11 | public abstract class Task { 12 | private final ProjectContext projectContext; 13 | private final String serverUrl; 14 | private UserCredentials userCredentials; 15 | private boolean retryIfNoAuthorization=true; 16 | 17 | public Task(ProjectContext projectContext, String serverUrl) { 18 | this.projectContext = projectContext; 19 | this.serverUrl=serverUrl; 20 | } 21 | 22 | public void setRetryIfNoAuthorization(boolean retryIfNoAuthorization) { 23 | this.retryIfNoAuthorization = retryIfNoAuthorization; 24 | } 25 | 26 | public boolean isRetryIfNoAuthorization() { 27 | return retryIfNoAuthorization; 28 | } 29 | 30 | public void setUserCredentials(UserCredentials userCredentials) { 31 | this.userCredentials = userCredentials; 32 | } 33 | 34 | public UserCredentials getUserCredentials() { 35 | return userCredentials; 36 | } 37 | 38 | public ProjectContext getProjectContext() { 39 | return projectContext; 40 | } 41 | 42 | public String getServerUrl() { 43 | return serverUrl; 44 | } 45 | 46 | public abstract T execute() throws TaskExecutionException; 47 | 48 | protected void reset() { 49 | 50 | } 51 | 52 | protected void init() { 53 | 54 | } 55 | 56 | protected void success(T result) { 57 | 58 | } 59 | 60 | protected void fail(Throwable ex) { 61 | Exceptions.printStackTrace(ex); 62 | } 63 | 64 | protected void completed() { 65 | 66 | } 67 | 68 | protected void destroy() { 69 | 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/task/TaskExecutionException.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.task; 2 | 3 | /** 4 | * Indicates an error executing a task. 5 | * 6 | * @author Victor 7 | */ 8 | public class TaskExecutionException extends Exception{ 9 | 10 | public TaskExecutionException(Throwable cause) { 11 | super(cause); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/qubexplorer/ui/task/TaskExecutor.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.task; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | import javax.swing.SwingUtilities; 7 | import javax.swing.SwingWorker; 8 | import org.netbeans.api.progress.ProgressHandle; 9 | import org.netbeans.api.progress.ProgressHandleFactory; 10 | import org.openide.util.Exceptions; 11 | import org.openide.windows.WindowManager; 12 | import qubexplorer.UserCredentials; 13 | import qubexplorer.AuthorizationException; 14 | import qubexplorer.ResourceKey; 15 | import qubexplorer.ui.AuthDialog; 16 | import qubexplorer.ui.UserCredentialsRepository; 17 | 18 | /** 19 | * 20 | * @author Victor 21 | */ 22 | public final class TaskExecutor { 23 | 24 | private TaskExecutor() { 25 | 26 | } 27 | 28 | public static void execute(Task task) { 29 | execute(UserCredentialsRepository.getInstance(), task); 30 | } 31 | 32 | public static void execute(final UserCredentialsRepository repository, final Task task) { 33 | SwingUtilities.invokeLater(() -> { 34 | new TaskWorker<>(repository, task).execute(); 35 | }); 36 | } 37 | 38 | public static ResourceKey getResourceKey(Task task) { 39 | if (task.getProjectContext() != null && task.getProjectContext().getConfiguration() != null) { 40 | return task.getProjectContext().getConfiguration().getKey(); 41 | } 42 | return null; 43 | } 44 | 45 | private static class TaskWorker extends SwingWorker { 46 | 47 | private static final Logger LOGGER = Logger.getLogger(TaskWorker.class.getName()); 48 | 49 | private final UserCredentialsRepository userCredentialsRepository; 50 | private final Task task; 51 | private ProgressHandle handle; 52 | 53 | public TaskWorker(UserCredentialsRepository repository, Task task) { 54 | this.userCredentialsRepository = repository; 55 | this.task = task; 56 | assert SwingUtilities.isEventDispatchThread(); 57 | handle = ProgressHandle.createHandle("Sonar"); 58 | handle.start(); 59 | handle.switchToIndeterminate(); 60 | try{ 61 | this.task.init(); 62 | }catch(Throwable t){ 63 | handle.finish(); 64 | handle=null; 65 | throw t; 66 | } 67 | } 68 | 69 | @Override 70 | protected final T doInBackground() throws Exception { 71 | return task.execute(); 72 | } 73 | 74 | @Override 75 | protected final void done() { 76 | boolean willRetry = false; 77 | try { 78 | T result = get(); 79 | task.completed(); 80 | task.success(result); 81 | handle.finish(); 82 | handle = null; 83 | 84 | if (task.getUserCredentials() != null) { 85 | assert task.getServerUrl() != null; 86 | userCredentialsRepository.saveUserCredentials(task.getServerUrl(), /* XXX There was a null here */ getResourceKey(task), task.getUserCredentials()); 87 | } 88 | } catch (ExecutionException ex) { 89 | LOGGER.log(Level.INFO, ex.getMessage(), ex); 90 | handle.finish(); 91 | handle = null; 92 | Throwable cause = ex.getCause(); 93 | if (cause instanceof AuthorizationException && task.isRetryIfNoAuthorization()) { 94 | assert task.getServerUrl() != null; 95 | 96 | UserCredentials userCredentials = userCredentialsRepository.getUserCredentials(task.getServerUrl(), getResourceKey(task)); 97 | if (userCredentials == null) { 98 | userCredentials = AuthDialog.showAuthDialog(WindowManager.getDefault().getMainWindow()); 99 | } 100 | 101 | if (userCredentials != null) { 102 | willRetry = true; 103 | retryTask(userCredentials); 104 | } 105 | } else { 106 | task.completed(); 107 | task.fail(cause); 108 | } 109 | } catch (InterruptedException ex) { 110 | Exceptions.printStackTrace(ex); 111 | } finally { 112 | if (!willRetry) { 113 | task.destroy(); 114 | } 115 | if (handle != null) { 116 | handle.finish(); 117 | } 118 | } 119 | } 120 | 121 | private void retryTask(UserCredentials userCredentials) { 122 | task.reset(); 123 | task.setUserCredentials(userCredentials); 124 | TaskExecutor.execute(userCredentialsRepository, task); 125 | } 126 | 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/nbm/manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | OpenIDE-Module-Layer: qubexplorer/sonarqubeexplorer/layer.xml 3 | OpenIDE-Module-Localizing-Bundle: qubexplorer/sonarqubeexplorer/Bundle.properties 4 | OpenIDE-Module-Requires: org.openide.windows.WindowManager 5 | OpenIDE-Module-Short-Description: Sonar Plugin 6 | OpenIDE-Module-Long-Description: Sonar Plugin for Maven based projects. 7 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/server/ui/Bundle.properties: -------------------------------------------------------------------------------- 1 | ServerConnectionDialog.jLabel4.text=Password: 2 | ServerConnectionDialog.user.text= 3 | ServerConnectionDialog.jLabel3.text=User: 4 | ServerConnectionDialog.loadButton.text=Load project list... 5 | ServerConnectionDialog.okButton.text=List Issues 6 | ServerConnectionDialog.jButton1.text=Cancel 7 | ServerConnectionDialog.url.text= 8 | ServerConnectionDialog.jLabel2.text=Project: 9 | ServerConnectionDialog.credentialsWarning.text=\ \ 10 | ServerConnectionDialog.jLabel1.text=Server URL: 11 | ServerConnectionDialog.password.text= 12 | ServerConnectionDialog.title=SonarQube Server Connection 13 | ProjectChooser.loadButton.text=Load project list... 14 | ProjectChooser.okButton.text=List Issues 15 | ProjectChooser.jButton1.text=Cancel 16 | ProjectChooser.url.text= 17 | ProjectChooser.jLabel2.text=Project: 18 | ProjectChooser.jLabel1.text=Server URL: 19 | ServerConnectionDialog.jLabel5.text=Asignees 20 | ServerConnectionDialog.asigneesTextfield.text= 21 | ServerConnectionDialog.groupBySeverityButton.text=Group by severity 22 | ServerConnectionDialog.groupByTypeButton.text=Group by type 23 | SummarySettingsDialog.jLabel4.text=Password: 24 | SummarySettingsDialog.user.text= 25 | SummarySettingsDialog.jLabel3.text=User: 26 | SummarySettingsDialog.loadButton.text=Load project list... 27 | SummarySettingsDialog.okButton.text=List Issues 28 | SummarySettingsDialog.jButton1.text=Cancel 29 | SummarySettingsDialog.url.text= 30 | SummarySettingsDialog.jLabel2.text=Project: 31 | SummarySettingsDialog.credentialsWarning.text=\ \ 32 | SummarySettingsDialog.jLabel1.text=Server URL: 33 | SummarySettingsDialog.password.text= 34 | SummarySettingsDialog.title=SonarQube Server Connection 35 | SummarySettingsDialog.okButton.text=List Issues 36 | SummarySettingsDialog.groupByTypeButton.text=Group by type 37 | SummarySettingsDialog.jButton1.text=Cancel 38 | SummarySettingsDialog.groupBySeverityButton.text=Group by severity 39 | SummarySettingsDialog.jLabel5.text=Assignees 40 | SummarySettingsDialog.credentialsWarning.text=\ \ 41 | SummarySettingsDialog.assigneesTextfield.prompt=List separated by comma 42 | SummarySettingsDialog.assigneesTextfield.text= 43 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/Bundle.properties: -------------------------------------------------------------------------------- 1 | # Localized module labels. Defaults taken from POM (, , ) if unset. 2 | #OpenIDE-Module-Name= 3 | #OpenIDE-Module-Short-Description= 4 | #OpenIDE-Module-Long-Description= 5 | OpenIDE-Module-Display-Category=Java 6 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/blocker-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/critical-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/info-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/layer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/major-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/sonarqubeexplorer/minor-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/Bundle.properties: -------------------------------------------------------------------------------- 1 | SonarQubeDialog.jButton1.text=Cancel 2 | SonarQubeDialog.jButton2.text=Retrieve 3 | SonarQubeDialog.jLabel1.text=Severity 4 | SonarQubeDialog.title=SonarQube Retrieve Options 5 | AuthDialog.jLabel1.text=Name: 6 | AuthDialog.jLabel2.text=Password: 7 | AuthDialog.usernameField.text= 8 | AuthDialog.passwordField.text= 9 | AuthDialog.title=SonarQube Authentication 10 | SonarIssuesTopComponent.filterText.text= 11 | SonarIssuesTopComponent.jLabel1.text=Search: 12 | SonarIssuesTopComponent.title.text=0 Issues 13 | SonarIssuesTopComponent.jLabel3.text=Shown: 14 | SonarIssuesTopComponent.shownCount.text=0 15 | SonarIssuesTopComponent.unexistentFile.title=Warning 16 | SonarIssuesTopComponent.unexistentFile.text=File does not exist: {0} 17 | RuleCountPanel.expandButton.text=+ 18 | RuleCountPanel.totalCount.text=10 19 | RuleDialog.jLabel1.text=jLabel1 20 | SonarMainTopComponent.jButton16.text=Class with only private constructors should be final 21 | SonarMainTopComponent.jLabel6.text=657 22 | SonarMainTopComponent.jButton18.text=Critical 23 | SonarMainTopComponent.jButton17.text=- 24 | SonarMainTopComponent.jLabel5.text=75 25 | SonarMainTopComponent.jButton3.text=Avoid too complex method 26 | SonarMainTopComponent.jLabel3.text=186 27 | SonarMainTopComponent.jLabel4.text=114 28 | SonarMainTopComponent.jButton4.text=Parameter Assignment 29 | SonarMainTopComponent.jButton5.text=Security - Array is stored directly 30 | SonarMainTopComponent.jButton21.text=Security - Array is stored directly 31 | SonarMainTopComponent.jButton20.text=Parameter Assignment 32 | SonarMainTopComponent.jButton22.text=Class with only private constructors should be final 33 | SonarMainTopComponent.jButton1.text=- 34 | SonarMainTopComponent.jButton2.text=Blocker 35 | SonarMainTopComponent.jLabel1.text=657 36 | SonarMainTopComponent.jLabel2.text=323 37 | SonarMainTopComponent.jLabel12.text=323 38 | SonarMainTopComponent.jLabel13.text=186 39 | SonarMainTopComponent.jLabel14.text=114 40 | SonarMainTopComponent.jLabel15.text=75 41 | SonarMainTopComponent.jButton19.text=Avoid too complex method 42 | SonarMainTopComponent.title.text=General Info 43 | SonarMainTopComponent.jButton6.text=Total 44 | SonarMainTopComponent.totalCount.text=0 45 | SonarMainTopComponent.jButton7.text=\ 46 | SonarMainTopComponent.rulesCompliance.text=0% 47 | AuthDialog.acceptButton.text=Connect 48 | AuthDialog.cancelButton.text=Cancel 49 | RuleCountPanel.severityLabel.text=Severity 50 | RuleCountPanel.listAll.text=List Issues 51 | SonarMainTopComponent.jLabel7.text=Total 52 | SonarMainTopComponent.listAllIssues.text=List Issues 53 | RuleDialog.title=Rule Info 54 | RuleDialog.closeButton.text=Close 55 | RuleCount2.jTextField1.text=13 56 | RuleCount2.jButton1.text=List Issues 57 | RuleCount2.jTextField2.text=6 58 | RuleCount2.jXHyperlink2.text=Malicious code vulnerability - May expose internal representation by incorporating reference to mutable object 59 | RuleCount2.jButton2.text=List Issues 60 | RuleCount2.jXHyperlink3.text=Evita m\u00e9todos demasiado complejos 61 | RuleCount2.jButton3.text=List Issues 62 | RuleCount2.jTextField3.text=3 63 | RuleCount2.jXHyperlink4.text=Security - Array is stored directly 64 | RuleCount2.jButton4.text=List Issues 65 | RuleCount2.jTextField4.text=2 66 | RuleCount2.jLabel1.text=Blocker 67 | RuleCount2.jTextField5.text=1 68 | RuleCount2.jXHyperlink5.text=Dodgy - Possible null pointer dereference due to return value of called method 69 | RuleCount2.jButton5.text=List Issues 70 | RuleCount2.jXHyperlink6.text=Methods should not have too many parameters 71 | RuleCount2.jButton6.text=List Issues 72 | RuleCount2.jTextField6.text=1 73 | RuleCount2.jButton7.text=+ 74 | ProjectChooser.title=Project Chooser 75 | ProjectNotFound=Project not found with key: {0} 76 | SourcesNotFound=This project does not contain sources to analyze 77 | SonarRunner.error=Error executing sonar-runner 78 | SonarRunner.cancelled=Sonar-runner stopped 79 | SonarMainTopComponent.actionPlan.label=Action Plan: 80 | SonarMainTopComponent.actionPlansCombo.none=None 81 | SonarIssuesTopComponent.actionPlansCombo.none=None 82 | SonarIssuesTopComponent.jMenuItem1.text=List Issues 83 | SonarIssuesTopComponent.ruleInfoMenuItem.text=Show Rule Info 84 | SonarIssuesTopComponent.buttonListIssues.text= 85 | SonarIssuesTopComponent.buttonRuleInfo.text= 86 | SonarIssuesTopComponent.summaryPanel.TabConstraints.tabTitle=Summary 87 | SonarIssuesTopComponent.issuesPanel.TabConstraints.tabTitle=Issues 88 | SonarIssuesTopComponent.jMenuItem2.text=jMenuItem2 89 | SonarIssuesTopComponent.jMenuItem3.text=jMenuItem3 90 | SonarIssuesTopComponent.showEmptySeverity.text= 91 | SonarIssuesTopComponent.showEmptySeverity.toolTipText=Shows or hides severities with no issues 92 | sonarqube-info-annotation=SonarQube Issue Info 93 | sonarqube-minor-annotation=SonarQube Issue Minor 94 | sonarqube-major-annotation=SonarQube Issue Major 95 | sonarqube-critical-annotation=SonarQube Issue Critical 96 | sonarqube-blocker-annotation=SonarQube Issue Blocker 97 | RuleDialog.ruleTitle.text_1=jLabel1 98 | SonarQubeOptionsPanel.jLabel1.text=Server Url: 99 | SonarQubeOptionsPanel.tJvmArguments.prompt=Example: -Xms500m -Xmx500m (options are separated by space) 100 | SonarQubeOptionsPanel.tJvmArguments.text= 101 | SonarQubeOptionsPanel.jLabel4.text=Runner JVM Arguments: 102 | SonarQubeOptionsPanel.jLabel3.text=(Analysis mode only applies in SonarQube 4.0 and above) 103 | SonarQubeOptionsPanel.jLabel2.text=Analysis Mode for Runner: 104 | SonarQubeOptionsPanel.serverAddress.text= 105 | SonarQubeOptionsPanel.editorAnnotationsEnabled.text=Editor Annotations Enabled 106 | SonarIssuesTopComponent.jButton2.text= 107 | SonarIssuesTopComponent.summaryOptionsLabel.text=Asignees: 108 | -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/application_view_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/application_view_list.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/arrow_refresh_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/arrow_refresh_small.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/blocker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/blocker.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/critical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/critical.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/eye.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/info.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/information.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/major.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/major.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/minor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/minor.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/page_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/page_gear.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/images/stop.png -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/options/Bundle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hmvictor/radar-netbeans/194293611f23494365e9e34b59ede77ef97bc9f9/src/main/resources/qubexplorer/ui/options/Bundle.properties -------------------------------------------------------------------------------- /src/main/resources/qubexplorer/ui/summary/Bundle.properties: -------------------------------------------------------------------------------- 1 | SourcesNotFound=This project does not contain sources to analyze 2 | SonarRunner.error=Error executing sonar-runner 3 | SonarRunner.cancelled=Sonar-runner stopped -------------------------------------------------------------------------------- /src/test/java/qubexplorer/PassEncoderTest.java: -------------------------------------------------------------------------------- 1 | 2 | package qubexplorer; 3 | 4 | import static org.hamcrest.CoreMatchers.is; 5 | import org.junit.Test; 6 | import static org.junit.Assert.*; 7 | 8 | /** 9 | * 10 | * @author Victor 11 | */ 12 | public class PassEncoderTest { 13 | 14 | @Test 15 | public void testEncode() { 16 | String expected="abcde"; 17 | assertThat(PassEncoder.decodeAsString(PassEncoder.encode(expected.toCharArray())), is(expected)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/qubexplorer/ResourceKeyTest.java: -------------------------------------------------------------------------------- 1 | package qubexplorer; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | import org.junit.Test; 5 | import static org.junit.Assert.*; 6 | import org.junit.runner.RunWith; 7 | import org.junit.runners.Parameterized; 8 | 9 | /** 10 | * 11 | * @author Victor 12 | */ 13 | @RunWith(Parameterized.class) 14 | public class ResourceKeyTest { 15 | private final String first; 16 | private final String second; 17 | private final String expected; 18 | 19 | public ResourceKeyTest(String first, String second, String expected) { 20 | this.first = first; 21 | this.second = second; 22 | this.expected = expected; 23 | } 24 | 25 | @Test 26 | public void shouldBeConcatenated(){ 27 | assertThat(ResourceKey.valueOf(first).concat(ResourceKey.valueOf(second)), is(ResourceKey.valueOf(expected))); 28 | } 29 | 30 | @Parameterized.Parameters 31 | public static Object[][] getParameters(){ 32 | return new Object[][]{ 33 | {"a", "b", "a:b"}, 34 | {"a:b", "c", "a:b:c"}, 35 | {"a", "b:c", "a:b:c"} 36 | }; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/qubexplorer/runner/SonarRunnerProccessTest.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.runner; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import static org.hamcrest.CoreMatchers.is; 6 | import static org.junit.Assert.*; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.Parameterized; 10 | import qubexplorer.server.Version; 11 | 12 | /** 13 | * 14 | * @author Victor 15 | */ 16 | @RunWith(Parameterized.class) 17 | public class SonarRunnerProccessTest { 18 | 19 | private final String version; 20 | private final int expected; 21 | 22 | public SonarRunnerProccessTest(String version, int expected) { 23 | this.version = version; 24 | this.expected = expected; 25 | } 26 | 27 | @Test 28 | public void testVersion() { 29 | assertThat(new Version(version).getMajor(), is(expected)); 30 | } 31 | 32 | @Parameterized.Parameters 33 | public static List getData() { 34 | return Arrays.asList(new Object[][]{ 35 | {"3.6", 3}, 36 | {"4.0", 4}, 37 | {"4.1", 4}, 38 | {"4.5-RC3", 4} 39 | }); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/qubexplorer/server/SimpleClassifierSummaryTest.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.server; 2 | 3 | import java.util.Objects; 4 | import javax.swing.Icon; 5 | import static org.hamcrest.CoreMatchers.is; 6 | import org.junit.Test; 7 | import static org.junit.Assert.*; 8 | import org.junit.Before; 9 | import qubexplorer.Classifier; 10 | import qubexplorer.Rule; 11 | import qubexplorer.filter.IssueFilter; 12 | 13 | /** 14 | * 15 | * @author Víctor 16 | */ 17 | public class SimpleClassifierSummaryTest { 18 | 19 | private SimpleClassifierSummary summary; 20 | private MyClassifier firstClassifier; 21 | private MyClassifier secondClassifier; 22 | 23 | @Before 24 | public void init() { 25 | firstClassifier = new MyClassifier("first"); 26 | secondClassifier = new MyClassifier("second"); 27 | summary= new SimpleClassifierSummary<>(); 28 | } 29 | 30 | @Test 31 | public void shouldHaveCountByClassifier() { 32 | summary.increment(firstClassifier, new Rule("a"), 1); 33 | summary.increment(firstClassifier, new Rule("b"), 2); 34 | summary.increment(firstClassifier, new Rule("c"), 3); 35 | assertThat(summary.getCount(firstClassifier), is(6)); 36 | assertThat(summary.getCount(secondClassifier), is(0)); 37 | } 38 | 39 | @Test 40 | public void shouldHaveCountByRule() { 41 | Rule first=new Rule("first"); 42 | Rule second=new Rule("second"); 43 | summary.increment(firstClassifier, first, 1); 44 | summary.increment(firstClassifier, first, 2); 45 | summary.increment(firstClassifier, first, 3); 46 | assertThat(summary.getCount(first), is(6)); 47 | assertThat(summary.getCount(second), is(0)); 48 | } 49 | 50 | @Test 51 | public void shouldHaveTotalCount() { 52 | assertThat(summary.getCount(), is(0)); 53 | summary.increment(new MyClassifier("a"), new Rule("a"), 1); 54 | summary.increment(new MyClassifier("b"), new Rule("b"), 2); 55 | summary.increment(new MyClassifier("c"), new Rule("c"), 3); 56 | summary.increment(new MyClassifier("d"), new Rule("d"), 4); 57 | assertThat(summary.getCount(), is(10)); 58 | } 59 | 60 | public static class MyClassifier implements Classifier { 61 | private final String identifier; 62 | 63 | public MyClassifier(String identifier) { 64 | this.identifier = identifier; 65 | } 66 | 67 | @Override 68 | public IssueFilter createFilter() { 69 | throw new UnsupportedOperationException(); 70 | } 71 | 72 | @Override 73 | public int hashCode() { 74 | int hash = 7; 75 | hash = 71 * hash + Objects.hashCode(this.identifier); 76 | return hash; 77 | } 78 | 79 | @Override 80 | public boolean equals(Object obj) { 81 | if (this == obj) { 82 | return true; 83 | } 84 | if (obj == null) { 85 | return false; 86 | } 87 | if (getClass() != obj.getClass()) { 88 | return false; 89 | } 90 | final MyClassifier other = (MyClassifier) obj; 91 | if (!Objects.equals(this.identifier, other.identifier)) { 92 | return false; 93 | } 94 | return true; 95 | } 96 | 97 | @Override 98 | public Icon getIcon() { 99 | throw new UnsupportedOperationException(); 100 | } 101 | 102 | @Override 103 | public String getUserDescription() { 104 | throw new UnsupportedOperationException(); 105 | } 106 | 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/qubexplorer/server/VersionTest.java: -------------------------------------------------------------------------------- 1 | 2 | package qubexplorer.server; 3 | 4 | import static org.hamcrest.CoreMatchers.is; 5 | import static org.junit.Assert.*; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.junit.rules.ExpectedException; 9 | 10 | /** 11 | * 12 | * @author Victor 13 | */ 14 | public class VersionTest { 15 | @Rule 16 | public ExpectedException ex=ExpectedException.none(); 17 | 18 | @Test 19 | public void testWithThreeLevels() { 20 | Version version = new Version("3.7.1"); 21 | assertThat(version.getMajor(), is(3)); 22 | assertThat(version.getMinor(), is(7)); 23 | } 24 | 25 | @Test 26 | public void testWithTwoLevels() { 27 | Version version = new Version("3.7"); 28 | assertThat(version.getMajor(), is(3)); 29 | assertThat(version.getMinor(), is(7)); 30 | } 31 | 32 | @Test 33 | public void testWithOneLevel() { 34 | Version version = new Version("3"); 35 | assertThat(version.getMajor(), is(3)); 36 | } 37 | 38 | @Test 39 | public void testWithRC3() { 40 | ex.expect(IllegalArgumentException.class); 41 | Version version = new Version("4.5-RC3"); 42 | assertThat(version.getMajor(), is(4)); 43 | assertThat(version.getMinor(), is(5)); 44 | } 45 | 46 | @Test 47 | public void testCompareVersions() { 48 | assertThat(new Version("4.6").compareTo(4, 5) >= 0, is(true)); 49 | assertThat(new Version("4.5-RC3").compareTo(4, 5) >= 0, is(true)); 50 | assertThat(new Version("4.5").compareTo(4, 5) >= 0, is(true)); 51 | assertThat(new Version("4.5.1").compareTo(4, 5) >= 0, is(true)); 52 | assertThat(new Version("6.0").compareTo(4, 5) >= 0, is(true)); 53 | assertThat(new Version("6").compareTo(4, 5) >= 0, is(true)); 54 | assertThat(new Version("4.4.1").compareTo(4, 5) >= 0, is(false)); 55 | assertThat(new Version("4.4").compareTo(4, 5) >= 0, is(false)); 56 | assertThat(new Version("4.0").compareTo(4, 5) >= 0, is(false)); 57 | assertThat(new Version("4").compareTo(4, 5) >= 0, is(false)); 58 | assertThat(new Version("3.6").compareTo(4, 5) >= 0, is(false)); 59 | assertThat(new Version("3.5").compareTo(4, 5) >= 0, is(false)); 60 | 61 | assertThat(new Version("4.5.1").compareTo(5, 2) <= 0, is(true)); 62 | 63 | assertThat(new Version("4.5").compareTo(4, 5) == 0, is(true)); 64 | assertThat(new Version("4.5.1").compareTo(4, 5) == 0, is(true)); 65 | assertThat(new Version("4.6").compareTo(4, 5) > 0, is(true)); 66 | assertThat(new Version("4.6.1").compareTo(4, 5) > 0, is(true)); 67 | assertThat(new Version("4.4").compareTo(4, 5) < 0, is(true)); 68 | assertThat(new Version("4.4.1").compareTo(4, 5) < 0, is(true)); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/qubexplorer/ui/AuthenticationRepositoryTest.java: -------------------------------------------------------------------------------- 1 | 2 | package qubexplorer.ui; 3 | 4 | import org.junit.Test; 5 | import static org.junit.Assert.*; 6 | import qubexplorer.UserCredentials; 7 | import static org.hamcrest.CoreMatchers.*; 8 | import qubexplorer.ResourceKey; 9 | 10 | /** 11 | * 12 | * @author Victor 13 | */ 14 | public class AuthenticationRepositoryTest { 15 | 16 | @Test 17 | public void shouldContaintAuthentication(){ 18 | UserCredentialsRepository repo=UserCredentialsRepository.getInstance(); 19 | UserCredentials auth=new UserCredentials("one", "two".toCharArray()); 20 | repo.saveUserCredentials("url", ResourceKey.valueOf("key"), auth); 21 | assertThat(repo.getUserCredentials("url", ResourceKey.valueOf("key")), is(auth)); 22 | assertThat(repo.getUserCredentials("url", ResourceKey.valueOf("key2")), is(auth)); 23 | UserCredentials auth2=new UserCredentials("one", "two".toCharArray()); 24 | repo.saveUserCredentials("url2", null, auth2); 25 | assertThat(repo.getUserCredentials("url2", ResourceKey.valueOf("key")), is(auth2)); 26 | assertThat(repo.getUserCredentials("url2", ResourceKey.valueOf("key2")), is(auth2)); 27 | assertNull(repo.getUserCredentials("url3", ResourceKey.valueOf("key2"))); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/qubexplorer/ui/task/TaskExecutorTest.java: -------------------------------------------------------------------------------- 1 | package qubexplorer.ui.task; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import static org.mockito.Matchers.anyObject; 8 | import static org.mockito.Matchers.anyString; 9 | import static org.mockito.Matchers.isA; 10 | import org.mockito.Mock; 11 | import static org.mockito.Mockito.verify; 12 | import static org.mockito.Mockito.when; 13 | import org.mockito.Spy; 14 | import org.mockito.runners.MockitoJUnitRunner; 15 | import qubexplorer.UserCredentials; 16 | import qubexplorer.AuthorizationException; 17 | import qubexplorer.GenericSonarQubeProjectConfiguration; 18 | import qubexplorer.ResourceKey; 19 | import qubexplorer.ui.UserCredentialsRepository; 20 | import qubexplorer.ui.ProjectContext; 21 | 22 | /** 23 | * 24 | * @author Victor 25 | */ 26 | @RunWith(MockitoJUnitRunner.class) 27 | public class TaskExecutorTest { 28 | 29 | @Spy 30 | private TaskImpl task = new TaskImpl<>(new ProjectContext(null, new GenericSonarQubeProjectConfiguration("name", ResourceKey.valueOf("part1:part2"), "1.0")), "http://testhost:9000"); 31 | 32 | @Mock 33 | private UserCredentialsRepository repository; 34 | 35 | @Before 36 | public void init() { 37 | when(repository.getUserCredentials(anyString(), (ResourceKey) anyObject())).thenReturn(new UserCredentials("username", new char[0])); 38 | } 39 | 40 | @Test(timeout = 5000) 41 | public void shouldCallInit() throws Exception { 42 | when(task.execute()).thenReturn(Boolean.TRUE); 43 | TaskExecutor.execute(repository, task); 44 | task.waitForDestruction(); 45 | verify(task).init(); 46 | } 47 | 48 | @Test(timeout = 5000) 49 | public void shouldExecute() throws Exception { 50 | when(task.execute()).thenReturn(Boolean.TRUE); 51 | TaskExecutor.execute(repository, task); 52 | task.waitForDestruction(); 53 | verify(task).execute(); 54 | } 55 | 56 | @Test(timeout = 5000) 57 | public void shouldCallCompleted() throws Exception { 58 | when(task.execute()).thenReturn(Boolean.TRUE); 59 | TaskExecutor.execute(repository, task); 60 | task.waitForDestruction(); 61 | verify(task).completed(); 62 | } 63 | 64 | @Test(timeout = 5000) 65 | public void shouldCallSuccess() throws Exception { 66 | when(task.execute()).thenReturn(Boolean.TRUE); 67 | TaskExecutor.execute(repository, task); 68 | task.waitForDestruction(); 69 | verify(task).success(Boolean.TRUE); 70 | } 71 | 72 | @Test(timeout = 5000) 73 | public void shouldCallFail() throws Exception { 74 | when(task.execute()).thenThrow(new IllegalArgumentException()); 75 | TaskExecutor.execute(repository, task); 76 | task.waitForDestruction(); 77 | verify(task).fail(isA(IllegalArgumentException.class)); 78 | } 79 | 80 | @Test 81 | public void shouldCallReset() throws Exception { 82 | when(task.execute()) 83 | .thenThrow(new AuthorizationException()) 84 | .thenReturn(Boolean.TRUE); 85 | TaskExecutor.execute(repository, task); 86 | task.waitForDestruction(); 87 | verify(task).reset(); 88 | } 89 | 90 | @Test(timeout = 5000) 91 | public void shouldCallSuccessAfterAuthFailed() throws Exception { 92 | when(task.execute()) 93 | .thenThrow(new AuthorizationException()) 94 | .thenReturn(Boolean.TRUE); 95 | TaskExecutor.execute(repository, task); 96 | task.waitForDestruction(); 97 | verify(task).success(Boolean.TRUE); 98 | } 99 | 100 | @Test(timeout = 5000) 101 | public void shouldCallFailAfterAuthFailedButNoRetry() throws Exception { 102 | when(task.execute()).thenThrow(new AuthorizationException()); 103 | task.setRetryIfNoAuthorization(false); 104 | TaskExecutor.execute(repository, task); 105 | task.waitForDestruction(); 106 | verify(task).fail(isA(AuthorizationException.class)); 107 | } 108 | 109 | @Test(timeout = 5000) 110 | public void shouldCallDestroy() throws Exception { 111 | when(task.execute()).thenReturn(Boolean.TRUE); 112 | TaskExecutor.execute(repository, task); 113 | task.waitForDestruction(); 114 | verify(task).destroy(); 115 | } 116 | 117 | public static class TaskImpl extends Task { 118 | private boolean destroyed = false; 119 | private final CountDownLatch lock=new CountDownLatch(1); 120 | 121 | public TaskImpl(ProjectContext projectContext, String serverUrl) { 122 | super(projectContext, serverUrl); 123 | } 124 | 125 | @Override 126 | protected void destroy() { 127 | destroyed = true; 128 | lock.countDown(); 129 | } 130 | 131 | private void waitForDestruction(){ 132 | while(!destroyed){ 133 | try { 134 | lock.await(); 135 | } catch (InterruptedException ex) { 136 | 137 | } 138 | } 139 | } 140 | 141 | @Override 142 | public T execute() throws TaskExecutionException { 143 | return null; 144 | } 145 | 146 | } 147 | 148 | } 149 | --------------------------------------------------------------------------------