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