@Indexable(type = IndexableType.REINDEX)
  @Override
  public AssetCategory moveCategory(
      long categoryId, long parentCategoryId, long vocabularyId, ServiceContext serviceContext)
      throws PortalException, SystemException {

    AssetCategory category = assetCategoryPersistence.findByPrimaryKey(categoryId);

    validate(categoryId, parentCategoryId, category.getName(), vocabularyId);

    if (parentCategoryId > 0) {
      assetCategoryPersistence.findByPrimaryKey(parentCategoryId);
    }

    if (vocabularyId != category.getVocabularyId()) {
      assetVocabularyPersistence.findByPrimaryKey(vocabularyId);

      category.setVocabularyId(vocabularyId);

      updateChildrenVocabularyId(category, vocabularyId);
    }

    category.setModifiedDate(new Date());
    category.setParentCategoryId(parentCategoryId);

    assetCategoryPersistence.update(category);

    return category;
  }
  protected Map<Locale, String> getAssetCategoryTitleMap(AssetCategory assetCategory) {

    Map<Locale, String> titleMap = assetCategory.getTitleMap();

    if (titleMap == null) {
      titleMap = new HashMap<Locale, String>();
    }

    Locale locale = LocaleUtil.getDefault();

    String title = titleMap.get(locale);

    if (Validator.isNull(title)) {
      titleMap.put(locale, assetCategory.getName());
    }

    return titleMap;
  }
  @Override
  protected Document doGetDocument(Object obj) throws Exception {
    AssetCategory category = (AssetCategory) obj;

    if (_log.isDebugEnabled()) {
      _log.debug("Indexing category " + category);
    }

    Document document = getBaseModelDocument(PORTLET_ID, category);

    document.addKeyword(Field.ASSET_CATEGORY_ID, category.getCategoryId());
    document.addKeyword(Field.ASSET_VOCABULARY_ID, category.getVocabularyId());
    document.addLocalizedText(Field.DESCRIPTION, category.getDescriptionMap());
    document.addText(Field.NAME, category.getName());
    document.addLocalizedText(Field.TITLE, category.getTitleMap());

    if (_log.isDebugEnabled()) {
      _log.debug("Document " + category + " indexed successfully");
    }

    return document;
  }
  protected JSONArray toJSONArray(List<AssetCategory> categories)
      throws PortalException, SystemException {

    JSONArray jsonArray = JSONFactoryUtil.createJSONArray();

    for (AssetCategory category : categories) {
      String categoryJSON = JSONFactoryUtil.looseSerialize(category);

      JSONObject categoryJSONObject = JSONFactoryUtil.createJSONObject(categoryJSON);

      List<String> names = new ArrayList<String>();

      AssetCategory curCategory = category;

      while (curCategory.getParentCategoryId() > 0) {
        AssetCategory parentCategory = getCategory(curCategory.getParentCategoryId());

        names.add(parentCategory.getName());
        names.add(StringPool.SPACE + StringPool.GREATER_THAN + StringPool.SPACE);

        curCategory = parentCategory;
      }

      Collections.reverse(names);

      AssetVocabulary vocabulary = assetVocabularyService.getVocabulary(category.getVocabularyId());

      StringBundler sb = new StringBundler(1 + names.size());

      sb.append(vocabulary.getName());
      sb.append(names.toArray(new String[names.size()]));

      categoryJSONObject.put("path", sb.toString());

      jsonArray.put(categoryJSONObject);
    }

    return jsonArray;
  }
  protected void importAssetCategory(
      PortletDataContext portletDataContext,
      Map<Long, Long> assetVocabularyPKs,
      Map<Long, Long> assetCategoryPKs,
      Map<String, String> assetCategoryUuids,
      Element assetCategoryElement,
      AssetCategory assetCategory)
      throws Exception {

    long userId = portletDataContext.getUserId(assetCategory.getUserUuid());
    long assetVocabularyId =
        MapUtil.getLong(
            assetVocabularyPKs, assetCategory.getVocabularyId(), assetCategory.getVocabularyId());
    long parentAssetCategoryId =
        MapUtil.getLong(
            assetCategoryPKs,
            assetCategory.getParentCategoryId(),
            assetCategory.getParentCategoryId());

    if ((parentAssetCategoryId != AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID)
        && (parentAssetCategoryId == assetCategory.getParentCategoryId())) {

      String path = getAssetCategoryPath(portletDataContext, parentAssetCategoryId);

      AssetCategory parentAssetCategory =
          (AssetCategory) portletDataContext.getZipEntryAsObject(path);

      Node parentCategoryNode =
          assetCategoryElement.getParent().selectSingleNode("./category[@path='" + path + "']");

      if (parentCategoryNode != null) {
        importAssetCategory(
            portletDataContext,
            assetVocabularyPKs,
            assetCategoryPKs,
            assetCategoryUuids,
            (Element) parentCategoryNode,
            parentAssetCategory);

        parentAssetCategoryId =
            MapUtil.getLong(
                assetCategoryPKs,
                assetCategory.getParentCategoryId(),
                assetCategory.getParentCategoryId());
      }
    }

    ServiceContext serviceContext = new ServiceContext();

    serviceContext.setAddGroupPermissions(true);
    serviceContext.setAddGuestPermissions(true);
    serviceContext.setCreateDate(assetCategory.getCreateDate());
    serviceContext.setModifiedDate(assetCategory.getModifiedDate());
    serviceContext.setScopeGroupId(portletDataContext.getScopeGroupId());

    AssetCategory importedAssetCategory = null;

    try {
      if (parentAssetCategoryId != AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {

        AssetCategoryUtil.findByPrimaryKey(parentAssetCategoryId);
      }

      List<Element> propertyElements = assetCategoryElement.elements("property");

      String[] properties = new String[propertyElements.size()];

      for (int i = 0; i < propertyElements.size(); i++) {
        Element propertyElement = propertyElements.get(i);

        String key = propertyElement.attributeValue("key");
        String value = propertyElement.attributeValue("value");

        properties[i] = key.concat(StringPool.COLON).concat(value);
      }

      AssetCategory existingAssetCategory =
          AssetCategoryUtil.fetchByP_N_V(
              parentAssetCategoryId, assetCategory.getName(), assetVocabularyId);

      if (existingAssetCategory == null) {
        serviceContext.setUuid(assetCategory.getUuid());

        importedAssetCategory =
            AssetCategoryLocalServiceUtil.addCategory(
                userId,
                parentAssetCategoryId,
                getAssetCategoryTitleMap(assetCategory),
                assetCategory.getDescriptionMap(),
                assetVocabularyId,
                properties,
                serviceContext);
      } else {
        importedAssetCategory =
            AssetCategoryLocalServiceUtil.updateCategory(
                userId,
                existingAssetCategory.getCategoryId(),
                parentAssetCategoryId,
                getAssetCategoryTitleMap(assetCategory),
                assetCategory.getDescriptionMap(),
                assetVocabularyId,
                properties,
                serviceContext);
      }

      assetCategoryPKs.put(assetCategory.getCategoryId(), importedAssetCategory.getCategoryId());

      assetCategoryUuids.put(assetCategory.getUuid(), importedAssetCategory.getUuid());

      portletDataContext.importPermissions(
          AssetCategory.class,
          assetCategory.getCategoryId(),
          importedAssetCategory.getCategoryId());
    } catch (NoSuchCategoryException nsce) {
      _log.error(
          "Could not find the parent category for category " + assetCategory.getCategoryId());
    }
  }
  @Indexable(type = IndexableType.REINDEX)
  @Override
  public AssetCategory updateCategory(
      long userId,
      long categoryId,
      long parentCategoryId,
      Map<Locale, String> titleMap,
      Map<Locale, String> descriptionMap,
      long vocabularyId,
      String[] categoryProperties,
      ServiceContext serviceContext)
      throws PortalException, SystemException {

    // Category

    String name = titleMap.get(LocaleUtil.getSiteDefault());

    name = ModelHintsUtil.trimString(AssetCategory.class.getName(), "name", name);

    if (categoryProperties == null) {
      categoryProperties = new String[0];
    }

    validate(categoryId, parentCategoryId, name, vocabularyId);

    if (parentCategoryId > 0) {
      assetCategoryPersistence.findByPrimaryKey(parentCategoryId);
    }

    AssetCategory category = assetCategoryPersistence.findByPrimaryKey(categoryId);

    String oldName = category.getName();

    if (vocabularyId != category.getVocabularyId()) {
      assetVocabularyPersistence.findByPrimaryKey(vocabularyId);

      parentCategoryId = AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;

      category.setVocabularyId(vocabularyId);

      updateChildrenVocabularyId(category, vocabularyId);
    }

    category.setModifiedDate(new Date());
    category.setParentCategoryId(parentCategoryId);
    category.setName(name);
    category.setTitleMap(titleMap);
    category.setDescriptionMap(descriptionMap);

    assetCategoryPersistence.update(category);

    // Properties

    List<AssetCategoryProperty> oldCategoryProperties =
        assetCategoryPropertyPersistence.findByCategoryId(categoryId);

    oldCategoryProperties = ListUtil.copy(oldCategoryProperties);

    for (int i = 0; i < categoryProperties.length; i++) {
      String[] categoryProperty =
          StringUtil.split(
              categoryProperties[i], AssetCategoryConstants.PROPERTY_KEY_VALUE_SEPARATOR);

      if (categoryProperty.length <= 1) {
        categoryProperty = StringUtil.split(categoryProperties[i], CharPool.COLON);
      }

      String key = StringPool.BLANK;

      if (categoryProperty.length > 0) {
        key = GetterUtil.getString(categoryProperty[0]);
      }

      String value = StringPool.BLANK;

      if (categoryProperty.length > 1) {
        value = GetterUtil.getString(categoryProperty[1]);
      }

      if (Validator.isNotNull(key)) {
        boolean addCategoryProperty = true;

        AssetCategoryProperty oldCategoryProperty = null;

        Iterator<AssetCategoryProperty> iterator = oldCategoryProperties.iterator();

        while (iterator.hasNext()) {
          oldCategoryProperty = iterator.next();

          if ((categoryId == oldCategoryProperty.getCategoryId())
              && key.equals(oldCategoryProperty.getKey())) {

            addCategoryProperty = false;

            if (!value.equals(oldCategoryProperty.getValue())) {
              assetCategoryPropertyLocalService.updateCategoryProperty(
                  userId, oldCategoryProperty.getCategoryPropertyId(), key, value);
            }

            iterator.remove();

            break;
          }
        }

        if (addCategoryProperty) {
          assetCategoryPropertyLocalService.addCategoryProperty(userId, categoryId, key, value);
        }
      }
    }

    for (AssetCategoryProperty categoryProperty : oldCategoryProperties) {
      assetCategoryPropertyLocalService.deleteAssetCategoryProperty(categoryProperty);
    }

    // Indexer

    if (!oldName.equals(name)) {
      List<AssetEntry> entries = assetCategoryPersistence.getAssetEntries(category.getCategoryId());

      assetEntryLocalService.reindex(entries);
    }

    return category;
  }
  @Override
  protected void doImportStagedModel(PortletDataContext portletDataContext, AssetCategory category)
      throws Exception {

    long userId = portletDataContext.getUserId(category.getUserUuid());

    if (category.getParentCategoryId() != AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {

      StagedModelDataHandlerUtil.importReferenceStagedModel(
          portletDataContext, category, AssetCategory.class, category.getParentCategoryId());
    } else {
      StagedModelDataHandlerUtil.importReferenceStagedModel(
          portletDataContext, category, AssetVocabulary.class, category.getVocabularyId());
    }

    Map<Long, Long> vocabularyIds =
        (Map<Long, Long>) portletDataContext.getNewPrimaryKeysMap(AssetVocabulary.class);

    long vocabularyId =
        MapUtil.getLong(vocabularyIds, category.getVocabularyId(), category.getVocabularyId());

    Map<Long, Long> categoryIds =
        (Map<Long, Long>) portletDataContext.getNewPrimaryKeysMap(AssetCategory.class);

    long parentCategoryId =
        MapUtil.getLong(
            categoryIds, category.getParentCategoryId(), category.getParentCategoryId());

    Element categoryElement = portletDataContext.getImportDataElement(category);

    List<Element> propertyElements = categoryElement.elements("property");

    String[] properties = new String[propertyElements.size()];

    for (int i = 0; i < propertyElements.size(); i++) {
      Element propertyElement = propertyElements.get(i);

      String key = propertyElement.attributeValue("key");
      String value = propertyElement.attributeValue("value");

      properties[i] = key.concat(AssetCategoryConstants.PROPERTY_KEY_VALUE_SEPARATOR).concat(value);
    }

    ServiceContext serviceContext = createServiceContext(portletDataContext, category);

    AssetCategory importedCategory = null;

    AssetCategory existingCategory =
        AssetCategoryUtil.fetchByUUID_G(category.getUuid(), portletDataContext.getScopeGroupId());

    if (existingCategory == null) {
      existingCategory =
          AssetCategoryUtil.fetchByUUID_G(
              category.getUuid(), portletDataContext.getCompanyGroupId());
    }

    if (existingCategory == null) {
      String name =
          getCategoryName(
              null,
              portletDataContext.getScopeGroupId(),
              parentCategoryId,
              category.getName(),
              category.getVocabularyId(),
              2);

      serviceContext.setUuid(category.getUuid());

      importedCategory =
          AssetCategoryLocalServiceUtil.addCategory(
              userId,
              parentCategoryId,
              getCategoryTitleMap(portletDataContext.getScopeGroupId(), category, name),
              category.getDescriptionMap(),
              vocabularyId,
              properties,
              serviceContext);
    } else {
      String name =
          getCategoryName(
              category.getUuid(),
              portletDataContext.getScopeGroupId(),
              parentCategoryId,
              category.getName(),
              category.getVocabularyId(),
              2);

      importedCategory =
          AssetCategoryLocalServiceUtil.updateCategory(
              userId,
              existingCategory.getCategoryId(),
              parentCategoryId,
              getCategoryTitleMap(portletDataContext.getScopeGroupId(), category, name),
              category.getDescriptionMap(),
              vocabularyId,
              properties,
              serviceContext);
    }

    categoryIds.put(category.getCategoryId(), importedCategory.getCategoryId());

    Map<String, String> categoryUuids =
        (Map<String, String>)
            portletDataContext.getNewPrimaryKeysMap(AssetCategory.class + ".uuid");

    categoryUuids.put(category.getUuid(), importedCategory.getUuid());

    portletDataContext.importPermissions(
        AssetCategory.class, category.getCategoryId(), importedCategory.getCategoryId());
  }