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