Qualitätsregeln für benutzerspezifischen Code

Diese Seite beschreibt die Qualitätsregeln für benutzerspezifischen Code, die von Cloud Manager im Rahmen der Code-Qualitätstests ausgeführt werden. Sie basieren auf Best Practices von AEM Engineering.

HINWEIS

Die hier bereitgestellten Code-Beispiele dienen nur Veranschaulichungszwecken. Siehe SonarQube Dokumentation zu Konzepten , um mehr über SonarQube-Konzepte und -Qualitätsregeln zu erfahren.

SonarQube-Regeln

Im folgenden Abschnitt werden die SonarQube-Regeln beschrieben, die von Cloud Manager ausgeführt werden.

Verwenden Sie keine potenziell gefährlichen Funktionen

  • Schlüssel: CQRules:CWE-676
  • Typ: Sicherheitslücke
  • Schweregrad: Hoch
  • Seit: Version 2018.4.0

Die Methoden Thread.stop() und Thread.interrupt() können schwer zu reproduzierende Probleme und in einigen Fällen Sicherheitslücken verursachen. Daher sollte deren Verwendung sorgfältig überwacht und validiert werden. Im Allgemeinen ist die Nachrichtenübergabe eine sicherere Möglichkeit, ähnliche Ziele zu erreichen.

Nicht konformer Code

public class DontDoThis implements Runnable {
  private Thread thread;

  public void start() {
    thread = new Thread(this);
    thread.start();
  }

  public void stop() {
    thread.stop();  // UNSAFE!
  }

  public void run() {
    while (true) {
        somethingWhichTakesAWhileToDo();
    }
  }
}

Konformer Code

public class DoThis implements Runnable {
  private Thread thread;
  private boolean keepGoing = true;

  public void start() {
    thread = new Thread(this);
    thread.start();
  }

  public void stop() {
    keepGoing = false;
  }

  public void run() {
    while (this.keepGoing) {
        somethingWhichTakesAWhileToDo();
    }
  }
}

Verwenden Sie keine Formatzeichenfolgen, die möglicherweise extern kontrolliert werden

  • Schlüssel: CQRules:CWE-134
  • Typ: Sicherheitslücke
  • Schweregrad: Hoch
  • Seit: Version 2018.4.0

Durch die Verwendung einer Formatzeichenfolge aus einer externen Quelle (z. B. einem Anbfrageparameter oder benutzergenerierten Inhalten) kann ein Programm für Denial-of-Service-Angriffe anfällig werden. Es gibt Fälle, in denen eine Formatzeichenfolge von außen gesteuert werden kann, jedoch nur aus vertrauenswürdigen Quellen zulässig ist.

Nicht konformer Code

protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) {
  String messageFormat = request.getParameter("messageFormat");
  request.getResource().getValueMap().put("some property", String.format(messageFormat, "some text"));
  response.sendStatus(HttpServletResponse.SC_OK);
}

HTTP-Anfragen sollten immer Zeitüberschreitungswerte für Sockets und Verbindungen enthalten.

  • Schlüssel: CQRules:ConnectionTimeoutMechanism
  • Typ: Fehler
  • Schweregrad: Kritisch
  • Seit: Version 2018.6.0

Beim Ausführen von HTTP-Anfragen aus einem AEM-Programm muss unbedingt sichergestellt sein, dass korrekte Zeitüberschreitungswerte konfiguriert werden, um unnötige Thread-Nutzung zu vermeiden. Leider ist das Standardverhalten des standardmäßigen HTTP-Clients (java.net.HttpUrlConnection) und der häufig verwendete Apache HTTP Components-Client darf niemals eine Zeitüberschreitung bewirken. Daher müssen Timeouts explizit festgelegt werden. Als Best Practice gilt, diese Zeitüberschreitungen bei maximal 60 Sekunden zu definieren.

Nicht konformer Code

@Reference
private HttpClientBuilderFactory httpClientBuilderFactory;

public void dontDoThis() {
  HttpClientBuilder builder = httpClientBuilderFactory.newBuilder();
  HttpClient httpClient = builder.build();

  // do something with the client
}

public void dontDoThisEither() {
  URL url = new URL("http://www.google.com");
  URLConnection urlConnection = url.openConnection();

  BufferedReader in = new BufferedReader(new InputStreamReader(
    urlConnection.getInputStream()));

  String inputLine;
  while ((inputLine = in.readLine()) != null) {
    logger.info(inputLine);
  }

  in.close();
}

Konformer Code

@Reference
private HttpClientBuilderFactory httpClientBuilderFactory;

public void doThis() {
  HttpClientBuilder builder = httpClientBuilderFactory.newBuilder();
  RequestConfig requestConfig = RequestConfig.custom()
    .setConnectTimeout(5000)
    .setSocketTimeout(5000)
    .build();
  builder.setDefaultRequestConfig(requestConfig);

  HttpClient httpClient = builder.build();

  // do something with the client
}

public void orDoThis() {
  URL url = new URL("http://www.google.com");
  URLConnection urlConnection = url.openConnection();
  urlConnection.setConnectTimeout(5000);
  urlConnection.setReadTimeout(5000);

  BufferedReader in = new BufferedReader(new InputStreamReader(
    urlConnection.getInputStream()));

  String inputLine;
  while ((inputLine = in.readLine()) != null) {
    logger.info(inputLine);
  }

  in.close();
}

ResourceResolver-Objekte sollten immer geschlossen werden

  • Schlüssel: CQRules:CQBP-72
  • Typ: Code Smell
  • Schweregrad: Hoch
  • Seit: Version 2018.4.0

ResourceResolver-Objekte, die aus ResourceResolverFactory abgerufen werden, verbrauchen Systemressourcen. Obwohl es Möglichkeiten gibt, diese Ressourcen freizugeben, wenn ein ResourceResolver nicht mehr verwendet wird, ist es effizienter, alle offenen ResourceResolver-Objekte explizit durch Aufruf der Methode close() zu schließen.

Ein relativ häufiges Missverständnis ist, dass ResourceResolver Objekte, die mit einer vorhandenen JCR-Sitzung erstellt wurden, sollten nicht explizit geschlossen werden. Andernfalls wird die zugrunde liegende JCR-Sitzung geschlossen. Dies ist nicht der Fall. Gleichgültig, wie ein ResourceResolver geöffnet wird, sollte es geschlossen werden, wenn es nicht mehr benötigt wird. Da ResourceResolver die Closeable-Schnittstelle implementiert, kann auch die Syntax try-with-resources statt eines expliziten Aufrufs von close() verwendet werden.

Nicht konformer Code

public void dontDoThis(Session session) throws Exception {
  ResourceResolver resolver = factory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object)session));
  // do some stuff with the resolver
}

Konformer Code

public void doThis(Session session) throws Exception {
  ResourceResolver resolver = null;
  try {
    resolver = factory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object)session));
    // do something with the resolver
  } finally {
    if (resolver != null) {
      resolver.close();
    }
  }
}

public void orDoThis(Session session) throws Exception {
  try (ResourceResolver resolver = factory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object) session))){
    // do something with the resolver
  }
}

Verwenden Sie keine Sling-Servlet-Pfade zum Registrieren von Servlets

  • Schlüssel: CQRules:CQBP-75
  • Typ: Code Smell
  • Schweregrad: Hoch
  • Seit: Version 2018.4.0

Wie in der Sling-Dokumentation beschrieben, sollten Servlets nicht über Pfade verknüpft werden. Pfadgebundene Servlets können keine standardmäßigen JCR-Zugriffssteuerungselemente verwenden, sodass besonders strenge Sicherheitsmaßnahmen erforderlich sind. Statt pfadgebundene Servlets zu verwenden, wird empfohlen, Knoten im Repository zu erstellen und Servlets nach Ressourcentyp zu registrieren.

Nicht konformer Code

@Component(property = {
  "sling.servlet.paths=/apps/myco/endpoint"
})
public class DontDoThis extends SlingAllMethodsServlet {
 // implementation
}

Ausnahmefehler sollten protokolliert oder ausgegeben werden, nicht beide

  • Schlüssel: CQRules:CQBP-44—CatchAndEitherLogOrThrow
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Im Allgemeinen sollte eine Ausnahme genau einmal protokolliert werden. Die mehrfache Protokollierung von Ausnahmen kann verwirren, da unklar ist, wie oft eine Ausnahme aufgetreten ist. Dies wird vor allem dadurch verursacht, dass eine erfasste Ausnahme sowohl protokolliert als auch ausgegeben wird.

Nicht konformer Code

public void dontDoThis() throws Exception {
  try {
    someOperation();
  } catch (Exception e) {
    logger.error("something went wrong", e);
    throw e;
  }
}

Konformer Code

public void doThis() {
  try {
    someOperation();
  } catch (Exception e) {
    logger.error("something went wrong", e);
  }
}

public void orDoThis() throws MyCustomException {
  try {
    someOperation();
  } catch (Exception e) {
    throw new MyCustomException(e);
  }
}

Vermeiden Sie Protokollanweisungen, die unmittelbar auf eine Throw-Anweisung folgen

  • Schlüssel: CQRules:CQBP-44—ConsecutivelyLogAndThrow
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Ein weiteres gängiges Muster, das vermieden werden sollte, ist die Protokollierung einer Nachricht, direkt gefolgt von der Auslösung einer Ausnahme. Dadurch erscheint die Ausnahmemeldung in Protokolldateien meist doppelt.

Nicht konformer Code

public void dontDoThis() throws Exception {
  logger.error("something went wrong");
  throw new RuntimeException("something went wrong");
}

Konformer Code

public void doThis() throws Exception {
  throw new RuntimeException("something went wrong");
}

Vermeiden Sie beim Verarbeiten von GET- oder HEAD-Anforderungen die Protokollierung bei INFO

  • Schlüssel: CQRules:CQBP-44—LogInfoInGetOrHeadRequests
  • Typ: Code Smell
  • Schweregrad: Gering

Im Allgemeinen sollten mit der Protokollierungsstufe INFO wichtige Aktionen abgegrenzt werden. Standardmäßig ist AEM so konfiguriert, dass auf der INFO-Ebene oder höher protokolliert wird. GET- und HEAD-Methoden sollten nur schreibgeschützte Vorgänge sein und stellen daher keine wichtigen Aktionen dar. Die Protokollierung auf INFO-Ebene als Antwort auf GET- oder HEAD-Anfragen füllt das Protokoll wahrscheinlich mit erheblichen Mengen überflüssiger Informationen, sodass es schwieriger wird, nützliche Informationen in Protokolldateien zu finden. Bei der Verarbeitung von GET- oder HEAD-Anfragen sollte die Protokollierung entweder bei einem Fehler auf WARN- oder ERROR-Ebene erfolgen oder auf DEBUG- oder TRACE-Ebene, wenn eine tiefgehendere Fehlerbehebung hilfreich wäre.

HINWEIS

Dies gilt nicht für access.log-type-Protokollierung für jede Anfrage.

Nicht konformer Code

public void doGet() throws Exception {
  logger.info("handling a request from the user");
}

Konformer Code

public void doGet() throws Exception {
  logger.debug("handling a request from the user.");
}

Verwenden Sie Exception.getMessage() nicht als ersten Parameter einer Protokollierungsanweisung

  • Schlüssel: CQRules:CQBP-44—ExceptionGetMessageIsFirstLogParam
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Als Best Practice sollten Protokollmeldungen kontextbezogene Informationen darüber enthalten, wo eine Programmausnahme aufgetreten ist. Während der Kontext auch mit Stacktraces bestimmt werden kann, ist die Protokollmeldung meist besser lesbar und verständlicher. Wenn Sie eine Ausnahme protokollieren, ist es daher nicht empfehlenswert, die Ausnahmemeldung als Protokollmeldung zu verwenden. Die Ausnahmemeldung enthält Informationen dazu, was nicht funktioniert hat, während die Protokollmeldung dem Protokollleser mitteilt, was das Programm getan hat, als die Ausnahme auftrat. Die Ausnahmemeldung wird weiterhin protokolliert. Durch die Angabe Ihrer eigenen Nachricht werden die Logs einfach verständlicher.

Nicht konformer Code

public void dontDoThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    logger.error(e.getMessage(), e);
  }
}

Konformer Code

public void doThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    logger.error("Unable to do something", e);
  }
}

Die Protokollierung in Catch-Blöcken sollte auf WARN- oder ERROR-Ebene erfolgen

  • Schlüssel: CQRules:CQBP-44—WrongLogLevelInCatchBlock
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Wie der schon Name sagt, sollten Java-Ausnahmen immer unter Ausnahmebedingungen verwendet werden. Wenn eine Ausnahme erfasst wird, muss daher sichergestellt werden, dass Protokollmeldungen auf der entsprechenden Ebene protokolliert werden, entweder WARN oder ERROR. damit diese Meldungen in den Protokollen korrekt angezeigt werden.

Nicht konformer Code

public void dontDoThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    logger.debug(e.getMessage(), e);
  }
}

Konformer Code

public void doThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    logger.error("Unable to do something", e);
  }
}

Drucken Sie keine Stacktraces in der Konsole

  • Schlüssel: CQRules:CQBP-44—ExceptionPrintStackTrace
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Wie bereits erwähnt, ist Kontext beim Verständnis von Protokollmeldungen äußerst wichtig. Durch Verwendung von Exception.printStackTrace() wird bei der Ausgabe des Standardfehler-Streams nur der Stacktrace ausgegeben, sodass der gesamte Kontext verloren geht. Wenn in einer Multi-Thread-Anwendung wie AEM mehrere Ausnahmen parallel mit dieser Methode gedruckt werden, können sich ihre Stacktraces überschneiden, was erhebliche Verwirrung verursacht. Ausnahmen sollten daher nur über das Protokollierungs-Framework protokolliert werden.

Nicht konformer Code

public void dontDoThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    e.printStackTrace();
  }
}

Konformer Code

public void doThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    logger.error("Unable to do something", e);
  }
}

Verzichten Sie auf Ausgaben als Standardausgabe oder Standardfehler

  • Schlüssel: CQRules:CQBP-44—LogLevelConsolePrinters
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Die Anmeldung in AEM sollte immer über das Protokollierungs-Framework (SLF4J) erfolgen. Durch die direkte Ausgabe an Standardausgabe- oder Standardfehler-Streams gehen strukturelle und kontextbezogene Informationen verloren, die vom Protokollierungs-Framework bereitgestellt werden. Außerdem kann diese Vorgehensweise in einigen Fällen zu Leistungseinbußen führen.

Nicht konformer Code

public void dontDoThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    System.err.println("Unable to do something");
  }
}

Konformer Code

public void doThis() {
  try {
    someMethodThrowingAnException();
  } catch (Exception e) {
    logger.error("Unable to do something", e);
  }
}

Vermeiden Sie hartcodierte /apps- und /libs-Pfade

  • Schlüssel: CQRules:CQBP-71
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2018.4.0

Im Allgemeinen beginnen Pfade mit /libs und /apps sollten nicht fest codiert werden, da die Pfade, auf die sie verweisen, am häufigsten als Pfade relativ zum Sling-Suchpfad gespeichert werden, der auf /libs,/apps Standardmäßig. Durch die Angabe des absoluten Pfads können geringfügige Fehler entstehen, die erst später im Projektlebenszyklus deutlich werden.

Nicht konformer Code

public boolean dontDoThis(Resource resource) {
  return resource.isResourceType("/libs/foundation/components/text");
}

Konformer Code

public void doThis(Resource resource) {
  return resource.isResourceType("foundation/components/text");
}

Sling-Planung sollte nicht verwendet werden

  • Schlüssel: CQRules:AMSCORE-554
  • Typ: Code Smell/Cloud Service-Kompatibilität
  • Schweregrad: Gering
  • Seit: Version 2020.5.0

Die Sling-Planung darf nicht für Aufgaben verwendet werden, die eine garantierte Ausführung erfordern. Über Sling geplante Aufträge garantieren die Ausführung und eignen sich besser für Umgebungen mit und ohne Cluster.

Weitere Informationen zum Umgang mit Sling-Aufträgen in einer Umgebung mit Clustern finden Sie unter Apache Sling Eventing und Job Handling.

AEM veraltete APIs sollten nicht verwendet werden

  • Schlüssel: AMSCORE-553
  • Typ: Code Smell/Cloud Service-Kompatibilität
  • Schweregrad: Gering
  • Seit: Version 2020.5.0

Die AEM-API-Oberfläche wird ständig überarbeitet, um APIs zu identifizieren, von deren Verwendung abgeraten wird und die daher als veraltet gelten.

In vielen Fällen werden diese APIs mithilfe des standardmäßigen Java-Codes nicht mehr unterstützt @Deprecated -Anmerkung und als solche, wie durch squid:CallToDeprecatedMethod.

Es gibt jedoch Fälle, in denen eine API im Kontext von AEM veraltet ist, in anderen Kontexten jedoch nicht. Diese Regel identifiziert diese zweite Klasse.

OakPAL-Inhaltsregeln

Im folgenden Abschnitt werden die von Cloud Manager durchgeführten OakPAL-Prüfungen vorgestellt.

HINWEIS

OakPAL ist ein Framework, das Inhaltspakete mit einem eigenständigen Oak-Repository validiert. Es wurde von einem AEM Partner entwickelt, der mit dem 2019 AEM Rockstar North America Award ausgezeichnet wurde.

Produkt-APIs, die mit @ProviderType kommentiert wurden, sollten von Kunden nicht implementiert oder erweitert werden

  • Schlüssel: CQBP-84
  • Typ: Fehler
  • Schweregrad: Kritisch
  • Seit: Version 2018.7.0

Die AEM-API enthält Java-Schnittstellen und -Klassen, die durch benutzerdefinierten Code lediglich verwendet, aber nicht implementiert werden sollen. Zum Beispiel ist die Schnittstelle com.day.cq.wcm.api.Page nur für die Implementierung durch AEM vorgesehen.

Wenn zu diesen Schnittstellen neue Methoden hinzugefügt werden, wirken sich diese zusätzlichen Methoden nicht auf den vorhandenen Code aus, der diese Schnittstellen verwendet. Daher wird das Hinzufügen neuer Methoden zu diesen Schnittstellen als abwärtskompatibel betrachtet. Wenn jedoch benutzerdefinierter Code eine dieser Schnittstellen implementiert, führt dieser benutzerspezifische Code ein Abwärtskompatibilitätsrisiko für den Kunden ein.

Schnittstellen und Klassen, die nur von AEM implementiert werden sollen, werden mit org.osgi.annotation.versioning.ProviderType oder in einigen Fällen eine ähnliche Legacy-Anmerkung aQute.bnd.annotation.ProviderType. Diese Regel identifiziert die Fälle, in denen eine solche Schnittstelle durch benutzerdefinierten Code implementiert wird (oder eine Klasse erweitert wird).

Nicht konformer Code

import com.day.cq.wcm.api.Page;

public class DontDoThis implements Page {
// implementation here
}

Benutzerdefinierte Lucene-Oak-Indizes müssen über eine Tika-Konfiguration verfügen.

  • Schlüssel: IndexTikaNode
  • Typ: Fehler
  • Schweregrad: Blocker
  • Seit: 2021.8.0

Mehrere vordefinierte AEM Oak-Indizes enthalten eine Tika-Konfiguration und Anpassungen dieser Indizes müssen eine Tika-Konfiguration enthalten. Diese Regel überprüft auf Anpassungen der Indizes damAssetLucene, lucene und graphqlConfig und löst ein Problem aus, wenn entweder der Knoten tika fehlt oder wenn im Knoten tika ein untergeordneter Knoten mit dem Namen config.xml fehlt.

Siehe Abschnitt Indizierungsdokumentation Weitere Informationen zum Anpassen von Indexdefinitionen.

Nicht konformer Code

+ oak:index
    + damAssetLucene-1-custom
      - async: [async]
      - evaluatePathRestrictions: true
      - includedPaths: /content/dam
      - reindex: false
      - tags: [visualSimilaritySearch]
      - type: lucene

Konformer Code

+ oak:index
    + damAssetLucene-1-custom-2
      - async: [async]
      - evaluatePathRestrictions: true
      - includedPaths: /content/dam
      - reindex: false
      - tags: [visualSimilaritySearch]
      - type: lucene
      + tika
        + config.xml

Benutzerdefinierte Lucene-Oak-Indizes dürfen nicht synchron sein

  • Schlüssel: IndexAsyncProperty
  • Typ: Fehler
  • Schweregrad: Blocker
  • Seit: 2021.8.0

Oak-Indizes des Typs lucene muss immer asynchron indiziert sein. Andernfalls kann es zu einer Instabilität des Systems kommen. Weitere Informationen zur Struktur von Lucene-Indizes finden Sie in der Dokumentation zu Oak.

Nicht konformer Code

+ oak:index
    + damAssetLucene-1-custom
      - evaluatePathRestrictions: true
      - includedPaths: /content/dam
      - reindex: false
      - type: lucene
      - reindex: false
      - tags: [visualSimilaritySearch]
      - type: lucene
      + tika
        + config.xml

Konformer Code

+ oak:index
    + damAssetLucene-1-custom-2
      - async: [async]
      - evaluatePathRestrictions: true
      - includedPaths: /content/dam
      - reindex: false
      - tags: [visualSimilaritySearch]
      - type: lucene
      + tika
        + config.xml

Benutzerdefinierte DAM Asset Lucene Oak-Indizes sind ordnungsgemäß strukturiert

  • Schlüssel: IndexDamAssetLucene
  • Typ: Fehler
  • Schweregrad: Blocker
  • Seit: 2021.6.0

Damit die Asset-Suche in AEM Assets ordnungsgemäß funktioniert, müssen die Anpassungen des damAssetLucene-Oak-Index einem Satz von Richtlinien entsprechen, die für diesen Index spezifisch sind. Diese Regel überprüft, ob die Indexdefinition eine Eigenschaft mit mehreren Werten mit dem Namen tags , der den Wert enthält visualSimilaritySearch.

Nicht konformer Code

+ oak:index
    + damAssetLucene-1-custom
      - async: [async, nrt]
      - evaluatePathRestrictions: true
      - includedPaths: /content/dam
      - reindex: false
      - type: lucene
      + tika
        + config.xml

Konformer Code

+ oak:index
    + damAssetLucene-1-custom-2
      - async: [async, nrt]
      - evaluatePathRestrictions: true
      - includedPaths: /content/dam
      - reindex: false
      - tags: [visualSimilaritySearch]
      - type: lucene
      + tika
        + config.xml

Kundenpakete sollten keine Knoten unter /libs erstellen oder ändern

  • Schlüssel: BannedPath
  • Typ: Fehler
  • Schweregrad: Kritisch
  • Seit: Version 2019.6.0

Es ist eine lange bestehende Best Practice, dass die Inhaltsstruktur /libs im AEM-Inhalts-Repository von Kunden als schreibgeschützt betrachtet werden sollte. Das Ändern von Knoten und Eigenschaften unter /libs ist mit erheblichen Risiken für umfassende und kleinere Aktualisierungen verbunden. Änderungen an /libs sollten nur durch Adobe über offizielle Kanäle vorgenommen werden.

Pakete dürfen keine doppelten OSGi-Konfigurationen enthalten

  • Schlüssel: DuplicateOsgiConfigurations
  • Typ: Fehler
  • Schweregrad: Hoch
  • Seit: Version 2019.6.0

Ein häufig auftretendes Problem bei komplexen Projekten besteht darin, dass dieselbe OSGi-Komponente mehrmals konfiguriert ist. Dadurch entsteht eine Unklarheit darüber, welche Konfiguration anwendbar sein wird. Diese Regel ist „Laufzeitmodus-fokussiert“, da sie nur Probleme erkennt, bei denen dieselbe Komponente mehrmals im gleichen Laufzeitmodus (oder mit der gleichen Kombination aus Laufzeitmodi) konfiguriert ist.

HINWEIS

Diese Regel führt zu Problemen, wenn dieselbe Konfiguration unter demselben Pfad in mehreren Paketen definiert ist, einschließlich der Fälle, in denen dasselbe Paket in der Gesamtliste der erstellten Pakete dupliziert ist.

Wenn der Build zum Beispiel Pakete mit den Namen com.myco:com.myco.ui.apps und com.myco:com.myco.all erstellt, wobei com.myco:com.myco.all com.myco:com.myco.ui.apps einbettet, werden alle Konfigurationen innerhalb von com.myco:com.myco.ui.apps als Duplikat gemeldet.

Dies ist im Allgemeinen der Fall, dass die Richtlinien für die Inhaltspaketstruktur.. In diesem speziellen Beispiel wird das -Paket com.myco:com.myco.ui.apps fehlt die <cloudManagerTarget>none</cloudManagerTarget> -Eigenschaft.

Nicht konformer Code

+ apps
  + projectA
    + config
      + com.day.cq.commons.impl.ExternalizerImpl
  + projectB
    + config
      + com.day.cq.commons.impl.ExternalizerImpl

Konformer Code

+ apps
  + shared-config
    + config
      + com.day.cq.commons.impl.ExternalizerImpl

Konfigurationen und Installationsordner dürfen nur OSGi-Knoten enthalten

  • Schlüssel: ConfigAndInstallShouldOnlyContainOsgiNodes
  • Typ: Fehler
  • Schweregrad: Hoch
  • Seit: Version 2019.6.0

Aus Sicherheitsgründen sind Pfade, die /config/ und /install/ enthalten, nur von Administratoranwendern in AEM lesbar und sollten nur für OSGi-Konfigurationen und OSGi-Bundles verwendet werden. Das Platzieren anderer Inhaltstypen in Pfade mit diesen Segmenten führt dazu, dass sich das Programm abhängig davon anders verhält, ob sie von Administratoren- oder Nicht-Administratoren verwendet wird.

Ein häufig auftretendes Problem ist die Verwendung von Knoten mit der Bezeichnung config in Komponentendialogfeldern oder beim Angeben der Rich-Text-Editor-Konfiguration für die Inline-Bearbeitung. Um dies zu beheben, sollte der fehlerhafte Knoten in einen kompatiblen Namen umbenannt werden. Nutzen Sie bei der Rich-Text-Editor-Konfiguration die Eigenschaft configPath im Knoten cq:inplaceEditing, um den neuen Speicherort anzugeben.

Nicht konformer Code

+ cq:editConfig [cq:EditConfig]
  + cq:inplaceEditing [cq:InplaceEditConfig]
    + config [nt:unstructured]
      + rtePlugins [nt:unstructured]

Konformer Code

+ cq:editConfig [cq:EditConfig]
  + cq:inplaceEditing [cq:InplaceEditConfig]
    ./configPath = inplaceEditingConfig (String)
    + inplaceEditingConfig [nt:unstructured]
      + rtePlugins [nt:unstructured]

Pakete sollten nicht überlappen

  • Schlüssel: PackageOverlaps
  • Typ: Fehler
  • Schweregrad: Hoch
  • Seit: Version 2019.6.0

Ähnlich wie bei der Regel Pakete dürfen keine doppelten OSGi-Konfigurationen enthalten ist dies ein häufiges Problem bei komplexen Projekten, bei denen mehrere separate Inhaltspakete in denselben Knotenpfad schreiben. Mit Inhaltspaketabhängigkeiten kann zwar ein konsistentes Ergebnis sichergestellt werden, Überlappungen sollten aber dennoch von vorneherein vermieden werden.

Der standardmäßige Authoring-Modus sollte nicht die klassische Benutzeroberfläche sein

  • Schlüssel: ClassicUIAuthoringMode
  • Typ: Code Smell/Cloud Service-Kompatibilität
  • Schweregrad: Gering
  • Seit: Version 2020.5.0

Die OSGi-Konfiguration com.day.cq.wcm.core.impl.AuthoringUIModeServiceImpl definiert den standardmäßigen Authoring-Modus in AEM. Da die klassische Benutzeroberfläche seit AEM 6.4 nicht mehr unterstützt wird, tritt jetzt ein Problem auf, wenn als standardmäßiger Authoring-Modus die klassische Benutzeroberfläche konfiguriert ist.

Komponenten mit Dialogfeldern sollten Dialogfelder für die Touch-Benutzeroberfläche aufweisen

  • Schlüssel: ComponentWithOnlyClassicUIDialog
  • Typ: Code Smell/Cloud Service-Kompatibilität
  • Schweregrad: Gering
  • Seit: Version 2020.5.0

AEM Komponenten mit einem Dialogfeld für die klassische Benutzeroberfläche sollten immer über ein entsprechendes Dialogfeld für die Touch-Benutzeroberfläche verfügen, um ein optimales Authoring-Erlebnis zu bieten und mit dem Cloud Service-Bereitstellungsmodell kompatibel zu sein, bei dem die klassische Benutzeroberfläche nicht unterstützt wird. Diese Regel überprüft die folgenden Szenarien:

  • Eine Komponente mit einem Dialogfeld für die klassische Benutzeroberfläche (d. h. einem untergeordneten dialog-Knoten) muss über ein entsprechendes Dialogfeld für die Touch-Benutzeroberfläche verfügen (d. h. über einen untergeordneten cq:dialog-Knoten).
  • Eine Komponente mit einem Design-Dialogfeld für die klassische Benutzeroberfläche (d. h. einem design_dialog-Knoten) muss über ein entsprechendes Design-Dialogfeld für die Touch-Benutzeroberfläche verfügen (d. h. über einen untergeordneten cq:design_dialog-Knoten).
  • Eine Komponente mit einem Dialogfeld für die klassische Benutzeroberfläche und einem Design-Dialogfeld für die klassische Benutzeroberfläche muss sowohl über ein entsprechendes Dialogfeld für die Touch-Benutzeroberfläche als auch über ein entsprechendes Design-Dialogfeld für die Touch-Benutzeroberfläche verfügen.

Die Dokumentation zu den AEM-Modernisierungs-Tools enthält Dokumentation und Tools zum Konvertieren von Komponenten aus der klassischen Benutzeroberfläche in die Touch-Benutzeroberfläche. Siehe Dokumentation zu AEM Modernisierungs-Tools für weitere Details.

Pakete sollten keinen veränderlichen und unveränderlichen Inhalt mischen

  • Schlüssel: ImmutableMutableMixedPackage
  • Typ: Code Smell/Cloud Service-Kompatibilität
  • Schweregrad: Gering
  • Seit: Version 2020.5.0

Um mit dem Cloud Service-Bereitstellungsmodell kompatibel zu sein, müssen einzelne Inhaltspakete entweder Inhalte für die unveränderlichen Bereiche des Repositorys (d. h. /apps und /libs) oder den veränderlichen Bereich (d. h. alles, was nicht in /apps oder /libs ist) enthalten, aber nicht beides. Beispielsweise ist ein Paket, das beide /apps/myco/components/text and /etc/clientlibs/myco enthält, nicht mit Cloud Service kompatibel und führt dazu, dass ein Problem gemeldet wird.

Weitere Informationen finden Sie unter AEM-Projektstruktur.

Rückwärtsreplikations-Agenten sollten nicht verwendet werden

  • Schlüssel: ReverseReplication
  • Typ: Code Smell/Cloud Service-Kompatibilität
  • Schweregrad: Gering
  • Seit: Version 2020.5.0

In Cloud Service-Implementierungen ist keine Unterstützung für die Rückwärtsreplikation verfügbar, wie im AEM as a Cloud Service Versionshinweise.

Kunden, die die Rückwärtsreplikation verwenden, sollten sich für alternative Lösungen an Adobe wenden.

Ressourcen, die in Proxy-aktivierten Client-Bibliotheken enthalten sind, sollten sich in einem Ordner befinden, der Ressourcen heißt

  • Schlüssel: ClientlibProxyResource
  • Typ: Fehler
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM Client-Bibliotheken können statische Ressourcen wie Bilder und Schriftarten enthalten. Wie im Dokument beschrieben Verwendung von Präprozessoren, Bei Verwendung von Proxyclient-Bibliotheken müssen diese statischen Ressourcen in einem untergeordneten Ordner mit dem Namen resources um effektiv auf die Veröffentlichungsinstanzen verwiesen zu werden.

Nicht konformer Code

+ apps
  + projectA
    + clientlib
      - allowProxy=true
      + images
        + myimage.jpg

Konformer Code

+ apps
  + projectA
    + clientlib
      - allowProxy=true
      + resources
        + myimage.jpg

Verwenden von nicht mit Cloud Service kompatiblen Workflow-Prozessen

  • Schlüssel: CloudServiceIncompatibleWorkflowProcess
  • Typ: Fehler
  • Schweregrad: Hoch
  • Seit: Version 2021.2.0

Mit der Umstellung auf Asset-Microservices für die Asset-Verarbeitung auf AEM as a Cloud Service sind mehrere Workflow-Prozesse, die in On-Premise- und AMS-Versionen von AEM verwendet wurden, entweder nicht mehr unterstützt oder nicht mehr erforderlich.

Mit dem Migrations-Tool im GitHub-Repository für AEM Assets as a Cloud Service können Workflow-Modelle während der Migration in AEM as a Cloud Service aktualisiert werden.

Von der Verwendung von statischen Vorlagen wird zugunsten von bearbeitbaren Vorlagen abgeraten

  • Schlüssel: StaticTemplateUsage
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

Die Verwendung von statischen Vorlagen war in AEM-Projekten stets weit verbreitet. Editierbare Vorlagen werden jedoch dringend empfohlen, da sie die größte Flexibilität bieten und zusätzliche Funktionen unterstützen, die in statischen Vorlagen nicht vorhanden sind. Weitere Informationen finden Sie im Dokument . Seitenvorlagen.

Die Migration von statischen zu bearbeitbaren Vorlagen kann mithilfe der AEM-Modernisierungs-Tools weitgehend automatisiert werden.

Die Verwendung älterer Foundation-Komponenten wird nicht empfohlen

  • Schlüssel: LegacyFoundationComponentUsage
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

Die alten Foundation-Komponenten (d. h. Komponenten unter /libs/foundation) werden seit mehreren AEM-Versionen nicht mehr verwendet und wurden durch die -Kernkomponenten ersetzt. Die Verwendung der Foundation-Komponenten als Grundlage für benutzerdefinierte Komponenten (ob durch Überlagerung oder Vererbung) wird empfohlen und sollte in die entsprechenden Kernkomponenten konvertiert werden.

Diese Konvertierung kann durch die AEM-Modernisierungs-Tools erleichtert werden.

Es sollten nur unterstützte Ausführungsmodus-Namen und -Reihenfolgen verwendet werden

  • Schlüssel: SupportedRunmode
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM as a Cloud Service erzwingt eine strikte Benennungsrichtlinie für Ausführungsmodusnamen und eine strikte Reihenfolge für diese Ausführungsmodi. Die Liste der unterstützten Ausführungsmodi finden Sie im Dokument . Bereitstellen in AEM as a Cloud Service und jede Abweichung davon wird als Problem identifiziert.

  • Schlüssel: OakIndexLocation
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM as a Cloud Service erfordert, dass benutzerdefinierte Suchindex-Definitionen (d. h. Knoten des Typs oak:QueryIndexDefinition) direkt untergeordnete Knoten von /oak:index. Indizes an anderen Orten müssen verschoben werden, um mit AEM as a Cloud Service kompatibel zu sein. Weitere Informationen zu Suchindizes finden Sie im Dokument . Inhaltssuche und -indizierung.

Knoten einer benutzerdefinierten Suchindex-Definition müssen die compatVersion 2 haben

  • Schlüssel: IndexCompatVersion
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM as a Cloud Service erfordert, dass benutzerdefinierte Suchindex-Definitionen (d. h. Knoten des Typs oak:QueryIndexDefinition) muss die Variable compatVersion Eigenschaft auf 2. Andere Werte werden von AEM as a Cloud Service nicht unterstützt. Weitere Informationen zu Suchindizes finden Sie unter Inhaltssuche und indizierung.

Absteigende Knoten einer benutzerdefinierten Suchindex-Definition müssen vom Typ nt:unstructured sein

  • Schlüssel: IndexDescendantNodeType
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

Schwer behebbare Probleme können auftreten, wenn ein Knoten mit einer benutzerdefinierten Suchindex-Definition ungeordnete untergeordnete Knoten enthält. Um diese Situation zu vermeiden, wird empfohlen, dass alle untergeordneten Knoten eines oak:QueryIndexDefinition node be of type nt:unstructured.

Benutzerdefinierte Suchindex-Definitionsknoten müssen einen untergeordneten Knoten namens indexRules enthalten, der untergeordnete Elemente enthält

  • Schlüssel: IndexRulesNode
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

Ein ordnungsgemäß definierter benutzerdefinierter Suchindex-Definitionsknoten muss einen untergeordneten Knoten mit dem Namen indexRules die wiederum mindestens ein Kind haben müssen. Weitere Informationen finden Sie in der Oak-Dokumentation.

Knoten für benutzerdefinierte Suchindex-Definitionen müssen Namenskonventionen folgen

  • Schlüssel: IndexName
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM as a Cloud Service erfordert, dass benutzerdefinierte Suchindex-Definitionen (d. h. Knoten des Typs oak:QueryIndexDefinition) muss nach einem bestimmten Muster benannt werden, das im Dokument beschrieben wird Inhaltssuche und -indizierung.

Knoten für benutzerdefinierte Suchindex-Definitionen müssen den Indextyp „lucene“ verwenden

  • Schlüssel: IndexType
  • Typ: Fehler
  • Schweregrad: Blocker
  • Seit: Version 2021.2.0 (Änderung von Typ und Schweregrad in 2021.8.0)

AEM as a Cloud Service erfordert, dass benutzerdefinierte Suchindex-Definitionen (d. h. Knoten des Typs oak:QueryIndexDefinition) haben eine type -Eigenschaft mit dem Wert lucene. Die Indizierung mit älteren Indextypen muss vor der Migration auf AEM as a Cloud Service aktualisiert werden. Siehe Dokument Inhaltssuche und -indizierung für weitere Informationen.

Knoten einer benutzerdefinierten Suchindex-Definition dürfen keine Eigenschaft namens „seed“ enthalten

  • Schlüssel: IndexSeedProperty
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM as a Cloud Service verbietet benutzerdefinierte Suchindex-Definitionen (d. h. Knoten des Typs oak:QueryIndexDefinition), die eine Eigenschaft namens seed. Die Indizierung mit dieser Eigenschaft muss vor der Migration auf AEM as a Cloud Service aktualisiert werden. Siehe Dokument . Inhaltssuche und -indizierung für weitere Informationen.

Knoten einer benutzerdefinierten Suchindex-Definition dürfen keine Eigenschaft namens „reindex“ enthalten

  • Schlüssel: IndexReindexProperty
  • Typ: Code Smell
  • Schweregrad: Gering
  • Seit: Version 2021.2.0

AEM as a Cloud Service verbietet benutzerdefinierte Suchindex-Definitionen (d. h. Knoten des Typs oak:QueryIndexDefinition), die eine Eigenschaft namens reindex. Die Indizierung mit dieser Eigenschaft muss vor der Migration auf AEM as a Cloud Service aktualisiert werden. Siehe Dokument . Inhaltssuche und -indizierung für weitere Informationen.

Auf dieser Seite