自訂程式碼品質規則 custom-code-quality-rules

本頁說明 Cloud Manager 在程式碼品質測試過程中執行的自訂程式碼品質規則。它們是根據 Experience Manager Engineering 的最佳實務。

NOTE
由於 Adobe 專屬資訊,完整的 SonarQube 規則無法下載。若要下載完整的規則清單,可使用此連結。繼續閱讀本文件以取得規則的說明和範例。
NOTE
在此提供的程式碼範例僅供說明用途。請參閱 SonarQube 概念文件以了解 SonarQube 概念和品質規則。

SonarQube 規則 sonarqube-rules

下節會詳細介紹由 Cloud Manager 執行的 SonarQube 規則。

請勿使用有潛在危險的功能 do-not-use-potentially-dangerous-functions

  • 索引碼:CQRules:CWE-676
  • 類型:漏洞
  • 嚴重度:重大
  • 始自:2018.4.0 版本

方法 Thread.stop()Thread.interrupt() 可能產生難以重現的問題,有時還可能產生安全性漏洞。它們的使用應受到嚴密監控和驗證。總的來說,傳遞資訊是實現類似目標的更安全的方式。

不符合規範的程式碼 non-compliant-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();
    }
  }
}

符合規範的程式碼 compliant-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();
    }
  }
}

請勿使用可能由外部控制的格式字串 do-not-use-format-strings-which-may-be-externally-controlled

  • 索引碼:CQRules:CWE-134
  • 類型:漏洞
  • 嚴重度:重大
  • 始自:2018.4.0 版本

使用來自外部來源的格式字串 (例如要求參數或使用者產生的內容) 可能會讓應用程式遭受拒絕服務的攻擊。在某些情況下,格式字串可能會受到外部控制,但僅允許來自受信任的來源。

不符合規範的程式碼 non-compliant-code-1

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 要求始終都應該有通訊端和連線逾時 http-requests-should-always-have-socket-and-connect-timeouts

  • 索引碼:CQRules:ConnectionTimeoutMechanism
  • 類型:錯誤
  • 嚴重度:嚴重
  • 始自:2018.6.0 版本

從 Experience Manager 應用程式內部執行 HTTP 要求時,需確保設定適當的逾時以避免不必要的執行緒消耗,這點極為重要。不幸的是,Java™ 的預設 HTTP 用戶端 (java.net.HttpUrlConnection) 和常用的 Apache HTTP 元件用戶端的預設行為是永不逾時,因此必須明確設定逾時。此外,依據最佳做法的要求,上述逾時不應超過 60 秒。

不符合規範的程式碼 non-compliant-code-2

@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();
}

符合規範的程式碼 compliant-code-1

@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 物件 resourceresolver-objects-should-always-be-closed

  • 索引碼:CQRules:CQBP-72
  • 類型:程式碼異味
  • 嚴重度:重大
  • 始自:2018.4.0 版本

ResourceResolver 物件 (獲自 ResourceResolverFactory) 會消耗系統資源。儘管現有一些措施可以在 ResourceResolver 不再使用時回收這些資源,但透過呼叫 close() 方法明確關閉任何開啟的 ResourceResolver 物件會更有效率。

一個相當常見的誤解是,不應明確關閉使用現有 JCR 工作階段建立的 ResourceResolver 物件,否則會關閉基本的 JCR 工作階段。情況並非如此。無論 ResourceResolver 如何開啟,不使用時都經將其關閉。由於 ResourceResolver 實作 Closeable 介面,也有可能使用 try-with-resources 語法而不是明確地叫用 close()

不符合規範的程式碼 non-compliant-code-4

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

符合規範的程式碼 compliant-code-2

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
  }
}

請勿使用 Sling Servlet 路徑來註冊 Servlet do-not-use-sling-servlet-paths-to-register-servlets

  • 索引碼:CQRules:CQBP-75
  • 類型:程式碼異味
  • 嚴重度:重大
  • 始自:2018.4.0 版本

如同在 Sling 文件紀錄中的說明,不建議按路徑繫結 servlet。路徑繫結的 servlet 不能使用標準的 JCR 存取控制,因此需要額外嚴格的安全性。建議不要使用路徑繫結的 servlet,而是在存放庫中建立節點並按資源類型註冊 servlet。

不符合規範的程式碼 non-compliant-code-5

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

應記錄或擲回攔截到的例外狀況,而非執行兩者。 caught-exceptions-should-be-logged-or-thrown-but-not-both

  • 索引碼:CQRules:CQBP-44—CatchAndEitherLogOrThrow
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

一般而言,應該只記錄一次例外狀況。記錄多次例外狀況可能會導致混淆,因為會不清楚發生了多少次例外狀況。會導致這種情況的最常見模式是將攔截到的例外狀況記錄並擲回。

不符合規範的程式碼 non-compliant-code-6

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

符合規範的程式碼 compliant-code-3

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);
  }
}

避免 Log 陳述式後緊跟著 Throw 陳述式 avoid-having-a-log-statement-immediately-followed-by-a-throw-statement

  • 索引碼:CQRules:CQBP-44—ConsecutivelyLogAndThrow
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

另一個要避免的常見模式是記錄一則訊息後立即擲回例外狀況。此做法通常表示例外狀況訊息最終會在記錄檔案中重複。

不符合規範的程式碼 non-compliant-code-7

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

符合規範的程式碼 compliant-code-4

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

處理 GET 或 HEAD 要求時避免在 INFO 上進行記錄 avoid-logging-at-info-when-handling-get-or-head-requests

  • 索引碼:CQRules:CQBP-44—LogInfoInGetOrHeadRequests
  • 類型:程式碼異味
  • 嚴重度:輕微

一般而言,應該使用 INFO 記錄層級來區分重要操作,並且預設情況下,會將 Experience Manager 設定為在 INFO 或以上層級記錄。GET 和 HEAD 方法應僅能唯讀操作,因此不構成重要操作。在 INFO 層級記錄以回應 GET 或 HEAD 要求可能會產生大量記錄雜訊,而使得在記錄檔中識別有用資訊變得更加困難。在處理 GET 或 HEAD 要求時若出現錯誤,應該在 WARN 或 ERROR 層級進行記錄,或者若是更深入的疑難排解資訊會有幫助,則應在 DEBUG 或 TRACE 層級進行。

NOTE
這不適用於每個要求的 access.log-type 記錄。

不符合規範的程式碼 non-compliant-code-8

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

符合規範的程式碼 compliant-code-5

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

請勿使用 Exception.getMessage() 作為記錄陳述式的第一個參數 do-not-use-exception-getmessage-as-the-first-parameter-of-a-logging-statement

  • 索引碼:CQRules:CQBP-44—ExceptionGetMessageIsFirstLogParam
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

依據最佳做法的要求,紀錄訊息應提供有關應用程式中發生例外狀況的位置的內容相關資訊。雖然也可以透過使用堆疊追蹤來確定內容,但記錄訊息通常將更容易讀取和理解。因此,在記錄例外狀況時,將例外狀況的訊息當成記錄訊息來使用是不好的做法。例外狀況訊息會包含所發生的問題,而記錄訊息則應該用於告知記錄讀取程式例外狀況發生時應用程式正在做什麼。例外狀況訊息仍會記錄。透過指定您自己的訊息,更容易理解這些紀錄。

不符合規範的程式碼 non-compliant-code-9

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

符合規範的程式碼 compliant-code-6

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

Catch 區塊中的記錄應在 WARN 或 ERROR 層級進行 logging-in-catch-blocks-should-be-at-the-warn-or-error-level

  • 索引碼:CQRules:CQBP-44—WrongLogLevelInCatchBlock
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

顧名思義,在例外情況下,始終都應該使用 Java™ 例外狀況。因此,當攔截到例外狀況時,確保將紀錄訊息記錄在以下適當層級 (WARN 或 ERROR) 非常重要。這可確保這些訊息正確地顯示在紀錄中。

不符合規範的程式碼 non-compliant-code-10

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

符合規範的程式碼 compliant-code-7

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

不可將堆疊追蹤列印到控制台 do-not-print-stack-traces-to-the-console

  • 索引碼:CQRules:CQBP-44—ExceptionPrintStackTrace
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

如前所述,在了解紀錄訊息時,內容極為重要。使用 Exception.printStackTrace() 只會導致堆疊追蹤輸出至標準錯誤流,而遺失所有內容。此外,在像 Experience Manager 這類多執行緒應用程式中,如果使用此方法同時列印多個例外狀況,它們的堆疊追蹤可能會重疊,從而產生嚴重的混亂。僅能透過記錄架構記錄例外狀況。

不符合規範的程式碼 non-compliant-code-11

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

符合規範的程式碼 compliant-code-8

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

不可輸出到標準輸出或標準錯誤 do-not-output-to-standard-output-or-standard-error

  • 索引碼:CQRules:CQBP-44—LogLevelConsolePrinters
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

Experience Manager 中的記錄應該始終透過記錄架構 (SLF4J) 完成。直接輸出到標準輸出或標準錯誤串流會遺失記錄架構提供的結構和相關內容資訊。有時還可能導致效能問題。

不符合規範的程式碼 non-compliant-code-12

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

符合規範的程式碼 compliant-code-9

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

避免硬式編碼 /應用程式和 /libs 路徑 avoid-hardcoded-apps-and-libs-paths

  • 索引碼:CQRules:CQBP-71
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2018.4.0 版本

一般而言,以 /libs/apps 開頭的路徑不應為硬式編碼,因為它們參考的路徑最常儲存為和 Sling 搜尋路徑 (預設情況下會設定為 /libs,/apps) 相關的路徑。使用絕對路徑可能會引進難以察覺的缺陷,而且只會在專案生命週期的後期出現。

不符合規範的程式碼 non-compliant-code-13

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

符合規範的程式碼 compliant-code-10

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

請勿使用 Sling 排程器 sonarqube-sling-scheduler

  • 索引碼:CQRules:AMSCORE-554
  • 類型:程式碼異味/雲端服務相容性
  • 嚴重度:輕微
  • 始自:2020.5.0 版本

請勿將 Sling 排程器用於要求保證執行的任務。Sling 已排程的作業可保證執行並更適合叢集和非叢集環境。

若要了解如何在叢集環境中處理 Sling 作業的詳細資訊,請參閱 Apache Sling 事件和作業處理

請勿使用 Experience Manager 已過時的 API sonarqube-aem-deprecated

  • 索引碼:AMSCORE-553
  • 類型:程式碼異味/雲端服務相容性
  • 嚴重度:輕微
  • 始自:2020.5.0 版本

Experience Manager API 表面經過不斷修正,以識別不鼓勵使用並因此被視為已過時的 API。

通常,會使用標準 Java™ @Deprecated 註解來取代這些 API,而且會由 squid:CallToDeprecatedMethod 進行識別。

但是,在某些情況下,API 在 Experience Manager 的內容中會遭到取代,但在其他內容中卻可能不會。此規則會識別此第二分類。

請勿在Sling模型中搭配@Optional使用@Inject註釋 sonarqube-slingmodels-inject-optional

  • 索引鍵: InjectAnnotationWithOptionalInjectionCheck
  • 型別:軟體品質
  • 嚴重度:輕微
  • :2023.11版

Apache Sling專案不鼓勵使用 @Inject Sling模型上下文中的註解,因為它在與 DefaultInjectionStrategy.OPTIONAL (在欄位或類別層級)。 而是更具體的注射(例如 @ValueMapValue@OsgiInjector 註解)。

檢查 Apache Sling檔案 以取得建議註解的詳細資訊,以及最初提出此建議的原因。

重複使用HTTPClient的執行個體 sonarqube-reuse-httpclient

  • 索引鍵: AEMSRE-870
  • 型別:軟體品質
  • 嚴重度:輕微
  • :2023.11版

AEM應用程式經常使用HTTP通訊協定聯絡其他應用程式,而Apache HttpClient則是實現這一目標的常用程式庫。 但是建立這樣的HttpClient物件會產生一些額外負荷,因此這些物件應儘可能重複使用。

此規則會檢查這種HttpClient物件在方法內是否不是私人,而是在類別層級上是否為全域,以便可以重複使用。 在這種情況下,httpClient欄位應在類別的建構函式中設定,或 activate() 方法(如果此類別是OSGi元件/服務)。

檢查 Optimization指南 HttpClient的使用說明,以瞭解使用HttpClient的一些最佳作法。

不符合規範的程式碼 non-compliant-code-14

public void doHttpCall() {
  HttpClient httpclient = HttpClients.createDefault();
  // do something with the httpclient
}

符合規範的程式碼 compliant-code-11

public class myClass {

  HttpClient httpclient;

  public void doHttpCall() {
    // do something with the httpclient
  }

}

OakPAL 內容規則 oakpal-rules

下節會詳細介紹由 Cloud Manager 執行的 OakPAL 檢查。

NOTE
OakPAL 是一種架構,會使用獨立的 Oak 存放庫來驗證內容套件。它是由 Experience Manager 合作夥伴開發出來的,並榮獲 2019 年 Experience Manager Rockstar 北美獎。

客戶不應實作或擴展有 @ProviderType 註解的產品 API product-apis-annotated-with-providertype-should-not-be-implemented-or-extended-by-customers

  • 索引碼:CQBP-84
  • 類型:錯誤
  • 嚴重度:嚴重
  • 始自:2018.7.0 版本

Experience Manager API 包含 Java™ 介面和類別,這些介面和類別僅能由自訂程式碼使用,但不能實作。例如,介面 com.day.cq.wcm.api.Page 應僅由 Experience Manager 實作。

將新方法新增到這些介面時,這些附加方法不會影響使用這些介面的現有程式碼。因此,在這些介面中新增新方法會視為回溯相容。但是,如果自訂程式碼實作其中一個介面,該自訂程式碼會給客戶帶來回溯相容性的風險。

由 Experience Manager 實作的介面和分類會使用 org.osgi.annotation.versioning.ProviderType 進行註解,或有時會使用類似的舊註解 aQute.bnd.annotation.ProviderType。此規則會識別實作此類介面或由自訂程式碼擴展的分類的情況。

不符合規範的程式碼 non-compliant-code-3

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

public class DontDoThis implements Page {
// implementation here
}

自訂 Lucene Oak 索引必須具有 Tika 設定 oakpal-indextikanode

  • 索引碼:IndexTikaNode
  • 類型:錯誤
  • 嚴重度:阻斷因素
  • 始自:2021.8.0

多個現成的 Experience Manager Oak 索引包括 Tika 設定,且這些索引的自訂必須包括 Tika 設定。此規則會檢查 damAssetLucenelucenegraphqlConfig 索引的自訂,並在 tika 節點缺少或 tika 節點缺少名為 config.xml 的子節點時引發問題。

如需有關自訂索引定義的詳細資訊,請參閱索引文件

不符合規範的程式碼 non-compliant-code-indextikanode

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

符合規範的程式碼 compliant-code-indextikanode

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

自訂 Lucene Oak 索引不能同步 oakpal-indexasync

  • 索引碼:IndexAsyncProperty
  • 類型:錯誤
  • 嚴重度:阻斷因素
  • 始自:2021.8.0

lucene 類型的 Oak 索引必須一律進行非同步索引。如果不這樣做可能會導致系統不穩定。如需有關 Lucene 索引結構的更多資訊,可在 Oak 文件中找到。

不符合規範的程式碼 non-compliant-code-indexasync

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

符合規範的程式碼 compliant-code-indexasync

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

自訂 DAM 資產 Lucene Oak 索引結構正確 oakpal-damAssetLucene-sanity-check

  • 索引碼:IndexDamAssetLucene
  • 類型:錯誤
  • 嚴重度:阻斷因素
  • 始自:2021.6.0

要使資產搜尋在 Experience Manager Assets 中正常運作,damAssetLuceneOak 索引的自訂必須遵循一組特定於此索引的準則。此規則會檢查索引定義是否必須具有包含值 visualSimilaritySearch,名為 tags 的多值屬性。

不符合規範的程式碼 non-compliant-code-damAssetLucene

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

符合規範的程式碼 compliant-code-damAssetLucene

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

客戶套件不應在 /libs 下建立或修改節點 oakpal-customer-package

  • 索引碼:BannedPath
  • 類型:錯誤
  • 嚴重度:嚴重
  • 始自:2019.6.0 版本

客戶應將 Experience Manager 內容存放庫中的 /libs 內容樹視為唯讀,這是一個存在已久的最佳做法。修改 /libs 下的節點和屬性都會對大幅和小幅更新產生顯著風險。對 /libs 的修改必須由 Adobe 透過正式通道進行。

套件不應包含重複的 OSGi 設定 oakpal-package-osgi

  • 索引碼:DuplicateOsgiConfigurations
  • 類型:錯誤
  • 嚴重度:重大
  • 始自:2019.6.0 版本

複雜專案中會出現的一個常見問題是多次設定同一個 OSGi 元件。此問題會產生模稜兩可的結果,無法確定可套用哪種設定。此規則為「執行模式感知」,因為它只會識別在同一執行模式或多個執行模式組合中多次設定相同元件的問題。

NOTE
此規則會在多個套件中定義相同路徑的相同設定時造成問題,包括相同套件在建置套件的整體清單中重複的情況。
例如,如果組建產生名為 com.myco:com.myco.ui.appscom.myco:com.myco.all 的套件,其中 com.myco:com.myco.all 嵌入了 com.myco:com.myco.ui.apps,則 com.myco:com.myco.ui.apps 中的所有設定都會回報為重複專案。
會發生這種情況通常是因為未遵循內容套件結構指南。在此特定範例中,套件 com.myco:com.myco.ui.apps 中缺少 <cloudManagerTarget>none</cloudManagerTarget> 屬性。

不符合規範的程式碼 non-compliant-code-osgi

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

符合規範的程式碼 compliant-code-osgi

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

設定和安裝資料夾應只包含 OSGi 節點 oakpal-config-install

  • 索引碼碼:ConfigAndInstallShouldOnlyContainOsgiNodes
  • 類型:錯誤
  • 嚴重度:重大
  • 始自:2019.6.0 版本

基於安全性理由,包含 /config//install/ 的路徑只有 Experience Manager 中的管理員使用者可讀取,並且僅能用於 OSGi 設定和 OSGi 套裝。將其他類型的內容放在包含這些區段的路徑下會導致應用程式行為在管理員使用者和非管理員使用者之間無意間發生變化。

一個常見問題是在元件對話框中或在為內嵌編輯指定 RTF 文字編輯器設定時會使用名為 config 的節點。若要解決此問題,應將違規節點重新命名為合規名稱。對於 RTF 文字編輯器設定,請使用 configPath 屬性 (在 cq:inplaceEditing 節點上) 來指定新位置。

不符合規範的程式碼 non-compliant-code-config-install

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

符合規範的程式碼 compliant-code-config-install

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

套件不應重疊 oakpal-no-overlap

  • 索引碼:PackageOverlaps
  • 類型:錯誤
  • 嚴重度:重大
  • 始自:2019.6.0 版本

類似套件不應包含重複的 OSGi 設定規則,這是複雜專案中常見的問題,這類專案會由多個單獨的內容套件寫入相同的節點路徑。雖然使用內容套件相依性可用於確保一致的結果,但最好還是完全避免重疊。

預設的撰寫模式不應該是 Classic UI oakpal-default-authoring

  • 索引碼:ClassicUIAuthoringMode
  • 類型:程式碼異味/雲端服務相容性
  • 嚴重度:輕微
  • 始自:2020.5.0 版本

OSGi 設定 com.day.cq.wcm.core.impl.AuthoringUIModeServiceImpl 會定義 Experience Manager 中的預設撰寫模式。由於從 Experience Manager 6.4 起,Classic UI 就已被取代,若將預設的撰寫模式設定為 Classic UI,會產生問題。

包含對話框的元件應該有 Touch UI 對話框 oakpal-components-dialogs

  • 索引碼:ComponentWithOnlyClassicUIDialog
  • 類型:程式碼異味/雲端服務相容性
  • 嚴重度:輕微
  • 始自:2020.5.0 版本

有 Classic UI 對話框的 Experience Manager 元件應該隨時有相對應的 Touch UI 對話框。既能提供最佳撰寫體驗,又與不支援 Classic UI 的雲端服務部署模式相容。本規則可證實以下情境:

  • 具有 Classic UI 對話框 (即 dialog 子節點) 的元件必須具有相對應的 Touch UI 對話框 (即 cq:dialog 子節點)。
  • 具有 Classic UI 設計對話框 (即 design_dialog 節點) 的元件必須具有相對應的 Touch UI 對話框 (即 cq:design_dialog 子節點)。
  • 同時具有 Classic UI 對話框以及 Classic UI 設計對話框的元件必須同時有相對應的 Touch UI 對話框以及相對應的 Touch UI 設計對話框。

Experience Manager 現代化工具文件提供了有關如何將元件從 Classic UI 轉換為 Touch UI 的文件和工具。如需更多詳細資訊,請參閱 Experience Manager 現代化工具文件

套件不應該混合可變和不可變的內容 oakpal-packages-immutable

  • 索引碼:ImmutableMutableMixedPackage
  • 類型:程式碼異味/雲端服務相容性
  • 嚴重度:輕微
  • 始自:2020.5.0 版本

要與雲端服務部署模式相容,個別內容套件必須包含存放庫不可變區域 (/apps/libs) 或可變區域 (不在 /apps/libs 中的所有內容) 的內容,但不能同時包含兩者。例如,同時包含 /apps/myco/components/text/etc/clientlibs/myco 的套件和雲端服務不相容,並會導致需通報的問題。

如需更多詳細資訊,請參閱 Experience Manager 專案結構

不應使用反向複寫代理 oakpal-reverse-replication

  • 索引碼:ReverseReplication
  • 類型:程式碼異味/雲端服務相容性
  • 嚴重度:輕微
  • 始自:2020.5.0 版本

Cloud Service 部署中不支援反向複寫,如 Experience Manager as a Cloud Service 的發行說明中所述。

使用反向複寫的客戶應和 Adobe 聯絡,以取得替代解決方案。

已啟用 Proxy 的用戶端資料庫中所包含的資源應位於名為資源的資料夾中 oakpal-resources-proxy

  • 索引碼:ClientlibProxyResource
  • 類型:錯誤
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager 用戶端資料庫可能包含影像和字體之類的靜態資源。如使用前置處理器文件中所述,使用透過 Proxy 的用戶端資料庫時,這些靜態資源必須包含在名為 resources 的子資料夾中,以便在發佈執行個體上有效地參考。

不符合規範的程式碼 non-compliant-proxy-enabled

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

符合規範的程式碼 compliant-proxy-enabled

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

Cloud Service 的使用與工作流程不相容 oakpal-usage-cloud-service

  • 索引碼:CloudServiceIncompatibleWorkflowProcess
  • 類型:錯誤
  • 嚴重度:重大
  • 始自:2021.2.0 版本

隨著在 Experience Manager as a Cloud Service 上移動到資產微服務以進行資產處理,在 Experience Manager 的內部部署和 AMS 版本中使用的多個工作流程已變得不受支援或不必要。

Experience Manager Assets as a Cloud Service GitHub 存放庫中的移轉工具可在移轉至 Experience Manager as a Cloud Service 期間用於更新工作流程模式。

不建議使用靜態範本而支持可編輯範本 oakpal-static-template

  • 索引碼:StaticTemplateUsage
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

雖然靜態範本的使用歷來在 Experience Manager 專案中極為普遍,Adobe 建議使用可編輯範本,因為它們可提供最大的靈活度並支援靜態範本中不存在的附加功能。在頁面範本文件中可找到更多資訊。

使用 Experience Manager 現代化工具可將從靜態範本到可編輯範本的遷移大幅自動化。

不建議使用舊版基礎元件 oakpal-usage-legacy

  • 索引碼:LegacyFoundationComponentUsage
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

舊版基礎元件 (即 /libs/foundation 下的元件) 已在多個 Experience Manager 版本中被取代,以支援核心元件。不建議使用基礎元件作為自訂元件的基礎 (無論是透過覆蓋還是繼承),並應轉換為相對應的核心元件。

Experience Manager 現代化工具可有助於這種轉換。

僅使用受支援的執行模式名稱和順序 oakpal-supported-runmodes

  • 索引碼:SupportedRunmode
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager as a Cloud Service 對執行模式名稱實施嚴格的命名原則,並對這些執行模式要求嚴格的排序。受支援的執行模式清單可在部署到 Experience Manager as a Cloud Service 文件中找到,任何與此的偏離都會被識別為問題。

  • 索引碼:OakIndexLocation
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager as a Cloud Service 要求自訂搜尋索引定義 (即類型 oak:QueryIndexDefinition 的節點) 是 /oak:index 的直接子節點。必須移動其他位置中的索引才能和 Experience Manager as a Cloud Service 相容。如需有關搜尋索引的詳細資訊,可在內容搜尋和索引文件中找到。

自訂搜尋索引定義節點的 compatVersion 必須為 2 oakpal-custom-search-compatVersion

  • 索引碼:IndexCompatVersion
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager as a Cloud Service 要求自訂搜尋索引定義 (例如類型 oak:QueryIndexDefinition 的節點) 必須將 compatVersion 屬性設定為 2。Experience Manager as a Cloud Service 並不支援任何其他值。如需有關搜尋索引的詳細資訊,可在以下連結中找到:內容搜尋和索引

自訂搜尋索引定義節點的下階節點必須屬於 nt:unstructured 類型 oakpal-descendent-nodes

  • 索引碼:IndexDescendantNodeType
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

當自訂搜尋索引定義節點具有無序子節點時,可能會出現難以解決的問題。若要避免出現這種情況,建議 oak:QueryIndexDefinition 節點的所有下階節點屬於 nt:unstructured 類型。

自訂搜尋索引定義節點必須包含名為 indexRules 並有子系的子節點 oakpal-custom-search-index

  • 索引碼:IndexRulesNode
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

正確定義的自訂搜尋索引定義節點必須包含一個名為 indexRules 的子節點,而該子節點又必須至少有一個子系。在以下連結中可找到更多資訊:Oak 文件。

自訂搜尋索引定義節點必須遵循命名慣例 oakpal-custom-search-definitions

  • 索引碼:IndexName
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager as a Cloud Service 要求自訂搜尋索引定義 (即 oak:QueryIndexDefinition 類型的節點) 必須按照以下文件中說明的特定模式命名:內容搜尋和索引

自訂搜尋索引定義節點必須使用索引類型 Lucene oakpal-index-type-lucene

  • 索引碼:IndexType
  • 類型:錯誤
  • 嚴重度:阻斷因素
  • 始自:2021.2.0 版本 (在 2021.8.0 變更類型和嚴重性)

Experience Manager as a Cloud Service 要求自訂搜尋索引定義 (即類型 oak:QueryIndexDefinition 的節點) 必須具備 type 屬性,且值設定為 lucene。在移轉到 Experience Manager as a Cloud Service 之前,必須更新使用舊式索引類型的索引。如需詳細資訊,請參閱內容搜尋和索引

自訂搜尋索引定義節點不得包含名為 seed 的屬性 oakpal-property-name-seed

  • 索引碼:IndexSeedProperty
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager as a Cloud Service 禁止自訂搜尋索引定義 (即 oak:QueryIndexDefinition 類型的節點) 包含名為 seed 的屬性。在移轉到 Experience Manager as a Cloud Service 之前,必須更新使用此屬性的索引。如需詳細資訊,請參閱內容搜尋和索引文件。

自訂搜尋索引定義節點不得包含名為 reindex 的屬性 oakpal-reindex-property

  • 索引碼:IndexReindexProperty
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2021.2.0 版本

Experience Manager as a Cloud Service 禁止自訂搜尋索引定義 (即 oak:QueryIndexDefinition 類型的節點) 包含名為 reindex 的屬性。在移轉到Experience Manageras a Cloud Service之前,必須更新使用此屬性的索引。 如需詳細資訊,請參閱內容搜尋和索引文件。

自訂DAM資產lucene節點不得指定「queryPaths」 oakpal-damAssetLucene-queryPaths

  • 索引碼:IndexDamAssetLucene
  • 類型:錯誤
  • 嚴重度:阻斷因素
  • 始自:2022.1.0 版本

不符合規範的程式碼 non-compliant-code-damAssetLucene-queryPaths

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

符合規範的程式碼 compliant-code-damAssetLucene-queryPaths

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

如果自訂搜尋索引定義包含compatVersion,則必須將其設為2 oakpal-compatVersion

  • 索引碼:IndexCompatVersion
  • 類型:程式碼異味
  • 嚴重度:重大
  • 始自:2022.1.0 版本

指定「includedPaths」的索引節點也應使用相同的值指定「queryPaths」 oakpal-included-paths-without-query-paths

  • 索引鍵: IndexIncludedPathsWithoutQueryPaths
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2023.1.0 版本

對於自訂索引,兩者皆可 includedPathsqueryPaths 應設定為相同的值。 若已指定其中一個,另一個必須符合它。 但是,下列的索引有一個特殊情況 damAssetLucene,包括其自訂版本。 對於這些專案,您應該只提供 includedPaths.

在一般節點型別上指定nodeScopeIndex的索引節點也應該指定includedPaths和queryPaths oakpal-full-text-on-generic-node-type

  • 索引鍵: IndexFulltextOnGenericType
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2023.1.0 版本

設定時 nodeScopeIndex 「一般」節點型別(例如)上的屬性 nt:unstructurednt:base,您也必須指定 includedPathsqueryPaths 屬性。
nt:base 可視為「一般」,因為所有節點型別都會繼承自它。 所以設定 nodeScopeIndexnt:base 會讓它索引存放庫中的所有節點。 同樣地, nt:unstructured 由於存放庫中有許多此型別的節點,因此也視為「一般」。

不符合規範的程式碼 non-compliant-code-full-text-on-generic-node-type

+ oak:index/acme.someIndex-custom-1
  - async: [async, nrt]
  - evaluatePathRestrictions: true
  - tags: [visualSimilaritySearch]
  - type: lucene
    + indexRules
      - jcr:primaryType: nt:unstructured
      + nt:base
        - jcr:primaryType: nt:unstructured
        + properties
          + acme.someIndex-custom-1
            - nodeScopeIndex: true

符合規範的程式碼 compliant-code-full-text-on-generic-node-type

+ oak:index/acme.someIndex-custom-1
  - async: [async, nrt]
  - evaluatePathRestrictions: true
  - tags: [visualSimilaritySearch]
  - type: lucene
  - includedPaths: ["/content/dam/"]
  - queryPaths: ["/content/dam/"]
    + indexRules
      - jcr:primaryType: nt:unstructured
      + nt:base
        - jcr:primaryType: nt:unstructured
        + properties
          + acme.someIndex-custom-1
            - nodeScopeIndex: true

不應覆寫查詢引擎的queryLimitReads屬性 oakpal-query-limit-reads

  • 索引鍵: OverrideOfQueryLimitReads
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2023.1.0 版本

覆寫預設值可能會導致頁面讀取非常緩慢,尤其是在新增更多內容時。

相同索引的多個作用中版本 oakpal-multiple-active-versions

  • 索引鍵: IndexDetectMultipleActiveVersionsOfSameIndex
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2023.1.0 版本

不符合規範的程式碼 non-compliant-code-multiple-active-versions

+ oak:index
  + damAssetLucene-1-custom-1
    ...
  + damAssetLucene-1-custom-2
    ...
  + damAssetLucene-1-custom-3
    ...

符合規範的程式碼 compliant-code-multiple-active-versions

+ damAssetLucene-1-custom-3
    ...

完整自訂索引定義的名稱應符合官方方針 oakpal-fully-custom-index-name

  • 索引鍵: IndexValidFullyCustomName
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2023.1.0 版本

完整自訂索引名稱的預期模式為: [prefix].[indexName]-custom-[version]. 如需詳細資訊,請參閱檔案 內容搜尋與索引.

具有相同索引定義中不同分析值的相同屬性 oakpal-same-property-different-analyzed-values

不符合規範的程式碼 non-compliant-code-same-property-different-analyzed-values

+ indexRules
  + dam:Asset
    + properties
      + status
        - name: status
        - analyzed: true
  + dam:cfVariationNode
    + properties
      + status
        - name: status

符合規範的程式碼 compliant-code-same-property-different-analyzed-values

範例:

+ indexRules
  + dam:Asset
    + properties
      + status
        - name: status
        - analyzed: true
  + dam:cfVariationNode
    + properties
      + status
        - name: status
        - analyzed: true

範例:

+ indexRules
  + dam:Asset
    + properties
      + status
        - name: status
  + dam:cfVariationNode
    + properties
      + status
        - name: status
        - analyzed: true

如果未明確設定分析的屬性,其預設值為false。

標籤屬性

  • 索引鍵: IndexHasValidTagsProperty
  • 類型:程式碼異味
  • 嚴重度:輕微
  • 始自:2023.1.0 版本

對於特定索引,請確定您保留標籤屬性及其目前值。 雖然可以將新值新增到標籤屬性,但刪除任何現有值(或完全刪除屬性)可能會導致意外結果。

recommendation-more-help
fbcff2a9-b6fe-4574-b04a-21e75df764ab