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