![JAR search and dependency download from the Maven repository](/logo.png)
org.sonar.plugins.openedge.foundation.OpenEdgeComponents Maven / Gradle / Ivy
/*
* OpenEdge plugin for SonarQube
* Copyright (c) 2015-2024 Riverside Software
* contact AT riverside DASH software DOT fr
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.plugins.openedge.foundation;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.prorefactor.proparse.antlr4.ProparseListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.SonarProduct;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Status;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.config.Configuration;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.MessageException;
import org.sonar.check.RuleProperty;
import org.sonar.plugins.openedge.api.CheckRegistration;
import org.sonar.plugins.openedge.api.Constants;
import org.sonar.plugins.openedge.api.InvalidLicenseException;
import org.sonar.plugins.openedge.api.LicenseRegistration;
import org.sonar.plugins.openedge.api.LicenseRegistration.License;
import org.sonar.plugins.openedge.api.LicenseRegistration.LicenseType;
import org.sonar.plugins.openedge.api.TreeParserRegistration;
import org.sonar.plugins.openedge.api.checks.OpenEdgeCheck;
import org.sonar.plugins.openedge.api.checks.OpenEdgeCheck.CheckType;
import org.sonar.plugins.openedge.api.checks.OpenEdgeDumpFileCheck;
import org.sonar.plugins.openedge.api.checks.OpenEdgeProparseCheck;
import org.sonarsource.api.sonarlint.SonarLintSide;
import com.google.common.base.Strings;
@ScannerSide
@SonarLintSide
@ServerSide
public class OpenEdgeComponents {
private static final Logger LOG = LoggerFactory.getLogger(OpenEdgeComponents.class);
private final Map ppChecksMap = new HashMap<>();
private final Map dfChecksMap = new HashMap<>();
private final Configuration config;
private final CheckRegistrar checkRegistrar = new CheckRegistrar();
private final LicenseRegistrar licenseRegistrar = new LicenseRegistrar();
private final TreeParserRegistrar parserRegistrar = new TreeParserRegistrar();
private boolean initialized = false;
private String analytics = "";
private int ncLoc = 0;
private Map> includeDependencies = new HashMap<>();
public OpenEdgeComponents() {
this(null, null, null, null);
}
public OpenEdgeComponents(Configuration config) {
this(config, null, null, null);
}
public OpenEdgeComponents(CheckRegistration[] checkRegistrars) {
this(null, checkRegistrars, null, null);
}
public OpenEdgeComponents(Configuration config, CheckRegistration[] checkRegistrars) {
this(config, checkRegistrars, null, null);
}
public OpenEdgeComponents(CheckRegistration[] checkRegistrars, LicenseRegistration[] licRegistrars) {
this(null, checkRegistrars, licRegistrars, null);
}
public OpenEdgeComponents(Configuration config, CheckRegistration[] checkRegistrars, LicenseRegistration[] licRegistrars) {
this(config, checkRegistrars, licRegistrars, null);
}
public OpenEdgeComponents(CheckRegistration[] checkRegistrars, LicenseRegistration[] licRegistrars,
TreeParserRegistration[] tpRegistrars) {
this(null, checkRegistrars, licRegistrars, tpRegistrars);
}
public OpenEdgeComponents(Configuration config, CheckRegistration[] checkRegistrars, LicenseRegistration[] licRegistrars,
TreeParserRegistration[] tpRegistrars) {
this.config = config;
if (checkRegistrars != null) {
for (CheckRegistration registration : checkRegistrars) {
registration.register(checkRegistrar);
}
}
if (licRegistrars != null) {
for (LicenseRegistration registration : licRegistrars) {
registration.register(licenseRegistrar);
}
}
if (tpRegistrars != null) {
for (TreeParserRegistration registration : tpRegistrars) {
registration.register(parserRegistrar);
}
}
}
public Iterable> getProparseListeners() {
return Collections.unmodifiableList(parserRegistrar.allListeners);
}
public Collection getLicenses() {
return licenseRegistrar.getLicenses();
}
public License getLicense(SonarProduct product, String permId, String repoName) {
return licenseRegistrar.getLicense(product, permId, repoName);
}
public void init(SensorContext context) {
if (initialized)
return;
initializeChecks(context);
initialized = true;
}
private void initializeChecks(SensorContext context) {
String permId = getServerId();
// Proparse and XREF rules
for (ActiveRule rule : context.activeRules().findByLanguage(Constants.LANGUAGE_KEY)) {
OpenEdgeCheck> lint = initializeCheck(context, rule, context.runtime().getProduct(), permId);
if ((lint != null) && (lint.getCheckType() == CheckType.PROPARSE)) {
ppChecksMap.put(rule, (OpenEdgeProparseCheck) lint);
}
}
// DB rules
for (ActiveRule rule : context.activeRules().findByLanguage(Constants.DB_LANGUAGE_KEY)) {
OpenEdgeCheck> lint = initializeCheck(context, rule, context.runtime().getProduct(), permId);
if ((lint != null) && (lint.getCheckType() == CheckType.DUMP_FILE)) {
dfChecksMap.put(rule, (OpenEdgeDumpFileCheck) lint);
}
}
}
public void setAnalytics(String analytics) {
this.analytics = analytics;
}
public String getAnalytics() {
return analytics;
}
public void setNcLoc(int ncLoc) {
this.ncLoc = ncLoc;
}
public int getNcLoc() {
return ncLoc;
}
public void addIncludeDependency(String uri, List dependencies) {
includeDependencies.put(uri, dependencies);
}
public List getIncludeDependencies(String uri) {
return includeDependencies.getOrDefault(uri, Arrays.asList());
}
/**
* Return true if main file or one of its include files has changed
*/
public boolean isChanged(SensorContext context, InputFile file) {
if ((file.status() == Status.ADDED) || (file.status() == Status.CHANGED))
return true;
for (String str : getIncludeDependencies(file.uri().toString())) {
InputFile target = context.fileSystem().inputFile(context.fileSystem().predicates().hasRelativePath(str));
if ((target != null) && ((target.status() == Status.ADDED) || (target.status() == Status.CHANGED)))
return true;
}
return false;
}
public Map getProparseRules() {
return Collections.unmodifiableMap(ppChecksMap);
}
public Map getDumpFileRules() {
return Collections.unmodifiableMap(dfChecksMap);
}
private OpenEdgeCheck> initializeCheck(SensorContext context, ActiveRule rule, SonarProduct product,
String permId) {
RuleKey ruleKey = rule.ruleKey();
// AFAIK, no way to be sure if a rule is based on a template or not
String clsName = rule.templateRuleKey() == null ? ruleKey.rule() : rule.templateRuleKey();
try {
Class extends OpenEdgeCheck>> clz = checkRegistrar.getCheck(clsName);
if (clz == null)
return null;
OpenEdgeCheck> check = clz.getConstructor().newInstance();
check.setContext(ruleKey, context, getLicense(product, permId, ruleKey.repository()));
configureFields(rule, check);
check.initialize();
return check;
} catch (ReflectiveOperationException caught) {
LOG.error("Unable to instantiate rule " + clsName, caught);
throw new RuntimeException("Stopping analyzer due to previous exception");
} catch (InvalidLicenseException caught) {
LOG.error("Unable to instantiate rule {} - {}", clsName, caught.getMessage());
throw new RuntimeException("Stopping analyzer due to previous exception");
}
}
private static void configureFields(ActiveRule activeRule, Object check) {
for (String param : activeRule.params().keySet()) {
Field field = getField(check, param);
if (field == null) {
throw MessageException.of("The field " + param
+ " does not exist or is not annotated with @RuleProperty in the class " + check.getClass().getName());
}
if (Strings.nullToEmpty(activeRule.param(param)).trim().length() > 0) {
configureField(check, field, activeRule.param(param));
}
}
}
private static void configureField(Object check, Field field, String value) {
try {
field.setAccessible(true);
if (field.getType().equals(String.class)) {
field.set(check, value);
} else if (int.class == field.getType()) {
field.setInt(check, Integer.parseInt(value));
} else if (short.class == field.getType()) {
field.setShort(check, Short.parseShort(value));
} else if (long.class == field.getType()) {
field.setLong(check, Long.parseLong(value));
} else if (double.class == field.getType()) {
field.setDouble(check, Double.parseDouble(value));
} else if (boolean.class == field.getType()) {
field.setBoolean(check, Boolean.parseBoolean(value));
} else if (byte.class == field.getType()) {
field.setByte(check, Byte.parseByte(value));
} else if (Integer.class == field.getType()) {
field.set(check, Integer.parseInt(value));
} else if (Long.class == field.getType()) {
field.set(check, Long.parseLong(value));
} else if (Double.class == field.getType()) {
field.set(check, Double.parseDouble(value));
} else if (Boolean.class == field.getType()) {
field.set(check, Boolean.parseBoolean(value));
} else {
throw MessageException.of("The type of the field " + field + " is not supported: " + field.getType());
}
} catch (IllegalAccessException e) {
throw MessageException.of(
"Can not set the value of the field " + field + " in the class: " + check.getClass().getName(), e);
}
}
private static Field getField(Object check, String key) {
Field[] fields = check.getClass().getDeclaredFields();
for (Field field : fields) {
RuleProperty propertyAnnotation = field.getAnnotation(RuleProperty.class);
if ((propertyAnnotation != null) && (key.equals(field.getName()) || key.equals(propertyAnnotation.key()))) {
return field;
}
}
return null;
}
public String getServerId() {
return config == null ? "" : config.get(CoreProperties.SERVER_ID).orElse("");
}
private static class LicenseRegistrar implements LicenseRegistration.Registrar {
private final Collection licenses = new ArrayList<>();
@Override
public void registerLicense(int version, String permanentId, SonarProduct product, String customerName, String salt,
String repoName, LicenseRegistration.LicenseType type, byte[] signature, long expirationDate, long lines) {
if (Strings.isNullOrEmpty(repoName))
return;
LOG.debug("Found {} license - Permanent ID '{}' - Customer '{}' - Repository '{}' - Expiration date {}",
type.toString(), permanentId, customerName, repoName,
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date(expirationDate)));
// Only one license per product/ repository / permID
License existingLic = hasRegisteredLicense(product, repoName, permanentId);
License newLic = new License.Builder().setVersion(version).setPermanentId(permanentId).setProduct(
product).setCustomerName(customerName).setSalt(salt).setRepositoryName(repoName).setType(type).setSignature(
signature).setExpirationDate(expirationDate).setLines(lines).build();
if (existingLic == null) {
licenses.add(newLic);
} else if (existingLic.getExpirationDate() < newLic.getExpirationDate()) {
licenses.remove(existingLic);
licenses.add(newLic);
}
}
private Collection getLicenses() {
return licenses;
}
private License hasRegisteredLicense(SonarProduct product, String repoName, String permId) {
if ((permId == null) || (repoName == null))
return null;
for (License lic : licenses) {
if (((lic.getType() == LicenseType.COMMERCIAL) || (lic.getType() == LicenseType.PARTNER))
&& (lic.getProduct() == product) && repoName.equals(lic.getRepositoryName())
&& permId.equals(lic.getPermanentId()))
return lic;
}
return null;
}
private License getLicense(SonarProduct product, String permId, String repoName) {
if ((permId == null) || (repoName == null))
return null;
// TODO Remove this code when old licenses are not used anymore
String miniPermId = (permId.indexOf('-') == 8) && (permId.length() >= 20)
? permId.substring(permId.indexOf('-') + 1) : permId;
Optional srch = licenses.stream() //
.filter(lic -> (lic.getType() == LicenseType.COMMERCIAL) || (lic.getType() == LicenseType.PARTNER)) //
.filter(lic -> lic.getProduct() == product) //
.filter(lic -> repoName.equals(lic.getRepositoryName())) //
.filter(lic -> (lic.getVersion() >= 3 && permId.equals(lic.getPermanentId()))
|| miniPermId.equals(lic.getPermanentId())).findFirst();
if (srch.isPresent())
return srch.get();
srch = licenses.stream() //
.filter(lic -> lic.getType() == LicenseType.EVALUATION) //
.filter(lic -> lic.getProduct() == product) //
.filter(lic -> repoName.equals(lic.getRepositoryName())) //
.filter(lic -> (lic.getVersion() >= 3 && permId.equals(lic.getPermanentId()))
|| miniPermId.equals(lic.getPermanentId())).findFirst();
if (srch.isPresent())
return srch.get();
return null;
}
}
private static class CheckRegistrar implements CheckRegistration.Registrar {
private final Collection>> allChecks = new ArrayList<>();
@Override
public void registerParserCheck(Class extends OpenEdgeProparseCheck> check) {
allChecks.add(check);
}
@Override
public void registerDumpFileCheck(Class extends OpenEdgeDumpFileCheck> check) {
allChecks.add(check);
}
public Class extends OpenEdgeCheck>> getCheck(String className) {
for (Class extends OpenEdgeCheck>> clz : allChecks) {
if (clz.getCanonicalName().equalsIgnoreCase(className)) {
return clz;
}
}
return null;
}
}
private static class TreeParserRegistrar implements TreeParserRegistration.Registrar {
private final List> allListeners = new ArrayList<>();
@Override
public void registerTreeParser(Class extends ProparseListener> listener) {
allListeners.add(listener);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy