001    /**
002     * Copyright (c) 2000-2012 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.LayoutHiddenException;
019    import com.liferay.portal.LayoutNameException;
020    import com.liferay.portal.LayoutParentLayoutIdException;
021    import com.liferay.portal.LayoutTypeException;
022    import com.liferay.portal.NoSuchLayoutException;
023    import com.liferay.portal.RequiredLayoutException;
024    import com.liferay.portal.kernel.dao.orm.Criterion;
025    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
026    import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
027    import com.liferay.portal.kernel.dao.orm.Junction;
028    import com.liferay.portal.kernel.dao.orm.Projection;
029    import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
030    import com.liferay.portal.kernel.dao.orm.Property;
031    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
032    import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
033    import com.liferay.portal.kernel.exception.PortalException;
034    import com.liferay.portal.kernel.exception.SystemException;
035    import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
036    import com.liferay.portal.kernel.language.LanguageUtil;
037    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
038    import com.liferay.portal.kernel.util.FileUtil;
039    import com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil;
040    import com.liferay.portal.kernel.util.GetterUtil;
041    import com.liferay.portal.kernel.util.ListUtil;
042    import com.liferay.portal.kernel.util.LocaleUtil;
043    import com.liferay.portal.kernel.util.LocalizationUtil;
044    import com.liferay.portal.kernel.util.ParamUtil;
045    import com.liferay.portal.kernel.util.StringBundler;
046    import com.liferay.portal.kernel.util.StringPool;
047    import com.liferay.portal.kernel.util.UnicodeProperties;
048    import com.liferay.portal.kernel.util.Validator;
049    import com.liferay.portal.kernel.workflow.WorkflowConstants;
050    import com.liferay.portal.lar.LayoutExporter;
051    import com.liferay.portal.lar.LayoutImporter;
052    import com.liferay.portal.lar.PortletExporter;
053    import com.liferay.portal.lar.PortletImporter;
054    import com.liferay.portal.model.Group;
055    import com.liferay.portal.model.Layout;
056    import com.liferay.portal.model.LayoutConstants;
057    import com.liferay.portal.model.LayoutPrototype;
058    import com.liferay.portal.model.LayoutReference;
059    import com.liferay.portal.model.LayoutSet;
060    import com.liferay.portal.model.LayoutTypePortlet;
061    import com.liferay.portal.model.Portlet;
062    import com.liferay.portal.model.PortletConstants;
063    import com.liferay.portal.model.PortletPreferences;
064    import com.liferay.portal.model.Resource;
065    import com.liferay.portal.model.ResourceConstants;
066    import com.liferay.portal.model.ResourcePermission;
067    import com.liferay.portal.model.User;
068    import com.liferay.portal.model.UserGroup;
069    import com.liferay.portal.model.impl.LayoutImpl;
070    import com.liferay.portal.model.impl.PortletPreferencesImpl;
071    import com.liferay.portal.service.ServiceContext;
072    import com.liferay.portal.service.base.LayoutLocalServiceBaseImpl;
073    import com.liferay.portal.util.PortalUtil;
074    import com.liferay.portal.util.PortletKeys;
075    import com.liferay.portal.util.PropsValues;
076    import com.liferay.portal.util.comparator.LayoutComparator;
077    import com.liferay.portal.util.comparator.LayoutPriorityComparator;
078    import com.liferay.portlet.PortletPreferencesFactoryUtil;
079    import com.liferay.portlet.expando.model.ExpandoBridge;
080    
081    import java.io.File;
082    import java.io.IOException;
083    import java.io.InputStream;
084    
085    import java.text.DateFormat;
086    
087    import java.util.ArrayList;
088    import java.util.Date;
089    import java.util.HashMap;
090    import java.util.HashSet;
091    import java.util.LinkedHashSet;
092    import java.util.List;
093    import java.util.Locale;
094    import java.util.Map;
095    import java.util.Set;
096    
097    import javax.portlet.PortletException;
098    
099    /**
100     * The implementation of the layout local service.
101     *
102     * @author Brian Wing Shun Chan
103     * @author Jorge Ferrer
104     * @author Joel Kozikowski
105     * @author Charles May
106     * @author Raymond Augé
107     * @author Jorge Ferrer
108     * @author Bruno Farache
109     */
110    public class LayoutLocalServiceImpl extends LayoutLocalServiceBaseImpl {
111    
112            /**
113             * Returns the object counter's name.
114             *
115             * @param  groupId the primary key of the group
116             * @param  privateLayout whether layout is private to the group
117             * @return the object counter's name
118             */
119            public static String getCounterName(long groupId, boolean privateLayout) {
120                    StringBundler sb = new StringBundler();
121    
122                    sb.append(Layout.class.getName());
123                    sb.append(StringPool.POUND);
124                    sb.append(groupId);
125                    sb.append(StringPool.POUND);
126                    sb.append(privateLayout);
127    
128                    return sb.toString();
129            }
130    
131            /**
132             * Adds a layout with additional parameters.
133             *
134             * <p>
135             * This method handles the creation of the layout including its resources,
136             * metadata, and internal data structures. It is not necessary to make
137             * subsequent calls to any methods to setup default groups, resources, ...
138             * etc.
139             * </p>
140             *
141             * @param  userId the primary key of the user
142             * @param  groupId the primary key of the group
143             * @param  privateLayout whether the layout is private to the group
144             * @param  parentLayoutId the primary key of the parent layout (optionally
145             *         {@link
146             *         com.liferay.portal.model.LayoutConstants#DEFAULT_PARENT_LAYOUT_ID})
147             * @param  nameMap the layout's locales and localized names
148             * @param  titleMap the layout's locales and localized titles
149             * @param  descriptionMap the layout's locales and localized descriptions
150             * @param  keywordsMap the layout's locales and localized keywords
151             * @param  robotsMap the layout's locales and localized robots
152             * @param  type the layout's type (optionally {@link
153             *         com.liferay.portal.model.LayoutConstants#TYPE_PORTLET}). The
154             *         possible types can be found in {@link
155             *         com.liferay.portal.model.LayoutConstants}.
156             * @param  hidden whether the layout is hidden
157             * @param  friendlyURL the layout's friendly URL (optionally {@link
158             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PRIVATE_LAYOUT_FRIENDLY_URL}
159             *         or {@link
160             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PUBLIC_LAYOUT_FRIENDLY_URL}).
161             *         The default values can be overridden in
162             *         <code>portal-ext.properties</code> by specifying new values for
163             *         the corresponding properties defined in {@link
164             *         com.liferay.portal.util.PropsValues}. To see how the URL is
165             *         normalized when accessed see {@link
166             *         com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil#normalize(
167             *         String)}.
168             * @param  serviceContext the service context. Must set the universally
169             *         unique identifier (UUID) for the layout. Can set the creation
170             *         date, modification date and the expando bridge attributes for the
171             *         layout. For layouts that belong to a layout set prototype, an
172             *         attribute named 'layoutUpdateable' can be set to specify whether
173             *         site administrators can modify this page within their site. For
174             *         layouts that are created from a layout prototype, attributes
175             *         named 'layoutPrototypeUuid' and 'layoutPrototypeLinkedEnabled'
176             *         can be specified to provide the unique identifier of the source
177             *         prototype and a boolean to determined whether a link to it should
178             *         be enabled to activate propagation of changes made to the linked
179             *         page in the prototype.
180             * @return the layout
181             * @throws PortalException if a group or user with the primary key could not
182             *         be found, or if layout values were invalid
183             * @throws SystemException if a system exception occurred
184             */
185            public Layout addLayout(
186                            long userId, long groupId, boolean privateLayout,
187                            long parentLayoutId, Map<Locale, String> nameMap,
188                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
189                            Map<Locale, String> keywordsMap, Map<Locale, String> robotsMap,
190                            String type, boolean hidden, String friendlyURL,
191                            ServiceContext serviceContext)
192                    throws PortalException, SystemException {
193    
194                    // Layout
195    
196                    User user = userPersistence.findByPrimaryKey(userId);
197                    long layoutId = getNextLayoutId(groupId, privateLayout);
198                    parentLayoutId = getParentLayoutId(
199                            groupId, privateLayout, parentLayoutId);
200                    String name = nameMap.get(LocaleUtil.getDefault());
201                    friendlyURL = getFriendlyURL(
202                            groupId, privateLayout, layoutId, name, friendlyURL);
203                    int priority = getNextPriority(groupId, privateLayout, parentLayoutId);
204    
205                    validate(
206                            groupId, privateLayout, layoutId, parentLayoutId, name, type,
207                            hidden, friendlyURL);
208    
209                    Date now = new Date();
210    
211                    long plid = counterLocalService.increment();
212    
213                    Layout layout = layoutPersistence.create(plid);
214    
215                    layout.setUuid(serviceContext.getUuid());
216                    layout.setGroupId(groupId);
217                    layout.setCompanyId(user.getCompanyId());
218                    layout.setCreateDate(serviceContext.getCreateDate(now));
219                    layout.setModifiedDate(serviceContext.getModifiedDate(now));
220                    layout.setPrivateLayout(privateLayout);
221                    layout.setLayoutId(layoutId);
222                    layout.setParentLayoutId(parentLayoutId);
223                    layout.setNameMap(nameMap);
224                    layout.setTitleMap(titleMap);
225                    layout.setDescriptionMap(descriptionMap);
226                    layout.setKeywordsMap(keywordsMap);
227                    layout.setRobotsMap(robotsMap);
228                    layout.setType(type);
229                    layout.setHidden(hidden);
230                    layout.setFriendlyURL(friendlyURL);
231                    layout.setPriority(priority);
232    
233                    boolean layoutUpdateable = ParamUtil.getBoolean(
234                            serviceContext, "layoutUpdateable", true);
235    
236                    if (!layoutUpdateable) {
237                            UnicodeProperties typeSettingsProperties =
238                                    layout.getTypeSettingsProperties();
239    
240                            typeSettingsProperties.put(
241                                    "layoutUpdateable", String.valueOf(layoutUpdateable));
242    
243                            layout.setTypeSettingsProperties(typeSettingsProperties);
244                    }
245    
246                    String layoutPrototypeUuid = ParamUtil.getString(
247                            serviceContext, "layoutPrototypeUuid");
248                    boolean layoutPrototypeLinkEnabled = ParamUtil.getBoolean(
249                            serviceContext, "layoutPrototypeLinkEnabled", true);
250    
251                    if (Validator.isNotNull(layoutPrototypeUuid)) {
252                            layout.setLayoutPrototypeUuid(layoutPrototypeUuid);
253                            layout.setLayoutPrototypeLinkEnabled(layoutPrototypeLinkEnabled);
254    
255                            LayoutPrototype layoutPrototype =
256                                    layoutPrototypeLocalService.getLayoutPrototypeByUuid(
257                                            layoutPrototypeUuid);
258    
259                            Layout layoutPrototypeLayout = layoutPrototype.getLayout();
260    
261                            layout.setSourcePrototypeLayoutUuid(
262                                    layoutPrototypeLayout.getUuid());
263                    }
264    
265                    if (type.equals(LayoutConstants.TYPE_PORTLET)) {
266                            LayoutTypePortlet layoutTypePortlet =
267                                    (LayoutTypePortlet)layout.getLayoutType();
268    
269                            layoutTypePortlet.setLayoutTemplateId(
270                                    0, PropsValues.LAYOUT_DEFAULT_TEMPLATE_ID, false);
271                    }
272    
273                    layoutPersistence.update(layout, false);
274    
275                    // Resources
276    
277                    boolean addGroupPermissions = true;
278    
279                    Group group = groupLocalService.getGroup(groupId);
280    
281                    if (privateLayout && group.isUser()) {
282                            addGroupPermissions = false;
283                    }
284    
285                    boolean addGuestPermissions = false;
286    
287                    if (!privateLayout ||
288                            type.equals(LayoutConstants.TYPE_CONTROL_PANEL) ||
289                            group.isLayoutSetPrototype()) {
290    
291                            addGuestPermissions = true;
292                    }
293    
294                    resourceLocalService.addResources(
295                            user.getCompanyId(), groupId, user.getUserId(),
296                            Layout.class.getName(), layout.getPlid(), false,
297                            addGroupPermissions, addGuestPermissions);
298    
299                    // Group
300    
301                    groupLocalService.updateSite(groupId, true);
302    
303                    // Layout set
304    
305                    layoutSetLocalService.updatePageCount(groupId, privateLayout);
306    
307                    LayoutSet layoutSet = layoutSetLocalService.getLayoutSet(
308                            groupId, privateLayout);
309    
310                    layout.setLayoutSet(layoutSet);
311    
312                    // Expando
313    
314                    ExpandoBridge expandoBridge = layout.getExpandoBridge();
315    
316                    expandoBridge.setAttributes(serviceContext);
317    
318                    // Message boards
319    
320                    if (PropsValues.LAYOUT_COMMENTS_ENABLED) {
321                            mbMessageLocalService.addDiscussionMessage(
322                                    userId, user.getFullName(), groupId, Layout.class.getName(),
323                                    plid, WorkflowConstants.ACTION_PUBLISH);
324                    }
325    
326                    return layout;
327            }
328    
329            /**
330             * Adds a layout.
331             *
332             * <p>
333             * This method handles the creation of the layout including its resources,
334             * metadata, and internal data structures. It is not necessary to make
335             * subsequent calls to any methods to setup default groups, resources, ...
336             * etc.
337             * </p>
338             *
339             * @param  userId the primary key of the user
340             * @param  groupId the primary key of the group
341             * @param  privateLayout whether the layout is private to the group
342             * @param  parentLayoutId the primary key of the parent layout (optionally
343             *         {@link
344             *         com.liferay.portal.model.LayoutConstants#DEFAULT_PARENT_LAYOUT_ID}).
345             *         The possible values can be found in {@link
346             *         com.liferay.portal.model.LayoutConstants}.
347             * @param  name the layout's name (optionally {@link
348             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PRIVATE_LAYOUT_NAME}
349             *         or {@link
350             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PUBLIC_LAYOUT_NAME}).
351             *         The default values can be overridden in
352             *         <code>portal-ext.properties</code> by specifying new values for
353             *         the corresponding properties defined in {@link
354             *         com.liferay.portal.util.PropsValues}
355             * @param  title the layout's title
356             * @param  description the layout's description
357             * @param  type the layout's type (optionally {@link
358             *         com.liferay.portal.model.LayoutConstants#TYPE_PORTLET}). The
359             *         possible types can be found in {@link
360             *         com.liferay.portal.model.LayoutConstants}.
361             * @param  hidden whether the layout is hidden
362             * @param  friendlyURL the friendly URL of the layout (optionally {@link
363             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PRIVATE_LAYOUT_FRIENDLY_URL}
364             *         or {@link
365             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PUBLIC_LAYOUT_FRIENDLY_URL}).
366             *         The default values can be overridden in
367             *         <code>portal-ext.properties</code> by specifying new values for
368             *         the corresponding properties defined in {@link
369             *         com.liferay.portal.util.PropsValues}. To see how the URL is
370             *         normalized when accessed see {@link
371             *         com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil#normalize(
372             *         String)}.
373             * @param  serviceContext the service context. Must set the universally
374             *         unique identifier (UUID) for the layout. Can set the creation
375             *         date and modification date for the layout. For layouts that
376             *         belong to a layout set prototype, an attribute named
377             *         'layoutUpdateable' can be set to specify whether site
378             *         administrators can modify this page within their site.
379             * @return the layout
380             * @throws PortalException if a group or user with the primary key could not
381             *         be found
382             * @throws SystemException if a system exception occurred
383             */
384            public Layout addLayout(
385                            long userId, long groupId, boolean privateLayout,
386                            long parentLayoutId, String name, String title, String description,
387                            String type, boolean hidden, String friendlyURL,
388                            ServiceContext serviceContext)
389                    throws PortalException, SystemException {
390    
391                    Map<Locale, String> localeNamesMap = new HashMap<Locale, String>();
392    
393                    Locale defaultLocale = LocaleUtil.getDefault();
394    
395                    localeNamesMap.put(defaultLocale, name);
396    
397                    return addLayout(
398                            userId, groupId, privateLayout, parentLayoutId, localeNamesMap,
399                            new HashMap<Locale, String>(), new HashMap<Locale, String>(),
400                            new HashMap<Locale, String>(), new HashMap<Locale, String>(), type,
401                            hidden, friendlyURL, serviceContext);
402            }
403    
404            /**
405             * Deletes the layout, its child layouts, and its associated resources.
406             *
407             * @param  layout the layout
408             * @param  updateLayoutSet whether the layout set's page counter needs to be
409             *         updated
410             * @param  serviceContext the service context
411             * @throws PortalException if a portal exception occurred
412             * @throws SystemException if a system exception occurred
413             */
414            public void deleteLayout(
415                            Layout layout, boolean updateLayoutSet,
416                            ServiceContext serviceContext)
417                    throws PortalException, SystemException {
418    
419                    // First layout validation
420    
421                    if (layout.getParentLayoutId() ==
422                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
423    
424                            List<Layout> rootLayouts = layoutPersistence.findByG_P_P(
425                                    layout.getGroupId(), layout.isPrivateLayout(),
426                                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
427    
428                            if (rootLayouts.size() > 1) {
429                                    Layout firstLayout = rootLayouts.get(0);
430    
431                                    if (firstLayout.getLayoutId() == layout.getLayoutId()) {
432                                            Layout secondLayout = rootLayouts.get(1);
433    
434                                            validateFirstLayout(secondLayout.getType());
435                                    }
436                            }
437                    }
438    
439                    // Child layouts
440    
441                    List<Layout> childLayouts = layoutPersistence.findByG_P_P(
442                            layout.getGroupId(), layout.isPrivateLayout(),
443                            layout.getLayoutId());
444    
445                    for (Layout childLayout : childLayouts) {
446                            deleteLayout(childLayout, updateLayoutSet, serviceContext);
447                    }
448    
449                    // Portlet preferences
450    
451                    portletPreferencesLocalService.deletePortletPreferences(
452                            PortletKeys.PREFS_OWNER_ID_DEFAULT,
453                            PortletKeys.PREFS_OWNER_TYPE_LAYOUT, layout.getPlid());
454    
455                    // Ratings
456    
457                    ratingsStatsLocalService.deleteStats(
458                            Layout.class.getName(), layout.getPlid());
459    
460                    // Message boards
461    
462                    mbMessageLocalService.deleteDiscussionMessages(
463                            Layout.class.getName(), layout.getPlid());
464    
465                    // Journal articles
466    
467                    journalArticleLocalService.deleteLayoutArticleReferences(
468                            layout.getGroupId(), layout.getUuid());
469    
470                    // Journal content searches
471    
472                    journalContentSearchLocalService.deleteLayoutContentSearches(
473                            layout.getGroupId(), layout.isPrivateLayout(),
474                            layout.getLayoutId());
475    
476                    // Expando
477    
478                    expandoValueLocalService.deleteValues(
479                            Layout.class.getName(), layout.getPlid());
480    
481                    // Icon
482    
483                    imageLocalService.deleteImage(layout.getIconImageId());
484    
485                    // Scope group
486    
487                    Group scopeGroup = layout.getScopeGroup();
488    
489                    if (scopeGroup != null) {
490                            groupLocalService.deleteGroup(scopeGroup.getGroupId());
491                    }
492    
493                    // Resources
494    
495                    String primKey =
496                            layout.getPlid() + PortletConstants.LAYOUT_SEPARATOR + "%";
497    
498                    if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
499                            List<ResourcePermission> resourcePermissions =
500                                    resourcePermissionFinder.findByC_P(
501                                            layout.getCompanyId(), primKey);
502    
503                            for (ResourcePermission resourcePermission : resourcePermissions) {
504                                    resourcePermissionLocalService.deleteResourcePermission(
505                                            resourcePermission);
506                            }
507                    }
508                    else {
509                            List<Resource> resources = resourceFinder.findByC_P(
510                                    layout.getCompanyId(), primKey);
511    
512                            for (Resource resource : resources) {
513                                    resourceLocalService.deleteResource(resource);
514                            }
515                    }
516    
517                    resourceLocalService.deleteResource(
518                            layout.getCompanyId(), Layout.class.getName(),
519                            ResourceConstants.SCOPE_INDIVIDUAL, layout.getPlid());
520    
521                    // Layout
522    
523                    layoutPersistence.remove(layout);
524    
525                    // Layout set
526    
527                    if (updateLayoutSet) {
528                            layoutSetLocalService.updatePageCount(
529                                    layout.getGroupId(), layout.isPrivateLayout());
530                    }
531            }
532    
533            /**
534             * Deletes the layout with the primary key, also deleting the layout's child
535             * layouts, and associated resources.
536             *
537             * @param  groupId the primary key of the group
538             * @param  privateLayout whether the layout is private to the group
539             * @param  layoutId the primary key of the layout
540             * @param  serviceContext the service context
541             * @throws PortalException if a matching layout could not be found , or if
542             *         some other portal exception occurred
543             * @throws SystemException if a system exception occurred
544             */
545            public void deleteLayout(
546                            long groupId, boolean privateLayout, long layoutId,
547                            ServiceContext serviceContext)
548                    throws PortalException, SystemException {
549    
550                    Layout layout = layoutPersistence.findByG_P_L(
551                            groupId, privateLayout, layoutId);
552    
553                    deleteLayout(layout, true, serviceContext);
554            }
555    
556            /**
557             * Deletes the layout with the plid, also deleting the layout's child
558             * layouts, and associated resources.
559             *
560             * @param  plid the primary key of the layout
561             * @param  serviceContext the service context
562             * @throws PortalException if a layout with the primary key could not be
563             *         found , or if some other portal exception occurred
564             * @throws SystemException if a system exception occurred
565             */
566            public void deleteLayout(long plid, ServiceContext serviceContext)
567                    throws PortalException, SystemException {
568    
569                    Layout layout = layoutPersistence.findByPrimaryKey(plid);
570    
571                    deleteLayout(layout, true, serviceContext);
572            }
573    
574            /**
575             * Deletes the group's private or non-private layouts, also deleting the
576             * layouts' child layouts, and associated resources.
577             *
578             * @param  groupId the primary key of the group
579             * @param  privateLayout whether the layout is private to the group
580             * @param  serviceContext the service context
581             * @throws PortalException if a group with the primary key could not be
582             *         found or if a layout set for the group and privacy could not be
583             *         found
584             * @throws SystemException if a system exception occurred
585             */
586            public void deleteLayouts(
587                            long groupId, boolean privateLayout, ServiceContext serviceContext)
588                    throws PortalException, SystemException {
589    
590                    // Layouts
591    
592                    List<Layout> layouts = layoutPersistence.findByG_P_P(
593                            groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
594    
595                    for (Layout layout : layouts) {
596                            try {
597                                    deleteLayout(layout, false, serviceContext);
598                            }
599                            catch (NoSuchLayoutException nsle) {
600                            }
601                    }
602    
603                    // Layout set
604    
605                    layoutSetLocalService.updatePageCount(groupId, privateLayout);
606    
607                    // Counter
608    
609                    counterLocalService.reset(getCounterName(groupId, privateLayout));
610            }
611    
612            /**
613             * Exports layouts with the primary keys and criteria as a byte array.
614             *
615             * @param  groupId the primary key of the group
616             * @param  privateLayout whether the layout is private to the group
617             * @param  layoutIds the primary keys of the layouts to be exported
618             * @param  parameterMap the mapping of parameters indicating which
619             *         information to export. For information on the keys used in the
620             *         map see {@link
621             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
622             * @param  startDate the export's start date
623             * @param  endDate the export's end date
624             * @return the layouts as a byte array
625             * @throws PortalException if a group or any layout with the primary key
626             *         could not be found, or if some other portal exception occurred
627             * @throws SystemException if a system exception occurred
628             */
629            public byte[] exportLayouts(
630                            long groupId, boolean privateLayout, long[] layoutIds,
631                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
632                    throws PortalException, SystemException {
633    
634                    File file = exportLayoutsAsFile(
635                            groupId, privateLayout, layoutIds, parameterMap, startDate,
636                            endDate);
637    
638                    try {
639                            return FileUtil.getBytes(file);
640                    }
641                    catch (IOException ioe) {
642                            throw new SystemException(ioe);
643                    }
644                    finally {
645                            file.delete();
646                    }
647            }
648    
649            /**
650             * Exports all layouts that match the criteria as a byte array.
651             *
652             * @param  groupId the primary key of the group
653             * @param  privateLayout whether the layout is private to the group
654             * @param  parameterMap the mapping of parameters indicating which
655             *         information to export. For information on the keys used in the
656             *         map see {@link
657             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
658             * @param  startDate the export's start date
659             * @param  endDate the export's end date
660             * @return the layout as a byte array
661             * @throws PortalException if a group with the primary key could not be
662             *         found or if some other portal exception occurred
663             * @throws SystemException if a system exception occurred
664             */
665            public byte[] exportLayouts(
666                            long groupId, boolean privateLayout,
667                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
668                    throws PortalException, SystemException {
669    
670                    return exportLayouts(
671                            groupId, privateLayout, null, parameterMap, startDate, endDate);
672            }
673    
674            /**
675             * Exports the layouts that match the primary keys and criteria as a file.
676             *
677             * @param  groupId the primary key of the group
678             * @param  privateLayout whether the layout is private to the group
679             * @param  layoutIds the primary keys of the layouts to be exported
680             *         (optionally <code>null</code>)
681             * @param  parameterMap the mapping of parameters indicating which
682             *         information to export. For information on the keys used in the
683             *         map see {@link
684             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
685             * @param  startDate the export's start date
686             * @param  endDate the export's end date
687             * @return the layouts as a File
688             * @throws PortalException if a group or any layout with the primary key
689             *         could not be found, or if some other portal exception occurred
690             * @throws SystemException if a system exception occurred
691             */
692            public File exportLayoutsAsFile(
693                            long groupId, boolean privateLayout, long[] layoutIds,
694                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
695                    throws PortalException, SystemException {
696    
697                    try {
698                            LayoutExporter layoutExporter = new LayoutExporter();
699    
700                            return layoutExporter.exportLayoutsAsFile(
701                                    groupId, privateLayout, layoutIds, parameterMap, startDate,
702                                    endDate);
703                    }
704                    catch (PortalException pe) {
705                            throw pe;
706                    }
707                    catch (SystemException se) {
708                            throw se;
709                    }
710                    catch (Exception e) {
711                            throw new SystemException(e);
712                    }
713            }
714    
715            /**
716             * Exports the portlet information (categories, permissions, ... etc.) as a
717             * byte array.
718             *
719             * @param  plid the primary key of the layout
720             * @param  groupId the primary key of the group
721             * @param  portletId the primary key of the portlet
722             * @param  parameterMap the mapping of parameters indicating which
723             *         information to export. For information on the keys used in the
724             *         map see {@link
725             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
726             * @param  startDate the export's start date
727             * @param  endDate the export's end date
728             * @return the portlet information as a byte array
729             * @throws PortalException if a group or portlet with the primary key could
730             *         not be found, or if some other portal exception occurred
731             * @throws SystemException if a system exception occurred
732             */
733            public byte[] exportPortletInfo(
734                            long plid, long groupId, String portletId,
735                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
736                    throws PortalException, SystemException {
737    
738                    File file = exportPortletInfoAsFile(
739                            plid, groupId, portletId, parameterMap, startDate, endDate);
740    
741                    try {
742                            return FileUtil.getBytes(file);
743                    }
744                    catch (IOException ioe) {
745                            throw new SystemException(ioe);
746                    }
747                    finally {
748                            file.delete();
749                    }
750            }
751    
752            /**
753             * Exports the portlet information (categories, permissions, ... etc.) as a
754             * file.
755             *
756             * @param  plid the primary key of the layout
757             * @param  groupId the primary key of the group
758             * @param  portletId the primary key of the portlet
759             * @param  parameterMap the mapping of parameters indicating which
760             *         information to export. For information on the keys used in the
761             *         map see {@link
762             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
763             * @param  startDate the export's start date
764             * @param  endDate the export's end date
765             * @return the portlet information as a file
766             * @throws PortalException if a group or portlet with the primary key could
767             *         not be found, or if some other portal exception occurred
768             * @throws SystemException if a system exception occurred
769             */
770            public File exportPortletInfoAsFile(
771                            long plid, long groupId, String portletId,
772                            Map<String, String[]> parameterMap, Date startDate, Date endDate)
773                    throws PortalException, SystemException {
774    
775                    try {
776                            PortletExporter portletExporter = new PortletExporter();
777    
778                            return portletExporter.exportPortletInfoAsFile(
779                                    plid, groupId, portletId, parameterMap, startDate, endDate);
780                    }
781                    catch (PortalException pe) {
782                            throw pe;
783                    }
784                    catch (SystemException se) {
785                            throw se;
786                    }
787                    catch (Exception e) {
788                            throw new SystemException(e);
789                    }
790            }
791    
792            public Layout fetchFirstLayout(
793                            long groupId, boolean privateLayout, long parentLayoutId)
794                    throws SystemException {
795    
796                    Layout firstLayout = null;
797    
798                    try {
799                            firstLayout = layoutPersistence.findByG_P_P_First(
800                                    groupId, privateLayout, parentLayoutId,
801                                    new LayoutPriorityComparator());
802                    }
803                    catch (NoSuchLayoutException nsle) {
804                    }
805    
806                    return firstLayout;
807            }
808    
809            /**
810             * Returns the layout matching the universally unique identifier and group
811             * ID
812             *
813             * @param  uuid the universally unique identifier of the scope layout
814             * @param  groupId the primary key of the group
815             * @return the layout, or <code>null</code> if a matching layout could not
816             *         be found
817             * @throws SystemException if a system exception occurred
818             */
819            public Layout fetchLayoutByUuidAndGroupId(String uuid, long groupId)
820                    throws SystemException {
821    
822                    return layoutPersistence.fetchByUUID_G(uuid, groupId);
823            }
824    
825            /**
826             * Returns the primary key of the default layout for the group
827             *
828             * @param  groupId the primary key of the group
829             * @return the primary key of the default layout for the group (optionally
830             *         {@link com.liferay.portal.model.LayoutConstants#DEFAULT_PLID})
831             * @throws SystemException if a system exception occurred
832             */
833            public long getDefaultPlid(long groupId) throws SystemException {
834                    if (groupId > 0) {
835                            List<Layout> layouts = layoutPersistence.findByGroupId(
836                                    groupId, 0, 1);
837    
838                            if (layouts.size() > 0) {
839                                    Layout layout = layouts.get(0);
840    
841                                    return layout.getPlid();
842                            }
843                    }
844    
845                    return LayoutConstants.DEFAULT_PLID;
846            }
847    
848            /**
849             * Returns primary key of the matching default layout for the group
850             *
851             * @param  groupId the primary key of the group
852             * @param  privateLayout whether the layout is private to the group
853             * @return the primary key of the default layout for the group; {@link
854             *         com.liferay.portal.model.LayoutConstants#DEFAULT_PLID}) otherwise
855             * @throws SystemException if a system exception occurred
856             */
857            public long getDefaultPlid(long groupId, boolean privateLayout)
858                    throws SystemException {
859    
860                    if (groupId > 0) {
861                            List<Layout> layouts = layoutPersistence.findByG_P(
862                                    groupId, privateLayout, 0, 1);
863    
864                            if (layouts.size() > 0) {
865                                    Layout layout = layouts.get(0);
866    
867                                    return layout.getPlid();
868                            }
869                    }
870    
871                    return LayoutConstants.DEFAULT_PLID;
872            }
873    
874            /**
875             * Returns primary key of the default portlet layout for the group
876             *
877             * @param  groupId the primary key of the group
878             * @param  privateLayout whether the layout is private to the group
879             * @param  portletId the primary key of the portlet
880             * @return the primary key of the default portlet layout for the group;
881             *         {@link com.liferay.portal.model.LayoutConstants#DEFAULT_PLID}
882             *         otherwise
883             * @throws PortalException if a portlet with the primary key could not be
884             *         found
885             * @throws SystemException if a system exception occurred
886             */
887            public long getDefaultPlid(
888                            long groupId, boolean privateLayout, String portletId)
889                    throws PortalException, SystemException {
890    
891                    if (groupId > 0) {
892                            List<Layout> layouts = layoutPersistence.findByG_P(
893                                    groupId, privateLayout);
894    
895                            for (Layout layout : layouts) {
896                                    if (layout.isTypePortlet()) {
897                                            LayoutTypePortlet layoutTypePortlet =
898                                                    (LayoutTypePortlet)layout.getLayoutType();
899    
900                                            if (layoutTypePortlet.hasPortletId(portletId)) {
901                                                    return layout.getPlid();
902                                            }
903                                    }
904                            }
905                    }
906    
907                    return LayoutConstants.DEFAULT_PLID;
908            }
909    
910            /**
911             * Returns the layout for the friendly URL
912             *
913             * @param  groupId the primary key of the group
914             * @param  privateLayout whether the layout is private to the group
915             * @param  friendlyURL the friendly URL of the layout
916             * @return the layout for the friendly URL
917             * @throws PortalException if the friendly URL is <code>null</code> or a
918             *         matching layout could not be found
919             * @throws SystemException if a system exception occurred
920             */
921            public Layout getFriendlyURLLayout(
922                            long groupId, boolean privateLayout, String friendlyURL)
923                    throws PortalException, SystemException {
924    
925                    if (Validator.isNull(friendlyURL)) {
926                            throw new NoSuchLayoutException();
927                    }
928    
929                    friendlyURL = getFriendlyURL(friendlyURL);
930    
931                    Layout layout = layoutPersistence.fetchByG_P_F(
932                            groupId, privateLayout, friendlyURL);
933    
934                    if ((layout == null) &&
935                            (friendlyURL.startsWith(StringPool.SLASH)) &&
936                            (Validator.isNumber(friendlyURL.substring(1)))) {
937    
938                            long layoutId = GetterUtil.getLong(friendlyURL.substring(1));
939    
940                            layout = layoutPersistence.fetchByG_P_L(
941                                    groupId, privateLayout, layoutId);
942                    }
943    
944                    if (layout == null) {
945                            throw new NoSuchLayoutException();
946                    }
947    
948                    return layout;
949            }
950    
951            /**
952             * Returns the layout matching the primary key; throws a {@link
953             * com.liferay.portal.NoSuchLayoutException} otherwise.
954             *
955             * @param  plid the primary key of the layout
956             * @return the matching layout
957             * @throws PortalException if a layout with the primary key could not be
958             *         found
959             * @throws SystemException if a system exception occurred
960             */
961            @Override
962            public Layout getLayout(long plid)
963                    throws PortalException, SystemException {
964    
965                    return layoutPersistence.findByPrimaryKey(plid);
966            }
967    
968            /**
969             * Returns the layout matching the primary key, group, and privacy; throws a
970             * {@link com.liferay.portal.NoSuchLayoutException} otherwise.
971             *
972             * @param  groupId the primary key of the group
973             * @param  privateLayout whether the layout is private to the group
974             * @param  layoutId the primary key of the layout
975             * @return the matching layout
976             * @throws PortalException if a matching layout could not be found
977             * @throws SystemException if a system exception occurred
978             */
979            public Layout getLayout(long groupId, boolean privateLayout, long layoutId)
980                    throws PortalException, SystemException {
981    
982                    return layoutPersistence.findByG_P_L(groupId, privateLayout, layoutId);
983            }
984    
985            /**
986             * Returns the layout for the icon image; throws a {@link
987             * com.liferay.portal.NoSuchLayoutException} otherwise.
988             *
989             * @param  iconImageId the primary key of the icon image
990             * @return Returns the layout for the icon image
991             * @throws PortalException if an icon image with the primary key could not
992             *         be found
993             * @throws SystemException if a system exception occurred
994             */
995            public Layout getLayoutByIconImageId(long iconImageId)
996                    throws PortalException, SystemException {
997    
998                    return layoutPersistence.findByIconImageId(iconImageId);
999            }
1000    
1001            /**
1002             * Returns the layout with the universally unique identifier and the group.
1003             *
1004             * @param  uuid the universally unique identifier of the layout
1005             * @param  groupId the primary key of the group
1006             * @return the layout with the universally unique identifier and the group
1007             * @throws PortalException if a group with the primary key could not be
1008             *         found
1009             * @throws SystemException if a system exception occurred
1010             */
1011            @Override
1012            public Layout getLayoutByUuidAndGroupId(String uuid, long groupId)
1013                    throws PortalException, SystemException {
1014    
1015                    return layoutPersistence.findByUUID_G(uuid, groupId);
1016            }
1017    
1018            /**
1019             * Returns all the layouts belonging to the group.
1020             *
1021             * @param  groupId the primary key of the group
1022             * @param  privateLayout whether the layout is private to the group
1023             * @return the matching layouts, or <code>null</code> if no matches were
1024             *         found
1025             * @throws SystemException if a system exception occurred
1026             */
1027            public List<Layout> getLayouts(long groupId, boolean privateLayout)
1028                    throws SystemException {
1029    
1030                    return layoutPersistence.findByG_P(groupId, privateLayout);
1031            }
1032    
1033            /**
1034             * Returns all the layouts belonging to the group that are children of the
1035             * parent layout.
1036             *
1037             * @param  groupId the primary key of the group
1038             * @param  privateLayout whether the layout is private to the group
1039             * @param  parentLayoutId the primary key of the parent layout
1040             * @return the matching layouts, or <code>null</code> if no matches were
1041             *         found
1042             * @throws SystemException if a system exception occurred
1043             */
1044            public List<Layout> getLayouts(
1045                            long groupId, boolean privateLayout, long parentLayoutId)
1046                    throws SystemException {
1047    
1048                    return layoutPersistence.findByG_P_P(
1049                            groupId, privateLayout, parentLayoutId);
1050            }
1051    
1052            /**
1053             * Returns a range of all the layouts belonging to the group that are
1054             * children of the parent layout.
1055             *
1056             * <p>
1057             * Useful when paginating results. Returns a maximum of <code>end -
1058             * start</code> instances. <code>start</code> and <code>end</code> are not
1059             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1060             * refers to the first result in the set. Setting both <code>start</code>
1061             * and <code>end</code> to {@link
1062             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
1063             * result set.
1064             * </p>
1065             *
1066             * @param  groupId the primary key of the group
1067             * @param  privateLayout whether the layout is private to the group
1068             * @param  parentLayoutId the primary key of the parent layout
1069             * @param  incomplete whether the layout is incomplete
1070             * @param  start the lower bound of the range of layouts
1071             * @param  end the upper bound of the range of layouts (not inclusive)
1072             * @return the matching layouts, or <code>null</code> if no matches were
1073             *         found
1074             * @throws SystemException if a system exception occurred
1075             */
1076            public List<Layout> getLayouts(
1077                            long groupId, boolean privateLayout, long parentLayoutId,
1078                            boolean incomplete, int start, int end)
1079                    throws SystemException {
1080    
1081                    return layoutPersistence.findByG_P_P(
1082                            groupId, privateLayout, parentLayoutId, start, end);
1083            }
1084    
1085            /**
1086             * Returns all the layouts that match the layout IDs and belong to the
1087             * group.
1088             *
1089             * @param  groupId the primary key of the group
1090             * @param  privateLayout whether the layout is private to the group
1091             * @param  layoutIds the primary keys of the layouts
1092             * @return the matching layouts, or <code>null</code> if no matches were
1093             *         found
1094             * @throws PortalException if a group or layout with the primary key could
1095             *         not be found
1096             * @throws SystemException if a system exception occurred
1097             */
1098            public List<Layout> getLayouts(
1099                            long groupId, boolean privateLayout, long[] layoutIds)
1100                    throws PortalException, SystemException {
1101    
1102                    List<Layout> layouts = new ArrayList<Layout>();
1103    
1104                    for (long layoutId : layoutIds) {
1105                            Layout layout = getLayout(groupId, privateLayout, layoutId);
1106    
1107                            layouts.add(layout);
1108                    }
1109    
1110                    return layouts;
1111            }
1112    
1113            /**
1114             * Returns all the layouts that match the type and belong to the group.
1115             *
1116             * @param  groupId the primary key of the group
1117             * @param  privateLayout whether the layout is private to the group
1118             * @param  type the type of the layouts (optionally {@link
1119             *         com.liferay.portal.model.LayoutConstants#TYPE_PORTLET})
1120             * @return the matching layouts, or <code>null</code> if no matches were
1121             *         found
1122             * @throws SystemException if a system exception occurred
1123             */
1124            public List<Layout> getLayouts(
1125                            long groupId, boolean privateLayout, String type)
1126                    throws SystemException {
1127    
1128                    return layoutPersistence.findByG_P_T(groupId, privateLayout, type);
1129            }
1130    
1131            /**
1132             * Returns the layout references for all the layouts that belong to the
1133             * company and belong to the portlet that matches the preferences.
1134             *
1135             * @param  companyId the primary key of the company
1136             * @param  portletId the primary key of the portlet
1137             * @param  preferencesKey the portlet's preference key
1138             * @param  preferencesValue the portlet's preference value
1139             * @return the layout references of the matching layouts
1140             * @throws SystemException if a system exception occurred
1141             */
1142            public LayoutReference[] getLayouts(
1143                            long companyId, String portletId, String preferencesKey,
1144                            String preferencesValue)
1145                    throws SystemException {
1146    
1147                    List<LayoutReference> layoutReferences = layoutFinder.findByC_P_P(
1148                            companyId, portletId, preferencesKey, preferencesValue);
1149    
1150                    return layoutReferences.toArray(
1151                            new LayoutReference[layoutReferences.size()]);
1152            }
1153    
1154            public int getLayoutsCount(Group group, boolean privateLayout)
1155                    throws PortalException, SystemException {
1156    
1157                    LayoutSet layoutSet = layoutSetPersistence.findByG_P(
1158                            group.getGroupId(), privateLayout);
1159    
1160                    int count = layoutSet.getPageCount();
1161    
1162                    if (group.isUser()) {
1163                            List<UserGroup> userGroups = userPersistence.getUserGroups(
1164                                    group.getClassPK());
1165    
1166                            if (!userGroups.isEmpty()) {
1167                                    long userGroupClassNameId =
1168                                            classNameLocalService.getClassNameId(UserGroup.class);
1169    
1170                                    for (UserGroup userGroup : userGroups) {
1171                                            Group userGroupGroup = groupPersistence.findByC_C_C(
1172                                                    group.getCompanyId(), userGroupClassNameId,
1173                                                    userGroup.getUserGroupId());
1174    
1175                                            layoutSet = layoutSetPersistence.findByG_P(
1176                                                    userGroupGroup.getGroupId(), privateLayout);
1177    
1178                                            count += layoutSet.getPageCount();
1179                                    }
1180                            }
1181                    }
1182    
1183                    return count;
1184            }
1185    
1186            public int getLayoutsCount(User user, boolean privateLayout)
1187                    throws PortalException, SystemException {
1188    
1189                    long classNameId = classNameLocalService.getClassNameId(User.class);
1190    
1191                    Group group = groupPersistence.findByC_C_C(
1192                            user.getCompanyId(), classNameId, user.getUserId());
1193    
1194                    return getLayoutsCount(group, privateLayout);
1195            }
1196    
1197            /**
1198             * Returns the primary key to use for the next layout.
1199             *
1200             * @param  groupId the primary key of the group
1201             * @param  privateLayout whether the layout is private to the group
1202             * @return the primary key to use for the next layout
1203             * @throws SystemException if a system exception occurred
1204             */
1205            public long getNextLayoutId(long groupId, boolean privateLayout)
1206                    throws SystemException {
1207    
1208                    long nextLayoutId = counterLocalService.increment(
1209                            getCounterName(groupId, privateLayout));
1210    
1211                    if (nextLayoutId == 1) {
1212                            List<Layout> layouts = layoutPersistence.findByG_P(
1213                                    groupId, privateLayout, 0, 1, new LayoutComparator());
1214    
1215                            if (!layouts.isEmpty()) {
1216                                    Layout layout = layouts.get(0);
1217    
1218                                    nextLayoutId = layout.getLayoutId() + 1;
1219    
1220                                    counterLocalService.reset(
1221                                            getCounterName(groupId, privateLayout), nextLayoutId);
1222                            }
1223                    }
1224    
1225                    return nextLayoutId;
1226            }
1227    
1228            /**
1229             * Returns all the layouts whose friendly URLs are <code>null</code>
1230             *
1231             * @return all the layouts whose friendly URLs are <code>null</code>
1232             * @throws SystemException if a system exception occurred
1233             */
1234            public List<Layout> getNullFriendlyURLLayouts() throws SystemException {
1235                    return layoutFinder.findByNullFriendlyURL();
1236            }
1237    
1238            /**
1239             * Returns all the layouts within scope of the group
1240             *
1241             * @param  groupId the primary key of the group
1242             * @param  privateLayout whether the layout is private to the group
1243             * @return the layouts within scope of the group
1244             * @throws SystemException if a system exception occurred
1245             */
1246            public List<Layout> getScopeGroupLayouts(
1247                            long groupId, boolean privateLayout)
1248                    throws SystemException {
1249    
1250                    return layoutFinder.findByScopeGroup(groupId, privateLayout);
1251            }
1252    
1253            public boolean hasLayouts(Group group, boolean privateLayout)
1254                    throws PortalException, SystemException {
1255    
1256                    LayoutSet layoutSet = layoutSetPersistence.findByG_P(
1257                            group.getGroupId(), privateLayout);
1258    
1259                    if (layoutSet.getPageCount() > 0) {
1260                            return true;
1261                    }
1262    
1263                    if (group.isUser()) {
1264                            List<UserGroup> userGroups = userPersistence.getUserGroups(
1265                                    group.getClassPK());
1266    
1267                            if (!userGroups.isEmpty()) {
1268                                    long userGroupClassNameId =
1269                                            classNameLocalService.getClassNameId(UserGroup.class);
1270    
1271                                    for (UserGroup userGroup : userGroups) {
1272                                            Group userGroupGroup = groupPersistence.findByC_C_C(
1273                                                    group.getCompanyId(), userGroupClassNameId,
1274                                                    userGroup.getUserGroupId());
1275    
1276                                            layoutSet = layoutSetPersistence.findByG_P(
1277                                                    userGroupGroup.getGroupId(), privateLayout);
1278    
1279                                            if (layoutSet.getPageCount() > 0) {
1280                                                    return true;
1281                                            }
1282                                    }
1283                            }
1284                    }
1285    
1286                    return false;
1287            }
1288    
1289            /**
1290             * Returns <code>true</code> if the group has any layouts;
1291             * <code>false</code> otherwise.
1292             *
1293             * @param  groupId the primary key of the group
1294             * @param  privateLayout whether the layout is private to the group
1295             * @param  parentLayoutId the primary key of the parent layout
1296             * @return <code>true</code> if the group has any layouts;
1297             *         <code>false</code> otherwise
1298             * @throws SystemException if a system exception occurred
1299             */
1300            public boolean hasLayouts(
1301                            long groupId, boolean privateLayout, long parentLayoutId)
1302                    throws SystemException {
1303    
1304                    return layoutPersistence.countByG_P_P(
1305                            groupId, privateLayout, parentLayoutId) > 0;
1306            }
1307    
1308            public boolean hasLayouts(User user, boolean privateLayout)
1309                    throws PortalException, SystemException {
1310    
1311                    long classNameId = classNameLocalService.getClassNameId(User.class);
1312    
1313                    Group group = groupPersistence.findByC_C_C(
1314                            user.getCompanyId(), classNameId, user.getUserId());
1315    
1316                    return hasLayouts(group, privateLayout);
1317            }
1318    
1319            /**
1320             * Imports the layouts from the byte array.
1321             *
1322             * @param  userId the primary key of the user
1323             * @param  groupId the primary key of the group
1324             * @param  privateLayout whether the layout is private to the group
1325             * @param  parameterMap the mapping of parameters indicating which
1326             *         information will be imported. For information on the keys used in
1327             *         the map see {@link
1328             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
1329             * @param  bytes the byte array with the data
1330             * @throws PortalException if a group or user with the primary key could not
1331             *         be found, or if some other portal exception occurred
1332             * @throws SystemException if a system exception occurred
1333             * @see    com.liferay.portal.lar.LayoutImporter
1334             */
1335            public void importLayouts(
1336                            long userId, long groupId, boolean privateLayout,
1337                            Map<String, String[]> parameterMap, byte[] bytes)
1338                    throws PortalException, SystemException {
1339    
1340                    importLayouts(
1341                            userId, groupId, privateLayout, parameterMap,
1342                            new UnsyncByteArrayInputStream(bytes));
1343            }
1344    
1345            /**
1346             * Imports the layouts from the file.
1347             *
1348             * @param  userId the primary key of the user
1349             * @param  groupId the primary key of the group
1350             * @param  privateLayout whether the layout is private to the group
1351             * @param  parameterMap the mapping of parameters indicating which
1352             *         information will be imported. For information on the keys used in
1353             *         the map see {@link
1354             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
1355             * @param  file the LAR file with the data
1356             * @throws PortalException if a group or user with the primary key could not
1357             *         be found, or if some other portal exception occurred
1358             * @throws SystemException if a system exception occurred
1359             * @see    com.liferay.portal.lar.LayoutImporter
1360             */
1361            public void importLayouts(
1362                            long userId, long groupId, boolean privateLayout,
1363                            Map<String, String[]> parameterMap, File file)
1364                    throws PortalException, SystemException {
1365    
1366                    try {
1367                            LayoutImporter layoutImporter = new LayoutImporter();
1368    
1369                            layoutImporter.importLayouts(
1370                                    userId, groupId, privateLayout, parameterMap, file);
1371                    }
1372                    catch (PortalException pe) {
1373                            throw pe;
1374                    }
1375                    catch (SystemException se) {
1376                            throw se;
1377                    }
1378                    catch (Exception e) {
1379                            throw new SystemException(e);
1380                    }
1381            }
1382    
1383            /**
1384             * Imports the layouts from the input stream.
1385             *
1386             * @param  userId the primary key of the user
1387             * @param  groupId the primary key of the group
1388             * @param  privateLayout whether the layout is private to the group
1389             * @param  parameterMap the mapping of parameters indicating which
1390             *         information will be imported. For information on the keys used in
1391             *         the map see {@link
1392             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
1393             * @param  is the input stream
1394             * @throws PortalException if a group or user with the primary key could not
1395             *         be found, or if some other portal exception occurred
1396             * @throws SystemException if a system exception occurred
1397             * @see    com.liferay.portal.lar.LayoutImporter
1398             */
1399            public void importLayouts(
1400                            long userId, long groupId, boolean privateLayout,
1401                            Map<String, String[]> parameterMap, InputStream is)
1402                    throws PortalException, SystemException {
1403    
1404                    try {
1405                            File file = FileUtil.createTempFile("lar");
1406    
1407                            FileUtil.write(file, is);
1408    
1409                            importLayouts(userId, groupId, privateLayout, parameterMap, file);
1410                    }
1411                    catch (IOException e) {
1412                            throw new SystemException(e);
1413                    }
1414            }
1415    
1416            /**
1417             * Imports the portlet information (categories, permissions, ... etc.) from
1418             * the file.
1419             *
1420             * @param  userId the primary key of the user
1421             * @param  plid the primary key of the target layout
1422             * @param  groupId the primary key of the target group
1423             * @param  portletId the primary key of the portlet
1424             * @param  parameterMap the mapping of parameters indicating which
1425             *         information will be imported. For information on the keys used in
1426             *         the map see {@link
1427             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
1428             * @param  file the LAR file with the data
1429             * @throws PortalException if a group, layout, portlet or user with the
1430             *         primary key could not be found
1431             * @throws SystemException if a system exception occurred
1432             */
1433            public void importPortletInfo(
1434                            long userId, long plid, long groupId, String portletId,
1435                            Map<String, String[]> parameterMap, File file)
1436                    throws PortalException, SystemException {
1437    
1438                    try {
1439                            PortletImporter portletImporter = new PortletImporter();
1440    
1441                            portletImporter.importPortletInfo(
1442                                    userId, plid, groupId, portletId, parameterMap, file);
1443                    }
1444                    catch (PortalException pe) {
1445                            throw pe;
1446                    }
1447                    catch (SystemException se) {
1448                            throw se;
1449                    }
1450                    catch (Exception e) {
1451                            throw new SystemException(e);
1452                    }
1453            }
1454    
1455            /**
1456             * Imports the portlet information (categories, permissions, ... etc.) from
1457             * the input stream.
1458             *
1459             * @param  userId the primary key of the user
1460             * @param  plid the primary key of the layout
1461             * @param  groupId the primary key of the group
1462             * @param  portletId the primary key of the portlet
1463             * @param  parameterMap the mapping of parameters indicating which
1464             *         information will be imported. For information on the keys used in
1465             *         the map see {@link
1466             *         com.liferay.portal.kernel.lar.PortletDataHandlerKeys}.
1467             * @param  is the input stream
1468             * @throws PortalException if a group, portlet, layout or user with the
1469             *         primary key could not be found
1470             * @throws SystemException if a system exception occurred
1471             */
1472            public void importPortletInfo(
1473                            long userId, long plid, long groupId, String portletId,
1474                            Map<String, String[]> parameterMap, InputStream is)
1475                    throws PortalException, SystemException {
1476    
1477                    try {
1478                            File file = FileUtil.createTempFile("lar");
1479    
1480                            FileUtil.write(file, is);
1481    
1482                            importPortletInfo(
1483                                    userId, plid, groupId, portletId, parameterMap, file);
1484                    }
1485                    catch (IOException e) {
1486                            throw new SystemException(e);
1487                    }
1488            }
1489    
1490            /**
1491             * Sets the layouts for the group, replacing and prioritizing all layouts of
1492             * the parent layout.
1493             *
1494             * @param  groupId the primary key of the group
1495             * @param  privateLayout whether the layout is private to the group
1496             * @param  parentLayoutId the primary key of the parent layout
1497             * @param  layoutIds the primary keys of the layouts
1498             * @param  serviceContext the service context
1499             * @throws PortalException if a group or layout with the primary key could
1500             *         not be found, if no layouts were specified, if the first layout
1501             *         was not page-able, if the first layout was hidden, or if some
1502             *         other portal exception occurred
1503             * @throws SystemException if a system exception occurred
1504             */
1505            public void setLayouts(
1506                            long groupId, boolean privateLayout, long parentLayoutId,
1507                            long[] layoutIds, ServiceContext serviceContext)
1508                    throws PortalException, SystemException {
1509    
1510                    if (layoutIds == null) {
1511                            return;
1512                    }
1513    
1514                    if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1515                            if (layoutIds.length < 1) {
1516                                    throw new RequiredLayoutException(
1517                                            RequiredLayoutException.AT_LEAST_ONE);
1518                            }
1519    
1520                            Layout layout = layoutPersistence.findByG_P_L(
1521                                    groupId, privateLayout, layoutIds[0]);
1522    
1523                            if (!PortalUtil.isLayoutFirstPageable(layout.getType())) {
1524                                    throw new RequiredLayoutException(
1525                                            RequiredLayoutException.FIRST_LAYOUT_TYPE);
1526                            }
1527    
1528                            if (layout.isHidden()) {
1529                                    throw new RequiredLayoutException(
1530                                            RequiredLayoutException.FIRST_LAYOUT_HIDDEN);
1531                            }
1532                    }
1533    
1534                    Set<Long> layoutIdsSet = new LinkedHashSet<Long>();
1535    
1536                    for (long layoutId : layoutIds) {
1537                            layoutIdsSet.add(layoutId);
1538                    }
1539    
1540                    Set<Long> newLayoutIdsSet = new HashSet<Long>();
1541    
1542                    List<Layout> layouts = layoutPersistence.findByG_P_P(
1543                            groupId, privateLayout, parentLayoutId);
1544    
1545                    for (Layout layout : layouts) {
1546                            if (!layoutIdsSet.contains(layout.getLayoutId())) {
1547                                    deleteLayout(layout, true, serviceContext);
1548                            }
1549                            else {
1550                                    newLayoutIdsSet.add(layout.getLayoutId());
1551                            }
1552                    }
1553    
1554                    int priority = 0;
1555    
1556                    for (long layoutId : layoutIdsSet) {
1557                            Layout layout = layoutPersistence.findByG_P_L(
1558                                    groupId, privateLayout, layoutId);
1559    
1560                            layout.setPriority(priority++);
1561    
1562                            layoutPersistence.update(layout, false);
1563                    }
1564    
1565                    layoutSetLocalService.updatePageCount(groupId, privateLayout);
1566            }
1567    
1568            /**
1569             * Updates the friendly URL of the layout.
1570             *
1571             * @param  plid the primary key of the layout
1572             * @param  friendlyURL the friendly URL to be assigned
1573             * @return the updated layout
1574             * @throws PortalException if a group or layout with the primary key could
1575             *         not be found
1576             * @throws SystemException if a system exception occurred
1577             */
1578            public Layout updateFriendlyURL(long plid, String friendlyURL)
1579                    throws PortalException, SystemException {
1580    
1581                    Date now = new Date();
1582    
1583                    Layout layout = layoutPersistence.findByPrimaryKey(plid);
1584    
1585                    friendlyURL = getFriendlyURL(
1586                            layout.getGroupId(), layout.isPrivateLayout(),
1587                            layout.getLayoutId(), StringPool.BLANK, friendlyURL);
1588    
1589                    validateFriendlyURL(
1590                            layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
1591                            friendlyURL);
1592    
1593                    layout.setModifiedDate(now);
1594                    layout.setFriendlyURL(friendlyURL);
1595    
1596                    layoutPersistence.update(layout, false);
1597    
1598                    return layout;
1599            }
1600    
1601            /**
1602             * Updates the layout.
1603             *
1604             * @param  groupId the primary key of the group
1605             * @param  privateLayout whether the layout is private to the group
1606             * @param  layoutId the primary key of the layout
1607             * @param  parentLayoutId the primary key of the layout's new parent layout
1608             * @param  nameMap the locales and localized names to merge (optionally
1609             *         <code>null</code>)
1610             * @param  titleMap the locales and localized titles to merge (optionally
1611             *         <code>null</code>)
1612             * @param  descriptionMap the locales and localized descriptions to merge
1613             *         (optionally <code>null</code>)
1614             * @param  keywordsMap the locales and localized keywords to merge
1615             *         (optionally <code>null</code>)
1616             * @param  robotsMap the locales and localized robots to merge (optionally
1617             *         <code>null</code>)
1618             * @param  type the layout's new type (optionally {@link
1619             *         com.liferay.portal.model.LayoutConstants#TYPE_PORTLET})
1620             * @param  hidden whether the layout is hidden
1621             * @param  friendlyURL the layout's new friendly URL (optionally {@link
1622             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PRIVATE_LAYOUT_FRIENDLY_URL}
1623             *         or {@link
1624             *         com.liferay.portal.util.PropsValues#DEFAULT_USER_PRIVATE_LAYOUT_FRIENDLY_URL}).
1625             *         The default values can be overridden in
1626             *         <code>portal-ext.properties</code> by specifying new values for
1627             *         the corresponding properties defined in {@link
1628             *         com.liferay.portal.util.PropsValues}. To see how the URL is
1629             *         normalized when accessed see {@link
1630             *         com.liferay.portal.kernel.util.FriendlyURLNormalizerUtil#normalize(
1631             *         String)}.
1632             * @param  iconImage whether the icon image will be updated
1633             * @param  iconBytes the byte array of the layout's new icon image
1634             * @param  serviceContext the service context. Can set the modification date
1635             *         and expando bridge attributes for the layout. For layouts that
1636             *         are linked to a layout prototype, attributes named
1637             *         'layoutPrototypeUuid' and 'layoutPrototypeLinkedEnabled' can be
1638             *         specified to provide the unique identifier of the source
1639             *         prototype and a boolean to determined whether a link to it should
1640             *         be enabled to activate propagation of changes made to the linked
1641             *         page in the prototype.
1642             * @return the updated layout
1643             * @throws PortalException if a group or layout with the primary key could
1644             *         not be found, if a unique friendly URL could not be generated, if
1645             *         a valid parent layout ID to use could not be found, or if the
1646             *         layout parameters were invalid
1647             * @throws SystemException if a system exception occurred
1648             */
1649            public Layout updateLayout(
1650                            long groupId, boolean privateLayout, long layoutId,
1651                            long parentLayoutId, Map<Locale, String> nameMap,
1652                            Map<Locale, String> titleMap, Map<Locale, String> descriptionMap,
1653                            Map<Locale, String> keywordsMap, Map<Locale, String> robotsMap,
1654                            String type, boolean hidden, String friendlyURL, Boolean iconImage,
1655                            byte[] iconBytes, ServiceContext serviceContext)
1656                    throws PortalException, SystemException {
1657    
1658                    // Layout
1659    
1660                    parentLayoutId = getParentLayoutId(
1661                            groupId, privateLayout, parentLayoutId);
1662                    String name = nameMap.get(LocaleUtil.getDefault());
1663                    friendlyURL = getFriendlyURL(
1664                            groupId, privateLayout, layoutId, StringPool.BLANK, friendlyURL);
1665    
1666                    validate(
1667                            groupId, privateLayout, layoutId, parentLayoutId, name, type,
1668                            hidden, friendlyURL);
1669    
1670                    validateParentLayoutId(
1671                            groupId, privateLayout, layoutId, parentLayoutId);
1672    
1673                    Date now = new Date();
1674    
1675                    Layout layout = layoutPersistence.findByG_P_L(
1676                            groupId, privateLayout, layoutId);
1677    
1678                    List<Locale> modifiedLocales = LocalizationUtil.getModifiedLocales(
1679                            layout.getNameMap(), nameMap);
1680    
1681                    if (parentLayoutId != layout.getParentLayoutId()) {
1682                            layout.setPriority(
1683                                    getNextPriority(groupId, privateLayout, parentLayoutId));
1684                    }
1685    
1686                    layout.setModifiedDate(serviceContext.getModifiedDate(now));
1687                    layout.setParentLayoutId(parentLayoutId);
1688                    layout.setNameMap(nameMap);
1689                    layout.setTitleMap(titleMap);
1690                    layout.setDescriptionMap(descriptionMap);
1691                    layout.setKeywordsMap(keywordsMap);
1692                    layout.setRobotsMap(robotsMap);
1693                    layout.setType(type);
1694                    layout.setHidden(hidden);
1695                    layout.setFriendlyURL(friendlyURL);
1696    
1697                    if (iconImage != null) {
1698                            layout.setIconImage(iconImage.booleanValue());
1699    
1700                            if (iconImage.booleanValue()) {
1701                                    long iconImageId = layout.getIconImageId();
1702    
1703                                    if (iconImageId <= 0) {
1704                                            iconImageId = counterLocalService.increment();
1705    
1706                                            layout.setIconImageId(iconImageId);
1707                                    }
1708                            }
1709                    }
1710    
1711                    boolean layoutUpdateable = GetterUtil.getBoolean(
1712                            serviceContext.getAttribute("layoutUpdateable"), true);
1713    
1714                    UnicodeProperties typeSettingsProperties =
1715                            layout.getTypeSettingsProperties();
1716    
1717                    typeSettingsProperties.put(
1718                            "layoutUpdateable", String.valueOf(layoutUpdateable));
1719    
1720                    layout.setTypeSettingsProperties(typeSettingsProperties);
1721    
1722                    String layoutPrototypeUuid = ParamUtil.getString(
1723                            serviceContext, "layoutPrototypeUuid");
1724                    boolean layoutPrototypeLinkEnabled = ParamUtil.getBoolean(
1725                            serviceContext, "layoutPrototypeLinkEnabled");
1726    
1727                    if (Validator.isNotNull(layoutPrototypeUuid)) {
1728                            layout.setLayoutPrototypeUuid(layoutPrototypeUuid);
1729                            layout.setLayoutPrototypeLinkEnabled(layoutPrototypeLinkEnabled);
1730    
1731                            LayoutPrototype layoutPrototype =
1732                                    layoutPrototypeLocalService.getLayoutPrototypeByUuid(
1733                                            layoutPrototypeUuid);
1734    
1735                            Layout layoutPrototypeLayout = layoutPrototype.getLayout();
1736    
1737                            layout.setSourcePrototypeLayoutUuid(
1738                                    layoutPrototypeLayout.getUuid());
1739                    }
1740    
1741                    layoutPersistence.update(layout, false);
1742    
1743                    // Icon
1744    
1745                    if (iconImage != null) {
1746                            if (!iconImage.booleanValue()) {
1747                                    imageLocalService.deleteImage(layout.getIconImageId());
1748                            }
1749                            else if ((iconBytes != null) && (iconBytes.length > 0)) {
1750                                    imageLocalService.updateImage(
1751                                            layout.getIconImageId(), iconBytes);
1752                            }
1753                    }
1754    
1755                    // Portlet preferences
1756    
1757                    if (!modifiedLocales.isEmpty()) {
1758                            updateScopedPortletNames(
1759                                    groupId, privateLayout, layoutId, nameMap, modifiedLocales);
1760                    }
1761    
1762                    // Expando
1763    
1764                    ExpandoBridge expandoBridge = layout.getExpandoBridge();
1765    
1766                    expandoBridge.setAttributes(serviceContext);
1767    
1768                    return layout;
1769            }
1770    
1771            /**
1772             * Updates the layout replacing its type settings.
1773             *
1774             * @param  groupId the primary key of the group
1775             * @param  privateLayout whether the layout is private to the group
1776             * @param  layoutId the primary key of the layout
1777             * @param  typeSettings the settings to load the unicode properties object.
1778             *         See {@link com.liferay.portal.kernel.util.UnicodeProperties
1779             *         #fastLoad(String)}.
1780             * @return the updated layout
1781             * @throws PortalException if a matching layout could not be found
1782             * @throws SystemException if a system exception occurred
1783             */
1784            public Layout updateLayout(
1785                            long groupId, boolean privateLayout, long layoutId,
1786                            String typeSettings)
1787                    throws PortalException, SystemException {
1788    
1789                    Date now = new Date();
1790    
1791                    UnicodeProperties typeSettingsProperties = new UnicodeProperties();
1792    
1793                    DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
1794                            PropsValues.INDEX_DATE_FORMAT_PATTERN);
1795    
1796                    typeSettingsProperties.fastLoad(typeSettings);
1797    
1798                    typeSettingsProperties.setProperty(
1799                            "modifiedDate", dateFormat.format(now));
1800    
1801                    Layout layout = layoutPersistence.findByG_P_L(
1802                            groupId, privateLayout, layoutId);
1803    
1804                    layout.setModifiedDate(now);
1805                    layout.setTypeSettings(typeSettingsProperties.toString());
1806    
1807                    layoutPersistence.update(layout, false);
1808    
1809                    return layout;
1810            }
1811    
1812            /**
1813             * Updates the look and feel of the layout.
1814             *
1815             * @param  groupId the primary key of the group
1816             * @param  privateLayout whether the layout is private to the group
1817             * @param  layoutId the primary key of the layout
1818             * @param  themeId the primary key of the layout's new theme
1819             * @param  colorSchemeId the primary key of the layout's new color scheme
1820             * @param  css the layout's new CSS
1821             * @param  wapTheme whether the theme is for WAP browsers
1822             * @return the updated layout
1823             * @throws PortalException if a matching layout could not be found
1824             * @throws SystemException if a system exception occurred
1825             */
1826            public Layout updateLookAndFeel(
1827                            long groupId, boolean privateLayout, long layoutId, String themeId,
1828                            String colorSchemeId, String css, boolean wapTheme)
1829                    throws PortalException, SystemException {
1830    
1831                    Date now = new Date();
1832    
1833                    Layout layout = layoutPersistence.findByG_P_L(
1834                            groupId, privateLayout, layoutId);
1835    
1836                    layout.setModifiedDate(now);
1837    
1838                    if (wapTheme) {
1839                            layout.setWapThemeId(themeId);
1840                            layout.setWapColorSchemeId(colorSchemeId);
1841                    }
1842                    else {
1843                            layout.setThemeId(themeId);
1844                            layout.setColorSchemeId(colorSchemeId);
1845                            layout.setCss(css);
1846                    }
1847    
1848                    layoutPersistence.update(layout, false);
1849    
1850                    return layout;
1851            }
1852    
1853            /**
1854             * Updates the name of the layout.
1855             *
1856             * @param  layout the layout to be updated
1857             * @param  name the layout's new name
1858             * @param  languageId the primary key of the language. For more information
1859             *         see {@link java.util.Locale}.
1860             * @return the updated layout
1861             * @throws PortalException if the new name was <code>null</code>
1862             * @throws SystemException if a system exception occurred
1863             */
1864            public Layout updateName(Layout layout, String name, String languageId)
1865                    throws PortalException, SystemException {
1866    
1867                    Date now = new Date();
1868    
1869                    validateName(name, languageId);
1870    
1871                    layout.setModifiedDate(now);
1872                    layout.setName(name, LocaleUtil.fromLanguageId(languageId));
1873    
1874                    layoutPersistence.update(layout, false);
1875    
1876                    return layout;
1877            }
1878    
1879            /**
1880             * Updates the name of the layout matching the group, layout ID, and
1881             * privacy.
1882             *
1883             * @param  groupId the primary key of the group
1884             * @param  privateLayout whether the layout is private to the group
1885             * @param  layoutId the primary key of the layout
1886             * @param  name the layout's new name
1887             * @param  languageId the primary key of the language. For more information
1888             *         see {@link java.util.Locale}.
1889             * @return the updated layout
1890             * @throws PortalException if a matching layout could not be found or if the
1891             *         new name was <code>null</code>
1892             * @throws SystemException if a system exception occurred
1893             */
1894            public Layout updateName(
1895                            long groupId, boolean privateLayout, long layoutId, String name,
1896                            String languageId)
1897                    throws PortalException, SystemException {
1898    
1899                    Layout layout = layoutPersistence.findByG_P_L(
1900                            groupId, privateLayout, layoutId);
1901    
1902                    return layoutLocalService.updateName(layout, name, languageId);
1903            }
1904    
1905            /**
1906             * Updates the name of the layout matching the primary key.
1907             *
1908             * @param  plid the primary key of the layout
1909             * @param  name the name to be assigned
1910             * @param  languageId the primary key of the language. For more information
1911             *         see {@link java.util.Locale}.
1912             * @return the updated layout
1913             * @throws PortalException if a layout with the primary key could not be
1914             *         found or if the name was <code>null</code>
1915             * @throws SystemException if a system exception occurred
1916             */
1917            public Layout updateName(long plid, String name, String languageId)
1918                    throws PortalException, SystemException {
1919    
1920                    Layout layout = layoutPersistence.findByPrimaryKey(plid);
1921    
1922                    return layoutLocalService.updateName(layout, name, languageId);
1923            }
1924    
1925            /**
1926             * Updates the parent layout ID of the layout matching the group, layout ID,
1927             * and privacy.
1928             *
1929             * @param  groupId the primary key of the group
1930             * @param  privateLayout whether the layout is private to the group
1931             * @param  layoutId the primary key of the layout
1932             * @param  parentLayoutId the primary key to be assigned to the parent
1933             *         layout
1934             * @return the matching layout
1935             * @throws PortalException if a valid parent layout ID to use could not be
1936             *         found or if a matching layout could not be found
1937             * @throws SystemException if a system exception occurred
1938             */
1939            public Layout updateParentLayoutId(
1940                            long groupId, boolean privateLayout, long layoutId,
1941                            long parentLayoutId)
1942                    throws PortalException, SystemException {
1943    
1944                    parentLayoutId = getParentLayoutId(
1945                            groupId, privateLayout, parentLayoutId);
1946    
1947                    validateParentLayoutId(
1948                            groupId, privateLayout, layoutId, parentLayoutId);
1949    
1950                    Date now = new Date();
1951    
1952                    Layout layout = layoutPersistence.findByG_P_L(
1953                            groupId, privateLayout, layoutId);
1954    
1955                    if (parentLayoutId != layout.getParentLayoutId()) {
1956                            layout.setPriority(
1957                                    getNextPriority(groupId, privateLayout, parentLayoutId));
1958                    }
1959    
1960                    layout.setModifiedDate(now);
1961                    layout.setParentLayoutId(parentLayoutId);
1962    
1963                    layoutPersistence.update(layout, false);
1964    
1965                    return layout;
1966            }
1967    
1968            /**
1969             * Updates the parent layout ID of the layout matching the primary key. If a
1970             * layout matching the parent primary key is found, the layout ID of that
1971             * layout is assigned, otherwise {@link
1972             * com.liferay.portal.model.LayoutConstants#DEFAULT_PARENT_LAYOUT_ID} is
1973             * assigned.
1974             *
1975             * @param  plid the primary key of the layout
1976             * @param  parentPlid the primary key of the parent layout
1977             * @return the layout matching the primary key
1978             * @throws PortalException if a layout with the primary key could not be
1979             *         found or if a valid parent layout ID to use could not be found
1980             * @throws SystemException if a system exception occurred
1981             */
1982            public Layout updateParentLayoutId(long plid, long parentPlid)
1983                    throws PortalException, SystemException {
1984    
1985                    Date now = new Date();
1986    
1987                    Layout layout = layoutPersistence.findByPrimaryKey(plid);
1988    
1989                    long parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
1990    
1991                    if (parentPlid > 0) {
1992                            Layout parentLayout = layoutPersistence.fetchByPrimaryKey(
1993                                    parentPlid);
1994    
1995                            if (parentLayout != null) {
1996                                    parentLayoutId = parentLayout.getLayoutId();
1997                            }
1998                    }
1999    
2000                    parentLayoutId = getParentLayoutId(
2001                            layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
2002    
2003                    validateParentLayoutId(
2004                            layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
2005                            parentLayoutId);
2006    
2007                    if (parentLayoutId != layout.getParentLayoutId()) {
2008                            int priority = getNextPriority(
2009                                    layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
2010    
2011                            layout.setPriority(priority);
2012                    }
2013    
2014                    layout.setModifiedDate(now);
2015                    layout.setParentLayoutId(parentLayoutId);
2016    
2017                    layoutPersistence.update(layout, false);
2018    
2019                    return layout;
2020            }
2021    
2022            /**
2023             * Updates the priority of the layout.
2024             *
2025             * @param  layout the layout to be updated
2026             * @param  priority the layout's new priority
2027             * @return the updated layout
2028             * @throws SystemException if a system exception occurred
2029             */
2030            public Layout updatePriority(Layout layout, int priority)
2031                    throws SystemException {
2032    
2033                    if (layout.getPriority() == priority) {
2034                            return layout;
2035                    }
2036    
2037                    Date now = new Date();
2038    
2039                    boolean lessThan = false;
2040    
2041                    if (layout.getPriority() < priority) {
2042                            lessThan = true;
2043                    }
2044    
2045                    layout.setModifiedDate(now);
2046                    layout.setPriority(priority);
2047    
2048                    layoutPersistence.update(layout, false);
2049    
2050                    priority = 0;
2051    
2052                    List<Layout> layouts = layoutPersistence.findByG_P_P(
2053                            layout.getGroupId(), layout.isPrivateLayout(),
2054                            layout.getParentLayoutId());
2055    
2056                    layouts = ListUtil.sort(
2057                            layouts, new LayoutPriorityComparator(layout, lessThan));
2058    
2059                    for (Layout curLayout : layouts) {
2060                            curLayout.setModifiedDate(now);
2061                            curLayout.setPriority(priority++);
2062    
2063                            layoutPersistence.update(curLayout, false);
2064    
2065                            if (curLayout.equals(layout)) {
2066                                    layout = curLayout;
2067                            }
2068                    }
2069    
2070                    return layout;
2071            }
2072    
2073            /**
2074             * Updates the priority of the layout matching the group, layout ID, and
2075             * privacy.
2076             *
2077             * @param  groupId the primary key of the group
2078             * @param  privateLayout whether the layout is private to the group
2079             * @param  layoutId the primary key of the layout
2080             * @param  priority the layout's new priority
2081             * @return the updated layout
2082             * @throws PortalException if a matching layout could not be found
2083             * @throws SystemException if a system exception occurred
2084             */
2085            public Layout updatePriority(
2086                            long groupId, boolean privateLayout, long layoutId, int priority)
2087                    throws PortalException, SystemException {
2088    
2089                    Layout layout = layoutPersistence.findByG_P_L(
2090                            groupId, privateLayout, layoutId);
2091    
2092                    return updatePriority(layout, priority);
2093            }
2094    
2095            /**
2096             * Updates the priority of the layout matching the primary key.
2097             *
2098             * @param  plid the primary key of the layout
2099             * @param  priority the layout's new priority
2100             * @return the updated layout
2101             * @throws PortalException if a layout with the primary key could not be
2102             *         found
2103             * @throws SystemException if a system exception occurred
2104             */
2105            public Layout updatePriority(long plid, int priority)
2106                    throws PortalException, SystemException {
2107    
2108                    Layout layout = layoutPersistence.findByPrimaryKey(plid);
2109    
2110                    return updatePriority(layout, priority);
2111            }
2112    
2113            public void updateScopedPortletNames(
2114                            long groupId, boolean privateLayout, long layoutId,
2115                            Map<Locale, String> nameMap, List<Locale> nameMapModifiedLocales)
2116                    throws PortalException, SystemException {
2117    
2118                    Layout layout = layoutPersistence.findByG_P_L(
2119                            groupId, privateLayout, layoutId);
2120    
2121                    DynamicQuery portletPreferencesDynamicQuery =
2122                            DynamicQueryFactoryUtil.forClass(
2123                                    PortletPreferences.class, PortletPreferencesImpl.TABLE_NAME);
2124    
2125                    Property plidProperty = PropertyFactoryUtil.forName("plid");
2126    
2127                    DynamicQuery layoutDynamicQuery = DynamicQueryFactoryUtil.forClass(
2128                            Layout.class, LayoutImpl.TABLE_NAME);
2129    
2130                    Projection plidProjection = ProjectionFactoryUtil.property("plid");
2131    
2132                    layoutDynamicQuery.setProjection(plidProjection);
2133    
2134                    Property groupIdProperty = PropertyFactoryUtil.forName("groupId");
2135    
2136                    layoutDynamicQuery.add(groupIdProperty.eq(groupId));
2137    
2138                    Property privateLayoutProperty = PropertyFactoryUtil.forName(
2139                            "privateLayout");
2140    
2141                    layoutDynamicQuery.add(privateLayoutProperty.eq(privateLayout));
2142    
2143                    portletPreferencesDynamicQuery.add(plidProperty.in(layoutDynamicQuery));
2144    
2145                    Junction junction = RestrictionsFactoryUtil.disjunction();
2146    
2147                    List<Portlet> scopablePortlets =
2148                            portletLocalService.getScopablePortlets();
2149    
2150                    for (Portlet scopablePortlet :scopablePortlets) {
2151                            if (scopablePortlet.isInstanceable()) {
2152                                    Criterion criterion = RestrictionsFactoryUtil.like(
2153                                            "portletId",
2154                                            scopablePortlet.getPortletId() +
2155                                                    PortletConstants.INSTANCE_SEPARATOR +
2156                                                            StringPool.PERCENT);
2157    
2158                                    junction.add(criterion);
2159                            }
2160                            else{
2161                                    Criterion criterion = RestrictionsFactoryUtil.eq(
2162                                            "portletId", scopablePortlet.getPortletId());
2163    
2164                                    junction.add(criterion);
2165                            }
2166                    }
2167    
2168                    portletPreferencesDynamicQuery.add(junction);
2169    
2170                    List<PortletPreferences> portletPreferencesList =
2171                            portletPreferencesLocalService.dynamicQuery(
2172                                    portletPreferencesDynamicQuery);
2173    
2174                    for (PortletPreferences portletPreferences : portletPreferencesList) {
2175                            if ((portletPreferences.getPortletId() == null)) {
2176                                    continue;
2177                            }
2178    
2179                            Layout curLayout = layoutPersistence.findByPrimaryKey(
2180                                    portletPreferences.getPlid());
2181    
2182                            javax.portlet.PortletPreferences jxPreferences =
2183                                    PortletPreferencesFactoryUtil.getLayoutPortletSetup(
2184                                            curLayout, portletPreferences.getPortletId());
2185    
2186                            String scopeLayoutUuid = GetterUtil.getString(
2187                                    jxPreferences.getValue("lfrScopeLayoutUuid", null));
2188    
2189                            if (!scopeLayoutUuid.equals(layout.getUuid())) {
2190                                    continue;
2191                            }
2192    
2193                            for (Locale locale : nameMapModifiedLocales) {
2194                                    String languageId = LanguageUtil.getLanguageId(locale);
2195    
2196                                    String portletTitle = PortalUtil.getPortletTitle(
2197                                            PortletConstants.getRootPortletId(
2198                                                    portletPreferences.getPortletId()), languageId);
2199    
2200                                    String newPortletTitle = PortalUtil.getNewPortletTitle(
2201                                            portletTitle, curLayout.getName(languageId),
2202                                            nameMap.get(locale));
2203    
2204                                    if (newPortletTitle.equals(portletTitle)) {
2205                                            continue;
2206                                    }
2207    
2208                                    try {
2209                                            jxPreferences.setValue(
2210                                                    "portletSetupTitle_" + languageId, newPortletTitle);
2211                                            jxPreferences.setValue(
2212                                                    "portletSetupUseCustomTitle", Boolean.TRUE.toString());
2213    
2214                                            jxPreferences.store();
2215                                    }
2216                                    catch (IOException ioe) {
2217                                            throw new SystemException(ioe);
2218                                    }
2219                                    catch (PortletException pe) {
2220                                            throw new SystemException(pe);
2221                                    }
2222                            }
2223                    }
2224            }
2225    
2226            /**
2227             * Updates the names of the portlets within scope of the group, the scope of
2228             * the layout's universally unique identifier, and the privacy.
2229             *
2230             * @param  groupId the primary key of the group
2231             * @param  privateLayout whether the layout is private to the group
2232             * @param  layoutId the primary key of the layout whose universally unique
2233             *         identifier to match
2234             * @param  name the new name for the portlets
2235             * @param  languageId the primary key of the language
2236             * @throws PortalException if a matching layout could not be found
2237             * @throws SystemException if a system exception occurred
2238             * @see    com.liferay.portlet.portletconfiguration.action.EditScopeAction
2239             */
2240            public void updateScopedPortletNames(
2241                            long groupId, boolean privateLayout, long layoutId, String name,
2242                            String languageId)
2243                    throws PortalException, SystemException {
2244    
2245                    Map<Locale, String> map = new HashMap<Locale, String>();
2246    
2247                    Locale locale = LocaleUtil.fromLanguageId(languageId);
2248    
2249                    map.put(locale, name);
2250    
2251                    List<Locale> locales = new ArrayList<Locale>();
2252    
2253                    locales.add(locale);
2254    
2255                    updateScopedPortletNames(
2256                            groupId, privateLayout, layoutId, map, locales);
2257            }
2258    
2259            protected String getFriendlyURL(
2260                            long groupId, boolean privateLayout, long layoutId,
2261                            String name, String friendlyURL)
2262                    throws PortalException, SystemException {
2263    
2264                    friendlyURL = getFriendlyURL(friendlyURL);
2265    
2266                    if (Validator.isNull(friendlyURL)) {
2267                            friendlyURL = StringPool.SLASH + getFriendlyURL(name);
2268    
2269                            String originalFriendlyURL = friendlyURL;
2270    
2271                            for (int i = 1;; i++) {
2272                                    try {
2273                                            validateFriendlyURL(
2274                                                    groupId, privateLayout, layoutId, friendlyURL);
2275    
2276                                            break;
2277                                    }
2278                                    catch (LayoutFriendlyURLException lfurle) {
2279                                            int type = lfurle.getType();
2280    
2281                                            if (type == LayoutFriendlyURLException.DUPLICATE) {
2282                                                    friendlyURL = originalFriendlyURL + i;
2283                                            }
2284                                            else {
2285                                                    friendlyURL = StringPool.SLASH + layoutId;
2286    
2287                                                    break;
2288                                            }
2289                                    }
2290                            }
2291                    }
2292    
2293                    return friendlyURL;
2294            }
2295    
2296            protected String getFriendlyURL(String friendlyURL) {
2297                    return FriendlyURLNormalizerUtil.normalize(friendlyURL);
2298            }
2299    
2300            protected int getNextPriority(
2301                            long groupId, boolean privateLayout, long parentLayoutId)
2302                    throws SystemException {
2303    
2304                    List<Layout> layouts = layoutPersistence.findByG_P_P(
2305                            groupId, privateLayout, parentLayoutId);
2306    
2307                    if (layouts.size() == 0) {
2308                            return 0;
2309                    }
2310    
2311                    Layout layout = layouts.get(layouts.size() - 1);
2312    
2313                    return layout.getPriority() + 1;
2314            }
2315    
2316            protected long getParentLayoutId(
2317                            long groupId, boolean privateLayout, long parentLayoutId)
2318                    throws SystemException {
2319    
2320                    if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
2321    
2322                            // Ensure parent layout exists
2323    
2324                            Layout parentLayout = layoutPersistence.fetchByG_P_L(
2325                                    groupId, privateLayout, parentLayoutId);
2326    
2327                            if (parentLayout == null) {
2328                                    parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
2329                            }
2330                    }
2331    
2332                    return parentLayoutId;
2333            }
2334    
2335            protected void validate(
2336                            long groupId, boolean privateLayout, long layoutId,
2337                            long parentLayoutId, String name, String type, boolean hidden,
2338                            String friendlyURL)
2339                    throws PortalException, SystemException {
2340    
2341                    validateName(name);
2342    
2343                    boolean firstLayout = false;
2344    
2345                    if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
2346                            List<Layout> layouts = layoutPersistence.findByG_P_P(
2347                                    groupId, privateLayout, parentLayoutId, 0, 1);
2348    
2349                            if (layouts.size() == 0) {
2350                                    firstLayout = true;
2351                            }
2352                            else {
2353                                    long firstLayoutId = layouts.get(0).getLayoutId();
2354    
2355                                    if (firstLayoutId == layoutId) {
2356                                            firstLayout = true;
2357                                    }
2358                            }
2359                    }
2360    
2361                    if (firstLayout) {
2362                            validateFirstLayout(type);
2363                    }
2364    
2365                    if (!PortalUtil.isLayoutParentable(type)) {
2366                            if (layoutPersistence.countByG_P_P(
2367                                            groupId, privateLayout, layoutId) > 0) {
2368    
2369                                    throw new LayoutTypeException(
2370                                            LayoutTypeException.NOT_PARENTABLE);
2371                            }
2372                    }
2373    
2374                    validateFriendlyURL(groupId, privateLayout, layoutId, friendlyURL);
2375            }
2376    
2377            protected void validateFirstLayout(String type)
2378                    throws PortalException {
2379    
2380                    if (Validator.isNull(type) || !PortalUtil.isLayoutFirstPageable(type)) {
2381                            LayoutTypeException lte = new LayoutTypeException(
2382                                    LayoutTypeException.FIRST_LAYOUT);
2383    
2384                            lte.setLayoutType(type);
2385    
2386                            throw lte;
2387                    }
2388            }
2389    
2390            protected void validateFriendlyURL(
2391                            long groupId, boolean privateLayout, long layoutId,
2392                            String friendlyURL)
2393                    throws PortalException, SystemException {
2394    
2395                    if (Validator.isNull(friendlyURL)) {
2396                            return;
2397                    }
2398    
2399                    int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
2400    
2401                    if (exceptionType != -1) {
2402                            throw new LayoutFriendlyURLException(exceptionType);
2403                    }
2404    
2405                    Layout layout = layoutPersistence.fetchByG_P_F(
2406                            groupId, privateLayout, friendlyURL);
2407    
2408                    if ((layout != null) && (layout.getLayoutId() != layoutId)) {
2409                            throw new LayoutFriendlyURLException(
2410                                    LayoutFriendlyURLException.DUPLICATE);
2411                    }
2412    
2413                    LayoutImpl.validateFriendlyURLKeyword(friendlyURL);
2414    
2415                    /*List<FriendlyURLMapper> friendlyURLMappers =
2416                            portletLocalService.getFriendlyURLMappers();
2417    
2418                    for (FriendlyURLMapper friendlyURLMapper : friendlyURLMappers) {
2419                            if (friendlyURL.indexOf(friendlyURLMapper.getMapping()) != -1) {
2420                                    LayoutFriendlyURLException lfurle =
2421                                            new LayoutFriendlyURLException(
2422                                                    LayoutFriendlyURLException.KEYWORD_CONFLICT);
2423    
2424                                    lfurle.setKeywordConflict(friendlyURLMapper.getMapping());
2425    
2426                                    throw lfurle;
2427                            }
2428                    }*/
2429    
2430                    String layoutIdFriendlyURL = friendlyURL.substring(1);
2431    
2432                    if (Validator.isNumber(layoutIdFriendlyURL) &&
2433                            !layoutIdFriendlyURL.equals(String.valueOf(layoutId))) {
2434    
2435                            LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
2436                                    LayoutFriendlyURLException.POSSIBLE_DUPLICATE);
2437    
2438                            lfurle.setKeywordConflict(layoutIdFriendlyURL);
2439    
2440                            throw lfurle;
2441                    }
2442            }
2443    
2444            protected void validateName(String name) throws PortalException {
2445                    if (Validator.isNull(name)) {
2446                            throw new LayoutNameException();
2447                    }
2448            }
2449    
2450            protected void validateName(String name, String languageId)
2451                    throws PortalException {
2452    
2453                    String defaultLanguageId = LocaleUtil.toLanguageId(
2454                            LocaleUtil.getDefault());
2455    
2456                    if (defaultLanguageId.equals(languageId)) {
2457                            validateName(name);
2458                    }
2459            }
2460    
2461            protected void validateParentLayoutId(
2462                            long groupId, boolean privateLayout, long layoutId,
2463                            long parentLayoutId)
2464                    throws PortalException, SystemException {
2465    
2466                    Layout layout = layoutPersistence.findByG_P_L(
2467                            groupId, privateLayout, layoutId);
2468    
2469                    if (parentLayoutId != layout.getParentLayoutId()) {
2470    
2471                            // Layouts can always be moved to the root level
2472    
2473                            if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
2474                                    return;
2475                            }
2476    
2477                            // Layout cannot become a child of a layout that is not parentable
2478    
2479                            Layout parentLayout = layoutPersistence.findByG_P_L(
2480                                    groupId, privateLayout, parentLayoutId);
2481    
2482                            if (!PortalUtil.isLayoutParentable(parentLayout)) {
2483                                    throw new LayoutParentLayoutIdException(
2484                                            LayoutParentLayoutIdException.NOT_PARENTABLE);
2485                            }
2486    
2487                            // Layout cannot become descendant of itself
2488    
2489                            if (PortalUtil.isLayoutDescendant(layout, parentLayoutId)) {
2490                                    throw new LayoutParentLayoutIdException(
2491                                            LayoutParentLayoutIdException.SELF_DESCENDANT);
2492                            }
2493    
2494                            // If layout is moved, the new first layout must be valid
2495    
2496                            if (layout.getParentLayoutId() ==
2497                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
2498    
2499                                    List<Layout> layouts = layoutPersistence.findByG_P_P(
2500                                            groupId, privateLayout,
2501                                            LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
2502    
2503                                    // You can only reach this point if there are more than two
2504                                    // layouts at the root level because of the descendant check
2505    
2506                                    long firstLayoutId = layouts.get(0).getLayoutId();
2507    
2508                                    if (firstLayoutId == layoutId) {
2509                                            Layout secondLayout = layouts.get(1);
2510    
2511                                            try {
2512                                                    validateFirstLayout(secondLayout.getType());
2513                                            }
2514                                            catch (LayoutHiddenException lhe) {
2515                                                    throw new LayoutParentLayoutIdException(
2516                                                            LayoutParentLayoutIdException.FIRST_LAYOUT_HIDDEN);
2517                                            }
2518                                            catch (LayoutTypeException lte) {
2519                                                    throw new LayoutParentLayoutIdException(
2520                                                            LayoutParentLayoutIdException.FIRST_LAYOUT_TYPE);
2521                                            }
2522                                    }
2523                            }
2524                    }
2525            }
2526    
2527    }