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