001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.model.impl;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.portlet.PortletLayoutListener;
023    import com.liferay.portal.kernel.util.ArrayUtil;
024    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
025    import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.ListUtil;
028    import com.liferay.portal.kernel.util.PropsKeys;
029    import com.liferay.portal.kernel.util.StringPool;
030    import com.liferay.portal.kernel.util.StringUtil;
031    import com.liferay.portal.kernel.util.UnicodeProperties;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.model.CustomizedPages;
034    import com.liferay.portal.model.Group;
035    import com.liferay.portal.model.Layout;
036    import com.liferay.portal.model.LayoutSet;
037    import com.liferay.portal.model.LayoutTemplate;
038    import com.liferay.portal.model.LayoutTypeAccessPolicy;
039    import com.liferay.portal.model.LayoutTypeController;
040    import com.liferay.portal.model.LayoutTypePortlet;
041    import com.liferay.portal.model.LayoutTypePortletConstants;
042    import com.liferay.portal.model.Plugin;
043    import com.liferay.portal.model.Portlet;
044    import com.liferay.portal.model.PortletConstants;
045    import com.liferay.portal.model.PortletPreferences;
046    import com.liferay.portal.model.PortletPreferencesIds;
047    import com.liferay.portal.model.Theme;
048    import com.liferay.portal.security.permission.ActionKeys;
049    import com.liferay.portal.security.permission.PermissionChecker;
050    import com.liferay.portal.security.permission.PermissionThreadLocal;
051    import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
052    import com.liferay.portal.service.PluginSettingLocalServiceUtil;
053    import com.liferay.portal.service.PortletLocalServiceUtil;
054    import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
055    import com.liferay.portal.service.permission.LayoutPermissionUtil;
056    import com.liferay.portal.service.permission.PortletPermissionUtil;
057    import com.liferay.portal.util.LayoutTypePortletFactoryUtil;
058    import com.liferay.portal.util.PortalUtil;
059    import com.liferay.portal.util.PortletKeys;
060    import com.liferay.portal.util.PropsUtil;
061    import com.liferay.portal.util.PropsValues;
062    import com.liferay.portlet.PortalPreferences;
063    import com.liferay.portlet.PortletPreferencesFactoryUtil;
064    import com.liferay.portlet.sites.util.SitesUtil;
065    import com.liferay.util.JS;
066    
067    import java.text.DateFormat;
068    import java.text.Format;
069    
070    import java.util.ArrayList;
071    import java.util.Date;
072    import java.util.HashSet;
073    import java.util.List;
074    import java.util.Map;
075    import java.util.Set;
076    
077    /**
078     * @author Brian Wing Shun Chan
079     * @author Berentey Zsolt
080     * @author Jorge Ferrer
081     * @author Raymond Aug??
082     */
083    public class LayoutTypePortletImpl
084            extends LayoutTypeImpl implements LayoutTypePortlet {
085    
086            public LayoutTypePortletImpl(
087                    Layout layout, LayoutTypeController layoutTypeController,
088                    LayoutTypeAccessPolicy layoutTypeAccessPolicy) {
089    
090                    super(layout, layoutTypeController, layoutTypeAccessPolicy);
091    
092                    _layoutSetPrototypeLayout = SitesUtil.getLayoutSetPrototypeLayout(
093                            layout);
094            }
095    
096            @Override
097            public void addModeAboutPortletId(String portletId) {
098                    removeModesPortletId(portletId);
099                    setModeAbout(StringUtil.add(getModeAbout(), portletId));
100            }
101    
102            @Override
103            public void addModeConfigPortletId(String portletId) {
104                    removeModesPortletId(portletId);
105                    setModeConfig(StringUtil.add(getModeConfig(), portletId));
106            }
107    
108            @Override
109            public void addModeEditDefaultsPortletId(String portletId) {
110                    removeModesPortletId(portletId);
111                    setModeEditDefaults(StringUtil.add(getModeEditDefaults(), portletId));
112            }
113    
114            @Override
115            public void addModeEditGuestPortletId(String portletId) {
116                    removeModesPortletId(portletId);
117                    setModeEditGuest(StringUtil.add(getModeEditGuest(), portletId));
118            }
119    
120            @Override
121            public void addModeEditPortletId(String portletId) {
122                    removeModesPortletId(portletId);
123                    setModeEdit(StringUtil.add(getModeEdit(), portletId));
124            }
125    
126            @Override
127            public void addModeHelpPortletId(String portletId) {
128                    removeModesPortletId(portletId);
129                    setModeHelp(StringUtil.add(getModeHelp(), portletId));
130            }
131    
132            @Override
133            public void addModePreviewPortletId(String portletId) {
134                    removeModesPortletId(portletId);
135                    setModePreview(StringUtil.add(getModePreview(), portletId));
136            }
137    
138            @Override
139            public void addModePrintPortletId(String portletId) {
140                    removeModesPortletId(portletId);
141                    setModePrint(StringUtil.add(getModePrint(), portletId));
142            }
143    
144            @Override
145            public String addPortletId(long userId, String portletId) {
146                    return addPortletId(userId, portletId, true);
147            }
148    
149            @Override
150            public String addPortletId(
151                    long userId, String portletId, boolean checkPermission) {
152    
153                    return addPortletId(userId, portletId, null, -1, checkPermission);
154            }
155    
156            @Override
157            public String addPortletId(
158                    long userId, String portletId, String columnId, int columnPos) {
159    
160                    return addPortletId(userId, portletId, columnId, columnPos, true);
161            }
162    
163            @Override
164            public String addPortletId(
165                    long userId, String portletId, String columnId, int columnPos,
166                    boolean checkPermission) {
167    
168                    return addPortletId(
169                            userId, portletId, columnId, columnPos, checkPermission, false);
170            }
171    
172            @Override
173            public void addPortletIds(
174                    long userId, String[] portletIds, boolean checkPermission) {
175    
176                    for (String portletId : portletIds) {
177                            addPortletId(userId, portletId, checkPermission);
178                    }
179            }
180    
181            @Override
182            public void addPortletIds(
183                    long userId, String[] portletIds, String columnId,
184                    boolean checkPermission) {
185    
186                    for (String portletId : portletIds) {
187                            addPortletId(userId, portletId, columnId, -1, checkPermission);
188                    }
189            }
190    
191            @Override
192            public void addStateMaxPortletId(String portletId) {
193                    removeStatesPortletId(portletId);
194                    //setStateMax(StringUtil.add(getStateMax(), portletId));
195                    setStateMax(StringUtil.add(StringPool.BLANK, portletId));
196            }
197    
198            @Override
199            public void addStateMinPortletId(String portletId) {
200                    removeStateMaxPortletId(portletId);
201                    setStateMin(StringUtil.add(getStateMin(), portletId));
202            }
203    
204            @Override
205            public List<Portlet> addStaticPortlets(
206                    List<Portlet> portlets, List<Portlet> startPortlets,
207                    List<Portlet> endPortlets) {
208    
209                    // Return the original array of portlets if no static portlets are
210                    // specified
211    
212                    if (startPortlets == null) {
213                            startPortlets = new ArrayList<>();
214                    }
215    
216                    if (endPortlets == null) {
217                            endPortlets = new ArrayList<>();
218                    }
219    
220                    if (startPortlets.isEmpty() && endPortlets.isEmpty()) {
221                            return portlets;
222                    }
223    
224                    // New array of portlets that contain the static portlets
225    
226                    List<Portlet> list = new ArrayList<>(
227                            portlets.size() + startPortlets.size() + endPortlets.size());
228    
229                    if (!startPortlets.isEmpty()) {
230                            list.addAll(startPortlets);
231                    }
232    
233                    for (int i = 0; i < portlets.size(); i++) {
234                            Portlet portlet = portlets.get(i);
235    
236                            // Add the portlet if and only if it is not also a static portlet
237    
238                            if (!startPortlets.contains(portlet) &&
239                                    !endPortlets.contains(portlet)) {
240    
241                                    list.add(portlet);
242                            }
243                    }
244    
245                    if (!endPortlets.isEmpty()) {
246                            list.addAll(endPortlets);
247                    }
248    
249                    return list;
250            }
251    
252            @Override
253            public List<Portlet> getAllPortlets() {
254                    List<Portlet> explicitlyAddedPortlets = getExplicitlyAddedPortlets();
255    
256                    List<Portlet> staticPortlets = getStaticPortlets(
257                            PropsKeys.LAYOUT_STATIC_PORTLETS_ALL);
258    
259                    List<Portlet> embeddedPortlets = getEmbeddedPortlets(
260                            explicitlyAddedPortlets, staticPortlets);
261    
262                    return addStaticPortlets(
263                            explicitlyAddedPortlets, staticPortlets, embeddedPortlets);
264            }
265    
266            @Override
267            public List<Portlet> getAllPortlets(boolean includeSystem) {
268                    List<Portlet> filteredPortlets = new ArrayList<>();
269    
270                    List<Portlet> portlets = getAllPortlets();
271    
272                    for (Portlet portlet : portlets) {
273                            if (portlet.isSystem() && !includeSystem) {
274                                    continue;
275                            }
276    
277                            filteredPortlets.add(portlet);
278                    }
279    
280                    return filteredPortlets;
281            }
282    
283            @Override
284            public List<Portlet> getAllPortlets(String columnId) {
285                    String columnValue = getColumnValue(columnId);
286    
287                    String[] portletIds = StringUtil.split(columnValue);
288    
289                    List<Portlet> portlets = new ArrayList<>(portletIds.length);
290    
291                    for (String portletId : portletIds) {
292                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
293                                    getCompanyId(), portletId);
294    
295                            if (portlet != null) {
296                                    portlets.add(portlet);
297                            }
298                    }
299    
300                    List<Portlet> startPortlets = getStaticPortlets(
301                            PropsKeys.LAYOUT_STATIC_PORTLETS_START + columnId);
302    
303                    List<Portlet> endPortlets = getStaticPortlets(
304                            PropsKeys.LAYOUT_STATIC_PORTLETS_END + columnId);
305    
306                    return addStaticPortlets(portlets, startPortlets, endPortlets);
307            }
308    
309            @Override
310            public List<Portlet> getEmbeddedPortlets() {
311                    List<Portlet> explicitlyAddedPortlets = getExplicitlyAddedPortlets();
312    
313                    List<Portlet> staticPortlets = getStaticPortlets(
314                            PropsKeys.LAYOUT_STATIC_PORTLETS_ALL);
315    
316                    return getEmbeddedPortlets(explicitlyAddedPortlets, staticPortlets);
317            }
318    
319            @Override
320            public Layout getLayoutSetPrototypeLayout() {
321                    return _layoutSetPrototypeLayout;
322            }
323    
324            @Override
325            public String getLayoutSetPrototypeLayoutProperty(String key) {
326                    if (_layoutSetPrototypeLayout == null) {
327                            return StringPool.BLANK;
328                    }
329    
330                    UnicodeProperties typeSettingsProperties =
331                            _layoutSetPrototypeLayout.getTypeSettingsProperties();
332    
333                    return typeSettingsProperties.getProperty(key);
334            }
335    
336            @Override
337            public LayoutTemplate getLayoutTemplate() {
338                    String themeId = getThemeId();
339    
340                    LayoutTemplate layoutTemplate =
341                            LayoutTemplateLocalServiceUtil.getLayoutTemplate(
342                                    getLayoutTemplateId(), false, themeId);
343    
344                    if (layoutTemplate == null) {
345                            layoutTemplate = new LayoutTemplateImpl(
346                                    StringPool.BLANK, StringPool.BLANK);
347    
348                            List<String> columns = new ArrayList<>();
349    
350                            for (int i = 1; i <= 10; i++) {
351                                    columns.add(LayoutTypePortletConstants.COLUMN_PREFIX + i);
352                            }
353    
354                            layoutTemplate.setColumns(columns);
355                    }
356    
357                    return layoutTemplate;
358            }
359    
360            @Override
361            public String getLayoutTemplateId() {
362                    return GetterUtil.getString(
363                            getTypeSettingsProperty(
364                                    LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID));
365            }
366    
367            @Override
368            public String getModeAbout() {
369                    return getTypeSettingsProperty(LayoutTypePortletConstants.MODE_ABOUT);
370            }
371    
372            @Override
373            public String getModeConfig() {
374                    return getTypeSettingsProperty(LayoutTypePortletConstants.MODE_CONFIG);
375            }
376    
377            @Override
378            public String getModeEdit() {
379                    return getTypeSettingsProperty(LayoutTypePortletConstants.MODE_EDIT);
380            }
381    
382            @Override
383            public String getModeEditDefaults() {
384                    return getTypeSettingsProperty(
385                            LayoutTypePortletConstants.MODE_EDIT_DEFAULTS);
386            }
387    
388            @Override
389            public String getModeEditGuest() {
390                    return getTypeSettingsProperty(
391                            LayoutTypePortletConstants.MODE_EDIT_GUEST);
392            }
393    
394            @Override
395            public String getModeHelp() {
396                    return getTypeSettingsProperty(LayoutTypePortletConstants.MODE_HELP);
397            }
398    
399            @Override
400            public String getModePreview() {
401                    return getTypeSettingsProperty(LayoutTypePortletConstants.MODE_PREVIEW);
402            }
403    
404            @Override
405            public String getModePrint() {
406                    return getTypeSettingsProperty(LayoutTypePortletConstants.MODE_PRINT);
407            }
408    
409            @Override
410            public int getNumOfColumns() {
411                    return getLayoutTemplate().getColumns().size();
412            }
413    
414            @Override
415            public PortalPreferences getPortalPreferences() {
416                    return _portalPreferences;
417            }
418    
419            @Override
420            public List<String> getPortletIds() {
421                    List<String> portletIds = new ArrayList<>();
422    
423                    List<String> columns = getColumns();
424    
425                    for (int i = 0; i < columns.size(); i++) {
426                            String columnId = columns.get(i);
427    
428                            String columnValue = getColumnValue(columnId);
429    
430                            portletIds.addAll(
431                                    ListUtil.fromArray(StringUtil.split(columnValue)));
432                    }
433    
434                    return portletIds;
435            }
436    
437            @Override
438            public List<Portlet> getPortlets() {
439                    List<String> portletIds = getPortletIds();
440    
441                    List<Portlet> portlets = new ArrayList<>(portletIds.size());
442    
443                    for (int i = 0; i < portletIds.size(); i++) {
444                            String portletId = portletIds.get(i);
445    
446                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
447                                    getCompanyId(), portletId);
448    
449                            if (portlet != null) {
450                                    portlets.add(portlet);
451                            }
452                    }
453    
454                    return portlets;
455            }
456    
457            @Override
458            public String getStateMax() {
459                    return getTypeSettingsProperty(LayoutTypePortletConstants.STATE_MAX);
460            }
461    
462            @Override
463            public String getStateMaxPortletId() {
464                    String[] stateMax = StringUtil.split(getStateMax());
465    
466                    if (stateMax.length > 0) {
467                            return stateMax[0];
468                    }
469                    else {
470                            return StringPool.BLANK;
471                    }
472            }
473    
474            @Override
475            public String getStateMin() {
476                    return getTypeSettingsProperty(LayoutTypePortletConstants.STATE_MIN);
477            }
478    
479            @Override
480            public boolean hasDefaultScopePortletId(long groupId, String portletId) {
481                    if (hasPortletId(portletId)) {
482                            long scopeGroupId = PortalUtil.getScopeGroupId(
483                                    getLayout(), portletId);
484    
485                            if (groupId == scopeGroupId) {
486                                    return true;
487                            }
488                    }
489    
490                    return false;
491            }
492    
493            @Override
494            public boolean hasModeAboutPortletId(String portletId) {
495                    return StringUtil.contains(getModeAbout(), portletId);
496            }
497    
498            @Override
499            public boolean hasModeConfigPortletId(String portletId) {
500                    return StringUtil.contains(getModeConfig(), portletId);
501            }
502    
503            @Override
504            public boolean hasModeEditDefaultsPortletId(String portletId) {
505                    return StringUtil.contains(getModeEditDefaults(), portletId);
506            }
507    
508            @Override
509            public boolean hasModeEditGuestPortletId(String portletId) {
510                    return StringUtil.contains(getModeEditGuest(), portletId);
511            }
512    
513            @Override
514            public boolean hasModeEditPortletId(String portletId) {
515                    return StringUtil.contains(getModeEdit(), portletId);
516            }
517    
518            @Override
519            public boolean hasModeHelpPortletId(String portletId) {
520                    return StringUtil.contains(getModeHelp(), portletId);
521            }
522    
523            @Override
524            public boolean hasModePreviewPortletId(String portletId) {
525                    return StringUtil.contains(getModePreview(), portletId);
526            }
527    
528            @Override
529            public boolean hasModePrintPortletId(String portletId) {
530                    return StringUtil.contains(getModePrint(), portletId);
531            }
532    
533            @Override
534            public boolean hasModeViewPortletId(String portletId) {
535                    if (hasModeAboutPortletId(portletId) ||
536                            hasModeConfigPortletId(portletId) ||
537                            hasModeEditPortletId(portletId) ||
538                            hasModeEditDefaultsPortletId(portletId) ||
539                            hasModeEditGuestPortletId(portletId) ||
540                            hasModeHelpPortletId(portletId) ||
541                            hasModePreviewPortletId(portletId) ||
542                            hasModePrintPortletId(portletId)) {
543    
544                            return false;
545                    }
546                    else {
547                            return true;
548                    }
549            }
550    
551            @Override
552            public boolean hasPortletId(String portletId) {
553                    return hasPortletId(portletId, false);
554            }
555    
556            @Override
557            public boolean hasPortletId(String portletId, boolean strict) {
558                    List<String> columns = getColumns();
559    
560                    for (String columnId : columns) {
561                            if (hasNonstaticPortletId(columnId, portletId)) {
562                                    return true;
563                            }
564    
565                            if (hasStaticPortletId(columnId, portletId)) {
566                                    return true;
567                            }
568                    }
569    
570                    Layout layout = getLayout();
571    
572                    if (layout.isTypeControlPanel()) {
573                            return false;
574                    }
575    
576                    if (isCustomizable() && isCustomizedView()) {
577                            LayoutTypePortletImpl defaultLayoutTypePortletImpl =
578                                    getDefaultLayoutTypePortletImpl();
579    
580                            if (defaultLayoutTypePortletImpl.hasNonstaticPortletId(portletId)) {
581                                    return false;
582                            }
583                    }
584    
585                    if (!strict &&
586                            ((PortletPreferencesLocalServiceUtil.getPortletPreferencesCount(
587                                    PortletKeys.PREFS_OWNER_TYPE_LAYOUT, layout.getPlid(),
588                                    portletId) > 0) ||
589                             (PortletPreferencesLocalServiceUtil.getPortletPreferencesCount(
590                                     PortletKeys.PREFS_OWNER_TYPE_USER, layout.getPlid(),
591                                     portletId) > 0))) {
592    
593                            return true;
594                    }
595    
596                    return false;
597            }
598    
599            @Override
600            public boolean hasStateMax() {
601                    String[] stateMax = StringUtil.split(getStateMax());
602    
603                    if (stateMax.length > 0) {
604                            return true;
605                    }
606                    else {
607                            return false;
608                    }
609            }
610    
611            @Override
612            public boolean hasStateMaxPortletId(String portletId) {
613                    if (StringUtil.contains(getStateMax(), portletId)) {
614                            return true;
615                    }
616                    else {
617                            return false;
618                    }
619            }
620    
621            @Override
622            public boolean hasStateMin() {
623                    String[] stateMin = StringUtil.split(getStateMin());
624    
625                    if (stateMin.length > 0) {
626                            return true;
627                    }
628                    else {
629                            return false;
630                    }
631            }
632    
633            @Override
634            public boolean hasStateMinPortletId(String portletId) {
635                    if (StringUtil.contains(getStateMin(), portletId)) {
636                            return true;
637                    }
638                    else {
639                            return false;
640                    }
641            }
642    
643            @Override
644            public boolean hasStateNormalPortletId(String portletId) {
645                    if (hasStateMaxPortletId(portletId) ||
646                            hasStateMinPortletId(portletId)) {
647    
648                            return false;
649                    }
650                    else {
651                            return true;
652                    }
653            }
654    
655            @Override
656            public boolean hasUpdatePermission() {
657                    return _updatePermission;
658            }
659    
660            @Override
661            public boolean isCacheable() {
662                    List<Portlet> portlets = new ArrayList<>();
663    
664                    for (String columnId : getColumns()) {
665                            List<Portlet> columnPortlets = getAllPortlets(columnId);
666    
667                            for (Portlet portlet : columnPortlets) {
668                                    Portlet rootPortlet = portlet.getRootPortlet();
669    
670                                    if (!rootPortlet.isLayoutCacheable()) {
671                                            return false;
672                                    }
673                            }
674    
675                            portlets.addAll(columnPortlets);
676                    }
677    
678                    List<Portlet> staticPortlets = getStaticPortlets(
679                            PropsKeys.LAYOUT_STATIC_PORTLETS_ALL);
680    
681                    for (Portlet portlet : staticPortlets) {
682                            Portlet rootPortlet = portlet.getRootPortlet();
683    
684                            if (!rootPortlet.isLayoutCacheable()) {
685                                    return false;
686                            }
687                    }
688    
689                    List<Portlet> embeddedPortlets = getEmbeddedPortlets(
690                            portlets, staticPortlets);
691    
692                    for (Portlet portlet : embeddedPortlets) {
693                            Portlet rootPortlet = portlet.getRootPortlet();
694    
695                            if (!rootPortlet.isLayoutCacheable()) {
696                                    return false;
697                            }
698                    }
699    
700                    return true;
701            }
702    
703            @Override
704            public boolean isColumnCustomizable(String columnId) {
705                    if (!isLayoutSetPrototype()) {
706                            String customizableString = getTypeSettingsProperty(
707                                    CustomizedPages.namespaceColumnId(columnId));
708    
709                            boolean customizable = GetterUtil.getBoolean(customizableString);
710    
711                            if (!customizable && hasUserPreferences()) {
712                                    String columnValue = _portalPreferences.getValue(
713                                            CustomizedPages.namespacePlid(getPlid()), columnId,
714                                            StringPool.NULL);
715    
716                                    if (!Validator.equals(columnValue, StringPool.NULL)) {
717                                            setUserPreference(columnId, null);
718                                    }
719                            }
720    
721                            return customizable;
722                    }
723    
724                    return false;
725            }
726    
727            @Override
728            public boolean isColumnDisabled(String columnId) {
729                    if ((isCustomizedView() && !isColumnCustomizable(columnId)) ||
730                            (!isCustomizedView() && !hasUpdatePermission())) {
731    
732                            return true;
733                    }
734    
735                    return false;
736            }
737    
738            @Override
739            public boolean isCustomizable() {
740                    for (String columnId : getColumns()) {
741                            if (isColumnCustomizable(columnId)) {
742                                    return true;
743                            }
744                    }
745    
746                    return false;
747            }
748    
749            @Override
750            public boolean isCustomizedView() {
751                    return _customizedView;
752            }
753    
754            @Override
755            public boolean isDefaultUpdated() {
756                    if (!isCustomizedView() || !hasUserPreferences()) {
757                            return false;
758                    }
759    
760                    String preferencesModifiedDateString = _portalPreferences.getValue(
761                            CustomizedPages.namespacePlid(getPlid()), _MODIFIED_DATE,
762                            _NULL_DATE);
763    
764                    DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
765                            PropsValues.INDEX_DATE_FORMAT_PATTERN);
766    
767                    try {
768                            Date preferencesModifiedDate = dateFormat.parse(
769                                    preferencesModifiedDateString);
770    
771                            Layout layout = getLayout();
772    
773                            String propertiesModifiedDateString =
774                                    layout.getTypeSettingsProperty(_MODIFIED_DATE, _NULL_DATE);
775    
776                            Date propertiesModifiedDate = dateFormat.parse(
777                                    propertiesModifiedDateString);
778    
779                            return propertiesModifiedDate.after(preferencesModifiedDate);
780                    }
781                    catch (Exception e) {
782                            _log.error(e, e);
783                    }
784    
785                    return false;
786            }
787    
788            @Override
789            public boolean isPortletCustomizable(String portletId) {
790                    return isColumnCustomizable(getColumn(portletId));
791            }
792    
793            @Override
794            public boolean isPortletEmbedded(String portletId) {
795                    List<Portlet> embeddedPortlets = getEmbeddedPortlets();
796    
797                    for (Portlet embeddedPortlet : embeddedPortlets) {
798                            if (portletId.equals(embeddedPortlet.getPortletId())) {
799                                    return true;
800                            }
801                    }
802    
803                    return false;
804            }
805    
806            @Override
807            public void movePortletId(
808                    long userId, String portletId, String columnId, int columnPos) {
809    
810                    if (!hasPortletId(portletId)) {
811                            return;
812                    }
813    
814                    _enablePortletLayoutListener = false;
815    
816                    try {
817                            removePortletId(userId, portletId, false);
818                            addPortletId(userId, portletId, columnId, columnPos, false, true);
819                    }
820                    finally {
821                            _enablePortletLayoutListener = true;
822                    }
823    
824                    Layout layout = getLayout();
825    
826                    try {
827                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
828                                    layout.getCompanyId(), portletId);
829    
830                            if (portlet != null) {
831                                    PortletLayoutListener portletLayoutListener =
832                                            portlet.getPortletLayoutListenerInstance();
833    
834                                    if (portletLayoutListener != null) {
835                                            portletLayoutListener.onMoveInLayout(
836                                                    portletId, layout.getPlid());
837                                    }
838                            }
839                    }
840                    catch (Exception e) {
841                            _log.error("Unable to fire portlet layout listener event", e);
842                    }
843            }
844    
845            @Override
846            public void removeModeAboutPortletId(String portletId) {
847                    setModeAbout(StringUtil.removeFromList(getModeAbout(), portletId));
848            }
849    
850            @Override
851            public void removeModeConfigPortletId(String portletId) {
852                    setModeConfig(StringUtil.removeFromList(getModeConfig(), portletId));
853            }
854    
855            @Override
856            public void removeModeEditDefaultsPortletId(String portletId) {
857                    setModeEditDefaults(
858                            StringUtil.removeFromList(getModeEditDefaults(), portletId));
859            }
860    
861            @Override
862            public void removeModeEditGuestPortletId(String portletId) {
863                    setModeEditGuest(
864                            StringUtil.removeFromList(getModeEditGuest(), portletId));
865            }
866    
867            @Override
868            public void removeModeEditPortletId(String portletId) {
869                    setModeEdit(StringUtil.removeFromList(getModeEdit(), portletId));
870            }
871    
872            @Override
873            public void removeModeHelpPortletId(String portletId) {
874                    setModeHelp(StringUtil.removeFromList(getModeHelp(), portletId));
875            }
876    
877            @Override
878            public void removeModePreviewPortletId(String portletId) {
879                    setModePreview(StringUtil.removeFromList(getModePreview(), portletId));
880            }
881    
882            @Override
883            public void removeModePrintPortletId(String portletId) {
884                    setModePrint(StringUtil.removeFromList(getModePrint(), portletId));
885            }
886    
887            @Override
888            public void removeModesPortletId(String portletId) {
889                    removeModeAboutPortletId(portletId);
890                    removeModeConfigPortletId(portletId);
891                    removeModeEditPortletId(portletId);
892                    removeModeEditDefaultsPortletId(portletId);
893                    removeModeEditGuestPortletId(portletId);
894                    removeModeHelpPortletId(portletId);
895                    removeModePreviewPortletId(portletId);
896                    removeModePrintPortletId(portletId);
897            }
898    
899            @Override
900            public void removeNestedColumns(String portletNamespace) {
901                    UnicodeProperties typeSettingsProperties = getTypeSettingsProperties();
902    
903                    UnicodeProperties newTypeSettingsProperties = new UnicodeProperties();
904    
905                    for (Map.Entry<String, String> entry :
906                                    typeSettingsProperties.entrySet()) {
907    
908                            String key = entry.getKey();
909    
910                            if (!key.startsWith(portletNamespace)) {
911                                    newTypeSettingsProperties.setProperty(key, entry.getValue());
912                            }
913                    }
914    
915                    Layout layout = getLayout();
916    
917                    layout.setTypeSettingsProperties(newTypeSettingsProperties);
918    
919                    String nestedColumnIds = GetterUtil.getString(
920                            getTypeSettingsProperty(
921                                    LayoutTypePortletConstants.NESTED_COLUMN_IDS));
922    
923                    String[] nestedColumnIdsArray = ArrayUtil.removeByPrefix(
924                            StringUtil.split(nestedColumnIds), portletNamespace);
925    
926                    setTypeSettingsProperty(
927                            LayoutTypePortletConstants.NESTED_COLUMN_IDS,
928                            StringUtil.merge(nestedColumnIdsArray));
929            }
930    
931            @Override
932            public void removePortletId(long userId, String portletId) {
933                    removePortletId(userId, portletId, true);
934            }
935    
936            @Override
937            public void removePortletId(
938                    long userId, String portletId, boolean cleanUp) {
939    
940                    try {
941                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
942                                    getCompanyId(), portletId);
943    
944                            if (portlet == null) {
945                                    _log.error(
946                                            "Portlet " + portletId +
947                                                    " cannot be removed because it is not registered");
948    
949                                    return;
950                            }
951    
952                            PermissionChecker permissionChecker =
953                                    PermissionThreadLocal.getPermissionChecker();
954    
955                            if (!LayoutPermissionUtil.contains(
956                                            permissionChecker, getLayout(), ActionKeys.UPDATE) &&
957                                    !isCustomizable()) {
958    
959                                    return;
960                            }
961                    }
962                    catch (Exception e) {
963                            _log.error(e, e);
964    
965                            return;
966                    }
967    
968                    List<String> columns = getColumns();
969    
970                    for (int i = 0; i < columns.size(); i++) {
971                            String columnId = columns.get(i);
972    
973                            if (isCustomizable() && isColumnDisabled(columnId)) {
974                                    continue;
975                            }
976    
977                            String columnValue = StringPool.BLANK;
978    
979                            if (hasUserPreferences()) {
980                                    columnValue = getUserPreference(columnId);
981                            }
982                            else {
983                                    columnValue = getTypeSettingsProperty(columnId);
984                            }
985    
986                            columnValue = StringUtil.removeFromList(columnValue, portletId);
987    
988                            if (hasUserPreferences()) {
989                                    setUserPreference(columnId, columnValue);
990                            }
991                            else {
992                                    setTypeSettingsProperty(columnId, columnValue);
993                            }
994                    }
995    
996                    if (cleanUp) {
997                            try {
998                                    onRemoveFromLayout(new String[] {portletId});
999                            }
1000                            catch (Exception e) {
1001                                    _log.error(e, e);
1002                            }
1003                    }
1004            }
1005    
1006            @Override
1007            public void removeStateMaxPortletId(String portletId) {
1008                    setStateMax(StringUtil.removeFromList(getStateMax(), portletId));
1009            }
1010    
1011            @Override
1012            public void removeStateMinPortletId(String portletId) {
1013                    setStateMin(StringUtil.removeFromList(getStateMin(), portletId));
1014            }
1015    
1016            @Override
1017            public void removeStatesPortletId(String portletId) {
1018                    removeStateMaxPortletId(portletId);
1019                    removeStateMinPortletId(portletId);
1020            }
1021    
1022            @Override
1023            public void reorganizePortlets(
1024                    List<String> newColumns, List<String> oldColumns) {
1025    
1026                    String lastNewColumnId = newColumns.get(newColumns.size() - 1);
1027                    String lastNewColumnValue = getTypeSettingsProperty(lastNewColumnId);
1028    
1029                    for (String oldColumnId : oldColumns) {
1030                            if (!newColumns.contains(oldColumnId)) {
1031                                    String oldColumnValue = getTypeSettingsProperties().remove(
1032                                            oldColumnId);
1033    
1034                                    String[] portletIds = StringUtil.split(oldColumnValue);
1035    
1036                                    for (String portletId : portletIds) {
1037                                            lastNewColumnValue = StringUtil.add(
1038                                                    lastNewColumnValue, portletId);
1039                                    }
1040                            }
1041                    }
1042    
1043                    setTypeSettingsProperty(lastNewColumnId, lastNewColumnValue);
1044            }
1045    
1046            @Override
1047            public void resetModes() {
1048                    setModeAbout(StringPool.BLANK);
1049                    setModeConfig(StringPool.BLANK);
1050                    setModeEdit(StringPool.BLANK);
1051                    setModeEditDefaults(StringPool.BLANK);
1052                    setModeEditGuest(StringPool.BLANK);
1053                    setModeHelp(StringPool.BLANK);
1054                    setModePreview(StringPool.BLANK);
1055                    setModePrint(StringPool.BLANK);
1056            }
1057    
1058            @Override
1059            public void resetStates() {
1060                    setStateMax(StringPool.BLANK);
1061                    setStateMin(StringPool.BLANK);
1062            }
1063    
1064            @Override
1065            public void resetUserPreferences() {
1066                    if (!hasUserPreferences()) {
1067                            return;
1068                    }
1069    
1070                    long plid = getPlid();
1071    
1072                    Set<String> customPortletIds = new HashSet<>();
1073    
1074                    for (String columnId : getColumns()) {
1075                            String value = _portalPreferences.getValue(
1076                                    CustomizedPages.namespacePlid(plid), columnId);
1077    
1078                            for (String customPortletId : StringUtil.split(value)) {
1079                                    customPortletIds.add(customPortletId);
1080                            }
1081                    }
1082    
1083                    try {
1084                            onRemoveFromLayout(
1085                                    customPortletIds.toArray(new String[customPortletIds.size()]));
1086                    }
1087                    catch (Exception e) {
1088                            _log.error(e, e);
1089                    }
1090    
1091                    _portalPreferences.resetValues(CustomizedPages.namespacePlid(plid));
1092    
1093                    _portalPreferences.setValue(
1094                            CustomizedPages.namespacePlid(plid), _MODIFIED_DATE,
1095                            _dateFormat.format(new Date()));
1096            }
1097    
1098            @Override
1099            public void setCustomizedView(boolean customizedView) {
1100                    _customizedView = customizedView;
1101            }
1102    
1103            @Override
1104            public void setLayoutTemplateId(long userId, String newLayoutTemplateId) {
1105                    setLayoutTemplateId(userId, newLayoutTemplateId, true);
1106            }
1107    
1108            @Override
1109            public void setLayoutTemplateId(
1110                    long userId, String newLayoutTemplateId, boolean checkPermission) {
1111    
1112                    if (checkPermission &&
1113                            !PluginSettingLocalServiceUtil.hasPermission(
1114                                    userId, newLayoutTemplateId, Plugin.TYPE_LAYOUT_TEMPLATE)) {
1115    
1116                            return;
1117                    }
1118    
1119                    LayoutTemplate oldLayoutTemplate = getLayoutTemplate();
1120    
1121                    String themeId = getThemeId();
1122    
1123                    LayoutTemplate newLayoutTemplate =
1124                            LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1125                                    newLayoutTemplateId, false, themeId);
1126    
1127                    if (newLayoutTemplate == null) {
1128                            if (_log.isWarnEnabled()) {
1129                                    _log.warn(
1130                                            "Unable to find layout template " + newLayoutTemplateId);
1131                            }
1132    
1133                            return;
1134                    }
1135    
1136                    setTypeSettingsProperty(
1137                            LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID, newLayoutTemplateId);
1138    
1139                    List<String> oldColumns = oldLayoutTemplate.getColumns();
1140                    List<String> newColumns = newLayoutTemplate.getColumns();
1141    
1142                    reorganizePortlets(newColumns, oldColumns);
1143            }
1144    
1145            @Override
1146            public void setModeAbout(String modeAbout) {
1147                    setTypeSettingsProperty(
1148                            LayoutTypePortletConstants.MODE_ABOUT, modeAbout);
1149            }
1150    
1151            @Override
1152            public void setModeConfig(String modeConfig) {
1153                    setTypeSettingsProperty(
1154                            LayoutTypePortletConstants.MODE_CONFIG, modeConfig);
1155            }
1156    
1157            @Override
1158            public void setModeEdit(String modeEdit) {
1159                    setTypeSettingsProperty(LayoutTypePortletConstants.MODE_EDIT, modeEdit);
1160            }
1161    
1162            @Override
1163            public void setModeEditDefaults(String modeEditDefaults) {
1164                    setTypeSettingsProperty(
1165                            LayoutTypePortletConstants.MODE_EDIT_DEFAULTS, modeEditDefaults);
1166            }
1167    
1168            @Override
1169            public void setModeEditGuest(String modeEditGuest) {
1170                    setTypeSettingsProperty(
1171                            LayoutTypePortletConstants.MODE_EDIT_GUEST, modeEditGuest);
1172            }
1173    
1174            @Override
1175            public void setModeHelp(String modeHelp) {
1176                    setTypeSettingsProperty(LayoutTypePortletConstants.MODE_HELP, modeHelp);
1177            }
1178    
1179            @Override
1180            public void setModePreview(String modePreview) {
1181                    setTypeSettingsProperty(
1182                            LayoutTypePortletConstants.MODE_PREVIEW, modePreview);
1183            }
1184    
1185            @Override
1186            public void setModePrint(String modePrint) {
1187                    setTypeSettingsProperty(
1188                            LayoutTypePortletConstants.MODE_PRINT, modePrint);
1189            }
1190    
1191            @Override
1192            public void setPortalPreferences(PortalPreferences portalPreferences) {
1193                    _portalPreferences = portalPreferences;
1194            }
1195    
1196            @Override
1197            public void setStateMax(String stateMax) {
1198                    setTypeSettingsProperty(LayoutTypePortletConstants.STATE_MAX, stateMax);
1199            }
1200    
1201            @Override
1202            public void setStateMin(String stateMin) {
1203                    setTypeSettingsProperty(LayoutTypePortletConstants.STATE_MIN, stateMin);
1204            }
1205    
1206            @Override
1207            public void setUpdatePermission(boolean updatePermission) {
1208                    _updatePermission = updatePermission;
1209            }
1210    
1211            protected void addNestedColumn(String columnId) {
1212                    String nestedColumnIds = getTypeSettingsProperty(
1213                            LayoutTypePortletConstants.NESTED_COLUMN_IDS, StringPool.BLANK);
1214    
1215                    if (!nestedColumnIds.contains(columnId)) {
1216                            nestedColumnIds = StringUtil.add(nestedColumnIds, columnId);
1217    
1218                            setTypeSettingsProperty(
1219                                    LayoutTypePortletConstants.NESTED_COLUMN_IDS, nestedColumnIds);
1220                    }
1221            }
1222    
1223            protected String addPortletId(
1224                    long userId, String portletId, String columnId, int columnPos,
1225                    boolean checkPermission, boolean strictHasPortlet) {
1226    
1227                    portletId = JS.getSafeName(portletId);
1228    
1229                    Layout layout = getLayout();
1230    
1231                    Portlet portlet = null;
1232    
1233                    try {
1234                            portlet = PortletLocalServiceUtil.getPortletById(
1235                                    layout.getCompanyId(), portletId);
1236    
1237                            if (portlet == null) {
1238                                    if (_log.isWarnEnabled()) {
1239                                            _log.warn(
1240                                                    "Portlet " + portletId +
1241                                                            " cannot be added because it is not registered");
1242                                    }
1243    
1244                                    return null;
1245                            }
1246    
1247                            PermissionChecker permissionChecker =
1248                                    PermissionThreadLocal.getPermissionChecker();
1249    
1250                            if (checkPermission &&
1251                                    !PortletPermissionUtil.contains(
1252                                            permissionChecker, layout, portlet,
1253                                            ActionKeys.ADD_TO_PAGE)) {
1254    
1255                                    return null;
1256                            }
1257                    }
1258                    catch (Exception e) {
1259                            _log.error(e, e);
1260                    }
1261    
1262                    if (portlet.isSystem()) {
1263                            return null;
1264                    }
1265    
1266                    if (portlet.isInstanceable() &&
1267                            !PortletConstants.hasInstanceId(portletId)) {
1268    
1269                            portletId = PortletConstants.assemblePortletId(
1270                                    portletId, PortletConstants.generateInstanceId());
1271                    }
1272    
1273                    if (hasPortletId(portletId, strictHasPortlet)) {
1274                            return null;
1275                    }
1276    
1277                    if (columnId == null) {
1278                            LayoutTemplate layoutTemplate = getLayoutTemplate();
1279    
1280                            List<String> columns = layoutTemplate.getColumns();
1281    
1282                            if (!columns.isEmpty()) {
1283                                    columnId = columns.get(0);
1284                            }
1285                    }
1286    
1287                    if (columnId == null) {
1288                            return null;
1289                    }
1290    
1291                    if (isCustomizable()) {
1292                            if (isColumnDisabled(columnId)) {
1293                                    return null;
1294                            }
1295    
1296                            if ((PortletConstants.hasInstanceId(portletId) ||
1297                                     portlet.isPreferencesUniquePerLayout()) &&
1298                                    hasUserPreferences()) {
1299    
1300                                    portletId = PortletConstants.assemblePortletId(
1301                                            portletId, userId);
1302                            }
1303                    }
1304    
1305                    String columnValue = StringPool.BLANK;
1306    
1307                    if (hasUserPreferences()) {
1308                            columnValue = getUserPreference(columnId);
1309                    }
1310                    else {
1311                            columnValue = getTypeSettingsProperty(columnId);
1312                    }
1313    
1314                    if ((columnValue == null) &&
1315                            columnId.startsWith(_NESTED_PORTLETS_NAMESPACE)) {
1316    
1317                            addNestedColumn(columnId);
1318                    }
1319    
1320                    if (columnPos >= 0) {
1321                            List<String> portletIds = ListUtil.fromArray(
1322                                    StringUtil.split(columnValue));
1323    
1324                            if (columnPos <= portletIds.size()) {
1325                                    portletIds.add(columnPos, portletId);
1326                            }
1327                            else {
1328                                    portletIds.add(portletId);
1329                            }
1330    
1331                            columnValue = StringUtil.merge(portletIds);
1332                    }
1333                    else {
1334                            columnValue = StringUtil.add(columnValue, portletId);
1335                    }
1336    
1337                    if (hasUserPreferences()) {
1338                            setUserPreference(columnId, columnValue);
1339                    }
1340                    else {
1341                            setTypeSettingsProperty(columnId, columnValue);
1342                    }
1343    
1344                    try {
1345                            if (_enablePortletLayoutListener) {
1346                                    PortletLayoutListener portletLayoutListener =
1347                                            portlet.getPortletLayoutListenerInstance();
1348    
1349                                    if (portletLayoutListener != null) {
1350                                            portletLayoutListener.onAddToLayout(
1351                                                    portletId, layout.getPlid());
1352                                    }
1353                            }
1354                    }
1355                    catch (Exception e) {
1356                            _log.error("Unable to fire portlet layout listener event", e);
1357                    }
1358    
1359                    return portletId;
1360            }
1361    
1362            protected void copyPreferences(
1363                    long userId, String sourcePortletId, String targetPortletId) {
1364    
1365                    Layout layout = getLayout();
1366    
1367                    try {
1368                            PortletPreferencesIds portletPreferencesIds =
1369                                    PortletPreferencesFactoryUtil.getPortletPreferencesIds(
1370                                            layout.getGroupId(), 0, layout, sourcePortletId, false);
1371    
1372                            javax.portlet.PortletPreferences sourcePortletPreferences =
1373                                    PortletPreferencesLocalServiceUtil.getStrictPreferences(
1374                                            portletPreferencesIds);
1375    
1376                            portletPreferencesIds =
1377                                    PortletPreferencesFactoryUtil.getPortletPreferencesIds(
1378                                            layout.getGroupId(), userId, layout, targetPortletId,
1379                                            false);
1380    
1381                            PortletPreferencesLocalServiceUtil.updatePreferences(
1382                                    portletPreferencesIds.getOwnerId(),
1383                                    portletPreferencesIds.getOwnerType(),
1384                                    portletPreferencesIds.getPlid(),
1385                                    portletPreferencesIds.getPortletId(), sourcePortletPreferences);
1386                    }
1387                    catch (Exception e) {
1388                    }
1389            }
1390    
1391            protected String getColumn(String portletId) {
1392                    String portletIdColumnId = StringPool.BLANK;
1393    
1394                    List<String> columnIds = getColumns();
1395    
1396                    for (String columnId : columnIds) {
1397                            String columnValue = getColumnValue(columnId);
1398    
1399                            String[] portletIds = StringUtil.split(columnValue);
1400    
1401                            for (String columnPortletId : portletIds) {
1402                                    if (columnPortletId.equals(portletId)) {
1403                                            return columnId;
1404                                    }
1405    
1406                                    if (Validator.isNull(portletIdColumnId) &&
1407                                            PortletConstants.hasIdenticalRootPortletId(
1408                                                    columnPortletId, portletId)) {
1409    
1410                                            portletIdColumnId = columnId;
1411                                    }
1412                            }
1413                    }
1414    
1415                    return portletIdColumnId;
1416            }
1417    
1418            protected List<String> getColumns() {
1419                    List<String> columns = new ArrayList<>();
1420    
1421                    Layout layout = getLayout();
1422    
1423                    if (layout.isTypePortlet()) {
1424                            LayoutTemplate layoutTemplate = getLayoutTemplate();
1425    
1426                            columns.addAll(layoutTemplate.getColumns());
1427    
1428                            columns.addAll(getNestedColumns());
1429                    }
1430                    else if (layout.isTypePanel()) {
1431                            columns.add("panelSelectedPortlets");
1432                    }
1433    
1434                    return columns;
1435            }
1436    
1437            protected String getColumnValue(String columnId) {
1438                    if (hasUserPreferences() && isCustomizable() &&
1439                            !isColumnDisabled(columnId)) {
1440    
1441                            return getUserPreference(columnId);
1442                    }
1443    
1444                    return getTypeSettingsProperty(columnId);
1445            }
1446    
1447            protected long getCompanyId() {
1448                    Layout layout = getLayout();
1449    
1450                    return layout.getCompanyId();
1451            }
1452    
1453            protected LayoutTypePortletImpl getDefaultLayoutTypePortletImpl() {
1454                    if (!isCustomizedView()) {
1455                            return this;
1456                    }
1457    
1458                    LayoutTypePortletImpl defaultLayoutTypePortletImpl =
1459                            (LayoutTypePortletImpl)LayoutTypePortletFactoryUtil.create(
1460                                    getLayout());
1461    
1462                    defaultLayoutTypePortletImpl._embeddedPortlets = _embeddedPortlets;
1463                    defaultLayoutTypePortletImpl._layoutSetPrototypeLayout =
1464                            _layoutSetPrototypeLayout;
1465                    defaultLayoutTypePortletImpl._updatePermission = _updatePermission;
1466    
1467                    return defaultLayoutTypePortletImpl;
1468            }
1469    
1470            protected List<Portlet> getEmbeddedPortlets(
1471                    List<Portlet> columnPortlets, List<Portlet> staticPortlets) {
1472    
1473                    List<Portlet> portlets = new ArrayList<>();
1474    
1475                    Layout layout = getLayout();
1476    
1477                    List<PortletPreferences> portletPreferences =
1478                            PortletPreferencesLocalServiceUtil.getPortletPreferences(
1479                                    PortletKeys.PREFS_OWNER_ID_DEFAULT,
1480                                    PortletKeys.PREFS_OWNER_TYPE_LAYOUT, layout.getPlid());
1481    
1482                    if (isCustomizable() && hasUserPreferences()) {
1483                            portletPreferences = ListUtil.copy(portletPreferences);
1484    
1485                            portletPreferences.addAll(
1486                                    PortletPreferencesLocalServiceUtil.getPortletPreferences(
1487                                            _portalPreferences.getUserId(),
1488                                            PortletKeys.PREFS_OWNER_TYPE_USER, layout.getPlid()));
1489                    }
1490    
1491                    for (PortletPreferences portletPreference : portletPreferences) {
1492                            String portletId = portletPreference.getPortletId();
1493    
1494                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
1495                                    getCompanyId(), portletId);
1496    
1497                            if ((portlet == null) || columnPortlets.contains(portlet) ||
1498                                    staticPortlets.contains(portlet) || !portlet.isReady() ||
1499                                    portlet.isUndeployedPortlet() || !portlet.isActive()) {
1500    
1501                                    continue;
1502                            }
1503    
1504                            Portlet embeddedPortlet = portlet;
1505    
1506                            if (portlet.isInstanceable()) {
1507    
1508                                    // Instanceable portlets do not need to be cloned because they
1509                                    // are already cloned. See the method getPortletById in the
1510                                    // class PortletLocalServiceImpl and how it references the
1511                                    // method getClonedInstance in the class PortletImpl.
1512    
1513                            }
1514                            else {
1515                                    embeddedPortlet = (Portlet)embeddedPortlet.clone();
1516                            }
1517    
1518                            // We set embedded portlets as static on order to avoid adding the
1519                            // close and/or move icons.
1520    
1521                            embeddedPortlet.setStatic(true);
1522    
1523                            portlets.add(embeddedPortlet);
1524                    }
1525    
1526                    _embeddedPortlets = portlets;
1527    
1528                    return _embeddedPortlets;
1529            }
1530    
1531            protected List<Portlet> getExplicitlyAddedPortlets() {
1532                    List<Portlet> portlets = new ArrayList<>();
1533    
1534                    List<String> columns = getColumns();
1535    
1536                    for (int i = 0; i < columns.size(); i++) {
1537                            String columnId = columns.get(i);
1538    
1539                            portlets.addAll(getAllPortlets(columnId));
1540                    }
1541    
1542                    return portlets;
1543            }
1544    
1545            protected List<String> getNestedColumns() {
1546                    String nestedColumnIds = getTypeSettingsProperty(
1547                            LayoutTypePortletConstants.NESTED_COLUMN_IDS);
1548    
1549                    return ListUtil.fromArray(StringUtil.split(nestedColumnIds));
1550            }
1551    
1552            protected long getPlid() {
1553                    Layout layout = getLayout();
1554    
1555                    return layout.getPlid();
1556            }
1557    
1558            protected String[] getStaticPortletIds(String position) {
1559                    Layout layout = getLayout();
1560    
1561                    String selector1 = StringPool.BLANK;
1562    
1563                    Group group = null;
1564    
1565                    try {
1566                            group = layout.getGroup();
1567                    }
1568                    catch (PortalException e) {
1569                            _log.error("Unable to get group " + layout.getGroupId());
1570    
1571                            return new String[0];
1572                    }
1573    
1574                    if (group.isUser()) {
1575                            selector1 = LayoutTypePortletConstants.STATIC_PORTLET_USER_SELECTOR;
1576                    }
1577                    else if (group.isOrganization()) {
1578                            selector1 =
1579                                    LayoutTypePortletConstants.STATIC_PORTLET_ORGANIZATION_SELECTOR;
1580                    }
1581                    else if (group.isRegularSite()) {
1582                            selector1 =
1583                                    LayoutTypePortletConstants.STATIC_PORTLET_REGULAR_SITE_SELECTOR;
1584                    }
1585    
1586                    String selector2 = layout.getFriendlyURL();
1587    
1588                    String[] portletIds = PropsUtil.getArray(
1589                            position, new Filter(selector1, selector2));
1590    
1591                    for (int i = 0; i < portletIds.length; i++) {
1592                            portletIds[i] = JS.getSafeName(portletIds[i]);
1593                    }
1594    
1595                    return portletIds;
1596            }
1597    
1598            protected List<Portlet> getStaticPortlets(String position) {
1599                    String[] portletIds = getStaticPortletIds(position);
1600    
1601                    List<Portlet> portlets = new ArrayList<>();
1602    
1603                    for (String portletId : portletIds) {
1604                            if (Validator.isNull(portletId) ||
1605                                    hasNonstaticPortletId(portletId)) {
1606    
1607                                    continue;
1608                            }
1609    
1610                            Portlet portlet = PortletLocalServiceUtil.getPortletById(
1611                                    getCompanyId(), portletId);
1612    
1613                            if (portlet != null) {
1614                                    Portlet staticPortlet = portlet;
1615    
1616                                    if (portlet.isInstanceable()) {
1617    
1618                                            // Instanceable portlets do not need to be cloned because
1619                                            // they are already cloned. See the method getPortletById in
1620                                            // the class PortletLocalServiceImpl and how it references
1621                                            // the method getClonedInstance in the class PortletImpl.
1622    
1623                                    }
1624                                    else {
1625                                            staticPortlet = (Portlet)staticPortlet.clone();
1626                                    }
1627    
1628                                    staticPortlet.setStatic(true);
1629    
1630                                    if (position.startsWith("layout.static.portlets.start")) {
1631                                            staticPortlet.setStaticStart(true);
1632                                    }
1633    
1634                                    portlets.add(staticPortlet);
1635                            }
1636                    }
1637    
1638                    return portlets;
1639            }
1640    
1641            protected String getThemeId() {
1642                    String themeId = null;
1643    
1644                    try {
1645                            Layout layout = getLayout();
1646    
1647                            Theme theme = layout.getTheme();
1648    
1649                            if (theme != null) {
1650                                    themeId = theme.getThemeId();
1651                            }
1652                            else {
1653                                    themeId = layout.getThemeId();
1654                            }
1655                    }
1656                    catch (Exception e) {
1657                            _log.error(e, e);
1658                    }
1659    
1660                    return themeId;
1661            }
1662    
1663            protected String getUserPreference(String key) {
1664                    String value = StringPool.BLANK;
1665    
1666                    if (!hasUserPreferences()) {
1667                            return value;
1668                    }
1669    
1670                    value = _portalPreferences.getValue(
1671                            CustomizedPages.namespacePlid(getPlid()), key, StringPool.NULL);
1672    
1673                    if (!value.equals(StringPool.NULL)) {
1674                            return value;
1675                    }
1676    
1677                    value = getTypeSettingsProperty(key);
1678    
1679                    if (Validator.isNull(value)) {
1680                            return value;
1681                    }
1682    
1683                    List<String> newPortletIds = new ArrayList<>();
1684    
1685                    PermissionChecker permissionChecker =
1686                            PermissionThreadLocal.getPermissionChecker();
1687    
1688                    String[] portletIds = StringUtil.split(value);
1689    
1690                    for (String portletId : portletIds) {
1691                            try {
1692                                    String rootPortletId = PortletConstants.getRootPortletId(
1693                                            portletId);
1694    
1695                                    if (!PortletPermissionUtil.contains(
1696                                                    permissionChecker, rootPortletId,
1697                                                    ActionKeys.ADD_TO_PAGE)) {
1698    
1699                                            continue;
1700                                    }
1701                            }
1702                            catch (Exception e) {
1703                                    _log.error(e, e);
1704                            }
1705    
1706                            String newPortletId = null;
1707    
1708                            boolean preferencesUniquePerLayout = false;
1709    
1710                            try {
1711                                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
1712                                            getCompanyId(), portletId);
1713    
1714                                    preferencesUniquePerLayout =
1715                                            portlet.isPreferencesUniquePerLayout();
1716                            }
1717                            catch (SystemException se) {
1718                                    _log.error(se, se);
1719                            }
1720    
1721                            if (PortletConstants.hasInstanceId(portletId) ||
1722                                    preferencesUniquePerLayout) {
1723    
1724                                    String instanceId = null;
1725    
1726                                    if (PortletConstants.hasInstanceId(portletId)) {
1727                                            instanceId = PortletConstants.generateInstanceId();
1728                                    }
1729    
1730                                    newPortletId = PortletConstants.assemblePortletId(
1731                                            portletId, _portalPreferences.getUserId(), instanceId);
1732    
1733                                    copyPreferences(
1734                                            _portalPreferences.getUserId(), portletId, newPortletId);
1735                            }
1736                            else {
1737                                    newPortletId = portletId;
1738                            }
1739    
1740                            newPortletIds.add(newPortletId);
1741                    }
1742    
1743                    value = StringUtil.merge(newPortletIds);
1744    
1745                    setUserPreference(key, value);
1746    
1747                    return value;
1748            }
1749    
1750            protected boolean hasNonstaticPortletId(String portletId) {
1751                    LayoutTemplate layoutTemplate = getLayoutTemplate();
1752    
1753                    List<String> columns = layoutTemplate.getColumns();
1754    
1755                    for (int i = 0; i < columns.size(); i++) {
1756                            String columnId = columns.get(i);
1757    
1758                            if (hasNonstaticPortletId(columnId, portletId)) {
1759                                    return true;
1760                            }
1761                    }
1762    
1763                    return false;
1764            }
1765    
1766            protected boolean hasNonstaticPortletId(String columnId, String portletId) {
1767                    String columnValue = getColumnValue(columnId);
1768    
1769                    String[] columnValues = StringUtil.split(columnValue);
1770    
1771                    for (String nonstaticPortletId : columnValues) {
1772                            if (nonstaticPortletId.equals(portletId) ||
1773                                    PortletConstants.getRootPortletId(
1774                                            nonstaticPortletId).equals(portletId)) {
1775    
1776                                    return true;
1777                            }
1778                    }
1779    
1780                    return false;
1781            }
1782    
1783            protected boolean hasStaticPortletId(String columnId, String portletId) {
1784                    String[] staticPortletIdsStart = getStaticPortletIds(
1785                            PropsKeys.LAYOUT_STATIC_PORTLETS_START + columnId);
1786    
1787                    String[] staticPortletIdsEnd = getStaticPortletIds(
1788                            PropsKeys.LAYOUT_STATIC_PORTLETS_END + columnId);
1789    
1790                    for (String staticPortletId : staticPortletIdsStart) {
1791                            if (staticPortletId.equals(portletId) ||
1792                                    PortletConstants.getRootPortletId(
1793                                            staticPortletId).equals(portletId)) {
1794    
1795                                    return true;
1796                            }
1797                    }
1798    
1799                    for (String staticPortletId : staticPortletIdsEnd) {
1800                            if (staticPortletId.equals(portletId) ||
1801                                    PortletConstants.getRootPortletId(
1802                                            staticPortletId).equals(portletId)) {
1803    
1804                                    return true;
1805                            }
1806                    }
1807    
1808                    return false;
1809            }
1810    
1811            protected boolean hasUserPreferences() {
1812                    if (_portalPreferences != null) {
1813                            return true;
1814                    }
1815    
1816                    return false;
1817            }
1818    
1819            protected boolean isLayoutSetPrototype() {
1820                    try {
1821                            Layout layout = getLayout();
1822    
1823                            LayoutSet layoutSet = layout.getLayoutSet();
1824    
1825                            Group group = layoutSet.getGroup();
1826    
1827                            return group.isLayoutSetPrototype();
1828                    }
1829                    catch (Exception e) {
1830                            _log.error(e, e);
1831                    }
1832    
1833                    return false;
1834            }
1835    
1836            protected void onRemoveFromLayout(String[] portletIds) {
1837                    Set<String> portletIdList = new HashSet<>();
1838    
1839                    for (String portletId : portletIds) {
1840                            removeModesPortletId(portletId);
1841                            removeStatesPortletId(portletId);
1842    
1843                            portletIdList.add(portletId);
1844    
1845                            String rootPortletId = PortletConstants.getRootPortletId(portletId);
1846    
1847                            if (rootPortletId.equals(PortletKeys.NESTED_PORTLETS)) {
1848                                    String portletNamespace = PortalUtil.getPortletNamespace(
1849                                            portletId);
1850    
1851                                    UnicodeProperties typeSettingsProperties =
1852                                            getTypeSettingsProperties();
1853    
1854                                    for (Map.Entry<String, String> entry :
1855                                                    typeSettingsProperties.entrySet()) {
1856    
1857                                            String key = entry.getKey();
1858    
1859                                            if (!key.startsWith(portletNamespace)) {
1860                                                    continue;
1861                                            }
1862    
1863                                            String nestedPortletIds = entry.getValue();
1864    
1865                                            for (String nestedPortletId :
1866                                                            StringUtil.split(nestedPortletIds)) {
1867    
1868                                                    removeModesPortletId(nestedPortletId);
1869                                                    removeStatesPortletId(nestedPortletId);
1870    
1871                                                    portletIdList.add(nestedPortletId);
1872                                            }
1873                                    }
1874    
1875                                    removeNestedColumns(portletNamespace);
1876                            }
1877    
1878                            Portlet portlet = PortletLocalServiceUtil.getPortletById(portletId);
1879    
1880                            if (portlet == null) {
1881                                    continue;
1882                            }
1883    
1884                            PortletLayoutListener portletLayoutListener =
1885                                    portlet.getPortletLayoutListenerInstance();
1886    
1887                            if (portletLayoutListener == null) {
1888                                    continue;
1889                            }
1890    
1891                            portletLayoutListener.updatePropertiesOnRemoveFromLayout(
1892                                    portletId, getTypeSettingsProperties());
1893                    }
1894    
1895                    try {
1896                            PortletLocalServiceUtil.deletePortlets(
1897                                    getCompanyId(),
1898                                    portletIdList.toArray(new String[portletIdList.size()]),
1899                                    getPlid());
1900                    }
1901                    catch (PortalException pe) {
1902                            _log.error(pe, pe);
1903                    }
1904            }
1905    
1906            protected void setUserPreference(String key, String value) {
1907                    if (!hasUserPreferences()) {
1908                            return;
1909                    }
1910    
1911                    _portalPreferences.setValue(
1912                            CustomizedPages.namespacePlid(getPlid()), key, value);
1913    
1914                    _portalPreferences.setValue(
1915                            CustomizedPages.namespacePlid(getPlid()), _MODIFIED_DATE,
1916                            _dateFormat.format(new Date()));
1917            }
1918    
1919            private static final String _MODIFIED_DATE = "modifiedDate";
1920    
1921            private static final String _NESTED_PORTLETS_NAMESPACE =
1922                    PortalUtil.getPortletNamespace(PortletKeys.NESTED_PORTLETS);
1923    
1924            private static final String _NULL_DATE = "00000000000000";
1925    
1926            private static final Log _log = LogFactoryUtil.getLog(
1927                    LayoutTypePortletImpl.class);
1928    
1929            private boolean _customizedView;
1930            private final Format _dateFormat =
1931                    FastDateFormatFactoryUtil.getSimpleDateFormat(
1932                            PropsValues.INDEX_DATE_FORMAT_PATTERN);
1933            private transient List<Portlet> _embeddedPortlets;
1934            private boolean _enablePortletLayoutListener = true;
1935            private Layout _layoutSetPrototypeLayout;
1936            private PortalPreferences _portalPreferences;
1937            private boolean _updatePermission;
1938    
1939    }