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