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