001
014
015 package com.liferay.portal.lar;
016
017 import com.liferay.counter.service.CounterLocalServiceUtil;
018 import com.liferay.portal.LARFileException;
019 import com.liferay.portal.LARTypeException;
020 import com.liferay.portal.LayoutImportException;
021 import com.liferay.portal.NoSuchLayoutException;
022 import com.liferay.portal.NoSuchLayoutSetPrototypeException;
023 import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
024 import com.liferay.portal.kernel.cluster.ClusterRequest;
025 import com.liferay.portal.kernel.exception.PortalException;
026 import com.liferay.portal.kernel.exception.SystemException;
027 import com.liferay.portal.kernel.lar.ImportExportThreadLocal;
028 import com.liferay.portal.kernel.lar.PortletDataContext;
029 import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
030 import com.liferay.portal.kernel.lar.UserIdStrategy;
031 import com.liferay.portal.kernel.log.Log;
032 import com.liferay.portal.kernel.log.LogFactoryUtil;
033 import com.liferay.portal.kernel.search.Indexer;
034 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
035 import com.liferay.portal.kernel.staging.StagingUtil;
036 import com.liferay.portal.kernel.util.ArrayUtil;
037 import com.liferay.portal.kernel.util.CharPool;
038 import com.liferay.portal.kernel.util.FileUtil;
039 import com.liferay.portal.kernel.util.GetterUtil;
040 import com.liferay.portal.kernel.util.LocaleUtil;
041 import com.liferay.portal.kernel.util.MapUtil;
042 import com.liferay.portal.kernel.util.MethodHandler;
043 import com.liferay.portal.kernel.util.MethodKey;
044 import com.liferay.portal.kernel.util.ReleaseInfo;
045 import com.liferay.portal.kernel.util.StringBundler;
046 import com.liferay.portal.kernel.util.StringPool;
047 import com.liferay.portal.kernel.util.StringUtil;
048 import com.liferay.portal.kernel.util.Time;
049 import com.liferay.portal.kernel.util.UnicodeProperties;
050 import com.liferay.portal.kernel.util.Validator;
051 import com.liferay.portal.kernel.xml.Attribute;
052 import com.liferay.portal.kernel.xml.Document;
053 import com.liferay.portal.kernel.xml.Element;
054 import com.liferay.portal.kernel.xml.Node;
055 import com.liferay.portal.kernel.xml.SAXReaderUtil;
056 import com.liferay.portal.kernel.zip.ZipReader;
057 import com.liferay.portal.kernel.zip.ZipReaderFactoryUtil;
058 import com.liferay.portal.model.Group;
059 import com.liferay.portal.model.Layout;
060 import com.liferay.portal.model.LayoutConstants;
061 import com.liferay.portal.model.LayoutSet;
062 import com.liferay.portal.model.LayoutSetPrototype;
063 import com.liferay.portal.model.LayoutTemplate;
064 import com.liferay.portal.model.LayoutTypePortlet;
065 import com.liferay.portal.model.LayoutTypePortletConstants;
066 import com.liferay.portal.model.Portlet;
067 import com.liferay.portal.model.PortletConstants;
068 import com.liferay.portal.model.Resource;
069 import com.liferay.portal.model.ResourceConstants;
070 import com.liferay.portal.model.Role;
071 import com.liferay.portal.model.RoleConstants;
072 import com.liferay.portal.model.User;
073 import com.liferay.portal.model.impl.ColorSchemeImpl;
074 import com.liferay.portal.security.permission.ActionKeys;
075 import com.liferay.portal.security.permission.PermissionCacheUtil;
076 import com.liferay.portal.service.GroupLocalServiceUtil;
077 import com.liferay.portal.service.ImageLocalServiceUtil;
078 import com.liferay.portal.service.LayoutLocalServiceUtil;
079 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
080 import com.liferay.portal.service.LayoutSetPrototypeLocalServiceUtil;
081 import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
082 import com.liferay.portal.service.PermissionLocalServiceUtil;
083 import com.liferay.portal.service.PortletLocalServiceUtil;
084 import com.liferay.portal.service.ResourceLocalServiceUtil;
085 import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
086 import com.liferay.portal.service.RoleLocalServiceUtil;
087 import com.liferay.portal.service.ServiceContext;
088 import com.liferay.portal.service.ServiceContextThreadLocal;
089 import com.liferay.portal.service.persistence.LayoutUtil;
090 import com.liferay.portal.service.persistence.UserUtil;
091 import com.liferay.portal.servlet.filters.cache.CacheUtil;
092 import com.liferay.portal.theme.ThemeLoader;
093 import com.liferay.portal.theme.ThemeLoaderFactory;
094 import com.liferay.portal.util.PortalUtil;
095 import com.liferay.portal.util.PortletKeys;
096 import com.liferay.portal.util.PropsValues;
097 import com.liferay.portlet.journal.lar.JournalPortletDataHandlerImpl;
098 import com.liferay.portlet.journal.model.JournalArticle;
099 import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
100 import com.liferay.portlet.journalcontent.util.JournalContentUtil;
101 import com.liferay.portlet.sites.util.SitesUtil;
102
103 import java.io.File;
104 import java.io.IOException;
105 import java.io.InputStream;
106
107 import java.util.ArrayList;
108 import java.util.Date;
109 import java.util.HashSet;
110 import java.util.List;
111 import java.util.Locale;
112 import java.util.Map;
113 import java.util.Set;
114
115 import org.apache.commons.lang.time.StopWatch;
116
117
130 public class LayoutImporter {
131
132 public void importLayouts(
133 long userId, long groupId, boolean privateLayout,
134 Map<String, String[]> parameterMap, File file)
135 throws Exception {
136
137 try {
138 ImportExportThreadLocal.setLayoutImportInProcess(true);
139
140 doImportLayouts(userId, groupId, privateLayout, parameterMap, file);
141 }
142 finally {
143 ImportExportThreadLocal.setLayoutImportInProcess(false);
144
145 CacheUtil.clearCache();
146 JournalContentUtil.clearCache();
147 PermissionCacheUtil.clearCache();
148 }
149 }
150
151 protected String[] appendPortletIds(
152 String[] portletIds, String[] newPortletIds, String portletsMergeMode) {
153
154 for (String portletId : newPortletIds) {
155 if (ArrayUtil.contains(portletIds, portletId)) {
156 continue;
157 }
158
159 if (portletsMergeMode.equals(
160 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_ADD_TO_BOTTOM)) {
161
162 portletIds = ArrayUtil.append(portletIds, portletId);
163 }
164 else {
165 portletIds = ArrayUtil.append(
166 new String[] {portletId}, portletIds);
167 }
168 }
169
170 return portletIds;
171 }
172
173 protected void deleteMissingLayouts(
174 long groupId, boolean privateLayout, Set<Long> newLayoutIds,
175 List<Layout> previousLayouts, ServiceContext serviceContext)
176 throws Exception {
177
178
179
180 if (_log.isDebugEnabled()) {
181 if (newLayoutIds.size() > 0) {
182 _log.debug("Delete missing layouts");
183 }
184 }
185
186 for (Layout layout : previousLayouts) {
187 if (!newLayoutIds.contains(layout.getLayoutId())) {
188 try {
189 LayoutLocalServiceUtil.deleteLayout(
190 layout, false, serviceContext);
191 }
192 catch (NoSuchLayoutException nsle) {
193 }
194 }
195 }
196
197
198
199 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
200 }
201
202 protected void doImportLayouts(
203 long userId, long groupId, boolean privateLayout,
204 Map<String, String[]> parameterMap, File file)
205 throws Exception {
206
207 boolean deleteMissingLayouts = MapUtil.getBoolean(
208 parameterMap, PortletDataHandlerKeys.DELETE_MISSING_LAYOUTS,
209 Boolean.TRUE.booleanValue());
210 boolean deletePortletData = MapUtil.getBoolean(
211 parameterMap, PortletDataHandlerKeys.DELETE_PORTLET_DATA);
212 boolean importCategories = MapUtil.getBoolean(
213 parameterMap, PortletDataHandlerKeys.CATEGORIES);
214 boolean importPermissions = MapUtil.getBoolean(
215 parameterMap, PortletDataHandlerKeys.PERMISSIONS);
216 boolean importPublicLayoutPermissions = MapUtil.getBoolean(
217 parameterMap, PortletDataHandlerKeys.PUBLIC_LAYOUT_PERMISSIONS);
218 boolean importUserPermissions = MapUtil.getBoolean(
219 parameterMap, PortletDataHandlerKeys.USER_PERMISSIONS);
220 boolean importPortletData = MapUtil.getBoolean(
221 parameterMap, PortletDataHandlerKeys.PORTLET_DATA);
222 boolean importPortletSetup = MapUtil.getBoolean(
223 parameterMap, PortletDataHandlerKeys.PORTLET_SETUP);
224 boolean importPortletArchivedSetups = MapUtil.getBoolean(
225 parameterMap, PortletDataHandlerKeys.PORTLET_ARCHIVED_SETUPS);
226 boolean importPortletUserPreferences = MapUtil.getBoolean(
227 parameterMap, PortletDataHandlerKeys.PORTLET_USER_PREFERENCES);
228 boolean importTheme = MapUtil.getBoolean(
229 parameterMap, PortletDataHandlerKeys.THEME);
230 boolean importThemeSettings = MapUtil.getBoolean(
231 parameterMap, PortletDataHandlerKeys.THEME_REFERENCE);
232 boolean layoutSetPrototypeLinkEnabled = MapUtil.getBoolean(
233 parameterMap,
234 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_LINK_ENABLED, true);
235 boolean publishToRemote = MapUtil.getBoolean(
236 parameterMap, PortletDataHandlerKeys.PUBLISH_TO_REMOTE);
237 String layoutsImportMode = MapUtil.getString(
238 parameterMap, PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE,
239 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_UUID);
240 String portletsMergeMode = MapUtil.getString(
241 parameterMap, PortletDataHandlerKeys.PORTLETS_MERGE_MODE,
242 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE);
243 String userIdStrategy = MapUtil.getString(
244 parameterMap, PortletDataHandlerKeys.USER_ID_STRATEGY);
245
246 if (_log.isDebugEnabled()) {
247 _log.debug("Delete portlet data " + deletePortletData);
248 _log.debug("Import categories " + importCategories);
249 _log.debug("Import permissions " + importPermissions);
250 _log.debug("Import user permissions " + importUserPermissions);
251 _log.debug("Import portlet data " + importPortletData);
252 _log.debug("Import portlet setup " + importPortletSetup);
253 _log.debug(
254 "Import portlet archived setups " +
255 importPortletArchivedSetups);
256 _log.debug(
257 "Import portlet user preferences " +
258 importPortletUserPreferences);
259 _log.debug("Import theme " + importTheme);
260 }
261
262 StopWatch stopWatch = null;
263
264 if (_log.isInfoEnabled()) {
265 stopWatch = new StopWatch();
266
267 stopWatch.start();
268 }
269
270 LayoutCache layoutCache = new LayoutCache();
271
272 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
273 groupId, privateLayout);
274
275 long companyId = layoutSet.getCompanyId();
276
277 User user = UserUtil.findByPrimaryKey(userId);
278
279 UserIdStrategy strategy = _portletImporter.getUserIdStrategy(
280 user, userIdStrategy);
281
282 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(file);
283
284 PortletDataContext portletDataContext = new PortletDataContextImpl(
285 companyId, groupId, parameterMap, new HashSet<String>(), strategy,
286 zipReader);
287
288 portletDataContext.setPortetDataContextListener(
289 new PortletDataContextListenerImpl(portletDataContext));
290
291 portletDataContext.setPrivateLayout(privateLayout);
292
293
294
295 Element rootElement = null;
296 InputStream themeZip = null;
297
298
299
300 String xml = portletDataContext.getZipEntryAsString("/manifest.xml");
301
302 if (xml == null) {
303 throw new LARFileException("manifest.xml not found in the LAR");
304 }
305
306 try {
307 Document document = SAXReaderUtil.read(xml);
308
309 rootElement = document.getRootElement();
310 }
311 catch (Exception e) {
312 throw new LARFileException(e);
313 }
314
315
316
317 Element headerElement = rootElement.element("header");
318
319 int buildNumber = ReleaseInfo.getBuildNumber();
320
321 int importBuildNumber = GetterUtil.getInteger(
322 headerElement.attributeValue("build-number"));
323
324 if (buildNumber != importBuildNumber) {
325 throw new LayoutImportException(
326 "LAR build number " + importBuildNumber + " does not match " +
327 "portal build number " + buildNumber);
328 }
329
330
331
332 String larType = headerElement.attributeValue("type");
333
334 if (!larType.equals("layout-set")) {
335 throw new LARTypeException(
336 "Invalid type of LAR file (" + larType + ")");
337 }
338
339
340
341 long sourceGroupId = GetterUtil.getLong(
342 headerElement.attributeValue("group-id"));
343
344 portletDataContext.setSourceGroupId(sourceGroupId);
345
346
347
348 String layoutSetPrototypeUuid = headerElement.attributeValue(
349 "layout-set-prototype-uuid");
350
351 ServiceContext serviceContext =
352 ServiceContextThreadLocal.getServiceContext();
353
354 if (Validator.isNotNull(layoutSetPrototypeUuid)) {
355 if (layoutSetPrototypeLinkEnabled) {
356 if (publishToRemote) {
357 importLayoutSetPrototype(
358 portletDataContext, user, layoutSetPrototypeUuid,
359 serviceContext);
360 }
361 }
362
363 layoutSet.setLayoutSetPrototypeUuid(layoutSetPrototypeUuid);
364 layoutSet.setLayoutSetPrototypeLinkEnabled(
365 layoutSetPrototypeLinkEnabled);
366
367 LayoutSetLocalServiceUtil.updateLayoutSet(layoutSet);
368 }
369
370
371
372 if (importTheme) {
373 themeZip = portletDataContext.getZipEntryAsInputStream("theme.zip");
374 }
375
376
377
378 String themeId = layoutSet.getThemeId();
379 String colorSchemeId = layoutSet.getColorSchemeId();
380
381 if (importThemeSettings) {
382 Attribute themeIdAttribute = headerElement.attribute("theme-id");
383
384 if (themeIdAttribute != null) {
385 themeId = themeIdAttribute.getValue();
386 }
387
388 Attribute colorSchemeIdAttribute = headerElement.attribute(
389 "color-scheme-id");
390
391 if (colorSchemeIdAttribute != null) {
392 colorSchemeId = colorSchemeIdAttribute.getValue();
393 }
394 }
395
396 String css = GetterUtil.getString(headerElement.elementText("css"));
397
398 if (themeZip != null) {
399 String importThemeId = importTheme(layoutSet, themeZip);
400
401 if (importThemeId != null) {
402 themeId = importThemeId;
403 colorSchemeId =
404 ColorSchemeImpl.getDefaultRegularColorSchemeId();
405 }
406
407 if (_log.isDebugEnabled()) {
408 _log.debug(
409 "Importing theme takes " + stopWatch.getTime() + " ms");
410 }
411 }
412
413 boolean wapTheme = false;
414
415 LayoutSetLocalServiceUtil.updateLookAndFeel(
416 groupId, privateLayout, themeId, colorSchemeId, css, wapTheme);
417
418
419
420
421
422 if (importPermissions) {
423 _permissionImporter.readPortletDataPermissions(portletDataContext);
424 }
425
426 if (importCategories) {
427 _portletImporter.readAssetCategories(portletDataContext);
428 }
429
430 _portletImporter.readAssetTags(portletDataContext);
431 _portletImporter.readComments(portletDataContext);
432 _portletImporter.readExpandoTables(portletDataContext);
433 _portletImporter.readLocks(portletDataContext);
434 _portletImporter.readRatingsEntries(portletDataContext);
435
436
437
438 List<Layout> previousLayouts = LayoutUtil.findByG_P(
439 groupId, privateLayout);
440
441
442
443 if (Validator.isNotNull(layoutSetPrototypeUuid) &&
444 layoutSetPrototypeLinkEnabled) {
445
446 LayoutSetPrototype layoutSetPrototype =
447 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
448 layoutSetPrototypeUuid);
449
450 Group group = layoutSetPrototype.getGroup();
451
452 for (Layout layout : previousLayouts) {
453 String sourcePrototypeLayoutUuid =
454 layout.getSourcePrototypeLayoutUuid();
455
456 if (Validator.isNull(layout.getSourcePrototypeLayoutUuid())) {
457 continue;
458 }
459
460 Layout sourcePrototypeLayout = LayoutUtil.fetchByUUID_G(
461 sourcePrototypeLayoutUuid, group.getGroupId());
462
463 if (sourcePrototypeLayout == null) {
464 LayoutLocalServiceUtil.deleteLayout(layout);
465 }
466 }
467 }
468
469 List<Layout> newLayouts = new ArrayList<Layout>();
470
471 Set<Long> newLayoutIds = new HashSet<Long>();
472
473 Map<Long, Layout> newLayoutsMap =
474 (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
475 Layout.class);
476
477 Element layoutsElement = rootElement.element("layouts");
478
479 List<Element> layoutElements = layoutsElement.elements("layout");
480
481 if (_log.isDebugEnabled()) {
482 if (layoutElements.size() > 0) {
483 _log.debug("Importing layouts");
484 }
485 }
486
487 for (Element layoutElement : layoutElements) {
488 importLayout(
489 portletDataContext, user, layoutCache, previousLayouts,
490 newLayouts, newLayoutsMap, newLayoutIds, portletsMergeMode,
491 themeId, colorSchemeId, layoutsImportMode, privateLayout,
492 importPermissions, importPublicLayoutPermissions,
493 importUserPermissions, importThemeSettings,
494 rootElement, layoutElement);
495 }
496
497 Element portletsElement = rootElement.element("portlets");
498
499 List<Element> portletElements = portletsElement.elements("portlet");
500
501
502
503 if (deletePortletData) {
504 if (_log.isDebugEnabled()) {
505 if (portletElements.size() > 0) {
506 _log.debug("Deleting portlet data");
507 }
508 }
509
510 for (Element portletElement : portletElements) {
511 String portletId = portletElement.attributeValue("portlet-id");
512 long layoutId = GetterUtil.getLong(
513 portletElement.attributeValue("layout-id"));
514 long plid = newLayoutsMap.get(layoutId).getPlid();
515
516 portletDataContext.setPlid(plid);
517
518 _portletImporter.deletePortletData(
519 portletDataContext, portletId, plid);
520 }
521 }
522
523
524
525 if (_log.isDebugEnabled()) {
526 if (portletElements.size() > 0) {
527 _log.debug("Importing portlets");
528 }
529 }
530
531 for (Element portletElement : portletElements) {
532 String portletPath = portletElement.attributeValue("path");
533 String portletId = portletElement.attributeValue("portlet-id");
534 long layoutId = GetterUtil.getLong(
535 portletElement.attributeValue("layout-id"));
536 long plid = newLayoutsMap.get(layoutId).getPlid();
537 long oldPlid = GetterUtil.getLong(
538 portletElement.attributeValue("old-plid"));
539
540 Portlet portlet = PortletLocalServiceUtil.getPortletById(
541 portletDataContext.getCompanyId(), portletId);
542
543 if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
544 continue;
545 }
546
547 Layout layout = null;
548
549 try {
550 layout = LayoutUtil.findByPrimaryKey(plid);
551 }
552 catch (NoSuchLayoutException nsle) {
553 continue;
554 }
555
556 portletDataContext.setPlid(plid);
557 portletDataContext.setOldPlid(oldPlid);
558
559 Document portletDocument = SAXReaderUtil.read(
560 portletDataContext.getZipEntryAsString(portletPath));
561
562 portletElement = portletDocument.getRootElement();
563
564
565
566
567
568
569 _portletImporter.setPortletScope(
570 portletDataContext, portletElement);
571
572 try {
573
574
575
576 _portletImporter.importPortletPreferences(
577 portletDataContext, layoutSet.getCompanyId(),
578 layout.getGroupId(), layout, null, portletElement,
579 importPortletSetup, importPortletArchivedSetups,
580 importPortletUserPreferences, false);
581
582
583
584 Element portletDataElement = portletElement.element(
585 "portlet-data");
586
587 if (importPortletData && (portletDataElement != null)) {
588 _portletImporter.importPortletData(
589 portletDataContext, portletId, plid,
590 portletDataElement);
591 }
592 }
593 finally {
594 _portletImporter.resetPortletScope(
595 portletDataContext, layout.getGroupId());
596 }
597
598
599
600 if (importPermissions) {
601 _permissionImporter.importPortletPermissions(
602 layoutCache, companyId, groupId, userId, layout,
603 portletElement, portletId, importUserPermissions);
604 }
605
606
607
608 _portletImporter.importPortletPreferences(
609 portletDataContext, layoutSet.getCompanyId(), groupId, null,
610 null, portletElement, importPortletSetup,
611 importPortletArchivedSetups, importPortletUserPreferences,
612 false);
613 }
614
615 if (importPermissions) {
616 if ((userId > 0) &&
617 ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
618 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6))) {
619
620 Indexer indexer = IndexerRegistryUtil.getIndexer(User.class);
621
622 indexer.reindex(userId);
623 }
624 }
625
626
627
628 _portletImporter.readAssetLinks(portletDataContext);
629
630
631
632 if (deleteMissingLayouts) {
633 deleteMissingLayouts(
634 groupId, privateLayout, newLayoutIds, previousLayouts,
635 serviceContext);
636 }
637
638
639
640 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
641
642 if (_log.isInfoEnabled()) {
643 _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
644 }
645
646
647
648 GroupLocalServiceUtil.updateSite(groupId, true);
649
650
651
652 for (Layout layout : newLayouts) {
653 UnicodeProperties typeSettingsProperties =
654 layout.getTypeSettingsProperties();
655
656 String articleId = typeSettingsProperties.getProperty("article-id");
657
658 if (Validator.isNotNull(articleId)) {
659 Map<String, String> articleIds =
660 (Map<String, String>)portletDataContext.
661 getNewPrimaryKeysMap(
662 JournalArticle.class + ".articleId");
663
664 typeSettingsProperties.setProperty(
665 "article-id",
666 MapUtil.getString(articleIds, articleId, articleId));
667
668 LayoutUtil.update(layout, false);
669 }
670 }
671
672 zipReader.close();
673 }
674
675 protected String getLayoutSetPrototype(
676 PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
677
678 StringBundler sb = new StringBundler(3);
679
680 sb.append(portletDataContext.getSourceRootPath());
681 sb.append("/layout-set-prototype/");
682 sb.append(layoutSetPrototypeUuid);
683
684 return sb.toString();
685 }
686
687 protected void fixTypeSettings(Layout layout) throws Exception {
688 if (!layout.isTypeURL()) {
689 return;
690 }
691
692 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
693
694 String url = GetterUtil.getString(typeSettings.getProperty("url"));
695
696 String friendlyURLPrivateGroupPath =
697 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
698 String friendlyURLPrivateUserPath =
699 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
700 String friendlyURLPublicPath =
701 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
702
703 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
704 !url.startsWith(friendlyURLPrivateUserPath) &&
705 !url.startsWith(friendlyURLPublicPath)) {
706
707 return;
708 }
709
710 int x = url.indexOf(CharPool.SLASH, 1);
711
712 if (x == -1) {
713 return;
714 }
715
716 int y = url.indexOf(CharPool.SLASH, x + 1);
717
718 if (y == -1) {
719 return;
720 }
721
722 String friendlyURL = url.substring(x, y);
723
724 if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
725 return;
726 }
727
728 Group group = layout.getGroup();
729
730 typeSettings.setProperty(
731 "url",
732 url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
733 }
734
735 protected void importJournalArticle(
736 PortletDataContext portletDataContext, Layout layout,
737 Element layoutElement)
738 throws Exception {
739
740 UnicodeProperties typeSettingsProperties =
741 layout.getTypeSettingsProperties();
742
743 String articleId = typeSettingsProperties.getProperty(
744 "article-id", StringPool.BLANK);
745
746 if (Validator.isNull(articleId)) {
747 return;
748 }
749
750 JournalPortletDataHandlerImpl.importReferencedData(
751 portletDataContext, layoutElement);
752
753 Element structureElement = layoutElement.element("structure");
754
755 if (structureElement != null) {
756 JournalPortletDataHandlerImpl.importStructure(
757 portletDataContext, structureElement);
758 }
759
760 Element templateElement = layoutElement.element("template");
761
762 if (templateElement != null) {
763 JournalPortletDataHandlerImpl.importTemplate(
764 portletDataContext, templateElement);
765 }
766
767 Element articleElement = layoutElement.element("article");
768
769 if (articleElement != null) {
770 JournalPortletDataHandlerImpl.importArticle(
771 portletDataContext, articleElement);
772 }
773
774 Map<String, String> articleIds =
775 (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
776 JournalArticle.class + ".articleId");
777
778 articleId = MapUtil.getString(articleIds, articleId, articleId);
779
780 typeSettingsProperties.setProperty("article-id", articleId);
781
782 JournalContentSearchLocalServiceUtil.updateContentSearch(
783 portletDataContext.getScopeGroupId(), layout.isPrivateLayout(),
784 layout.getLayoutId(), StringPool.BLANK, articleId, true);
785 }
786
787 protected void importLayout(
788 PortletDataContext portletDataContext, User user,
789 LayoutCache layoutCache, List<Layout> previousLayouts,
790 List<Layout> newLayouts, Map<Long, Layout> newLayoutsMap,
791 Set<Long> newLayoutIds, String portletsMergeMode, String themeId,
792 String colorSchemeId, String layoutsImportMode,
793 boolean privateLayout, boolean importPermissions,
794 boolean importPublicLayoutPermissions,
795 boolean importUserPermissions, boolean importThemeSettings,
796 Element rootElement, Element layoutElement)
797 throws Exception {
798
799 long groupId = portletDataContext.getGroupId();
800
801 String layoutUuid = GetterUtil.getString(
802 layoutElement.attributeValue("layout-uuid"));
803
804 long layoutId = GetterUtil.getInteger(
805 layoutElement.attributeValue("layout-id"));
806
807 long oldLayoutId = layoutId;
808
809 boolean deleteLayout = GetterUtil.getBoolean(
810 layoutElement.attributeValue("delete"));
811
812 if (deleteLayout) {
813 Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
814 layoutUuid, groupId);
815
816 if (layout != null) {
817 newLayoutsMap.put(oldLayoutId, layout);
818
819 LayoutLocalServiceUtil.deleteLayout(layout);
820 }
821
822 return;
823 }
824
825 String path = layoutElement.attributeValue("path");
826
827 if (!portletDataContext.isPathNotProcessed(path)) {
828 return;
829 }
830
831 Layout layout = (Layout)portletDataContext.getZipEntryAsObject(path);
832
833 Layout existingLayout = null;
834 Layout importedLayout = null;
835
836 String friendlyURL = layout.getFriendlyURL();
837
838 if (layoutsImportMode.equals(
839 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
840
841 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
842 groupId, privateLayout);
843 friendlyURL = StringPool.SLASH + layoutId;
844 }
845 else if (layoutsImportMode.equals(
846 PortletDataHandlerKeys.
847 LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
848
849 Locale locale = LocaleUtil.getDefault();
850
851 String localizedName = layout.getName(locale);
852
853 for (Layout curLayout : previousLayouts) {
854 if (localizedName.equals(curLayout.getName(locale)) ||
855 friendlyURL.equals(curLayout.getFriendlyURL())) {
856
857 existingLayout = curLayout;
858
859 break;
860 }
861 }
862
863 if (existingLayout == null) {
864 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
865 groupId, privateLayout);
866 }
867 }
868 else if (layoutsImportMode.equals(
869 PortletDataHandlerKeys.
870 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
871
872 existingLayout = LayoutUtil.fetchByG_P_SPLU(
873 groupId, privateLayout, layout.getUuid());
874 }
875 else {
876
877
878
879
880 existingLayout = LayoutUtil.fetchByUUID_G(
881 layout.getUuid(), groupId);
882
883 if (existingLayout == null) {
884 existingLayout = LayoutUtil.fetchByG_P_F(
885 groupId, privateLayout, friendlyURL);
886 }
887
888 if (existingLayout == null) {
889 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
890 groupId, privateLayout);
891 }
892 }
893
894 if (_log.isDebugEnabled()) {
895 if (existingLayout == null) {
896 _log.debug(
897 "Layout with {groupId=" + groupId + ",privateLayout=" +
898 privateLayout + ",layoutId=" + layoutId +
899 "} does not exist");
900 }
901 else {
902 _log.debug(
903 "Layout with {groupId=" + groupId + ",privateLayout=" +
904 privateLayout + ",layoutId=" + layoutId +
905 "} exists");
906 }
907 }
908
909 if (existingLayout == null) {
910 long plid = CounterLocalServiceUtil.increment();
911
912 importedLayout = LayoutUtil.create(plid);
913
914 if (layoutsImportMode.equals(
915 PortletDataHandlerKeys.
916 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
917
918 importedLayout.setSourcePrototypeLayoutUuid(layout.getUuid());
919 }
920 else {
921 importedLayout.setUuid(layout.getUuid());
922 }
923
924 importedLayout.setGroupId(groupId);
925 importedLayout.setPrivateLayout(privateLayout);
926 importedLayout.setLayoutId(layoutId);
927
928 if (layout.isIconImage()) {
929 long iconImageId = CounterLocalServiceUtil.increment();
930
931 importedLayout.setIconImageId(iconImageId);
932 }
933
934
935
936 boolean addGroupPermissions = true;
937
938 Group group = importedLayout.getGroup();
939
940 if (privateLayout && group.isUser()) {
941 addGroupPermissions = false;
942 }
943
944 boolean addGuestPermissions = false;
945
946 if (!privateLayout || layout.isTypeControlPanel()) {
947 addGuestPermissions = true;
948 }
949
950 ResourceLocalServiceUtil.addResources(
951 user.getCompanyId(), groupId, user.getUserId(),
952 Layout.class.getName(), importedLayout.getPlid(), false,
953 addGroupPermissions, addGuestPermissions);
954
955 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
956 groupId, privateLayout);
957
958 importedLayout.setLayoutSet(layoutSet);
959 }
960 else {
961 importedLayout = existingLayout;
962 }
963
964 newLayoutsMap.put(oldLayoutId, importedLayout);
965
966 long parentLayoutId = layout.getParentLayoutId();
967
968 Node parentLayoutNode = rootElement.selectSingleNode(
969 "./layouts/layout[@layout-id='" + parentLayoutId + "']");
970
971 String parentLayoutUuid = GetterUtil.getString(
972 layoutElement.attributeValue("parent-layout-uuid"));
973
974 if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
975 (parentLayoutNode != null)) {
976
977 importLayout(
978 portletDataContext, user, layoutCache, previousLayouts,
979 newLayouts, newLayoutsMap, newLayoutIds, portletsMergeMode,
980 themeId, colorSchemeId, layoutsImportMode, privateLayout,
981 importPermissions, importPublicLayoutPermissions,
982 importUserPermissions, importThemeSettings,
983 rootElement, (Element)parentLayoutNode);
984
985 Layout parentLayout = newLayoutsMap.get(parentLayoutId);
986
987 parentLayoutId = parentLayout.getLayoutId();
988 }
989 else if (Validator.isNotNull(parentLayoutUuid)) {
990 Layout parentLayout =
991 LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
992 parentLayoutUuid, groupId);
993
994 parentLayoutId = parentLayout.getLayoutId();
995 }
996
997 if (_log.isDebugEnabled()) {
998 _log.debug(
999 "Importing layout with layout id " + layoutId +
1000 " and parent layout id " + parentLayoutId);
1001 }
1002
1003 importedLayout.setCompanyId(user.getCompanyId());
1004 importedLayout.setParentLayoutId(parentLayoutId);
1005 importedLayout.setName(layout.getName());
1006 importedLayout.setTitle(layout.getTitle());
1007 importedLayout.setDescription(layout.getDescription());
1008 importedLayout.setKeywords(layout.getKeywords());
1009 importedLayout.setRobots(layout.getRobots());
1010 importedLayout.setType(layout.getType());
1011
1012 if (layout.isTypeArticle()) {
1013 importJournalArticle(portletDataContext, layout, layoutElement);
1014
1015 importedLayout.setTypeSettings(layout.getTypeSettings());
1016 }
1017 else if (layout.isTypePortlet() &&
1018 Validator.isNotNull(layout.getTypeSettings()) &&
1019 !portletsMergeMode.equals(
1020 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
1021
1022 mergePortlets(
1023 importedLayout, layout.getTypeSettings(), portletsMergeMode);
1024 }
1025 else if (layout.isTypeLinkToLayout()) {
1026 UnicodeProperties typeSettingsProperties =
1027 layout.getTypeSettingsProperties();
1028
1029 long linkToLayoutId = GetterUtil.getLong(
1030 typeSettingsProperties.getProperty(
1031 "linkToLayoutId", StringPool.BLANK));
1032
1033 if (linkToLayoutId > 0) {
1034 Node linkedLayoutNode = rootElement.selectSingleNode(
1035 "./layouts/layout[@layout-id='" + linkToLayoutId + "']");
1036
1037 if (linkedLayoutNode != null) {
1038 importLayout(
1039 portletDataContext, user, layoutCache, previousLayouts,
1040 newLayouts, newLayoutsMap, newLayoutIds,
1041 portletsMergeMode, themeId, colorSchemeId,
1042 layoutsImportMode, privateLayout, importPermissions,
1043 importPublicLayoutPermissions, importUserPermissions,
1044 importThemeSettings, rootElement,
1045 (Element)linkedLayoutNode);
1046
1047 Layout linkedLayout = newLayoutsMap.get(linkToLayoutId);
1048
1049 typeSettingsProperties.setProperty(
1050 "privateLayout",
1051 String.valueOf(linkedLayout.getPrivateLayout()));
1052 typeSettingsProperties.setProperty(
1053 "linkToLayoutId",
1054 String.valueOf(linkedLayout.getLayoutId()));
1055 }
1056 else {
1057 if (_log.isWarnEnabled()) {
1058 StringBundler sb = new StringBundler();
1059
1060 sb.append("Unable to link layout with friendly URL ");
1061 sb.append(layout.getFriendlyURL());
1062 sb.append(" and layout id ");
1063 sb.append(layout.getLayoutId());
1064 sb.append(" to layout with layout id ");
1065 sb.append(linkToLayoutId);
1066
1067 _log.warn(sb.toString());
1068 }
1069 }
1070 }
1071
1072 importedLayout.setTypeSettings(layout.getTypeSettings());
1073 }
1074 else {
1075 importedLayout.setTypeSettings(layout.getTypeSettings());
1076 }
1077
1078 importedLayout.setHidden(layout.isHidden());
1079 importedLayout.setFriendlyURL(friendlyURL);
1080
1081 if (importThemeSettings) {
1082 importedLayout.setThemeId(layout.getThemeId());
1083 importedLayout.setColorSchemeId(layout.getColorSchemeId());
1084 }
1085 else {
1086 importedLayout.setThemeId(StringPool.BLANK);
1087 importedLayout.setColorSchemeId(StringPool.BLANK);
1088 }
1089
1090 importedLayout.setWapThemeId(layout.getWapThemeId());
1091 importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
1092 importedLayout.setCss(layout.getCss());
1093 importedLayout.setPriority(layout.getPriority());
1094
1095 StagingUtil.updateLastImportSettings(
1096 layoutElement, importedLayout, portletDataContext);
1097
1098 fixTypeSettings(importedLayout);
1099
1100 if (layout.isIconImage()) {
1101 String iconImagePath = layoutElement.elementText("icon-image-path");
1102
1103 byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
1104 iconImagePath);
1105
1106 if ((iconBytes != null) && (iconBytes.length > 0)) {
1107 importedLayout.setIconImage(true);
1108
1109 ImageLocalServiceUtil.updateImage(
1110 importedLayout.getIconImageId(), iconBytes);
1111 }
1112 }
1113 else {
1114 ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
1115 }
1116
1117 ServiceContext serviceContext = portletDataContext.createServiceContext(
1118 layoutElement, importedLayout, null);
1119
1120 importedLayout.setExpandoBridgeAttributes(serviceContext);
1121
1122 LayoutUtil.update(importedLayout, false);
1123
1124 portletDataContext.setPlid(importedLayout.getPlid());
1125 portletDataContext.setOldPlid(layout.getPlid());
1126
1127 newLayoutIds.add(importedLayout.getLayoutId());
1128
1129 newLayouts.add(importedLayout);
1130
1131
1132
1133 if (importPermissions) {
1134 _permissionImporter.importLayoutPermissions(
1135 layoutCache, portletDataContext.getCompanyId(), groupId,
1136 user.getUserId(), importedLayout, layoutElement, rootElement,
1137 importUserPermissions);
1138 }
1139
1140 if (importPublicLayoutPermissions) {
1141 String resourceName = Layout.class.getName();
1142 String resourcePrimKey = String.valueOf(importedLayout.getPlid());
1143
1144 Role guestRole = RoleLocalServiceUtil.getRole(
1145 importedLayout.getCompanyId(), RoleConstants.GUEST);
1146
1147 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
1148 Resource resource = layoutCache.getResource(
1149 importedLayout.getCompanyId(), groupId, resourceName,
1150 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey, false);
1151
1152 PermissionLocalServiceUtil.setRolePermissions(
1153 guestRole.getRoleId(), new String[] {ActionKeys.VIEW},
1154 resource.getResourceId());
1155 }
1156 else if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
1157 ResourcePermissionLocalServiceUtil.setResourcePermissions(
1158 importedLayout.getCompanyId(), resourceName,
1159 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
1160 guestRole.getRoleId(), new String[] {ActionKeys.VIEW});
1161 }
1162 else {
1163 Resource resource = layoutCache.getResource(
1164 importedLayout.getCompanyId(), groupId, resourceName,
1165 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey, false);
1166
1167 PermissionLocalServiceUtil.setGroupPermissions(
1168 groupId, new String[] {ActionKeys.VIEW},
1169 resource.getResourceId());
1170 }
1171 }
1172
1173 _portletImporter.importPortletData(
1174 portletDataContext, PortletKeys.LAYOUT_CONFIGURATION, null,
1175 layoutElement);
1176 }
1177
1178 protected void importLayoutSetPrototype(
1179 PortletDataContext portletDataContext, User user,
1180 String layoutSetPrototypeUuid, ServiceContext serviceContext)
1181 throws PortalException, SystemException {
1182
1183 String path = getLayoutSetPrototype(
1184 portletDataContext, layoutSetPrototypeUuid);
1185
1186 LayoutSetPrototype layoutSetPrototype = null;
1187
1188 try {
1189 layoutSetPrototype =
1190 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
1191 layoutSetPrototypeUuid);
1192 }
1193 catch (NoSuchLayoutSetPrototypeException nslspe) {
1194 }
1195
1196 if (layoutSetPrototype == null) {
1197 layoutSetPrototype =
1198 (LayoutSetPrototype)portletDataContext.getZipEntryAsObject(
1199 path.concat(".xml"));
1200
1201 serviceContext.setUuid(layoutSetPrototypeUuid);
1202
1203 layoutSetPrototype =
1204 LayoutSetPrototypeLocalServiceUtil.addLayoutSetPrototype(
1205 user.getUserId(), user.getCompanyId(),
1206 layoutSetPrototype.getNameMap(),
1207 layoutSetPrototype.getDescription(),
1208 layoutSetPrototype.getActive(), true, serviceContext);
1209 }
1210
1211 InputStream inputStream = portletDataContext.getZipEntryAsInputStream(
1212 path.concat(".lar"));
1213
1214 SitesUtil.importLayoutSetPrototype(
1215 layoutSetPrototype, inputStream, serviceContext);
1216 }
1217
1218 protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
1219 throws Exception {
1220
1221 ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
1222
1223 if (themeLoader == null) {
1224 _log.error("No theme loaders are deployed");
1225
1226 return null;
1227 }
1228
1229 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
1230
1231 String lookAndFeelXML = zipReader.getEntryAsString(
1232 "liferay-look-and-feel.xml");
1233
1234 String themeId = String.valueOf(layoutSet.getGroupId());
1235
1236 if (layoutSet.isPrivateLayout()) {
1237 themeId += "-private";
1238 }
1239 else {
1240 themeId += "-public";
1241 }
1242
1243 if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
1244 Date now = new Date();
1245
1246 themeId += "-" + Time.getShortTimestamp(now);
1247 }
1248
1249 String themeName = themeId;
1250
1251 lookAndFeelXML = StringUtil.replace(
1252 lookAndFeelXML,
1253 new String[] {
1254 "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
1255 },
1256 new String[] {
1257 String.valueOf(layoutSet.getGroupId()), themeId, themeName
1258 }
1259 );
1260
1261 FileUtil.deltree(
1262 themeLoader.getFileStorage() + StringPool.SLASH + themeId);
1263
1264 List<String> zipEntries = zipReader.getEntries();
1265
1266 for (String zipEntry : zipEntries) {
1267 String key = zipEntry;
1268
1269 if (key.equals("liferay-look-and-feel.xml")) {
1270 FileUtil.write(
1271 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1272 StringPool.SLASH + key,
1273 lookAndFeelXML.getBytes());
1274 }
1275 else {
1276 InputStream is = zipReader.getEntryAsInputStream(zipEntry);
1277
1278 FileUtil.write(
1279 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1280 StringPool.SLASH + key,
1281 is);
1282 }
1283 }
1284
1285 themeLoader.loadThemes();
1286
1287 ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
1288 _loadThemesMethodHandler, true);
1289
1290 clusterRequest.setFireAndForget(true);
1291
1292 ClusterExecutorUtil.execute(clusterRequest);
1293
1294 themeId +=
1295 PortletConstants.WAR_SEPARATOR +
1296 themeLoader.getServletContextName();
1297
1298 return PortalUtil.getJsSafePortletId(themeId);
1299 }
1300
1301 protected void mergePortlets(
1302 Layout layout, String newTypeSettings, String portletsMergeMode) {
1303
1304 try {
1305 UnicodeProperties previousTypeSettingsProperties =
1306 layout.getTypeSettingsProperties();
1307
1308 LayoutTypePortlet previousLayoutType =
1309 (LayoutTypePortlet)layout.getLayoutType();
1310
1311 LayoutTemplate previousLayoutTemplate =
1312 previousLayoutType.getLayoutTemplate();
1313
1314 List<String> previousColumns = previousLayoutTemplate.getColumns();
1315
1316 UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1317 true);
1318
1319 newTypeSettingsProperties.load(newTypeSettings);
1320
1321 String layoutTemplateId = newTypeSettingsProperties.getProperty(
1322 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1323
1324 previousTypeSettingsProperties.setProperty(
1325 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1326 layoutTemplateId);
1327
1328 LayoutTemplate newLayoutTemplate =
1329 LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1330 layoutTemplateId, false, null);
1331
1332 String[] newPortletIds = new String[0];
1333
1334 for (String columnId : newLayoutTemplate.getColumns()) {
1335 String columnValue = newTypeSettingsProperties.getProperty(
1336 columnId);
1337
1338 String[] portletIds = StringUtil.split(columnValue);
1339
1340 if (!previousColumns.contains(columnId)) {
1341 newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1342 }
1343 else {
1344 String[] previousPortletIds = StringUtil.split(
1345 previousTypeSettingsProperties.getProperty(columnId));
1346
1347 portletIds = appendPortletIds(
1348 previousPortletIds, portletIds, portletsMergeMode);
1349
1350 previousTypeSettingsProperties.setProperty(
1351 columnId, StringUtil.merge(portletIds));
1352 }
1353 }
1354
1355
1356
1357 String columnId = previousColumns.get(0);
1358
1359 String[] portletIds = StringUtil.split(
1360 previousTypeSettingsProperties.getProperty(columnId));
1361
1362 appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1363
1364 previousTypeSettingsProperties.setProperty(
1365 columnId, StringUtil.merge(portletIds));
1366
1367 layout.setTypeSettings(previousTypeSettingsProperties.toString());
1368 }
1369 catch (IOException ioe) {
1370 layout.setTypeSettings(newTypeSettings);
1371 }
1372 }
1373
1374 private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1375
1376 private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1377 new MethodKey(ThemeLoaderFactory.class.getName(), "loadThemes"));
1378
1379 private PermissionImporter _permissionImporter = new PermissionImporter();
1380 private PortletImporter _portletImporter = new PortletImporter();
1381
1382 }