Uploaded image for project: 'PUBLIC - Liferay Portal Community Edition'
  1. PUBLIC - Liferay Portal Community Edition
  2. LPS-55049

ContentTransformerListener transforms only the first <dynamic-content> in multi-language journal articles

    Details

      Description

      When rendering a journal article, a set of Transformers are applied according to the property journal.transformer.listener

      Execution order of those listeners should be irrelevant, but there is a case where it does matter. The issue is that ContentTransformer just applies to the first <dynamic-content> element. As a result, if this transformer executes before LocaleTransformer, it will apply ony to the first locale. If article is rendered in a non-default locale, LocaleTransformerListener will keep just the <dynamic-content> for that locale, which wasn't modified by ContextTransformer.

      Changing the listener order in this property does not work as it is read as a Set, therefore, order is not guaranteed across JVM implementations. Therefore, occurrence of this behavior is almost random.

      A case where this has an impact is the following:
      1. Change portal context to /newcontext
      2. Configure journal.transformer.listener so that ContentTransformer appears before LocaleTransformer (see below)
      3. Create a structure containing an Image field
      4. Create a web content from that structure. Provide an image for the default language
      5. Add a translation to another language. Make sure you provide another image
      6. Add a wcd portlet to some page and configure it to show the content
      7. Visit the page in the default language and in the other language you chose in step 5.

      Expected result:

      • The content should show the image according to the language used to render it

      Observed result:

      • The content shows the right image for the default language, but for the other it shows no image. This is due to ContentTransformer is not processing the image reference so the "/newcontext" is not being added to the image URL.

      Due to transformer application order is can't be controlled, the reported behavior can't be tested unless you force a specific order. Please execute following Beanshell script from the control panel in order to do that. Please note that nothing prevents this order to happen naturally, following code just saves testing time

      For ee-7.0.x

      import com.liferay.portal.kernel.util.SetUtil;
      import com.liferay.portal.util.PropsUtil;
      import java.util.HashSet;
      import java.util.LinkedHashSet;
      import com.liferay.portal.kernel.templateparser.TransformerListener;
      import com.liferay.portal.kernel.util.InstanceFactory;
      import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
      import java.lang.reflect.Field;
      import java.lang.reflect.Modifier;
      import com.liferay.portlet.journal.util.JournalTransformer;
      import com.liferay.portlet.journal.util.JournalUtil;
      
      // get transformerListener field from JournalTransformer, and change the modifiers
      tl = JournalTransformer.class.getDeclaredField("_transformerListeners");
      tl.setAccessible(true);
      
      modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(tl, tl.getModifiers() & ~Modifier.FINAL);
      
      // Prepare a new (sorted) set of transformers
      // make sure LocaleTransformer goes AFTER contentTransformer
      newTransformers = new LinkedHashSet();
      
      ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
      
      transformers=new String[]{
      "com.liferay.portlet.journal.util.TokensTransformerListener",
      "com.liferay.portlet.journal.util.ContentTransformerListener",
      "com.liferay.portlet.journal.util.LocaleTransformerListener",
      "com.liferay.portlet.journal.util.RegexTransformerListener",
      "com.liferay.portlet.journal.util.ViewCounterTransformerListener"};
      
      for (String transformerListenerClassName : transformers) {
        try {
          TransformerListener transformerListener =
            (TransformerListener) InstanceFactory.newInstance(
      	classLoader, transformerListenerClassName);
      	newTransformers.add(transformerListener);
        }
        catch (Exception e) {
          e.printStackTrace(out);
        }
      }
      
      // get the JournalTransformer object from JournalUtil class
      jt = JournalUtil.class.getDeclaredField("_journalTransformer");
      jt.setAccessible(true);
      
      // set the transformerListener set for the JournalTransformer object
      tl.set(jt.get(null), newTransformers);
      

      For ee-6.2.x

      import com.liferay.portal.templateparser.Transformer;
      import com.liferay.portlet.journal.util.JournalUtil;
      
      // Prepare a new (sorted) set of transformers
      // make sure LocaleTransformer goes AFTER contentTransformer
      newTransformers = new LinkedHashSet();
      
      transformers=new String[]{
      "com.liferay.portlet.journal.util.TokensTransformerListener",
      "com.liferay.portlet.journal.util.ContentTransformerListener",
      "com.liferay.portlet.journal.util.LocaleTransformerListener",
      "com.liferay.portlet.journal.util.RegexTransformerListener",
      "com.liferay.portlet.journal.util.ViewCounterTransformerListener"};
      
      for (String transformerListenerClassName : transformers) {
        try {
      
      	newTransformers.add(transformerListenerClassName);
        }
        catch (Exception e) {
          e.printStackTrace(out);
        }
      }
      
      // get the Transformer object from JournalUtil class
      tField = JournalUtil.class.getDeclaredField("_transformer");
      tField.setAccessible(true);
      Transformer t = (Transformer)tField.get(null);
      
      // get the String set having the transformer listener class names
      tlcnField = Transformer.class.getDeclaredField("_transformerListenerClassNames");
      tlcnField.setAccessible(true);
      
      // set the transformerListener set for the Transformer object
      tlcnField.set(t, newTransformers);
      

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              lu.liu Lu Liu
              Reporter:
              daniel.sanz Daniel Sanz
              Participants of an Issue:
              Recent user:
              Marta Elicegui
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:
                Days since last comment:
                5 years, 26 weeks, 3 days ago

                  Packages

                  Version Package
                  6.2.X EE
                  7.0.0 M5