001    /**
002     * Copyright (c) 2000-2013 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.Lifecycle;
018    import com.liferay.portal.kernel.cache.ThreadLocalCache;
019    import com.liferay.portal.kernel.cache.ThreadLocalCacheManager;
020    import com.liferay.portal.kernel.dao.orm.QueryUtil;
021    import com.liferay.portal.kernel.exception.PortalException;
022    import com.liferay.portal.kernel.exception.SystemException;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.util.ArrayUtil;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.security.permission.ActionKeys;
028    import com.liferay.portal.security.permission.PermissionChecker;
029    import com.liferay.portal.util.PropsValues;
030    import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
031    import com.liferay.portlet.asset.model.AssetCategory;
032    import com.liferay.portlet.asset.model.AssetEntry;
033    import com.liferay.portlet.asset.model.AssetRendererFactory;
034    import com.liferay.portlet.asset.service.base.AssetEntryServiceBaseImpl;
035    import com.liferay.portlet.asset.service.permission.AssetCategoryPermission;
036    import com.liferay.portlet.asset.service.permission.AssetEntryPermission;
037    import com.liferay.portlet.asset.service.permission.AssetTagPermission;
038    import com.liferay.portlet.asset.service.persistence.AssetEntryQuery;
039    
040    import java.util.ArrayList;
041    import java.util.Date;
042    import java.util.List;
043    
044    /**
045     * Provides the remote service for accessing and updating asset entries. Its
046     * methods include permission checks.
047     *
048     * @author Brian Wing Shun Chan
049     * @author Jorge Ferrer
050     * @author Bruno Farache
051     * @author Raymond Aug??
052     */
053    public class AssetEntryServiceImpl extends AssetEntryServiceBaseImpl {
054    
055            @Override
056            public List<AssetEntry> getCompanyEntries(
057                            long companyId, int start, int end)
058                    throws SystemException {
059    
060                    List<AssetEntry> entries = new ArrayList<AssetEntry>();
061    
062                    List<AssetEntry> companyEntries =
063                            assetEntryLocalService.getCompanyEntries(companyId, start, end);
064    
065                    for (AssetEntry entry : companyEntries) {
066                            try {
067                                    if (AssetEntryPermission.contains(
068                                                    getPermissionChecker(), entry, ActionKeys.VIEW)) {
069    
070                                            entries.add(entry);
071                                    }
072                            }
073                            catch (PortalException pe) {
074                                    if (_log.isWarnEnabled()) {
075                                            _log.warn(pe, pe);
076                                    }
077                            }
078                    }
079    
080                    return entries;
081            }
082    
083            @Override
084            public int getCompanyEntriesCount(long companyId) throws SystemException {
085                    return assetEntryLocalService.getCompanyEntriesCount(companyId);
086            }
087    
088            @Override
089            public List<AssetEntry> getEntries(AssetEntryQuery entryQuery)
090                    throws PortalException, SystemException {
091    
092                    AssetEntryQuery filteredEntryQuery = buildFilteredEntryQuery(
093                            entryQuery);
094    
095                    if (hasEntryQueryResults(entryQuery, filteredEntryQuery)) {
096                            return new ArrayList<AssetEntry>();
097                    }
098    
099                    Object[] results = filterEntryQuery(filteredEntryQuery, false);
100    
101                    return (List<AssetEntry>)results[0];
102            }
103    
104            @Override
105            public int getEntriesCount(AssetEntryQuery entryQuery)
106                    throws PortalException, SystemException {
107    
108                    AssetEntryQuery filteredEntryQuery = buildFilteredEntryQuery(
109                            entryQuery);
110    
111                    if (hasEntryQueryResults(entryQuery, filteredEntryQuery)) {
112                            return 0;
113                    }
114    
115                    Object[] results = filterEntryQuery(filteredEntryQuery, true);
116    
117                    return (Integer)results[1];
118            }
119    
120            @Override
121            public AssetEntry getEntry(long entryId)
122                    throws PortalException, SystemException {
123    
124                    AssetEntryPermission.check(
125                            getPermissionChecker(), entryId, ActionKeys.VIEW);
126    
127                    return assetEntryLocalService.getEntry(entryId);
128            }
129    
130            @Override
131            public AssetEntry incrementViewCounter(String className, long classPK)
132                    throws PortalException, SystemException {
133    
134                    AssetEntryPermission.check(
135                            getPermissionChecker(), className, classPK, ActionKeys.VIEW);
136    
137                    return assetEntryLocalService.incrementViewCounter(
138                            getGuestOrUserId(), className, classPK);
139            }
140    
141            @Override
142            public AssetEntry updateEntry(
143                            long groupId, Date createDate, Date modifiedDate, String className,
144                            long classPK, String classUuid, long classTypeId,
145                            long[] categoryIds, String[] tagNames, boolean visible,
146                            Date startDate, Date endDate, Date expirationDate, String mimeType,
147                            String title, String description, String summary, String url,
148                            String layoutUuid, int height, int width, Integer priority,
149                            boolean sync)
150                    throws PortalException, SystemException {
151    
152                    AssetEntryPermission.check(
153                            getPermissionChecker(), className, classPK, ActionKeys.UPDATE);
154    
155                    return assetEntryLocalService.updateEntry(
156                            getUserId(), groupId, createDate, modifiedDate, className, classPK,
157                            classUuid, classTypeId, categoryIds, tagNames, visible, startDate,
158                            endDate, expirationDate, mimeType, title, description, summary, url,
159                            layoutUuid, height, width, priority, sync);
160            }
161    
162            /**
163             * @deprecated As of 6.2.0, replaced by {@link #updateEntry(long, String,
164             *             long, String, long, long[], String[], boolean, Date, Date,
165             *             Date, String, String, String, String, String, String, int,
166             *             int, Integer, boolean)}
167             */
168            @Override
169            public AssetEntry updateEntry(
170                            long groupId, String className, long classPK, String classUuid,
171                            long classTypeId, long[] categoryIds, String[] tagNames,
172                            boolean visible, Date startDate, Date endDate, Date publishDate,
173                            Date expirationDate, String mimeType, String title,
174                            String description, String summary, String url, String layoutUuid,
175                            int height, int width, Integer priority, boolean sync)
176                    throws PortalException, SystemException {
177    
178                    AssetEntryPermission.check(
179                            getPermissionChecker(), className, classPK, ActionKeys.UPDATE);
180    
181                    return assetEntryLocalService.updateEntry(
182                            getUserId(), groupId, className, classPK, classUuid, classTypeId,
183                            categoryIds, tagNames, visible, startDate, endDate, expirationDate,
184                            mimeType, title, description, summary, url, layoutUuid, height,
185                            width, priority, sync);
186            }
187    
188            /**
189             * @deprecated As of 6.2.0, replaced by {@link #updateEntry(long, Date,
190             *             Date, String, long, String, long, long[], String[], boolean,
191             *             Date, Date, Date, String, String, String, String, String,
192             *             String, int, int, Integer, boolean)}
193             */
194            @Override
195            public AssetEntry updateEntry(
196                            long groupId, String className, long classPK, String classUuid,
197                            long classTypeId, long[] categoryIds, String[] tagNames,
198                            boolean visible, Date startDate, Date endDate, Date expirationDate,
199                            String mimeType, String title, String description, String summary,
200                            String url, String layoutUuid, int height, int width,
201                            Integer priority, boolean sync)
202                    throws PortalException, SystemException {
203    
204                    return assetEntryLocalService.updateEntry(
205                            getUserId(), groupId, null, null, className, classPK, classUuid,
206                            classTypeId, categoryIds, tagNames, visible, startDate, endDate,
207                            expirationDate, mimeType, title, description, summary, url,
208                            layoutUuid, height, width, priority, sync);
209            }
210    
211            protected AssetEntryQuery buildFilteredEntryQuery(
212                            AssetEntryQuery entryQuery)
213                    throws PortalException, SystemException {
214    
215                    // Return an entry query with only the category ids and tag ids that the
216                    // user has access to
217    
218                    AssetEntryQuery filteredEntryQuery = new AssetEntryQuery(entryQuery);
219    
220                    filteredEntryQuery.setAllCategoryIds(
221                            filterCategoryIds(entryQuery.getAllCategoryIds()));
222                    filteredEntryQuery.setAllTagIdsArray(
223                            filterTagIdsArray(entryQuery.getAllTagIdsArray()));
224                    filteredEntryQuery.setAnyCategoryIds(
225                            filterCategoryIds(entryQuery.getAnyCategoryIds()));
226                    filteredEntryQuery.setAnyTagIds(
227                            filterTagIds(entryQuery.getAnyTagIds()));
228    
229                    return filteredEntryQuery;
230            }
231    
232            protected long[] filterCategoryIds(long[] categoryIds)
233                    throws PortalException, SystemException {
234    
235                    List<Long> viewableCategoryIds = new ArrayList<Long>();
236    
237                    for (long categoryId : categoryIds) {
238                            AssetCategory category = assetCategoryPersistence.fetchByPrimaryKey(
239                                    categoryId);
240    
241                            if ((category != null) &&
242                                    AssetCategoryPermission.contains(
243                                            getPermissionChecker(), categoryId, ActionKeys.VIEW)) {
244    
245                                    viewableCategoryIds.add(categoryId);
246                            }
247                    }
248    
249                    return ArrayUtil.toArray(
250                            viewableCategoryIds.toArray(new Long[viewableCategoryIds.size()]));
251            }
252    
253            protected Object[] filterEntryQuery(
254                            AssetEntryQuery entryQuery, boolean returnEntriesCountOnly)
255                    throws PortalException, SystemException {
256    
257                    ThreadLocalCache<Object[]> threadLocalCache =
258                            ThreadLocalCacheManager.getThreadLocalCache(
259                                    Lifecycle.REQUEST, AssetEntryServiceImpl.class.getName());
260    
261                    String key = entryQuery.toString();
262    
263                    key = key.concat(StringPool.POUND).concat(
264                            Boolean.toString(returnEntriesCountOnly));
265    
266                    Object[] results = threadLocalCache.get(key);
267    
268                    if (results != null) {
269                            return results;
270                    }
271    
272                    if (returnEntriesCountOnly && !entryQuery.isEnablePermissions()) {
273                            int entriesCount = assetEntryLocalService.getEntriesCount(
274                                    entryQuery);
275    
276                            results = new Object[] {null, entriesCount};
277    
278                            threadLocalCache.put(key, results);
279    
280                            return results;
281                    }
282    
283                    int end = entryQuery.getEnd();
284                    int start = entryQuery.getStart();
285    
286                    if (entryQuery.isEnablePermissions()) {
287                            entryQuery.setEnd(end + PropsValues.ASSET_FILTER_SEARCH_LIMIT);
288                            entryQuery.setStart(0);
289                    }
290    
291                    List<AssetEntry> entries = assetEntryLocalService.getEntries(
292                            entryQuery);
293    
294                    List<AssetEntry> filteredEntries = null;
295                    int filteredEntriesCount = 0;
296    
297                    if (entryQuery.isEnablePermissions()) {
298                            PermissionChecker permissionChecker = getPermissionChecker();
299    
300                            filteredEntries = new ArrayList<AssetEntry>();
301    
302                            for (AssetEntry entry : entries) {
303                                    String className = entry.getClassName();
304                                    long classPK = entry.getClassPK();
305    
306                                    AssetRendererFactory assetRendererFactory =
307                                            AssetRendererFactoryRegistryUtil.
308                                                    getAssetRendererFactoryByClassName(className);
309    
310                                    try {
311                                            if (assetRendererFactory.hasPermission(
312                                                            permissionChecker, classPK, ActionKeys.VIEW)) {
313    
314                                                    filteredEntries.add(entry);
315                                            }
316                                    }
317                                    catch (Exception e) {
318                                    }
319    
320                                    if ((end != QueryUtil.ALL_POS) &&
321                                            (filteredEntries.size() > end)) {
322    
323                                            break;
324                                    }
325                            }
326    
327                            filteredEntriesCount = filteredEntries.size();
328    
329                            if ((end != QueryUtil.ALL_POS) && (start != QueryUtil.ALL_POS)) {
330                                    if (end > filteredEntriesCount) {
331                                            end = filteredEntriesCount;
332                                    }
333    
334                                    if (start > filteredEntriesCount) {
335                                            start = filteredEntriesCount;
336                                    }
337    
338                                    filteredEntries = filteredEntries.subList(start, end);
339                            }
340    
341                            entryQuery.setEnd(end);
342                            entryQuery.setStart(start);
343                    }
344                    else {
345                            filteredEntries = entries;
346                            filteredEntriesCount = filteredEntries.size();
347                    }
348    
349                    results = new Object[] {filteredEntries, filteredEntriesCount};
350    
351                    threadLocalCache.put(key, results);
352    
353                    return results;
354            }
355    
356            protected long[] filterTagIds(long[] tagIds)
357                    throws PortalException, SystemException {
358    
359                    List<Long> viewableTagIds = new ArrayList<Long>();
360    
361                    for (long tagId : tagIds) {
362                            if (AssetTagPermission.contains(
363                                            getPermissionChecker(), tagId, ActionKeys.VIEW)) {
364    
365                                    viewableTagIds.add(tagId);
366                            }
367                    }
368    
369                    return ArrayUtil.toArray(
370                            viewableTagIds.toArray(new Long[viewableTagIds.size()]));
371            }
372    
373            protected long[][] filterTagIdsArray(long[][] tagIdsArray)
374                    throws PortalException, SystemException {
375    
376                    List<long[]> viewableTagIdsArray = new ArrayList<long[]>();
377    
378                    for (int i = 0; i< tagIdsArray.length; i++) {
379                            long[] tagIds = tagIdsArray[i];
380    
381                            List<Long> viewableTagIds = new ArrayList<Long>();
382    
383                            for (long tagId : tagIds) {
384                                    if (AssetTagPermission.contains(
385                                                    getPermissionChecker(), tagId, ActionKeys.VIEW)) {
386    
387                                            viewableTagIds.add(tagId);
388                                    }
389                            }
390    
391                            viewableTagIdsArray.add(
392                                    ArrayUtil.toArray(
393                                            viewableTagIds.toArray(new Long[viewableTagIds.size()])));
394                    }
395    
396                    return viewableTagIdsArray.toArray(
397                            new long[viewableTagIdsArray.size()][]);
398            }
399    
400            protected boolean hasEntryQueryResults(
401                    AssetEntryQuery originalEntryQuery,
402                    AssetEntryQuery filteredEntryQuery) {
403    
404                    if (originalEntryQuery.getAllCategoryIds().length >
405                                    filteredEntryQuery.getAllCategoryIds().length) {
406    
407                            // No results will be available if the user must have access to all
408                            // category ids, but the user has access to fewer category ids in
409                            // the filtered entry query than what was specified in the original
410                            // entry query
411    
412                            return true;
413                    }
414    
415                    if (originalEntryQuery.getAllTagIds().length >
416                                    filteredEntryQuery.getAllTagIds().length) {
417    
418                            // No results will be available if the user must have access to all
419                            // tag ids, but the user has access to fewer tag ids in the filtered
420                            // entry query than what was specified in the original entry query
421    
422                            return true;
423                    }
424    
425                    if ((originalEntryQuery.getAnyCategoryIds().length > 0) &&
426                            (filteredEntryQuery.getAnyCategoryIds().length == 0)) {
427    
428                            // No results will be available if the original entry query
429                            // specified at least one category id, but the filtered entry query
430                            // shows that the user does not have access to any category ids
431    
432                            return true;
433                    }
434    
435                    if ((originalEntryQuery.getAnyTagIds().length > 0) &&
436                            (filteredEntryQuery.getAnyTagIds().length == 0)) {
437    
438                            // No results will be available if the original entry query
439                            // specified at least one tag id, but the filtered entry query shows
440                            // that the user does not have access to any tag ids
441    
442                            return true;
443                    }
444    
445                    return false;
446            }
447    
448            private static Log _log = LogFactoryUtil.getLog(
449                    AssetEntryServiceImpl.class);
450    
451    }