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.WorkflowConstants;
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(), groupId, Layout.class.getName(),
177                 plid, WorkflowConstants.ACTION_PUBLISH);
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 PortalException, 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.isTypePortlet()) {
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), nextLayoutId);
615             }
616         }
617 
618         return nextLayoutId;
619     }
620 
621     public List<Layout> getNullFriendlyURLLayouts() throws SystemException {
622         return layoutFinder.findByNullFriendlyURL();
623     }
624 
625     public boolean hasLayouts(
626             long groupId, boolean privateLayout, long parentLayoutId)
627         throws SystemException {
628 
629         return layoutPersistence.countByG_P_P(
630             groupId, privateLayout, parentLayoutId) > 0;
631     }
632 
633     public void importLayouts(
634             long userId, long groupId, boolean privateLayout,
635             Map<String, String[]> parameterMap, byte[] bytes)
636         throws PortalException, SystemException {
637 
638         importLayouts(
639             userId, groupId, privateLayout, parameterMap,
640             new UnsyncByteArrayInputStream(bytes));
641     }
642 
643     public void importLayouts(
644             long userId, long groupId, boolean privateLayout,
645             Map<String, String[]> parameterMap, File file)
646         throws PortalException, SystemException {
647 
648         BatchSessionUtil.setEnabled(true);
649 
650         try {
651             LayoutImporter layoutImporter = new LayoutImporter();
652 
653             layoutImporter.importLayouts(
654                 userId, groupId, privateLayout, parameterMap, file);
655         }
656         finally {
657             BatchSessionUtil.setEnabled(false);
658         }
659     }
660 
661     public void importLayouts(
662             long userId, long groupId, boolean privateLayout,
663             Map<String, String[]> parameterMap, InputStream is)
664         throws PortalException, SystemException {
665 
666         try {
667             File file = FileUtil.createTempFile("lar");
668 
669             FileUtil.write(file, is);
670 
671             importLayouts(userId, groupId, privateLayout, parameterMap, file);
672         }
673         catch (IOException e) {
674             throw new SystemException(e);
675         }
676     }
677 
678     public void importPortletInfo(
679             long userId, long plid, long groupId, String portletId,
680             Map<String, String[]> parameterMap, File file)
681         throws PortalException, SystemException {
682 
683         BatchSessionUtil.setEnabled(true);
684 
685         try {
686             PortletImporter portletImporter = new PortletImporter();
687 
688             portletImporter.importPortletInfo(
689                 userId, plid, groupId, portletId, parameterMap, file);
690         }
691         finally {
692             BatchSessionUtil.setEnabled(false);
693         }
694     }
695 
696     public void importPortletInfo(
697             long userId, long plid, long groupId, String portletId,
698             Map<String, String[]> parameterMap, InputStream is)
699         throws PortalException, SystemException {
700 
701         try {
702             File file = FileUtil.createTempFile("lar");
703 
704             FileUtil.write(file, is);
705 
706             importPortletInfo(
707                 userId, plid, groupId, portletId, parameterMap, file);
708         }
709         catch (IOException e) {
710             throw new SystemException(e);
711         }
712     }
713 
714     public void setLayouts(
715             long groupId, boolean privateLayout, long parentLayoutId,
716             long[] layoutIds)
717         throws PortalException, SystemException {
718 
719         if (layoutIds == null) {
720             return;
721         }
722 
723         if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
724             if (layoutIds.length < 1) {
725                 throw new RequiredLayoutException(
726                     RequiredLayoutException.AT_LEAST_ONE);
727             }
728 
729             Layout layout = layoutPersistence.findByG_P_L(
730                 groupId, privateLayout, layoutIds[0]);
731 
732             if (!PortalUtil.isLayoutFirstPageable(layout.getType())) {
733                 throw new RequiredLayoutException(
734                     RequiredLayoutException.FIRST_LAYOUT_TYPE);
735             }
736 
737             if (layout.isHidden()) {
738                 throw new RequiredLayoutException(
739                     RequiredLayoutException.FIRST_LAYOUT_HIDDEN);
740             }
741         }
742 
743         Set<Long> layoutIdsSet = new LinkedHashSet<Long>();
744 
745         for (int i = 0; i < layoutIds.length; i++) {
746             layoutIdsSet.add(layoutIds[i]);
747         }
748 
749         Set<Long> newLayoutIdsSet = new HashSet<Long>();
750 
751         List<Layout> layouts = layoutPersistence.findByG_P_P(
752             groupId, privateLayout, parentLayoutId);
753 
754         for (Layout layout : layouts) {
755             if (!layoutIdsSet.contains(layout.getLayoutId())) {
756                 deleteLayout(layout, true);
757             }
758             else {
759                 newLayoutIdsSet.add(layout.getLayoutId());
760             }
761         }
762 
763         int priority = 0;
764 
765         for (long layoutId : layoutIdsSet) {
766             Layout layout = layoutPersistence.findByG_P_L(
767                 groupId, privateLayout, layoutId);
768 
769             layout.setPriority(priority++);
770 
771             layoutPersistence.update(layout, false);
772         }
773 
774         layoutSetLocalService.updatePageCount(groupId, privateLayout);
775     }
776 
777     public Layout updateFriendlyURL(long plid, String friendlyURL)
778         throws PortalException, SystemException {
779 
780         Layout layout = layoutPersistence.findByPrimaryKey(plid);
781 
782         friendlyURL = getFriendlyURL(
783             layout.getGroupId(), layout.getPrivateLayout(),
784             layout.getLayoutId(), StringPool.BLANK, friendlyURL);
785 
786         validateFriendlyURL(
787             layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
788             friendlyURL);
789 
790         layout.setFriendlyURL(friendlyURL);
791 
792         layoutPersistence.update(layout, false);
793 
794         return layout;
795     }
796 
797     public Layout updateLayout(
798             long groupId, boolean privateLayout, long layoutId,
799             long parentLayoutId, Map<Locale, String> localeNamesMap,
800             Map<Locale, String> localeTitlesMap, String description,
801             String type, boolean hidden, String friendlyURL, Boolean iconImage,
802             byte[] iconBytes, ServiceContext serviceContext)
803         throws PortalException, SystemException {
804 
805         // Layout
806 
807         parentLayoutId = getParentLayoutId(
808             groupId, privateLayout, parentLayoutId);
809         String name = localeNamesMap.get(LocaleUtil.getDefault());
810         friendlyURL = getFriendlyURL(
811             groupId, privateLayout, layoutId, StringPool.BLANK, friendlyURL);
812 
813         validate(
814             groupId, privateLayout, layoutId, parentLayoutId, name, type,
815             hidden, friendlyURL);
816 
817         validateParentLayoutId(
818             groupId, privateLayout, layoutId, parentLayoutId);
819 
820         Layout layout = layoutPersistence.findByG_P_L(
821             groupId, privateLayout, layoutId);
822 
823         if (parentLayoutId != layout.getParentLayoutId()) {
824             layout.setPriority(
825                 getNextPriority(groupId, privateLayout, parentLayoutId));
826         }
827 
828         layout.setParentLayoutId(parentLayoutId);
829         layout.setDescription(description);
830         layout.setType(type);
831         layout.setHidden(hidden);
832         layout.setFriendlyURL(friendlyURL);
833 
834         setLocalizedAttributes(layout, localeNamesMap, localeTitlesMap);
835 
836         if (iconImage != null) {
837             layout.setIconImage(iconImage.booleanValue());
838 
839             if (iconImage.booleanValue()) {
840                 long iconImageId = layout.getIconImageId();
841 
842                 if (iconImageId <= 0) {
843                     iconImageId = counterLocalService.increment();
844 
845                     layout.setIconImageId(iconImageId);
846                 }
847             }
848         }
849 
850         layoutPersistence.update(layout, false);
851 
852         // Icon
853 
854         if (iconImage != null) {
855             if (!iconImage.booleanValue()) {
856                 imageLocalService.deleteImage(layout.getIconImageId());
857             }
858             else if ((iconBytes != null) && (iconBytes.length > 0)) {
859                 imageLocalService.updateImage(
860                     layout.getIconImageId(), iconBytes);
861             }
862         }
863 
864         // Document library
865 
866         try {
867             if (layout.getDlFolderId() > 0) {
868                 DLFolder folder = dlFolderLocalService.getFolder(
869                     layout.getDlFolderId());
870 
871                 if (!name.equals(folder.getName())) {
872                     dlFolderLocalService.updateFolder(
873                         folder.getFolderId(), folder.getParentFolderId(), name,
874                         folder.getDescription(), new ServiceContext());
875                 }
876             }
877         }
878         catch (DuplicateFolderNameException dfne) {
879             if (_log.isDebugEnabled()) {
880                 _log.debug(dfne);
881             }
882         }
883         catch (NoSuchFolderException nsfe) {
884         }
885 
886         // Expando
887 
888         ExpandoBridge expandoBridge = layout.getExpandoBridge();
889 
890         expandoBridge.setAttributes(serviceContext);
891 
892         return layout;
893     }
894 
895     public Layout updateLayout(
896             long groupId, boolean privateLayout, long layoutId,
897             long parentLayoutId, Map<Locale, String> localeNamesMap,
898             Map<Locale, String> localeTitlesMap, String description,
899             String type, boolean hidden, String friendlyURL,
900             ServiceContext serviceContext)
901         throws PortalException, SystemException {
902 
903         return updateLayout(
904             groupId, privateLayout, layoutId, parentLayoutId, localeNamesMap,
905             localeTitlesMap, description, type, hidden, friendlyURL, null,
906             null, serviceContext);
907     }
908 
909     public Layout updateLayout(
910             long groupId, boolean privateLayout, long layoutId,
911             String typeSettings)
912         throws PortalException, SystemException {
913 
914         Layout layout = layoutPersistence.findByG_P_L(
915             groupId, privateLayout, layoutId);
916 
917         layout.setTypeSettings(typeSettings);
918 
919         layoutPersistence.update(layout, false);
920 
921         return layout;
922     }
923 
924     public Layout updateLookAndFeel(
925             long groupId, boolean privateLayout, long layoutId, String themeId,
926             String colorSchemeId, String css, boolean wapTheme)
927         throws PortalException, SystemException {
928 
929         Layout layout = layoutPersistence.findByG_P_L(
930             groupId, privateLayout, layoutId);
931 
932         if (wapTheme) {
933             layout.setWapThemeId(themeId);
934             layout.setWapColorSchemeId(colorSchemeId);
935         }
936         else {
937             layout.setThemeId(themeId);
938             layout.setColorSchemeId(colorSchemeId);
939             layout.setCss(css);
940         }
941 
942         layoutPersistence.update(layout, false);
943 
944         return layout;
945     }
946 
947     public Layout updateName(Layout layout, String name, String languageId)
948         throws PortalException, SystemException {
949 
950         validateName(name, languageId);
951 
952         layout.setName(name, LocaleUtil.fromLanguageId(languageId));
953 
954         layoutPersistence.update(layout, false);
955 
956         try {
957             if (layout.getDlFolderId() > 0) {
958                 DLFolder folder = dlFolderLocalService.getFolder(
959                     layout.getDlFolderId());
960 
961                 ServiceContext serviceContext = new ServiceContext();
962 
963                 dlFolderLocalService.updateFolder(
964                     folder.getFolderId(), folder.getParentFolderId(),
965                     layout.getName(LocaleUtil.getDefault()),
966                     folder.getDescription(), serviceContext);
967             }
968         }
969         catch (NoSuchFolderException nsfe) {
970         }
971 
972         return layout;
973     }
974 
975     public Layout updateName(
976             long groupId, boolean privateLayout, long layoutId, String name,
977             String languageId)
978         throws PortalException, SystemException {
979 
980         Layout layout = layoutPersistence.findByG_P_L(
981             groupId, privateLayout, layoutId);
982 
983         return updateName(layout, name, languageId);
984     }
985 
986     public Layout updateName(long plid, String name, String languageId)
987         throws PortalException, SystemException {
988 
989         Layout layout = layoutPersistence.findByPrimaryKey(plid);
990 
991         return updateName(layout, name, languageId);
992     }
993 
994     public Layout updateParentLayoutId(
995             long groupId, boolean privateLayout, long layoutId,
996             long parentLayoutId)
997         throws PortalException, SystemException {
998 
999         parentLayoutId = getParentLayoutId(
1000            groupId, privateLayout, parentLayoutId);
1001
1002        validateParentLayoutId(
1003            groupId, privateLayout, layoutId, parentLayoutId);
1004
1005        Layout layout = layoutPersistence.findByG_P_L(
1006            groupId, privateLayout, layoutId);
1007
1008        if (parentLayoutId != layout.getParentLayoutId()) {
1009            layout.setPriority(
1010                getNextPriority(groupId, privateLayout, parentLayoutId));
1011        }
1012
1013        layout.setParentLayoutId(parentLayoutId);
1014
1015        layoutPersistence.update(layout, false);
1016
1017        return layout;
1018    }
1019
1020    public Layout updateParentLayoutId(long plid, long parentPlid)
1021        throws PortalException, SystemException {
1022
1023        Layout layout = layoutPersistence.findByPrimaryKey(plid);
1024
1025        long parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
1026
1027        if (parentPlid > 0) {
1028            Layout parentLayout = layoutPersistence.fetchByPrimaryKey(
1029                parentPlid);
1030
1031            if (parentLayout != null) {
1032                parentLayoutId = parentLayout.getLayoutId();
1033            }
1034        }
1035
1036        parentLayoutId = getParentLayoutId(
1037            layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
1038
1039        validateParentLayoutId(
1040            layout.getGroupId(), layout.isPrivateLayout(), layout.getLayoutId(),
1041            parentLayoutId);
1042
1043        if (parentLayoutId != layout.getParentLayoutId()) {
1044            int priority = getNextPriority(
1045                layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
1046
1047            layout.setPriority(priority);
1048        }
1049
1050        layout.setParentLayoutId(parentLayoutId);
1051
1052        layoutPersistence.update(layout, false);
1053
1054        return layout;
1055    }
1056
1057    public Layout updatePriority(Layout layout, int priority)
1058        throws SystemException {
1059
1060        if (layout.getPriority() == priority) {
1061            return layout;
1062        }
1063
1064        boolean lessThan = false;
1065
1066        if (layout.getPriority() < priority) {
1067            lessThan = true;
1068        }
1069
1070        layout.setPriority(priority);
1071
1072        layoutPersistence.update(layout, false);
1073
1074        priority = 0;
1075
1076        List<Layout> layouts = layoutPersistence.findByG_P_P(
1077            layout.getGroupId(), layout.isPrivateLayout(),
1078            layout.getParentLayoutId());
1079
1080        layouts = ListUtil.sort(
1081            layouts, new LayoutPriorityComparator(layout, lessThan));
1082
1083        for (Layout curLayout : layouts) {
1084            curLayout.setPriority(priority++);
1085
1086            layoutPersistence.update(curLayout, false);
1087
1088            if (curLayout.equals(layout)) {
1089                layout = curLayout;
1090            }
1091        }
1092
1093        return layout;
1094    }
1095
1096    public Layout updatePriority(
1097            long groupId, boolean privateLayout, long layoutId, int priority)
1098        throws PortalException, SystemException {
1099
1100        Layout layout = layoutPersistence.findByG_P_L(
1101            groupId, privateLayout, layoutId);
1102
1103        return updatePriority(layout, priority);
1104    }
1105
1106    public Layout updatePriority(long plid, int priority)
1107        throws PortalException, SystemException {
1108
1109        Layout layout = layoutPersistence.findByPrimaryKey(plid);
1110
1111        return updatePriority(layout, priority);
1112    }
1113
1114    protected String getFriendlyURL(
1115            long groupId, boolean privateLayout, long layoutId,
1116            String name, String friendlyURL)
1117        throws PortalException, SystemException {
1118
1119        friendlyURL = getFriendlyURL(friendlyURL);
1120
1121        if (Validator.isNull(friendlyURL)) {
1122            friendlyURL = StringPool.SLASH + getFriendlyURL(name);
1123
1124            String originalFriendlyURL = friendlyURL;
1125
1126            for (int i = 1;; i++) {
1127                try {
1128                    validateFriendlyURL(
1129                        groupId, privateLayout, layoutId, friendlyURL);
1130
1131                    break;
1132                }
1133                catch (LayoutFriendlyURLException lfurle) {
1134                    int type = lfurle.getType();
1135
1136                    if (type == LayoutFriendlyURLException.DUPLICATE) {
1137                        friendlyURL = originalFriendlyURL + i;
1138                    }
1139                    else {
1140                        friendlyURL = StringPool.SLASH + layoutId;
1141
1142                        break;
1143                    }
1144                }
1145            }
1146        }
1147
1148        return friendlyURL;
1149    }
1150
1151    protected String getFriendlyURL(String friendlyURL) {
1152        return FriendlyURLNormalizer.normalize(friendlyURL);
1153    }
1154
1155    protected int getNextPriority(
1156            long groupId, boolean privateLayout, long parentLayoutId)
1157        throws SystemException {
1158
1159        List<Layout> layouts = layoutPersistence.findByG_P_P(
1160            groupId, privateLayout, parentLayoutId);
1161
1162        if (layouts.size() == 0) {
1163            return 0;
1164        }
1165
1166        Layout layout = layouts.get(layouts.size() - 1);
1167
1168        return layout.getPriority() + 1;
1169    }
1170
1171    protected long getParentLayoutId(
1172            long groupId, boolean privateLayout, long parentLayoutId)
1173        throws SystemException {
1174
1175        if (parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1176
1177            // Ensure parent layout exists
1178
1179            Layout parentLayout = layoutPersistence.fetchByG_P_L(
1180                groupId, privateLayout, parentLayoutId);
1181
1182            if (parentLayout == null) {
1183                parentLayoutId = LayoutConstants.DEFAULT_PARENT_LAYOUT_ID;
1184            }
1185        }
1186
1187        return parentLayoutId;
1188    }
1189
1190    protected boolean isDescendant(Layout layout, long layoutId)
1191        throws PortalException, SystemException {
1192
1193        if (layout.getLayoutId() == layoutId) {
1194            return true;
1195        }
1196        else {
1197            for (Layout childLayout : layout.getChildren()) {
1198                if (isDescendant(childLayout, layoutId)) {
1199                    return true;
1200                }
1201            }
1202
1203            return false;
1204        }
1205    }
1206
1207    protected void setLocalizedAttributes(
1208        Layout layout, Map<Locale, String> localeNamesMap,
1209        Map<Locale, String> localeTitlesMap) {
1210
1211        if (localeNamesMap == null) {
1212            return;
1213        }
1214
1215        if (localeTitlesMap == null) {
1216            return;
1217        }
1218
1219        Locale[] locales = LanguageUtil.getAvailableLocales();
1220
1221        for (Locale locale : locales) {
1222            String name = localeNamesMap.get(locale);
1223            String title = localeTitlesMap.get(locale);
1224
1225            layout.setName(name, locale);
1226            layout.setTitle(title, locale);
1227        }
1228    }
1229
1230    protected void validate(
1231            long groupId, boolean privateLayout, long layoutId,
1232            long parentLayoutId, String name, String type, boolean hidden,
1233            String friendlyURL)
1234        throws PortalException, SystemException {
1235
1236        validateName(name);
1237
1238        boolean firstLayout = false;
1239
1240        if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1241            List<Layout> layouts = layoutPersistence.findByG_P_P(
1242                groupId, privateLayout, parentLayoutId, 0, 1);
1243
1244            if (layouts.size() == 0) {
1245                firstLayout = true;
1246            }
1247            else {
1248                long firstLayoutId = layouts.get(0).getLayoutId();
1249
1250                if (firstLayoutId == layoutId) {
1251                    firstLayout = true;
1252                }
1253            }
1254        }
1255
1256        if (firstLayout) {
1257            validateFirstLayout(type, hidden);
1258        }
1259
1260        if (!PortalUtil.isLayoutParentable(type)) {
1261            if (layoutPersistence.countByG_P_P(
1262                    groupId, privateLayout, layoutId) > 0) {
1263
1264                throw new LayoutTypeException(
1265                    LayoutTypeException.NOT_PARENTABLE);
1266            }
1267        }
1268
1269        validateFriendlyURL(groupId, privateLayout, layoutId, friendlyURL);
1270    }
1271
1272    protected void validateFirstLayout(String type, boolean hidden)
1273        throws PortalException {
1274
1275        if (!PortalUtil.isLayoutFirstPageable(type)) {
1276            throw new LayoutTypeException(LayoutTypeException.FIRST_LAYOUT);
1277        }
1278
1279        if (hidden) {
1280            throw new LayoutHiddenException();
1281        }
1282    }
1283
1284    protected void validateFriendlyURL(
1285            long groupId, boolean privateLayout, long layoutId,
1286            String friendlyURL)
1287        throws PortalException, SystemException {
1288
1289        if (Validator.isNull(friendlyURL)) {
1290            return;
1291        }
1292
1293        int exceptionType = LayoutImpl.validateFriendlyURL(friendlyURL);
1294
1295        if (exceptionType != -1) {
1296            throw new LayoutFriendlyURLException(exceptionType);
1297        }
1298
1299        Layout layout = layoutPersistence.fetchByG_P_F(
1300            groupId, privateLayout, friendlyURL);
1301
1302        if ((layout != null) && (layout.getLayoutId() != layoutId)) {
1303            throw new LayoutFriendlyURLException(
1304                LayoutFriendlyURLException.DUPLICATE);
1305        }
1306
1307        LayoutImpl.validateFriendlyURLKeyword(friendlyURL);
1308
1309        /*List<FriendlyURLMapper> friendlyURLMappers =
1310            portletLocalService.getFriendlyURLMappers();
1311
1312        for (FriendlyURLMapper friendlyURLMapper : friendlyURLMappers) {
1313            if (friendlyURL.indexOf(friendlyURLMapper.getMapping()) != -1) {
1314                LayoutFriendlyURLException lfurle =
1315                    new LayoutFriendlyURLException(
1316                        LayoutFriendlyURLException.KEYWORD_CONFLICT);
1317
1318                lfurle.setKeywordConflict(friendlyURLMapper.getMapping());
1319
1320                throw lfurle;
1321            }
1322        }*/
1323
1324        String layoutIdFriendlyURL = friendlyURL.substring(1);
1325
1326        if (Validator.isNumber(layoutIdFriendlyURL) &&
1327            !layoutIdFriendlyURL.equals(String.valueOf(layoutId))) {
1328
1329            LayoutFriendlyURLException lfurle = new LayoutFriendlyURLException(
1330                LayoutFriendlyURLException.POSSIBLE_DUPLICATE);
1331
1332            lfurle.setKeywordConflict(layoutIdFriendlyURL);
1333
1334            throw lfurle;
1335        }
1336    }
1337
1338    protected void validateName(String name) throws PortalException {
1339        if (Validator.isNull(name)) {
1340            throw new LayoutNameException();
1341        }
1342    }
1343
1344    protected void validateName(String name, String languageId)
1345        throws PortalException {
1346
1347        String defaultLanguageId = LocaleUtil.toLanguageId(
1348            LocaleUtil.getDefault());
1349
1350        if (defaultLanguageId.equals(languageId)) {
1351            validateName(name);
1352        }
1353    }
1354
1355    protected void validateParentLayoutId(
1356            long groupId, boolean privateLayout, long layoutId,
1357            long parentLayoutId)
1358        throws PortalException, SystemException {
1359
1360        Layout layout = layoutPersistence.findByG_P_L(
1361            groupId, privateLayout, layoutId);
1362
1363        if (parentLayoutId != layout.getParentLayoutId()) {
1364
1365            // Layouts can always be moved to the root level
1366
1367            if (parentLayoutId == LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1368                return;
1369            }
1370
1371            // Layout cannot become a child of a layout that is not parentable
1372
1373            Layout parentLayout = layoutPersistence.findByG_P_L(
1374                groupId, privateLayout, parentLayoutId);
1375
1376            if (!PortalUtil.isLayoutParentable(parentLayout)) {
1377                throw new LayoutParentLayoutIdException(
1378                    LayoutParentLayoutIdException.NOT_PARENTABLE);
1379            }
1380
1381            // Layout cannot become descendant of itself
1382
1383            if (isDescendant(layout, parentLayoutId)) {
1384                throw new LayoutParentLayoutIdException(
1385                    LayoutParentLayoutIdException.SELF_DESCENDANT);
1386            }
1387
1388            // If layout is moved, the new first layout must be valid
1389
1390            if (layout.getParentLayoutId() ==
1391                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) {
1392
1393                List<Layout> layouts = layoutPersistence.findByG_P_P(
1394                    groupId, privateLayout,
1395                    LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, 0, 2);
1396
1397                // You can only reach this point if there are more than two
1398                // layouts at the root level because of the descendant check
1399
1400                long firstLayoutId = layouts.get(0).getLayoutId();
1401
1402                if (firstLayoutId == layoutId) {
1403                    Layout secondLayout = layouts.get(1);
1404
1405                    try {
1406                        validateFirstLayout(
1407                            secondLayout.getType(), secondLayout.getHidden());
1408                    }
1409                    catch (LayoutHiddenException lhe) {
1410                        throw new LayoutParentLayoutIdException(
1411                            LayoutParentLayoutIdException.FIRST_LAYOUT_HIDDEN);
1412                    }
1413                    catch (LayoutTypeException lte) {
1414                        throw new LayoutParentLayoutIdException(
1415                            LayoutParentLayoutIdException.FIRST_LAYOUT_TYPE);
1416                    }
1417                }
1418            }
1419        }
1420    }
1421
1422    private static Log _log = LogFactoryUtil.getLog(
1423        LayoutLocalServiceImpl.class);
1424
1425}