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