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