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