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