1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.service.impl;
16  
17  import com.liferay.portal.LayoutFriendlyURLException;
18  import com.liferay.portal.LayoutHiddenException;
19  import com.liferay.portal.LayoutNameException;
20  import com.liferay.portal.LayoutParentLayoutIdException;
21  import com.liferay.portal.LayoutTypeException;
22  import com.liferay.portal.NoSuchLayoutException;
23  import com.liferay.portal.RequiredLayoutException;
24  import com.liferay.portal.kernel.exception.PortalException;
25  import com.liferay.portal.kernel.exception.SystemException;
26  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
27  import com.liferay.portal.kernel.language.LanguageUtil;
28  import com.liferay.portal.kernel.log.Log;
29  import com.liferay.portal.kernel.log.LogFactoryUtil;
30  import com.liferay.portal.kernel.util.FileUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.ListUtil;
33  import com.liferay.portal.kernel.util.LocaleUtil;
34  import com.liferay.portal.kernel.util.StringBundler;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.Validator;
37  import com.liferay.portal.kernel.workflow.StatusConstants;
38  import com.liferay.portal.lar.LayoutExporter;
39  import com.liferay.portal.lar.LayoutImporter;
40  import com.liferay.portal.lar.PortletExporter;
41  import com.liferay.portal.lar.PortletImporter;
42  import com.liferay.portal.model.Group;
43  import com.liferay.portal.model.Layout;
44  import com.liferay.portal.model.LayoutConstants;
45  import com.liferay.portal.model.LayoutReference;
46  import com.liferay.portal.model.LayoutTypePortlet;
47  import com.liferay.portal.model.PortletConstants;
48  import com.liferay.portal.model.Resource;
49  import com.liferay.portal.model.ResourceConstants;
50  import com.liferay.portal.model.User;
51  import com.liferay.portal.model.impl.LayoutImpl;
52  import com.liferay.portal.service.ServiceContext;
53  import com.liferay.portal.service.base.LayoutLocalServiceBaseImpl;
54  import com.liferay.portal.service.persistence.BatchSessionUtil;
55  import com.liferay.portal.util.FriendlyURLNormalizer;
56  import com.liferay.portal.util.PortalUtil;
57  import com.liferay.portal.util.PortletKeys;
58  import com.liferay.portal.util.PropsValues;
59  import com.liferay.portal.util.comparator.LayoutComparator;
60  import com.liferay.portal.util.comparator.LayoutPriorityComparator;
61  import com.liferay.portlet.documentlibrary.DuplicateFolderNameException;
62  import com.liferay.portlet.documentlibrary.NoSuchFolderException;
63  import com.liferay.portlet.documentlibrary.model.DLFolder;
64  import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
65  import com.liferay.portlet.expando.model.ExpandoBridge;
66  
67  import java.io.File;
68  import java.io.IOException;
69  import java.io.InputStream;
70  
71  import java.util.ArrayList;
72  import java.util.Date;
73  import java.util.HashMap;
74  import java.util.HashSet;
75  import java.util.LinkedHashSet;
76  import java.util.List;
77  import java.util.Locale;
78  import java.util.Map;
79  import java.util.Set;
80  
81  /**
82   * <a href="LayoutLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
83   *
84   * @author Brian Wing Shun Chan
85   * @author Joel Kozikowski
86   * @author Charles May
87   * @author Raymond Augé
88   * @author Jorge Ferrer
89   * @author Bruno Farache
90   */
91  public class LayoutLocalServiceImpl extends LayoutLocalServiceBaseImpl {
92  
93      public static String getCounterName(long groupId, boolean privateLayout) {
94          StringBundler sb = new StringBundler();
95  
96          sb.append(Layout.class.getName());
97          sb.append(StringPool.POUND);
98          sb.append(groupId);
99          sb.append(StringPool.POUND);
100         sb.append(privateLayout);
101 
102         return sb.toString();
103     }
104 
105     public Layout addLayout(
106             long userId, long groupId, boolean privateLayout,
107             long parentLayoutId, Map<Locale, String> localeNamesMap,
108             Map<Locale, String> localeTitlesMap, String description,
109             String type, boolean hidden, String friendlyURL, long dlFolderId,
110             ServiceContext serviceContext)
111         throws PortalException, SystemException {
112 
113         // Layout
114 
115         User user = userPersistence.findByPrimaryKey(userId);
116         long layoutId = getNextLayoutId(groupId, privateLayout);
117         parentLayoutId = getParentLayoutId(
118             groupId, privateLayout, parentLayoutId);
119         String name = localeNamesMap.get(LocaleUtil.getDefault());
120         friendlyURL = getFriendlyURL(
121             groupId, privateLayout, layoutId, name, friendlyURL);
122         int priority = getNextPriority(groupId, privateLayout, parentLayoutId);
123 
124         validate(
125             groupId, privateLayout, layoutId, parentLayoutId, name, type,
126             hidden, friendlyURL);
127 
128         long plid = counterLocalService.increment();
129 
130         Layout layout = layoutPersistence.create(plid);
131 
132         layout.setGroupId(groupId);
133         layout.setCompanyId(user.getCompanyId());
134         layout.setPrivateLayout(privateLayout);
135         layout.setLayoutId(layoutId);
136         layout.setParentLayoutId(parentLayoutId);
137         layout.setDescription(description);
138         layout.setType(type);
139         layout.setHidden(hidden);
140         layout.setFriendlyURL(friendlyURL);
141         layout.setPriority(priority);
142         layout.setDlFolderId(dlFolderId);
143 
144         setLocalizedAttributes(layout, localeNamesMap, localeTitlesMap);
145 
146         if (type.equals(LayoutConstants.TYPE_PORTLET)) {
147             LayoutTypePortlet layoutTypePortlet =
148                 (LayoutTypePortlet)layout.getLayoutType();
149 
150             layoutTypePortlet.setLayoutTemplateId(
151                 0, PropsValues.LAYOUT_DEFAULT_TEMPLATE_ID, false);
152         }
153 
154         layoutPersistence.update(layout, false);
155 
156         // Resources
157 
158         resourceLocalService.addResources(
159             user.getCompanyId(), groupId, user.getUserId(),
160             Layout.class.getName(), layout.getPlid(), false, true, true);
161 
162         // Layout set
163 
164         layoutSetLocalService.updatePageCount(groupId, privateLayout);
165 
166         // Expando
167 
168         ExpandoBridge expandoBridge = layout.getExpandoBridge();
169 
170         expandoBridge.setAttributes(serviceContext);
171 
172         // Message boards
173 
174         if (PropsValues.LAYOUT_COMMENTS_ENABLED) {
175             mbMessageLocalService.addDiscussionMessage(
176                 userId, user.getFullName(), Layout.class.getName(), plid,
177                 StatusConstants.APPROVED);
178         }
179 
180         return layout;
181     }
182 
183     public Layout addLayout(
184             long userId, long groupId, boolean privateLayout,
185             long parentLayoutId, Map<Locale, String> localeNamesMap,
186             Map<Locale, String> localeTitlesMap, String description,
187             String type, boolean hidden, String friendlyURL,
188             ServiceContext serviceContext)
189         throws PortalException, SystemException {
190 
191         return addLayout(
192             userId, groupId, privateLayout, parentLayoutId, localeNamesMap,
193             localeTitlesMap, description, type, hidden, friendlyURL,
194             DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, serviceContext);
195     }
196 
197     public Layout addLayout(
198             long userId, long groupId, boolean privateLayout,
199             long parentLayoutId, String name, String title, String description,
200             String type, boolean hidden, String friendlyURL, long dlFolderId,
201             ServiceContext serviceContext)
202         throws PortalException, SystemException {
203 
204         Map<Locale, String> localeNamesMap = new HashMap<Locale, String>();
205 
206         Locale defaultLocale = LocaleUtil.getDefault();
207 
208         localeNamesMap.put(defaultLocale, name);
209 
210         return addLayout(
211             userId, groupId, privateLayout, parentLayoutId, localeNamesMap,
212             null, description, type, hidden, friendlyURL, dlFolderId,
213             serviceContext);
214     }
215 
216     public Layout addLayout(
217             long userId, long groupId, boolean privateLayout,
218             long parentLayoutId, String name, String title, String description,
219             String type, boolean hidden, String friendlyURL,
220             ServiceContext serviceContext)
221         throws PortalException, SystemException {
222 
223         Map<Locale, String> localeNamesMap = new HashMap<Locale, String>();
224 
225         Locale defaultLocale = LocaleUtil.getDefault();
226 
227         localeNamesMap.put(defaultLocale, name);
228 
229         return addLayout(
230             userId, groupId, privateLayout, parentLayoutId, localeNamesMap,
231             new HashMap<Locale, String>(), description, type, hidden,
232             friendlyURL, serviceContext);
233     }
234 
235     public void deleteLayout(Layout layout, boolean updateLayoutSet)
236         throws PortalException, SystemException {
237 
238         // Child layouts
239 
240         List<Layout> childLayouts = layoutPersistence.findByG_P_P(
241             layout.getGroupId(), layout.isPrivateLayout(),
242             layout.getLayoutId());
243 
244         for (Layout childLayout : childLayouts) {
245             deleteLayout(childLayout, updateLayoutSet);
246         }
247 
248         // Portlet preferences
249 
250         portletPreferencesLocalService.deletePortletPreferences(
251             PortletKeys.PREFS_OWNER_ID_DEFAULT,
252             PortletKeys.PREFS_OWNER_TYPE_LAYOUT, layout.getPlid());
253 
254         // Tasks
255 
256         tasksProposalLocalService.deleteProposal(
257             Layout.class.getName(), String.valueOf(layout.getPlid()));
258 
259         // Ratings
260 
261         ratingsStatsLocalService.deleteStats(
262             Layout.class.getName(), layout.getPlid());
263 
264         // Message boards
265 
266         mbMessageLocalService.deleteDiscussionMessages(
267             Layout.class.getName(), layout.getPlid());
268 
269         // Journal content searches
270 
271         journalContentSearchLocalService.deleteLayoutContentSearches(
272             layout.getGroupId(), layout.isPrivateLayout(),
273             layout.getLayoutId());
274 
275         // Expando
276 
277         expandoValueLocalService.deleteValues(
278             Layout.class.getName(), layout.getPlid());
279 
280         // Icon
281 
282         imageLocalService.deleteImage(layout.getIconImageId());
283 
284         // Scope group
285 
286         Group scopeGroup = layout.getScopeGroup();
287 
288         if (scopeGroup != null) {
289             groupLocalService.deleteGroup(scopeGroup.getGroupId());
290         }
291 
292         // Resources
293 
294         String primKey =
295             layout.getPlid() + PortletConstants.LAYOUT_SEPARATOR + "%";
296 
297         List<Resource> resources = resourceFinder.findByC_P(
298             layout.getCompanyId(), primKey);
299 
300         for (Resource resource : resources) {
301             resourceLocalService.deleteResource(resource);
302         }
303 
304         resourceLocalService.deleteResource(
305             layout.getCompanyId(), Layout.class.getName(),
306             ResourceConstants.SCOPE_INDIVIDUAL, layout.getPlid());
307 
308         // Layout
309 
310         layoutPersistence.remove(layout);
311 
312         // Layout set
313 
314         if (updateLayoutSet) {
315             layoutSetLocalService.updatePageCount(
316                 layout.getGroupId(), layout.isPrivateLayout());
317         }
318     }
319 
320     public void deleteLayout(long plid)
321         throws PortalException, SystemException {
322 
323         Layout layout = layoutPersistence.findByPrimaryKey(plid);
324 
325         deleteLayout(layout, true);
326     }
327 
328     public void deleteLayout(long groupId, boolean privateLayout, long layoutId)
329         throws PortalException, SystemException {
330 
331         Layout layout = layoutPersistence.findByG_P_L(
332             groupId, privateLayout, layoutId);
333 
334         deleteLayout(layout, true);
335     }
336 
337     public void deleteLayouts(long groupId, boolean privateLayout)
338         throws PortalException, SystemException {
339 
340         // Layouts
341 
342         List<Layout> layouts = layoutPersistence.findByG_P_P(
343             groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
344 
345         for (Layout layout : layouts) {
346             try {
347                 deleteLayout(layout, false);
348             }
349             catch (NoSuchLayoutException nsle) {
350             }
351         }
352 
353         // Layout set
354 
355         layoutSetLocalService.updatePageCount(groupId, privateLayout);
356 
357         // Counter
358 
359         counterLocalService.reset(getCounterName(groupId, privateLayout));
360     }
361 
362     public byte[] exportLayouts(
363             long groupId, boolean privateLayout, long[] layoutIds,
364             Map<String, String[]> parameterMap, Date startDate, Date endDate)
365         throws PortalException, SystemException {
366 
367         File file = exportLayoutsAsFile(
368             groupId, privateLayout, layoutIds, parameterMap, startDate,
369             endDate);
370 
371         try {
372             return FileUtil.getBytes(file);
373         }
374         catch (IOException ioe) {
375             throw new SystemException(ioe);
376         }
377         finally {
378             file.delete();
379         }
380     }
381 
382     public byte[] exportLayouts(
383             long groupId, boolean privateLayout,
384             Map<String, String[]> parameterMap, Date startDate, Date endDate)
385         throws PortalException, SystemException {
386 
387         return exportLayouts(
388             groupId, privateLayout, null, parameterMap, startDate, endDate);
389     }
390 
391     public File exportLayoutsAsFile(
392             long groupId, boolean privateLayout, long[] layoutIds,
393             Map<String, String[]> parameterMap, Date startDate, Date endDate)
394         throws PortalException, SystemException {
395 
396         LayoutExporter layoutExporter = new LayoutExporter();
397 
398         return layoutExporter.exportLayoutsAsFile(
399             groupId, privateLayout, layoutIds, parameterMap, startDate,
400             endDate);
401     }
402 
403     public byte[] exportPortletInfo(
404             long plid, long groupId, String portletId,
405             Map<String, String[]> parameterMap, Date startDate, Date endDate)
406         throws PortalException, SystemException {
407 
408         File file = exportPortletInfoAsFile(
409             plid, groupId, portletId, parameterMap, startDate, endDate);
410 
411         try {
412             return FileUtil.getBytes(file);
413         }
414         catch (IOException ioe) {
415             throw new SystemException(ioe);
416         }
417         finally {
418             file.delete();
419         }
420     }
421 
422     public File exportPortletInfoAsFile(
423             long plid, long groupId, String portletId,
424             Map<String, String[]> parameterMap, Date startDate, Date endDate)
425         throws PortalException, SystemException {
426 
427         PortletExporter portletExporter = new PortletExporter();
428 
429         return portletExporter.exportPortletInfoAsFile(
430             plid, groupId, portletId, parameterMap, startDate, endDate);
431     }
432 
433     public long getDefaultPlid(long groupId) throws SystemException {
434         if (groupId > 0) {
435             List<Layout> layouts = layoutPersistence.findByGroupId(
436                 groupId, 0, 1);
437 
438             if (layouts.size() > 0) {
439                 Layout layout = layouts.get(0);
440 
441                 return layout.getPlid();
442             }
443         }
444 
445         return LayoutConstants.DEFAULT_PLID;
446     }
447 
448     public long getDefaultPlid(long groupId, boolean privateLayout)
449         throws SystemException {
450 
451         if (groupId > 0) {
452             List<Layout> layouts = layoutPersistence.findByG_P(
453                 groupId, privateLayout, 0, 1);
454 
455             if (layouts.size() > 0) {
456                 Layout layout = layouts.get(0);
457 
458                 return layout.getPlid();
459             }
460         }
461 
462         return LayoutConstants.DEFAULT_PLID;
463     }
464 
465     public long getDefaultPlid(
466             long groupId, boolean privateLayout, String portletId)
467         throws SystemException {
468 
469         if (groupId > 0) {
470             List<Layout> layouts = layoutPersistence.findByG_P(
471                 groupId, privateLayout);
472 
473             for (Layout layout : layouts) {
474                 if (layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
475                     LayoutTypePortlet layoutTypePortlet =
476                         (LayoutTypePortlet)layout.getLayoutType();
477 
478                     if (layoutTypePortlet.hasPortletId(portletId)) {
479                         return layout.getPlid();
480                     }
481                 }
482             }
483         }
484 
485         return LayoutConstants.DEFAULT_PLID;
486     }
487 
488     public Layout getDLFolderLayout(long dlFolderId)
489         throws PortalException, SystemException {
490 
491         return layoutPersistence.findByDLFolderId(dlFolderId);
492     }
493 
494     public Layout getFriendlyURLLayout(
495             long groupId, boolean privateLayout, String friendlyURL)
496         throws PortalException, SystemException {
497 
498         if (Validator.isNull(friendlyURL)) {
499             throw new NoSuchLayoutException();
500         }
501 
502         friendlyURL = getFriendlyURL(friendlyURL);
503 
504         Layout layout = layoutPersistence.fetchByG_P_F(
505             groupId, privateLayout, friendlyURL);
506 
507         if ((layout == null) &&
508             (friendlyURL.startsWith(StringPool.SLASH))) {
509 
510             long layoutId = GetterUtil.getLong(friendlyURL.substring(1));
511 
512             layout = layoutPersistence.fetchByG_P_L(
513                 groupId, privateLayout, layoutId);
514         }
515 
516         if (layout == null) {
517             throw new NoSuchLayoutException();
518         }
519 
520         return layout;
521     }
522 
523     public Layout getLayout(long plid)
524         throws PortalException, SystemException {
525 
526         return layoutPersistence.findByPrimaryKey(plid);
527     }
528 
529     public Layout getLayout(long groupId, boolean privateLayout, long layoutId)
530         throws PortalException, SystemException {
531 
532         return layoutPersistence.findByG_P_L(groupId, privateLayout, layoutId);
533     }
534 
535     public Layout getLayoutByIconImageId(long iconImageId)
536         throws PortalException, SystemException {
537 
538         return layoutPersistence.findByIconImageId(iconImageId);
539     }
540 
541     public List<Layout> getLayouts(long groupId, boolean privateLayout)
542         throws SystemException {
543 
544         return layoutPersistence.findByG_P(groupId, privateLayout);
545     }
546 
547     public List<Layout> getLayouts(
548             long groupId, boolean privateLayout, long parentLayoutId)
549         throws SystemException {
550 
551         return layoutPersistence.findByG_P_P(
552             groupId, privateLayout, parentLayoutId);
553     }
554 
555     public List<Layout> getLayouts(
556             long groupId, boolean privateLayout, long parentLayoutId, int start,
557             int end)
558         throws SystemException {
559 
560         return layoutPersistence.findByG_P_P(
561             groupId, privateLayout, parentLayoutId, start, end);
562     }
563 
564     public List<Layout> getLayouts(
565             long groupId, boolean privateLayout, long[] layoutIds)
566         throws PortalException, SystemException {
567 
568         List<Layout> layouts = new ArrayList<Layout>();
569 
570         for (long layoutId : layoutIds) {
571             Layout layout = getLayout(groupId, privateLayout, layoutId);
572 
573             layouts.add(layout);
574         }
575 
576         return layouts;
577     }
578 
579     public List<Layout> getLayouts(
580             long groupId, boolean privateLayout, String type)
581         throws SystemException {
582 
583         return layoutPersistence.findByG_P_T(groupId, privateLayout, type);
584     }
585 
586     public LayoutReference[] getLayouts(
587             long companyId, String portletId, String preferencesKey,
588             String preferencesValue)
589         throws SystemException {
590 
591         List<LayoutReference> layoutReferences = layoutFinder.findByC_P_P(
592             companyId, portletId, preferencesKey, preferencesValue);
593 
594         return layoutReferences.toArray(
595             new LayoutReference[layoutReferences.size()]);
596     }
597 
598     public long getNextLayoutId(long groupId, boolean privateLayout)
599         throws SystemException {
600 
601         long nextLayoutId = counterLocalService.increment(
602             getCounterName(groupId, privateLayout));
603 
604         if (nextLayoutId == 1) {
605             List<Layout> layouts = layoutPersistence.findByG_P(
606                 groupId, privateLayout, 0, 1, new LayoutComparator());
607 
608             if (!layouts.isEmpty()) {
609                 Layout layout = layouts.get(0);
610 
611                 nextLayoutId = layout.getLayoutId() + 1;
612 
613                 counterLocalService.reset(
614                     getCounterName(groupId, privateLayout),
615                     layout.getLayoutId());
616             }
617         }
618 
619         return nextLayoutId;
620     }
621 
622     public List<Layout> getNullFriendlyURLLayouts() throws SystemException {
623         return layoutFinder.findByNullFriendlyURL();
624     }
625 
626     public boolean hasLayouts(
627             long groupId, boolean privateLayout, long parentLayoutId)
628         throws SystemException {
629 
630         return layoutPersistence.countByG_P_P(
631             groupId, privateLayout, parentLayoutId) > 0;
632     }
633 
634     public void importLayouts(
635             long userId, long groupId, boolean privateLayout,
636             Map<String, String[]> parameterMap, byte[] bytes)
637         throws PortalException, SystemException {
638 
639         importLayouts(
640             userId, groupId, privateLayout, parameterMap,
641             new UnsyncByteArrayInputStream(bytes));
642     }
643 
644     public void importLayouts(
645             long userId, long groupId, boolean privateLayout,
646             Map<String, String[]> parameterMap, File file)
647         throws PortalException, SystemException {
648 
649         BatchSessionUtil.setEnabled(true);
650 
651         try {
652             LayoutImporter layoutImporter = new LayoutImporter();
653 
654             layoutImporter.importLayouts(
655                 userId, groupId, privateLayout, parameterMap, file);
656         }
657         finally {
658             BatchSessionUtil.setEnabled(false);
659         }
660     }
661 
662     public void importLayouts(
663             long userId, long groupId, boolean privateLayout,
664             Map<String, String[]> parameterMap, InputStream is)
665         throws PortalException, SystemException {
666 
667         try {
668             File file = FileUtil.createTempFile("lar");
669 
670             FileUtil.write(file, is);
671 
672             importLayouts(userId, groupId, privateLayout, parameterMap, file);
673         }
674         catch (IOException e) {
675             throw new SystemException(e);
676         }
677     }
678 
679     public void importPortletInfo(
680             long userId, long plid, long groupId, String portletId,
681             Map<String, String[]> parameterMap, File file)
682         throws PortalException, SystemException {
683 
684         BatchSessionUtil.setEnabled(true);
685 
686         try {
687             PortletImporter portletImporter = new PortletImporter();
688 
689             portletImporter.importPortletInfo(
690                 userId, plid, groupId, portletId, parameterMap, file);
691         }
692         finally {
693             BatchSessionUtil.setEnabled(false);
694         }
695     }
696 
697     public void importPortletInfo(
698             long userId, long plid, long groupId, String portletId,
699             Map<String, String[]> parameterMap, InputStream is)
700         throws PortalException, SystemException {
701 
702         try {
703             File file = FileUtil.createTempFile("lar");
704 
705             FileUtil.write(file, is);
706 
707             importPortletInfo(
708                 userId, plid, groupId, portletId, parameterMap, file);
709         }
710         catch (IOException e) {
711             throw new SystemException(e);
712         }
713     }
714 
715     public void setLayouts(
716             long groupId, boolean privateLayout, long parentLayoutId,
717             long[] layoutIds)
718         throws PortalException, SystemException {
719 
720         if (layoutIds == null) {
721             return;
722         }
723 
724         if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
725             if (layoutIds.length < 1) {
726                 throw new RequiredLayoutException(
727                     RequiredLayoutException.AT_LEAST_ONE);
728             }
729 
730             Layout layout = layoutPersistence.findByG_P_L(
731                 groupId, privateLayout, layoutIds[0]);
732 
733             if (!PortalUtil.isLayoutFirstPageable(layout.getType())) {
734                 throw new RequiredLayoutException(
735                     RequiredLayoutException.FIRST_LAYOUT_TYPE);
736             }
737 
738             if (layout.isHidden()) {
739                 throw new RequiredLayoutException(
740                     RequiredLayoutException.FIRST_LAYOUT_HIDDEN);
741             }
742         }
743 
744         Set<Long> layoutIdsSet = new LinkedHashSet<Long>();
745 
746         for (int i = 0; i < layoutIds.length; i++) {
747             layoutIdsSet.add(layoutIds[i]);
748         }
749 
750         Set<Long> newLayoutIdsSet = new HashSet<Long>();
751 
752         List<Layout> layouts = layoutPersistence.findByG_P_P(
753             groupId, privateLayout, parentLayoutId);
754 
755         for (Layout layout : layouts) {
756             if (!layoutIdsSet.contains(layout.getLayoutId())) {
757                 deleteLayout(layout, true);
758             }
759             else {
760                 newLayoutIdsSet.add(layout.getLayoutId());
761             }
762         }
763 
764         int priority = 0;
765 
766         for (long layoutId : layoutIdsSet) {
767             Layout layout = layoutPersistence.findByG_P_L(
768                 groupId, privateLayout, layoutId);
769 
770             layout.setPriority(priority++);
771 
772             layoutPersistence.update(layout, false);
773         }
774 
775         layoutSetLocalService.updatePageCount(groupId, privateLayout);
776     }
777 
778     public Layout updateFriendlyURL(long plid, String friendlyURL)
779         throws PortalException, SystemException {
780 
781         Layout layout = layoutPersistence.findByPrimaryKey(plid);
782 
783         friendlyURL = getFriendlyURL(
784             layout.getGroupId(), layout.getPrivateLayout(),
785             layout.getLayoutId(), StringPool.BLANK, friendlyURL);
786 
787         validateFriendlyURL(
788             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
789             friendlyURL);
790 
791         layout.setFriendlyURL(friendlyURL);
792 
793         layoutPersistence.update(layout, false);
794 
795         return layout;
796     }
797 
798     public Layout updateLayout(
799             long groupId, boolean privateLayout, long layoutId,
800             long parentLayoutId, Map<Locale, String> localeNamesMap,
801             Map<Locale, String> localeTitlesMap, String description,
802             String type, boolean hidden, String friendlyURL, Boolean iconImage,
803             byte[] iconBytes, ServiceContext serviceContext)
804         throws PortalException, SystemException {
805 
806         // Layout
807 
808         parentLayoutId = getParentLayoutId(
809             groupId, privateLayout, parentLayoutId);
810         String name = localeNamesMap.get(LocaleUtil.getDefault());
811         friendlyURL = getFriendlyURL(
812             groupId, privateLayout, layoutId, StringPool.BLANK, friendlyURL);
813 
814         validate(
815             groupId, privateLayout, layoutId, parentLayoutId, name, type,
816             hidden, friendlyURL);
817 
818         validateParentLayoutId(
819             groupId, privateLayout, layoutId, parentLayoutId);
820 
821         Layout layout = layoutPersistence.findByG_P_L(
822             groupId, privateLayout, layoutId);
823 
824         if (parentLayoutId != layout.getParentLayoutId()) {
825             layout.setPriority(
826                 getNextPriority(groupId, privateLayout, parentLayoutId));
827         }
828 
829         layout.setParentLayoutId(parentLayoutId);
830         layout.setDescription(description);
831         layout.setType(type);
832         layout.setHidden(hidden);
833         layout.setFriendlyURL(friendlyURL);
834 
835         setLocalizedAttributes(layout, localeNamesMap, localeTitlesMap);
836 
837         if (iconImage != null) {
838             layout.setIconImage(iconImage.booleanValue());
839 
840             if (iconImage.booleanValue()) {
841                 long iconImageId = layout.getIconImageId();
842 
843                 if (iconImageId <= 0) {
844                     iconImageId = counterLocalService.increment();
845 
846                     layout.setIconImageId(iconImageId);
847                 }
848             }
849         }
850 
851         layoutPersistence.update(layout, false);
852 
853         // Icon
854 
855         if (iconImage != null) {
856             if (!iconImage.booleanValue()) {
857                 imageLocalService.deleteImage(layout.getIconImageId());
858             }
859             else if ((iconBytes != null) && (iconBytes.length > 0)) {
860                 imageLocalService.updateImage(
861                     layout.getIconImageId(), iconBytes);
862             }
863         }
864 
865         // Document library
866 
867         try {
868             if (layout.getDlFolderId() > 0) {
869                 DLFolder folder = dlFolderLocalService.getFolder(
870                     layout.getDlFolderId());
871 
872                 if (!name.equals(folder.getName())) {
873                     dlFolderLocalService.updateFolder(
874                         folder.getFolderId(), folder.getParentFolderId(), name,
875                         folder.getDescription(), new ServiceContext());
876                 }
877             }
878         }
879         catch (DuplicateFolderNameException dfne) {
880             if (_log.isDebugEnabled()) {
881                 _log.debug(dfne);
882             }
883         }
884         catch (NoSuchFolderException nsfe) {
885         }
886 
887         // Expando
888 
889         ExpandoBridge expandoBridge = layout.getExpandoBridge();
890 
891         expandoBridge.setAttributes(serviceContext);
892 
893         return layout;
894     }
895 
896     public Layout updateLayout(
897             long groupId, boolean privateLayout, long layoutId,
898             long parentLayoutId, Map<Locale, String> localeNamesMap,
899             Map<Locale, String> localeTitlesMap, String description,
900             String type, boolean hidden, String friendlyURL,
901             ServiceContext serviceContext)
902         throws PortalException, SystemException {
903 
904         return updateLayout(
905             groupId, privateLayout, layoutId, parentLayoutId, localeNamesMap,
906             localeTitlesMap, description, type, hidden, friendlyURL, null,
907             null, serviceContext);
908     }
909 
910     public Layout updateLayout(
911             long groupId, boolean privateLayout, long layoutId,
912             String typeSettings)
913         throws PortalException, SystemException {
914 
915         Layout layout = layoutPersistence.findByG_P_L(
916             groupId, privateLayout, layoutId);
917 
918         layout.setTypeSettings(typeSettings);
919 
920         layoutPersistence.update(layout, false);
921 
922         return layout;
923     }
924 
925     public Layout updateLookAndFeel(
926             long groupId, boolean privateLayout, long layoutId, String themeId,
927             String colorSchemeId, String css, boolean wapTheme)
928         throws PortalException, SystemException {
929 
930         Layout layout = layoutPersistence.findByG_P_L(
931             groupId, privateLayout, layoutId);
932 
933         if (wapTheme) {
934             layout.setWapThemeId(themeId);
935             layout.setWapColorSchemeId(colorSchemeId);
936         }
937         else {
938             layout.setThemeId(themeId);
939             layout.setColorSchemeId(colorSchemeId);
940             layout.setCss(css);
941         }
942 
943         layoutPersistence.update(layout, false);
944 
945         return layout;
946     }
947 
948     public Layout updateName(Layout layout, String name, String languageId)
949         throws PortalException, SystemException {
950 
951         validateName(name, languageId);
952 
953         layout.setName(name, LocaleUtil.fromLanguageId(languageId));
954 
955         layoutPersistence.update(layout, false);
956 
957         try {
958             if (layout.getDlFolderId() > 0) {
959                 DLFolder folder = dlFolderLocalService.getFolder(
960                     layout.getDlFolderId());
961 
962                 ServiceContext serviceContext = new ServiceContext();
963 
964                 dlFolderLocalService.updateFolder(
965                     folder.getFolderId(), folder.getParentFolderId(),
966                     layout.getName(LocaleUtil.getDefault()),
967                     folder.getDescription(), serviceContext);
968             }
969         }
970         catch (NoSuchFolderException nsfe) {
971         }
972 
973         return layout;
974     }
975 
976     public Layout updateName(
977             long groupId, boolean privateLayout, long layoutId, String name,
978             String languageId)
979         throws PortalException, SystemException {
980 
981         Layout layout = layoutPersistence.findByG_P_L(
982             groupId, privateLayout, layoutId);
983 
984         return updateName(layout, name, languageId);
985     }
986 
987     public Layout updateName(long plid, String name, String languageId)
988         throws PortalException, SystemException {
989 
990         Layout layout = layoutPersistence.findByPrimaryKey(plid);
991 
992         return updateName(layout, name, languageId);
993     }
994 
995     public Layout updateParentLayoutId(
996             long groupId, boolean privateLayout, long layoutId,
997             long parentLayoutId)
998         throws PortalException, SystemException {
999 
1000        parentLayoutId = getParentLayoutId(
1001            groupId, privateLayout, parentLayoutId);
1002
1003        validateParentLayoutId(
1004            groupId, privateLayout, layoutId, parentLayoutId);
1005
1006        Layout layout = layoutPersistence.findByG_P_L(
1007            groupId, privateLayout, layoutId);
1008
1009        if (parentLayoutId != layout.getParentLayoutId()) {
1010            layout.setPriority(
1011                getNextPriority(groupId, privateLayout, parentLayoutId));
1012        }
1013
1014        layout.setParentLayoutId(parentLayoutId);
1015
1016        layoutPersistence.update(layout, false);
1017
1018        return layout;
1019    }
1020
1021    public Layout updateParentLayoutId(long plid, long parentPlid)
1022        throws PortalException, SystemException {
1023
1024        Layout layout = layoutPersistence.findByPrimaryKey(plid);
1025
1026        long parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
1027
1028        if (parentPlid > 0) {
1029            Layout parentLayout = layoutPersistence.fetchByPrimaryKey(
1030                parentPlid);
1031
1032            if (parentLayout != null) {
1033                parentLayoutId = parentLayout.getLayoutId();
1034            }
1035        }
1036
1037        parentLayoutId = getParentLayoutId(
1038            layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
1039
1040        validateParentLayoutId(
1041            layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
1042            parentLayoutId);
1043
1044        if (parentLayoutId != layout.getParentLayoutId()) {
1045            int priority = getNextPriority(
1046                layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
1047
1048            layout.setPriority(priority);
1049        }
1050
1051        layout.setParentLayoutId(parentLayoutId);
1052
1053        layoutPersistence.update(layout, false);
1054
1055        return layout;
1056    }
1057
1058    public Layout updatePriority(Layout layout, int priority)
1059        throws SystemException {
1060
1061        if (layout.getPriority() == priority) {
1062            return layout;
1063        }
1064
1065        boolean lessThan = false;
1066
1067        if (layout.getPriority() < priority) {
1068            lessThan = true;
1069        }
1070
1071        layout.setPriority(priority);
1072
1073        layoutPersistence.update(layout, false);
1074
1075        priority = 0;
1076
1077        List<Layout> layouts = layoutPersistence.findByG_P_P(
1078            layout.getGroupId(), layout.isPrivateLayout(),
1079            layout.getParentLayoutId());
1080
1081        layouts = ListUtil.sort(
1082            layouts, new LayoutPriorityComparator(layout, lessThan));
1083
1084        for (Layout curLayout : layouts) {
1085            curLayout.setPriority(priority++);
1086
1087            layoutPersistence.update(curLayout, false);
1088
1089            if (curLayout.equals(layout)) {
1090                layout = curLayout;
1091            }
1092        }
1093
1094        return layout;
1095    }
1096
1097    public Layout updatePriority(
1098            long groupId, boolean privateLayout, long layoutId, int priority)
1099        throws PortalException, SystemException {
1100
1101        Layout layout = layoutPersistence.findByG_P_L(
1102            groupId, privateLayout, layoutId);
1103
1104        return updatePriority(layout, priority);
1105    }
1106
1107    public Layout updatePriority(long plid, int priority)
1108        throws PortalException, SystemException {
1109
1110        Layout layout = layoutPersistence.findByPrimaryKey(plid);
1111
1112        return updatePriority(layout, priority);
1113    }
1114
1115    protected String getFriendlyURL(
1116            long groupId, boolean privateLayout, long layoutId,
1117            String name, String friendlyURL)
1118        throws PortalException, SystemException {
1119
1120        friendlyURL = getFriendlyURL(friendlyURL);
1121
1122        if (Validator.isNull(friendlyURL)) {
1123            friendlyURL = StringPool.SLASH + getFriendlyURL(name);
1124
1125            String originalFriendlyURL = friendlyURL;
1126
1127            for (int i = 1;; i++) {
1128                try {
1129                    validateFriendlyURL(
1130                        groupId, privateLayout, layoutId, friendlyURL);
1131
1132                    break;
1133                }
1134                catch (LayoutFriendlyURLException lfurle) {
1135                    int type = lfurle.getType();
1136
1137                    if (type == LayoutFriendlyURLException.DUPLICATE) {
1138                        friendlyURL = originalFriendlyURL + i;
1139                    }
1140                    else {
1141                        friendlyURL = StringPool.SLASH + layoutId;
1142
1143                        break;
1144                    }
1145                }
1146            }
1147        }
1148
1149        return friendlyURL;
1150    }
1151
1152    protected String getFriendlyURL(String friendlyURL) {
1153        return FriendlyURLNormalizer.normalize(friendlyURL);
1154    }
1155
1156    protected int getNextPriority(
1157            long groupId, boolean privateLayout, long parentLayoutId)
1158        throws SystemException {
1159
1160        List<Layout> layouts = layoutPersistence.findByG_P_P(
1161            groupId, privateLayout, parentLayoutId);
1162
1163        if (layouts.size() == 0) {
1164            return 0;
1165        }
1166
1167        Layout layout = layouts.get(layouts.size() - 1);
1168
1169        return layout.getPriority() + 1;
1170    }
1171
1172    protected long getParentLayoutId(
1173            long groupId, boolean privateLayout, long parentLayoutId)
1174        throws SystemException {
1175
1176        if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1177
1178            // Ensure parent layout exists
1179
1180            Layout parentLayout = layoutPersistence.fetchByG_P_L(
1181                groupId, privateLayout, parentLayoutId);
1182
1183            if (parentLayout == null) {
1184                parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
1185            }
1186        }
1187
1188        return parentLayoutId;
1189    }
1190
1191    protected boolean isDescendant(Layout layout, long layoutId)
1192        throws PortalException, SystemException {
1193
1194        if (layout.getLayoutId() == layoutId) {
1195            return true;
1196        }
1197        else {
1198            for (Layout childLayout : layout.getChildren()) {
1199                if (isDescendant(childLayout, layoutId)) {
1200                    return true;
1201                }
1202            }
1203
1204            return false;
1205        }
1206    }
1207
1208    protected void setLocalizedAttributes(
1209        Layout layout, Map<Locale, String> localeNamesMap,
1210        Map<Locale, String> localeTitlesMap) {
1211
1212        if (localeNamesMap == null) {
1213            return;
1214        }
1215
1216        if (localeTitlesMap == null) {
1217            return;
1218        }
1219
1220        Locale[] locales = LanguageUtil.getAvailableLocales();
1221
1222        for (Locale locale : locales) {
1223            String name = localeNamesMap.get(locale);
1224            String title = localeTitlesMap.get(locale);
1225
1226            layout.setName(name, locale);
1227            layout.setTitle(title, locale);
1228        }
1229    }
1230
1231    protected void validate(
1232            long groupId, boolean privateLayout, long layoutId,
1233            long parentLayoutId, String name, String type, boolean hidden,
1234            String friendlyURL)
1235        throws PortalException, SystemException {
1236
1237        validateName(name);
1238
1239        boolean firstLayout = false;
1240
1241        if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1242            List<Layout> layouts = layoutPersistence.findByG_P_P(
1243                groupId, privateLayout, parentLayoutId, 0, 1);
1244
1245            if (layouts.size() == 0) {
1246                firstLayout = true;
1247            }
1248            else {
1249                long firstLayoutId = layouts.get(0).getLayoutId();
1250
1251                if (firstLayoutId == layoutId) {
1252                    firstLayout = true;
1253                }
1254            }
1255        }
1256
1257        if (firstLayout) {
1258            validateFirstLayout(type, hidden);
1259        }
1260
1261        if (!PortalUtil.isLayoutParentable(type)) {
1262            if (layoutPersistence.countByG_P_P(
1263                    groupId, privateLayout, layoutId) > 0) {
1264
1265                throw new LayoutTypeException(
1266                    LayoutTypeException.NOT_PARENTABLE);
1267            }
1268        }
1269
1270        validateFriendlyURL(groupId, privateLayout, layoutId, friendlyURL);
1271    }
1272
1273    protected void validateFirstLayout(String type, boolean hidden)
1274        throws PortalException {
1275
1276        if (!PortalUtil.isLayoutFirstPageable(type)) {
1277            throw new LayoutTypeException(LayoutTypeException.FIRST_LAYOUT);
1278        }
1279
1280        if (hidden) {
1281            throw new LayoutHiddenException();
1282        }
1283    }
1284
1285    protected void validateFriendlyURL(
1286            long groupId, boolean privateLayout, long layoutId,
1287            String friendlyURL)
1288        throws PortalException, SystemException {
1289
1290        if (Validator.isNull(friendlyURL)) {
1291            return;
1292        }
1293
1294        int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
1295
1296        if (exceptionType != -1) {
1297            throw new LayoutFriendlyURLException(exceptionType);
1298        }
1299
1300        Layout layout = layoutPersistence.fetchByG_P_F(
1301            groupId, privateLayout, friendlyURL);
1302
1303        if ((layout != null) && (layout.getLayoutId() != layoutId)) {
1304            throw new LayoutFriendlyURLException(
1305                LayoutFriendlyURLException.DUPLICATE);
1306        }
1307
1308        LayoutImpl.validateFriendlyURLKeyword(friendlyURL);
1309
1310        /*List<FriendlyURLMapper> friendlyURLMappers =
1311            portletLocalService.getFriendlyURLMappers();
1312
1313        for (FriendlyURLMapper friendlyURLMapper : friendlyURLMappers) {
1314            if (friendlyURL.indexOf(friendlyURLMapper.getMapping()) != -1) {
1315                LayoutFriendlyURLException lfurle =
1316                    new LayoutFriendlyURLException(
1317                        LayoutFriendlyURLException.KEYWORD_CONFLICT);
1318
1319                lfurle.setKeywordConflict(friendlyURLMapper.getMapping());
1320
1321                throw lfurle;
1322            }
1323        }*/
1324
1325        String layoutIdFriendlyURL = friendlyURL.substring(1);
1326
1327        if (Validator.isNumber(layoutIdFriendlyURL) &&
1328            !layoutIdFriendlyURL.equals(String.valueOf(layoutId))) {
1329
1330            LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
1331                LayoutFriendlyURLException.POSSIBLE_DUPLICATE);
1332
1333            lfurle.setKeywordConflict(layoutIdFriendlyURL);
1334
1335            throw lfurle;
1336        }
1337    }
1338
1339    protected void validateName(String name) throws PortalException {
1340        if (Validator.isNull(name)) {
1341            throw new LayoutNameException();
1342        }
1343    }
1344
1345    protected void validateName(String name, String languageId)
1346        throws PortalException {
1347
1348        String defaultLanguageId = LocaleUtil.toLanguageId(
1349            LocaleUtil.getDefault());
1350
1351        if (defaultLanguageId.equals(languageId)) {
1352            validateName(name);
1353        }
1354    }
1355
1356    protected void validateParentLayoutId(
1357            long groupId, boolean privateLayout, long layoutId,
1358            long parentLayoutId)
1359        throws PortalException, SystemException {
1360
1361        Layout layout = layoutPersistence.findByG_P_L(
1362            groupId, privateLayout, layoutId);
1363
1364        if (parentLayoutId != layout.getParentLayoutId()) {
1365
1366            // Layouts can always be moved to the root level
1367
1368            if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1369                return;
1370            }
1371
1372            // Layout cannot become a child of a layout that is not parentable
1373
1374            Layout parentLayout = layoutPersistence.findByG_P_L(
1375                groupId, privateLayout, parentLayoutId);
1376
1377            if (!PortalUtil.isLayoutParentable(parentLayout)) {
1378                throw new LayoutParentLayoutIdException(
1379                    LayoutParentLayoutIdException.NOT_PARENTABLE);
1380            }
1381
1382            // Layout cannot become descendant of itself
1383
1384            if (isDescendant(layout, parentLayoutId)) {
1385                throw new LayoutParentLayoutIdException(
1386                    LayoutParentLayoutIdException.SELF_DESCENDANT);
1387            }
1388
1389            // If layout is moved, the new first layout must be valid
1390
1391            if (layout.getParentLayoutId() ==
1392                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1393
1394                List<Layout> layouts = layoutPersistence.findByG_P_P(
1395                    groupId, privateLayout,
1396                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
1397
1398                // You can only reach this point if there are more than two
1399                // layouts at the root level because of the descendant check
1400
1401                long firstLayoutId = layouts.get(0).getLayoutId();
1402
1403                if (firstLayoutId == layoutId) {
1404                    Layout secondLayout = layouts.get(1);
1405
1406                    try {
1407                        validateFirstLayout(
1408                            secondLayout.getType(), secondLayout.getHidden());
1409                    }
1410                    catch (LayoutHiddenException lhe) {
1411                        throw new LayoutParentLayoutIdException(
1412                            LayoutParentLayoutIdException.FIRST_LAYOUT_HIDDEN);
1413                    }
1414                    catch (LayoutTypeException lte) {
1415                        throw new LayoutParentLayoutIdException(
1416                            LayoutParentLayoutIdException.FIRST_LAYOUT_TYPE);
1417                    }
1418                }
1419            }
1420        }
1421    }
1422
1423    private static Log _log = LogFactoryUtil.getLog(
1424        LayoutLocalServiceImpl.class);
1425
1426}