DefaultAddContentPresentationControl.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.contentmanager.impl;

  28. import javax.annotation.CheckForNull;
  29. import javax.annotation.Nonnull;
  30. import javax.annotation.PostConstruct;
  31. import java.time.Instant;
  32. import java.time.ZoneId;
  33. import java.time.ZonedDateTime;
  34. import java.util.HashMap;
  35. import java.util.List;
  36. import java.util.Map;
  37. import java.io.UnsupportedEncodingException;
  38. import java.io.IOException;
  39. import java.io.InputStreamReader;
  40. import java.io.Reader;
  41. import java.net.URLEncoder;
  42. import com.google.common.base.Splitter;
  43. import com.google.common.collect.Lists;
  44. import com.google.common.io.CharStreams;
  45. import lombok.RequiredArgsConstructor;
  46. import org.springframework.core.io.ClassPathResource;
  47. import it.tidalwave.util.Key;
  48. import it.tidalwave.role.IdFactory;
  49. import it.tidalwave.util.InstantProvider;
  50. import it.tidalwave.messagebus.annotation.ListensTo;
  51. import it.tidalwave.messagebus.annotation.SimpleMessageSubscriber;
  52. import it.tidalwave.northernwind.core.model.Content;
  53. import it.tidalwave.northernwind.rca.ui.event.CreateContentRequest;
  54. import it.tidalwave.northernwind.rca.ui.contentmanager.AddContentPresentation;
  55. import it.tidalwave.northernwind.rca.ui.contentmanager.AddContentPresentation.Bindings;
  56. import it.tidalwave.northernwind.rca.ui.contentmanager.AddContentPresentationControl;
  57. import lombok.Cleanup;
  58. import lombok.extern.slf4j.Slf4j;
  59. import static java.util.stream.Collectors.joining;
  60. import static it.tidalwave.util.ui.UserNotificationWithFeedback.*;
  61. import static it.tidalwave.northernwind.model.admin.Properties.*;
  62. import static it.tidalwave.northernwind.rca.ui.contentmanager.impl.ContentChildCreator.ContentChildCreator;

  63. /***********************************************************************************************************************
  64.  *
  65.  * The default implementation of {@link AddContentPresentationControl}.
  66.  *
  67.  * @stereotype control
  68.  *
  69.  * @author  Fabrizio Giudici
  70.  *
  71.  **********************************************************************************************************************/
  72. @SimpleMessageSubscriber @RequiredArgsConstructor @Slf4j
  73. public class DefaultAddContentPresentationControl implements AddContentPresentationControl
  74.   {
  75.     @Nonnull
  76.     private final AddContentPresentation presentation;

  77.     @Nonnull
  78.     private final IdFactory idFactory;

  79.     @Nonnull
  80.     private final InstantProvider instantProvider;

  81.     private final Bindings bindings = new ValidatingBindings();

  82.     /* visible for testing */ String xhtmlSkeleton = "tbd";

  83.     /*******************************************************************************************************************
  84.      *
  85.      ******************************************************************************************************************/
  86.     @PostConstruct
  87.     /* visible for testing */ void initialize()
  88.       throws IOException
  89.       {
  90.         xhtmlSkeleton = loadResource("Skeleton.xhtml");
  91.       }

  92.     /*******************************************************************************************************************
  93.      *
  94.      ******************************************************************************************************************/
  95.     /* visible for testing */ void onCreateContentRequest (final @ListensTo @Nonnull CreateContentRequest event)
  96.       {
  97.         log.info("onCreateContentRequest({})", event);
  98.         bindings.publishingDateTime.set(toZonedDateTime(instantProvider.get()));
  99.         presentation.bind(bindings);
  100.         presentation.showUp(notificationWithFeedback()
  101.                 .withCaption("Create new content")
  102.                 .withFeedback(feedback().withOnConfirm(() -> createContent(event.getParentContent()))
  103.                                         .withOnCancel(() -> {}))); // FIXME: withOnCancel(DO_NOTHING)
  104.       }

  105.     /*******************************************************************************************************************
  106.      *
  107.      ******************************************************************************************************************/
  108.     private void createContent (final @Nonnull Content parentContent)
  109.       throws IOException
  110.       {
  111.         final String folderName = urlEncoded(bindings.folder.get());
  112.         // TODO: use TypeSafeMap, with a safe put() method
  113.         final Map<Key<?>, Object> propertyValues = new HashMap<>();
  114.         putIfNonEmpty(propertyValues, PROPERTY_TITLE,           bindings.title.get());
  115.         putIfNonEmpty(propertyValues, PROPERTY_EXPOSED_URI,     bindings.exposedUri.get());
  116.         putIfNonEmpty(propertyValues, PROPERTY_CREATION_TIME,   toZonedDateTime(instantProvider.get()));
  117.         putIfNonEmpty(propertyValues, PROPERTY_PUBLISHING_TIME, bindings.publishingDateTime.get());
  118.         putIfNonEmpty(propertyValues, PROPERTY_FULL_TEXT,       xhtmlSkeleton);
  119.         putIfNonEmpty(propertyValues, PROPERTY_ID,              idFactory.createId());

  120.         final Splitter splitter = Splitter.on(',').trimResults().omitEmptyStrings();
  121.         final List<String> tags = Lists.newArrayList(splitter.split(bindings.tags.get()));

  122.         if (!tags.isEmpty())
  123.           {
  124.             // See NWRCA-69
  125.             propertyValues.put(PROPERTY_TAGS, tags.stream().collect(joining(",")));
  126. //                propertyValues.put(PROPERTY_TAGS, tags);
  127.           }

  128.         parentContent.as(ContentChildCreator).createContent(folderName, propertyValues);
  129.       }

  130.     /*******************************************************************************************************************
  131.      *
  132.      ******************************************************************************************************************/
  133.     @Nonnull // FIXME: the new InstantProvider has getZonedDateTime().
  134.     private static ZonedDateTime toZonedDateTime (final @Nonnull Instant instant)
  135.       {
  136.         return ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
  137.       }

  138.     /*******************************************************************************************************************
  139.      *
  140.      ******************************************************************************************************************/
  141.     private static <T> void putIfNonEmpty (final @Nonnull Map<Key<?>, Object> values,
  142.                                            final @Nonnull Key<T> key,
  143.                                            final @CheckForNull T value)
  144.       {
  145.         if ((value != null) && !"".equals(value))
  146.           {
  147.             values.put(key, value);
  148.           }
  149.       }

  150.     /*******************************************************************************************************************
  151.      *
  152.      ******************************************************************************************************************/
  153.     @Nonnull
  154.     private static String urlEncoded (final @Nonnull String string)
  155.       {
  156.         try
  157.           {
  158.             return URLEncoder.encode(string, "UTF-8");
  159.           }
  160.         catch (UnsupportedEncodingException e)
  161.           {
  162.             throw new RuntimeException(e); // never happens
  163.           }
  164.       }

  165.     /*******************************************************************************************************************
  166.      *
  167.      ******************************************************************************************************************/
  168.     @Nonnull
  169.     /* visible for testing */ String loadResource (final @Nonnull String path)
  170.       throws IOException
  171.       {
  172.         final String prefix = getClass().getPackage().getName().replace(".", "/");
  173.         final ClassPathResource resource = new ClassPathResource(prefix + "/" + path);
  174.         final @Cleanup Reader r = new InputStreamReader(resource.getInputStream(), "UTF-8");
  175.         return CharStreams.toString(r);
  176.       }
  177.   }