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.asset.kernel.exception.NoSuchLinkException;
018    import com.liferay.asset.kernel.model.AssetEntry;
019    import com.liferay.asset.kernel.model.AssetLink;
020    import com.liferay.asset.kernel.model.AssetLinkConstants;
021    import com.liferay.asset.kernel.model.adapter.StagedAssetLink;
022    import com.liferay.exportimport.kernel.lar.PortletDataContext;
023    import com.liferay.exportimport.kernel.lar.StagedModelDataHandlerUtil;
024    import com.liferay.exportimport.kernel.lar.StagedModelType;
025    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
026    import com.liferay.portal.kernel.dao.orm.Criterion;
027    import com.liferay.portal.kernel.dao.orm.Disjunction;
028    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
029    import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
030    import com.liferay.portal.kernel.dao.orm.ExportActionableDynamicQuery;
031    import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
032    import com.liferay.portal.kernel.dao.orm.Property;
033    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
034    import com.liferay.portal.kernel.dao.orm.QueryPos;
035    import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
036    import com.liferay.portal.kernel.dao.orm.SQLQuery;
037    import com.liferay.portal.kernel.dao.orm.Session;
038    import com.liferay.portal.kernel.exception.PortalException;
039    import com.liferay.portal.kernel.log.Log;
040    import com.liferay.portal.kernel.log.LogFactoryUtil;
041    import com.liferay.portal.kernel.model.User;
042    import com.liferay.portal.kernel.model.adapter.ModelAdapterUtil;
043    import com.liferay.portal.kernel.util.ArrayUtil;
044    import com.liferay.portlet.asset.service.base.AssetLinkLocalServiceBaseImpl;
045    import com.liferay.util.dao.orm.CustomSQLUtil;
046    
047    import java.util.ArrayList;
048    import java.util.Collections;
049    import java.util.Date;
050    import java.util.List;
051    
052    /**
053     * This class implements the methods needed to handle AssetLinks, the entity
054     * that relates different assets in the portal.
055     *
056     * The basic information stored for every link includes both assets entry IDs,
057     * the userId, the link type and the link's weight.
058     *
059     * @author Brian Wing Shun Chan
060     * @author Juan Fern??ndez
061     */
062    public class AssetLinkLocalServiceImpl extends AssetLinkLocalServiceBaseImpl {
063    
064            /**
065             * Adds a new asset link.
066             *
067             * @param  userId the primary key of the link's creator
068             * @param  entryId1 the primary key of the first asset entry
069             * @param  entryId2 the primary key of the second asset entry
070             * @param  type the link type. Acceptable values include {@link
071             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
072             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
073             *         unidirectional relationship. For more information see {@link
074             *         AssetLinkConstants}
075             * @param  weight the weight of the relationship, allowing precedence
076             *         ordering of links
077             * @return the asset link
078             */
079            @Override
080            public AssetLink addLink(
081                            long userId, long entryId1, long entryId2, int type, int weight)
082                    throws PortalException {
083    
084                    User user = userPersistence.findByPrimaryKey(userId);
085                    Date now = new Date();
086    
087                    long linkId = counterLocalService.increment();
088    
089                    AssetLink link = assetLinkPersistence.create(linkId);
090    
091                    link.setCompanyId(user.getCompanyId());
092                    link.setUserId(user.getUserId());
093                    link.setUserName(user.getFullName());
094                    link.setCreateDate(now);
095                    link.setEntryId1(entryId1);
096                    link.setEntryId2(entryId2);
097                    link.setType(type);
098                    link.setWeight(weight);
099    
100                    assetLinkPersistence.update(link);
101    
102                    if (AssetLinkConstants.isTypeBi(type)) {
103                            long linkId2 = counterLocalService.increment();
104    
105                            AssetLink link2 = assetLinkPersistence.create(linkId2);
106    
107                            link2.setCompanyId(user.getCompanyId());
108                            link2.setUserId(user.getUserId());
109                            link2.setUserName(user.getFullName());
110                            link2.setCreateDate(now);
111                            link2.setEntryId1(entryId2);
112                            link2.setEntryId2(entryId1);
113                            link2.setType(type);
114                            link2.setWeight(weight);
115    
116                            assetLinkPersistence.update(link2);
117                    }
118    
119                    return link;
120            }
121    
122            @Override
123            public void deleteGroupLinks(long groupId) {
124                    Session session = assetLinkPersistence.openSession();
125    
126                    try {
127                            String sql = CustomSQLUtil.get(_DELETE_BY_ASSET_ENTRY_GROUP_ID);
128    
129                            SQLQuery sqlQuery = session.createSynchronizedSQLQuery(sql);
130    
131                            QueryPos qPos = QueryPos.getInstance(sqlQuery);
132    
133                            qPos.add(groupId);
134                            qPos.add(groupId);
135    
136                            sqlQuery.executeUpdate();
137                    }
138                    finally {
139                            assetLinkPersistence.closeSession(session);
140    
141                            assetLinkPersistence.clearCache();
142                    }
143            }
144    
145            /**
146             * Deletes the asset link.
147             *
148             * @param link the asset link
149             */
150            @Override
151            public void deleteLink(AssetLink link) {
152                    if (AssetLinkConstants.isTypeBi(link.getType())) {
153                            try {
154                                    assetLinkPersistence.removeByE_E_T(
155                                            link.getEntryId2(), link.getEntryId1(), link.getType());
156                            }
157                            catch (NoSuchLinkException nsle) {
158                                    if (_log.isWarnEnabled()) {
159                                            _log.warn("Unable to delete asset link", nsle);
160                                    }
161                            }
162                    }
163    
164                    assetLinkPersistence.remove(link);
165            }
166    
167            /**
168             * Deletes the asset link.
169             *
170             * @param linkId the primary key of the asset link
171             */
172            @Override
173            public void deleteLink(long linkId) throws PortalException {
174                    AssetLink link = assetLinkPersistence.findByPrimaryKey(linkId);
175    
176                    deleteLink(link);
177            }
178    
179            /**
180             * Deletes all links associated with the asset entry.
181             *
182             * @param entryId the primary key of the asset entry
183             */
184            @Override
185            public void deleteLinks(long entryId) {
186                    for (AssetLink link : assetLinkPersistence.findByE1(entryId)) {
187                            deleteLink(link);
188                    }
189    
190                    for (AssetLink link : assetLinkPersistence.findByE2(entryId)) {
191                            deleteLink(link);
192                    }
193            }
194    
195            /**
196             * Delete all links that associate the two asset entries.
197             *
198             * @param entryId1 the primary key of the first asset entry
199             * @param entryId2 the primary key of the second asset entry
200             */
201            @Override
202            public void deleteLinks(long entryId1, long entryId2) {
203                    List<AssetLink> links = assetLinkPersistence.findByE_E(
204                            entryId1, entryId2);
205    
206                    for (AssetLink link : links) {
207                            deleteLink(link);
208                    }
209            }
210    
211            /**
212             * Returns all the asset links whose first entry ID is the given entry ID.
213             *
214             * @param  entryId the primary key of the asset entry
215             * @return the asset links whose first entry ID is the given entry ID
216             */
217            @Override
218            public List<AssetLink> getDirectLinks(long entryId) {
219                    return getDirectLinks(entryId, true);
220            }
221    
222            @Override
223            public List<AssetLink> getDirectLinks(
224                    long entryId, boolean excludeInvisibleLinks) {
225    
226                    List<AssetLink> assetLinks = assetLinkPersistence.findByE1(entryId);
227    
228                    return filterAssetLinks(assetLinks, excludeInvisibleLinks);
229            }
230    
231            /**
232             * Returns all the asset links of the given link type whose first entry ID
233             * is the given entry ID.
234             *
235             * @param  entryId the primary key of the asset entry
236             * @param  typeId the link type. Acceptable values include {@link
237             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
238             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
239             *         unidirectional relationship. For more information see {@link
240             *         AssetLinkConstants}
241             * @return the asset links of the given link type whose first entry ID is
242             *         the given entry ID
243             */
244            @Override
245            public List<AssetLink> getDirectLinks(long entryId, int typeId) {
246                    return getDirectLinks(entryId, typeId, true);
247            }
248    
249            @Override
250            public List<AssetLink> getDirectLinks(
251                    long entryId, int typeId, boolean excludeInvisibleLinks) {
252    
253                    List<AssetLink> assetLinks = assetLinkPersistence.findByE1_T(
254                            entryId, typeId);
255    
256                    return filterAssetLinks(assetLinks, excludeInvisibleLinks);
257            }
258    
259            @Override
260            public ExportActionableDynamicQuery getExportActionbleDynamicQuery(
261                    final PortletDataContext portletDataContext) {
262    
263                    final ExportActionableDynamicQuery exportActionableDynamicQuery =
264                            new ExportActionableDynamicQuery();
265    
266                    exportActionableDynamicQuery.setAddCriteriaMethod(
267                            new ActionableDynamicQuery.AddCriteriaMethod() {
268    
269                                    @Override
270                                    public void addCriteria(DynamicQuery dynamicQuery) {
271                                            Criterion createDateCriterion =
272                                                    portletDataContext.getDateRangeCriteria("createDate");
273    
274                                            if (createDateCriterion != null) {
275                                                    dynamicQuery.add(createDateCriterion);
276                                            }
277    
278                                            DynamicQuery assetEntryDynamicQuery =
279                                                    DynamicQueryFactoryUtil.forClass(
280                                                            AssetEntry.class, "assetEntry", getClassLoader());
281    
282                                            assetEntryDynamicQuery.setProjection(
283                                                    ProjectionFactoryUtil.alias(
284                                                            ProjectionFactoryUtil.property(
285                                                                    "assetEntry.entryId"),
286                                                            "assetEntry.assetEntryId"));
287    
288                                            Property groupIdProperty = PropertyFactoryUtil.forName(
289                                                    "groupId");
290    
291                                            Criterion groupIdCriterion = groupIdProperty.eq(
292                                                    portletDataContext.getScopeGroupId());
293    
294                                            assetEntryDynamicQuery.add(groupIdCriterion);
295    
296                                            Disjunction disjunction =
297                                                    RestrictionsFactoryUtil.disjunction();
298    
299                                            Property entryId1Property = PropertyFactoryUtil.forName(
300                                                    "entryId1");
301                                            Property entryId2Property = PropertyFactoryUtil.forName(
302                                                    "entryId2");
303    
304                                            disjunction.add(
305                                                    entryId1Property.in(assetEntryDynamicQuery));
306                                            disjunction.add(
307                                                    entryId2Property.in(assetEntryDynamicQuery));
308    
309                                            dynamicQuery.add(disjunction);
310                                    }
311    
312                            });
313                    exportActionableDynamicQuery.setBaseLocalService(this);
314                    exportActionableDynamicQuery.setClassLoader(getClassLoader());
315                    exportActionableDynamicQuery.setCompanyId(
316                            portletDataContext.getCompanyId());
317                    exportActionableDynamicQuery.setModelClass(AssetLink.class);
318                    exportActionableDynamicQuery.setPerformActionMethod(
319                            new ActionableDynamicQuery.PerformActionMethod<AssetLink>() {
320    
321                                    @Override
322                                    public void performAction(AssetLink assetLink)
323                                            throws PortalException {
324    
325                                            StagedAssetLink stagedAssetLink = ModelAdapterUtil.adapt(
326                                                    assetLink, AssetLink.class, StagedAssetLink.class);
327    
328                                            StagedModelDataHandlerUtil.exportStagedModel(
329                                                    portletDataContext, stagedAssetLink);
330                                    }
331    
332                            });
333                    exportActionableDynamicQuery.setPrimaryKeyPropertyName("linkId");
334                    exportActionableDynamicQuery.setStagedModelType(
335                            new StagedModelType(StagedModelType.class));
336    
337                    return exportActionableDynamicQuery;
338            }
339    
340            /**
341             * Returns all the asset links whose first or second entry ID is the given
342             * entry ID.
343             *
344             * @param  entryId the primary key of the asset entry
345             * @return the asset links whose first or second entry ID is the given entry
346             *         ID
347             */
348            @Override
349            public List<AssetLink> getLinks(long entryId) {
350                    List<AssetLink> e1Links = assetLinkPersistence.findByE1(entryId);
351                    List<AssetLink> e2Links = assetLinkPersistence.findByE2(entryId);
352    
353                    List<AssetLink> links = new ArrayList<>(
354                            e1Links.size() + e2Links.size());
355    
356                    links.addAll(e1Links);
357                    links.addAll(e2Links);
358    
359                    return links;
360            }
361    
362            /**
363             * Returns all the asset links of the given link type whose first or second
364             * entry ID is the given entry ID.
365             *
366             * @param  entryId the primary key of the asset entry
367             * @param  typeId the link type. Acceptable values include {@link
368             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
369             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
370             *         unidirectional relationship. For more information see {@link
371             *         AssetLinkConstants}
372             * @return the asset links of the given link type whose first or second
373             *         entry ID is the given entry ID
374             */
375            @Override
376            public List<AssetLink> getLinks(long entryId, int typeId) {
377                    List<AssetLink> e1Links = assetLinkPersistence.findByE1_T(
378                            entryId, typeId);
379                    List<AssetLink> e2Links = assetLinkPersistence.findByE2_T(
380                            entryId, typeId);
381    
382                    List<AssetLink> links = new ArrayList<>(
383                            e1Links.size() + e2Links.size());
384    
385                    links.addAll(e1Links);
386                    links.addAll(e2Links);
387    
388                    return links;
389            }
390    
391            /**
392             * Returns all the asset links of the given link type whose second entry ID
393             * is the given entry ID.
394             *
395             * @param  entryId the primary key of the asset entry
396             * @param  typeId the link type. Acceptable values include {@link
397             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
398             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
399             *         unidirectional relationship. For more information see {@link
400             *         AssetLinkConstants}
401             * @return the asset links of the given link type whose second entry ID is
402             *         the given entry ID
403             */
404            @Override
405            public List<AssetLink> getReverseLinks(long entryId, int typeId) {
406                    return assetLinkPersistence.findByE2_T(entryId, typeId);
407            }
408    
409            @Override
410            public AssetLink updateLink(
411                            long userId, long entryId1, long entryId2, int typeId, int weight)
412                    throws PortalException {
413    
414                    AssetLink assetLink = assetLinkPersistence.fetchByE_E_T(
415                            entryId1, entryId2, typeId);
416    
417                    if (assetLink == null) {
418                            return addLink(userId, entryId1, entryId2, typeId, weight);
419                    }
420    
421                    assetLink.setWeight(weight);
422    
423                    assetLinkPersistence.update(assetLink);
424    
425                    return assetLink;
426            }
427    
428            /**
429             * Updates all links of the asset entry, replacing them with links
430             * associating the asset entry with the asset entries of the given link
431             * entry IDs.
432             *
433             * <p>
434             * If no link exists with a given link entry ID, a new link is created
435             * associating the current asset entry with the asset entry of that link
436             * entry ID. An existing link is deleted if either of its entry IDs is not
437             * contained in the given link entry IDs.
438             * </p>
439             *
440             * @param userId the primary key of the user updating the links
441             * @param entryId the primary key of the asset entry to be managed
442             * @param linkEntryIds the primary keys of the asset entries to be linked
443             *        with the asset entry to be managed
444             * @param typeId the type of the asset links to be created. Acceptable
445             *        values include {@link AssetLinkConstants#TYPE_RELATED} which is a
446             *        bidirectional relationship and {@link
447             *        AssetLinkConstants#TYPE_CHILD} which is a unidirectional
448             *        relationship. For more information see {@link AssetLinkConstants}
449             */
450            @Override
451            public void updateLinks(
452                            long userId, long entryId, long[] linkEntryIds, int typeId)
453                    throws PortalException {
454    
455                    if (linkEntryIds == null) {
456                            return;
457                    }
458    
459                    List<AssetLink> links = getLinks(entryId, typeId);
460    
461                    for (AssetLink link : links) {
462                            if (((link.getEntryId1() == entryId) &&
463                                     !ArrayUtil.contains(linkEntryIds, link.getEntryId2())) ||
464                                    ((link.getEntryId2() == entryId) &&
465                                     !ArrayUtil.contains(linkEntryIds, link.getEntryId1()))) {
466    
467                                    deleteLink(link);
468                            }
469                    }
470    
471                    for (long assetLinkEntryId : linkEntryIds) {
472                            if (assetLinkEntryId != entryId) {
473                                    AssetLink link = assetLinkPersistence.fetchByE_E_T(
474                                            entryId, assetLinkEntryId, typeId);
475    
476                                    if (link == null) {
477                                            addLink(userId, entryId, assetLinkEntryId, typeId, 0);
478                                    }
479                            }
480                    }
481            }
482    
483            protected List<AssetLink> filterAssetLinks(
484                    List<AssetLink> assetLinks, boolean excludeInvisibleLinks) {
485    
486                    if (assetLinks.isEmpty() || !excludeInvisibleLinks) {
487                            return assetLinks;
488                    }
489    
490                    List<AssetLink> filteredAssetLinks = new ArrayList<>(assetLinks.size());
491    
492                    for (AssetLink assetLink : assetLinks) {
493                            AssetEntry assetEntry = assetEntryPersistence.fetchByPrimaryKey(
494                                    assetLink.getEntryId2());
495    
496                            if ((assetEntry != null) && assetEntry.isVisible()) {
497                                    filteredAssetLinks.add(assetLink);
498                            }
499                    }
500    
501                    assetLinks = Collections.unmodifiableList(filteredAssetLinks);
502    
503                    return assetLinks;
504            }
505    
506            private static final String _DELETE_BY_ASSET_ENTRY_GROUP_ID =
507                    AssetLinkLocalServiceImpl.class.getName() +
508                            ".deleteByAssetEntryGroupId";
509    
510            private static final Log _log = LogFactoryUtil.getLog(
511                    AssetLinkLocalServiceImpl.class);
512    
513    }