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