HtmlDocument.java

  1. /*
  2.  * #%L
  3.  * *********************************************************************************************************************
  4.  *
  5.  * NorthernWind - lightweight CMS
  6.  * http://northernwind.tidalwave.it - git clone git@bitbucket.org:tidalwave/northernwind-rca-src.git
  7.  * %%
  8.  * Copyright (C) 2013 - 2021 Tidalwave s.a.s. (http://tidalwave.it)
  9.  * %%
  10.  * *********************************************************************************************************************
  11.  *
  12.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  13.  * the License. You may obtain a copy of the License at
  14.  *
  15.  *     http://www.apache.org/licenses/LICENSE-2.0
  16.  *
  17.  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  18.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  19.  * specific language governing permissions and limitations under the License.
  20.  *
  21.  * *********************************************************************************************************************
  22.  *
  23.  *
  24.  * *********************************************************************************************************************
  25.  * #L%
  26.  */
  27. package it.tidalwave.northernwind.rca.ui.contenteditor.impl;

  28. import javax.annotation.Nonnull;
  29. import javax.annotation.concurrent.Immutable;
  30. import it.tidalwave.northernwind.rca.ui.contenteditor.spi.XhtmlNormalizer;
  31. import lombok.EqualsAndHashCode;
  32. import lombok.Getter;
  33. import lombok.RequiredArgsConstructor;
  34. import lombok.ToString;
  35. import lombok.With;
  36. import lombok.extern.slf4j.Slf4j;
  37. import static lombok.AccessLevel.PACKAGE;

  38. /***********************************************************************************************************************
  39.  *
  40.  * A container for HTML text that allow substitution of prolog and epilog in order to prepare a HTML document for
  41.  * editing. It keeps an internal representation where the prolog, the body and the epilog are separately stored.
  42.  *
  43.  * @author  Fabrizio Giudici
  44.  *
  45.  **********************************************************************************************************************/
  46. @Immutable
  47. @RequiredArgsConstructor(access = PACKAGE)
  48. @EqualsAndHashCode @ToString @Slf4j
  49. public class HtmlDocument
  50.   {
  51.     @Getter @With @Nonnull
  52.     private final String prolog;

  53.     @Getter @With @Nonnull
  54.     private final String body;

  55.     @Getter @With @Nonnull
  56.     private final String epilog;

  57.     @Nonnull
  58.     private final XhtmlNormalizer normalizer;

  59.     /*******************************************************************************************************************
  60.      *
  61.      *
  62.      *
  63.      ******************************************************************************************************************/
  64.     enum State
  65.       {
  66.         PROLOG
  67.           {
  68.             @Override
  69.             State process (final @Nonnull String line,
  70.                            final @Nonnull StringBuilder prologBuilder,
  71.                            final @Nonnull StringBuilder bodyBuilder,
  72.                            final @Nonnull StringBuilder epilogBuilder)
  73.               {
  74.                 prologBuilder.append(line).append("\n");
  75.                 return line.contains("<body") ? BODY : PROLOG;
  76.               }
  77.           },

  78.         BODY
  79.           {
  80.             @Override
  81.             State process (final @Nonnull String line,
  82.                            final @Nonnull StringBuilder prologBuilder,
  83.                            final @Nonnull StringBuilder bodyBuilder,
  84.                            final @Nonnull StringBuilder epilogBuilder)
  85.               {
  86.                 final boolean containsEndBody = line.contains("</body");
  87.                 (containsEndBody ? epilogBuilder : bodyBuilder).append(line).append("\n");
  88.                 return containsEndBody ? EPILOG : BODY;
  89.               }
  90.           },

  91.         EPILOG
  92.           {
  93.             @Override
  94.             State process (final @Nonnull String line,
  95.                            final @Nonnull StringBuilder prologBuilder,
  96.                            final @Nonnull StringBuilder bodyBuilder,
  97.                            final @Nonnull StringBuilder epilogBuilder)
  98.               {
  99.                 epilogBuilder.append(line).append("\n");
  100.                 return EPILOG;
  101.               }
  102.           };

  103.         abstract State process (@Nonnull String line,
  104.                                 @Nonnull StringBuilder prologBuilder,
  105.                                 @Nonnull StringBuilder bodyBuilder,
  106.                                 @Nonnull StringBuilder epilogBuilder);
  107.       }

  108.     /*******************************************************************************************************************
  109.      *
  110.      * Creates a new document from a string.
  111.      *
  112.      * @param       text        the string
  113.      * @return                  the document
  114.      *
  115.      ******************************************************************************************************************/
  116.     @Nonnull
  117.     public static HtmlDocument createFromText (final @Nonnull String text)
  118.       {
  119.         final StringBuilder prologBuilder = new StringBuilder();
  120.         final StringBuilder bodyBuilder = new StringBuilder();
  121.         final StringBuilder epilogBuilder = new StringBuilder();

  122.         State state = State.PROLOG;

  123.         for (final String line : text.split("\\n"))
  124.           {
  125.             state = state.process(line, prologBuilder, bodyBuilder, epilogBuilder);
  126.           }

  127.         return new HtmlDocument(prologBuilder.toString(),
  128.                                 bodyBuilder.toString(),
  129.                                 epilogBuilder.toString(),
  130.                                 new JSoupXhtmlNormalizer());
  131.       }

  132.     /*******************************************************************************************************************
  133.      *
  134.      * Returns the contents as a string, after having being normalised.
  135.      *
  136.      * @return      the string
  137.      *
  138.      ******************************************************************************************************************/
  139.     @Nonnull
  140.     public String asString()
  141.       {
  142.         return normalizer.asNormalizedString(prolog + body + epilog);
  143.       }
  144.   }