001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.asset.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
018    import com.liferay.portal.kernel.dao.orm.Criterion;
019    import com.liferay.portal.kernel.dao.orm.Disjunction;
020    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
021    import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
022    import com.liferay.portal.kernel.dao.orm.ExportActionableDynamicQuery;
023    import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
024    import com.liferay.portal.kernel.dao.orm.Property;
025    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
026    import com.liferay.portal.kernel.dao.orm.QueryPos;
027    import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
028    import com.liferay.portal.kernel.dao.orm.SQLQuery;
029    import com.liferay.portal.kernel.dao.orm.Session;
030    import com.liferay.portal.kernel.exception.PortalException;
031    import com.liferay.portal.kernel.log.Log;
032    import com.liferay.portal.kernel.log.LogFactoryUtil;
033    import com.liferay.portal.kernel.util.ArrayUtil;
034    import com.liferay.portal.model.User;
035    import com.liferay.portal.model.adapter.ModelAdapterUtil;
036    import com.liferay.portlet.asset.exception.NoSuchLinkException;
037    import com.liferay.portlet.asset.model.AssetEntry;
038    import com.liferay.portlet.asset.model.AssetLink;
039    import com.liferay.portlet.asset.model.AssetLinkConstants;
040    import com.liferay.portlet.asset.model.adapter.StagedAssetLink;
041    import com.liferay.portlet.asset.service.base.AssetLinkLocalServiceBaseImpl;
042    import com.liferay.portlet.exportimport.lar.PortletDataContext;
043    import com.liferay.portlet.exportimport.lar.StagedModelDataHandlerUtil;
044    import com.liferay.portlet.exportimport.lar.StagedModelType;
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                    List<AssetLink> assetLinks = assetLinkPersistence.findByE1(entryId);
220    
221                    if (!assetLinks.isEmpty()) {
222                            List<AssetLink> filteredAssetLinks = new ArrayList<>(
223                                    assetLinks.size());
224    
225                            for (AssetLink assetLink : assetLinks) {
226                                    AssetEntry assetEntry = assetEntryPersistence.fetchByPrimaryKey(
227                                            assetLink.getEntryId2());
228    
229                                    if ((assetEntry != null) && assetEntry.isVisible()) {
230                                            filteredAssetLinks.add(assetLink);
231                                    }
232                            }
233    
234                            assetLinks = Collections.unmodifiableList(filteredAssetLinks);
235                    }
236    
237                    return assetLinks;
238            }
239    
240            /**
241             * Returns all the asset links of the given link type whose first entry ID
242             * is the given entry ID.
243             *
244             * @param  entryId the primary key of the asset entry
245             * @param  typeId the link type. Acceptable values include {@link
246             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
247             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
248             *         unidirectional relationship. For more information see {@link
249             *         AssetLinkConstants}
250             * @return the asset links of the given link type whose first entry ID is
251             *         the given entry ID
252             */
253            @Override
254            public List<AssetLink> getDirectLinks(long entryId, int typeId) {
255                    List<AssetLink> assetLinks = assetLinkPersistence.findByE1_T(
256                            entryId, typeId);
257    
258                    if (!assetLinks.isEmpty()) {
259                            List<AssetLink> filteredAssetLinks = new ArrayList<>(
260                                    assetLinks.size());
261    
262                            for (AssetLink assetLink : assetLinks) {
263                                    AssetEntry assetEntry = assetEntryPersistence.fetchByPrimaryKey(
264                                            assetLink.getEntryId2());
265    
266                                    if ((assetEntry != null) && assetEntry.isVisible()) {
267                                            filteredAssetLinks.add(assetLink);
268                                    }
269                            }
270    
271                            assetLinks = Collections.unmodifiableList(filteredAssetLinks);
272                    }
273    
274                    return assetLinks;
275            }
276    
277            @Override
278            public ExportActionableDynamicQuery getExportActionbleDynamicQuery(
279                    final PortletDataContext portletDataContext) {
280    
281                    final ExportActionableDynamicQuery exportActionableDynamicQuery =
282                            new ExportActionableDynamicQuery();
283    
284                    exportActionableDynamicQuery.setAddCriteriaMethod(
285                            new ActionableDynamicQuery.AddCriteriaMethod() {
286    
287                                    @Override
288                                    public void addCriteria(DynamicQuery dynamicQuery) {
289                                            Criterion createDateCriterion =
290                                                    portletDataContext.getDateRangeCriteria("createDate");
291    
292                                            if (createDateCriterion != null) {
293                                                    dynamicQuery.add(createDateCriterion);
294                                            }
295    
296                                            DynamicQuery assetEntryDynamicQuery =
297                                                    DynamicQueryFactoryUtil.forClass(
298                                                            AssetEntry.class, "assetEntry", getClassLoader());
299    
300                                            assetEntryDynamicQuery.setProjection(
301                                                    ProjectionFactoryUtil.alias(
302                                                            ProjectionFactoryUtil.property(
303                                                                    "assetEntry.entryId"),
304                                                            "assetEntry.assetEntryId"));
305    
306                                            Property groupIdProperty = PropertyFactoryUtil.forName(
307                                                    "groupId");
308    
309                                            Criterion groupIdCriterion = groupIdProperty.eq(
310                                                    portletDataContext.getScopeGroupId());
311    
312                                            assetEntryDynamicQuery.add(groupIdCriterion);
313    
314                                            Disjunction disjunction =
315                                                    RestrictionsFactoryUtil.disjunction();
316    
317                                            Property entryId1Property = PropertyFactoryUtil.forName(
318                                                    "entryId1");
319                                            Property entryId2Property = PropertyFactoryUtil.forName(
320                                                    "entryId2");
321    
322                                            disjunction.add(
323                                                    entryId1Property.in(assetEntryDynamicQuery));
324                                            disjunction.add(
325                                                    entryId2Property.in(assetEntryDynamicQuery));
326    
327                                            dynamicQuery.add(disjunction);
328                                    }
329    
330                            });
331                    exportActionableDynamicQuery.setBaseLocalService(this);
332                    exportActionableDynamicQuery.setClassLoader(getClassLoader());
333                    exportActionableDynamicQuery.setCompanyId(
334                            portletDataContext.getCompanyId());
335                    exportActionableDynamicQuery.setModelClass(AssetLink.class);
336                    exportActionableDynamicQuery.setPerformActionMethod(
337                            new ActionableDynamicQuery.PerformActionMethod<AssetLink>() {
338    
339                                    @Override
340                                    public void performAction(AssetLink assetLink)
341                                            throws PortalException {
342    
343                                            StagedAssetLink stagedAssetLink = ModelAdapterUtil.adapt(
344                                                    assetLink, AssetLink.class, StagedAssetLink.class);
345    
346                                            StagedModelDataHandlerUtil.exportStagedModel(
347                                                    portletDataContext, stagedAssetLink);
348                                    }
349    
350                            });
351                    exportActionableDynamicQuery.setPrimaryKeyPropertyName("linkId");
352                    exportActionableDynamicQuery.setStagedModelType(
353                            new StagedModelType(StagedModelType.class));
354    
355                    return exportActionableDynamicQuery;
356            }
357    
358            /**
359             * Returns all the asset links whose first or second entry ID is the given
360             * entry ID.
361             *
362             * @param  entryId the primary key of the asset entry
363             * @return the asset links whose first or second entry ID is the given entry
364             *         ID
365             */
366            @Override
367            public List<AssetLink> getLinks(long entryId) {
368                    List<AssetLink> e1Links = assetLinkPersistence.findByE1(entryId);
369                    List<AssetLink> e2Links = assetLinkPersistence.findByE2(entryId);
370    
371                    List<AssetLink> links = new ArrayList<>(
372                            e1Links.size() + e2Links.size());
373    
374                    links.addAll(e1Links);
375                    links.addAll(e2Links);
376    
377                    return links;
378            }
379    
380            /**
381             * Returns all the asset links of the given link type whose first or second
382             * entry ID is the given entry ID.
383             *
384             * @param  entryId the primary key of the asset entry
385             * @param  typeId the link type. Acceptable values include {@link
386             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
387             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
388             *         unidirectional relationship. For more information see {@link
389             *         AssetLinkConstants}
390             * @return the asset links of the given link type whose first or second
391             *         entry ID is the given entry ID
392             */
393            @Override
394            public List<AssetLink> getLinks(long entryId, int typeId) {
395                    List<AssetLink> e1Links = assetLinkPersistence.findByE1_T(
396                            entryId, typeId);
397                    List<AssetLink> e2Links = assetLinkPersistence.findByE2_T(
398                            entryId, typeId);
399    
400                    List<AssetLink> links = new ArrayList<>(
401                            e1Links.size() + e2Links.size());
402    
403                    links.addAll(e1Links);
404                    links.addAll(e2Links);
405    
406                    return links;
407            }
408    
409            /**
410             * Returns all the asset links of the given link type whose second entry ID
411             * is the given entry ID.
412             *
413             * @param  entryId the primary key of the asset entry
414             * @param  typeId the link type. Acceptable values include {@link
415             *         AssetLinkConstants#TYPE_RELATED} which is a bidirectional
416             *         relationship and {@link AssetLinkConstants#TYPE_CHILD} which is a
417             *         unidirectional relationship. For more information see {@link
418             *         AssetLinkConstants}
419             * @return the asset links of the given link type whose second entry ID is
420             *         the given entry ID
421             */
422            @Override
423            public List<AssetLink> getReverseLinks(long entryId, int typeId) {
424                    return assetLinkPersistence.findByE2_T(entryId, typeId);
425            }
426    
427            @Override
428            public AssetLink updateLink(
429                            long userId, long entryId1, long entryId2, int typeId, int weight)
430                    throws PortalException {
431    
432                    AssetLink assetLink = assetLinkPersistence.fetchByE_E_T(
433                            entryId1, entryId2, typeId);
434    
435                    if (assetLink == null) {
436                            return addLink(userId, entryId1, entryId2, typeId, weight);
437                    }
438    
439                    assetLink.setWeight(weight);
440    
441                    assetLinkPersistence.update(assetLink);
442    
443                    return assetLink;
444            }
445    
446            /**
447             * Updates all links of the asset entry, replacing them with links
448             * associating the asset entry with the asset entries of the given link
449             * entry IDs.
450             *
451             * <p>
452             * If no link exists with a given link entry ID, a new link is created
453             * associating the current asset entry with the asset entry of that link
454             * entry ID. An existing link is deleted if either of its entry IDs is not
455             * contained in the given link entry IDs.
456             * </p>
457             *
458             * @param userId the primary key of the user updating the links
459             * @param entryId the primary key of the asset entry to be managed
460             * @param linkEntryIds the primary keys of the asset entries to be linked
461             *        with the asset entry to be managed
462             * @param typeId the type of the asset links to be created. Acceptable
463             *        values include {@link AssetLinkConstants#TYPE_RELATED} which is a
464             *        bidirectional relationship and {@link
465             *        AssetLinkConstants#TYPE_CHILD} which is a unidirectional
466             *        relationship. For more information see {@link AssetLinkConstants}
467             */
468            @Override
469            public void updateLinks(
470                            long userId, long entryId, long[] linkEntryIds, int typeId)
471                    throws PortalException {
472    
473                    if (linkEntryIds == null) {
474                            return;
475                    }
476    
477                    List<AssetLink> links = getLinks(entryId, typeId);
478    
479                    for (AssetLink link : links) {
480                            if (((link.getEntryId1() == entryId) &&
481                                     !ArrayUtil.contains(linkEntryIds, link.getEntryId2())) ||
482                                    ((link.getEntryId2() == entryId) &&
483                                     !ArrayUtil.contains(linkEntryIds, link.getEntryId1()))) {
484    
485                                    deleteLink(link);
486                            }
487                    }
488    
489                    for (long assetLinkEntryId : linkEntryIds) {
490                            if (assetLinkEntryId != entryId) {
491                                    AssetLink link = assetLinkPersistence.fetchByE_E_T(
492                                            entryId, assetLinkEntryId, typeId);
493    
494                                    if (link == null) {
495                                            addLink(userId, entryId, assetLinkEntryId, typeId, 0);
496                                    }
497                            }
498                    }
499            }
500    
501            private static final String _DELETE_BY_ASSET_ENTRY_GROUP_ID =
502                    AssetLinkLocalServiceImpl.class.getName() +
503                            ".deleteByAssetEntryGroupId";
504    
505            private static final Log _log = LogFactoryUtil.getLog(
506                    AssetLinkLocalServiceImpl.class);
507    
508    }