Intégrer des services à la console JMX integrating-services-with-the-jmx-console

CAUTION
AEM 6.4 a atteint la fin de la prise en charge étendue et cette documentation n’est plus mise à jour. Pour plus d’informations, voir notre période de support technique. Rechercher les versions prises en charge here.

Créez et déployez des MBeans pour gérer les services à l’aide de la console JMX. Exposez les attributs et les opérations de service pour permettre l’exécution des tâches d’administration.

Pour plus d’informations sur l’utilisation de la console JMX, voir Surveillance des ressources du serveur à l’aide de la console JMX.

La structure JMX dans Felix et CQ5 the-jmx-framework-in-felix-and-cq

Sur la plateforme Apache Felix, vous déployez MBeans en tant que services OSGi. Lorsqu’un service MBean est enregistré dans le registre de service OSGi, le module Aries JMX Whiteboard enregistre automatiquement le MBean avec le serveur MBean. Le MBean est alors disponible pour la console JMX qui expose les attributs et opérations publics.

jmxwhiteboard

Création de MBeans pour CQ5 et CRX creating-mbeans-for-cq-and-crx

Les MBeans que vous créez pour gérer les ressources CQ5 ou CRX sont basés sur l’interface javax.management.DynamicMBean. Pour les créer, vous suivez les modèles de conception habituels définis dans la spécification JMX :

  • Créez l’interface de gestion, y compris les méthodes get, set et is pour définir les attributs et d’autres méthodes pour définir les opérations.
  • Créez la classe d’implémentation. La classe doit implémenter DynamicMBean ou étendre une classe d’implémentation de DynamicMBean.
  • Respectez la convention d’affectation de nom standard afin que le nom de la classe d’implémentation soit le nom de l’interface avec le suffixe MBean.

En plus de configurer l’interface de gestion, l’interface paramètre également l’interface de service OSGi. La classe d’implémentation met en oeuvre le service OSGi.

Utilisation d’annotations pour fournir des informations MBean using-annotations-to-provide-mbean-information

Le package module com.adobe.granite.jmx.annotation offre plusieurs annotations et classes pour fournir facilement des métadonnées MBean à la console JMX. Utilisez ces annotations et classes au lieu d’ajouter des informations directement à l’objet MBeanInfo du MBean.

Annotations

Ajoutez des annotations à l’interface de gestion pour spécifier les métadonnées MBean. Les informations apparaissent dans la console JMX pour chaque classe d’implémentation déployée. Les annotations suivantes sont disponibles (pour plus d’informations, reportez-vous à la section com.adobe.granite.jmx.annotation JavaDocs) :

  • Description : fournit une description de la classe ou de la méthode MBean. Lorsqu’elle est utilisée dans la déclaration de classe, la description est visible dans la page de la console JMX pour le MBean. Lorsqu’elle est utilisée sur une méthode, la description s’affiche sous forme de texte de survol pour l’attribut ou l’opération correspondant.

  • Impact :  répercussions d’une méthode. Les valeurs de paramètre valides sont les champs définis par javax.management.MBeanOperationInfo.

  • Nom : spécifie le nom à afficher pour un paramètre d’opération. Utilisez cette annotation pour remplacer le nom réel du paramètre de méthode utilisé dans l’interface.

  • OpenTypeInfo  : spécifie la classe à utiliser pour représenter les données composites ou les données tabulaires dans la console JMX. Utilisation avec les MBeans ouverts

  • TabularTypeInfo: Utilisé pour annoter la classe utilisée pour représenter les données tabulaires.

Classes

Les classes sont fournies pour la création de MBeans dynamiques qui utilisent les annotations que vous ajoutez à leurs interfaces :

  • AnnotatedStandardMBean : Sous-classe de la classe javax.management.StandardMBean qui fournit automatiquement à la console JMX les métadonnées d’annotation.
  • OpenAnnotatedStandardMBean : sous-classe de la classe AnnotatedStandardMBean qui sert à créer des MBeans ouverts utilisant l’annotation OpenTypeInfo.

Développement de MBeans developing-mbeans

En règle générale, le MBean reflète le service OSGi que vous souhaitez gérer. Sur la plateforme Felix, vous créez le MBean comme vous le feriez pour le déploiement sur d’autres plates-formes de serveur Java. La Principale différence réside dans le fait que vous pouvez utiliser des annotations pour spécifier les informations MBean :

  • Interface de gestion : définit les attributs à l’aide des méthodes getter, setter et is. Définit les opérations à l’aide de toute autre méthode publique. Utilise des annotations afin de fournir des métadonnées pour l’objet BeanInfo.
  • Classe MBean : Implémente l’interface de gestion. Étend la classe AnnotatedStandardMBean afin qu’elle traite les annotations sur l’interface.

L’exemple suivant MBean fournit des informations sur le référentiel CRX. L’interface utilise l’annotation Description pour fournir des informations à la console JMX.

Interface de gestion management-interface

package com.adobe.example.myapp;

import com.adobe.granite.jmx.annotation.Description;

@Description("Example MBean that exposes repository properties.")
public interface ExampleMBean {

    @Description("The name of the repository.")
    String getRepositoryName();

    @Description("The vendor of the repository.")
    String   getRepositoryVendor();

    @Description("The URL of repository vendor.")
    String getVendorUrl();
}

La classe d’implémentation utilise le service SlingRepository pour récupérer des informations sur le référentiel CRX.

Classe d’implémentation MBean mbean-implementation-class

package com.adobe.example.myapp;

import org.apache.felix.scr.annotations.*;
import org.apache.sling.jcr.api.SlingRepository;

import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;

import javax.management.*;

public class ExampleMBeanImpl extends AnnotatedStandardMBean implements ExampleMBean {

    @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
    private SlingRepository repository;

    public ExampleMBeanImpl() throws NotCompliantMBeanException {
        super(ExampleMBean.class);
    }

    public String getRepositoryName() {
        return repository.getDescriptor("jcr.repository.name");
    }

    public String getRepositoryVendor() {
        return repository.getDescriptor("jcr.repository.vendor");
    }

    public String getVendorUrl() {
        return repository.getDescriptor("jcr.repository.vendor.url");
    }
}

Le graphique suivant montre la page de ce MBean dans la console JMX.

jmxdescription

Enregistrement des MBeans registering-mbeans

Lorsque vous enregistrez des MBeans en tant que service OSGi, ils sont automatiquement enregistrés avec le serveur MBean. Pour installer un MBean sur CQ5, incluez-le dans un lot et exportez le service MBean comme vous le feriez pour tout autre service OSGi.

Outre les métadonnées liées à OSGi, vous devez également fournir les métadonnées requises par le module Aries JMX Whiteboard pour enregistrer le MBean auprès du serveur MBean :

  • Nom de l’interface DynamicMBean : déclarez que le service MBean implémente l’interface javax.management.DynamicMBean. Cette déclaration indique au module Aries JMX Whiteboard que le service est un service MBean.

  • Propriétés du domaine et de la clé MBean : sur Felix, cette information est entrée en tant que propriété du service OSGi du MBean. Il s’agit des informations similaires à celles que vous fournissez habituellement au serveur MBean dans un objet javax.management.ObjectName.

Lorsque votre MBean reflète un service unique, une seule instance du service MBean est requise. Dans ce cas, si vous utilisez le module externe Felix SCR Maven, vous pouvez utiliser les annotations SCR (Apache Felix Service Component Runtime) sur la classe d’implémentation MBean pour spécifier les métadonnées associées à JMX. Pour instancier plusieurs instances MBean, vous pouvez créer une autre classe qui effectue cet enregistrement du service OSGi du MBean. Dans ce cas, les métadonnées liées à JMX sont générées au moment de l’exécution.

MBean unique

Les MBeans pour lesquels vous pouvez définir tous les attributs et toutes les opérations au moment de la conception peuvent être déployés à l’aide d’annotations SCR dans la classe d’implémentation MBean. Dans l’exemple suivant, l’attribut value de l’annotation Service déclare que le service implémente l’interface DynamicMBean. L’attribut name de l’annotation Property spécifie les propriétés de domaine et de clé JMX.

Classe d’implémentation MBean avec annotations SCR mbean-implementation-class-with-scr-annotations

package com.adobe.example.myapp;

import org.apache.felix.scr.annotations.*;
import org.apache.sling.jcr.api.SlingRepository;

import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;

import javax.management.*;

@Component(immediate = true)
@Property(name = "jmx.objectname", value="com.adobe.example:type=CRX")
@Service(value = DynamicMBean.class)
public class ExampleMBeanImpl extends AnnotatedStandardMBean implements ExampleMBean {

    @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
    private SlingRepository repository;

    public ExampleMBeanImpl() throws NotCompliantMBeanException {
        super(ExampleMBean.class);
    }

    public String getRepositoryName() {
        return repository.getDescriptor("jcr.repository.name");
    }

    public String getRepositoryVendor() {
        return repository.getDescriptor("jcr.repository.vendor");
    }

    public String getVendorUrl() {
        return repository.getDescriptor("jcr.repository.vendor.url");
    }
}

Plusieurs instances de service MBean

Pour gérer plusieurs instances d’un service géré, il convient de créer plusieurs instances du service MBean correspondant. En outre, les instances de service MBean doivent être créées ou supprimées lorsque des instances gérées sont démarrées ou arrêtées. Vous pouvez créer une classe de gestionnaire MBean pour instancier les services MBean à l’exécution et gérer le cycle de vie du service.

Utilisez BundleContext pour enregistrer le MBean en tant que service OSGi. Incluez les informations relatives à JMX dans l’objet Dictionnaire que vous utilisez comme argument de la variable BundleContext.registerService .

Dans l’exemple de code suivant, le service ExampleMBean est enregistré par programmation. L’objet componentContext est ComponentContext, qui permet d’accéder à BundleContext.

Fragment de code : Enregistrement du service MBean programmatique code-snippet-programmatic-mbean-service-registration

Dictionary mbeanProps = new Hashtable();
mbeanProps.put("jmx.objectname", "com.adobe.example:type=CRX");
ExampleMBeanImpl mbean = new ExampleMBeanImpl();
ServiceRegistration serviceregistration =
            componentContext.getBundleContext().registerService(DynamicMBean.class.getName(), mbean, mbeanProps);

L’exemple de MBean de la section suivante fournit des détails supplémentaires.

Un gestionnaire de service MBean est utile si les configurations de service sont stockées dans le référentiel. Le gestionnaire peut récupérer les informations de service et les utiliser pour configurer et créer le MBean correspondant. La classe manager peut également écouter les événements de modification du référentiel et mettre à jour les services MBean en conséquence.

Exemple : Surveillance des modèles de workflow à l’aide de JMX example-monitoring-workflow-models-using-jmx

Le MBean de cet exemple fournit des informations sur les modèles de processus CQ5 stockés dans le référentiel. Une classe de gestionnaire MBean crée des MBeans basés sur des modèles de processus stockés dans le référentiel et qui enregistrent leur service OSGi au moment de l’exécution. Cet exemple consiste en un seul lot contenant les membres suivants :

  • WorkflowMBean : Interface de gestion.
  • WorkflowMBeanImpl : Classe d’implémentation MBean.
  • WorkflowMBeanManager : Interface de la classe de gestionnaire MBean.
  • WorkflowMBeanManagerImpl : Classe d’implémentation du gestionnaire MBean.
NOTE
Pour plus de simplicité, le code de cet exemple n’effectue pas de journalisation ou ne réagit pas aux exceptions générées.

WorkflowMBeanManagerImpl inclut une méthode d’activation de composant. Lorsque le composant est activé, la méthode effectue les tâches suivantes :

  • Obtient un BundleContext pour le lot.
  • Interroge le référentiel pour obtenir les chemins d’accès des modèles de workflow existants.
  • Crée des MBeans pour chaque modèle de workflow.
  • Enregistre les MBeans avec le registre de services OSGi.

Les métadonnées MBean s’affichent dans la console JMX avec le domaine com.adobe.example , le type workflow_model et Propriétés est le chemin d’accès du noeud de configuration du modèle de workflow.

jmxworkflowmbean

Exemple de MBean the-example-mbean

Cet exemple nécessite une interface MBean et une implémentation qui se reflète sur l’interface com.day.cq.workflow.model.WorkflowModel. Le MBean est très simple. Ainsi, l’exemple peut se concentrer sur les aspects de configuration et de déploiement de la conception. Le MBean expose un seul attribut, le nom du modèle.

Interface WorkflowMBean workflowmbean-interface

package com.adobe.example.myapp.api;

import com.adobe.granite.jmx.annotation.Description;

@Description("Example MBean that exposes Workflow model properties.")
public interface WorkflowMBean {

 @Description("The name of the Workflow model.")
 String getModelName();
}

WorkflowMBeanImpl workflowmbeanimpl

package com.adobe.example.myapp.impl;

import javax.management.NotCompliantMBeanException;

import com.day.cq.workflow.model.WorkflowModel;
import com.adobe.example.myapp.api.WorkflowMBean;
import com.adobe.granite.jmx.annotation.AnnotatedStandardMBean;

public class WorkflowMBeanImpl extends AnnotatedStandardMBean implements WorkflowMBean {

 WorkflowModel model;

 protected WorkflowMBeanImpl(WorkflowModel inmodel)
   throws NotCompliantMBeanException {
  super(WorkflowMBean.class);
  model=inmodel;
 }

 public String getModelName() {
  return model.getTitle();
 }
}

Exemple de gestionnaire de MBean the-example-mbean-manager

Le service WorkflowMBeanManager inclut la méthode d’activation du composant qui crée les services WorkflowMBean. La mise en oeuvre du service comprend les méthodes suivantes :

  • activate : activateur de composant. Crée la session JCR pour lire les nœuds de configuration WorkflowModel. Le nœud racine où sont stockées les configurations du modèle est défini dans un champ statique. Le nom du nœud de configuration est également défini dans un champ statique. Cette méthode appelle d’autres méthodes qui obtiennent les chemins de modèle de noeud et créent le modèle WorkflowMBeans.
  • getModelIds: Effectue le suivi du référentiel sous le noeud racine et récupère le chemin d’accès de chaque noeud de modèle.
  • makeMBean : Utilise le chemin d’accès au modèle pour créer un objet WorkflowModel , crée un WorkflowMBean et enregistre son service OSGi.
NOTE
L’implémentation WorkflowMBeanManager crée uniquement des services MBean pour les configurations de modèle qui existent une fois le composant activé. Une implémentation plus robuste écoute les événements du référentiel concernant les nouvelles configurations de modèle et les modifications ou suppressions de la configuration de modèle existante. Lorsqu’une modification se produit, le gestionnaire peut créer, modifier ou supprimer le service WorkflowMBean correspondant.

Interface WorkflowMBeanManager workflowmbeanmanager-interface

package com.adobe.example.myapp.api;

public interface WorkflowMBeanManager {

}

WorkflowMBeanManagerImpl workflowmbeanmanagerimpl

package com.adobe.example.myapp.impl;

import java.util.*;

import org.apache.felix.scr.annotations.*;

import javax.jcr.Session;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.management.ObjectName;

import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.workflow.WorkflowService;
import com.day.cq.workflow.WorkflowSession;
import com.adobe.example.myapp.api.WorkflowMBean;
import com.adobe.example.myapp.api.WorkflowMBeanManager;

/**Instantiates and registers WorkflowMBean services */
@Component(immediate=true)
@Service(value=WorkflowMBeanManager.class)
public class WorkflowMBeanManagerImpl implements WorkflowMBeanManager {
 //The ComponentContext provides access to the BundleContext
 private ComponentContext componentContext;

 //Use the SlingRepository service to read model nodes
 @Reference
        private SlingRepository repository = null;

 //Use the WorkflowService service to create WorkflowModel objects
 @Reference
 private WorkflowService workflowservice = null;

  private Session session;

         //Details about model nodes
  private static final String MODEL_ROOT ="/etc/workflow/models";
  private static final String MODEL_NODE = "model";

  private Set<String> modelIds = new HashSet<String>();

        //Storage for ServiceRegistrations for MBean services
  private Collection<ServiceRegistration> mbeanRegistrations= new Vector<ServiceRegistration>(0,1);

 @Activate
        protected void activate(ComponentContext ctx) {
             //Traverse the repository and load the model nodes
             try {
                   session = repository.loginAdministrative(null);
                   // load and store model node paths
                   if (session.nodeExists(MODEL_ROOT)) {
                          getModelIds(session.getNode(MODEL_ROOT));
                   }
                   //Create MBeans for each model
                   for(String modid: modelIds){
                    makeMBean(modid);
                    }
             }catch(Exception e){ }
          }

        /**
         * Add JMX domain and key properties to a collection
         * Instantiate a WorkflowModel and its WorkflowMBeanImpl object
         * Register the MBean OSGi service
         */
 private void makeMBean(String modelId) {
             // create MBean for the model
             try {
                 Dictionary<String, String> mbeanProps = new Hashtable<String, String>();
                 //These properties appear on the JMX Console home page
                 mbeanProps.put("jmx.objectname", "com.adobe.example:type=workflow_model,id=" + ObjectName.quote(modelId));
                 WorkflowSession wfsession = workflowservice.getWorkflowSession(session);
                 WorkflowMBeanImpl mbean = new WorkflowMBeanImpl(wfsession.getModel(modelId));

                ServiceRegistration serviceregistration = componentContext.getBundleContext().registerService(WorkflowMBean.class.getName(), mbean, mbeanProps);
                //Store the ServiceRegistration objects for deactivation
                mbeanRegistrations.add(serviceregistration);
             } catch (Throwable t) {}
         }

        /**
         * Traverses the repository branch below a given Node. Stores the path of each model node.
         */
 private void getModelIds(Node node) throws RepositoryException {
  try{
                     NodeIterator iter = node.getNodes();
                     while (iter.hasNext()) {
                           Node n = iter.nextNode();
                           //Look for "jcr:content" nodes
                           if (n.getName().equals("jcr:content")) {
                                //get the path of the model node and save it
                                if(n.hasNode(MODEL_NODE)){
                                      modelIds.add(n.getNode(MODEL_NODE).getPath());
                                 }
                           } else{
                                   //Scan child nodes
                                   getModelIds(n);
                           }
                       }
  }catch(Exception e){ }
       }

        /**
         * Log out of the JCR session and unregister WorkflowMBean services
         */
        @Deactivate
        protected void deactivate() {
          session.logout();
          session=null;
          for(ServiceRegistration sr:mbeanRegistrations){
         sr.unregister();
          }
        }
}

Fichier POM pour l’exemple de MBean the-pom-file-for-the-example-mbean

Par souci de commodité, nous proposons de copier et de coller le code XML suivant dans le fichier pom.xml de votre projet pour créer le bundle de composants. Le POM fait référence à plusieurs dépendances et modules externes requis.

Modules externes:

  • Module externe de compilateur Apache Maven : Permet de compiler des classes Java à partir du code source.
  • Module externe Apache Felix Maven Bundle : Crée le lot et le manifeste
  • Module externe Apache Felix Maven SCR : Crée le fichier de descripteur de composant et configure l’en-tête de manifeste du composant de service.

Remarque : au moment de la rédaction de ce document, le module externe maven scr n’est pas compatible avec le module externe m2e pour Eclipse. (Voir Bogue Felix 3170.) Pour utiliser l’IDE Eclipse, installez Maven et utilisez l’interface de ligne de commande pour créer des versions.

Exemple de fichier POM example-pom-file

<project xmlns="https://maven.apache.org/POM/4.0.0"
  xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.adobe.example.myapp</groupId>
  <artifactId>workflow-mbean</artifactId>
  <version>0.0.2-SNAPSHOT</version>
  <name>mbean-simple</name>
  <url>www.adobe.com</url>
  <description>A simple MBean</description>
  <packaging>bundle</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.5</source>
                <target>1.5</target>
            </configuration>
        </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
                <version>1.7.2</version>
                <executions>
                    <execution>
                        <id>generate-scr-scrdescriptor</id>
              <goals>
                 <goal>scr</goal>
              </goals>
            </execution>
         </executions>
            </plugin>
             <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <version>1.4.3</version>
            <extensions>true</extensions>
            <configuration>
                <instructions>
                    <Export-Package>com.adobe.example.myapp.*;version=${project.version}</Export-Package>
                </instructions>
            </configuration>
        </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.scr.annotations</artifactId>
            <version>1.6.0</version>
            <scope>provided</scope>
        </dependency>
         <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.api</artifactId>
            <version>2.0.8</version>
            <scope>provided</scope>
        </dependency>
         <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.scr</artifactId>
            <version>1.6.1-R1236132</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.jcr.api</artifactId>
            <version>2.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.adobe.granite</groupId>
            <artifactId>com.adobe.granite.jmx</artifactId>
            <version>0.1.6</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
       <groupId>com.day.cq.wcm</groupId>
       <artifactId>cq-wcm-mobile-api</artifactId>
       <version>5.5.2</version>
       <scope>provided</scope>
      </dependency>
      <dependency>
       <groupId>com.day.cq.workflow</groupId>
       <artifactId>cq-workflow-api</artifactId>
       <version>5.5.0</version>
       <scope>provided</scope>
      </dependency>
      <dependency>
       <groupId>javax.jcr</groupId>
       <artifactId>jcr</artifactId>
       <version>2.0</version>
       <scope>provided</scope>
      </dependency>
      <dependency>
                <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.4</version>
  <scope>provided</scope>
 </dependency>
    </dependencies>
</project>

Ajoutez le profil suivant à votre fichier de paramètres Maven pour utiliser le référentiel public Adobe.

Profil Maven maven-profile

<profile>
    <id>adobe-public</id>
    <activation>
         <activeByDefault>false</activeByDefault>
    </activation>
    <properties>
         <releaseRepository-Id>adobe-public-releases</releaseRepository-Id>
         <releaseRepository-Name>Adobe Public Releases</releaseRepository-Name>
         <releaseRepository-URL>https://repo.adobe.com/nexus/content/groups/public</releaseRepository-URL>
    </properties>
    <repositories>
         <repository>
             <id>adobe-public-releases</id>
             <name>Adobe Basel Public Repository</name>
             <url>https://repo.adobe.com/nexus/content/groups/public</url>
             <releases>
                 <enabled>true</enabled>
                 <updatePolicy>never</updatePolicy>
             </releases>
             <snapshots>
                 <enabled>false</enabled>
             </snapshots>
         </repository>
     </repositories>
     <pluginRepositories>
         <pluginRepository>
             <id>adobe-public-releases</id>
             <name>Adobe Basel Public Repository</name>
             <url>https://repo.adobe.com/nexus/content/groups/public</url>
             <releases>
                 <enabled>true</enabled>
                 <updatePolicy>never</updatePolicy>
             </releases>
             <snapshots>
                 <enabled>false</enabled>
             </snapshots>
         </pluginRepository>
     </pluginRepositories>
</profile>
recommendation-more-help
2315f3f5-cb4a-4530-9999-30c8319c520e