001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.service.impl;
016    
017    import com.liferay.portal.LayoutFriendlyURLException;
018    import com.liferay.portal.LayoutNameException;
019    import com.liferay.portal.LayoutParentLayoutIdException;
020    import com.liferay.portal.LayoutTypeException;
021    import com.liferay.portal.NoSuchLayoutException;
022    import com.liferay.portal.kernel.bean.BeanReference;
023    import com.liferay.portal.kernel.bean.IdentifiableBean;
024    import com.liferay.portal.kernel.exception.PortalException;
025    import com.liferay.portal.kernel.exception.SystemException;
026    import com.liferay.portal.kernel.language.LanguageUtil;
027    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
028    import com.liferay.portal.kernel.util.LocaleUtil;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.Validator;
031    import com.liferay.portal.model.Group;
032    import com.liferay.portal.model.Layout;
033    import com.liferay.portal.model.LayoutConstants;
034    import com.liferay.portal.model.LayoutFriendlyURL;
035    import com.liferay.portal.model.LayoutSet;
036    import com.liferay.portal.model.LayoutSetPrototype;
037    import com.liferay.portal.model.ResourceConstants;
038    import com.liferay.portal.model.Role;
039    import com.liferay.portal.model.RoleConstants;
040    import com.liferay.portal.model.impl.LayoutImpl;
041    import com.liferay.portal.security.permission.ActionKeys;
042    import com.liferay.portal.service.ResourcePermissionLocalService;
043    import com.liferay.portal.service.RoleLocalServiceUtil;
044    import com.liferay.portal.service.persistence.LayoutFriendlyURLPersistence;
045    import com.liferay.portal.service.persistence.LayoutPersistence;
046    import com.liferay.portal.service.persistence.LayoutSetPersistence;
047    import com.liferay.portal.util.PortalUtil;
048    import com.liferay.portal.util.comparator.LayoutPriorityComparator;
049    import com.liferay.portlet.sites.util.SitesUtil;
050    
051    import java.util.HashMap;
052    import java.util.List;
053    import java.util.Locale;
054    import java.util.Map;
055    
056    /**
057     * @author Raymond Aug??
058     */
059    public class LayoutLocalServiceHelper implements IdentifiableBean {
060    
061            @Override
062            public String getBeanIdentifier() {
063                    return _beanIdentifier;
064            }
065    
066            public String getFriendlyURL(
067                            long groupId, boolean privateLayout, long layoutId, String name,
068                            String friendlyURL)
069                    throws PortalException, SystemException {
070    
071                    friendlyURL = getFriendlyURL(friendlyURL);
072    
073                    if (Validator.isNotNull(friendlyURL)) {
074                            return friendlyURL;
075                    }
076    
077                    friendlyURL = StringPool.SLASH + getFriendlyURL(name);
078    
079                    String originalFriendlyURL = friendlyURL;
080    
081                    for (int i = 1;; i++) {
082                            try {
083                                    validateFriendlyURL(
084                                            groupId, privateLayout, layoutId, friendlyURL);
085    
086                                    break;
087                            }
088                            catch (LayoutFriendlyURLException lfurle) {
089                                    int type = lfurle.getType();
090    
091                                    if (type == LayoutFriendlyURLException.DUPLICATE) {
092                                            friendlyURL = originalFriendlyURL + i;
093                                    }
094                                    else {
095                                            friendlyURL = StringPool.SLASH + layoutId;
096    
097                                            break;
098                                    }
099                            }
100                    }
101    
102                    return friendlyURL;
103            }
104    
105            public String getFriendlyURL(String friendlyURL) {
106                    return FriendlyURLNormalizerUtil.normalize(friendlyURL);
107            }
108    
109            public Map<Locale, String> getFriendlyURLMap(
110                            long groupId, boolean privateLayout, long layoutId, String name,
111                            Map<Locale, String> friendlyURLMap)
112                    throws PortalException, SystemException {
113    
114                    Map<Locale, String> newFriendlyURLMap = new HashMap<Locale, String>();
115    
116                    Locale[] locales = LanguageUtil.getAvailableLocales(groupId);
117    
118                    for (Locale locale : locales) {
119                            String friendlyURL = friendlyURLMap.get(locale);
120    
121                            if (Validator.isNotNull(friendlyURL)) {
122                                    friendlyURL = getFriendlyURL(
123                                            groupId, privateLayout, layoutId, name, friendlyURL);
124    
125                                    newFriendlyURLMap.put(locale, friendlyURL);
126                            }
127                    }
128    
129                    if (newFriendlyURLMap.isEmpty()) {
130                            String friendlyURL = getFriendlyURL(
131                                    groupId, privateLayout, layoutId, name, StringPool.BLANK);
132    
133                            newFriendlyURLMap.put(LocaleUtil.getSiteDefault(), friendlyURL);
134                    }
135    
136                    return newFriendlyURLMap;
137            }
138    
139            public int getNextPriority(
140                            long groupId, boolean privateLayout, long parentLayoutId,
141                            String sourcePrototypeLayoutUuid, int defaultPriority)
142                    throws SystemException {
143    
144                    try {
145                            int priority = defaultPriority;
146    
147                            if (priority < 0) {
148                                    Layout layout = layoutPersistence.findByG_P_P_First(
149                                            groupId, privateLayout, parentLayoutId,
150                                            new LayoutPriorityComparator(false));
151    
152                                    priority = layout.getPriority() + 1;
153                            }
154    
155                            if ((priority < _PRIORITY_BUFFER) &&
156                                    Validator.isNull(sourcePrototypeLayoutUuid)) {
157    
158                                    LayoutSet layoutSet = layoutSetPersistence.fetchByG_P(
159                                            groupId, privateLayout);
160    
161                                    if (Validator.isNotNull(
162                                                    layoutSet.getLayoutSetPrototypeUuid()) &&
163                                            layoutSet.isLayoutSetPrototypeLinkEnabled()) {
164    
165                                            priority = priority + _PRIORITY_BUFFER;
166                                    }
167                            }
168    
169                            return priority;
170                    }
171                    catch (NoSuchLayoutException nsle) {
172                            return 0;
173                    }
174            }
175    
176            public long getParentLayoutId(
177                            long groupId, boolean privateLayout, long parentLayoutId)
178                    throws SystemException {
179    
180                    if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
181    
182                            // Ensure parent layout exists
183    
184                            Layout parentLayout = layoutPersistence.fetchByG_P_L(
185                                    groupId, privateLayout, parentLayoutId);
186    
187                            if (parentLayout == null) {
188                                    parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
189                            }
190                    }
191    
192                    return parentLayoutId;
193            }
194    
195            public boolean hasLayoutSetPrototypeLayout(
196                            LayoutSetPrototype layoutSetPrototype, String layoutUuid)
197                    throws PortalException, SystemException {
198    
199                    Layout layout = layoutPersistence.fetchByUUID_G_P(
200                            layoutUuid, layoutSetPrototype.getGroupId(), true);
201    
202                    if (layout != null) {
203                            return true;
204                    }
205    
206                    return false;
207            }
208    
209            @Override
210            public void setBeanIdentifier(String beanIdentifier) {
211                    _beanIdentifier = beanIdentifier;
212            }
213    
214            public void validate(
215                            long groupId, boolean privateLayout, long layoutId,
216                            long parentLayoutId, String name, String type, boolean hidden,
217                            Map<Locale, String> friendlyURLMap)
218                    throws PortalException, SystemException {
219    
220                    validateName(name);
221    
222                    boolean firstLayout = false;
223    
224                    if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
225                            List<Layout> layouts = layoutPersistence.findByG_P_P(
226                                    groupId, privateLayout, parentLayoutId, 0, 1);
227    
228                            if (layouts.size() == 0) {
229                                    firstLayout = true;
230                            }
231                            else {
232                                    long firstLayoutId = layouts.get(0).getLayoutId();
233    
234                                    if (firstLayoutId == layoutId) {
235                                            firstLayout = true;
236                                    }
237                            }
238                    }
239                    else {
240    
241                            // Layout cannot become a child of a layout that is not sortable
242                            // because it is linked to a layout set prototype
243    
244                            Layout parentLayout = layoutPersistence.findByG_P_L(
245                                    groupId, privateLayout, parentLayoutId);
246    
247                            if (!SitesUtil.isLayoutSortable(parentLayout)) {
248                                    throw new LayoutParentLayoutIdException(
249                                            LayoutParentLayoutIdException.NOT_SORTABLE);
250                            }
251                    }
252    
253                    if (firstLayout) {
254                            validateFirstLayout(type);
255                    }
256    
257                    if (!PortalUtil.isLayoutParentable(type)) {
258                            if (layoutPersistence.countByG_P_P(
259                                            groupId, privateLayout, layoutId) > 0) {
260    
261                                    throw new LayoutTypeException(
262                                            LayoutTypeException.NOT_PARENTABLE);
263                            }
264                    }
265    
266                    validateFriendlyURLs(groupId, privateLayout, layoutId, friendlyURLMap);
267            }
268    
269            public void validateFirstLayout(Layout layout)
270                    throws PortalException, SystemException {
271    
272                    Group group = layout.getGroup();
273    
274                    if (group.isGuest() && !hasGuestViewPermission(layout)) {
275                            LayoutTypeException lte = new LayoutTypeException(
276                                    LayoutTypeException.FIRST_LAYOUT_PERMISSION);
277    
278                            throw lte;
279                    }
280    
281                    validateFirstLayout(layout.getType());
282            }
283    
284            public void validateFirstLayout(String type) throws PortalException {
285                    if (Validator.isNull(type) || !PortalUtil.isLayoutFirstPageable(type)) {
286                            LayoutTypeException lte = new LayoutTypeException(
287                                    LayoutTypeException.FIRST_LAYOUT);
288    
289                            lte.setLayoutType(type);
290    
291                            throw lte;
292                    }
293            }
294    
295            public void validateFriendlyURL(
296                            long groupId, boolean privateLayout, long layoutId,
297                            String friendlyURL)
298                    throws PortalException, SystemException {
299    
300                    if (Validator.isNull(friendlyURL)) {
301                            return;
302                    }
303    
304                    int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
305    
306                    if (exceptionType != -1) {
307                            throw new LayoutFriendlyURLException(exceptionType);
308                    }
309    
310                    List<LayoutFriendlyURL> layoutFriendlyURLs =
311                            layoutFriendlyURLPersistence.findByG_P_F(
312                                    groupId, privateLayout, friendlyURL);
313    
314                    for (LayoutFriendlyURL layoutFriendlyURL : layoutFriendlyURLs) {
315                            Layout layout = layoutPersistence.findByPrimaryKey(
316                                    layoutFriendlyURL.getPlid());
317    
318                            if (layout.getLayoutId() != layoutId) {
319                                    throw new LayoutFriendlyURLException(
320                                            LayoutFriendlyURLException.DUPLICATE);
321                            }
322                    }
323    
324                    LayoutImpl.validateFriendlyURLKeyword(friendlyURL);
325    
326                    /*List<FriendlyURLMapper> friendlyURLMappers =
327                            portletLocalService.getFriendlyURLMappers();
328    
329                    for (FriendlyURLMapper friendlyURLMapper : friendlyURLMappers) {
330                            if (friendlyURL.indexOf(friendlyURLMapper.getMapping()) != -1) {
331                                    LayoutFriendlyURLException lfurle =
332                                            new LayoutFriendlyURLException(
333                                                    LayoutFriendlyURLException.KEYWORD_CONFLICT);
334    
335                                    lfurle.setKeywordConflict(friendlyURLMapper.getMapping());
336    
337                                    throw lfurle;
338                            }
339                    }*/
340    
341                    String layoutIdFriendlyURL = friendlyURL.substring(1);
342    
343                    if (Validator.isNumber(layoutIdFriendlyURL) &&
344                            !layoutIdFriendlyURL.equals(String.valueOf(layoutId))) {
345    
346                            LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
347                                    LayoutFriendlyURLException.POSSIBLE_DUPLICATE);
348    
349                            lfurle.setKeywordConflict(layoutIdFriendlyURL);
350    
351                            throw lfurle;
352                    }
353            }
354    
355            public void validateFriendlyURLs(
356                            long groupId, boolean privateLayout, long layoutId,
357                            Map<Locale, String> friendlyURLMap)
358                    throws PortalException, SystemException {
359    
360                    for (Map.Entry<Locale, String> entry : friendlyURLMap.entrySet()) {
361                            String friendlyURL = entry.getValue();
362    
363                            validateFriendlyURL(groupId, privateLayout, layoutId, friendlyURL);
364                    }
365            }
366    
367            public void validateName(String name) throws PortalException {
368                    if (Validator.isNull(name)) {
369                            throw new LayoutNameException();
370                    }
371            }
372    
373            public void validateName(String name, String languageId)
374                    throws PortalException {
375    
376                    String defaultLanguageId = LocaleUtil.toLanguageId(
377                            LocaleUtil.getSiteDefault());
378    
379                    if (defaultLanguageId.equals(languageId)) {
380                            validateName(name);
381                    }
382            }
383    
384            public void validateParentLayoutId(
385                            long groupId, boolean privateLayout, long layoutId,
386                            long parentLayoutId)
387                    throws PortalException, SystemException {
388    
389                    Layout layout = layoutPersistence.findByG_P_L(
390                            groupId, privateLayout, layoutId);
391    
392                    if (parentLayoutId == layout.getParentLayoutId()) {
393                            return;
394                    }
395    
396                    // Layouts can always be moved to the root level
397    
398                    if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
399                            return;
400                    }
401    
402                    // Layout cannot become a child of a layout that is not parentable
403    
404                    Layout parentLayout = layoutPersistence.findByG_P_L(
405                            groupId, privateLayout, parentLayoutId);
406    
407                    if (!PortalUtil.isLayoutParentable(parentLayout)) {
408                            throw new LayoutParentLayoutIdException(
409                                    LayoutParentLayoutIdException.NOT_PARENTABLE);
410                    }
411    
412                    // Layout cannot become a child of a layout that is not sortable because
413                    // it is linked to a layout set prototype
414    
415                    if (!SitesUtil.isLayoutSortable(parentLayout)) {
416                            throw new LayoutParentLayoutIdException(
417                                    LayoutParentLayoutIdException.NOT_SORTABLE);
418                    }
419    
420                    // Layout cannot become descendant of itself
421    
422                    if (PortalUtil.isLayoutDescendant(layout, parentLayoutId)) {
423                            throw new LayoutParentLayoutIdException(
424                                    LayoutParentLayoutIdException.SELF_DESCENDANT);
425                    }
426    
427                    // If layout is moved, the new first layout must be valid
428    
429                    if (layout.getParentLayoutId() ==
430                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
431    
432                            List<Layout> layouts = layoutPersistence.findByG_P_P(
433                                    groupId, privateLayout,
434                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
435    
436                            // You can only reach this point if there are more than two layouts
437                            // at the root level because of the descendant check
438    
439                            long firstLayoutId = layouts.get(0).getLayoutId();
440    
441                            if (firstLayoutId == layoutId) {
442                                    Layout secondLayout = layouts.get(1);
443    
444                                    if (Validator.isNull(secondLayout.getType()) ||
445                                            !PortalUtil.isLayoutFirstPageable(secondLayout.getType())) {
446    
447                                            throw new LayoutParentLayoutIdException(
448                                                    LayoutParentLayoutIdException.FIRST_LAYOUT_TYPE);
449                                    }
450                            }
451                    }
452            }
453    
454            protected boolean hasGuestViewPermission(Layout layout)
455                    throws PortalException, SystemException {
456    
457                    Role role = RoleLocalServiceUtil.getRole(
458                            layout.getCompanyId(), RoleConstants.GUEST);
459    
460                    return resourcePermissionLocalService.hasResourcePermission(
461                            layout.getCompanyId(), Layout.class.getName(),
462                            ResourceConstants.SCOPE_INDIVIDUAL,
463                            String.valueOf(layout.getPlid()), role.getRoleId(),
464                            ActionKeys.VIEW);
465            }
466    
467            @BeanReference(type = LayoutFriendlyURLPersistence.class)
468            protected LayoutFriendlyURLPersistence layoutFriendlyURLPersistence;
469    
470            @BeanReference(type = LayoutPersistence.class)
471            protected LayoutPersistence layoutPersistence;
472    
473            @BeanReference(type = LayoutSetPersistence.class)
474            protected LayoutSetPersistence layoutSetPersistence;
475    
476            @BeanReference(type = ResourcePermissionLocalService.class)
477            protected ResourcePermissionLocalService resourcePermissionLocalService;
478    
479            private static final int _PRIORITY_BUFFER = 1000000;
480    
481            private String _beanIdentifier;
482    
483    }