ProductInformations.java

  1. /**
  2.  * Copyright (C) 2009 eXo Platform SAS.
  3.  *
  4.  * This is free software; you can redistribute it and/or modify it
  5.  * under the terms of the GNU Lesser General Public License as
  6.  * published by the Free Software Foundation; either version 2.1 of
  7.  * the License, or (at your option) any later version.
  8.  *
  9.  * This software is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12.  * Lesser General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU Lesser General Public
  15.  * License along with this software; if not, write to the Free
  16.  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  17.  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  18.  */
  19. package org.exoplatform.commons.info;

  20. import org.exoplatform.commons.api.settings.SettingService;
  21. import org.exoplatform.commons.api.settings.SettingValue;
  22. import org.exoplatform.commons.api.settings.data.Context;
  23. import org.exoplatform.commons.api.settings.data.Scope;
  24. import org.exoplatform.container.configuration.ConfigurationManager;
  25. import org.exoplatform.container.xml.InitParams;
  26. import org.exoplatform.services.jcr.RepositoryService;
  27. import org.exoplatform.services.jcr.core.ManageableRepository;
  28. import org.exoplatform.services.jcr.ext.app.SessionProviderService;
  29. import org.exoplatform.services.jcr.ext.common.SessionProvider;
  30. import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
  31. import org.exoplatform.services.log.ExoLogger;
  32. import org.exoplatform.services.log.Log;
  33. import org.exoplatform.settings.jpa.entity.SettingsEntity;
  34. import org.picocontainer.Startable;

  35. import javax.jcr.*;
  36. import java.io.*;
  37. import java.text.DateFormat;
  38. import java.text.SimpleDateFormat;
  39. import java.util.*;
  40. import java.util.stream.Collectors;

  41. /**
  42.  * @author <a href="mailto:anouar.chattouna@exoplatform.com">Anouar
  43.  *         Chattouna</a>
  44.  * @version $Revision$
  45.  */
  46. public class ProductInformations implements Startable {

  47.   public static final String     product_Information                   = "ProductInformation";

  48.   public static final String     ENTERPRISE_EDITION                    = "ENTERPRISE";

  49.   public static final String     EXPRESS_EDITION                       = "EXPRESS";

  50.   public static final String     EDITION                               = "edition";

  51.   public static final String     KEY_GENERATION_DATE                   = "key generation date";

  52.   public static final String     DELAY                                 = "delay";

  53.   public static final String     PRODUCT_CODE                          = "productCode";

  54.   public static final String     PRODUCT_KEY                           = "productKey";

  55.   public static final String     NB_USERS                              = "number of users";

  56.   public static final String     PRODUCT_GROUP_ID                      = "product.groupId";

  57.   public static final String     PRODUCT_REVISION                      = "product.revision";

  58.   public static final String     PRODUCT_BUILD_NUMBER                  = "product.buildNumber";

  59.   public static final String     WORKING_WORSPACE_NAME                 = "working.worspace.name";

  60.   public static final String     PRODUCT_VERSIONS_DECLARATION_FILE     = "product.versions.declaration.file";

  61.   /**
  62.    * Constant that will be used in nodeHierarchyCreator.getJcrPath: it represents
  63.    * the Application data root node Alias
  64.    */
  65.   public static final String     EXO_APPLICATIONS_DATA_NODE_ALIAS      = "exoApplicationDataNode";

  66.   /**
  67.    * Service application data node name
  68.    */
  69.   public static final String     UPGRADE_PRODUCT_SERVICE_NODE_NAME     = "ProductInformationsService";

  70.   /**
  71.    * node name where the Product version declaration is
  72.    */
  73.   public static final String     PRODUCT_VERSION_DECLARATION_NODE_NAME = "productVersionDeclarationNode";

  74.   private static final Log       LOG                                   = ExoLogger.getLogger(ProductInformations.class);

  75.   public String                  applicationDataRootNodePath           = null;

  76.   private String                 productVersionDeclarationNodePath     = null;

  77.   private String                 workspaceName                         = null;

  78.   private Properties             productInformationProperties          = new Properties();

  79.   private Map<String, String>    productInformation                    = new HashMap<>();

  80.   private boolean                firstRun                              = false;

  81.   private SettingService         settingService;

  82.   private NodeHierarchyCreator   nodeHierarchyCreator;

  83.   private RepositoryService      repositoryService                     = null;

  84.   private SessionProviderService sessionProviderService                = null;

  85.   public ProductInformations(ConfigurationManager cmanager,
  86.                              NodeHierarchyCreator nodeHierarchyCreator,
  87.                              InitParams initParams,
  88.                              SettingService settingService,
  89.                              SessionProviderService sessionProviderService,
  90.                              RepositoryService repositoryService) {
  91.     this.repositoryService = repositoryService;
  92.     this.sessionProviderService = sessionProviderService;
  93.     this.settingService = settingService;
  94.     this.nodeHierarchyCreator = nodeHierarchyCreator;
  95.     if (!initParams.containsKey(PRODUCT_VERSIONS_DECLARATION_FILE)) {
  96.       if (LOG.isErrorEnabled()) {
  97.         LOG.error("Couldn't find the init value param: " + PRODUCT_VERSIONS_DECLARATION_FILE);
  98.       }
  99.       return;
  100.     }
  101.     String filePath = initParams.getValueParam(PRODUCT_VERSIONS_DECLARATION_FILE).getValue();
  102.     try {
  103.       if (LOG.isInfoEnabled()) {
  104.         LOG.info("Read products versions from " + filePath);
  105.       }
  106.       InputStream inputStream = cmanager.getInputStream(filePath);
  107.       productInformationProperties.load(inputStream);
  108.     } catch (IOException exception) {
  109.       if (LOG.isErrorEnabled()) {
  110.         LOG.error("Couldn't parse the file " + filePath, exception);
  111.       }
  112.       return;
  113.     } catch (Exception exception) {
  114.       // ConfigurationManager.getInputStream() throws Exception().
  115.       // It's from another project and we cannot modify it. So we have to catch
  116.       // Exception
  117.       if (LOG.isErrorEnabled()) {
  118.         LOG.error("Error occured while reading the file " + filePath, exception);
  119.       }
  120.       return;
  121.     }
  122.     if (initParams.containsKey(WORKING_WORSPACE_NAME)) {
  123.       workspaceName = initParams.getValueParam(WORKING_WORSPACE_NAME).getValue();
  124.     }
  125.   }

  126.   public String getEdition() throws MissingProductInformationException {
  127.     return productInformation.get(EDITION);
  128.   }

  129.   public String getNumberOfUsers() throws MissingProductInformationException {
  130.     return productInformation.get(NB_USERS);
  131.   }

  132.   public String getDateOfLicence() throws MissingProductInformationException {
  133.     return productInformation.get(KEY_GENERATION_DATE);
  134.   }

  135.   public String getDuration() throws MissingProductInformationException {
  136.     return productInformation.get(DELAY);
  137.   }

  138.   public String getProductCode() throws MissingProductInformationException {
  139.     return productInformation.get(PRODUCT_CODE);
  140.   }

  141.   public String getProductKey() throws MissingProductInformationException {
  142.     return productInformation.get(PRODUCT_KEY);
  143.   }

  144.   /**
  145.    * @return This method returns the current product's version.
  146.    */
  147.   public String getVersion() throws MissingProductInformationException {
  148.     return getVersion(getCurrentProductGroupId());
  149.   }

  150.   /**
  151.    * @return This method return the product version, selected by its maven
  152.    *         groupId.
  153.    */
  154.   public String getVersion(String productGroupId) throws MissingProductInformationException {
  155.     if (!productInformationProperties.containsKey(productGroupId)) {
  156.       throw new MissingProductInformationException(productGroupId);
  157.     }
  158.     return productInformationProperties.getProperty(productGroupId);
  159.   }

  160.   /**
  161.    * @return the product.buildNumber property value.
  162.    */
  163.   public String getBuildNumber() throws MissingProductInformationException {
  164.     if (!productInformationProperties.containsKey(PRODUCT_BUILD_NUMBER)) {
  165.       throw new MissingProductInformationException(PRODUCT_BUILD_NUMBER);
  166.     }
  167.     return productInformationProperties.getProperty(PRODUCT_BUILD_NUMBER);
  168.   }

  169.   /**
  170.    * @return the product.revision property value.
  171.    */
  172.   public String getRevision() throws MissingProductInformationException {
  173.     if (!productInformationProperties.containsKey(PRODUCT_REVISION)) {
  174.       throw new MissingProductInformationException(PRODUCT_REVISION);
  175.     }
  176.     return productInformationProperties.getProperty(PRODUCT_REVISION);
  177.   }

  178.   /**
  179.    * @return the current product's maven group id.
  180.    */
  181.   public String getCurrentProductGroupId() throws MissingProductInformationException {
  182.     if (!productInformationProperties.containsKey(PRODUCT_GROUP_ID)) {
  183.       throw new MissingProductInformationException(PRODUCT_GROUP_ID);
  184.     }
  185.     return productInformationProperties.getProperty(PRODUCT_GROUP_ID);
  186.   }

  187.   /**
  188.    * @return the platform.version property. This method return the platform
  189.    *         version.
  190.    */
  191.   public String getPreviousVersion() throws MissingProductInformationException {
  192.     return getPreviousVersion(getCurrentProductGroupId());
  193.   }

  194.   /**
  195.    * @return the platform.version property. This method return the platform
  196.    *         version.
  197.    */
  198.   public String getPreviousVersion(String productGroupId) throws MissingProductInformationException {
  199.     if (!productInformation.containsKey(productGroupId)) {
  200.       throw new MissingProductInformationException(productGroupId);
  201.     }
  202.     return productInformation.get(productGroupId);
  203.   }

  204.   /**
  205.    * @return an empty string if the properties file is not found, otherwise the
  206.    *         platform.buildNumber property. This method return the build number of
  207.    *         the platform.
  208.    */
  209.   public String getPreviousBuildNumber() throws MissingProductInformationException {
  210.     if (!productInformation.containsKey(PRODUCT_BUILD_NUMBER)) {
  211.       throw new MissingProductInformationException(PRODUCT_BUILD_NUMBER);
  212.     }
  213.     return productInformation.get(PRODUCT_BUILD_NUMBER);
  214.   }

  215.   /**
  216.    * @return the value of product.revision property. This method return the
  217.    *         current revison of the platform.
  218.    */
  219.   public String getPreviousRevision() throws MissingProductInformationException {
  220.     if (!productInformation.containsKey(PRODUCT_REVISION)) {
  221.       throw new MissingProductInformationException(PRODUCT_REVISION);
  222.     }
  223.     return productInformation.get(PRODUCT_REVISION);
  224.   }

  225.   public boolean isFirstRun() {
  226.     return this.firstRun;
  227.   }

  228.   /**
  229.    * This method migrate from the JCR the stored products versions to JPA. If it's
  230.    * the first server start up, then store the declared one.
  231.    */
  232.   public void start() {
  233.     try {
  234.       migrateProductInformation();
  235.       // Load product information from DB
  236.       Map<String, SettingValue> productInformationSettings =
  237.                                                            settingService.getSettingsByContextAndScope(Context.GLOBAL.getName(),
  238.                                                                                                        Context.GLOBAL.getId(),
  239.                                                                                                        Scope.APPLICATION.getName(),
  240.                                                                                                        product_Information);
  241.       if (productInformationSettings != null && !productInformationSettings.isEmpty()) {
  242.         productInformationSettings.entrySet()
  243.                                   .stream()
  244.                                   .forEach(e -> productInformation.put(e.getKey(), e.getValue().getValue().toString()));

  245.       } else {// This is the first time that this Service starts up
  246.         LOG.info("Platform first run - init and store product Information");
  247.         firstRun = true;
  248.         // Store product information properties in DB
  249.         initProductInformation(productInformationProperties);
  250.         storeProductInformation(productInformation);
  251.       }
  252.     } catch (Exception e) {
  253.       LOG.error("Error while starting product information service - Cause : " + e.getMessage(), e);
  254.     }
  255.   }

  256.   /**
  257.    * This method is called by eXo Kernel when stopping the parent ExoContainer
  258.    */
  259.   public void stop() {
  260.   }

  261.   public void storeProductInformation(Map<String, String> map) {
  262.     try {
  263.       for (Map.Entry<String, String> entry : map.entrySet()) {
  264.         settingService.set(Context.GLOBAL,
  265.                            Scope.APPLICATION.id(product_Information),
  266.                            entry.getKey(),
  267.                            SettingValue.create(entry.getValue()));
  268.       }
  269.     } catch (Exception e) {
  270.       LOG.error("Error while storing product informations    - Cause : " + e.getMessage(), e);
  271.     }
  272.   }

  273.   public void initProductInformation(Properties properties) {
  274.     properties.entrySet().stream().forEach(entry -> productInformation.put((String) entry.getKey(), (String) entry.getValue()));
  275.   }

  276.   /**
  277.    * Migrate product information from JCR to RDBMS
  278.    */
  279.   public void migrateProductInformation() {
  280.     if (workspaceName == null || workspaceName.equals("")) {
  281.       try {
  282.         workspaceName = repositoryService.getCurrentRepository().getConfiguration().getDefaultWorkspaceName();
  283.         if (LOG.isInfoEnabled()) {
  284.           LOG.info("Workspace wasn't specified, use '" + workspaceName + "' as default workspace of this repository.");
  285.         }
  286.       } catch (RepositoryException exception) {
  287.         LOG.error("Error occured while getting default workspace name.", exception);
  288.         return;
  289.       }
  290.     }
  291.     Session session = null;
  292.     try {
  293.       session = getSession();
  294.       applicationDataRootNodePath = nodeHierarchyCreator.getJcrPath(EXO_APPLICATIONS_DATA_NODE_ALIAS);
  295.       productVersionDeclarationNodePath = applicationDataRootNodePath + "/" + UPGRADE_PRODUCT_SERVICE_NODE_NAME + "/"
  296.           + PRODUCT_VERSION_DECLARATION_NODE_NAME;
  297.       if (session.itemExists(productVersionDeclarationNodePath)) {
  298.         Node productVersionDeclarationNode = (Node) session.getItem(productVersionDeclarationNodePath);
  299.         Node productVersionDeclarationNodeContent = productVersionDeclarationNode.getNode("jcr:content");
  300.         String data = productVersionDeclarationNodeContent.getProperty("jcr:data").getString();
  301.         Properties jcrInformation = new Properties();
  302.         jcrInformation.load(new ByteArrayInputStream(data.getBytes()));
  303.         initProductInformation(jcrInformation);
  304.         storeProductInformation(productInformation);
  305.         productVersionDeclarationNode.getParent().remove();
  306.         LOG.info("productVersionDeclaration node removed!");
  307.         session.save();
  308.       } else {
  309.         LOG.info("No product information to migrate from JCR to RDBMS");
  310.       }
  311.     } catch (LoginException exception) {
  312.       LOG.error("Can't load product informations from the JCR: Error when getting JCR session.", exception);
  313.       return;
  314.     } catch (NoSuchWorkspaceException exception) {
  315.       LOG.error("Can't load product informations from the JCR: Error when getting JCR session.", exception);
  316.       return;
  317.     } catch (RepositoryException exception) {
  318.       LOG.error("Can't load product informations from the JCR!", exception);
  319.       return;
  320.     } catch (IOException exception) {
  321.       LOG.error("Can't load product informations from the JCR: the data stored in the JCR couldn't be parsed.", exception);
  322.       return;
  323.     }
  324.     finally {
  325.       if (session != null) {
  326.         session.logout();
  327.       }
  328.     }
  329.   }

  330.   public void setUnlockInformation(Properties unlockInformation) {
  331.     productInformation.put(EDITION, (String) unlockInformation.get(EDITION));
  332.     productInformation.put(NB_USERS, (String) unlockInformation.get(NB_USERS));
  333.     productInformation.put(PRODUCT_KEY, (String) unlockInformation.get(PRODUCT_KEY));
  334.     productInformation.put(PRODUCT_CODE, (String) unlockInformation.get(PRODUCT_CODE));
  335.     productInformation.put(DELAY, (String) unlockInformation.get(DELAY));
  336.     productInformation.put(KEY_GENERATION_DATE, (String) unlockInformation.get(KEY_GENERATION_DATE));
  337.   }

  338.   public void setPreviousVersionsIfFirstRun(String defaultVersion) {
  339.     if (isFirstRun()) {
  340.       initProductInformation(productInformationProperties);
  341.       productInformation.forEach((key, value) -> productInformation.put(key, defaultVersion));
  342.     }
  343.   }

  344.   public String getWorkspaceName() {
  345.     return workspaceName;
  346.   }

  347.   public String getProductVersionDeclarationNodePath() {
  348.     return this.productVersionDeclarationNodePath;
  349.   }

  350.   private static String currentFlag() {
  351.     DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
  352.     return dateFormat.format(Calendar.getInstance(TimeZone.getDefault()).getTime());
  353.   }

  354.   public void setProductInformationProperties(Properties productInformationProperties) {
  355.     this.productInformationProperties = productInformationProperties;
  356.   }

  357.   public Properties getProductInformationProperties() {
  358.     return productInformationProperties;
  359.   }

  360.   public Map<String, String> getProductInformation() {
  361.     return productInformation;
  362.   }

  363.   public void setFirstRun(boolean firstRun) {
  364.     this.firstRun = firstRun;
  365.   }

  366.   private Session getSession() throws RepositoryException, LoginException, NoSuchWorkspaceException {
  367.     SessionProvider sessionProvider = sessionProviderService.getSystemSessionProvider(null);
  368.     ManageableRepository repository = repositoryService.getCurrentRepository();
  369.     return sessionProvider.getSession(workspaceName, repository);
  370.   }

  371. }