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         entry.setName(name);
140 
141         if (Validator.isNotNull(parentEntryName)) {
142             TagsEntry parentEntry = getEntry(
143                 groupId, parentEntryName, folksonomy);
144 
145             entry.setParentEntryId(parentEntry.getEntryId());
146         }
147         else {
148             entry.setParentEntryId(TagsEntryConstants.DEFAULT_PARENT_ENTRY_ID);
149         }
150 
151         tagsEntryPersistence.update(entry, false);
152 
153         // Resources
154 
155         if (serviceContext.getAddCommunityPermissions() ||
156             serviceContext.getAddGuestPermissions()) {
157 
158             addEntryResources(
159                 entry, serviceContext.getAddCommunityPermissions(),
160                 serviceContext.getAddGuestPermissions());
161         }
162         else {
163             addEntryResources(
164                 entry, serviceContext.getCommunityPermissions(),
165                 serviceContext.getGuestPermissions());
166         }
167 
168         // Properties
169 
170         for (int i = 0; i < properties.length; i++) {
171             String[] property = StringUtil.split(
172                 properties[i], StringPool.COLON);
173 
174             String key = StringPool.BLANK;
175 
176             if (property.length > 1) {
177                 key = GetterUtil.getString(property[1]);
178             }
179 
180             String value = StringPool.BLANK;
181 
182             if (property.length > 2) {
183                 value = GetterUtil.getString(property[2]);
184             }
185 
186             if (Validator.isNotNull(key)) {
187                 tagsPropertyLocalService.addProperty(
188                     userId, entryId, key, value);
189             }
190         }
191 
192         return entry;
193     }
194 
195     public void addEntryResources(
196             TagsEntry entry, boolean addCommunityPermissions,
197             boolean addGuestPermissions)
198         throws PortalException, SystemException {
199 
200         resourceLocalService.addResources(
201             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
202             TagsEntry.class.getName(), entry.getEntryId(), false,
203             addCommunityPermissions, addGuestPermissions);
204     }
205 
206     public void addEntryResources(
207             TagsEntry entry, String[] communityPermissions,
208             String[] guestPermissions)
209         throws PortalException, SystemException {
210 
211         resourceLocalService.addModelResources(
212             entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
213             TagsEntry.class.getName(), entry.getEntryId(), communityPermissions,
214             guestPermissions);
215     }
216 
217     public void checkEntries(long userId, long groupId, String[] names)
218         throws PortalException, SystemException {
219 
220         for (String name : names) {
221             try {
222                 getEntry(groupId, name, TagsEntryConstants.FOLKSONOMY_TAG);
223             }
224             catch (NoSuchEntryException nsee) {
225                 ServiceContext serviceContext = new ServiceContext();
226 
227                 serviceContext.setAddCommunityPermissions(true);
228                 serviceContext.setAddGuestPermissions(true);
229                 serviceContext.setScopeGroupId(groupId);
230 
231                 addEntry(
232                     userId, null, name, null,
233                     PropsValues.TAGS_PROPERTIES_DEFAULT, serviceContext);
234             }
235         }
236     }
237 
238     public void deleteEntry(long entryId)
239         throws PortalException, SystemException {
240 
241         TagsEntry entry = tagsEntryPersistence.findByPrimaryKey(entryId);
242 
243         deleteEntry(entry);
244     }
245 
246     public void deleteEntry(TagsEntry entry)
247         throws PortalException, SystemException {
248 
249         // Properties
250 
251         tagsPropertyLocalService.deleteProperties(entry.getEntryId());
252 
253         // Resources
254 
255         resourceLocalService.deleteResource(
256             entry.getCompanyId(), TagsEntry.class.getName(),
257             ResourceConstants.SCOPE_INDIVIDUAL, entry.getEntryId());
258 
259         // Entry
260 
261         tagsEntryPersistence.remove(entry);
262     }
263 
264     public void deleteVocabularyEntries(long vocabularyId)
265         throws PortalException, SystemException {
266 
267         List<TagsEntry> entries = tagsEntryPersistence.findByVocabularyId(
268             vocabularyId);
269 
270         for (TagsEntry entry : entries) {
271             deleteEntry(entry);
272         }
273     }
274 
275     public boolean hasEntry(long groupId, String name, boolean folksonomy)
276         throws PortalException, SystemException {
277 
278         try {
279             getEntry(groupId, name, folksonomy);
280 
281             return true;
282         }
283         catch (NoSuchEntryException nsee) {
284             return false;
285         }
286     }
287 
288     public List<TagsEntry> getAssetEntries(long assetId, boolean folksonomy)
289         throws SystemException {
290 
291         return tagsEntryFinder.findByA_F(assetId, folksonomy);
292     }
293 
294     public List<TagsEntry> getEntries() throws SystemException {
295         return getEntries(TagsEntryConstants.FOLKSONOMY_TAG);
296     }
297 
298     public List<TagsEntry> getEntries(boolean folksonomy)
299         throws SystemException {
300 
301         return tagsEntryFinder.findByFolksonomy(folksonomy);
302     }
303 
304     public List<TagsEntry> getEntries(String className, long classPK)
305         throws SystemException {
306 
307         return getEntries(
308             className, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
309     }
310 
311     public List<TagsEntry> getEntries(long classNameId, long classPK)
312         throws SystemException {
313 
314         return getEntries(
315             classNameId, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
316     }
317 
318     public List<TagsEntry> getEntries(
319             String className, long classPK, boolean folksonomy)
320         throws SystemException {
321 
322         long classNameId = PortalUtil.getClassNameId(className);
323 
324         return getEntries(classNameId, classPK, folksonomy);
325     }
326 
327     public List<TagsEntry> getEntries(
328             long classNameId, long classPK, boolean folksonomy)
329         throws SystemException {
330 
331         TagsAsset asset = tagsAssetPersistence.fetchByC_C(classNameId, classPK);
332 
333         if (asset == null) {
334             return new ArrayList<TagsEntry>();
335         }
336         else {
337             return getAssetEntries(asset.getAssetId(), folksonomy);
338         }
339     }
340 
341     public List<TagsEntry> getEntries(
342             long groupId, long classNameId, String name)
343         throws SystemException {
344 
345         return tagsEntryFinder.findByG_C_N_F(
346             groupId, classNameId, name, TagsEntryConstants.FOLKSONOMY_TAG);
347     }
348 
349     public List<TagsEntry> getEntries(
350             long groupId, long classNameId, String name, int start, int end)
351         throws SystemException {
352 
353         return tagsEntryFinder.findByG_C_N_F(
354             groupId, classNameId, name,
355             TagsEntryConstants.FOLKSONOMY_TAG, start, end);
356     }
357 
358     public int getEntriesSize(long groupId, long classNameId, String name)
359         throws SystemException {
360 
361         return tagsEntryFinder.countByG_C_N_F(
362             groupId, classNameId, name, TagsEntryConstants.FOLKSONOMY_TAG);
363     }
364 
365     public TagsEntry getEntry(long entryId)
366         throws PortalException, SystemException {
367 
368         return tagsEntryPersistence.findByPrimaryKey(entryId);
369     }
370 
371     public TagsEntry getEntry(long groupId, String name)
372         throws PortalException, SystemException {
373 
374         return getEntry(groupId, name, TagsEntryConstants.FOLKSONOMY_TAG);
375     }
376 
377     public TagsEntry getEntry(long groupId, String name, boolean folksonomy)
378         throws PortalException, SystemException {
379 
380         return tagsEntryFinder.findByG_N_F(groupId, name, folksonomy);
381     }
382 
383     public long[] getEntryIds(long groupId, String[] names)
384         throws PortalException, SystemException {
385 
386         return getEntryIds(groupId, names, TagsEntryConstants.FOLKSONOMY_TAG);
387     }
388 
389     public long[] getEntryIds(long groupId, String[] names, boolean folksonomy)
390         throws PortalException, SystemException {
391 
392         List<Long> entryIds = new ArrayList<Long>(names.length);
393 
394         for (String name : names) {
395             try {
396                 TagsEntry entry = getEntry(groupId, name, folksonomy);
397 
398                 entryIds.add(entry.getEntryId());
399             }
400             catch (NoSuchEntryException nsee) {
401             }
402         }
403 
404         return ArrayUtil.toArray(entryIds.toArray(new Long[entryIds.size()]));
405     }
406 
407     public String[] getEntryNames() throws SystemException {
408         return getEntryNames(TagsEntryConstants.FOLKSONOMY_TAG);
409     }
410 
411     public String[] getEntryNames(String className, long classPK)
412         throws SystemException {
413 
414         return getEntryNames(
415             className, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
416     }
417 
418     public String[] getEntryNames(long classNameId, long classPK)
419         throws SystemException {
420 
421         return getEntryNames(
422             classNameId, classPK, TagsEntryConstants.FOLKSONOMY_TAG);
423     }
424 
425     public String[] getEntryNames(boolean folksonomy) throws SystemException {
426         return getEntryNames(getEntries(folksonomy));
427     }
428 
429     public String[] getEntryNames(
430             String className, long classPK, boolean folksonomy)
431         throws SystemException {
432 
433         return getEntryNames(getEntries(className, classPK, folksonomy));
434     }
435 
436     public String[] getEntryNames(
437             long classNameId, long classPK, boolean folksonomy)
438         throws SystemException {
439 
440         return getEntryNames(getEntries(classNameId, classPK, folksonomy));
441     }
442 
443     public List<TagsEntry> getGroupVocabularyEntries(
444             long groupId, String vocabularyName)
445         throws PortalException, SystemException {
446 
447         TagsVocabulary vocabulary =
448             tagsVocabularyLocalService.getGroupVocabulary(
449                 groupId, vocabularyName);
450 
451         return tagsEntryPersistence.findByVocabularyId(
452             vocabulary.getVocabularyId());
453     }
454 
455     public List<TagsEntry> getGroupVocabularyEntries(
456             long groupId, String parentEntryName, String vocabularyName)
457         throws PortalException, SystemException {
458 
459         TagsVocabulary vocabulary =
460             tagsVocabularyLocalService.getGroupVocabulary(
461                 groupId, vocabularyName);
462 
463         TagsEntry entry = getEntry(
464             groupId, parentEntryName, vocabulary.isFolksonomy());
465 
466         return tagsEntryPersistence.findByP_V(
467             entry.getEntryId(), vocabulary.getVocabularyId());
468     }
469 
470     public List<TagsEntry> getGroupVocabularyRootEntries(
471             long groupId, String vocabularyName)
472         throws PortalException, SystemException {
473 
474         TagsVocabulary vocabulary =
475             tagsVocabularyLocalService.getGroupVocabulary(
476                 groupId, vocabularyName);
477 
478         return tagsEntryPersistence.findByP_V(
479             TagsEntryConstants.DEFAULT_PARENT_ENTRY_ID,
480             vocabulary.getVocabularyId());
481     }
482 
483     public void mergeEntries(long fromEntryId, long toEntryId)
484         throws PortalException, SystemException {
485 
486         List<TagsAsset> assets = tagsEntryPersistence.getTagsAssets(
487             fromEntryId);
488 
489         tagsEntryPersistence.addTagsAssets(toEntryId, assets);
490 
491         List<TagsProperty> properties = tagsPropertyPersistence.findByEntryId(
492             fromEntryId);
493 
494         for (TagsProperty fromProperty : properties) {
495             TagsProperty toProperty = tagsPropertyPersistence.fetchByE_K(
496                 toEntryId, fromProperty.getKey());
497 
498             if (toProperty == null) {
499                 fromProperty.setEntryId(toEntryId);
500 
501                 tagsPropertyPersistence.update(fromProperty, false);
502             }
503         }
504 
505         deleteEntry(fromEntryId);
506     }
507 
508     public JSONArray search(
509             long groupId, String name, String[] properties, int start, int end)
510         throws SystemException {
511 
512         List<TagsEntry> list = tagsEntryFinder.findByG_N_F_P(
513             groupId, name, TagsEntryConstants.FOLKSONOMY_TAG, properties, start,
514             end);
515 
516         return Autocomplete.listToJson(list, "name", "name");
517     }
518 
519     public TagsEntry updateEntry(
520             long userId, long entryId, String parentEntryName, String name,
521             String vocabularyName, String[] properties)
522         throws PortalException, SystemException {
523 
524         // Entry
525 
526         if (Validator.isNull(vocabularyName)) {
527             vocabularyName = PropsValues.TAGS_VOCABULARY_DEFAULT;
528         }
529 
530         TagsEntry entry = tagsEntryPersistence.findByPrimaryKey(entryId);
531 
532         entry.setModifiedDate(new Date());
533 
534         TagsVocabulary vocabulary = null;
535 
536         try {
537             vocabulary = tagsVocabularyPersistence.findByG_N(
538                 entry.getGroupId(), vocabularyName);
539         }
540         catch (NoSuchVocabularyException nsve) {
541             if (vocabularyName.equals(PropsValues.TAGS_VOCABULARY_DEFAULT)) {
542                 ServiceContext vocabularyServiceContext = new ServiceContext();
543 
544                 vocabularyServiceContext.setAddCommunityPermissions(true);
545                 vocabularyServiceContext.setAddGuestPermissions(true);
546                 vocabularyServiceContext.setScopeGroupId(entry.getGroupId());
547 
548                 vocabulary = tagsVocabularyLocalService.addVocabulary(
549                     userId, vocabularyName, TagsEntryConstants.FOLKSONOMY_TAG,
550                     vocabularyServiceContext);
551             }
552             else {
553                 throw nsve;
554             }
555         }
556 
557         entry.setVocabularyId(vocabulary.getVocabularyId());
558 
559         boolean folksonomy = vocabulary.isFolksonomy();
560 
561         name = name.trim();
562 
563         if (folksonomy) {
564             name = name.toLowerCase();
565 
566             if (!entry.getName().equals(name) &&
567                 hasEntry(entry.getGroupId(), name, folksonomy)) {
568 
569                 throw new DuplicateEntryException(
570                     "A tag entry with the name " + name + " already exists");
571             }
572         }
573 
574         if (!entry.getName().equals(name)) {
575             try {
576                 TagsEntry existingEntry = getEntry(
577                     entry.getGroupId(), name, folksonomy);
578 
579                 if (existingEntry.getEntryId() != entryId) {
580                     throw new DuplicateEntryException(
581                         "A tag entry with the name " + name +
582                             " already exists");
583                 }
584             }
585             catch (NoSuchEntryException nsee) {
586             }
587         }
588 
589         validate(name);
590 
591         entry.setName(name);
592 
593         if (Validator.isNotNull(parentEntryName)) {
594             TagsEntry parentEntry = getEntry(
595                 entry.getGroupId(), parentEntryName, folksonomy);
596 
597             entry.setParentEntryId(parentEntry.getEntryId());
598         }
599         else {
600             entry.setParentEntryId(TagsEntryConstants.DEFAULT_PARENT_ENTRY_ID);
601         }
602 
603         tagsEntryPersistence.update(entry, false);
604 
605         // Properties
606 
607         Set<Long> newProperties = new HashSet<Long>();
608 
609         List<TagsProperty> oldProperties =
610             tagsPropertyPersistence.findByEntryId(entryId);
611 
612         for (int i = 0; i < properties.length; i++) {
613             String[] property = StringUtil.split(
614                 properties[i], StringPool.COLON);
615 
616             long propertyId = 0;
617 
618             if (property.length > 0) {
619                 propertyId = GetterUtil.getLong(property[0]);
620             }
621 
622             String key = StringPool.BLANK;
623 
624             if (property.length > 1) {
625                 key = GetterUtil.getString(property[1]);
626             }
627 
628             String value = StringPool.BLANK;
629 
630             if (property.length > 2) {
631                 value = GetterUtil.getString(property[2]);
632             }
633 
634             if (propertyId == 0) {
635                 if (Validator.isNotNull(key)) {
636                     tagsPropertyLocalService.addProperty(
637                         userId, entryId, key, value);
638                 }
639             }
640             else {
641                 if (Validator.isNull(key)) {
642                     tagsPropertyLocalService.deleteProperty(propertyId);
643                 }
644                 else {
645                     tagsPropertyLocalService.updateProperty(
646                         propertyId, key, value);
647 
648                     newProperties.add(propertyId);
649                 }
650             }
651         }
652 
653         for (TagsProperty property : oldProperties) {
654             if (!newProperties.contains(property.getPropertyId())) {
655                 tagsPropertyLocalService.deleteProperty(property);
656             }
657         }
658 
659         return entry;
660     }
661 
662     protected String[] getEntryNames(List <TagsEntry>entries) {
663         return StringUtil.split(ListUtil.toString(entries, "name"));
664     }
665 
666     protected void validate(String name) throws PortalException {
667         if (!TagsUtil.isValidWord(name)) {
668             throw new TagsEntryException(TagsEntryException.INVALID_CHARACTER);
669         }
670     }
671 
672 }