Jcms ( 20 / 22 articles - Voir la liste )

Astuce Impossible de trouver mon nouveau skin dans JCMS

Je viens de créer un nouveau skin dans JCMS, mais malgré un redémarrage ou le vidage du work de tomcat, il n'apparaît pas dans la liste de choix du skin de mes portlets.

Par défaut, pour ajouter un nouveau skin il suffit de créer la jsp et de la déclarer dans le fichier plugin.xml. Par exemple :

<types>
    <templates type="AbstractPortletSkinable">
       <template name="newSkin" file="doNewSkin.jsp" usage="box">
             <label xml:lang="en">My new skin</label>
             <label xml:lang="fr">Mon nouveau skin</label>
       </template>
    </templates>
</type>

Il existe cependant un option méconnue dans le CMS : la possibilité d'activer des skins différents pour chaque espace de travail.

Pour cela :

  • Choisissez un espace de travail en back-offfice
  • Allez dans l'Espace d'administration fonctionnelle > Types de publication > Portlet
  • Éditez [Abstract] Portlet Skinable.
  • Cochez les skins à activer dans l'espace de travail

Par défaut dans JCMS, aucun n'est coché. Tous les nouveaux skins sont donc immédiatement disponibles.

Mais à partir du moment où l'un d'eux est coché, vous devrez repasser par cette interface à chaque création de skin pour l'activer manuellement.

Astuce Autoriser plusieurs soumissions de formulaire

Par mesure de sécurité, JCMS limite le nombre de soumissions des formulaires. Il faut attendre environ une minute entre chaque soumission.

Ce comportement peut-être éviter en ajoutant cette classe css sur la balise form du formulaire : noSingleSubmitButton.

Astuce Afficher une erreur dans JCMS

Dans JCMS (7 et +) les erreurs sont affichées dans un bloc ressemblant à ça.

Affichage d'une erreur dans JCMS

Transmettre le message

Vous devez tout d'abord transmettre votre message à JCMS.

  • Si vous êtes dans une JSP, utilisez l'une ou l'autre de ces méthodes :
// Ajoute un message d'erreur dans la request
setErrorMsg("Le téléchargement du document a échoué", request);

// Ajoute un message d'erreur dans la session
setErrorMsgSession("Le téléchargement du document a échoué", request);
  • Pour faire la même chose dans une classe Java, utilisez l'une de celles-ci :
    // Ajoute un message d'erreur dans la request
    JcmsContext.setErrorMsg("An error occured while saving your content", request);

    // Ajoute un message d'erreur dans la session
    JcmsContext.setErrorMsgSession("An error occured while saving your content", request);

Remarque :

Des méthodes équivalentes existent pour les messages d'information et d'avertissement.

Afficher le message

Une fois le message transmis, il reste à l'afficher. Il suffit pour cela d'inclure ce bout de code :

<%@ include file='/jcore/doMessageBox.jsp' %>

Cette JSP fournie par JCMS, va récupérer tous les messages d'information, d'avertissement ou d'erreur présents en session, dans les paramètres de la request et dans le contexte de la page. Chaque message trouvé est affiché.

Remarque :

Depuis la version 7.1 JCMS utilise Bootstrap. Si vous êtes en version antérieure, le message d'erreur ne ressemblera pas à celui ci-dessus.

Astuce Ordre des champs en ExtraData

Lors de l'affichage des champs en ExtraData, JCMS utilise l'ordre l'alphabétique des clés des propriétés d'ExtraData.

Si votre plugin.prop contient les propriétés suivantes :

extra.Category.jcmsplugin.monplugin.premierchamp
extra.Category.jcmsplugin.monplugin.champ2
extra.Category.jcmsplugin.monplugin.champ3
extra.Category.jcmsplugin.monplugin.dernierchamp

Les champs s'afficheront dans cet ordre en back-office :

  • champ2
  • champ3
  • dernierchamp
  • premierchamp

Astuce Rétablir le mot de passe admin par défaut

Si vous avez perdu le mot passe administrateur, ou si vous souhaitez le modifier directement dans le store, ajoutez une ligne de la forme suivante à la fin :

<member stamp="j_99999" id="j_2" op="update" author="" mdate="1091526019085" mobile="" name="Admin" password="ISMvKXpXpadDiUoOSoAfww==" />

Cette ligne remplace le mot de passe actuel par admin.

Remarques :

  • Remplacez la valeur de stamp par la même valeur que votre dernière ligne de store, en l'incrémentant.
  • Faites de même pour la date de modification (mdate).

JPlatform 10 (merci Axel pour cette MAJ)

Sur JPlatform 10, le chiffrement des mots de passe a changé. La ligne à ajouter pour le réinitialiser devient :

<member stamp="agi_7217" id="j_2" op="update" mdate="1528122795429" login="admin" name="Admin" password="$2a$10$gbCw7UaAI1kL7PXqodTY9OmzqsdFBufD063oG6ebQT/Zi2PBELX56" />

Astuce Le logger dans JCMS : log4j

Par défaut, JCMS utilise log4j pour gestionnaire de logs.

Utilisation générale de log4j

Voici comment l'utiliser dans une classe :

public class MyClass {

    /** Logger log4j */
    private static final Logger logger = Logger.getLogger(MyClass.class);

    public MyClass() {
        logger.info("Je suis dans le constructeur par défaut de ma classe.");
    }

Explications :

  • Déclarez un nouvel attribut de classe statique qui utilise la méthode getLogger() de log4j.
  • Passez votre classe en argument de cette méthode.
  • Utilisez le logger en appelant ses méthodes debug(), info(), warn(), error() ou fatal(), avec le message en argument, plus éventuellement une exception.

Configuration de log4j

Log4j est configuré via le fichier log4j.xml. Dans JCMS, ce fichier se trouve dans WEB-INF/data/.

Si dans un nouveau projet JCMS vous créez un package pour y mettre vos classes Java, il est probable que les logs ne fonctionnent pas. En effet, log4j n'a pas connaissance de ce nouveau package.

Pour l'en informer, éditez le fichier log4j.xml et ajoutez :

<!-- Logger de classes personnalisées --> 
<logger name="mon.package" additivity="false">
    <level value="DEBUG" />
    <appender-ref ref="JCMS" />
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="LOGFILE" />
    <appender-ref ref="PLUGIN" />
</logger>

Explications :

  • L'attribut name définit pour quels packages utiliser log4j. (Les sous-packages seront automatiquement logués.)
  • L'attribut value de l'élément <level> permet de déterminer quel niveau de log appliquer. En développement on utilise souvent DEBUG ou INFO alors qu'en production on se contentera de INFO ou WARN. Concrètement, avec le niveau WARN, les méthodes logger.debug() et logger.info() n'auront aucun effet (suivant cet ordre : debug < info < warn < error < fatal).
  • Les <appender> sont les sorties à utiliser : fichier de log, console, ...
  • Vous pouvez déclarer autant de logger que vous le souhaitez dans le fichier log4j.xml.

Astuce Utiliser un logger dans les classes de test

Dans vos classes de test, vous pouvez utiliser le gestionnaire de log slf4j Il s'agit d'une façade qui peut utiliser plusieurs loggers au choix, comme log4j par exemple.

Voici comment utiliser ce gestionnaire :

public class MyClassTest extends JcmsTestCase {

    /** Logger **/
    private static Logger logger;

    /**
     * Initialise un contexte pour une suite de tests, avec des méthodes d'initialisation et de finalisation.
     * 
     * @return une configuration de suite de tests
     */
    public static TestSetup suite() {

        return new TestSetup(new TestSuite(MyClassTest.class)) {

            @BeforeClass
            @Override
            protected void setUp() throws Exception {

                logger = LoggerFactory.getLogger(MyClassTest.class);
                logger.debug("Début des tests unitaires pour la classe " + MyClass.class.getSimpleName() + ".");
            }
            @AfterClass
            @Override
            protected void tearDown() throws Exception {
                logger.debug("Fin des tests unitaires.");
            }
        };
    }

Explications :

  • Déclarez le logger dans votre classe de test.
  • Créez la méthode statique suite(), pour pouvoir initialiser des éléments au début des tests.
  • Utilisez la méthode LoggerFactory.getLogger(), pour initialiser le logger.
  • Utilisez le logger comme avec log4j (ex : logger.info(), logger.debug(), ...).

Remarque :

Pour pouvoir utiliser slf4j avec log4j, vous devez inclure ces deux jars dans votre projet : slf4j-api-1.5.8.jar et slf4j-log4j12-1.5.8.jar.

Astuce Récupérer la version antérieure d'une Data, dans un DataController

Si vous avez besoin de comparer l'ancienne et la nouvelle version d'une Data, dans un DataController (par exemple dans afterWrite()), vous aurez besoin d'utiliser le contexte en paramètre de la méthode.

Pour obtenir cette version, utilisez quelque chose comme :

final Article oldArticle = (Article) context.get("Data.previous");

Astuce Les variables disponibles dans le contexte, pour les DataController

Lorsque vous créez un DataController et que vous surchargez les méthodes beforeWrite(), checkWrite() et afterWrite(), le dernier paramètre de la méthode (la Map), contient tout le contexte disponible.

Dans cette variable il y a notamment :

  • request : L'objet HttpServletRequest de tomcat.
  • response : L'objet HttpServletResponse de tomcat.
  • formHandler : Le FormHandler utilisé lors de l'édition du contenu.

Et dans le cas d'une modification de donnée, il y a également :

  • Data.previous : La dernière version de la Data avant modification.

Astuce Vider toutes les tables de la base de données Derby

Si vous utilisez Derby dans vos tests unitaires, vous aurez sans doute besoin de réinitialiser votre base entre chaque test.

Pour supprimer le contenu de toutes les tables d'un coup, vous pouvez utiliser cette fonction :

/**
 * Vide toutes les tables de la base de données, dont le nom commence par "G_" ou "J_".
 * 
 * @throws SQLException
 */
public static void derbyClearAllTables() throws SQLException {

    ResultSet tables;
    Statement stat;

    final String schema = "jdbc:derby:jcmsdbunit";

    // Récupération de la liste des tables de la base de données
    final Connection connection = DriverManager.getConnection(schema);
    tables = connection.getMetaData().getTables(null, null, null, null);

    final Set<String> tableNameSet = new HashSet<String>();

    // Parcours des tables de la base de données
    while (tables.next()) {

        final String tableName = tables.getString("TABLE_NAME");

        if (tableName.startsWith("G_") || tableName.startsWith("J_")) {

            tableNameSet.add(tableName);
        }
    }

    // Parcours des tables à vider
    for (final String tableName : tableNameSet) {

        // Nettoyage de la table
        stat = connection.createStatement();
        stat.executeUpdate("DELETE FROM " + tableName);
        connection.commit();
    }

    if (!tables.isClosed()) {
        tables.close();
    }
}

Remarque :

Les tables ne commençant ni par G_ ni par J_ sont probablement des tables utiles au fonctionnement interne de Derby. Elles ne sont pas à vider.

Astuce Méthode d'initialisation au début de la classe de test

Pour effectuer un traitement une fois au début des tests, on utilise généralement la méthode suivante dans la classe de test :

@BeforeClass
public static void oneTimeSetUp() {

    logger = LoggerFactory.getLogger(MyClassTest.class);
    logger.info("Début des tests unitaires.");
}

Cela permet d'initialiser un logger, configurer l'environnement à utiliser pour tous les tests, ...

Cette méthode ne semble pas fonctionner avec JCMS (dans eclipse en tous cas). Vous pouvez faire l'équivalent grâce à la méthode suite() à ajouter dans votre classe de test :

/**
 * Initialise un contexte pour une suite de tests, avec des méthodes d'initialisation et de finalisation.
 * 
 * @return une configuration de suite de tests
 */
public static TestSetup suite() {

    return new TestSetup(new TestSuite(MyClassTest.class)) {

        @Before
        @Override
        protected void setUp() throws Exception {
            logger = LoggerFactory.getLogger(MyClassTest.class);
            logger.info("Début des tests unitaires.");
        }

        @After
        @Override
        protected void tearDown() throws Exception {
            logger.info("Fin des tests unitaires.");
        }
    };
}

Remarque :

La méthode tearDown() permet d'effectuer un traitement une fois après tous les tests.

Erreur Erreur au démarrage de JCMS : lucene

Si votre lanceur de projet eclipse est mal configuré, vous pouvez obtenir l'erreur suivante au démarrage de JCMS, pendant l'initialisation des dépendances des plugins :

09:59:34,749 FATAL [JCMS] [ChannelInitServlet] - An exception occured while initializing JCMS. The site is not available.
java.lang.NoClassDefFoundError: org/apache/lucene/analysis/standard/StandardAnalyzer
    at java.lang.ClassLoader.defineClass1(Native Method)
    ...

Pour éviter cette erreur, vérifiez l'onglet Classpath de votre lanceur eclipse et supprimez votre projet des User Entries :

User Entries

Astuce La méthode getStringArrayProperty() de la classe Channel

Dans JCMS, la méthode getStringArrayProperty() de la classe Channel permet de récupérer un tableau de valeurs définies dans une même propriété.

Par exemple :

Channel.getChannel.getStringArrayProperty("jcmsplugin.myplugin.name-list", new String[] {})

avec dans un plugin.prop la propriété suivante :

jcmsplugin.myplugin.name-list: Jean Louis David Roger,Virgule

retournera un tableau (String[]) de quatre éléments : Jean, Louis, David et Roger,Virgule.

Remarques :

  • Le séparateur par défaut est l'espace (ou tabulation et autres chaînes d'espace)
  • Pour modifier le séparateur, il faut l'indiquer au début de la liste de valeurs, avec un @.
jcmsplugin.myplugin.name-list: @,Jean Louis David Roger,Virgule

La méthode appelée précédemment retournera cette fois un tableau de deux valeurs : Jean Louis David et Virgule.

Astuce Ouvrir un jalios:link dans une nouvelle fenêtre

JCMS fournit un tag pour créer des liens : <jalios:link>.

Pour que ce lien ouvre la cible dans une nouvelle fenêtre, il faut utiliser l'attribut htmlAttributes du tag. Par exemple :

<jalios:link data='<%= doc %>' htmlAttributes='target="_blank"' title='<%= glp("jcmsplugin.myplugin.target-blank.title") %>'>
    <%= doc.getTitle(userLang) %>
</jalios:link>

Remarque :

Pour l’accessibilité, il est conseillé de préciser l'attribut title pour informer l'utilisateur de l'ouverture dans une nouvelle fenêtre.

Astuce Simplifier l'utilisation des id dans les fichier de propriétés

JCMS permet de simplifier la récupération d'une Data à partir de son id, stocké dans un fichier de propriétés.

Par exemple, pour stocker l'id d'une catégorie et la récupérer, vous feriez

jcmsplugin.myplugin.category.my-category.id: j_6540

et

String categoryID = channel.getProperty("jcmsplugin.myplugin.category.my-category.id");
Category category = channel.getCategory(categoryID);

Utilisez

$jcmsplugin.myplugin.category.my-category.id

et

Category category = channel.getCategory("$jcmsplugin.myplugin.category.my-category.id");

Explication :

Comme son nom commence par $, JCMS sait qu'il s'agit d'une propriété contenant un id, et peut directement récupérer la Data associée.

Astuce Désactiver un module JCMS

Pour empêcher un module d'être chargé au démarrage de JCMS, modifiez son plugin.xml.

Passez l'attribut initialize de l'élément racine à false.

Astuce Utiliser l'ajax-refresh pour recharger un élément du DOM

JCMS intègre un framework pour utiliser de l'AJAX dans les pages d'un site.

Pour recharger un élément du DOM à partir d'une jsp, voici le code à utiliser :

var id          = 'mon_element';
var url         = 'plugins/MonPlugin/jsp/ajax/maJsp.jsp';
var value       = $(id).value;
var params      = 'key=' + value;

// Rechargement de l'élément
JCMS.ajax.Refresh._refresh(id, url, {
    history: false,
    formParams: params
});
  • L'id est celui de l'élément dont le contenu doit être rechargé (innerHTML).
  • L'url est le chemin vers la jsp (et pas jspf) qui génère le contenu.
  • params est la liste des paramètres à ajouter à l'url, qui pourront être récupérés dans la jsp appelée :
String keyValue = request.getParameter("key");

Astuce Ne pas compiler les .less à chaque démarrage

Si vous n'utilisez pas les fichiers .less dans vos modules et que vous ne modifiez pas ceux de JCMS, il est inutile de les recompiler à chaque redémarrage, car les fichiers .css générés ne changeront pas.

Pour éviter cette compilation automatique, ajoutez cette propriété au custom.prop :

channel.less-compile.startup: false

Erreur javac/Main introuvable au lancement de la webapp

Lorsque vous lancer une application JCMS avec tomcat 1.5, vous pouvez avoir cette erreur :

java.lang.NoClassDefFoundError: com/sun/tools/javac/Main

Elle signifie qu'il manque l'archive tools.jar au classpath.

Pour l'ajouter à votre projet au lancement de l'application, effectuez ces quelques étapes :

  • Clic-droit sur le projet
  • Run As > Run Configurations...
  • Onglet Classpath
  • Cliquez sur User Entries puis sur le bouton Advanced...
  • Sélectionnez Add Variable String:
  • Copiez-collez le chemin vers le fichier tools.jar qui se trouve dans le répertoire lib/ de votre jdk (ex: D:\Dev\DevPack\jdk\lib\tools.jar)