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 layoutSetPrototypeInherited = MapUtil.getBoolean(
233 parameterMap,
234 PortletDataHandlerKeys.LAYOUT_SET_PROTOTYPE_INHERITED);
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_ID);
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 (layoutSetPrototypeInherited) {
356 if (publishToRemote) {
357 importLayoutSetPrototype(
358 portletDataContext, user, layoutSetPrototypeUuid,
359 serviceContext);
360 }
361 }
362
363 layoutSet.setLayoutSetPrototypeUuid(layoutSetPrototypeUuid);
364 layoutSet.setLayoutSetPrototypeLinkEnabled(
365 layoutSetPrototypeInherited);
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 List<Layout> newLayouts = new ArrayList<Layout>();
442
443 Set<Long> newLayoutIds = new HashSet<Long>();
444
445 Map<Long, Layout> newLayoutsMap =
446 (Map<Long, Layout>)portletDataContext.getNewPrimaryKeysMap(
447 Layout.class);
448
449 Element layoutsElement = rootElement.element("layouts");
450
451 List<Element> layoutElements = layoutsElement.elements("layout");
452
453 if (_log.isDebugEnabled()) {
454 if (layoutElements.size() > 0) {
455 _log.debug("Importing layouts");
456 }
457 }
458
459 for (Element layoutElement : layoutElements) {
460 importLayout(
461 portletDataContext, user, layoutCache, previousLayouts,
462 newLayouts, newLayoutsMap, newLayoutIds, portletsMergeMode,
463 themeId, colorSchemeId, layoutsImportMode, privateLayout,
464 importPermissions, importPublicLayoutPermissions,
465 importUserPermissions, importThemeSettings,
466 rootElement, layoutElement);
467 }
468
469 Element portletsElement = rootElement.element("portlets");
470
471 List<Element> portletElements = portletsElement.elements("portlet");
472
473
474
475 if (deletePortletData) {
476 if (_log.isDebugEnabled()) {
477 if (portletElements.size() > 0) {
478 _log.debug("Deleting portlet data");
479 }
480 }
481
482 for (Element portletElement : portletElements) {
483 String portletId = portletElement.attributeValue("portlet-id");
484 long layoutId = GetterUtil.getLong(
485 portletElement.attributeValue("layout-id"));
486 long plid = newLayoutsMap.get(layoutId).getPlid();
487
488 portletDataContext.setPlid(plid);
489
490 _portletImporter.deletePortletData(
491 portletDataContext, portletId, plid);
492 }
493 }
494
495
496
497 if (_log.isDebugEnabled()) {
498 if (portletElements.size() > 0) {
499 _log.debug("Importing portlets");
500 }
501 }
502
503 for (Element portletElement : portletElements) {
504 String portletPath = portletElement.attributeValue("path");
505 String portletId = portletElement.attributeValue("portlet-id");
506 long layoutId = GetterUtil.getLong(
507 portletElement.attributeValue("layout-id"));
508 long plid = newLayoutsMap.get(layoutId).getPlid();
509 long oldPlid = GetterUtil.getLong(
510 portletElement.attributeValue("old-plid"));
511
512 Portlet portlet = PortletLocalServiceUtil.getPortletById(
513 portletDataContext.getCompanyId(), portletId);
514
515 if (!portlet.isActive() || portlet.isUndeployedPortlet()) {
516 continue;
517 }
518
519 Layout layout = null;
520
521 try {
522 layout = LayoutUtil.findByPrimaryKey(plid);
523 }
524 catch (NoSuchLayoutException nsle) {
525 continue;
526 }
527
528 portletDataContext.setPlid(plid);
529 portletDataContext.setOldPlid(oldPlid);
530
531 Document portletDocument = SAXReaderUtil.read(
532 portletDataContext.getZipEntryAsString(portletPath));
533
534 portletElement = portletDocument.getRootElement();
535
536
537
538
539
540
541 _portletImporter.setPortletScope(
542 portletDataContext, portletElement);
543
544 try {
545
546
547
548 _portletImporter.importPortletPreferences(
549 portletDataContext, layoutSet.getCompanyId(),
550 layout.getGroupId(), layout, null, portletElement,
551 importPortletSetup, importPortletArchivedSetups,
552 importPortletUserPreferences, false);
553
554
555
556 Element portletDataElement = portletElement.element(
557 "portlet-data");
558
559 if (importPortletData && (portletDataElement != null)) {
560 _portletImporter.importPortletData(
561 portletDataContext, portletId, plid,
562 portletDataElement);
563 }
564 }
565 finally {
566 _portletImporter.resetPortletScope(
567 portletDataContext, layout.getGroupId());
568 }
569
570
571
572 if (importPermissions) {
573 _permissionImporter.importPortletPermissions(
574 layoutCache, companyId, groupId, userId, layout,
575 portletElement, portletId, importUserPermissions);
576 }
577
578
579
580 _portletImporter.importPortletPreferences(
581 portletDataContext, layoutSet.getCompanyId(), groupId, null,
582 null, portletElement, importPortletSetup,
583 importPortletArchivedSetups, importPortletUserPreferences,
584 false);
585 }
586
587 if (importPermissions) {
588 if ((userId > 0) &&
589 ((PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) ||
590 (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6))) {
591
592 Indexer indexer = IndexerRegistryUtil.getIndexer(User.class);
593
594 indexer.reindex(userId);
595 }
596 }
597
598
599
600 _portletImporter.readAssetLinks(portletDataContext);
601
602
603
604 if (deleteMissingLayouts) {
605 deleteMissingLayouts(
606 groupId, privateLayout, newLayoutIds, previousLayouts,
607 serviceContext);
608 }
609
610
611
612 LayoutSetLocalServiceUtil.updatePageCount(groupId, privateLayout);
613
614 if (_log.isInfoEnabled()) {
615 _log.info("Importing layouts takes " + stopWatch.getTime() + " ms");
616 }
617
618
619
620 GroupLocalServiceUtil.updateSite(groupId, true);
621
622
623
624 for (Layout layout : newLayouts) {
625 UnicodeProperties typeSettingsProperties =
626 layout.getTypeSettingsProperties();
627
628 String articleId = typeSettingsProperties.getProperty("article-id");
629
630 if (Validator.isNotNull(articleId)) {
631 Map<String, String> articleIds =
632 (Map<String, String>)portletDataContext.
633 getNewPrimaryKeysMap(
634 JournalArticle.class + ".articleId");
635
636 typeSettingsProperties.setProperty(
637 "article-id",
638 MapUtil.getString(articleIds, articleId, articleId));
639
640 LayoutUtil.update(layout, false);
641 }
642 }
643
644 zipReader.close();
645 }
646
647 protected String getLayoutSetPrototype(
648 PortletDataContext portletDataContext, String layoutSetPrototypeUuid) {
649
650 StringBundler sb = new StringBundler(3);
651
652 sb.append(portletDataContext.getSourceRootPath());
653 sb.append("/layout-set-prototype/");
654 sb.append(layoutSetPrototypeUuid);
655
656 return sb.toString();
657 }
658
659 protected void fixTypeSettings(Layout layout) throws Exception {
660 if (!layout.isTypeURL()) {
661 return;
662 }
663
664 UnicodeProperties typeSettings = layout.getTypeSettingsProperties();
665
666 String url = GetterUtil.getString(typeSettings.getProperty("url"));
667
668 String friendlyURLPrivateGroupPath =
669 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
670 String friendlyURLPrivateUserPath =
671 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
672 String friendlyURLPublicPath =
673 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
674
675 if (!url.startsWith(friendlyURLPrivateGroupPath) &&
676 !url.startsWith(friendlyURLPrivateUserPath) &&
677 !url.startsWith(friendlyURLPublicPath)) {
678
679 return;
680 }
681
682 int x = url.indexOf(CharPool.SLASH, 1);
683
684 if (x == -1) {
685 return;
686 }
687
688 int y = url.indexOf(CharPool.SLASH, x + 1);
689
690 if (y == -1) {
691 return;
692 }
693
694 String friendlyURL = url.substring(x, y);
695
696 if (!friendlyURL.equals(LayoutExporter.SAME_GROUP_FRIENDLY_URL)) {
697 return;
698 }
699
700 Group group = layout.getGroup();
701
702 typeSettings.setProperty(
703 "url",
704 url.substring(0, x) + group.getFriendlyURL() + url.substring(y));
705 }
706
707 protected void importJournalArticle(
708 PortletDataContext portletDataContext, Layout layout,
709 Element layoutElement)
710 throws Exception {
711
712 UnicodeProperties typeSettingsProperties =
713 layout.getTypeSettingsProperties();
714
715 String articleId = typeSettingsProperties.getProperty(
716 "article-id", StringPool.BLANK);
717
718 if (Validator.isNull(articleId)) {
719 return;
720 }
721
722 JournalPortletDataHandlerImpl.importReferencedData(
723 portletDataContext, layoutElement);
724
725 Element structureElement = layoutElement.element("structure");
726
727 if (structureElement != null) {
728 JournalPortletDataHandlerImpl.importStructure(
729 portletDataContext, structureElement);
730 }
731
732 Element templateElement = layoutElement.element("template");
733
734 if (templateElement != null) {
735 JournalPortletDataHandlerImpl.importTemplate(
736 portletDataContext, templateElement);
737 }
738
739 Element articleElement = layoutElement.element("article");
740
741 if (articleElement != null) {
742 JournalPortletDataHandlerImpl.importArticle(
743 portletDataContext, articleElement);
744 }
745
746 Map<String, String> articleIds =
747 (Map<String, String>)portletDataContext.getNewPrimaryKeysMap(
748 JournalArticle.class + ".articleId");
749
750 articleId = MapUtil.getString(articleIds, articleId, articleId);
751
752 typeSettingsProperties.setProperty("article-id", articleId);
753
754 JournalContentSearchLocalServiceUtil.updateContentSearch(
755 portletDataContext.getScopeGroupId(), layout.isPrivateLayout(),
756 layout.getLayoutId(), StringPool.BLANK, articleId, true);
757 }
758
759 protected void importLayout(
760 PortletDataContext portletDataContext, User user,
761 LayoutCache layoutCache, List<Layout> previousLayouts,
762 List<Layout> newLayouts, Map<Long, Layout> newLayoutsMap,
763 Set<Long> newLayoutIds, String portletsMergeMode, String themeId,
764 String colorSchemeId, String layoutsImportMode,
765 boolean privateLayout, boolean importPermissions,
766 boolean importPublicLayoutPermissions,
767 boolean importUserPermissions, boolean importThemeSettings,
768 Element rootElement, Element layoutElement)
769 throws Exception {
770
771 long groupId = portletDataContext.getGroupId();
772
773 String layoutUuid = GetterUtil.getString(
774 layoutElement.attributeValue("layout-uuid"));
775
776 long layoutId = GetterUtil.getInteger(
777 layoutElement.attributeValue("layout-id"));
778
779 long oldLayoutId = layoutId;
780
781 boolean deleteLayout = GetterUtil.getBoolean(
782 layoutElement.attributeValue("delete"));
783
784 if (deleteLayout) {
785 Layout layout = LayoutLocalServiceUtil.fetchLayoutByUuidAndGroupId(
786 layoutUuid, groupId);
787
788 if (layout != null) {
789 newLayoutsMap.put(oldLayoutId, layout);
790
791 LayoutLocalServiceUtil.deleteLayout(layout);
792 }
793
794 return;
795 }
796
797 String path = layoutElement.attributeValue("path");
798
799 if (!portletDataContext.isPathNotProcessed(path)) {
800 return;
801 }
802
803 Layout layout = (Layout)portletDataContext.getZipEntryAsObject(path);
804
805 Layout existingLayout = null;
806 Layout importedLayout = null;
807
808 String friendlyURL = layout.getFriendlyURL();
809
810 if (layoutsImportMode.equals(
811 PortletDataHandlerKeys.LAYOUTS_IMPORT_MODE_ADD_AS_NEW)) {
812
813 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
814 groupId, privateLayout);
815 friendlyURL = StringPool.SLASH + layoutId;
816 }
817 else if (layoutsImportMode.equals(
818 PortletDataHandlerKeys.
819 LAYOUTS_IMPORT_MODE_MERGE_BY_LAYOUT_NAME)) {
820
821 Locale locale = LocaleUtil.getDefault();
822
823 String localizedName = layout.getName(locale);
824
825 for (Layout curLayout : previousLayouts) {
826 if (localizedName.equals(curLayout.getName(locale)) ||
827 friendlyURL.equals(curLayout.getFriendlyURL())) {
828
829 existingLayout = curLayout;
830
831 break;
832 }
833 }
834
835 if (existingLayout == null) {
836 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
837 groupId, privateLayout);
838 }
839 }
840 else if (layoutsImportMode.equals(
841 PortletDataHandlerKeys.
842 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
843
844 existingLayout = LayoutUtil.fetchByG_P_TLU(
845 groupId, privateLayout, layout.getUuid());
846 }
847 else {
848
849
850
851
852 existingLayout = LayoutUtil.fetchByUUID_G(
853 layout.getUuid(), groupId);
854
855 if (existingLayout == null) {
856 existingLayout = LayoutUtil.fetchByG_P_F(
857 groupId, privateLayout, friendlyURL);
858 }
859
860 if (existingLayout == null) {
861 layoutId = LayoutLocalServiceUtil.getNextLayoutId(
862 groupId, privateLayout);
863 }
864 }
865
866 if (_log.isDebugEnabled()) {
867 if (existingLayout == null) {
868 _log.debug(
869 "Layout with {groupId=" + groupId + ",privateLayout=" +
870 privateLayout + ",layoutId=" + layoutId +
871 "} does not exist");
872 }
873 else {
874 _log.debug(
875 "Layout with {groupId=" + groupId + ",privateLayout=" +
876 privateLayout + ",layoutId=" + layoutId +
877 "} exists");
878 }
879 }
880
881 if (existingLayout == null) {
882 long plid = CounterLocalServiceUtil.increment();
883
884 importedLayout = LayoutUtil.create(plid);
885
886 if (layoutsImportMode.equals(
887 PortletDataHandlerKeys.
888 LAYOUTS_IMPORT_MODE_CREATED_FROM_PROTOTYPE)) {
889
890 importedLayout.setTemplateLayoutUuid(layout.getUuid());
891 }
892 else {
893 importedLayout.setUuid(layout.getUuid());
894 }
895
896 importedLayout.setGroupId(groupId);
897 importedLayout.setPrivateLayout(privateLayout);
898 importedLayout.setLayoutId(layoutId);
899
900 if (layout.isIconImage()) {
901 long iconImageId = CounterLocalServiceUtil.increment();
902
903 importedLayout.setIconImageId(iconImageId);
904 }
905
906
907
908 boolean addGroupPermissions = true;
909
910 Group group = layout.getGroup();
911
912 if (privateLayout && group.isUser()) {
913 addGroupPermissions = false;
914 }
915
916 boolean addGuestPermissions = false;
917
918 if (!privateLayout || layout.isTypeControlPanel()) {
919 addGuestPermissions = true;
920 }
921
922 ResourceLocalServiceUtil.addResources(
923 user.getCompanyId(), groupId, user.getUserId(),
924 Layout.class.getName(), importedLayout.getPlid(), false,
925 addGroupPermissions, addGuestPermissions);
926
927 LayoutSet layoutSet = LayoutSetLocalServiceUtil.getLayoutSet(
928 groupId, privateLayout);
929
930 importedLayout.setLayoutSet(layoutSet);
931 }
932 else {
933 importedLayout = existingLayout;
934 }
935
936 newLayoutsMap.put(oldLayoutId, importedLayout);
937
938 long parentLayoutId = layout.getParentLayoutId();
939
940 Node parentLayoutNode = rootElement.selectSingleNode(
941 "./layouts/layout[@layout-id='" + parentLayoutId + "']");
942
943 String parentLayoutUuid = GetterUtil.getString(
944 layoutElement.attributeValue("parent-layout-uuid"));
945
946 if ((parentLayoutId != LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) &&
947 (parentLayoutNode != null)) {
948
949 importLayout(
950 portletDataContext, user, layoutCache, previousLayouts,
951 newLayouts, newLayoutsMap, newLayoutIds, portletsMergeMode,
952 themeId, colorSchemeId, layoutsImportMode, privateLayout,
953 importPermissions, importPublicLayoutPermissions,
954 importUserPermissions, importThemeSettings,
955 rootElement, (Element)parentLayoutNode);
956
957 Layout parentLayout = newLayoutsMap.get(parentLayoutId);
958
959 parentLayoutId = parentLayout.getLayoutId();
960 }
961 else if (Validator.isNotNull(parentLayoutUuid)) {
962 Layout parentLayout =
963 LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
964 parentLayoutUuid, groupId);
965
966 parentLayoutId = parentLayout.getLayoutId();
967 }
968
969 if (_log.isDebugEnabled()) {
970 _log.debug(
971 "Importing layout with layout id " + layoutId +
972 " and parent layout id " + parentLayoutId);
973 }
974
975 importedLayout.setCompanyId(user.getCompanyId());
976 importedLayout.setParentLayoutId(parentLayoutId);
977 importedLayout.setName(layout.getName());
978 importedLayout.setTitle(layout.getTitle());
979 importedLayout.setDescription(layout.getDescription());
980 importedLayout.setKeywords(layout.getKeywords());
981 importedLayout.setRobots(layout.getRobots());
982 importedLayout.setType(layout.getType());
983
984 if (layout.isTypeArticle()) {
985 importJournalArticle(portletDataContext, layout, layoutElement);
986
987 importedLayout.setTypeSettings(layout.getTypeSettings());
988 }
989 else if (layout.isTypePortlet() &&
990 Validator.isNotNull(layout.getTypeSettings()) &&
991 !portletsMergeMode.equals(
992 PortletDataHandlerKeys.PORTLETS_MERGE_MODE_REPLACE)) {
993
994 mergePortlets(
995 importedLayout, layout.getTypeSettings(), portletsMergeMode);
996 }
997 else if (layout.isTypeLinkToLayout()) {
998 UnicodeProperties typeSettingsProperties =
999 layout.getTypeSettingsProperties();
1000
1001 long linkToLayoutId = GetterUtil.getLong(
1002 typeSettingsProperties.getProperty(
1003 "linkToLayoutId", StringPool.BLANK));
1004
1005 if (linkToLayoutId > 0) {
1006 Node linkedLayoutNode = rootElement.selectSingleNode(
1007 "./layouts/layout[@layout-id='" + linkToLayoutId + "']");
1008
1009 if (linkedLayoutNode != null) {
1010 importLayout(
1011 portletDataContext, user, layoutCache, previousLayouts,
1012 newLayouts, newLayoutsMap, newLayoutIds,
1013 portletsMergeMode, themeId, colorSchemeId,
1014 layoutsImportMode, privateLayout, importPermissions,
1015 importPublicLayoutPermissions, importUserPermissions,
1016 importThemeSettings, rootElement,
1017 (Element)linkedLayoutNode);
1018
1019 Layout linkedLayout = newLayoutsMap.get(linkToLayoutId);
1020
1021 typeSettingsProperties.setProperty(
1022 "privateLayout",
1023 String.valueOf(linkedLayout.getPrivateLayout()));
1024 typeSettingsProperties.setProperty(
1025 "linkToLayoutId",
1026 String.valueOf(linkedLayout.getLayoutId()));
1027 }
1028 else {
1029 if (_log.isWarnEnabled()) {
1030 StringBundler sb = new StringBundler();
1031
1032 sb.append("Unable to link layout with friendly URL ");
1033 sb.append(layout.getFriendlyURL());
1034 sb.append(" and layout id ");
1035 sb.append(layout.getLayoutId());
1036 sb.append(" to layout with layout id ");
1037 sb.append(linkToLayoutId);
1038
1039 _log.warn(sb.toString());
1040 }
1041 }
1042 }
1043
1044 importedLayout.setTypeSettings(layout.getTypeSettings());
1045 }
1046 else {
1047 importedLayout.setTypeSettings(layout.getTypeSettings());
1048 }
1049
1050 importedLayout.setHidden(layout.isHidden());
1051 importedLayout.setFriendlyURL(friendlyURL);
1052
1053 if (importThemeSettings) {
1054 importedLayout.setThemeId(layout.getThemeId());
1055 importedLayout.setColorSchemeId(layout.getColorSchemeId());
1056 }
1057 else {
1058 importedLayout.setThemeId(StringPool.BLANK);
1059 importedLayout.setColorSchemeId(StringPool.BLANK);
1060 }
1061
1062 importedLayout.setWapThemeId(layout.getWapThemeId());
1063 importedLayout.setWapColorSchemeId(layout.getWapColorSchemeId());
1064 importedLayout.setCss(layout.getCss());
1065 importedLayout.setPriority(layout.getPriority());
1066
1067 StagingUtil.updateLastImportSettings(
1068 layoutElement, importedLayout, portletDataContext);
1069
1070 fixTypeSettings(importedLayout);
1071
1072 if (layout.isIconImage()) {
1073 String iconImagePath = layoutElement.elementText("icon-image-path");
1074
1075 byte[] iconBytes = portletDataContext.getZipEntryAsByteArray(
1076 iconImagePath);
1077
1078 if ((iconBytes != null) && (iconBytes.length > 0)) {
1079 importedLayout.setIconImage(true);
1080
1081 ImageLocalServiceUtil.updateImage(
1082 importedLayout.getIconImageId(), iconBytes);
1083 }
1084 }
1085 else {
1086 ImageLocalServiceUtil.deleteImage(importedLayout.getIconImageId());
1087 }
1088
1089 ServiceContext serviceContext = portletDataContext.createServiceContext(
1090 layoutElement, importedLayout, null);
1091
1092 importedLayout.setExpandoBridgeAttributes(serviceContext);
1093
1094 LayoutUtil.update(importedLayout, false);
1095
1096 portletDataContext.setPlid(importedLayout.getPlid());
1097 portletDataContext.setOldPlid(layout.getPlid());
1098
1099 newLayoutIds.add(importedLayout.getLayoutId());
1100
1101 newLayouts.add(importedLayout);
1102
1103
1104
1105 if (importPermissions) {
1106 _permissionImporter.importLayoutPermissions(
1107 layoutCache, portletDataContext.getCompanyId(), groupId,
1108 user.getUserId(), importedLayout, layoutElement, rootElement,
1109 importUserPermissions);
1110 }
1111
1112 if (importPublicLayoutPermissions) {
1113 String resourceName = Layout.class.getName();
1114 String resourcePrimKey = String.valueOf(importedLayout.getPlid());
1115
1116 Role guestRole = RoleLocalServiceUtil.getRole(
1117 importedLayout.getCompanyId(), RoleConstants.GUEST);
1118
1119 if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 5) {
1120 Resource resource = layoutCache.getResource(
1121 importedLayout.getCompanyId(), groupId, resourceName,
1122 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey, false);
1123
1124 PermissionLocalServiceUtil.setRolePermissions(
1125 guestRole.getRoleId(), new String[] {ActionKeys.VIEW},
1126 resource.getResourceId());
1127 }
1128 else if (PropsValues.PERMISSIONS_USER_CHECK_ALGORITHM == 6) {
1129 ResourcePermissionLocalServiceUtil.setResourcePermissions(
1130 importedLayout.getCompanyId(), resourceName,
1131 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey,
1132 guestRole.getRoleId(), new String[] {ActionKeys.VIEW});
1133 }
1134 else {
1135 Resource resource = layoutCache.getResource(
1136 importedLayout.getCompanyId(), groupId, resourceName,
1137 ResourceConstants.SCOPE_INDIVIDUAL, resourcePrimKey, false);
1138
1139 PermissionLocalServiceUtil.setGroupPermissions(
1140 groupId, new String[] {ActionKeys.VIEW},
1141 resource.getResourceId());
1142 }
1143 }
1144
1145 _portletImporter.importPortletData(
1146 portletDataContext, PortletKeys.LAYOUT_CONFIGURATION, null,
1147 layoutElement);
1148 }
1149
1150 protected void importLayoutSetPrototype(
1151 PortletDataContext portletDataContext, User user,
1152 String layoutSetPrototypeUuid, ServiceContext serviceContext)
1153 throws PortalException, SystemException {
1154
1155 String path = getLayoutSetPrototype(
1156 portletDataContext, layoutSetPrototypeUuid);
1157
1158 LayoutSetPrototype layoutSetPrototype = null;
1159
1160 try {
1161 layoutSetPrototype =
1162 LayoutSetPrototypeLocalServiceUtil.getLayoutSetPrototypeByUuid(
1163 layoutSetPrototypeUuid);
1164 }
1165 catch (NoSuchLayoutSetPrototypeException nslspe) {
1166 }
1167
1168 if (layoutSetPrototype == null) {
1169 layoutSetPrototype =
1170 (LayoutSetPrototype)portletDataContext.getZipEntryAsObject(
1171 path.concat(".xml"));
1172
1173 serviceContext.setUuid(layoutSetPrototypeUuid);
1174
1175 layoutSetPrototype =
1176 LayoutSetPrototypeLocalServiceUtil.addLayoutSetPrototype(
1177 user.getUserId(), user.getCompanyId(),
1178 layoutSetPrototype.getNameMap(),
1179 layoutSetPrototype.getDescription(),
1180 layoutSetPrototype.getActive(), true, true, serviceContext);
1181 }
1182
1183 InputStream inputStream = portletDataContext.getZipEntryAsInputStream(
1184 path.concat(".lar"));
1185
1186 SitesUtil.importLayoutSetPrototype(
1187 layoutSetPrototype, inputStream, serviceContext);
1188 }
1189
1190 protected String importTheme(LayoutSet layoutSet, InputStream themeZip)
1191 throws Exception {
1192
1193 ThemeLoader themeLoader = ThemeLoaderFactory.getDefaultThemeLoader();
1194
1195 if (themeLoader == null) {
1196 _log.error("No theme loaders are deployed");
1197
1198 return null;
1199 }
1200
1201 ZipReader zipReader = ZipReaderFactoryUtil.getZipReader(themeZip);
1202
1203 String lookAndFeelXML = zipReader.getEntryAsString(
1204 "liferay-look-and-feel.xml");
1205
1206 String themeId = String.valueOf(layoutSet.getGroupId());
1207
1208 if (layoutSet.isPrivateLayout()) {
1209 themeId += "-private";
1210 }
1211 else {
1212 themeId += "-public";
1213 }
1214
1215 if (PropsValues.THEME_LOADER_NEW_THEME_ID_ON_IMPORT) {
1216 Date now = new Date();
1217
1218 themeId += "-" + Time.getShortTimestamp(now);
1219 }
1220
1221 String themeName = themeId;
1222
1223 lookAndFeelXML = StringUtil.replace(
1224 lookAndFeelXML,
1225 new String[] {
1226 "[$GROUP_ID$]", "[$THEME_ID$]", "[$THEME_NAME$]"
1227 },
1228 new String[] {
1229 String.valueOf(layoutSet.getGroupId()), themeId, themeName
1230 }
1231 );
1232
1233 FileUtil.deltree(
1234 themeLoader.getFileStorage() + StringPool.SLASH + themeId);
1235
1236 List<String> zipEntries = zipReader.getEntries();
1237
1238 for (String zipEntry : zipEntries) {
1239 String key = zipEntry;
1240
1241 if (key.equals("liferay-look-and-feel.xml")) {
1242 FileUtil.write(
1243 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1244 StringPool.SLASH + key,
1245 lookAndFeelXML.getBytes());
1246 }
1247 else {
1248 InputStream is = zipReader.getEntryAsInputStream(zipEntry);
1249
1250 FileUtil.write(
1251 themeLoader.getFileStorage() + StringPool.SLASH + themeId +
1252 StringPool.SLASH + key,
1253 is);
1254 }
1255 }
1256
1257 themeLoader.loadThemes();
1258
1259 ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
1260 _loadThemesMethodHandler, true);
1261
1262 clusterRequest.setFireAndForget(true);
1263
1264 ClusterExecutorUtil.execute(clusterRequest);
1265
1266 themeId +=
1267 PortletConstants.WAR_SEPARATOR +
1268 themeLoader.getServletContextName();
1269
1270 return PortalUtil.getJsSafePortletId(themeId);
1271 }
1272
1273 protected void mergePortlets(
1274 Layout layout, String newTypeSettings, String portletsMergeMode) {
1275
1276 try {
1277 UnicodeProperties previousTypeSettingsProperties =
1278 layout.getTypeSettingsProperties();
1279
1280 LayoutTypePortlet previousLayoutType =
1281 (LayoutTypePortlet)layout.getLayoutType();
1282
1283 LayoutTemplate previousLayoutTemplate =
1284 previousLayoutType.getLayoutTemplate();
1285
1286 List<String> previousColumns = previousLayoutTemplate.getColumns();
1287
1288 UnicodeProperties newTypeSettingsProperties = new UnicodeProperties(
1289 true);
1290
1291 newTypeSettingsProperties.load(newTypeSettings);
1292
1293 String layoutTemplateId = newTypeSettingsProperties.getProperty(
1294 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID);
1295
1296 previousTypeSettingsProperties.setProperty(
1297 LayoutTypePortletConstants.LAYOUT_TEMPLATE_ID,
1298 layoutTemplateId);
1299
1300 LayoutTemplate newLayoutTemplate =
1301 LayoutTemplateLocalServiceUtil.getLayoutTemplate(
1302 layoutTemplateId, false, null);
1303
1304 String[] newPortletIds = new String[0];
1305
1306 for (String columnId : newLayoutTemplate.getColumns()) {
1307 String columnValue = newTypeSettingsProperties.getProperty(
1308 columnId);
1309
1310 String[] portletIds = StringUtil.split(columnValue);
1311
1312 if (!previousColumns.contains(columnId)) {
1313 newPortletIds = ArrayUtil.append(newPortletIds, portletIds);
1314 }
1315 else {
1316 String[] previousPortletIds = StringUtil.split(
1317 previousTypeSettingsProperties.getProperty(columnId));
1318
1319 portletIds = appendPortletIds(
1320 previousPortletIds, portletIds, portletsMergeMode);
1321
1322 previousTypeSettingsProperties.setProperty(
1323 columnId, StringUtil.merge(portletIds));
1324 }
1325 }
1326
1327
1328
1329 String columnId = previousColumns.get(0);
1330
1331 String[] portletIds = StringUtil.split(
1332 previousTypeSettingsProperties.getProperty(columnId));
1333
1334 appendPortletIds(portletIds, newPortletIds, portletsMergeMode);
1335
1336 previousTypeSettingsProperties.setProperty(
1337 columnId, StringUtil.merge(portletIds));
1338
1339 layout.setTypeSettings(previousTypeSettingsProperties.toString());
1340 }
1341 catch (IOException ioe) {
1342 layout.setTypeSettings(newTypeSettings);
1343 }
1344 }
1345
1346 private static Log _log = LogFactoryUtil.getLog(LayoutImporter.class);
1347
1348 private static MethodHandler _loadThemesMethodHandler = new MethodHandler(
1349 new MethodKey(ThemeLoaderFactory.class.getName(), "loadThemes"));
1350
1351 private PermissionImporter _permissionImporter = new PermissionImporter();
1352 private PortletImporter _portletImporter = new PortletImporter();
1353
1354 }