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