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