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