1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.tags.service.impl;
24  
25  import com.liferay.portal.PortalException;
26  import com.liferay.portal.SystemException;
27  import com.liferay.portal.kernel.json.JSONArray;
28  import com.liferay.portal.kernel.util.ArrayUtil;
29  import com.liferay.portal.kernel.util.GetterUtil;
30  import com.liferay.portal.kernel.util.ListUtil;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.ResourceConstants;
35  import com.liferay.portal.model.User;
36  import com.liferay.portal.service.ServiceContext;
37  import com.liferay.portal.util.PortalUtil;
38  import com.liferay.portal.util.PropsValues;
39  import com.liferay.portlet.tags.DuplicateEntryException;
40  import com.liferay.portlet.tags.NoSuchEntryException;
41  import com.liferay.portlet.tags.NoSuchVocabularyException;
42  import com.liferay.portlet.tags.TagsEntryException;
43  import com.liferay.portlet.tags.model.TagsAsset;
44  import com.liferay.portlet.tags.model.TagsEntry;
45  import com.liferay.portlet.tags.model.TagsEntryConstants;
46  import com.liferay.portlet.tags.model.TagsProperty;
47  import com.liferay.portlet.tags.model.TagsVocabulary;
48  import com.liferay.portlet.tags.service.base.TagsEntryLocalServiceBaseImpl;
49  import com.liferay.portlet.tags.util.TagsUtil;
50  import com.liferay.util.Autocomplete;
51  
52  import java.util.ArrayList;
53  import java.util.Date;
54  import java.util.HashSet;
55  import java.util.List;
56  import java.util.Set;
57  
58  /**
59   * <a href="TagsEntryLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
60   *
61   * @author Brian Wing Shun Chan
62   * @author Alvaro del Castillo
63   * @author Jorge Ferrer
64   * @author Bruno Farache
65   *
66   */
67  public class TagsEntryLocalServiceImpl extends TagsEntryLocalServiceBaseImpl {
68  
69      public TagsEntry addEntry(
70              long userId, String parentEntryName, String name,
71              String vocabularyName, String[] properties,
72              ServiceContext serviceContext)
73          throws PortalException, SystemException {
74  
75          // Entry
76  
77          User user = userPersistence.findByPrimaryKey(userId);
78          long groupId = serviceContext.getScopeGroupId();
79  
80          if (Validator.isNull(vocabularyName)) {
81              vocabularyName = PropsValues.TAGS_VOCABULARY_DEFAULT;
82          }
83  
84          if (properties == null) {
85              properties = new String[0];
86          }
87  
88          Date now = new Date();
89  
90          long entryId = counterLocalService.increment();
91  
92          TagsEntry entry = tagsEntryPersistence.create(entryId);
93  
94          entry.setGroupId(groupId);
95          entry.setCompanyId(user.getCompanyId());
96          entry.setUserId(user.getUserId());
97          entry.setUserName(user.getFullName());
98          entry.setCreateDate(now);
99          entry.setModifiedDate(now);
100 
101         TagsVocabulary vocabulary = null;
102 
103         try {
104             vocabulary = tagsVocabularyPersistence.findByG_N(
105                 groupId, vocabularyName);
106         }
107         catch (NoSuchVocabularyException nsve) {
108             if (vocabularyName.equals(PropsValues.TAGS_VOCABULARY_DEFAULT)) {
109                 ServiceContext vocabularyServiceContext = new ServiceContext();
110 
111                 vocabularyServiceContext.setAddCommunityPermissions(true);
112                 vocabularyServiceContext.setAddGuestPermissions(true);
113                 vocabularyServiceContext.setScopeGroupId(groupId);
114 
115                 vocabulary = tagsVocabularyLocalService.addVocabulary(
116                     userId, vocabularyName, TagsEntryConstants.FOLKSONOMY_TAG,
117                     vocabularyServiceContext);
118             }
119             else {
120                 throw nsve;
121             }
122         }
123 
124         entry.setVocabularyId(vocabulary.getVocabularyId());
125 
126         boolean folksonomy = vocabulary.isFolksonomy();
127 
128         name = name.trim();
129 
130         if (folksonomy) {
131             name = name.toLowerCase();
132         }
133 
134         if (hasEntry(groupId, name, folksonomy)) {
135             throw new DuplicateEntryException(
136                 "A tag entry with the name " + name + " already exists");
137         }
138 
139         validate(name);
140 
141         entry.setName(name);
142 
143         if (Validator.isNotNull(parentEntryName)) {
144             TagsEntry parentEntry = getEntry(
145                 groupId, parentEntryName, folksonomy);
146 
147             entry.setParentEntryId(parentEntry.getEntryId());
148         }
149         else {
150             entry.setParentEntryId(TagsEntryConstants.DEFAULT_PARENT_ENTRY_ID);
151         }
152 
153         tagsEntryPersistence.update(entry, false);
154 
155         // Resources
156 
157         if (serviceContext.getAddCommunityPermissions() ||
158             serviceContext.getAddGuestPermissions()) {
159 
160             addEntryResources(
161                 entry, serviceContext.getAddCommunityPermissions(),
162                 serviceContext.getAddGuestPermissions());
163         }
164         else {
165             addEntryResources(
166                 entry, serviceContext.getCommunityPermissions(),
167                 serviceContext.getGuestPermissions());
168         }
169 
170         // Properties
171 
172         for (int i = 0; i < properties.length; i++) {
173             String[] property = StringUtil.split(
174                 properties[i], StringPool.COLON);
175 
176             String key = StringPool.BLANK;
177 
178             if (property.length > 1) {
179                 key = GetterUtil.getString(property[1]);
180             }
181 
182             String value = StringPool.BLANK;
183 
184             if (property.length > 2) {
185                 value = GetterUtil.getString(property[2]);
186             }
187 
188             if (Validator.isNotNull(key)) {
189                 tagsPropertyLocalService.addProperty(
190                     userId, entryId, key, value);
191             }
192         }
193 
194         return entry;
195     }
196 
197     public void addEntryResources(
198             TagsEntry entry, boolean addCommunityPermissions,
199             boolean addGuestPermissions)
200         throws PortalException, SystemException {
201 
202         resourceLocalService.addResources(
203             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
204             TagsEntry.class.getName(), entry.getEntryId(), false,
205             addCommunityPermissions, addGuestPermissions);
206     }
207 
208     public void addEntryResources(
209             TagsEntry entry, String[] communityPermissions,
210             String[] guestPermissions)
211         throws PortalException, SystemException {
212 
213         resourceLocalService.addModelResources(
214             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
215             TagsEntry.class.getName(), entry.getEntryId(), communityPermissions,
216             guestPermissions);
217     }
218 
219     public void checkEntries(long userId, long groupId, String[] names)
220         throws PortalException, SystemException {
221 
222         for (String name : names) {
223             try {
224                 getEntry(groupId, name, TagsEntryConstants.FOLKSONOMY_TAG);
225             }
226             catch (NoSuchEntryException nsee) {
227                 ServiceContext serviceContext = new ServiceContext();
228 
229                 serviceContext.setAddCommunityPermissions(true);
230                 serviceContext.setAddGuestPermissions(true);
231                 serviceContext.setScopeGroupId(groupId);
232 
233                 addEntry(
234                     userId, null, name, null,
235                     PropsValues.TAGS_PROPERTIES_DEFAULT, serviceContext);
236             }
237         }
238     }
239 
240     public void deleteEntry(long entryId)
241         throws PortalException, SystemException {
242 
243         TagsEntry entry = tagsEntryPersistence.findByPrimaryKey(entryId);
244 
245         deleteEntry(entry);
246     }
247 
248     public void deleteEntry(TagsEntry entry)
249         throws PortalException, SystemException {
250 
251         // Properties
252 
253         tagsPropertyLocalService.deleteProperties(entry.getEntryId());
254 
255         // Resources
256 
257         resourceLocalService.deleteResource(
258             entry.getCompanyId(), TagsEntry.class.getName(),
259             ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
260 
261         // Entry
262 
263         tagsEntryPersistence.remove(entry);
264     }
265 
266     public void deleteVocabularyEntries(long vocabularyId)
267         throws PortalException, SystemException {
268 
269         List<TagsEntry> entries = tagsEntryPersistence.findByVocabularyId(
270             vocabularyId);
271 
272         for (TagsEntry entry : entries) {
273             deleteEntry(entry);
274         }
275     }
276 
277     public boolean hasEntry(long groupId, String name, boolean folksonomy)
278         throws PortalException, SystemException {
279 
280         try {
281             getEntry(groupId, name, folksonomy);
282 
283             return true;
284         }
285         catch (NoSuchEntryException nsee) {
286             return false;
287         }
288     }
289 
290     public List<TagsEntry> getAssetEntries(long assetId, boolean folksonomy)
291         throws SystemException {
292 
293         return tagsEntryFinder.findByA_F(assetId, folksonomy);
294     }
295 
296     public List<TagsEntry> getEntries() throws SystemException {
297         return getEntries(TagsEntryConstants.FOLKSONOMY_TAG);
298     }
299 
300     public List<TagsEntry> getEntries(boolean folksonomy)
301         throws SystemException {
302 
303         return tagsEntryFinder.findByFolksonomy(folksonomy);
304     }
305 
306     public List<TagsEntry> getEntries(String className, long classPK)
307         throws SystemException {
308 
309         return getEntries(
310             className, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
311     }
312 
313     public List<TagsEntry> getEntries(long classNameId, long classPK)
314         throws SystemException {
315 
316         return getEntries(
317             classNameId, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
318     }
319 
320     public List<TagsEntry> getEntries(
321             String className, long classPK, boolean folksonomy)
322         throws SystemException {
323 
324         long classNameId = PortalUtil.getClassNameId(className);
325 
326         return getEntries(classNameId, classPK, folksonomy);
327     }
328 
329     public List<TagsEntry> getEntries(
330             long classNameId, long classPK, boolean folksonomy)
331         throws SystemException {
332 
333         TagsAsset asset = tagsAssetPersistence.fetchByC_C(classNameId, classPK);
334 
335         if (asset == null) {
336             return new ArrayList<TagsEntry>();
337         }
338         else {
339             return getAssetEntries(asset.getAssetId(), folksonomy);
340         }
341     }
342 
343     public List<TagsEntry> getEntries(
344             long groupId, long classNameId, String name)
345         throws SystemException {
346 
347         return tagsEntryFinder.findByG_C_N_F(
348             groupId, classNameId, name, TagsEntryConstants.FOLKSONOMY_TAG);
349     }
350 
351     public List<TagsEntry> getEntries(
352             long groupId, long classNameId, String name, int start, int end)
353         throws SystemException {
354 
355         return tagsEntryFinder.findByG_C_N_F(
356             groupId, classNameId, name,
357             TagsEntryConstants.FOLKSONOMY_TAG, start, end);
358     }
359 
360     public int getEntriesSize(long groupId, long classNameId, String name)
361         throws SystemException {
362 
363         return tagsEntryFinder.countByG_C_N_F(
364             groupId, classNameId, name, TagsEntryConstants.FOLKSONOMY_TAG);
365     }
366 
367     public TagsEntry getEntry(long entryId)
368         throws PortalException, SystemException {
369 
370         return tagsEntryPersistence.findByPrimaryKey(entryId);
371     }
372 
373     public TagsEntry getEntry(long groupId, String name)
374         throws PortalException, SystemException {
375 
376         return getEntry(groupId, name, TagsEntryConstants.FOLKSONOMY_TAG);
377     }
378 
379     public TagsEntry getEntry(long groupId, String name, boolean folksonomy)
380         throws PortalException, SystemException {
381 
382         return tagsEntryFinder.findByG_N_F(groupId, name, folksonomy);
383     }
384 
385     public long[] getEntryIds(long groupId, String[] names)
386         throws PortalException, SystemException {
387 
388         return getEntryIds(groupId, names, TagsEntryConstants.FOLKSONOMY_TAG);
389     }
390 
391     public long[] getEntryIds(long groupId, String[] names, boolean folksonomy)
392         throws PortalException, SystemException {
393 
394         List<Long> entryIds = new ArrayList<Long>(names.length);
395 
396         for (String name : names) {
397             try {
398                 TagsEntry entry = getEntry(groupId, name, folksonomy);
399 
400                 entryIds.add(entry.getEntryId());
401             }
402             catch (NoSuchEntryException nsee) {
403             }
404         }
405 
406         return ArrayUtil.toArray(entryIds.toArray(new Long[entryIds.size()]));
407     }
408 
409     public String[] getEntryNames() throws SystemException {
410         return getEntryNames(TagsEntryConstants.FOLKSONOMY_TAG);
411     }
412 
413     public String[] getEntryNames(String className, long classPK)
414         throws SystemException {
415 
416         return getEntryNames(
417             className, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
418     }
419 
420     public String[] getEntryNames(long classNameId, long classPK)
421         throws SystemException {
422 
423         return getEntryNames(
424             classNameId, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
425     }
426 
427     public String[] getEntryNames(boolean folksonomy) throws SystemException {
428         return getEntryNames(getEntries(folksonomy));
429     }
430 
431     public String[] getEntryNames(
432             String className, long classPK, boolean folksonomy)
433         throws SystemException {
434 
435         return getEntryNames(getEntries(className, classPK, folksonomy));
436     }
437 
438     public String[] getEntryNames(
439             long classNameId, long classPK, boolean folksonomy)
440         throws SystemException {
441 
442         return getEntryNames(getEntries(classNameId, classPK, folksonomy));
443     }
444 
445     public List<TagsEntry> getGroupVocabularyEntries(
446             long groupId, String vocabularyName)
447         throws PortalException, SystemException {
448 
449         TagsVocabulary vocabulary =
450             tagsVocabularyLocalService.getGroupVocabulary(
451                 groupId, vocabularyName);
452 
453         return tagsEntryPersistence.findByVocabularyId(
454             vocabulary.getVocabularyId());
455     }
456 
457     public List<TagsEntry> getGroupVocabularyEntries(
458             long groupId, String parentEntryName, String vocabularyName)
459         throws PortalException, SystemException {
460 
461         TagsVocabulary vocabulary =
462             tagsVocabularyLocalService.getGroupVocabulary(
463                 groupId, vocabularyName);
464 
465         TagsEntry entry = getEntry(
466             groupId, parentEntryName, vocabulary.isFolksonomy());
467 
468         return tagsEntryPersistence.findByP_V(
469             entry.getEntryId(), vocabulary.getVocabularyId());
470     }
471 
472     public List<TagsEntry> getGroupVocabularyRootEntries(
473             long groupId, String vocabularyName)
474         throws PortalException, SystemException {
475 
476         TagsVocabulary vocabulary =
477             tagsVocabularyLocalService.getGroupVocabulary(
478                 groupId, vocabularyName);
479 
480         return tagsEntryPersistence.findByP_V(
481             TagsEntryConstants.DEFAULT_PARENT_ENTRY_ID,
482             vocabulary.getVocabularyId());
483     }
484 
485     public void mergeEntries(long fromEntryId, long toEntryId)
486         throws PortalException, SystemException {
487 
488         List<TagsAsset> assets = tagsEntryPersistence.getTagsAssets(
489             fromEntryId);
490 
491         tagsEntryPersistence.addTagsAssets(toEntryId, assets);
492 
493         List<TagsProperty> properties = tagsPropertyPersistence.findByEntryId(
494             fromEntryId);
495 
496         for (TagsProperty fromProperty : properties) {
497             TagsProperty toProperty = tagsPropertyPersistence.fetchByE_K(
498                 toEntryId, fromProperty.getKey());
499 
500             if (toProperty == null) {
501                 fromProperty.setEntryId(toEntryId);
502 
503                 tagsPropertyPersistence.update(fromProperty, false);
504             }
505         }
506 
507         deleteEntry(fromEntryId);
508     }
509 
510     public JSONArray search(
511             long groupId, String name, String[] properties, int start, int end)
512         throws SystemException {
513 
514         List<TagsEntry> list = tagsEntryFinder.findByG_N_F_P(
515             groupId, name, TagsEntryConstants.FOLKSONOMY_TAG, properties, start,
516             end);
517 
518         return Autocomplete.listToJson(list, "name", "name");
519     }
520 
521     public TagsEntry updateEntry(
522             long userId, long entryId, String parentEntryName, String name,
523             String vocabularyName, String[] properties)
524         throws PortalException, SystemException {
525 
526         // Entry
527 
528         if (Validator.isNull(vocabularyName)) {
529             vocabularyName = PropsValues.TAGS_VOCABULARY_DEFAULT;
530         }
531 
532         TagsEntry entry = tagsEntryPersistence.findByPrimaryKey(entryId);
533 
534         entry.setModifiedDate(new Date());
535 
536         TagsVocabulary vocabulary = null;
537 
538         try {
539             vocabulary = tagsVocabularyPersistence.findByG_N(
540                 entry.getGroupId(), vocabularyName);
541         }
542         catch (NoSuchVocabularyException nsve) {
543             if (vocabularyName.equals(PropsValues.TAGS_VOCABULARY_DEFAULT)) {
544                 ServiceContext vocabularyServiceContext = new ServiceContext();
545 
546                 vocabularyServiceContext.setAddCommunityPermissions(true);
547                 vocabularyServiceContext.setAddGuestPermissions(true);
548                 vocabularyServiceContext.setScopeGroupId(entry.getGroupId());
549 
550                 vocabulary = tagsVocabularyLocalService.addVocabulary(
551                     userId, vocabularyName, TagsEntryConstants.FOLKSONOMY_TAG,
552                     vocabularyServiceContext);
553             }
554             else {
555                 throw nsve;
556             }
557         }
558 
559         entry.setVocabularyId(vocabulary.getVocabularyId());
560 
561         boolean folksonomy = vocabulary.isFolksonomy();
562 
563         name = name.trim();
564 
565         if (folksonomy) {
566             name = name.toLowerCase();
567 
568             if (!entry.getName().equals(name) &&
569                 hasEntry(entry.getGroupId(), name, folksonomy)) {
570 
571                 throw new DuplicateEntryException(
572                     "A tag entry with the name " + name + " already exists");
573             }
574         }
575 
576         if (!entry.getName().equals(name)) {
577             try {
578                 TagsEntry existingEntry = getEntry(
579                     entry.getGroupId(), name, folksonomy);
580 
581                 if (existingEntry.getEntryId() != entryId) {
582                     throw new DuplicateEntryException(
583                         "A tag entry with the name " + name +
584                             " already exists");
585                 }
586             }
587             catch (NoSuchEntryException nsee) {
588             }
589         }
590 
591         validate(name);
592 
593         entry.setName(name);
594 
595         if (Validator.isNotNull(parentEntryName)) {
596             TagsEntry parentEntry = getEntry(
597                 entry.getGroupId(), parentEntryName, folksonomy);
598 
599             entry.setParentEntryId(parentEntry.getEntryId());
600         }
601         else {
602             entry.setParentEntryId(TagsEntryConstants.DEFAULT_PARENT_ENTRY_ID);
603         }
604 
605         tagsEntryPersistence.update(entry, false);
606 
607         // Properties
608 
609         Set<Long> newProperties = new HashSet<Long>();
610 
611         List<TagsProperty> oldProperties =
612             tagsPropertyPersistence.findByEntryId(entryId);
613 
614         for (int i = 0; i < properties.length; i++) {
615             String[] property = StringUtil.split(
616                 properties[i], StringPool.COLON);
617 
618             long propertyId = 0;
619 
620             if (property.length > 0) {
621                 propertyId = GetterUtil.getLong(property[0]);
622             }
623 
624             String key = StringPool.BLANK;
625 
626             if (property.length > 1) {
627                 key = GetterUtil.getString(property[1]);
628             }
629 
630             String value = StringPool.BLANK;
631 
632             if (property.length > 2) {
633                 value = GetterUtil.getString(property[2]);
634             }
635 
636             if (propertyId == 0) {
637                 if (Validator.isNotNull(key)) {
638                     tagsPropertyLocalService.addProperty(
639                         userId, entryId, key, value);
640                 }
641             }
642             else {
643                 if (Validator.isNull(key)) {
644                     tagsPropertyLocalService.deleteProperty(propertyId);
645                 }
646                 else {
647                     tagsPropertyLocalService.updateProperty(
648                         propertyId, key, value);
649 
650                     newProperties.add(propertyId);
651                 }
652             }
653         }
654 
655         for (TagsProperty property : oldProperties) {
656             if (!newProperties.contains(property.getPropertyId())) {
657                 tagsPropertyLocalService.deleteProperty(property);
658             }
659         }
660 
661         return entry;
662     }
663 
664     protected String[] getEntryNames(List <TagsEntry>entries) {
665         return StringUtil.split(ListUtil.toString(entries, "name"));
666     }
667 
668     protected void validate(String name) throws PortalException {
669         if (!TagsUtil.isValidWord(name)) {
670             throw new TagsEntryException(TagsEntryException.INVALID_CHARACTER);
671         }
672     }
673 
674 }