Esta página descreve as regras personalizadas de qualidade do código executadas pelo Cloud Manager como parte do teste de qualidade do código. Elas se baseiam nas práticas recomendadas pela equipe de engenharia do Experience Manager.
As regras completas do SonarQube não estão disponíveis para download devido às informações proprietárias da Adobe. Você pode baixar a lista completa de regras usando este link. Continue a ler este documento para obter descrições e exemplos das regras.
As amostras de código fornecidas aqui são apenas para fins ilustrativos. Consulte a Documentação de conceitos do SonarQube para saber mais sobre os conceitos e as regras de qualidade do SonarQube.
A seção a seguir especifica as regras do SonarQube executadas pelo Cloud Manager.
Os métodos Thread.stop()
e Thread.interrupt()
podem gerar problemas difíceis de reproduzir e, em alguns casos, vulnerabilidades de segurança. A utilização deve ser rigorosamente monitorizada e validada. Em geral, a transmissão de mensagens é uma forma mais segura de atingir objetivos semelhantes.
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();
}
}
}
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();
}
}
}
O uso de uma string de formatação de uma fonte externa (como um parâmetro de solicitação ou conteúdo gerado pelo usuário) pode expor um aplicativo a ataques de negação de serviço. Há casos em que uma string de formatação pode ser controlada externamente, mas isso somente é permitido de fontes confiáveis.
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);
}
Ao executar solicitações HTTP de dentro de um aplicativo do Experience Manager, é importante garantir que os tempos limite sejam configurados adequadamente para evitar o consumo desnecessário de thread. Infelizmente, o comportamento tradicional do cliente HTTP padrão do Java™ (java.net.HttpUrlConnection
) e do cliente de componentes HTTP do Apache mais usado é o de nunca atingir o tempo limite, portanto, estes devem ser definidos de forma explícita. Além disso, como prática recomendada, esses tempos limite não devem ultrapassar 60 segundos.
@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();
}
@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
objetos obtidos do ResourceResolverFactory
consomem recursos do sistema. Embora existam medidas em vigor para recuperar esses recursos quando um ResourceResolver
não estiver mais em uso, é mais eficiente fechar explicitamente todos os objetos ResourceResolver
abertos chamando o método close()
.
Um equívoco relativamente comum é que os objetos ResourceResolver
criados usando uma sessão existente do JCR não devem ser fechados explicitamente ou que fazer isso encerrará a sessão subjacente do JCR. Não é isso o que ocorre. Independentemente de como um ResourceResolver
foi aberto, ele deve ser fechado quando não estiver mais em uso. Como ResourceResolver
implementa a interface Closeable
, também é possível usar a sintaxe try-with-resources
em vez de chamar explicitamente close()
.
public void dontDoThis(Session session) throws Exception {
ResourceResolver resolver = factory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object)session));
// do some stuff with the resolver
}
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
}
}
Conforme descrito na Documentação do Sling, não é recomendado vincular servlets por caminhos. Os servlets vinculados a caminhos não podem usar os controles de acesso JCR padrão e, como resultado disso, exigem maior rigor de segurança. Em vez de usar servlets vinculados a caminhos, é recomendado criar nós no repositório e registrar os servlets por tipo de recurso.
@Component(property = {
"sling.servlet.paths=/apps/myco/endpoint"
})
public class DontDoThis extends SlingAllMethodsServlet {
// implementation
}
Em geral, uma exceção deve ser registrada exatamente uma vez. O múltiplo registro de exceções pode causar confusão, pois não deixa claro quantas vezes uma exceção ocorreu. O padrão mais comum que leva a isso é o registro e o descarte de uma exceção capturada.
public void dontDoThis() throws Exception {
try {
someOperation();
} catch (Exception e) {
logger.error("something went wrong", e);
throw e;
}
}
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);
}
}
Outro padrão comum a ser evitado é registrar uma mensagem e imediatamente depois lançar uma exceção. Isso geralmente indica que a mensagem de exceção acabará duplicada nos arquivos de log.
public void dontDoThis() throws Exception {
logger.error("something went wrong");
throw new RuntimeException("something went wrong");
}
public void doThis() throws Exception {
throw new RuntimeException("something went wrong");
}
Em geral, o nível de log INFO deve ser usado para demarcar ações importantes e, por padrão, o Experience Manager é configurado para registrar no nível INFO ou superior. Os métodos GET e HEAD devem ser operações somente leitura e, portanto, não constituem ações importantes. Registrar no nível INFO em resposta a solicitações GET ou HEAD provavelmente criará um ruído significativo de log, dificultando a identificação de informações úteis em arquivos de log. Ao manipular solicitações GET ou HEAD, o registro deverá estar nos níveis AVISO ou ERRO quando algo der errado ou nos níveis DEPURAÇÃO ou RASTREAMENTO, se informações mais detalhadas de solução de problemas forem necessárias.
Isso não se aplica ao registrar o tipo access.log
em cada solicitação.
public void doGet() throws Exception {
logger.info("handling a request from the user");
}
public void doGet() throws Exception {
logger.debug("handling a request from the user.");
}
Como prática recomendada, as mensagens de log devem fornecer informações contextuais sobre onde ocorreu uma exceção no aplicativo. Embora o contexto também possa ser determinado pelo uso de rastros de pilha, em geral, a mensagem de log será mais fácil de ler e entender. Como resultado disso, ao registrar uma exceção, não é uma prática recomendada usar a mensagem da exceção como a mensagem de registro. A mensagem de exceção contém o que deu errado, enquanto a mensagem de log deve ser usada para informar a um leitor de logs o que o aplicativo estava fazendo quando a exceção aconteceu. A mensagem de exceção ainda é registrada. Ao especificar sua própria mensagem, será mais fácil entender os logs.
public void dontDoThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
public void doThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
logger.error("Unable to do something", e);
}
}
Como o nome sugere, as exceções do Java™ sempre devem ser usadas em casos excepcionais. Como resultado disso, quando uma exceção é capturada, é importante garantir que as mensagens de log sejam registradas no nível apropriado, seja WARN ou ERROR. Isso garante que elas sejam exibidas corretamente nos logs.
public void dontDoThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
logger.debug(e.getMessage(), e);
}
}
public void doThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
logger.error("Unable to do something", e);
}
}
Como mencionado, o contexto é essencial para entender as mensagens de log. Usar Exception.printStackTrace()
faz com que somente o rastro de pilha seja enviado para o fluxo de erro padrão, perdendo todo o contexto. Além disso, em um aplicativo multithread como o Experience Manager, se várias exceções forem impressas em paralelo usando esse método, seus rastros de pilha poderão se sobrepor, gerando bastante confusão. As exceções devem ser registradas somente por meio da estrutura de registro.
public void dontDoThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
e.printStackTrace();
}
}
public void doThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
logger.error("Unable to do something", e);
}
}
Os registros no Experience Manager sempre devem ser feitos por meio da estrutura de registro (SLF4J). Enviar diretamente para a saída padrão ou fluxos de erro padrão perde as informações estruturais e contextuais fornecidas pela estrutura de registro. Às vezes, isso pode causar problemas de desempenho.
public void dontDoThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
System.err.println("Unable to do something");
}
}
public void doThis() {
try {
someMethodThrowingAnException();
} catch (Exception e) {
logger.error("Unable to do something", e);
}
}
Em geral, caminhos que começam com /libs
e /apps
não devem ser codificados, pois se referem a caminhos que normalmente são armazenados como caminhos relativos ao caminho de pesquisa Sling, que está definido como /libs,/apps
por padrão. O uso do caminho absoluto pode introduzir defeitos sutis que só apareceriam posteriormente no ciclo de vida do projeto.
public boolean dontDoThis(Resource resource) {
return resource.isResourceType("/libs/foundation/components/text");
}
public void doThis(Resource resource) {
return resource.isResourceType("foundation/components/text");
}
Não use o Sling Scheduler para tarefas que exigem uma execução garantida. Os processos agendados no Sling têm execução garantida e são mais adequados para ambientes clusterizados e não clusterizados.
Consulte a documentação Eventos e manuseio de processos do Apache Sling para saber mais sobre como os processos do Sling são tratados em ambientes clusterizados.
A superfície da API do Experience Manager está em constante revisão para identificar APIs cujo uso não é recomendado e, portanto, são consideradas obsoletas.
Geralmente, essas APIs são descontinuadas usando a anotação padrão Java™ @Deprecated
e, sendo assim, são identificadas por squid:CallToDeprecatedMethod
.
No entanto, há casos em que uma API é descontinuada no contexto do Experience Manager mas pode não ser descontinuada em outros contextos. Esta regra identifica essa segunda classe.
O projeto Apache Sling desencoraja o uso da variável @Inject
anotação no contexto de Modelos Sling, pois pode levar a um desempenho inadequado quando combinado com o DefaultInjectionStrategy.OPTIONAL
(no nível de campo ou de classe). Em vez disso, injeções mais @ValueMapValue
ou @OsgiInjector
anotações) devem ser usadas.
Verifique a Documentação do Apache Sling para obter mais informações sobre as anotações recomendadas e por que essa recomendação foi feita em primeiro lugar.
Os aplicativos do AEM muitas vezes alcançam outros aplicativos usando o protocolo HTTP, e o Apache HttpClient é uma biblioteca frequentemente usada para fazer isso. Mas a criação desse objeto HttpClient vem com alguma sobrecarga, de modo que esses objetos devem ser reutilizados o máximo possível.
Essa regra verifica se esse objeto HttpClient não é privado em um método, mas global em um nível de classe, para que possa ser reutilizado. Nesse caso, o campo httpClient deve ser definido no construtor da classe ou na variável activate()
(se essa classe for um componente/serviço OSGi).
Verifique a Guia de otimização do HttpClient para obter algumas práticas recomendadas relacionadas ao uso do HttpClient.
public void doHttpCall() {
HttpClient httpclient = HttpClients.createDefault();
// do something with the httpclient
}
public class myClass {
HttpClient httpclient;
public void doHttpCall() {
// do something with the httpclient
}
}
A seção a seguir especifica as verificações do OakPAL executadas pelo Cloud Manager.
O OakPAL é uma estrutura que valida pacotes de conteúdo usando um repositório Oak autônomo. Ele foi desenvolvido por um parceiro do Experience Manager e vencedor do prêmio Experience Manager Rockstar North America de 2019.
A API do Experience Manager contém interfaces e classes do Java™ que devem ser usadas, mas não implementadas, apenas pelo código personalizado. Por exemplo, a interface com.day.cq.wcm.api.Page
deve ser implementada somente pelo Experience Manager.
Quando novos métodos são adicionados a essas interfaces, esses métodos adicionais não afetam o código existente que usa essas interfaces. Como resultado, a adição de novos métodos a essas interfaces é considerada compatível com versões anteriores. No entanto, se o código personalizado implementa uma dessas interfaces, ele apresenta um risco de compatibilidade com versões anteriores para o cliente.
As interfaces e as classes, conforme implementadas pelo Experience Manager, são anotadas com org.osgi.annotation.versioning.ProviderType
ou, às vezes, com a anotação herdada semelhante: aQute.bnd.annotation.ProviderType
. Esta regra identifica os casos em que essa interface é implementada ou em que uma classe é estendida por código personalizado.
import com.day.cq.wcm.api.Page;
public class DontDoThis implements Page {
// implementation here
}
Vários índices do Oak prontos para uso no Experience Manager incluem uma configuração do Tika, e as personalizações desses índices devem incluir uma configuração do Tika. Essa regra verifica as personalizações do damAssetLucene
e lucene
, e o graphqlConfig
indexa e gera um problema se o nó tika
estiver ausente ou se o nó tika
não tiver um nó secundário chamado config.xml
.
Consulte a documentação de indexação para obter mais informações sobre como personalizar as definições de índice.
+ oak:index
+ damAssetLucene-1-custom
- async: [async]
- evaluatePathRestrictions: true
- includedPaths: /content/dam
- tags: [visualSimilaritySearch]
- type: lucene
+ oak:index
+ damAssetLucene-1-custom-2
- async: [async]
- evaluatePathRestrictions: true
- includedPaths: /content/dam
- tags: [visualSimilaritySearch]
- type: lucene
+ tika
+ config.xml
Os índices Oak do tipo lucene
sempre devem ser indexados de forma assíncrona. Caso contrário, poderá ocorrer instabilidade no sistema. Mais informações sobre a estrutura dos índices Lucene podem ser encontradas na documentação do Oak.
+ oak:index
+ damAssetLucene-1-custom
- evaluatePathRestrictions: true
- includedPaths: /content/dam
- type: lucene
- tags: [visualSimilaritySearch]
+ tika
+ config.xml
+ oak:index
+ damAssetLucene-1-custom-2
- async: [async]
- evaluatePathRestrictions: true
- includedPaths: /content/dam
- tags: [visualSimilaritySearch]
- type: lucene
+ tika
+ config.xml
Para que a pesquisa de ativos funcione corretamente no Experience Manager Assets, as personalizações de damAssetLucene
do índice Oak devem seguir um conjunto de diretrizes específicas desse índice. Essa regra verifica se a definição do índice deve ter uma propriedade de vários valores chamada tags
, que contém o valor visualSimilaritySearch
.
+ oak:index
+ damAssetLucene-1-custom
- async: [async, nrt]
- evaluatePathRestrictions: true
- includedPaths: /content/dam
- type: lucene
+ tika
+ config.xml
+ oak:index
+ damAssetLucene-1-custom-2
- async: [async, nrt]
- evaluatePathRestrictions: true
- includedPaths: /content/dam
- tags: [visualSimilaritySearch]
- type: lucene
+ tika
+ config.xml
Considerar a árvore de conteúdo do /libs
no repositório de conteúdo do Experience Manager como somente leitura pelos clientes é uma prática recomendada de longa data. A modificação dos nós e propriedades em /libs
cria riscos significativos para atualizações importantes e secundárias. Modificações em /libs
devem ser realizadas pela Adobe através dos canais oficiais.
Um problema comum que ocorre em projetos complexos é quando um mesmo componente OSGi é configurado várias vezes. Esse problema cria uma ambiguidade sobre qual configuração é aplicável. Essa regra age de acordo com o modo de execução, no sentido de que ela apenas identifica problemas em que o mesmo componente é configurado várias vezes no mesmo modo de execução ou combinação de modos de execução.
A regra gera problemas quando uma mesma configuração, em um mesmo caminho, é definida em vários pacotes, incluindo casos em que o mesmo pacote é duplicado na lista geral de pacotes incorporados.
Por exemplo, se a compilação produzir pacotes chamados com.myco:com.myco.ui.apps
e com.myco:com.myco.all
, nos quais com.myco:com.myco.all
incorpora com.myco:com.myco.ui.apps
, então todas as configurações em com.myco:com.myco.ui.apps
serão relatadas como duplicadas.
Em geral, esse é um caso em que não se deve seguir as Diretrizes de estrutura de pacotes de conteúdo. Neste exemplo específico, o pacote com.myco:com.myco.ui.apps
não inclui a propriedade <cloudManagerTarget>none</cloudManagerTarget>
.
+ apps
+ projectA
+ config
+ com.day.cq.commons.impl.ExternalizerImpl
+ projectB
+ config
+ com.day.cq.commons.impl.ExternalizerImpl
+ apps
+ shared-config
+ config
+ com.day.cq.commons.impl.ExternalizerImpl
Por motivos de segurança, os caminhos que contêm /config/
e /install/
só podem ser lidos por usuários administrativos no Experience Manager e devem ser usados apenas para configuração do OSGi e de pacotes do OSGi. Colocar outros tipos de conteúdo em caminhos que contêm esses segmentos resultará em uma variação incontrolável e não intencional do comportamento do aplicativo entre usuários administrativos e não administrativos.
Um problema comum é o uso de nós chamados config
nas caixas de diálogo de componente ou ao especificar a configuração do editor rich text para edição em linha. Para solucionar esse problema, o nó incorreto deve ser renomeado para um nome que esteja em conformidade. Para configurar o editor de rich text, use a propriedade configPath
do nó cq:inplaceEditing
para especificar o novo local.
+ cq:editConfig [cq:EditConfig]
+ cq:inplaceEditing [cq:InplaceEditConfig]
+ config [nt:unstructured]
+ rtePlugins [nt:unstructured]
+ cq:editConfig [cq:EditConfig]
+ cq:inplaceEditing [cq:InplaceEditConfig]
./configPath = inplaceEditingConfig (String)
+ inplaceEditingConfig [nt:unstructured]
+ rtePlugins [nt:unstructured]
Semelhante à regra Pacotes não devem conter configurações OSGi duplicadas, esse é um problema comum em projetos complexos, em que o mesmo caminho de nó é gravado por vários pacotes de conteúdo separados. Embora seja possível usar as dependências do pacote de conteúdo para garantir um resultado consistente, é melhor evitar qualquer sobreposição.
A configuração com.day.cq.wcm.core.impl.AuthoringUIModeServiceImpl
do OSGi define o modo de criação padrão no Experience Manager. Visto que a interface clássica foi descontinuada no Experience Manager 6.4, um problema será gerado se o modo de criação padrão estiver configurado para usá-la.
Os componentes do Experience Manager que têm uma caixa de diálogo da interface clássica devem sempre ter uma caixa de diálogo da interface de toque correspondente. Utilizar ambas fornece uma experiência de criação ideal e garante compatibilidade com o modelo de implantação do Cloud Service, onde a interface clássica não é compatível. Essa regra verifica os seguintes cenários:
dialog
) deve ter uma caixa de diálogo da interface do usuário de toque correspondente (ou seja, um nó secundário cq:dialog
).design_dialog
) deve ter uma caixa de diálogo de design com interface de toque correspondente (ou seja, um nó secundário cq:design_dialog
).A documentação das Ferramentas de modernização do Experience Manager fornece a documentação e as ferramentas para converter componentes da interface clássica para a interface sensível ao toque. Consulte a documentação das Ferramentas de modernização do Experience Manager para obter mais detalhes.
Para serem compatíveis com o modelo de implantação do Cloud Service, os pacotes de conteúdo individuais devem ter conteúdo para áreas imutáveis do repositório (/apps
e /libs
) ou para a área mutável (tudo que não esteja em /apps
ou /libs
), mas não ambos. Por exemplo, um pacote que inclui /apps/myco/components/text
e /etc/clientlibs/myco
não é compatível com o Cloud Service e fará com que um erro seja relatado.
A regra Pacotes de clientes não devem criar ou modificar nós em /libs sempre se aplica.
Consulte a Estrutura de projetos do Experience Manager para obter mais detalhes.
A compatibilidade com a replicação reversa não está disponível em implantações do Cloud Service, conforme descrito nas notas de versão do Experience Manager as a Cloud Service.
Os clientes que usam replicação reversa devem entrar em contato com a Adobe para obter soluções alternativas.
As bibliotecas de cliente do Experience Manager podem conter recursos estáticos, como imagens e fontes. Conforme descrito no documento Utilização de pré-processadores, ao usar bibliotecas de clientes por proxy, esses recursos estáticos devem estar contidos em uma pasta secundária chamada resources
, a fim de que sejam efetivamente referenciados nas instâncias de publicação.
+ apps
+ projectA
+ clientlib
- allowProxy=true
+ images
+ myimage.jpg
+ apps
+ projectA
+ clientlib
- allowProxy=true
+ resources
+ myimage.jpg
Com a mudança para os microsserviços de processamento de ativos no Experience Manager as a Cloud Service, vários processos de fluxo de trabalho que eram usados nas versões locais e de AMS do Experience Manager se tornaram incompatíveis ou desnecessários.
A ferramenta de migração do repositório de ativos do Experience Manager as a Cloud Service no GitHub pode ser usada para atualizar modelos de fluxo de trabalho durante a migração para o Experience Manager as a Cloud Service.
Embora o uso de modelos estáticos seja historicamente comum em projetos do Experience Manager, a Adobe recomenda usar modelos editáveis porque eles fornecem mais flexibilidade e são compatíveis com recursos adicionais não presentes em modelos estáticos. Mais informações podem ser encontradas no documento Modelos de página.
A migração de modelos estáticos para modelos editáveis pode ser quase totalmente automatizada usando as ferramentas de modernização do Experience Manager.
Os componentes fundamentais herdados (ou seja, localizados em /libs/foundation
) foram descontinuados em várias versões do Experience Manager para incentivar o uso dos componentes principais. O uso dos componentes básicos como base para os componentes personalizados (seja por sobreposição ou herança) não é recomendado e deve ser convertido para os componentes principais correspondentes.
Essa conversão pode ser facilitada pelas ferramentas de modernização do Experience Manager.
O Experience Manager as a Cloud Service utiliza uma política de nomeação rigorosa para nomes de modo de execução e uma ordenação estrita para eles. A lista de modos de execução compatíveis pode ser encontrada no documento Implantação no Experience Manager as a Cloud Service, e qualquer desvio em relação a isso será identificado como um problema.
O Experience Manager as a Cloud Service exige que as definições do índice de pesquisa personalizado (ou seja, nós do tipo oak:QueryIndexDefinition
) sejam nós secundários diretos de /oak:index
. Os índices em outros locais devem ser movidos para serem compatíveis com o Experience Manager as a Cloud Service. Mais informações sobre índices de pesquisa podem ser encontradas no documento Pesquisa e indexação de conteúdo.
O Experience Manager as a Cloud Service exige que as definições do índice de pesquisa personalizado (ou seja, nós do tipo oak:QueryIndexDefinition
) tenham a propriedade compatVersion
definida como 2
. Nenhum outro valor é compatível com o Experience Manager as a Cloud Service. Mais informações sobre índices de pesquisa podem ser encontradas em Pesquisa e indexação de conteúdo.
Problemas difíceis de solucionar podem ocorrer quando um nó de definição do índice de pesquisa personalizado possui nós secundários desordenados. Para evitar essa situação, é recomendado que todos os nós descendentes de um nó oak:QueryIndexDefinition
sejam do tipo nt:unstructured
.
Um nó de definição de índice de pesquisa personalizada corretamente definido deve conter um nó secundário chamado indexRules
que, por sua vez, deve ter pelo menos um secundário. Mais informações podem ser encontradas na documentação do Oak.
O Experience Manager as a Cloud Service exige que as definições do índice de pesquisa personalizado (ou seja, nós do tipo oak:QueryIndexDefinition
) sejam nomeadas de acordo com um padrão específico descrito no documento Pesquisa e indexação de conteúdo.
O Experience Manager as a Cloud Service exige que as definições do índice de pesquisa personalizado (ou seja, nós do tipo oak:QueryIndexDefinition
) tenham uma propriedade type
cujo valor esteja definido como lucene
. Uma indexação que utiliza tipos de índice herdados deve ser atualizada antes da migração para o Experience Manager as a Cloud Service. Consulte o documento Pesquisa e indexação de conteúdo para obter mais informações.
O Experience Manager as a Cloud Service proíbe que as definições do índice de pesquisa personalizado (ou seja, nós do tipo oak:QueryIndexDefinition
) contenham uma propriedade chamada seed
. Uma indexação que utiliza essa propriedade deve ser atualizada antes da migração para o Experience Manager as a Cloud Service. Consulte o documento Pesquisa e indexação de conteúdo para obter mais informações.
O Experience Manager as a Cloud Service proíbe que as definições do índice de pesquisa personalizado (ou seja, nós do tipo oak:QueryIndexDefinition
) contenham uma propriedade chamada reindex
. Uma indexação que utiliza essa propriedade deve ser atualizada antes da migração para o Experience Manager as a Cloud Service. Consulte o documento Pesquisa e indexação de conteúdo para obter mais informações.
+ oak:index
+ damAssetLucene-1-custom-1
- async: [async, nrt]
- evaluatePathRestrictions: true
- includedPaths: [/content/dam]
- queryPaths: [/content/dam]
- type: lucene
+ tika
+ config.xml
+ oak:index
+ damAssetLucene-1-custom-2
- async: [async, nrt]
- evaluatePathRestrictions: true
- includedPaths: [/content/dam]
- tags: [visualSimilaritySearch]
- type: lucene
+ tika
+ config.xml
Para índices personalizados, ambos includedPaths
e queryPaths
O deve ser configurado com valores idênticos. Se um for especificado, o outro deverá corresponder a ele. No entanto, há um caso especial para índices de damAssetLucene
, incluindo suas versões personalizadas. Para eles, você só deve fornecer includedPaths
.
Ao definir a variável nodeScopeIndex
em um tipo de nó "genérico" como nt:unstructured
ou nt:base
, você também deve especificar o includedPaths
e queryPaths
propriedades.
nt:base
pode ser considerado "genérico", pois todos os tipos de nó herdam dele. Portanto, definir um nodeScopeIndex
em nt:base
O fará indexar todos os nós no repositório. Da mesma forma, nt:unstructured
também é considerado "genérico", pois há muitos nós em repositórios desse tipo.
+ 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
+ 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
Substituir o valor padrão pode resultar em leituras de página muito lentas, especialmente quando mais conteúdo é adicionado.
+ oak:index
+ damAssetLucene-1-custom-1
...
+ damAssetLucene-1-custom-2
...
+ damAssetLucene-1-custom-3
...
+ damAssetLucene-1-custom-3
...
O padrão esperado para nomes de índice totalmente personalizados é: [prefix].[indexName]-custom-[version]
. Mais informações podem ser encontradas no documento Pesquisa e indexação de conteúdo.
+ indexRules
+ dam:Asset
+ properties
+ status
- name: status
- analyzed: true
+ dam:cfVariationNode
+ properties
+ status
- name: status
Exemplo:
+ indexRules
+ dam:Asset
+ properties
+ status
- name: status
- analyzed: true
+ dam:cfVariationNode
+ properties
+ status
- name: status
- analyzed: true
Exemplo:
+ indexRules
+ dam:Asset
+ properties
+ status
- name: status
+ dam:cfVariationNode
+ properties
+ status
- name: status
- analyzed: true
Se a propriedade analisada não tiver sido explicitamente definida, seu valor padrão será false.
Para índices específicos, certifique-se de manter a propriedade das tags e seus valores atuais. Embora a adição de novos valores à propriedade de tags seja permitida, a exclusão de qualquer valor existente (ou da propriedade completamente) pode levar a resultados inesperados.