1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.lar;
24  
25  import com.liferay.counter.service.CounterLocalServiceUtil;
26  import com.liferay.portal.LARFileException;
27  import com.liferay.portal.LARTypeException;
28  import com.liferay.portal.LayoutImportException;
29  import com.liferay.portal.NoSuchLayoutException;
30  import com.liferay.portal.PortalException;
31  import com.liferay.portal.SystemException;
32  import com.liferay.portal.comm.CommLink;
33  import com.liferay.portal.kernel.log.Log;
34  import com.liferay.portal.kernel.log.LogFactoryUtil;
35  import com.liferay.portal.kernel.util.ArrayUtil;
36  import com.liferay.portal.kernel.util.FileUtil;
37  import com.liferay.portal.kernel.util.GetterUtil;
38  import com.liferay.portal.kernel.util.LocaleUtil;
39  import com.liferay.portal.kernel.util.MapUtil;
40  import com.liferay.portal.kernel.util.MethodWrapper;
41  import com.liferay.portal.kernel.util.ReleaseInfo;
42  import com.liferay.portal.kernel.util.StringPool;
43  import com.liferay.portal.kernel.util.StringUtil;
44  import com.liferay.portal.kernel.util.Time;
45  import com.liferay.portal.kernel.util.UnicodeProperties;
46  import com.liferay.portal.kernel.util.Validator;
47  import com.liferay.portal.kernel.xml.Document;
48  import com.liferay.portal.kernel.xml.DocumentException;
49  import com.liferay.portal.kernel.xml.Element;
50  import com.liferay.portal.kernel.xml.SAXReaderUtil;
51  import com.liferay.portal.kernel.zip.ZipReader;
52  import com.liferay.portal.model.Group;
53  import com.liferay.portal.model.GroupConstants;
54  import com.liferay.portal.model.Layout;
55  import com.liferay.portal.model.LayoutConstants;
56  import com.liferay.portal.model.LayoutSet;
57  import com.liferay.portal.model.LayoutTemplate;
58  import com.liferay.portal.model.LayoutTypePortlet;
59  import com.liferay.portal.model.Portlet;
60  import com.liferay.portal.model.PortletConstants;
61  import com.liferay.portal.model.Resource;
62  import com.liferay.portal.model.ResourceConstants;
63  import com.liferay.portal.model.Role;
64  import com.liferay.portal.model.User;
65  import com.liferay.portal.model.impl.ColorSchemeImpl;
66  import com.liferay.portal.model.impl.LayoutTypePortletImpl;
67  import com.liferay.portal.service.GroupLocalServiceUtil;
68  import com.liferay.portal.service.ImageLocalServiceUtil;
69  import com.liferay.portal.service.LayoutLocalServiceUtil;
70  import com.liferay.portal.service.LayoutSetLocalServiceUtil;
71  import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
72  import com.liferay.portal.service.PermissionLocalServiceUtil;
73  import com.liferay.portal.service.PortletLocalServiceUtil;
74  import com.liferay.portal.service.RoleLocalServiceUtil;
75  import com.liferay.portal.service.permission.PortletPermissionUtil;
76  import com.liferay.portal.service.persistence.LayoutUtil;
77  import com.liferay.portal.service.persistence.UserUtil;
78  import com.liferay.portal.theme.ThemeLoader;
79  import com.liferay.portal.theme.ThemeLoaderFactory;
80  import com.liferay.portal.util.PortalUtil;
81  import com.liferay.portal.util.PortletKeys;
82  import com.liferay.portal.util.PropsValues;
83  import com.liferay.portlet.journal.model.JournalArticle;
84  import com.liferay.util.LocalizationUtil;
85  
86  import java.io.ByteArrayInputStream;
87  import java.io.IOException;
88  import java.io.InputStream;
89  
90  import java.util.ArrayList;
91  import java.util.Date;
92  import java.util.HashSet;
93  import java.util.Iterator;
94  import java.util.List;
95  import java.util.Locale;
96  import java.util.Map;
97  import java.util.Set;
98  
99  import org.apache.commons.lang.time.StopWatch;
100 
101 /**
102  * <a href="LayoutImporter.java.html"><b><i>View Source</i></b></a>
103  *
104  * @author Brian Wing Shun Chan
105  * @author Joel Kozikowski
106  * @author Charles May
107  * @author Raymond Augé
108  * @author Jorge Ferrer
109  * @author Bruno Farache
110  *
111  */
112 public class LayoutImporter {
113 
114     public void importLayouts(
115             long userId, long groupId, boolean privateLayout,
116             Map<String, String[]> parameterMap, InputStream is)
117         throws PortalException, SystemException {
118 
119         boolean deleteMissingLayouts = MapUtil.getBoolean(
120             parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
121             Boolean.TRUE.booleanValue());
122         boolean deletePortletData = MapUtil.getBoolean(
123             parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
124         boolean importPermissions = MapUtil.getBoolean(
125             parameterMap, PortletDataHandlerKeys.PERMISSIONS);
126         boolean importUserPermissions = MapUtil.getBoolean(
127             parameterMap, PortletDataHandlerKeys.PERMISSIONS);
128         boolean importPortletData = MapUtil.getBoolean(
129             parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
130         boolean importPortletSetup = MapUtil.getBoolean(
131             parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
132         boolean importPortletArchivedSetups = MapUtil.getBoolean(
133             parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
134         boolean importPortletUserPreferences = MapUtil.getBoolean(
135             parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
136         boolean importTheme = MapUtil.getBoolean(
137             parameterMap, PortletDataHandlerKeys.THEME);
138         String layoutsImportMode = MapUtil.getString(
139             parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
140             PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_ID);
141         String portletsMergeMode = MapUtil.getString(
142             parameterMap, PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
143             PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
144         String userIdStrategy = MapUtil.getString(
145             parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
146 
147         if (_log.isDebugEnabled()) {
148             _log.debug("Delete portlet data " + deletePortletData);
149             _log.debug("Import permissions " + importPermissions);
150             _log.debug("Import user permissions " + importUserPermissions);
151             _log.debug("Import portlet data " + importPortletData);
152             _log.debug("Import portlet setup " + importPortletSetup);
153             _log.debug(
154                 "Import portlet archived setups " +
155                     importPortletArchivedSetups);
156             _log.debug(
157                 "Import portlet user preferences " +
158                     importPortletUserPreferences);
159             _log.debug("Import theme " + importTheme);
160         }
161 
162         StopWatch stopWatch = null;
163 
164         if (_log.isInfoEnabled()) {
165             stopWatch = new StopWatch();
166 
167             stopWatch.start();
168         }
169 
170         LayoutCache layoutCache = new LayoutCache();
171 
172         LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
173             groupId, privateLayout);
174 
175         long companyId = layoutSet.getCompanyId();
176 
177         User user = UserUtil.findByPrimaryKey(userId);
178 
179         UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
180             user, userIdStrategy);
181 
182         ZipReader zipReader = new ZipReader(is);
183 
184         PortletDataContext context = new PortletDataContextImpl(
185             companyId, groupId, parameterMap, new HashSet<String>(), strategy,
186             zipReader);
187 
188         Group guestGroup = GroupLocalServiceUtil.getGroup(
189             companyId, GroupConstants.GUEST);
190 
191         // Zip
192 
193         Element root = null;
194         byte[] themeZip = null;
195 
196         // Manifest
197 
198         String xml = context.getZipEntryAsString("/manifest.xml");
199 
200         if (xml == null) {
201             throw new LARFileException("manifest.xml not found in the LAR");
202         }
203 
204         try {
205             Document doc = SAXReaderUtil.read(xml);
206 
207             root = doc.getRootElement();
208         }
209         catch (Exception e) {
210             throw new LARFileException(e);
211         }
212 
213         // Build compatibility
214 
215         Element header = root.element("header");
216 
217         int buildNumber = ReleaseInfo.getBuildNumber();
218 
219         int importBuildNumber = GetterUtil.getInteger(
220             header.attributeValue("build-number"));
221 
222         if (buildNumber != importBuildNumber) {
223             throw new LayoutImportException(
224                 "LAR build number " + importBuildNumber + " does not match " +
225                     "portal build number " + buildNumber);
226         }
227 
228         // Type compatibility
229 
230         String larType = header.attributeValue("type");
231 
232         if (!larType.equals("layout-set")) {
233             throw new LARTypeException(
234                 "Invalid type of LAR file (" + larType + ")");
235         }
236 
237         // Import GroupId
238 
239         long importGroupId = GetterUtil.getLong(
240             header.attributeValue("group-id"));
241 
242         context.setImportGroupId(importGroupId);
243 
244         // Look and feel
245 
246         if (importTheme) {
247             themeZip = context.getZipEntryAsByteArray("theme.zip");
248         }
249 
250         // Look and feel
251 
252         String themeId = header.attributeValue("theme-id");
253         String colorSchemeId = header.attributeValue("color-scheme-id");
254 
255         boolean useThemeZip = false;
256 
257         if (themeZip != null) {
258             try {
259                 String importThemeId = importTheme(layoutSet, themeZip);
260 
261                 if (importThemeId != null) {
262                     themeId = importThemeId;
263                     colorSchemeId =
264                         ColorSchemeImpl.getDefaultRegularColorSchemeId();
265 
266                     useThemeZip = true;
267                 }
268 
269                 if (_log.isDebugEnabled()) {
270                     _log.debug(
271                         "Importing theme takes " + stopWatch.getTime() + " ms");
272                 }
273             }
274             catch (Exception e) {
275                 throw new SystemException(e);
276             }
277         }
278 
279         boolean wapTheme = false;
280 
281         LayoutSetLocalServiceUtil.updateLookAndFeel(
282             groupId, privateLayout, themeId, colorSchemeId, StringPool.BLANK,
283             wapTheme);
284 
285         // Read comments, ratings, and tags to make them available to the data
286         // handlers through the context
287 
288         _portletImporter.readComments(context, root);
289         _portletImporter.readRatings(context, root);
290         _portletImporter.readTags(context, root);
291 
292         // Layouts
293 
294         List<Layout> previousLayouts = LayoutUtil.findByG_P(
295             groupId, privateLayout);
296 
297         List<Layout> newLayouts = new ArrayList<Layout>();
298 
299         Set<Long> newLayoutIds = new HashSet<Long>();
300 
301         Map<Long, Long> newLayoutIdPlidMap =
302             (Map<Long, Long>)context.getNewPrimaryKeysMap(Layout.class);
303 
304         List<Element> layoutEls = root.element("layouts").elements("layout");
305 
306         if (_log.isDebugEnabled()) {
307             if (layoutEls.size() > 0) {
308                 _log.debug("Importing layouts");
309             }
310         }
311 
312         for (Element layoutRefEl : layoutEls) {
313             long layoutId = GetterUtil.getInteger(
314                 layoutRefEl.attributeValue("layout-id"));
315 
316             long oldLayoutId = layoutId;
317 
318             String layoutPath = layoutRefEl.attributeValue("path");
319 
320             Element layoutEl = null;
321 
322             try {
323                 Document layoutDoc = SAXReaderUtil.read(
324                     context.getZipEntryAsString(layoutPath));
325 
326                 layoutEl = layoutDoc.getRootElement();
327             }
328             catch (DocumentException de) {
329                 throw new SystemException(de);
330             }
331 
332             long parentLayoutId = GetterUtil.getInteger(
333                 layoutEl.elementText("parent-layout-id"));
334 
335             if (_log.isDebugEnabled()) {
336                 _log.debug(
337                     "Importing layout with layout id " + layoutId +
338                         " and parent layout id " + parentLayoutId);
339             }
340 
341             long oldPlid = GetterUtil.getInteger(
342                 layoutEl.attributeValue("old-plid"));
343 
344             String name = layoutEl.elementText("name");
345             String title = layoutEl.elementText("title");
346             String description = layoutEl.elementText("description");
347             String type = layoutEl.elementText("type");
348             String typeSettings = layoutEl.elementText("type-settings");
349             boolean hidden = GetterUtil.getBoolean(
350                 layoutEl.elementText("hidden"));
351             String friendlyURL = layoutEl.elementText("friendly-url");
352             boolean iconImage = GetterUtil.getBoolean(
353                 layoutEl.elementText("icon-image"));
354 
355             byte[] iconBytes = null;
356 
357             if (iconImage) {
358                 String path = layoutEl.elementText("icon-image-path");
359 
360                 iconBytes = context.getZipEntryAsByteArray(path);
361             }
362 
363             if (useThemeZip) {
364                 themeId = StringPool.BLANK;
365                 colorSchemeId = StringPool.BLANK;
366             }
367             else {
368                 themeId = layoutEl.elementText("theme-id");
369                 colorSchemeId = layoutEl.elementText("color-scheme-id");
370             }
371 
372             String wapThemeId = layoutEl.elementText("wap-theme-id");
373             String wapColorSchemeId = layoutEl.elementText(
374                 "wap-color-scheme-id");
375             String css = layoutEl.elementText("css");
376             int priority = GetterUtil.getInteger(
377                 layoutEl.elementText("priority"));
378 
379             Layout layout = null;
380 
381             if (layoutsImportMode.equals(
382                     PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
383 
384                 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
385                     groupId, privateLayout);
386                 friendlyURL = StringPool.SLASH + layoutId;
387             }
388             else if (layoutsImportMode.equals(
389                     PortletDataHandlerKeys.
390                         LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
391 
392                 Locale locale = LocaleUtil.getDefault();
393 
394                 String localizedName = LocalizationUtil.getLocalization(
395                     name, LocaleUtil.toLanguageId(locale));
396 
397                 for (Layout curLayout : previousLayouts) {
398                     if (curLayout.getName(locale).equals(localizedName)) {
399                         layout = curLayout;
400 
401                         break;
402                     }
403                 }
404 
405                 if (layout == null) {
406                     layoutId = LayoutLocalServiceUtil.getNextLayoutId(
407                         groupId, privateLayout);
408                 }
409             }
410             else {
411                 layout = LayoutUtil.fetchByG_P_L(
412                     groupId, privateLayout, layoutId);
413             }
414 
415             if (_log.isDebugEnabled()) {
416                 if (layout == null) {
417                     _log.debug(
418                         "Layout with {groupId=" + groupId + ",privateLayout=" +
419                             privateLayout + ",layoutId=" + layoutId +
420                                 "} does not exist");
421                 }
422                 else {
423                     _log.debug(
424                         "Layout with {groupId=" + groupId + ",privateLayout=" +
425                             privateLayout + ",layoutId=" + layoutId +
426                                 "} exists");
427                 }
428             }
429 
430             if (layout == null) {
431                 long plid = CounterLocalServiceUtil.increment();
432 
433                 layout = LayoutUtil.create(plid);
434 
435                 layout.setGroupId(groupId);
436                 layout.setPrivateLayout(privateLayout);
437                 layout.setLayoutId(layoutId);
438             }
439 
440             layout.setCompanyId(user.getCompanyId());
441             layout.setParentLayoutId(parentLayoutId);
442             layout.setName(name);
443             layout.setTitle(title);
444             layout.setDescription(description);
445             layout.setType(type);
446 
447             if (layout.getType().equals(LayoutConstants.TYPE_PORTLET) &&
448                     Validator.isNotNull(layout.getTypeSettings()) &&
449                         !portletsMergeMode.equals(
450                             PortletDataHandlerKeys.
451                                 PORTLETS_MERGE_MODE_REPLACE)) {
452                 mergePortlets(layout, typeSettings, portletsMergeMode);
453             }
454             else {
455                 layout.setTypeSettings(typeSettings);
456             }
457 
458             layout.setHidden(hidden);
459             layout.setFriendlyURL(friendlyURL);
460 
461             if (iconImage) {
462                 layout.setIconImage(iconImage);
463 
464                 if (layout.isNew()) {
465                     long iconImageId = CounterLocalServiceUtil.increment();
466 
467                     layout.setIconImageId(iconImageId);
468                 }
469             }
470 
471             layout.setThemeId(themeId);
472             layout.setColorSchemeId(colorSchemeId);
473             layout.setWapThemeId(wapThemeId);
474             layout.setWapColorSchemeId(wapColorSchemeId);
475             layout.setCss(css);
476             layout.setPriority(priority);
477 
478             fixTypeSettings(layout);
479 
480             LayoutUtil.update(layout, false);
481 
482             if ((iconBytes != null) && (iconBytes.length > 0)) {
483                 ImageLocalServiceUtil.updateImage(
484                     layout.getIconImageId(), iconBytes);
485             }
486 
487             context.setPlid(layout.getPlid());
488             context.setOldPlid(oldPlid);
489 
490             newLayoutIdPlidMap.put(oldLayoutId, layout.getPlid());
491 
492             newLayoutIds.add(layoutId);
493 
494             newLayouts.add(layout);
495 
496             Element permissionsEl = layoutEl.element("permissions");
497 
498             // Layout permissions
499 
500             if (importPermissions && (permissionsEl != null)) {
501                 String resourceName = Layout.class.getName();
502                 String resourcePrimKey = String.valueOf(layout.getPlid());
503 
504                 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
505                     importLayoutPermissions_5(
506                         layoutCache, companyId, groupId, userId, resourceName,
507                         resourcePrimKey, permissionsEl);
508                 }
509                 else {
510                     importLayoutPermissions_4(
511                         layoutCache, companyId, groupId, guestGroup, layout,
512                         resourceName, resourcePrimKey, permissionsEl,
513                         importUserPermissions);
514                 }
515             }
516 
517             _portletImporter.importPortletData(
518                 context, PortletKeys.LAYOUT_CONFIGURATION, null, layoutEl);
519         }
520 
521         List<Element> portletEls = root.element("portlets").elements("portlet");
522 
523         // Delete portlet data
524 
525         if (deletePortletData) {
526             if (_log.isDebugEnabled()) {
527                 if (portletEls.size() > 0) {
528                     _log.debug("Deleting portlet data");
529                 }
530             }
531 
532             for (Element portletRefEl : portletEls) {
533                 String portletId = portletRefEl.attributeValue("portlet-id");
534                 long layoutId = GetterUtil.getLong(
535                     portletRefEl.attributeValue("layout-id"));
536                 long plid = newLayoutIdPlidMap.get(layoutId);
537 
538                 context.setPlid(plid);
539 
540                 _portletImporter.deletePortletData(context, portletId, plid);
541             }
542         }
543 
544         // Import portlets
545 
546         if (_log.isDebugEnabled()) {
547             if (portletEls.size() > 0) {
548                 _log.debug("Importing portlets");
549             }
550         }
551 
552         for (Element portletRefEl : portletEls) {
553             String portletPath = portletRefEl.attributeValue("path");
554             String portletId = portletRefEl.attributeValue("portlet-id");
555             long layoutId = GetterUtil.getLong(
556                 portletRefEl.attributeValue("layout-id"));
557             long plid = newLayoutIdPlidMap.get(layoutId);
558             long oldPlid = GetterUtil.getLong(
559                 portletRefEl.attributeValue("old-plid"));
560 
561             Layout layout = LayoutUtil.findByPrimaryKey(plid);
562 
563             context.setPlid(plid);
564             context.setOldPlid(oldPlid);
565 
566             Element portletEl = null;
567 
568             try {
569                 Document portletDoc = SAXReaderUtil.read(
570                     context.getZipEntryAsString(portletPath));
571 
572                 portletEl = portletDoc.getRootElement();
573             }
574             catch (DocumentException de) {
575                 throw new SystemException(de);
576             }
577 
578             // The order of the import is important. You must always import
579             // the portlet preferences first, then the portlet data, then
580             // the portlet permissions. The import of the portlet data
581             // assumes that portlet preferences already exist.
582 
583             // Portlet preferences
584 
585             _portletImporter.importPortletPreferences(
586                 context, layoutSet.getCompanyId(), layout.getGroupId(),
587                 layout.getPlid(), null, portletEl, importPortletSetup,
588                 importPortletArchivedSetups, importPortletUserPreferences);
589 
590             // Portlet data
591 
592             Element portletDataEl = portletEl.element("portlet-data");
593 
594             if (importPortletData && portletDataEl != null) {
595                 _portletImporter.importPortletData(
596                     context, portletId, plid, portletDataEl);
597             }
598 
599             // Portlet permissions
600 
601             Element permissionsEl = portletEl.element("permissions");
602 
603             if (importPermissions && (permissionsEl != null)) {
604                 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
605                     String resourceName = PortletConstants.getRootPortletId(
606                         portletId);
607 
608                     String resourcePrimKey =
609                         PortletPermissionUtil.getPrimaryKey(
610                             layout.getPlid(), portletId);
611 
612                     importPortletPermissions_5(
613                         layoutCache, companyId, groupId, userId, resourceName,
614                         resourcePrimKey, permissionsEl);
615                 }
616                 else {
617                     importPortletPermissions_4(
618                         layoutCache, companyId, groupId, guestGroup, layout,
619                         permissionsEl, importUserPermissions);
620                 }
621             }
622 
623             // Archived setups
624 
625             _portletImporter.importPortletPreferences(
626                 context, layoutSet.getCompanyId(), groupId, 0, null, portletEl,
627                 importPortletSetup, importPortletArchivedSetups,
628                 importPortletUserPreferences);
629 
630             if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM != 5) {
631 
632                 // Portlet roles
633 
634                 Element rolesEl = portletEl.element("roles");
635 
636                 if (importPermissions && (rolesEl != null)) {
637                     importPortletRoles(
638                         layoutCache, companyId, groupId, portletEl);
639 
640                     importPortletRoles(
641                         layoutCache, companyId, groupId, portletId, rolesEl);
642                 }
643             }
644         }
645 
646         if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM != 5) {
647             Element rolesEl = root.element("roles");
648 
649             // Layout roles
650 
651             if (importPermissions) {
652                 importLayoutRoles(layoutCache, companyId, groupId, rolesEl);
653             }
654         }
655 
656         // Delete missing layouts
657 
658         if (deleteMissingLayouts) {
659             deleteMissingLayouts(
660                 groupId, privateLayout, newLayoutIds, previousLayouts);
661         }
662 
663         // Page count
664 
665         LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
666 
667         if (_log.isInfoEnabled()) {
668             _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
669         }
670 
671         // Article layout type
672 
673         for (Layout layout : newLayouts) {
674             UnicodeProperties typeSettingsProperties =
675                 layout.getTypeSettingsProperties();
676 
677             String articleId = typeSettingsProperties.getProperty("article-id");
678 
679             if (Validator.isNotNull(articleId)) {
680                 Map<String, String> articleIds =
681                     (Map<String, String>)context.getNewPrimaryKeysMap(
682                         JournalArticle.class);
683 
684                 typeSettingsProperties.setProperty(
685                     "article-id",
686                     MapUtil.getString(articleIds, articleId, articleId));
687 
688                 LayoutUtil.update(layout, false);
689             }
690         }
691     }
692 
693     protected void deleteMissingLayouts(
694             long groupId, boolean privateLayout, Set<Long> newLayoutIds,
695             List<Layout> previousLayouts)
696         throws PortalException, SystemException {
697 
698         // Layouts
699 
700         if (_log.isDebugEnabled()) {
701             if (newLayoutIds.size() > 0) {
702                 _log.debug("Delete missing layouts");
703             }
704         }
705 
706         for (Layout layout : previousLayouts) {
707             if (!newLayoutIds.contains(layout.getLayoutId())) {
708                 try {
709                     LayoutLocalServiceUtil.deleteLayout(layout, false);
710                 }
711                 catch (NoSuchLayoutException nsle) {
712                 }
713             }
714         }
715 
716         // Layout set
717 
718         LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
719     }
720 
721     protected void fixTypeSettings(Layout layout) {
722         if (layout.getType().equals(LayoutConstants.TYPE_URL)) {
723             UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
724 
725             String url = GetterUtil.getString(typeSettings.getProperty("url"));
726 
727             String friendlyURLPrivateGroupPath =
728                 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
729             String friendlyURLPrivateUserPath =
730                 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
731             String friendlyURLPublicPath =
732                 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
733 
734             if (url.startsWith(friendlyURLPrivateGroupPath) ||
735                 url.startsWith(friendlyURLPrivateUserPath) ||
736                 url.startsWith(friendlyURLPublicPath)) {
737 
738                 int x = url.indexOf(StringPool.SLASH, 1);
739 
740                 if (x > 0) {
741                     int y = url.indexOf(StringPool.SLASH, x + 1);
742 
743                     if (y > x) {
744                         String fixedUrl = url.substring(0, x) +
745 
746                         layout.getGroup().getFriendlyURL() +
747 
748                         url.substring(y);
749 
750                         typeSettings.setProperty("url", fixedUrl);
751                     }
752                 }
753             }
754         }
755     }
756 
757     protected List<String> getActions(Element el) {
758         List<String> actions = new ArrayList<String>();
759 
760         Iterator<Element> itr = el.elements("action-key").iterator();
761 
762         while (itr.hasNext()) {
763             Element actionEl = itr.next();
764 
765             actions.add(actionEl.getText());
766         }
767 
768         return actions;
769     }
770 
771     protected void importGroupPermissions(
772             LayoutCache layoutCache, long companyId, long groupId,
773             String resourceName, String resourcePrimKey, Element parentEl,
774             String elName, boolean portletActions)
775         throws PortalException, SystemException {
776 
777         Element actionEl = parentEl.element(elName);
778 
779         if (actionEl == null) {
780             return;
781         }
782 
783         List<String> actions = getActions(actionEl);
784 
785         Resource resource = layoutCache.getResource(
786             companyId, groupId, resourceName,
787             ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
788             portletActions);
789 
790         PermissionLocalServiceUtil.setGroupPermissions(
791             groupId, actions.toArray(new String[actions.size()]),
792             resource.getResourceId());
793     }
794 
795     protected void importGroupRoles(
796             LayoutCache layoutCache, long companyId, long groupId,
797             String resourceName, String entityName,
798             Element parentEl)
799         throws PortalException, SystemException {
800 
801         Element entityRolesEl = parentEl.element(entityName + "-roles");
802 
803         if (entityRolesEl == null) {
804             return;
805         }
806 
807         importRolePermissions(
808             layoutCache, companyId, resourceName, ResourceConstants.SCOPE_GROUP,
809             String.valueOf(groupId), entityRolesEl, true);
810     }
811 
812     protected void importInheritedPermissions(
813             LayoutCache layoutCache, long companyId, String resourceName,
814             String resourcePrimKey, Element permissionsEl, String entityName,
815             boolean portletActions)
816         throws PortalException, SystemException {
817 
818         Element entityPermissionsEl = permissionsEl.element(
819             entityName + "-permissions");
820 
821         if (entityPermissionsEl == null) {
822             return;
823         }
824 
825         List<Element> actionsEls = entityPermissionsEl.elements(
826             entityName + "-actions");
827 
828         for (int i = 0; i < actionsEls.size(); i++) {
829             Element actionEl = actionsEls.get(i);
830 
831             String name = actionEl.attributeValue("name");
832 
833             long entityGroupId = layoutCache.getEntityGroupId(
834                 companyId, entityName, name);
835 
836             if (entityGroupId == 0) {
837                 _log.warn(
838                     "Ignore inherited permissions for entity " + entityName +
839                         " with name " + name);
840             }
841             else {
842                 Element parentEl = SAXReaderUtil.createElement("parent");
843 
844                 parentEl.add(actionEl.createCopy());
845 
846                 importGroupPermissions(
847                     layoutCache, companyId, entityGroupId, resourceName,
848                     resourcePrimKey, parentEl, entityName + "-actions",
849                     portletActions);
850             }
851         }
852     }
853 
854     protected void importInheritedRoles(
855             LayoutCache layoutCache, long companyId, long groupId,
856             String resourceName, String entityName, Element parentEl)
857         throws PortalException, SystemException {
858 
859         Element entityRolesEl = parentEl.element(entityName + "-roles");
860 
861         if (entityRolesEl == null) {
862             return;
863         }
864 
865         List<Element> entityEls = entityRolesEl.elements(entityName);
866 
867         for (int i = 0; i < entityEls.size(); i++) {
868             Element entityEl = entityEls.get(i);
869 
870             String name = entityEl.attributeValue("name");
871 
872             long entityGroupId = layoutCache.getEntityGroupId(
873                 companyId, entityName, name);
874 
875             if (entityGroupId == 0) {
876                 _log.warn(
877                     "Ignore inherited roles for entity " + entityName +
878                         " with name " + name);
879             }
880             else {
881                 importRolePermissions(
882                     layoutCache, companyId, resourceName,
883                     ResourceConstants.SCOPE_GROUP, String.valueOf(groupId),
884                     entityEl, false);
885             }
886         }
887     }
888 
889     protected void importLayoutPermissions_4(
890             LayoutCache layoutCache, long companyId, long groupId,
891             Group guestGroup, Layout layout, String resourceName,
892             String resourcePrimKey, Element permissionsEl,
893             boolean importUserPermissions)
894         throws PortalException, SystemException {
895 
896         importGroupPermissions(
897             layoutCache, companyId, groupId, resourceName, resourcePrimKey,
898             permissionsEl, "community-actions", false);
899 
900         if (groupId != guestGroup.getGroupId()) {
901             importGroupPermissions(
902                 layoutCache, companyId, guestGroup.getGroupId(), resourceName,
903                 resourcePrimKey, permissionsEl, "guest-actions", false);
904         }
905 
906         if (importUserPermissions) {
907             importUserPermissions(
908                 layoutCache, companyId, groupId, resourceName, resourcePrimKey,
909                 permissionsEl, false);
910         }
911 
912         importInheritedPermissions(
913             layoutCache, companyId, resourceName, resourcePrimKey,
914             permissionsEl, "organization", false);
915 
916         importInheritedPermissions(
917             layoutCache, companyId, resourceName, resourcePrimKey,
918             permissionsEl, "location", false);
919 
920         importInheritedPermissions(
921             layoutCache, companyId, resourceName, resourcePrimKey,
922             permissionsEl, "user-group", false);
923     }
924 
925     protected void importLayoutPermissions_5(
926             LayoutCache layoutCache, long companyId, long groupId, long userId,
927             String resourceName, String resourcePrimKey, Element permissionsEl)
928         throws PortalException, SystemException {
929 
930         boolean portletActions = false;
931 
932         Resource resource = layoutCache.getResource(
933             companyId, groupId, resourceName,
934             ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
935             portletActions);
936 
937         importPermissions_5(
938             layoutCache, companyId, userId, resource.getResourceId(),
939             permissionsEl);
940     }
941 
942     protected void importLayoutRoles(
943             LayoutCache layoutCache, long companyId, long groupId,
944             Element rolesEl)
945         throws PortalException, SystemException {
946 
947         String resourceName = Layout.class.getName();
948 
949         importGroupRoles(
950             layoutCache, companyId, groupId, resourceName, "community",
951             rolesEl);
952 
953         importUserRoles(layoutCache, companyId, groupId, resourceName, rolesEl);
954 
955         importInheritedRoles(
956             layoutCache, companyId, groupId, resourceName, "organization",
957             rolesEl);
958 
959         importInheritedRoles(
960             layoutCache, companyId, groupId, resourceName, "location", rolesEl);
961 
962         importInheritedRoles(
963             layoutCache, companyId, groupId, resourceName, "user-group",
964             rolesEl);
965     }
966 
967     protected void importPermissions_5(
968             LayoutCache layoutCache, long companyId, long userId,
969             long resourceId, Element permissionsEl)
970         throws PortalException, SystemException {
971 
972         List<Element> roleEls = permissionsEl.elements("role");
973 
974         for (Element roleEl : roleEls) {
975             String name = roleEl.attributeValue("name");
976 
977             Role role = layoutCache.getRole(companyId, name);
978 
979             if (role == null) {
980                 String description = roleEl.attributeValue("description");
981                 int type = Integer.valueOf(roleEl.attributeValue("type"));
982 
983                 role = RoleLocalServiceUtil.addRole(
984                     userId, companyId, name, description, type);
985             }
986 
987             List<String> actions = getActions(roleEl);
988 
989             PermissionLocalServiceUtil.setRolePermissions(
990                 role.getRoleId(), actions.toArray(new String[actions.size()]),
991                 resourceId);
992         }
993     }
994 
995     protected void importPortletPermissions_4(
996             LayoutCache layoutCache, long companyId, long groupId,
997             Group guestGroup, Layout layout, Element permissionsEl,
998             boolean importUserPermissions)
999         throws PortalException, SystemException {
1000
1001        Iterator<Element> itr = permissionsEl.elements("portlet").iterator();
1002
1003        while (itr.hasNext()) {
1004            Element portletEl = itr.next();
1005
1006            String portletId = portletEl.attributeValue("portlet-id");
1007
1008            String resourceName = PortletConstants.getRootPortletId(portletId);
1009            String resourcePrimKey = PortletPermissionUtil.getPrimaryKey(
1010                layout.getPlid(), portletId);
1011
1012            Portlet portlet = PortletLocalServiceUtil.getPortletById(
1013                companyId, resourceName);
1014
1015            if (portlet == null) {
1016                if (_log.isDebugEnabled()) {
1017                    _log.debug(
1018                        "Do not import portlet permissions for " + portletId +
1019                            " because the portlet does not exist");
1020                }
1021            }
1022            else {
1023                importGroupPermissions(
1024                    layoutCache, companyId, groupId, resourceName,
1025                    resourcePrimKey, portletEl, "community-actions", true);
1026
1027                if (groupId != guestGroup.getGroupId()) {
1028                    importGroupPermissions(
1029                        layoutCache, companyId, guestGroup.getGroupId(),
1030                        resourceName, resourcePrimKey, portletEl,
1031                        "guest-actions", true);
1032                }
1033
1034                if (importUserPermissions) {
1035                    importUserPermissions(
1036                        layoutCache, companyId, groupId, resourceName,
1037                        resourcePrimKey, portletEl, true);
1038                }
1039
1040                importInheritedPermissions(
1041                    layoutCache, companyId, resourceName, resourcePrimKey,
1042                    portletEl, "organization", true);
1043
1044                importInheritedPermissions(
1045                    layoutCache, companyId, resourceName, resourcePrimKey,
1046                    portletEl, "location", true);
1047
1048                importInheritedPermissions(
1049                    layoutCache, companyId, resourceName, resourcePrimKey,
1050                    portletEl, "user-group", true);
1051            }
1052        }
1053    }
1054
1055    protected void importPortletPermissions_5(
1056            LayoutCache layoutCache, long companyId, long groupId, long userId,
1057            String resourceName, String resourcePrimKey, Element permissionsEl)
1058        throws PortalException, SystemException {
1059
1060        boolean portletActions = true;
1061
1062        Resource resource = layoutCache.getResource(
1063            companyId, groupId, resourceName,
1064            ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
1065            portletActions);
1066
1067        importPermissions_5(
1068            layoutCache, companyId, userId, resource.getResourceId(),
1069            permissionsEl);
1070    }
1071
1072    protected void importPortletRoles(
1073            LayoutCache layoutCache, long companyId, long groupId,
1074            String portletId, Element rolesEl)
1075        throws PortalException, SystemException {
1076
1077        String resourceName = PortletConstants.getRootPortletId(portletId);
1078
1079        Portlet portlet = PortletLocalServiceUtil.getPortletById(
1080            companyId, resourceName);
1081
1082        if (portlet == null) {
1083            if (_log.isDebugEnabled()) {
1084                _log.debug(
1085                    "Do not import portlet roles for " + portletId +
1086                        " because the portlet does not exist");
1087            }
1088        }
1089        else {
1090            importGroupRoles(
1091                layoutCache, companyId, groupId, resourceName, "community",
1092                rolesEl);
1093
1094            importUserRoles(
1095                layoutCache, companyId, groupId, resourceName, rolesEl);
1096
1097            importInheritedRoles(
1098                layoutCache, companyId, groupId, resourceName,
1099                "organization", rolesEl);
1100
1101            importInheritedRoles(
1102                layoutCache, companyId, groupId, resourceName, "location",
1103                rolesEl);
1104
1105            importInheritedRoles(
1106                layoutCache, companyId, groupId, resourceName, "user-group",
1107                rolesEl);
1108        }
1109    }
1110
1111    protected void importPortletRoles(
1112            LayoutCache layoutCache, long companyId, long groupId,
1113            Element rolesEl)
1114        throws PortalException, SystemException {
1115
1116        Iterator<Element> itr = rolesEl.elements("portlet").iterator();
1117
1118        while (itr.hasNext()) {
1119            Element portletEl = itr.next();
1120
1121            String portletId = portletEl.attributeValue("portlet-id");
1122
1123            String resourceName = PortletConstants.getRootPortletId(portletId);
1124
1125            Portlet portlet = PortletLocalServiceUtil.getPortletById(
1126                companyId, resourceName);
1127
1128            if (portlet == null) {
1129                if (_log.isDebugEnabled()) {
1130                    _log.debug(
1131                        "Do not import portlet roles for " + portletId +
1132                            " because the portlet does not exist");
1133                }
1134            }
1135            else {
1136                importGroupRoles(
1137                    layoutCache, companyId, groupId, resourceName, "community",
1138                    portletEl);
1139
1140                importUserRoles(
1141                    layoutCache, companyId, groupId, resourceName, portletEl);
1142
1143                importInheritedRoles(
1144                    layoutCache, companyId, groupId, resourceName,
1145                    "organization", portletEl);
1146
1147                importInheritedRoles(
1148                    layoutCache, companyId, groupId, resourceName, "location",
1149                    portletEl);
1150
1151                importInheritedRoles(
1152                    layoutCache, companyId, groupId, resourceName, "user-group",
1153                    portletEl);
1154            }
1155        }
1156    }
1157
1158    protected void importRolePermissions(
1159            LayoutCache layoutCache, long companyId, String resourceName,
1160            int scope, String resourcePrimKey, Element parentEl,
1161            boolean communityRole)
1162        throws PortalException, SystemException {
1163
1164        List<Element> roleEls = parentEl.elements("role");
1165
1166        for (int i = 0; i < roleEls.size(); i++) {
1167            Element roleEl = roleEls.get(i);
1168
1169            String roleName = roleEl.attributeValue("name");
1170
1171            Role role = layoutCache.getRole(companyId, roleName);
1172
1173            if (role == null) {
1174                _log.warn(
1175                    "Ignoring permissions for role with name " + roleName);
1176            }
1177            else {
1178                List<String> actions = getActions(roleEl);
1179
1180                PermissionLocalServiceUtil.setRolePermissions(
1181                    role.getRoleId(), companyId, resourceName, scope,
1182                    resourcePrimKey,
1183                    actions.toArray(new String[actions.size()]));
1184
1185                if (communityRole) {
1186                    long[] groupIds = {GetterUtil.getLong(resourcePrimKey)};
1187
1188                    GroupLocalServiceUtil.addRoleGroups(
1189                        role.getRoleId(), groupIds);
1190                }
1191            }
1192        }
1193    }
1194
1195    protected String importTheme(LayoutSet layoutSet, byte[] themeZip)
1196        throws IOException {
1197
1198        ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
1199
1200        if (themeLoader == null) {
1201            _log.error("No theme loaders are deployed");
1202
1203            return null;
1204        }
1205
1206        ZipReader zipReader = new ZipReader(new ByteArrayInputStream(themeZip));
1207
1208        Map<String, byte[]> entries = zipReader.getEntries();
1209
1210        String lookAndFeelXML = new String(
1211            entries.get("liferay-look-and-feel.xml"));
1212
1213        String themeId = String.valueOf(layoutSet.getGroupId());
1214
1215        if (layoutSet.isPrivateLayout()) {
1216            themeId += "-private";
1217        }
1218        else {
1219            themeId += "-public";
1220        }
1221
1222        if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
1223            Date now = new Date();
1224
1225            themeId += "-" + Time.getShortTimestamp(now);
1226        }
1227
1228        String themeName = themeId;
1229
1230        lookAndFeelXML = StringUtil.replace(
1231            lookAndFeelXML,
1232            new String[] {
1233                "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
1234            },
1235            new String[] {
1236                String.valueOf(layoutSet.getGroupId()), themeId, themeName
1237            }
1238        );
1239
1240        FileUtil.deltree(themeLoader.getFileStorage() + "/" + themeId);
1241
1242        Iterator<Map.Entry<String, byte[]>> itr = entries.entrySet().iterator();
1243
1244        while (itr.hasNext()) {
1245            Map.Entry<String, byte[]> entry = itr.next();
1246
1247            String key = entry.getKey();
1248            byte[] value = entry.getValue();
1249
1250            if (key.equals("liferay-look-and-feel.xml")) {
1251                value = lookAndFeelXML.getBytes();
1252            }
1253
1254            FileUtil.write(
1255                themeLoader.getFileStorage() + "/" + themeId + "/" + key,
1256                value);
1257        }
1258
1259        themeLoader.loadThemes();
1260
1261        CommLink commLink = CommLink.getInstance();
1262
1263        MethodWrapper methodWrapper = new MethodWrapper(
1264            ThemeLoaderFactory.class.getName(), "loadThemes");
1265
1266        commLink.send(methodWrapper);
1267
1268        themeId +=
1269            PortletConstants.WAR_SEPARATOR +
1270                themeLoader.getServletContextName();
1271
1272        return PortalUtil.getJsSafePortletId(themeId);
1273    }
1274
1275    protected void importUserPermissions(
1276            LayoutCache layoutCache, long companyId, long groupId,
1277            String resourceName, String resourcePrimKey, Element parentEl,
1278            boolean portletActions)
1279        throws PortalException, SystemException {
1280
1281        Element userPermissionsEl = parentEl.element("user-permissions");
1282
1283        if (userPermissionsEl == null) {
1284            return;
1285        }
1286
1287        List<Element> userActionsEls = userPermissionsEl.elements(
1288            "user-actions");
1289
1290        for (int i = 0; i < userActionsEls.size(); i++) {
1291            Element userActionsEl = userActionsEls.get(i);
1292
1293            String emailAddress = userActionsEl.attributeValue("email-address");
1294
1295            User user = layoutCache.getUser(companyId, groupId, emailAddress);
1296
1297            if (user == null) {
1298                if (_log.isWarnEnabled()) {
1299                    _log.warn(
1300                        "Ignoring permissions for user with email address " +
1301                            emailAddress);
1302                }
1303            }
1304            else {
1305                List<String> actions = getActions(userActionsEl);
1306
1307                Resource resource = layoutCache.getResource(
1308                    companyId, groupId, resourceName,
1309                    ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
1310                    portletActions);
1311
1312                PermissionLocalServiceUtil.setUserPermissions(
1313                    user.getUserId(),
1314                    actions.toArray(new String[actions.size()]),
1315                    resource.getResourceId());
1316            }
1317        }
1318    }
1319
1320    protected void importUserRoles(
1321            LayoutCache layoutCache, long companyId, long groupId,
1322            String resourceName, Element parentEl)
1323        throws PortalException, SystemException {
1324
1325        Element userRolesEl = parentEl.element("user-roles");
1326
1327        if (userRolesEl == null) {
1328            return;
1329        }
1330
1331        List<Element> userEls = userRolesEl.elements("user");
1332
1333        for (int i = 0; i < userEls.size(); i++) {
1334            Element userEl = userEls.get(i);
1335
1336            String emailAddress = userEl.attributeValue("email-address");
1337
1338            User user = layoutCache.getUser(companyId, groupId, emailAddress);
1339
1340            if (user == null) {
1341                if (_log.isWarnEnabled()) {
1342                    _log.warn(
1343                        "Ignoring roles for user with email address " +
1344                            emailAddress);
1345                }
1346            }
1347            else {
1348                importRolePermissions(
1349                    layoutCache, companyId, resourceName,
1350                    ResourceConstants.SCOPE_GROUP, String.valueOf(groupId),
1351                    userEl, false);
1352            }
1353        }
1354    }
1355
1356    protected void mergePortlets(
1357        Layout layout, String newTypeSettings, String portletsMergeMode) {
1358
1359        try {
1360            UnicodeProperties previousProps =
1361                layout.getTypeSettingsProperties();
1362            LayoutTypePortlet previousLayoutType =
1363                (LayoutTypePortlet)layout.getLayoutType();
1364            List<String> previousColumns =
1365                previousLayoutType.getLayoutTemplate().getColumns();
1366
1367            UnicodeProperties newProps = new UnicodeProperties(true);
1368
1369            newProps.load(newTypeSettings);
1370
1371            String layoutTemplateId = newProps.getProperty(
1372                    LayoutTypePortletImpl.LAYOUT_TEMPLATE_ID);
1373
1374            LayoutTemplate newLayoutTemplate =
1375                LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1376                    layoutTemplateId, false, null);
1377
1378            String[] lostPortletIds = new String[0];
1379
1380            for (String columnId : newLayoutTemplate.getColumns()) {
1381                String columnValue =
1382                    newProps.getProperty(columnId);
1383
1384                String[] portletIds = StringUtil.split(columnValue);
1385
1386                if (!previousColumns.contains(columnId)) {
1387                    lostPortletIds = ArrayUtil.append(
1388                        lostPortletIds, portletIds);
1389                }
1390                else {
1391
1392                    String[] previousPortletIds = StringUtil.split(
1393                        previousProps.getProperty(columnId));
1394
1395                    portletIds = appendPortletIds(
1396                        previousPortletIds, portletIds, portletsMergeMode);
1397
1398                    previousProps.setProperty(
1399                        columnId, StringUtil.merge(portletIds));
1400                }
1401            }
1402
1403            // Add portlets in non-existent column to the first column
1404
1405            String columnId = previousColumns.get(0);
1406
1407            String[] portletIds = StringUtil.split(
1408                previousProps.getProperty(columnId));
1409
1410            appendPortletIds(portletIds, lostPortletIds, portletsMergeMode);
1411
1412            previousProps.setProperty(
1413                columnId, StringUtil.merge(portletIds));
1414
1415            layout.setTypeSettings(previousProps.toString());
1416
1417        }
1418        catch (IOException e) {
1419            layout.setTypeSettings(newTypeSettings);
1420        }
1421    }
1422
1423    protected String[] appendPortletIds(
1424        String[] portletIds, String[] newPortletIds,
1425        String portletsMergeMode) {
1426
1427        for (String portletId : newPortletIds) {
1428            if (ArrayUtil.contains(portletIds, portletId)) {
1429                continue;
1430            }
1431
1432            if (portletsMergeMode.equals(
1433                    PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
1434                portletIds = ArrayUtil.append(
1435                    portletIds, portletId);
1436            }
1437            else {
1438                portletIds = ArrayUtil.append(
1439                    new String[]{portletId}, portletIds);
1440            }
1441        }
1442
1443        return portletIds;
1444    }
1445
1446    private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1447
1448    private PortletImporter _portletImporter = new PortletImporter();
1449
1450}