001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.asset.service.impl;
016    
017    import com.liferay.portal.kernel.cache.ThreadLocalCachable;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.search.BaseModelSearchResult;
021    import com.liferay.portal.kernel.search.Field;
022    import com.liferay.portal.kernel.search.Hits;
023    import com.liferay.portal.kernel.search.Indexable;
024    import com.liferay.portal.kernel.search.IndexableType;
025    import com.liferay.portal.kernel.search.Indexer;
026    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
027    import com.liferay.portal.kernel.search.QueryConfig;
028    import com.liferay.portal.kernel.search.SearchContext;
029    import com.liferay.portal.kernel.search.SearchException;
030    import com.liferay.portal.kernel.systemevent.SystemEvent;
031    import com.liferay.portal.kernel.transaction.TransactionCommitCallbackRegistryUtil;
032    import com.liferay.portal.kernel.util.CharPool;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.kernel.util.ListUtil;
035    import com.liferay.portal.kernel.util.LocaleUtil;
036    import com.liferay.portal.kernel.util.OrderByComparator;
037    import com.liferay.portal.kernel.util.StringBundler;
038    import com.liferay.portal.kernel.util.StringPool;
039    import com.liferay.portal.kernel.util.StringUtil;
040    import com.liferay.portal.kernel.util.Validator;
041    import com.liferay.portal.model.ModelHintsUtil;
042    import com.liferay.portal.model.ResourceConstants;
043    import com.liferay.portal.model.SystemEventConstants;
044    import com.liferay.portal.model.User;
045    import com.liferay.portal.service.ServiceContext;
046    import com.liferay.portlet.asset.AssetCategoryNameException;
047    import com.liferay.portlet.asset.DuplicateCategoryException;
048    import com.liferay.portlet.asset.model.AssetCategory;
049    import com.liferay.portlet.asset.model.AssetCategoryConstants;
050    import com.liferay.portlet.asset.model.AssetCategoryProperty;
051    import com.liferay.portlet.asset.model.AssetEntry;
052    import com.liferay.portlet.asset.service.base.AssetCategoryLocalServiceBaseImpl;
053    import com.liferay.portlet.asset.util.AssetCategoryUtil;
054    import com.liferay.portlet.asset.util.comparator.AssetCategoryLeftCategoryIdComparator;
055    
056    import java.io.Serializable;
057    
058    import java.util.ArrayList;
059    import java.util.Collections;
060    import java.util.Date;
061    import java.util.HashMap;
062    import java.util.Iterator;
063    import java.util.List;
064    import java.util.Locale;
065    import java.util.Map;
066    import java.util.concurrent.Callable;
067    
068    /**
069     * Provides the local service for accessing, adding, deleting, merging, moving,
070     * and updating asset categories.
071     *
072     * @author Brian Wing Shun Chan
073     * @author Alvaro del Castillo
074     * @author Jorge Ferrer
075     * @author Bruno Farache
076     */
077    public class AssetCategoryLocalServiceImpl
078            extends AssetCategoryLocalServiceBaseImpl {
079    
080            @Indexable(type = IndexableType.REINDEX)
081            @Override
082            public AssetCategory addCategory(
083                            long userId, long parentCategoryId, Map<Locale, String> titleMap,
084                            Map<Locale, String> descriptionMap, long vocabularyId,
085                            String[] categoryProperties, ServiceContext serviceContext)
086                    throws PortalException {
087    
088                    // Category
089    
090                    User user = userPersistence.findByPrimaryKey(userId);
091                    long groupId = serviceContext.getScopeGroupId();
092    
093                    String name = titleMap.get(LocaleUtil.getSiteDefault());
094    
095                    name = ModelHintsUtil.trimString(
096                            AssetCategory.class.getName(), "name", name);
097    
098                    if (categoryProperties == null) {
099                            categoryProperties = new String[0];
100                    }
101    
102                    Date now = new Date();
103    
104                    validate(0, parentCategoryId, name, vocabularyId);
105    
106                    if (parentCategoryId > 0) {
107                            assetCategoryPersistence.findByPrimaryKey(parentCategoryId);
108                    }
109    
110                    assetVocabularyPersistence.findByPrimaryKey(vocabularyId);
111    
112                    long categoryId = counterLocalService.increment();
113    
114                    AssetCategory category = assetCategoryPersistence.create(categoryId);
115    
116                    category.setUuid(serviceContext.getUuid());
117                    category.setGroupId(groupId);
118                    category.setCompanyId(user.getCompanyId());
119                    category.setUserId(user.getUserId());
120                    category.setUserName(user.getFullName());
121                    category.setCreateDate(now);
122                    category.setModifiedDate(now);
123                    category.setParentCategoryId(parentCategoryId);
124                    category.setName(name);
125                    category.setTitleMap(titleMap);
126                    category.setDescriptionMap(descriptionMap);
127                    category.setVocabularyId(vocabularyId);
128    
129                    assetCategoryPersistence.update(category);
130    
131                    // Resources
132    
133                    if (serviceContext.isAddGroupPermissions() ||
134                            serviceContext.isAddGuestPermissions()) {
135    
136                            addCategoryResources(
137                                    category, serviceContext.isAddGroupPermissions(),
138                                    serviceContext.isAddGuestPermissions());
139                    }
140                    else {
141                            addCategoryResources(
142                                    category, serviceContext.getGroupPermissions(),
143                                    serviceContext.getGuestPermissions());
144                    }
145    
146                    // Properties
147    
148                    for (int i = 0; i < categoryProperties.length; i++) {
149                            String[] categoryProperty = StringUtil.split(
150                                    categoryProperties[i],
151                                    AssetCategoryConstants.PROPERTY_KEY_VALUE_SEPARATOR);
152    
153                            if (categoryProperty.length <= 1) {
154                                    categoryProperty = StringUtil.split(
155                                            categoryProperties[i], CharPool.COLON);
156                            }
157    
158                            String key = StringPool.BLANK;
159                            String value = StringPool.BLANK;
160    
161                            if (categoryProperty.length > 1) {
162                                    key = GetterUtil.getString(categoryProperty[0]);
163                                    value = GetterUtil.getString(categoryProperty[1]);
164                            }
165    
166                            if (Validator.isNotNull(key)) {
167                                    assetCategoryPropertyLocalService.addCategoryProperty(
168                                            userId, categoryId, key, value);
169                            }
170                    }
171    
172                    return category;
173            }
174    
175            @Override
176            public AssetCategory addCategory(
177                            long userId, String title, long vocabularyId,
178                            ServiceContext serviceContext)
179                    throws PortalException {
180    
181                    Map<Locale, String> titleMap = new HashMap<Locale, String>();
182    
183                    Locale locale = LocaleUtil.getSiteDefault();
184    
185                    titleMap.put(locale, title);
186    
187                    Map<Locale, String> descriptionMap = new HashMap<Locale, String>();
188    
189                    descriptionMap.put(locale, StringPool.BLANK);
190    
191                    return assetCategoryLocalService.addCategory(
192                            userId, AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID, titleMap,
193                            descriptionMap, vocabularyId, null, serviceContext);
194            }
195    
196            @Override
197            public void addCategoryResources(
198                            AssetCategory category, boolean addGroupPermissions,
199                            boolean addGuestPermissions)
200                    throws PortalException {
201    
202                    resourceLocalService.addResources(
203                            category.getCompanyId(), category.getGroupId(),
204                            category.getUserId(), AssetCategory.class.getName(),
205                            category.getCategoryId(), false, addGroupPermissions,
206                            addGuestPermissions);
207            }
208    
209            @Override
210            public void addCategoryResources(
211                            AssetCategory category, String[] groupPermissions,
212                            String[] guestPermissions)
213                    throws PortalException {
214    
215                    resourceLocalService.addModelResources(
216                            category.getCompanyId(), category.getGroupId(),
217                            category.getUserId(), AssetCategory.class.getName(),
218                            category.getCategoryId(), groupPermissions, guestPermissions);
219            }
220    
221            @Override
222            public void deleteCategories(List<AssetCategory> categories)
223                    throws PortalException {
224    
225                    List<Long> rebuildTreeGroupIds = new ArrayList<Long>();
226    
227                    for (AssetCategory category : categories) {
228                            if (!rebuildTreeGroupIds.contains(category.getGroupId()) &&
229                                    (getChildCategoriesCount(category.getCategoryId()) > 0)) {
230    
231                                    final long groupId = category.getGroupId();
232    
233                                    TransactionCommitCallbackRegistryUtil.registerCallback(
234                                            new Callable<Void>() {
235    
236                                                    @Override
237                                                    public Void call() throws Exception {
238                                                            assetCategoryLocalService.rebuildTree(
239                                                                    groupId, true);
240    
241                                                            return null;
242                                                    }
243    
244                                            });
245    
246                                    rebuildTreeGroupIds.add(groupId);
247                            }
248    
249                            deleteCategory(category, true);
250                    }
251            }
252    
253            @Override
254            public void deleteCategories(long[] categoryIds) throws PortalException {
255                    List<AssetCategory> categories = new ArrayList<AssetCategory>();
256    
257                    for (long categoryId : categoryIds) {
258                            AssetCategory category = assetCategoryPersistence.findByPrimaryKey(
259                                    categoryId);
260    
261                            categories.add(category);
262                    }
263    
264                    deleteCategories(categories);
265            }
266    
267            @Override
268            @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
269            public AssetCategory deleteCategory(AssetCategory category)
270                    throws PortalException {
271    
272                    return assetCategoryLocalService.deleteCategory(category, false);
273            }
274    
275            @Indexable(type = IndexableType.DELETE)
276            @Override
277            public AssetCategory deleteCategory(
278                            AssetCategory category, boolean skipRebuildTree)
279                    throws PortalException {
280    
281                    // Categories
282    
283                    List<AssetCategory> categories =
284                            assetCategoryPersistence.findByParentCategoryId(
285                                    category.getCategoryId());
286    
287                    for (AssetCategory curCategory : categories) {
288                            deleteCategory(curCategory, true);
289                    }
290    
291                    if (!categories.isEmpty() && !skipRebuildTree) {
292                            final long groupId = category.getGroupId();
293    
294                            TransactionCommitCallbackRegistryUtil.registerCallback(
295                                    new Callable<Void>() {
296    
297                                            @Override
298                                            public Void call() throws Exception {
299                                                    assetCategoryLocalService.rebuildTree(groupId, true);
300    
301                                                    return null;
302                                            }
303    
304                                    });
305                    }
306    
307                    // Entries
308    
309                    List<AssetEntry> entries = assetCategoryPersistence.getAssetEntries(
310                            category.getCategoryId());
311    
312                    // Category
313    
314                    assetCategoryPersistence.remove(category);
315    
316                    // Resources
317    
318                    resourceLocalService.deleteResource(
319                            category.getCompanyId(), AssetCategory.class.getName(),
320                            ResourceConstants.SCOPE_INDIVIDUAL, category.getCategoryId());
321    
322                    // Properties
323    
324                    assetCategoryPropertyLocalService.deleteCategoryProperties(
325                            category.getCategoryId());
326    
327                    // Indexer
328    
329                    assetEntryLocalService.reindex(entries);
330    
331                    return category;
332            }
333    
334            @Override
335            public AssetCategory deleteCategory(long categoryId)
336                    throws PortalException {
337    
338                    AssetCategory category = assetCategoryPersistence.findByPrimaryKey(
339                            categoryId);
340    
341                    return assetCategoryLocalService.deleteCategory(category);
342            }
343    
344            @Override
345            public void deleteVocabularyCategories(long vocabularyId)
346                    throws PortalException {
347    
348                    List<AssetCategory> categories =
349                            assetCategoryPersistence.findByP_V(
350                                    AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID, vocabularyId,
351                                    QueryUtil.ALL_POS, QueryUtil.ALL_POS,
352                                    new AssetCategoryLeftCategoryIdComparator(false));
353    
354                    assetCategoryLocalService.deleteCategories(categories);
355            }
356    
357            @Override
358            public AssetCategory fetchCategory(long categoryId) {
359                    return assetCategoryPersistence.fetchByPrimaryKey(categoryId);
360            }
361    
362            @Override
363            public List<AssetCategory> getCategories() {
364                    return assetCategoryPersistence.findAll();
365            }
366    
367            @Override
368            @ThreadLocalCachable
369            public List<AssetCategory> getCategories(long classNameId, long classPK) {
370                    AssetEntry entry = assetEntryPersistence.fetchByC_C(
371                            classNameId, classPK);
372    
373                    if (entry == null) {
374                            return Collections.emptyList();
375                    }
376    
377                    return assetEntryPersistence.getAssetCategories(entry.getEntryId());
378            }
379    
380            @Override
381            public List<AssetCategory> getCategories(String className, long classPK) {
382                    long classNameId = classNameLocalService.getClassNameId(className);
383    
384                    return getCategories(classNameId, classPK);
385            }
386    
387            @Override
388            public AssetCategory getCategory(long categoryId) throws PortalException {
389                    return assetCategoryPersistence.findByPrimaryKey(categoryId);
390            }
391    
392            @Override
393            public AssetCategory getCategory(String uuid, long groupId)
394                    throws PortalException {
395    
396                    return assetCategoryPersistence.findByUUID_G(uuid, groupId);
397            }
398    
399            @Override
400            public long[] getCategoryIds(String className, long classPK) {
401                    return getCategoryIds(getCategories(className, classPK));
402            }
403    
404            @Override
405            public String[] getCategoryNames() {
406                    return getCategoryNames(getCategories());
407            }
408    
409            @Override
410            public String[] getCategoryNames(long classNameId, long classPK) {
411                    return getCategoryNames(getCategories(classNameId, classPK));
412            }
413    
414            @Override
415            public String[] getCategoryNames(String className, long classPK) {
416                    return getCategoryNames(getCategories(className, classPK));
417            }
418    
419            @Override
420            public List<AssetCategory> getChildCategories(long parentCategoryId) {
421                    return assetCategoryPersistence.findByParentCategoryId(
422                            parentCategoryId);
423            }
424    
425            @Override
426            public List<AssetCategory> getChildCategories(
427                    long parentCategoryId, int start, int end,
428                    OrderByComparator<AssetCategory> obc) {
429    
430                    return assetCategoryPersistence.findByParentCategoryId(
431                            parentCategoryId, start, end, obc);
432            }
433    
434            @Override
435            public int getChildCategoriesCount(long parentCategoryId) {
436                    return assetCategoryPersistence.countByParentCategoryId(
437                            parentCategoryId);
438            }
439    
440            @Override
441            public List<AssetCategory> getEntryCategories(long entryId) {
442                    return assetEntryPersistence.getAssetCategories(entryId);
443            }
444    
445            @Override
446            public List<Long> getSubcategoryIds(long parentCategoryId) {
447                    AssetCategory parentAssetCategory =
448                            assetCategoryPersistence.fetchByPrimaryKey(parentCategoryId);
449    
450                    if (parentAssetCategory == null) {
451                            return Collections.emptyList();
452                    }
453    
454                    return ListUtil.toList(
455                            assetCategoryPersistence.getDescendants(parentAssetCategory),
456                            AssetCategory.CATEGORY_ID_ACCESSOR);
457            }
458    
459            @Override
460            public List<AssetCategory> getVocabularyCategories(
461                    long vocabularyId, int start, int end,
462                    OrderByComparator<AssetCategory> obc) {
463    
464                    return assetCategoryPersistence.findByVocabularyId(
465                            vocabularyId, start, end, obc);
466            }
467    
468            @Override
469            public List<AssetCategory> getVocabularyCategories(
470                    long parentCategoryId, long vocabularyId, int start, int end,
471                    OrderByComparator<AssetCategory> obc) {
472    
473                    return assetCategoryPersistence.findByP_V(
474                            parentCategoryId, vocabularyId, start, end, obc);
475            }
476    
477            @Override
478            public int getVocabularyCategoriesCount(long vocabularyId) {
479                    return assetCategoryPersistence.countByVocabularyId(vocabularyId);
480            }
481    
482            @Override
483            public List<AssetCategory> getVocabularyRootCategories(
484                    long vocabularyId, int start, int end,
485                    OrderByComparator<AssetCategory> obc) {
486    
487                    return getVocabularyCategories(
488                            AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID, vocabularyId,
489                            start, end, obc);
490            }
491    
492            @Override
493            public int getVocabularyRootCategoriesCount(long vocabularyId) {
494                    return assetCategoryPersistence.countByP_V(
495                            AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID, vocabularyId);
496            }
497    
498            @Indexable(type = IndexableType.REINDEX)
499            @Override
500            public AssetCategory mergeCategories(long fromCategoryId, long toCategoryId)
501                    throws PortalException {
502    
503                    List<AssetEntry> entries = assetCategoryPersistence.getAssetEntries(
504                            fromCategoryId);
505    
506                    assetCategoryPersistence.addAssetEntries(toCategoryId, entries);
507    
508                    List<AssetCategoryProperty> categoryProperties =
509                            assetCategoryPropertyPersistence.findByCategoryId(fromCategoryId);
510    
511                    for (AssetCategoryProperty fromCategoryProperty : categoryProperties) {
512                            AssetCategoryProperty toCategoryProperty =
513                                    assetCategoryPropertyPersistence.fetchByCA_K(
514                                            toCategoryId, fromCategoryProperty.getKey());
515    
516                            if (toCategoryProperty == null) {
517                                    fromCategoryProperty.setCategoryId(toCategoryId);
518    
519                                    assetCategoryPropertyPersistence.update(fromCategoryProperty);
520                            }
521                    }
522    
523                    assetCategoryLocalService.deleteCategory(fromCategoryId);
524    
525                    return getCategory(toCategoryId);
526            }
527    
528            @Indexable(type = IndexableType.REINDEX)
529            @Override
530            public AssetCategory moveCategory(
531                            long categoryId, long parentCategoryId, long vocabularyId,
532                            ServiceContext serviceContext)
533                    throws PortalException {
534    
535                    AssetCategory category = assetCategoryPersistence.findByPrimaryKey(
536                            categoryId);
537    
538                    validate(
539                            categoryId, parentCategoryId, category.getName(), vocabularyId);
540    
541                    if (parentCategoryId > 0) {
542                            assetCategoryPersistence.findByPrimaryKey(parentCategoryId);
543                    }
544    
545                    if (vocabularyId != category.getVocabularyId()) {
546                            assetVocabularyPersistence.findByPrimaryKey(vocabularyId);
547    
548                            category.setVocabularyId(vocabularyId);
549    
550                            updateChildrenVocabularyId(category, vocabularyId);
551                    }
552    
553                    category.setModifiedDate(new Date());
554                    category.setParentCategoryId(parentCategoryId);
555    
556                    assetCategoryPersistence.update(category);
557    
558                    return category;
559            }
560    
561            @Override
562            public void rebuildTree(long groupId, boolean force) {
563                    assetCategoryPersistence.rebuildTree(groupId, force);
564            }
565    
566            @Override
567            public List<AssetCategory> search(
568                    long groupId, String name, String[] categoryProperties, int start,
569                    int end) {
570    
571                    return assetCategoryFinder.findByG_N_P(
572                            groupId, name, categoryProperties, start, end);
573            }
574    
575            @Override
576            public BaseModelSearchResult<AssetCategory> searchCategories(
577                            long companyId, long groupIds, String title, long vocabularyId,
578                            int start, int end)
579                    throws PortalException {
580    
581                    return searchCategories(
582                            companyId, new long[] {groupIds}, title, new long[] {vocabularyId},
583                            start, end);
584            }
585    
586            @Override
587            public BaseModelSearchResult<AssetCategory> searchCategories(
588                            long companyId, long[] groupIds, String title, long[] vocabularyIds,
589                            int start, int end)
590                    throws PortalException {
591    
592                    SearchContext searchContext = buildSearchContext(
593                            companyId, groupIds, title, new long[0], vocabularyIds, start, end);
594    
595                    return searchCategories(searchContext);
596            }
597    
598            @Override
599            public BaseModelSearchResult<AssetCategory> searchCategories(
600                            long companyId, long[] groupIds, String title,
601                            long[] parentCategoryIds, long[] vocabularyIds, int start, int end)
602                    throws PortalException {
603    
604                    SearchContext searchContext = buildSearchContext(
605                            companyId, groupIds, title, parentCategoryIds, vocabularyIds, start,
606                            end);
607    
608                    return searchCategories(searchContext);
609            }
610    
611            @Indexable(type = IndexableType.REINDEX)
612            @Override
613            public AssetCategory updateCategory(
614                            long userId, long categoryId, long parentCategoryId,
615                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
616                            long vocabularyId, String[] categoryProperties,
617                            ServiceContext serviceContext)
618                    throws PortalException {
619    
620                    // Category
621    
622                    String name = titleMap.get(LocaleUtil.getSiteDefault());
623    
624                    name = ModelHintsUtil.trimString(
625                            AssetCategory.class.getName(), "name", name);
626    
627                    if (categoryProperties == null) {
628                            categoryProperties = new String[0];
629                    }
630    
631                    validate(categoryId, parentCategoryId, name, vocabularyId);
632    
633                    if (parentCategoryId > 0) {
634                            assetCategoryPersistence.findByPrimaryKey(parentCategoryId);
635                    }
636    
637                    AssetCategory category = assetCategoryPersistence.findByPrimaryKey(
638                            categoryId);
639    
640                    String oldName = category.getName();
641    
642                    if (vocabularyId != category.getVocabularyId()) {
643                            assetVocabularyPersistence.findByPrimaryKey(vocabularyId);
644    
645                            parentCategoryId =
646                                    AssetCategoryConstants.DEFAULT_PARENT_CATEGORY_ID;
647    
648                            category.setVocabularyId(vocabularyId);
649    
650                            updateChildrenVocabularyId(category, vocabularyId);
651                    }
652    
653                    category.setModifiedDate(new Date());
654                    category.setParentCategoryId(parentCategoryId);
655                    category.setName(name);
656                    category.setTitleMap(titleMap);
657                    category.setDescriptionMap(descriptionMap);
658    
659                    assetCategoryPersistence.update(category);
660    
661                    // Properties
662    
663                    List<AssetCategoryProperty> oldCategoryProperties =
664                            assetCategoryPropertyPersistence.findByCategoryId(categoryId);
665    
666                    oldCategoryProperties = ListUtil.copy(oldCategoryProperties);
667    
668                    for (int i = 0; i < categoryProperties.length; i++) {
669                            String[] categoryProperty = StringUtil.split(
670                                    categoryProperties[i],
671                                    AssetCategoryConstants.PROPERTY_KEY_VALUE_SEPARATOR);
672    
673                            if (categoryProperty.length <= 1) {
674                                    categoryProperty = StringUtil.split(
675                                            categoryProperties[i], CharPool.COLON);
676                            }
677    
678                            String key = StringPool.BLANK;
679    
680                            if (categoryProperty.length > 0) {
681                                    key = GetterUtil.getString(categoryProperty[0]);
682                            }
683    
684                            String value = StringPool.BLANK;
685    
686                            if (categoryProperty.length > 1) {
687                                    value = GetterUtil.getString(categoryProperty[1]);
688                            }
689    
690                            if (Validator.isNotNull(key)) {
691                                    boolean addCategoryProperty = true;
692    
693                                    AssetCategoryProperty oldCategoryProperty = null;
694    
695                                    Iterator<AssetCategoryProperty> iterator =
696                                            oldCategoryProperties.iterator();
697    
698                                    while (iterator.hasNext()) {
699                                            oldCategoryProperty = iterator.next();
700    
701                                            if ((categoryId == oldCategoryProperty.getCategoryId()) &&
702                                                    key.equals(oldCategoryProperty.getKey())) {
703    
704                                                    addCategoryProperty = false;
705    
706                                                    if (!value.equals(oldCategoryProperty.getValue())) {
707                                                            assetCategoryPropertyLocalService.
708                                                                    updateCategoryProperty(
709                                                                            userId,
710                                                                            oldCategoryProperty.getCategoryPropertyId(),
711                                                                            key, value);
712                                                    }
713    
714                                                    iterator.remove();
715    
716                                                    break;
717                                            }
718                                    }
719    
720                                    if (addCategoryProperty) {
721                                            assetCategoryPropertyLocalService.addCategoryProperty(
722                                                    userId, categoryId, key, value);
723                                    }
724                            }
725                    }
726    
727                    for (AssetCategoryProperty categoryProperty : oldCategoryProperties) {
728                            assetCategoryPropertyLocalService.deleteAssetCategoryProperty(
729                                    categoryProperty);
730                    }
731    
732                    // Indexer
733    
734                    if (!oldName.equals(name)) {
735                            List<AssetEntry> entries = assetCategoryPersistence.getAssetEntries(
736                                    category.getCategoryId());
737    
738                            assetEntryLocalService.reindex(entries);
739                    }
740    
741                    return category;
742            }
743    
744            protected SearchContext buildSearchContext(
745                    long companyId, long[] groupIds, String title, long[] parentCategoryIds,
746                    long[] vocabularyIds, int start, int end) {
747    
748                    SearchContext searchContext = new SearchContext();
749    
750                    Map<String, Serializable> attributes =
751                            new HashMap<String, Serializable>();
752    
753                    attributes.put(Field.ASSET_PARENT_CATEGORY_IDS, parentCategoryIds);
754                    attributes.put(Field.ASSET_VOCABULARY_IDS, vocabularyIds);
755                    attributes.put(Field.TITLE, title);
756    
757                    searchContext.setAttributes(attributes);
758    
759                    searchContext.setCompanyId(companyId);
760                    searchContext.setEnd(end);
761                    searchContext.setGroupIds(groupIds);
762                    searchContext.setKeywords(title);
763                    searchContext.setStart(start);
764    
765                    QueryConfig queryConfig = searchContext.getQueryConfig();
766    
767                    queryConfig.setHighlightEnabled(false);
768                    queryConfig.setScoreEnabled(false);
769    
770                    return searchContext;
771            }
772    
773            protected long[] getCategoryIds(List<AssetCategory> categories) {
774                    return ListUtil.toLongArray(
775                            categories, AssetCategory.CATEGORY_ID_ACCESSOR);
776            }
777    
778            protected String[] getCategoryNames(List<AssetCategory> categories) {
779                    return ListUtil.toArray(categories, AssetCategory.NAME_ACCESSOR);
780            }
781    
782            protected BaseModelSearchResult<AssetCategory> searchCategories(
783                            SearchContext searchContext)
784                    throws PortalException {
785    
786                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
787                            AssetCategory.class);
788    
789                    for (int i = 0; i < 10; i++) {
790                            Hits hits = indexer.search(searchContext);
791    
792                            List<AssetCategory> categories = AssetCategoryUtil.getCategories(
793                                    hits);
794    
795                            if (categories != null) {
796                                    return new BaseModelSearchResult<AssetCategory>(
797                                            categories, hits.getLength());
798                            }
799                    }
800    
801                    throw new SearchException(
802                            "Unable to fix the search index after 10 attempts");
803            }
804    
805            protected void updateChildrenVocabularyId(
806                    AssetCategory category, long vocabularyId) {
807    
808                    List<AssetCategory> childrenCategories =
809                            assetCategoryPersistence.findByParentCategoryId(
810                                    category.getCategoryId());
811    
812                    if (!childrenCategories.isEmpty()) {
813                            for (AssetCategory childCategory : childrenCategories) {
814                                    childCategory.setVocabularyId(vocabularyId);
815                                    childCategory.setModifiedDate(new Date());
816    
817                                    assetCategoryPersistence.update(childCategory);
818    
819                                    updateChildrenVocabularyId (childCategory, vocabularyId);
820                            }
821                    }
822            }
823    
824            protected void validate(
825                            long categoryId, long parentCategoryId, String name,
826                            long vocabularyId)
827                    throws PortalException {
828    
829                    if (Validator.isNull(name)) {
830                            throw new AssetCategoryNameException();
831                    }
832    
833                    AssetCategory category = assetCategoryPersistence.fetchByP_N_V(
834                            parentCategoryId, name, vocabularyId);
835    
836                    if ((category != null) && (category.getCategoryId() != categoryId)) {
837                            StringBundler sb = new StringBundler(4);
838    
839                            sb.append("There is another category named ");
840                            sb.append(name);
841                            sb.append(" as a child of category ");
842                            sb.append(parentCategoryId);
843    
844                            throw new DuplicateCategoryException(sb.toString());
845                    }
846            }
847    
848    }