/**
   * Records an activity in the database, using a time based on the current time in an attempt to
   * make the activity's time unique.
   *
   * @param userId the primary key of the acting user
   * @param groupId the primary key of the group
   * @param className the target asset's class name
   * @param classPK the primary key of the target asset
   * @param type the activity's type
   * @param extraData any extra data regarding the activity
   * @param receiverUserId the primary key of the receiving user
   * @throws PortalException if the user or group could not be found
   * @throws SystemException if a system exception occurred
   */
  public void addActivity(
      long userId,
      long groupId,
      String className,
      long classPK,
      int type,
      String extraData,
      long receiverUserId)
      throws PortalException, SystemException {

    if (ImportExportThreadLocal.isImportInProcess()) {
      return;
    }

    Date createDate = new Date();

    long classNameId = PortalUtil.getClassNameId(className);

    while (true) {
      SocialActivity socialActivity =
          socialActivityPersistence.fetchByG_U_CD_C_C_T_R(
              groupId, userId, createDate.getTime(), classNameId, classPK, type, receiverUserId);

      if (socialActivity != null) {
        createDate = new Date(createDate.getTime() + 1);
      } else {
        break;
      }
    }

    addActivity(userId, groupId, createDate, className, classPK, type, extraData, receiverUserId);
  }
  public File exportPortletInfoAsFile(
      long plid,
      long groupId,
      String portletId,
      Map<String, String[]> parameterMap,
      Date startDate,
      Date endDate)
      throws Exception {

    try {
      ImportExportThreadLocal.setPortletExportInProcess(true);

      return doExportPortletInfoAsFile(plid, groupId, portletId, parameterMap, startDate, endDate);
    } finally {
      ImportExportThreadLocal.setPortletExportInProcess(false);
    }
  }
  public File exportLayoutsAsFile(
      long groupId,
      boolean privateLayout,
      long[] layoutIds,
      Map<String, String[]> parameterMap,
      Date startDate,
      Date endDate)
      throws Exception {

    try {
      ImportExportThreadLocal.setLayoutExportInProcess(true);

      return doExportLayoutsAsFile(
          groupId, privateLayout, layoutIds, parameterMap, startDate, endDate);
    } finally {
      ImportExportThreadLocal.setLayoutExportInProcess(false);
    }
  }
  public void importLayouts(
      long userId,
      long groupId,
      boolean privateLayout,
      Map<String, String[]> parameterMap,
      File file)
      throws Exception {

    try {
      ImportExportThreadLocal.setLayoutImportInProcess(true);

      doImportLayouts(userId, groupId, privateLayout, parameterMap, file);
    } finally {
      ImportExportThreadLocal.setLayoutImportInProcess(false);

      CacheUtil.clearCache();
      JournalContentUtil.clearCache();
      PermissionCacheUtil.clearCache();
    }
  }
  /**
   * Adds a role with additional parameters. The user is reindexed after role is added.
   *
   * @param userId the primary key of the user
   * @param companyId the primary key of the company
   * @param name the role's name
   * @param titleMap the role's localized titles (optionally <code>null</code>)
   * @param descriptionMap the role's localized descriptions (optionally <code>null</code>)
   * @param type the role's type (optionally <code>0</code>)
   * @param className the name of the class for which the role is created (optionally <code>null
   *     </code>)
   * @param classPK the primary key of the class for which the role is created (optionally <code>0
   *     </code>)
   * @return the role
   * @throws PortalException if the class name or the role name were invalid, if the role is a
   *     duplicate, or if a user with the primary key could not be found
   * @throws SystemException if a system exception occurred
   */
  public Role addRole(
      long userId,
      long companyId,
      String name,
      Map<Locale, String> titleMap,
      Map<Locale, String> descriptionMap,
      int type,
      String className,
      long classPK)
      throws PortalException, SystemException {

    // Role

    className = GetterUtil.getString(className);
    long classNameId = PortalUtil.getClassNameId(className);

    long roleId = counterLocalService.increment();

    if ((classNameId <= 0) || className.equals(Role.class.getName())) {
      classNameId = PortalUtil.getClassNameId(Role.class);
      classPK = roleId;
    }

    validate(0, companyId, classNameId, name);

    Role role = rolePersistence.create(roleId);

    role.setCompanyId(companyId);
    role.setClassNameId(classNameId);
    role.setClassPK(classPK);
    role.setName(name);
    role.setTitleMap(titleMap);
    role.setDescriptionMap(descriptionMap);
    role.setType(type);

    rolePersistence.update(role, false);

    // Resources

    if (userId > 0) {
      resourceLocalService.addResources(
          companyId, 0, userId, Role.class.getName(), role.getRoleId(), false, false, false);

      if (!ImportExportThreadLocal.isImportInProcess()) {
        Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(User.class);

        indexer.reindex(userId);
      }
    }

    return role;
  }
  @Async
  public void addActivity(SocialActivity activity, SocialActivity mirrorActivity)
      throws PortalException, SystemException {

    if (ImportExportThreadLocal.isImportInProcess()) {
      return;
    }

    if ((activity.getActivityId() > 0)
        || ((mirrorActivity != null) && (mirrorActivity.getActivityId() > 0))) {

      throw new PortalException("Activity and mirror activity must not have primary keys set");
    }

    SocialActivityDefinition activityDefinition =
        socialActivitySettingLocalService.getActivityDefinition(
            activity.getGroupId(), activity.getClassName(), activity.getType());

    if ((activityDefinition == null) || activityDefinition.isLogActivity()) {

      long activityId = counterLocalService.increment(SocialActivity.class.getName());

      activity.setActivityId(activityId);

      socialActivityPersistence.update(activity, false);

      if (mirrorActivity != null) {
        long mirrorActivityId = counterLocalService.increment(SocialActivity.class.getName());

        mirrorActivity.setActivityId(mirrorActivityId);
        mirrorActivity.setMirrorActivityId(activity.getPrimaryKey());

        socialActivityPersistence.update(mirrorActivity, false);
      }
    }

    socialActivityCounterLocalService.addActivityCounters(activity);
  }
  protected void exportPortletData(
      PortletDataContext portletDataContext,
      Portlet portlet,
      Layout layout,
      javax.portlet.PortletPreferences jxPreferences,
      Element parentElement)
      throws Exception {

    PortletDataHandler portletDataHandler = portlet.getPortletDataHandlerInstance();

    if (portletDataHandler == null) {
      return;
    }

    String portletId = portlet.getPortletId();

    Group liveGroup = layout.getGroup();

    if (liveGroup.isStagingGroup()) {
      liveGroup = liveGroup.getLiveGroup();
    }

    boolean staged = liveGroup.isStagedPortlet(portlet.getRootPortletId());

    if (!staged && ImportExportThreadLocal.isLayoutExportInProcess()) {
      if (_log.isDebugEnabled()) {
        _log.debug(
            "Not exporting data for " + portletId + " because it is configured not to be staged");
      }

      return;
    }

    if (_log.isDebugEnabled()) {
      _log.debug("Exporting data for " + portletId);
    }

    StringBundler sb = new StringBundler(4);

    sb.append(portletDataContext.getPortletPath(portletId));
    sb.append(StringPool.SLASH);

    if (portlet.isPreferencesUniquePerLayout()) {
      sb.append(layout.getPlid());
    } else {
      sb.append(portletDataContext.getScopeGroupId());
    }

    sb.append("/portlet-data.xml");

    String path = sb.toString();

    if (!portletDataContext.isPathNotProcessed(path)) {
      return;
    }

    long lastPublishDate =
        GetterUtil.getLong(jxPreferences.getValue("last-publish-date", StringPool.BLANK));

    Date startDate = portletDataContext.getStartDate();

    if ((lastPublishDate > 0) && (startDate != null) && (lastPublishDate < startDate.getTime())) {

      portletDataContext.setStartDate(new Date(lastPublishDate));
    }

    String data = null;

    long groupId = portletDataContext.getGroupId();

    portletDataContext.setGroupId(portletDataContext.getScopeGroupId());

    try {
      data = portletDataHandler.exportData(portletDataContext, portletId, jxPreferences);
    } catch (Exception e) {
      throw new SystemException(e);
    } finally {
      portletDataContext.setGroupId(groupId);
      portletDataContext.setStartDate(startDate);
    }

    if (Validator.isNull(data)) {
      if (_log.isDebugEnabled()) {
        _log.debug("Not exporting data for " + portletId + " because null data was returned");
      }

      return;
    }

    Element portletDataElement = parentElement.addElement("portlet-data");

    portletDataElement.addAttribute("path", path);

    portletDataContext.addZipEntry(path, data);

    Date endDate = portletDataContext.getEndDate();

    if (endDate != null) {
      try {
        jxPreferences.setValue("last-publish-date", String.valueOf(endDate.getTime()));

        jxPreferences.store();
      } catch (Exception e) {
        _log.error(e, e);
      }
    }
  }
  /**
   * Records an activity with the given time in the database.
   *
   * <p>This method records a social activity done on an asset, identified by its class name and
   * class primary key, in the database. Additional information (such as the original message ID for
   * a reply to a forum post) is passed in via the <code>extraData</code> in JSON format. For
   * activities affecting another user, a mirror activity is generated that describes the action
   * from the user's point of view. The target user's ID is passed in via the <code>receiverUserId
   * </code>.
   *
   * <p>Example for a mirrored activity:<br>
   * When a user replies to a message boards post, the reply action is stored in the database with
   * the <code>receiverUserId</code> being the ID of the author of the original message. The <code>
   * extraData</code> contains the ID of the original message in JSON format. A mirror activity is
   * generated with the values of the <code>userId</code> and the <code>receiverUserId</code>
   * swapped. This mirror activity basically describes a "replied to" event.
   *
   * <p>Mirror activities are most often used in relation to friend requests and activities.
   *
   * @param userId the primary key of the acting user
   * @param groupId the primary key of the group
   * @param createDate the activity's date
   * @param className the target asset's class name
   * @param classPK the primary key of the target asset
   * @param type the activity's type
   * @param extraData any extra data regarding the activity
   * @param receiverUserId the primary key of the receiving user
   * @throws PortalException if the user or group could not be found
   * @throws SystemException if a system exception occurred
   */
  public void addActivity(
      long userId,
      long groupId,
      Date createDate,
      String className,
      long classPK,
      int type,
      String extraData,
      long receiverUserId)
      throws PortalException, SystemException {

    if (ImportExportThreadLocal.isImportInProcess()) {
      return;
    }

    User user = userPersistence.findByPrimaryKey(userId);
    long classNameId = PortalUtil.getClassNameId(className);

    if (groupId > 0) {
      Group group = groupLocalService.getGroup(groupId);

      if (group.isLayout()) {
        Layout layout = layoutLocalService.getLayout(group.getClassPK());

        groupId = layout.getGroupId();
      }
    }

    SocialActivity activity = socialActivityPersistence.create(0);

    activity.setGroupId(groupId);
    activity.setCompanyId(user.getCompanyId());
    activity.setUserId(user.getUserId());
    activity.setCreateDate(createDate.getTime());
    activity.setMirrorActivityId(0);
    activity.setClassNameId(classNameId);
    activity.setClassPK(classPK);
    activity.setType(type);
    activity.setExtraData(extraData);
    activity.setReceiverUserId(receiverUserId);

    AssetEntry assetEntry = assetEntryPersistence.fetchByC_C(classNameId, classPK);

    activity.setAssetEntry(assetEntry);

    SocialActivity mirrorActivity = null;

    if ((receiverUserId > 0) && (userId != receiverUserId)) {
      mirrorActivity = socialActivityPersistence.create(0);

      mirrorActivity.setGroupId(groupId);
      mirrorActivity.setCompanyId(user.getCompanyId());
      mirrorActivity.setUserId(receiverUserId);
      mirrorActivity.setCreateDate(createDate.getTime());
      mirrorActivity.setClassNameId(classNameId);
      mirrorActivity.setClassPK(classPK);
      mirrorActivity.setType(type);
      mirrorActivity.setExtraData(extraData);
      mirrorActivity.setReceiverUserId(user.getUserId());
      mirrorActivity.setAssetEntry(assetEntry);
    }

    socialActivityLocalService.addActivity(activity, mirrorActivity);
  }