From 232e8f9b0fc17077e756d48f7ed1d869e328933f Mon Sep 17 00:00:00 2001 From: ashklianko Date: Tue, 18 Jul 2023 15:19:10 +0200 Subject: [PATCH] Rollback Page object resolving: inject empty regions to the page object when returning content #10209 -Introduced xp.content config variable resolveEmptyRegions (set to 'false' by default) that allows to switch between previous content page resolving behavior that forces injection of all descriptor's regions into page/layout and new one where content's page object is returned as it is -Updated core-content classes to read config variable and build page object according to it -Updated portal-impl classes to read descriptor and inject empty regions into page if it is not being made by content api, and not to read and inject regions if it is done by content api --- .../LayoutDescriptorNotFoundException.java | 16 - .../PartDescriptorNotFoundException.java | 17 - ...tractCreatingOrUpdatingContentCommand.java | 39 ++ .../xp/core/impl/content/ContentConfig.java | 2 + .../impl/content/ContentNodeTranslator.java | 15 +- ...ontentOutboundDependenciesIdsResolver.java | 4 +- .../core/impl/content/ContentServiceImpl.java | 34 +- .../impl/content/CreateContentCommand.java | 37 +- .../core/impl/content/CreateMediaCommand.java | 37 +- .../impl/content/CreateNodeParamsFactory.java | 13 +- .../content/FullContentNodeTranslator.java | 127 ++++++ .../impl/content/ImportContentCommand.java | 1 + .../impl/content/ImportContentFactory.java | 12 +- .../impl/content/RenameContentCommand.java | 36 -- .../impl/content/ReprocessContentCommand.java | 42 -- .../impl/content/UpdateContentCommand.java | 37 +- .../core/impl/content/UpdateMediaCommand.java | 37 -- .../impl/content/UpdateNodeParamsFactory.java | 13 +- .../page/region/GetComponentByKeyCommand.java | 12 - .../ComponentDataSerializerProvider.java | 16 +- .../serializer/ContentDataSerializer.java | 15 +- .../FullComponentDataSerializerProvider.java | 14 + .../serializer/FullContentDataSerializer.java | 66 ++++ .../FullLayoutComponentDataSerializer.java | 56 +++ .../serializer/FullPageDataSerializer.java | 269 +++++++++++++ .../LayoutComponentDataSerializer.java | 4 +- .../serializer/PageDataSerializer.java | 11 +- ...ntOutboundDependenciesIdsResolverTest.java | 3 +- .../content/ImportContentFactoryTest.java | 3 +- .../content/RenameContentCommandTest.java | 1 + .../content/AbstractContentServiceTest.java | 7 +- .../AbstractContentSynchronizerTest.java | 4 +- .../content/ContentServiceImplTest_media.java | 4 +- .../impl/handler/render/ComponentHandler.java | 15 +- .../handler/render/ContentConfigReader.java | 25 ++ .../impl/handler/render/FullPageResolver.java | 157 ++++++++ .../render/FullPageResolverResult.java | 27 ++ .../impl/handler/render/PageHandler.java | 17 +- .../handler/render/PageHandlerWorker.java | 7 +- .../impl/handler/render/PageResolver.java | 155 +------- .../handler/render/PageResolverResult.java | 23 +- .../instruction/ComponentInstruction.java | 373 ++++++++++++------ .../handler/render/ComponentHandlerTest.java | 5 +- .../impl/handler/render/PageHandlerTest.java | 3 + .../impl/handler/render/PageResolverTest.java | 2 +- .../instruction/ComponentInstructionTest.java | 6 +- 46 files changed, 1216 insertions(+), 603 deletions(-) delete mode 100644 modules/core/core-api/src/main/java/com/enonic/xp/region/LayoutDescriptorNotFoundException.java delete mode 100644 modules/core/core-api/src/main/java/com/enonic/xp/region/PartDescriptorNotFoundException.java create mode 100644 modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/FullContentNodeTranslator.java create mode 100644 modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullComponentDataSerializerProvider.java create mode 100644 modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullContentDataSerializer.java create mode 100644 modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullLayoutComponentDataSerializer.java create mode 100644 modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullPageDataSerializer.java create mode 100644 modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ContentConfigReader.java create mode 100644 modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolver.java create mode 100644 modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolverResult.java diff --git a/modules/core/core-api/src/main/java/com/enonic/xp/region/LayoutDescriptorNotFoundException.java b/modules/core/core-api/src/main/java/com/enonic/xp/region/LayoutDescriptorNotFoundException.java deleted file mode 100644 index 69cb92a8b14..00000000000 --- a/modules/core/core-api/src/main/java/com/enonic/xp/region/LayoutDescriptorNotFoundException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.enonic.xp.region; - -import com.enonic.xp.annotation.PublicApi; -import com.enonic.xp.exception.NotFoundException; -import com.enonic.xp.page.DescriptorKey; - -@PublicApi -@Deprecated -public class LayoutDescriptorNotFoundException - extends NotFoundException -{ - public LayoutDescriptorNotFoundException( final DescriptorKey key, final Throwable cause ) - { - super( cause, "LayoutDescriptor [" + key.toString() + "] not found" ); - } -} \ No newline at end of file diff --git a/modules/core/core-api/src/main/java/com/enonic/xp/region/PartDescriptorNotFoundException.java b/modules/core/core-api/src/main/java/com/enonic/xp/region/PartDescriptorNotFoundException.java deleted file mode 100644 index 89a6c3ea476..00000000000 --- a/modules/core/core-api/src/main/java/com/enonic/xp/region/PartDescriptorNotFoundException.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.enonic.xp.region; - -import com.enonic.xp.annotation.PublicApi; -import com.enonic.xp.exception.NotFoundException; -import com.enonic.xp.page.DescriptorKey; - - -@PublicApi -@Deprecated -public class PartDescriptorNotFoundException - extends NotFoundException -{ - public PartDescriptorNotFoundException( final DescriptorKey key, final Throwable cause ) - { - super( cause, "PartDescriptor [" + key.toString() + "] not found" ); - } -} \ No newline at end of file diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/AbstractCreatingOrUpdatingContentCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/AbstractCreatingOrUpdatingContentCommand.java index 4f74db24f6d..c8b34c105cf 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/AbstractCreatingOrUpdatingContentCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/AbstractCreatingOrUpdatingContentCommand.java @@ -13,6 +13,9 @@ import com.enonic.xp.context.Context; import com.enonic.xp.context.ContextAccessor; import com.enonic.xp.core.internal.FileNames; +import com.enonic.xp.page.PageDescriptorService; +import com.enonic.xp.region.LayoutDescriptorService; +import com.enonic.xp.region.PartDescriptorService; import com.enonic.xp.schema.xdata.XDataService; import com.enonic.xp.security.User; import com.enonic.xp.site.SiteService; @@ -35,6 +38,12 @@ class AbstractCreatingOrUpdatingContentCommand final List contentValidators; + protected final PageDescriptorService pageDescriptorService; + + protected final PartDescriptorService partDescriptorService; + + protected final LayoutDescriptorService layoutDescriptorService; + final boolean allowUnsafeAttachmentNames; AbstractCreatingOrUpdatingContentCommand( final Builder builder ) @@ -45,6 +54,9 @@ class AbstractCreatingOrUpdatingContentCommand this.contentProcessors = List.copyOf( builder.contentProcessors ); this.contentValidators = List.copyOf( builder.contentValidators ); this.allowUnsafeAttachmentNames = builder.allowUnsafeAttachmentNames; + this.pageDescriptorService = builder.pageDescriptorService; + this.partDescriptorService = builder.partDescriptorService; + this.layoutDescriptorService = builder.layoutDescriptorService; } public static class Builder> @@ -60,6 +72,12 @@ public static class Builder> private boolean allowUnsafeAttachmentNames; + private PageDescriptorService pageDescriptorService; + + private PartDescriptorService partDescriptorService; + + private LayoutDescriptorService layoutDescriptorService; + Builder() { } @@ -71,6 +89,9 @@ public static class Builder> this.siteService = source.siteService; this.contentProcessors = source.contentProcessors; this.contentValidators = source.contentValidators; + this.pageDescriptorService = source.pageDescriptorService; + this.partDescriptorService = source.partDescriptorService; + this.layoutDescriptorService = source.layoutDescriptorService; } @SuppressWarnings("unchecked") @@ -108,6 +129,24 @@ B allowUnsafeAttachmentNames( final boolean allowUnsafeAttachmentNames ) return (B) this; } + B pageDescriptorService( final PageDescriptorService pageDescriptorService ) + { + this.pageDescriptorService = pageDescriptorService; + return (B) this; + } + + B partDescriptorService( final PartDescriptorService partDescriptorService ) + { + this.partDescriptorService = partDescriptorService; + return (B) this; + } + + B layoutDescriptorService( final LayoutDescriptorService layoutDescriptorService ) + { + this.layoutDescriptorService = layoutDescriptorService; + return (B) this; + } + @Override void validate() { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentConfig.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentConfig.java index 31860b63d5e..d91b05c595c 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentConfig.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentConfig.java @@ -8,5 +8,7 @@ boolean attachments_allowUnsafeNames() default false; + boolean resolveEmptyRegions() default false; + String auditlog_filter() default "!system.content.update,*"; } diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentNodeTranslator.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentNodeTranslator.java index 00a50ab8283..db5c883d525 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentNodeTranslator.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentNodeTranslator.java @@ -21,9 +21,9 @@ public class ContentNodeTranslator { private static final Logger LOG = LoggerFactory.getLogger( ContentNodeTranslator.class ); - private final NodeService nodeService; + protected final NodeService nodeService; - private final ContentDataSerializer contentDataSerializer; + protected final ContentDataSerializer contentDataSerializer; public ContentNodeTranslator( final NodeService nodeService ) { @@ -31,6 +31,17 @@ public ContentNodeTranslator( final NodeService nodeService ) this.contentDataSerializer = new ContentDataSerializer(); } + protected ContentNodeTranslator( final NodeService nodeService, final ContentDataSerializer contentDataSerializer ) + { + this.nodeService = nodeService; + this.contentDataSerializer = contentDataSerializer; + } + + public ContentDataSerializer getContentDataSerializer() + { + return contentDataSerializer; + } + public Contents fromNodes( final Nodes nodes, final boolean resolveHasChildren ) { if ( resolveHasChildren ) diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolver.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolver.java index 94a8363e63f..55323ac4a1e 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolver.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolver.java @@ -20,10 +20,10 @@ class ContentOutboundDependenciesIdsResolver private final ContentDataSerializer contentDataSerializer; - ContentOutboundDependenciesIdsResolver( final ContentService contentService ) + ContentOutboundDependenciesIdsResolver( final ContentService contentService, final ContentDataSerializer contentDataSerializer ) { this.contentService = contentService; - this.contentDataSerializer = new ContentDataSerializer(); + this.contentDataSerializer = contentDataSerializer; } public ContentIds resolve( final ContentId contentId ) diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentServiceImpl.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentServiceImpl.java index b7303b7703a..4cdba7b457b 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentServiceImpl.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ContentServiceImpl.java @@ -10,7 +10,6 @@ import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; @@ -100,6 +99,7 @@ import com.enonic.xp.content.processor.ContentProcessor; import com.enonic.xp.context.ContextAccessor; import com.enonic.xp.context.ContextBuilder; +import com.enonic.xp.core.impl.content.serializer.FullContentDataSerializer; import com.enonic.xp.data.PropertyTree; import com.enonic.xp.event.EventPublisher; import com.enonic.xp.form.FormDefaultValuesProcessor; @@ -173,25 +173,19 @@ public class ContentServiceImpl private ContentAuditLogSupport contentAuditLogSupport; - private volatile ContentConfig config; + private final ContentConfig config; @Activate public ContentServiceImpl( @Reference final NodeService nodeService, @Reference final PageDescriptorService pageDescriptorService, @Reference final PartDescriptorService partDescriptorService, - @Reference final LayoutDescriptorService layoutDescriptorService ) + @Reference final LayoutDescriptorService layoutDescriptorService, ContentConfig config ) { + this.config = config; this.nodeService = nodeService; this.pageDescriptorService = pageDescriptorService; this.partDescriptorService = partDescriptorService; this.layoutDescriptorService = layoutDescriptorService; - this.translator = new ContentNodeTranslator( nodeService ); - } - - @Activate - @Modified - public void initialize( final ContentConfig config ) - { - this.config = config; + this.translator = this.getTranslator(); } @Override @@ -1069,7 +1063,7 @@ public ContentDependencies getDependencies( final ContentId id ) @Override public ContentIds getOutboundDependencies( final ContentId id ) { - return new ContentOutboundDependenciesIdsResolver( this ).resolve( id ); + return new ContentOutboundDependenciesIdsResolver( this, this.translator.getContentDataSerializer() ).resolve( id ); } @Override @@ -1247,6 +1241,22 @@ public InputStream getBinaryInputStream( final ContentId contentId, final Binary } } + private ContentNodeTranslator getTranslator() + { + if ( config.resolveEmptyRegions() ) + { + final FullContentDataSerializer fullContentDataSerializer = FullContentDataSerializer.create() + .layoutDescriptorService( layoutDescriptorService ) + .pageDescriptorService( pageDescriptorService ) + .partDescriptorService( partDescriptorService ) + .build(); + + return new FullContentNodeTranslator( nodeService, fullContentDataSerializer ); + } + + return new ContentNodeTranslator( nodeService ); + } + private static void verifyContextBranch( final Branch branch ) { final Branch contextBranch = ContextAccessor.current().getBranch(); diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateContentCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateContentCommand.java index 663a7872759..552e02b848e 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateContentCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateContentCommand.java @@ -35,9 +35,6 @@ import com.enonic.xp.node.NodeAccessException; import com.enonic.xp.node.NodeAlreadyExistAtPathException; import com.enonic.xp.node.RefreshMode; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.PartDescriptorService; import com.enonic.xp.schema.content.ContentType; import com.enonic.xp.schema.content.GetContentTypeParams; import com.enonic.xp.security.PrincipalKey; @@ -56,21 +53,12 @@ final class CreateContentCommand private final FormDefaultValuesProcessor formDefaultValuesProcessor; - private final PageDescriptorService pageDescriptorService; - - private final PartDescriptorService partDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; - private CreateContentCommand( final Builder builder ) { super( builder ); this.params = builder.params; this.mediaInfo = builder.mediaInfo; this.formDefaultValuesProcessor = builder.formDefaultValuesProcessor; - this.pageDescriptorService = builder.pageDescriptorService; - this.partDescriptorService = builder.partDescriptorService; - this.layoutDescriptorService = builder.layoutDescriptorService; } static Builder create() @@ -108,6 +96,7 @@ private Content doExecute() .xDataService( this.xDataService ) .partDescriptorService( this.partDescriptorService ) .layoutDescriptorService( this.layoutDescriptorService ) + .contentDataSerializer( this.translator.getContentDataSerializer() ) .siteService( this.siteService ) .build() .produce().refresh( params.isRefresh() ? RefreshMode.ALL : RefreshMode.STORAGE ).build(); @@ -322,12 +311,6 @@ static class Builder private FormDefaultValuesProcessor formDefaultValuesProcessor; - private PageDescriptorService pageDescriptorService; - - private PartDescriptorService partDescriptorService; - - private LayoutDescriptorService layoutDescriptorService; - private Builder() { } @@ -355,24 +338,6 @@ Builder formDefaultValuesProcessor( final FormDefaultValuesProcessor formDefault return this; } - Builder pageDescriptorService( final PageDescriptorService value ) - { - this.pageDescriptorService = value; - return this; - } - - Builder partDescriptorService( final PartDescriptorService value ) - { - this.partDescriptorService = value; - return this; - } - - Builder layoutDescriptorService( final LayoutDescriptorService value ) - { - this.layoutDescriptorService = value; - return this; - } - @Override void validate() { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateMediaCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateMediaCommand.java index e3a21bc021e..eabe83bba03 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateMediaCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateMediaCommand.java @@ -13,9 +13,6 @@ import com.enonic.xp.form.FormDefaultValuesProcessor; import com.enonic.xp.media.MediaInfo; import com.enonic.xp.media.MediaInfoService; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.PartDescriptorService; import com.enonic.xp.schema.content.ContentTypeFromMimeTypeResolver; import com.enonic.xp.schema.content.ContentTypeName; @@ -28,21 +25,12 @@ final class CreateMediaCommand private final FormDefaultValuesProcessor formDefaultValuesProcessor; - private final PageDescriptorService pageDescriptorService; - - private final PartDescriptorService partDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; - private CreateMediaCommand( final Builder builder ) { super( builder ); this.params = builder.params; this.mediaInfoService = builder.mediaInfoService; this.formDefaultValuesProcessor = builder.formDefaultValuesProcessor; - this.pageDescriptorService = builder.pageDescriptorService; - this.partDescriptorService = builder.partDescriptorService; - this.layoutDescriptorService = builder.layoutDescriptorService; } Content execute() @@ -103,6 +91,7 @@ private Content doExecute() final CreateContentCommand createCommand = CreateContentCommand.create( this ). mediaInfo( mediaInfo ). + translator( this.translator ). params( createContentParams ). siteService( this.siteService ). xDataService( this.xDataService ). @@ -140,12 +129,6 @@ public static class Builder private FormDefaultValuesProcessor formDefaultValuesProcessor; - private PageDescriptorService pageDescriptorService; - - private PartDescriptorService partDescriptorService; - - private LayoutDescriptorService layoutDescriptorService; - public Builder params( final CreateMediaParams params ) { this.params = params; @@ -164,24 +147,6 @@ public Builder formDefaultValuesProcessor( final FormDefaultValuesProcessor form return this; } - Builder pageDescriptorService( final PageDescriptorService value ) - { - this.pageDescriptorService = value; - return this; - } - - Builder partDescriptorService( final PartDescriptorService value ) - { - this.partDescriptorService = value; - return this; - } - - Builder layoutDescriptorService( final LayoutDescriptorService value ) - { - this.layoutDescriptorService = value; - return this; - } - @Override void validate() { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateNodeParamsFactory.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateNodeParamsFactory.java index 83ff3555919..9be7d16f35f 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateNodeParamsFactory.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/CreateNodeParamsFactory.java @@ -45,6 +45,8 @@ public class CreateNodeParamsFactory private final SiteService siteService; + private final ContentDataSerializer contentDataSerializer; + public CreateNodeParamsFactory( final Builder builder ) { this.params = builder.params; @@ -54,11 +56,11 @@ public CreateNodeParamsFactory( final Builder builder ) this.pageDescriptorService = builder.pageDescriptorService; this.partDescriptorService = builder.partDescriptorService; this.layoutDescriptorService = builder.layoutDescriptorService; + this.contentDataSerializer = builder.contentDataSerializer; } public CreateNodeParams.Builder produce() { - final ContentDataSerializer contentDataSerializer = new ContentDataSerializer(); final PropertyTree contentAsData = contentDataSerializer.toCreateNodeData( params ); final PropertySet extraDataSet = contentAsData.getPropertySet( PropertyPath.from( ContentPropertyNames.EXTRA_DATA ) ); @@ -147,6 +149,8 @@ public static class Builder private LayoutDescriptorService layoutDescriptorService; + private ContentDataSerializer contentDataSerializer; + private SiteService siteService; Builder( final CreateContentTranslatorParams params ) @@ -190,6 +194,12 @@ Builder layoutDescriptorService( final LayoutDescriptorService value ) return this; } + Builder contentDataSerializer( final ContentDataSerializer value ) + { + this.contentDataSerializer = value; + return this; + } + void validate() { Preconditions.checkNotNull( params ); @@ -197,6 +207,7 @@ void validate() Preconditions.checkNotNull( pageDescriptorService ); Preconditions.checkNotNull( siteService ); Preconditions.checkNotNull( xDataService ); + Preconditions.checkNotNull( contentDataSerializer ); } public CreateNodeParamsFactory build() diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/FullContentNodeTranslator.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/FullContentNodeTranslator.java new file mode 100644 index 00000000000..b2595ecd25d --- /dev/null +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/FullContentNodeTranslator.java @@ -0,0 +1,127 @@ +package com.enonic.xp.core.impl.content; + +import java.util.function.Function; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.enonic.xp.content.Content; +import com.enonic.xp.content.ContentId; +import com.enonic.xp.content.ContentNotFoundException; +import com.enonic.xp.content.ContentPath; +import com.enonic.xp.content.Contents; +import com.enonic.xp.context.ContextAccessor; +import com.enonic.xp.core.impl.content.serializer.ContentDataSerializer; +import com.enonic.xp.node.Node; +import com.enonic.xp.node.NodePath; +import com.enonic.xp.node.NodeService; +import com.enonic.xp.node.Nodes; + +public class FullContentNodeTranslator + extends ContentNodeTranslator +{ + private static final Logger LOG = LoggerFactory.getLogger( FullContentNodeTranslator.class ); + + public FullContentNodeTranslator( final NodeService nodeService, final ContentDataSerializer contentDataSerializer ) + { + super( nodeService, contentDataSerializer ); + } + + public Contents fromNodes( final Nodes nodes, final boolean resolveHasChildren ) + { + if ( resolveHasChildren ) + { + return doTranslate( nodes, nodeService::hasChildren ); + } + else + { + return doTranslate( nodes, n -> false ); + } + } + + public Content fromNode( final Node node, final boolean resolveHasChildren ) + { + return fromNode( node, resolveHasChildren, false ); + } + + public Content fromNode( final Node node, final boolean resolveHasChildren, final boolean allowAltRootPath ) + { + final boolean hasChildren = resolveHasChildren && this.nodeService.hasChildren( node ); + return doTranslate( node, hasChildren, allowAltRootPath ); + } + + private Contents doTranslate( final Nodes nodes, final Function hasChildrenFn ) + { + final Contents.Builder contents = Contents.create(); + + for ( final Node node : nodes ) + { + try + { + contents.add( doTranslate( node, hasChildrenFn.apply( node ) ) ); + } + catch ( final ContentNotFoundException e ) + { + LOG.debug( "Failed to translate node '{}' [{}] to content", node.path(), node.id(), e ); + } + catch ( final Exception e ) + { + LOG.error( "Failed to translate node '{}' [{}] to content", node.path(), node.id(), e ); + } + } + + return contents.build(); + } + + private ContentPath getParent( final NodePath nodePath ) + { + final NodePath parentPath = nodePath.getParentPath(); + if ( parentPath.isRoot() ) + { + return ContentPath.ROOT; + } + + return ContentNodeHelper.translateNodePathToContentPath( parentPath ); + } + + private Content doTranslate( final Node node, final boolean hasChildren ) + { + return doTranslate( node, hasChildren, false ); + } + + private Content doTranslate( final Node node, final boolean hasChildren, final boolean allowAltRootPath ) + { + final ContentId contentId = ContentId.from( node.id() ); + + if ( !allowAltRootPath && !( node.path().toString().startsWith( ContentNodeHelper.getContentRoot().toString() + "/" ) || + node.path().equals( ContentNodeHelper.getContentRoot() ) ) ) + { + throw ContentNotFoundException.create() + .contentId( contentId ) + .repositoryId( ContextAccessor.current().getRepositoryId() ) + .branch( ContextAccessor.current().getBranch() ) + .contentRoot( ContentNodeHelper.getContentRoot() ) + .build(); + } + + final ContentPath parentContentPath = getParent( node.path() ); + + final Content.Builder builder = contentDataSerializer.fromData( node.data().getRoot() ); + + builder.id( contentId ) + .parentPath( parentContentPath ) + .name( node.name().toString() ) + .childOrder( node.getChildOrder() ) + .permissions( node.getPermissions() ) + .inheritPermissions( node.inheritsPermissions() ) + .hasChildren( hasChildren ) + .manualOrderValue( node.getManualOrderValue() ); + + if ( node.parentPath().isRoot() ) + { + builder.root(); + } + + return builder.build(); + } +} diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentCommand.java index 193ba58e536..f7e02a925e1 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentCommand.java @@ -34,6 +34,7 @@ private ImportContentResult doExecute() { final Node importNode = ImportContentFactory.create(). params( params ). + contentDataSerializer( this.translator.getContentDataSerializer() ). build().execute(); final ImportNodeParams importNodeParams = ImportNodeParams.create().importNode( importNode ) diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentFactory.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentFactory.java index 9fe4c6395d2..ec8bcc97e63 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentFactory.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ImportContentFactory.java @@ -20,9 +20,12 @@ public class ImportContentFactory { private final ImportContentParams params; + private final ContentDataSerializer contentDataSerializer; + private ImportContentFactory( Builder builder ) { this.params = builder.params; + this.contentDataSerializer = builder.contentDataSerializer; } public static Builder create() @@ -32,7 +35,6 @@ public static Builder create() public Node execute() { - final ContentDataSerializer contentDataSerializer = new ContentDataSerializer(); final PropertyTree nodeData = contentDataSerializer.toNodeData( params.getContent() ); if ( params.getInherit() != null ) @@ -72,6 +74,8 @@ public static final class Builder { private ImportContentParams params; + private ContentDataSerializer contentDataSerializer; + private Builder() { } @@ -82,6 +86,12 @@ public Builder params( final ImportContentParams params ) return this; } + public Builder contentDataSerializer( final ContentDataSerializer contentDataSerializer ) + { + this.contentDataSerializer = contentDataSerializer; + return this; + } + private void validate() { Preconditions.checkNotNull( this.params, "params cannot be null" ); diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/RenameContentCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/RenameContentCommand.java index c7aacbf4db6..03120ab3fa1 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/RenameContentCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/RenameContentCommand.java @@ -13,9 +13,6 @@ import com.enonic.xp.node.NodeName; import com.enonic.xp.node.RefreshMode; import com.enonic.xp.node.RenameNodeParams; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.PartDescriptorService; import static com.enonic.xp.core.impl.content.ContentNodeHelper.translateNodePathToContentPath; @@ -25,19 +22,10 @@ final class RenameContentCommand { private final RenameContentParams params; - private final PageDescriptorService pageDescriptorService; - - private final PartDescriptorService partDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; - private RenameContentCommand( final Builder builder ) { super( builder ); this.params = builder.params; - this.pageDescriptorService = builder.pageDescriptorService; - this.partDescriptorService = builder.partDescriptorService; - this.layoutDescriptorService = builder.layoutDescriptorService; } public static Builder create( final RenameContentParams params ) @@ -126,35 +114,11 @@ public static class Builder { private final RenameContentParams params; - private PageDescriptorService pageDescriptorService; - - private PartDescriptorService partDescriptorService; - - private LayoutDescriptorService layoutDescriptorService; - Builder( final RenameContentParams params ) { this.params = params; } - Builder pageDescriptorService( final PageDescriptorService value ) - { - this.pageDescriptorService = value; - return this; - } - - Builder partDescriptorService( final PartDescriptorService value ) - { - this.partDescriptorService = value; - return this; - } - - Builder layoutDescriptorService( final LayoutDescriptorService value ) - { - this.layoutDescriptorService = value; - return this; - } - @Override void validate() { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ReprocessContentCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ReprocessContentCommand.java index 2e34d96c2c8..d89e10edddd 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ReprocessContentCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/ReprocessContentCommand.java @@ -15,9 +15,6 @@ import com.enonic.xp.node.NodeId; import com.enonic.xp.node.RefreshMode; import com.enonic.xp.node.UpdateNodeParams; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.PartDescriptorService; import static com.enonic.xp.content.ContentPropertyNames.MODIFIED_TIME; @@ -29,20 +26,11 @@ final class ReprocessContentCommand private final MediaInfoService mediaInfoService; - private final PageDescriptorService pageDescriptorService; - - private final PartDescriptorService partDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; - private ReprocessContentCommand( final Builder builder ) { super( builder ); this.params = builder.params; this.mediaInfoService = builder.mediaInfoService; - this.pageDescriptorService = builder.pageDescriptorService; - this.partDescriptorService = builder.partDescriptorService; - this.layoutDescriptorService = builder.layoutDescriptorService; } Content execute() @@ -107,12 +95,6 @@ public static class Builder private MediaInfoService mediaInfoService; - private PageDescriptorService pageDescriptorService; - - private PartDescriptorService partDescriptorService; - - private LayoutDescriptorService layoutDescriptorService; - private Builder( final ReprocessContentParams params ) { this.params = params; @@ -124,30 +106,6 @@ public Builder mediaInfoService( final MediaInfoService value ) return this; } - public Builder pageDescriptorService( final PageDescriptorService value ) - { - this.pageDescriptorService = value; - return this; - } - - public Builder partDescriptorService( final PartDescriptorService value ) - { - this.partDescriptorService = value; - return this; - } - - public Builder layoutDescriptorService( final LayoutDescriptorService value ) - { - this.layoutDescriptorService = value; - return this; - } - - @Override - void validate() - { - super.validate(); - } - public ReprocessContentCommand build() { validate(); diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateContentCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateContentCommand.java index e24f6134eca..ed652064669 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateContentCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateContentCommand.java @@ -45,9 +45,6 @@ import com.enonic.xp.node.NodeId; import com.enonic.xp.node.NodeIds; import com.enonic.xp.node.UpdateNodeParams; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.PartDescriptorService; import com.enonic.xp.schema.content.ContentType; import com.enonic.xp.schema.content.ContentTypeName; import com.enonic.xp.schema.content.GetContentTypeParams; @@ -63,20 +60,11 @@ final class UpdateContentCommand private final MediaInfo mediaInfo; - private final PageDescriptorService pageDescriptorService; - - private final PartDescriptorService partDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; - private UpdateContentCommand( final Builder builder ) { super( builder ); this.params = builder.params; this.mediaInfo = builder.mediaInfo; - this.pageDescriptorService = builder.pageDescriptorService; - this.partDescriptorService = builder.partDescriptorService; - this.layoutDescriptorService = builder.layoutDescriptorService; } public static Builder create( final UpdateContentParams params ) @@ -197,6 +185,7 @@ private Content doExecute() .pageDescriptorService( this.pageDescriptorService ) .partDescriptorService( this.partDescriptorService ) .layoutDescriptorService( this.layoutDescriptorService ) + .contentDataSerializer( this.translator.getContentDataSerializer() ) .siteService( this.siteService ) .build() .produce(); @@ -355,12 +344,6 @@ public static class Builder private MediaInfo mediaInfo; - private PageDescriptorService pageDescriptorService; - - private PartDescriptorService partDescriptorService; - - private LayoutDescriptorService layoutDescriptorService; - Builder( final UpdateContentParams params ) { this.params = params; @@ -383,24 +366,6 @@ Builder mediaInfo( final MediaInfo value ) return this; } - Builder pageDescriptorService( final PageDescriptorService value ) - { - this.pageDescriptorService = value; - return this; - } - - Builder partDescriptorService( final PartDescriptorService value ) - { - this.partDescriptorService = value; - return this; - } - - Builder layoutDescriptorService( final LayoutDescriptorService value ) - { - this.layoutDescriptorService = value; - return this; - } - @Override void validate() { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateMediaCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateMediaCommand.java index f521e19b050..fb6ff459e45 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateMediaCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateMediaCommand.java @@ -11,9 +11,6 @@ import com.enonic.xp.content.UpdateMediaParams; import com.enonic.xp.media.MediaInfo; import com.enonic.xp.media.MediaInfoService; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.PartDescriptorService; import com.enonic.xp.schema.content.ContentTypeFromMimeTypeResolver; import com.enonic.xp.schema.content.ContentTypeName; @@ -24,20 +21,11 @@ final class UpdateMediaCommand private final MediaInfoService mediaInfoService; - private final PageDescriptorService pageDescriptorService; - - private final PartDescriptorService partDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; - private UpdateMediaCommand( final Builder builder ) { super( builder ); this.params = builder.params; this.mediaInfoService = builder.mediaInfoService; - this.pageDescriptorService = builder.pageDescriptorService; - this.partDescriptorService = builder.partDescriptorService; - this.layoutDescriptorService = builder.layoutDescriptorService; } public static Builder create( final UpdateMediaParams params ) @@ -123,13 +111,6 @@ public static class Builder private MediaInfoService mediaInfoService; - private PageDescriptorService pageDescriptorService; - - private PartDescriptorService partDescriptorService; - - private LayoutDescriptorService layoutDescriptorService; - - Builder( final UpdateMediaParams params ) { this.params = params; @@ -147,24 +128,6 @@ public Builder mediaInfoService( final MediaInfoService value ) return this; } - public Builder pageDescriptorService( final PageDescriptorService value ) - { - this.pageDescriptorService = value; - return this; - } - - public Builder partDescriptorService( final PartDescriptorService value ) - { - this.partDescriptorService = value; - return this; - } - - public Builder layoutDescriptorService( final LayoutDescriptorService value ) - { - this.layoutDescriptorService = value; - return this; - } - @Override void validate() { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateNodeParamsFactory.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateNodeParamsFactory.java index 373ba3bf726..7a4e2f75048 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateNodeParamsFactory.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/UpdateNodeParamsFactory.java @@ -44,6 +44,8 @@ public class UpdateNodeParamsFactory private final SiteService siteService; + private final ContentDataSerializer contentDataSerializer; + public UpdateNodeParamsFactory( final Builder builder ) { this.editedContent = builder.editedContent; @@ -55,6 +57,7 @@ public UpdateNodeParamsFactory( final Builder builder ) this.pageDescriptorService = builder.pageDescriptorService; this.partDescriptorService = builder.partDescriptorService; this.layoutDescriptorService = builder.layoutDescriptorService; + this.contentDataSerializer = builder.contentDataSerializer; this.siteService = builder.siteService; } @@ -81,7 +84,6 @@ public static Builder create() private NodeEditor toNodeEditor() { - final ContentDataSerializer contentDataSerializer = new ContentDataSerializer(); final PropertyTree nodeData = contentDataSerializer.toUpdateNodeData( editedContent, modifier, attachments ); final ContentIndexConfigFactory indexConfigFactory = ContentIndexConfigFactory.create(). @@ -127,6 +129,8 @@ public static class Builder private LayoutDescriptorService layoutDescriptorService; + private ContentDataSerializer contentDataSerializer; + private SiteService siteService; Builder editedContent( final Content editedContent ) @@ -189,6 +193,12 @@ Builder siteService( final SiteService value ) return this; } + Builder contentDataSerializer( final ContentDataSerializer contentDataSerializer ) + { + this.contentDataSerializer = contentDataSerializer; + return this; + } + void validate() { Preconditions.checkNotNull( modifier, "modifier cannot be null" ); @@ -201,6 +211,7 @@ void validate() Preconditions.checkNotNull( pageDescriptorService ); Preconditions.checkNotNull( partDescriptorService ); Preconditions.checkNotNull( layoutDescriptorService ); + Preconditions.checkNotNull( contentDataSerializer ); } public UpdateNodeParamsFactory build() diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/page/region/GetComponentByKeyCommand.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/page/region/GetComponentByKeyCommand.java index 859a64b884c..c111512fd57 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/page/region/GetComponentByKeyCommand.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/page/region/GetComponentByKeyCommand.java @@ -6,11 +6,9 @@ import com.enonic.xp.region.LayoutComponent; import com.enonic.xp.region.LayoutDescriptor; import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.LayoutRegions; import com.enonic.xp.region.PartComponent; import com.enonic.xp.region.PartDescriptor; import com.enonic.xp.region.PartDescriptorService; -import com.enonic.xp.region.Region; import com.enonic.xp.resource.ResourceKey; import com.enonic.xp.resource.ResourceService; @@ -38,21 +36,11 @@ public Component execute() { return LayoutComponent.create(). descriptor( layoutDescriptor.getKey() ). - regions( buildLayoutRegions( layoutDescriptor ) ). build(); } return null; } - private LayoutRegions buildLayoutRegions( final LayoutDescriptor layoutDescriptor ) - { - final LayoutRegions.Builder regionsBuilder = LayoutRegions.create(); - layoutDescriptor.getRegions() - .forEach( regionDescriptor -> regionsBuilder.add( Region.create().name( regionDescriptor.getName() ).build() ) ); - - return regionsBuilder.build(); - } - private boolean componentExists( final ResourceKey componentPath ) { return resourceService.getResource( componentPath.resolve( componentPath.getName() + ".xml" ) ).exists(); diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ComponentDataSerializerProvider.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ComponentDataSerializerProvider.java index 00b391c8227..cbcb6a59f8b 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ComponentDataSerializerProvider.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ComponentDataSerializerProvider.java @@ -7,28 +7,28 @@ import com.enonic.xp.region.PartComponentType; import com.enonic.xp.region.TextComponentType; -public final class ComponentDataSerializerProvider +public class ComponentDataSerializerProvider { - private final PartComponentDataSerializer partDataSerializer; + protected final PartComponentDataSerializer partDataSerializer; - private final TextComponentDataSerializer textDataSerializer; + protected final TextComponentDataSerializer textDataSerializer; - private final LayoutComponentDataSerializer layoutDataSerializer; + protected LayoutComponentDataSerializer layoutDataSerializer; - private final ImageComponentDataSerializer imageDataSerializer; + protected final ImageComponentDataSerializer imageDataSerializer; - private final FragmentComponentDataSerializer fragmentDataSerializer; + protected final FragmentComponentDataSerializer fragmentDataSerializer; - private final RegionDataSerializer regionDataSerializer; + protected final RegionDataSerializer regionDataSerializer; public ComponentDataSerializerProvider( ) { this.regionDataSerializer = new RegionDataSerializer( this ); this.partDataSerializer = new PartComponentDataSerializer(); this.textDataSerializer = new TextComponentDataSerializer(); - this.layoutDataSerializer = new LayoutComponentDataSerializer( this.regionDataSerializer ); this.imageDataSerializer = new ImageComponentDataSerializer(); this.fragmentDataSerializer = new FragmentComponentDataSerializer(); + this.layoutDataSerializer = new LayoutComponentDataSerializer( this.regionDataSerializer ); } public ComponentDataSerializer getDataSerializer( final ComponentType componentType ) diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ContentDataSerializer.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ContentDataSerializer.java index 500552cd9b2..4346df685b2 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ContentDataSerializer.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/ContentDataSerializer.java @@ -79,17 +79,22 @@ public class ContentDataSerializer { private static final ObjectMapper OBJECT_MAPPER = ObjectMapperHelper.create(); - private final PageDataSerializer pageDataSerializer; + protected final PageDataSerializer pageDataSerializer; - private final ExtraDataSerializer extraDataSerializer; + protected final ExtraDataSerializer extraDataSerializer; - private final WorkflowInfoSerializer workflowInfoSerializer; + protected final WorkflowInfoSerializer workflowInfoSerializer; - private final PublishInfoSerializer publishInfoSerializer; + protected final PublishInfoSerializer publishInfoSerializer; public ContentDataSerializer( ) { - this.pageDataSerializer = new PageDataSerializer(); + this( new PageDataSerializer() ); + } + + protected ContentDataSerializer( final PageDataSerializer pageDataSerializer ) + { + this.pageDataSerializer = pageDataSerializer; this.extraDataSerializer = new ExtraDataSerializer(); this.workflowInfoSerializer = new WorkflowInfoSerializer(); this.publishInfoSerializer = new PublishInfoSerializer(); diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullComponentDataSerializerProvider.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullComponentDataSerializerProvider.java new file mode 100644 index 00000000000..89703572e92 --- /dev/null +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullComponentDataSerializerProvider.java @@ -0,0 +1,14 @@ +package com.enonic.xp.core.impl.content.serializer; + +import com.enonic.xp.region.LayoutDescriptorService; + +public class FullComponentDataSerializerProvider extends ComponentDataSerializerProvider +{ + + public FullComponentDataSerializerProvider( final LayoutDescriptorService layoutDescriptorService ) + { + super(); + this.layoutDataSerializer = new FullLayoutComponentDataSerializer( layoutDescriptorService, regionDataSerializer ); + } + +} diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullContentDataSerializer.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullContentDataSerializer.java new file mode 100644 index 00000000000..2988275a47d --- /dev/null +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullContentDataSerializer.java @@ -0,0 +1,66 @@ +package com.enonic.xp.core.impl.content.serializer; + +import com.google.common.base.Preconditions; + +import com.enonic.xp.page.PageDescriptorService; +import com.enonic.xp.region.LayoutDescriptorService; +import com.enonic.xp.region.PartDescriptorService; + +public class FullContentDataSerializer extends ContentDataSerializer +{ + private FullContentDataSerializer( final Builder builder ) + { + super( FullPageDataSerializer.create() + .pageDescriptorService( builder.pageDescriptorService ) + .partDescriptorService( builder.partDescriptorService ) + .layoutDescriptorService( builder.layoutDescriptorService ) + .build() ); + + } + + public static Builder create() + { + return new Builder(); + } + + public static class Builder + { + private PageDescriptorService pageDescriptorService; + + private PartDescriptorService partDescriptorService; + + private LayoutDescriptorService layoutDescriptorService; + + public Builder pageDescriptorService( final PageDescriptorService value ) + { + this.pageDescriptorService = value; + return this; + } + + public Builder partDescriptorService( final PartDescriptorService value ) + { + this.partDescriptorService = value; + return this; + } + + public Builder layoutDescriptorService( final LayoutDescriptorService value ) + { + this.layoutDescriptorService = value; + return this; + } + + void validate() + { + Preconditions.checkNotNull( pageDescriptorService ); + Preconditions.checkNotNull( partDescriptorService ); + Preconditions.checkNotNull( layoutDescriptorService ); + } + + public FullContentDataSerializer build() + { + validate(); + return new FullContentDataSerializer( this ); + } + } + +} diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullLayoutComponentDataSerializer.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullLayoutComponentDataSerializer.java new file mode 100644 index 00000000000..a38f64970ea --- /dev/null +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullLayoutComponentDataSerializer.java @@ -0,0 +1,56 @@ +package com.enonic.xp.core.impl.content.serializer; + + +import java.util.List; + +import com.enonic.xp.data.PropertySet; +import com.enonic.xp.page.DescriptorKey; +import com.enonic.xp.region.LayoutComponent; +import com.enonic.xp.region.LayoutComponentType; +import com.enonic.xp.region.LayoutDescriptor; +import com.enonic.xp.region.LayoutDescriptorService; +import com.enonic.xp.region.LayoutRegions; + +class FullLayoutComponentDataSerializer + extends LayoutComponentDataSerializer +{ + private final LayoutDescriptorService layoutDescriptorService; + + FullLayoutComponentDataSerializer( final LayoutDescriptorService layoutDescriptorService, final RegionDataSerializer regionDataSerializer ) + { + super( regionDataSerializer ); + this.layoutDescriptorService = layoutDescriptorService; + } + + public LayoutComponent fromData( final PropertySet layoutData, final List componentsAsData ) + { + final LayoutComponent.Builder layoutComponent = LayoutComponent.create(); + + final LayoutRegions.Builder layoutRegionsBuilder = LayoutRegions.create(); + + final PropertySet specialBlockSet = layoutData.getSet( LayoutComponentType.INSTANCE.toString() ); + + if ( specialBlockSet != null && specialBlockSet.isNotNull( DESCRIPTOR ) ) + { + final DescriptorKey descriptorKey = DescriptorKey.from( specialBlockSet.getString( DESCRIPTOR ) ); + + layoutComponent.descriptor( descriptorKey ); + layoutComponent.config( getConfigFromData( specialBlockSet, descriptorKey ) ); + + final LayoutDescriptor layoutDescriptor = layoutDescriptorService.getByKey( descriptorKey ); + + final String layoutPath = layoutData.getString( PATH ); + + if ( layoutDescriptor.getRegions() != null && layoutDescriptor.getRegions().numberOfRegions() > 0 ) + { + layoutDescriptor.getRegions().forEach( regionDescriptor -> { + layoutRegionsBuilder.add( regionDataSerializer.fromData( regionDescriptor, layoutPath, componentsAsData ) ); + } ); + } + } + + layoutComponent.regions( layoutRegionsBuilder.build() ); + + return layoutComponent.build(); + } +} diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullPageDataSerializer.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullPageDataSerializer.java new file mode 100644 index 00000000000..38d956ea9e7 --- /dev/null +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/FullPageDataSerializer.java @@ -0,0 +1,269 @@ +package com.enonic.xp.core.impl.content.serializer; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import com.google.common.base.Preconditions; + +import com.enonic.xp.data.Property; +import com.enonic.xp.data.PropertySet; +import com.enonic.xp.node.NodeId; +import com.enonic.xp.page.DescriptorKey; +import com.enonic.xp.page.Page; +import com.enonic.xp.page.PageDescriptor; +import com.enonic.xp.page.PageDescriptorService; +import com.enonic.xp.page.PageRegions; +import com.enonic.xp.page.PageTemplateKey; +import com.enonic.xp.region.Component; +import com.enonic.xp.region.ComponentPath; +import com.enonic.xp.region.LayoutDescriptorService; +import com.enonic.xp.region.PartDescriptorService; +import com.enonic.xp.region.Region; +import com.enonic.xp.region.RegionDescriptors; +import com.enonic.xp.util.Reference; + +import static com.enonic.xp.content.ContentPropertyNames.PAGE; +import static com.enonic.xp.core.impl.content.serializer.ComponentDataSerializer.COMPONENTS; +import static com.enonic.xp.core.impl.content.serializer.ComponentDataSerializer.PATH; +import static com.enonic.xp.core.impl.content.serializer.ComponentDataSerializer.TYPE; +import static com.enonic.xp.core.impl.content.serializer.DescriptorBasedComponentDataSerializer.CONFIG; +import static com.enonic.xp.core.impl.content.serializer.DescriptorBasedComponentDataSerializer.DESCRIPTOR; +import static com.enonic.xp.core.impl.content.serializer.DescriptorBasedComponentDataSerializer.appNameToConfigPropertyName; +import static com.enonic.xp.core.impl.content.serializer.DescriptorBasedComponentDataSerializer.getConfigFromData; + +final class FullPageDataSerializer + extends PageDataSerializer +{ + private static final String TEMPLATE = "template"; + + private static final String CUSTOMIZED = "customized"; + + private final PageDescriptorService pageDescriptorService; + + private FullPageDataSerializer( final Builder builder ) + { + this.pageDescriptorService = builder.pageDescriptorService; + this.componentDataSerializerProvider = new FullComponentDataSerializerProvider(builder.layoutDescriptorService); + } + + @Override + public void toData( final Page page, final PropertySet parent ) + { + if ( page.isFragment() ) + { + serializeFragment( page, parent ); + } + else + { + serializePage( page, parent ); + } + } + + private void serializeFragment( final Page page, final PropertySet parent ) + { + final Component fragment = page.getFragment(); + componentDataSerializerProvider.getDataSerializer( fragment.getType() ).toData( fragment, parent ); + } + + private void serializePage( final Page page, final PropertySet parent ) + { + final PropertySet asSet = parent.addSet( COMPONENTS ); + + asSet.setString( TYPE, PAGE ); + asSet.setString( PATH, ComponentPath.DIVIDER ); + + final PropertySet specialBlockSet = asSet.addSet( PAGE ); + + if ( page.hasDescriptor() ) + { + specialBlockSet.addString( DESCRIPTOR, page.getDescriptor().toString() ); + } + + if ( page.hasTemplate() ) + { + specialBlockSet.addReference( TEMPLATE, new Reference( NodeId.from( page.getTemplate().getContentId() ) ) ); + } + + if ( page.hasRegions() ) + { + addRegions( page, parent ); + } + + specialBlockSet.addBoolean( CUSTOMIZED, page.isCustomized() ); + + if ( page.hasConfig() ) + { + final String pageName = appNameToConfigPropertyName( page.getDescriptor().getName() ); + final String appKeyAsString = appNameToConfigPropertyName( page.getDescriptor().getApplicationKey().toString() ); + final PropertySet configSet = specialBlockSet.addSet( CONFIG ).addSet( appKeyAsString ); + configSet.addSet( pageName, page.getConfig().getRoot().copy( asSet.getTree() ) ); + } + } + + private void addRegions( final Page page, final PropertySet asSet ) + { + if ( !page.getRegions().isEmpty() ) + { + for ( Region region : page.getRegions() ) + { + componentDataSerializerProvider.getRegionDataSerializer().toData( region, asSet ); + } + } + } + + @Override + public Page fromData( final PropertySet asSet ) + { + final List componentsAsData = asSet.getProperties( COMPONENTS ).stream().filter( Property::hasNotNullValue ). + map( Property::getSet ).collect( Collectors.toList() ); + + if ( componentsAsData.isEmpty() ) + { + return null; + } + + if ( !isRootComponent( componentsAsData.get( 0 ) ) ) + { + componentsAsData.sort( Comparator.comparing( this::getComponentPath ) ); + } + + return fromData( componentsAsData ); + } + + private boolean isRootComponent( final PropertySet componentData ) + { + return getComponentPath( componentData ).equals( ComponentPath.DIVIDER ); + } + + private String getComponentPath( final PropertySet componentData ) + { + return componentData.getString( PATH ); + } + + private Page fromData( final List componentsAsData ) + { + final PropertySet pageData = componentsAsData.get( 0 ); + componentsAsData.remove( 0 ); + + return fromData( pageData, componentsAsData ); + } + + private Page fromData( final PropertySet pageData, final List componentsAsData ) + { + final boolean isFragment = !pageData.getString( TYPE ).equals( PAGE ); + + if ( isFragment ) + { + return fromFragmentData( pageData, componentsAsData ); + } + + return fromPageData( pageData, componentsAsData ); + } + + private Page fromFragmentData( final PropertySet fragmentData, final List componentsAsData ) + { + final Page.Builder page = Page.create(); + + page.fragment( componentDataSerializerProvider.getRegionDataSerializer().getComponent( fragmentData, componentsAsData ) ); + + return page.build(); + } + + private Page fromPageData( final PropertySet pageData, final List componentsAsData ) + { + final Page.Builder page = Page.create(); + + final PropertySet specialBlockSet = pageData.getSet( PAGE ); + + if ( specialBlockSet != null ) + { + if ( specialBlockSet.isNotNull( DESCRIPTOR ) ) + { + final DescriptorKey descriptorKey = DescriptorKey.from( specialBlockSet.getString( DESCRIPTOR ) ); + page.descriptor( descriptorKey ); + page.config( getConfigFromData( specialBlockSet, descriptorKey ) ); + page.regions( getPageRegions( descriptorKey, componentsAsData ) ); + } + + if ( specialBlockSet.isNotNull( TEMPLATE ) ) + { + page.template( PageTemplateKey.from( specialBlockSet.getReference( TEMPLATE ).toString() ) ); + } + + if ( specialBlockSet.isNotNull( CUSTOMIZED ) ) + { + page.customized( specialBlockSet.getBoolean( CUSTOMIZED ) ); + } + } + + return page.build(); + } + + private PageRegions getPageRegions( final DescriptorKey descriptorKey, final List componentsAsData ) + { + final PageDescriptor pageDescriptor = pageDescriptorService.getByKey( descriptorKey ); + + final RegionDescriptors regionDescriptors = pageDescriptor.getRegions(); + + if ( regionDescriptors.numberOfRegions() == 0 ) + { + return null; + } + + final PageRegions.Builder pageRegionsBuilder = PageRegions.create(); + + regionDescriptors.forEach( regionDescriptor -> { + pageRegionsBuilder.add( + componentDataSerializerProvider.getRegionDataSerializer().fromData( regionDescriptor, ComponentPath.DIVIDER, + componentsAsData ) ); + } ); + + return pageRegionsBuilder.build(); + } + + public static Builder create() + { + return new Builder(); + } + + public static class Builder + { + private PageDescriptorService pageDescriptorService; + + private PartDescriptorService partDescriptorService; + + private LayoutDescriptorService layoutDescriptorService; + + public Builder pageDescriptorService( final PageDescriptorService value ) + { + this.pageDescriptorService = value; + return this; + } + + public Builder partDescriptorService( final PartDescriptorService value ) + { + this.partDescriptorService = value; + return this; + } + + public Builder layoutDescriptorService( final LayoutDescriptorService value ) + { + this.layoutDescriptorService = value; + return this; + } + + void validate() + { + Preconditions.checkNotNull( pageDescriptorService ); + Preconditions.checkNotNull( partDescriptorService ); + Preconditions.checkNotNull( layoutDescriptorService ); + } + + public FullPageDataSerializer build() + { + validate(); + return new FullPageDataSerializer( this ); + } + } +} diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/LayoutComponentDataSerializer.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/LayoutComponentDataSerializer.java index c6787af16b0..6c73a1fe45f 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/LayoutComponentDataSerializer.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/LayoutComponentDataSerializer.java @@ -15,10 +15,10 @@ import com.enonic.xp.region.Region; import com.enonic.xp.region.RegionDescriptors; -final class LayoutComponentDataSerializer +class LayoutComponentDataSerializer extends DescriptorBasedComponentDataSerializer { - private final RegionDataSerializer regionDataSerializer; + protected final RegionDataSerializer regionDataSerializer; LayoutComponentDataSerializer( final RegionDataSerializer regionDataSerializer ) { diff --git a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/PageDataSerializer.java b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/PageDataSerializer.java index d7a079d4df7..c2588d38a36 100644 --- a/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/PageDataSerializer.java +++ b/modules/core/core-content/src/main/java/com/enonic/xp/core/impl/content/serializer/PageDataSerializer.java @@ -25,18 +25,23 @@ import static com.enonic.xp.core.impl.content.serializer.DescriptorBasedComponentDataSerializer.appNameToConfigPropertyName; import static com.enonic.xp.core.impl.content.serializer.DescriptorBasedComponentDataSerializer.getConfigFromData; -final class PageDataSerializer +class PageDataSerializer extends AbstractDataSetSerializer { private static final String TEMPLATE = "template"; private static final String CUSTOMIZED = "customized"; - private final ComponentDataSerializerProvider componentDataSerializerProvider; + protected ComponentDataSerializerProvider componentDataSerializerProvider; PageDataSerializer( ) { - this.componentDataSerializerProvider = new ComponentDataSerializerProvider(); + this(new ComponentDataSerializerProvider()); + } + + protected PageDataSerializer( final ComponentDataSerializerProvider componentDataSerializerProvider ) + { + this.componentDataSerializerProvider = componentDataSerializerProvider; } @Override diff --git a/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolverTest.java b/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolverTest.java index 90326088348..7d5467222b8 100644 --- a/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolverTest.java +++ b/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ContentOutboundDependenciesIdsResolverTest.java @@ -14,6 +14,7 @@ import com.enonic.xp.content.Contents; import com.enonic.xp.content.ExtraData; import com.enonic.xp.content.ExtraDatas; +import com.enonic.xp.core.impl.content.serializer.ContentDataSerializer; import com.enonic.xp.data.PropertyTree; import com.enonic.xp.schema.content.ContentTypeName; import com.enonic.xp.schema.xdata.XDataName; @@ -35,7 +36,7 @@ public void setUp() throws Exception { this.contentService = Mockito.mock( ContentService.class ); - this.resolver = new ContentOutboundDependenciesIdsResolver( contentService ); + this.resolver = new ContentOutboundDependenciesIdsResolver( contentService, new ContentDataSerializer() ); } private Content createContent( final String id, final PropertyTree data, final ContentTypeName contentTypeName ) diff --git a/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ImportContentFactoryTest.java b/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ImportContentFactoryTest.java index 7a88e8009ca..a1de4a8e787 100644 --- a/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ImportContentFactoryTest.java +++ b/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/ImportContentFactoryTest.java @@ -17,6 +17,7 @@ import com.enonic.xp.content.ContentPath; import com.enonic.xp.content.ContentPublishInfo; import com.enonic.xp.content.ImportContentParams; +import com.enonic.xp.core.impl.content.serializer.ContentDataSerializer; import com.enonic.xp.data.PropertyTree; import com.enonic.xp.node.Node; import com.enonic.xp.project.ProjectName; @@ -107,6 +108,6 @@ public void removePublishInfo() private ImportContentFactory createFactory() { - return ImportContentFactory.create().params( this.params ).build(); + return ImportContentFactory.create().params( this.params ).contentDataSerializer( new ContentDataSerializer() ).build(); } } diff --git a/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/RenameContentCommandTest.java b/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/RenameContentCommandTest.java index a9760ecb84f..e40cedece26 100644 --- a/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/RenameContentCommandTest.java +++ b/modules/core/core-content/src/test/java/com/enonic/xp/core/impl/content/RenameContentCommandTest.java @@ -97,6 +97,7 @@ void setUp() when( nodeService.rename( isA( RenameNodeParams.class ) ) ).thenReturn( mockNode ); when( nodeService.getById( mockNode.id() ) ).thenReturn( mockNode ); + when( translator.getContentDataSerializer() ).thenReturn( new ContentDataSerializer() ); } @Test diff --git a/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentServiceTest.java b/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentServiceTest.java index 1dc2d19e0e9..e59b02973e5 100644 --- a/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentServiceTest.java +++ b/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentServiceTest.java @@ -144,6 +144,8 @@ public abstract class AbstractContentServiceTest protected ContentServiceImpl contentService; + protected ContentConfig config; + protected NodeServiceImpl nodeService; protected MixinService mixinService; @@ -320,7 +322,8 @@ void setUpAbstractContentServiceTest() projectService.create( CreateProjectParams.create().name( testprojectName ).displayName( "test" ).build() ); - contentService = new ContentServiceImpl( nodeService, pageDescriptorService, partDescriptorService, layoutDescriptorService ); + this.config = mock( ContentConfig.class, invocation -> invocation.getMethod().getDefaultValue() ); + contentService = new ContentServiceImpl( nodeService, pageDescriptorService, partDescriptorService, layoutDescriptorService, config ); contentService.setEventPublisher( eventPublisher ); contentService.setMediaInfoService( mediaInfoService ); contentService.setSiteService( siteService ); @@ -334,8 +337,6 @@ void setUpAbstractContentServiceTest() contentService.addContentValidator( new SiteConfigsValidator( siteService ) ); contentService.addContentValidator( new OccurrenceValidator() ); contentService.addContentValidator( new ExtraDataValidator( xDataService ) ); - - contentService.initialize( mock( ContentConfig.class, invocation -> invocation.getMethod().getDefaultValue() ) ); } @AfterEach diff --git a/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentSynchronizerTest.java b/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentSynchronizerTest.java index 6ddc3a12a4d..a28a2448c33 100644 --- a/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentSynchronizerTest.java +++ b/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/AbstractContentSynchronizerTest.java @@ -254,7 +254,8 @@ private void setUpContentService() final ContentAuditLogSupportImpl contentAuditLogSupport = new ContentAuditLogSupportImpl( contentConfig, Runnable::run, auditLogService, contentAuditLogFilterService ); - contentService = new ContentServiceImpl( nodeService, pageDescriptorService, partDescriptorService, layoutDescriptorService ); + final ContentConfig config = mock( ContentConfig.class, invocation -> invocation.getMethod().getDefaultValue() ); + contentService = new ContentServiceImpl( nodeService, pageDescriptorService, partDescriptorService, layoutDescriptorService, config ); contentService.setEventPublisher( eventPublisher ); contentService.setMediaInfoService( mediaInfoService ); contentService.setSiteService( siteService ); @@ -263,7 +264,6 @@ private void setUpContentService() contentService.setFormDefaultValuesProcessor( ( form, data ) -> { } ); contentService.setContentAuditLogSupport( contentAuditLogSupport ); - contentService.initialize( mock( ContentConfig.class, invocation -> invocation.getMethod().getDefaultValue() ) ); } private void setupTaskService() diff --git a/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/ContentServiceImplTest_media.java b/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/ContentServiceImplTest_media.java index 660e483b2be..e2fc6dcdf2c 100644 --- a/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/ContentServiceImplTest_media.java +++ b/modules/itest/itest-core/src/test/java/com/enonic/xp/core/content/ContentServiceImplTest_media.java @@ -84,10 +84,8 @@ public void create_media_image_invalid_file_name_allowed_by_config() Mockito.when( this.xDataService.getFromContentType( Mockito.any( ContentType.class ) ) ).thenReturn( XDatas.empty() ); - final ContentConfig contentConfig = mock( ContentConfig.class ); - when( contentConfig.attachments_allowUnsafeNames() ).thenReturn( true ); + when( config.attachments_allowUnsafeNames() ).thenReturn( true ); - contentService.initialize( contentConfig ); final Content content = this.contentService.create( createMediaParams ); final Content storedContent = this.contentService.getById( content.getId() ); diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ComponentHandler.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ComponentHandler.java index 4cc6aa80c48..ff975ef261b 100644 --- a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ComponentHandler.java +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ComponentHandler.java @@ -39,11 +39,14 @@ public final class ComponentHandler private final LayoutDescriptorService layoutDescriptorService; + private final ContentConfigReader configReader; + @Activate public ComponentHandler( @Reference final ContentService contentService, @Reference final RendererDelegate rendererDelegate, @Reference final PageTemplateService pageTemplateService, @Reference final PostProcessor postProcessor, @Reference final PageDescriptorService pageDescriptorService, - @Reference final LayoutDescriptorService layoutDescriptorService ) + @Reference final LayoutDescriptorService layoutDescriptorService, + @Reference final ContentConfigReader configReader ) { super( "component" ); this.contentService = contentService; @@ -52,6 +55,7 @@ public ComponentHandler( @Reference final ContentService contentService, @Refere this.postProcessor = postProcessor; this.pageDescriptorService = pageDescriptorService; this.layoutDescriptorService = layoutDescriptorService; + this.configReader = configReader; } @Override @@ -73,7 +77,7 @@ protected PortalResponse doHandle( final WebRequest webRequest, final WebRespons worker.contentService = contentService; worker.contentResolver = new ContentResolver( contentService ); worker.rendererDelegate = rendererDelegate; - worker.pageResolver = new PageResolver( pageTemplateService, pageDescriptorService, layoutDescriptorService ); + worker.pageResolver = getPageResolver(); worker.postProcessor = postProcessor; final Trace trace = Tracer.newTrace( "renderComponent" ); if ( trace == null ) @@ -82,4 +86,11 @@ protected PortalResponse doHandle( final WebRequest webRequest, final WebRespons } return Tracer.traceEx( trace, worker::execute ); } + + private PageResolver getPageResolver() + { + return configReader.getResolveEmptyRegions() + ? new PageResolver( pageTemplateService ) + : new FullPageResolver( pageTemplateService, pageDescriptorService, layoutDescriptorService ); + } } diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ContentConfigReader.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ContentConfigReader.java new file mode 100644 index 00000000000..38b3c9d97ee --- /dev/null +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/ContentConfigReader.java @@ -0,0 +1,25 @@ +package com.enonic.xp.portal.impl.handler.render; + +import java.util.Map; +import java.util.Optional; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; + +@Component(service = ContentConfigReader.class, configurationPid = "com.enonic.xp.content") +public class ContentConfigReader +{ + private final boolean resolveEmptyRegions; + + @Activate + public ContentConfigReader( final Map config ) + { + this.resolveEmptyRegions = + Optional.ofNullable( config.get( "resolveEmptyRegions" ) ).map( Object::toString ).map( Boolean::valueOf ).orElse( false ); + } + + public boolean getResolveEmptyRegions() + { + return this.resolveEmptyRegions; + } +} diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolver.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolver.java new file mode 100644 index 00000000000..afce229011d --- /dev/null +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolver.java @@ -0,0 +1,157 @@ +package com.enonic.xp.portal.impl.handler.render; + +import com.google.common.collect.ImmutableList; + +import com.enonic.xp.page.DescriptorKey; +import com.enonic.xp.page.Page; +import com.enonic.xp.page.PageDescriptor; +import com.enonic.xp.page.PageDescriptorService; +import com.enonic.xp.page.PageRegions; +import com.enonic.xp.page.PageTemplateService; +import com.enonic.xp.region.Component; +import com.enonic.xp.region.LayoutComponent; +import com.enonic.xp.region.LayoutDescriptor; +import com.enonic.xp.region.LayoutDescriptorService; +import com.enonic.xp.region.LayoutRegions; +import com.enonic.xp.region.Region; +import com.enonic.xp.region.RegionDescriptor; + +public class FullPageResolver extends PageResolver +{ + private final PageDescriptorService pageDescriptorService; + + private final LayoutDescriptorService layoutDescriptorService; + + public FullPageResolver( final PageTemplateService pageTemplateService, final PageDescriptorService pageDescriptorService, + final LayoutDescriptorService layoutDescriptorService ) + { + super( pageTemplateService ); + this.pageDescriptorService = pageDescriptorService; + this.layoutDescriptorService = layoutDescriptorService; + } + + @Override + protected PageResolverResult createResult( final Page effectivePage, final DescriptorKey controller ) + { + if ( controller == null ) + { + return new FullPageResolverResult( effectivePage, null, null ); + } + + return buildPageWithRegionsFromController( effectivePage, controller ); + } + + @Override + protected Page makeEffectivePageForFragment( final Page page ) + { + return buildPageFromFragment( page ); + } + + private Page buildPageFromFragment( final Page effectivePage ) + { + final Component fragmentComponent = effectivePage.getFragment(); + + if ( fragmentComponent instanceof LayoutComponent ) + { + final Page.Builder pageBuilder = Page.create( effectivePage ); + pageBuilder.fragment( processLayoutComponent( (LayoutComponent) fragmentComponent ) ); + return pageBuilder.build(); + } + + return effectivePage; + } + + private FullPageResolverResult buildPageWithRegionsFromController( final Page effectivePage, final DescriptorKey controller ) + { + final PageDescriptor pageDescriptor = pageDescriptorService.getByKey( controller ); + + if ( pageDescriptor == null || pageDescriptor.getModifiedTime() == null ) + { + return new FullPageResolverResult( effectivePage, controller, null ); + } + + final Page resultingPage = buildPageWithRegions( effectivePage, pageDescriptor ); + + return new FullPageResolverResult( resultingPage, controller, pageDescriptor ); + } + + private Page buildPageWithRegions( final Page sourcePage, final PageDescriptor pageDescriptor ) + { + final Page.Builder pageBuilder = Page.create( sourcePage ); + final PageRegions.Builder pageRegionsBuilder = PageRegions.create(); + + if ( pageDescriptor.getRegions() != null ) + { + pageDescriptor.getRegions().forEach( regionDescriptor -> { + pageRegionsBuilder.add( getOrCreatePageRegion( regionDescriptor, sourcePage ) ); + } ); + } + + return pageBuilder.regions( pageRegionsBuilder.build() ).build(); + } + + private Region getOrCreatePageRegion( final RegionDescriptor regionDescriptor, final Page sourcePage ) + { + final Region existingRegion = sourcePage.getRegion( regionDescriptor.getName() ); + + return existingRegion == null + ? Region.create().name( regionDescriptor.getName() ).build() + : processExistingPageRegion( existingRegion ); + } + + private Region processExistingPageRegion( final Region existingRegion ) + { + final Region.Builder builder = Region.create( existingRegion ); + final ImmutableList components = existingRegion.getComponents(); + + for ( int i = 0; i < components.size(); i++) + { + builder.set( i, processComponent( components.get( i ) ) ); + } + + return builder.build(); + } + + private Component processComponent( final Component component ) + { + if ( component instanceof LayoutComponent ) + { + return processLayoutComponent( (LayoutComponent) component ); + } + else + { + return component; + } + } + + private LayoutComponent processLayoutComponent( final LayoutComponent component ) + { + final LayoutDescriptor layoutDescriptor = + component.hasDescriptor() ? layoutDescriptorService.getByKey( component.getDescriptor() ) : null; + + if ( layoutDescriptor == null || layoutDescriptor.getModifiedTime() == null ) + { + return component; + } + + return buildLayoutWithRegions( component, layoutDescriptor ); + } + + private LayoutComponent buildLayoutWithRegions( final LayoutComponent existingLayout, final LayoutDescriptor layoutDescriptor ) + { + final LayoutComponent.Builder layoutBuilder = LayoutComponent.create( existingLayout ); + final LayoutRegions.Builder regionsBuilder = LayoutRegions.create(); + + if ( layoutDescriptor.getRegions() != null ) + { + layoutDescriptor.getRegions().forEach( region -> { + final Region existingRegion = existingLayout.getRegion( region.getName() ); + final Region regionToAdd = existingRegion == null ? Region.create().name( region.getName() ).build() : existingRegion; + regionsBuilder.add( regionToAdd ); + } ); + } + + return layoutBuilder.regions( regionsBuilder.build() ).build(); + } + +} diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolverResult.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolverResult.java new file mode 100644 index 00000000000..352e10838f5 --- /dev/null +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/FullPageResolverResult.java @@ -0,0 +1,27 @@ +package com.enonic.xp.portal.impl.handler.render; + +import com.enonic.xp.app.ApplicationKey; +import com.enonic.xp.page.DescriptorKey; +import com.enonic.xp.page.Page; +import com.enonic.xp.page.PageDescriptor; + +public final class FullPageResolverResult extends PageResolverResult +{ + private final PageDescriptor pageDescriptor; + + public FullPageResolverResult( final Page effectivePage, final DescriptorKey controller, final PageDescriptor pageDescriptor ) + { + super( effectivePage, controller ); + this.pageDescriptor = pageDescriptor; + } + + public ApplicationKey getApplicationKey() + { + return this.pageDescriptor == null ? null : pageDescriptor.getApplicationKey(); + } + + public PageDescriptor getPageDescriptor() + { + return pageDescriptor; + } +} diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandler.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandler.java index ea8d16858c9..73ce6288b77 100644 --- a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandler.java +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandler.java @@ -37,6 +37,8 @@ public final class PageHandler private PortalUrlService portalUrlService; + private ContentConfigReader configReader; + public PageHandler() { super( 50 ); @@ -58,7 +60,7 @@ protected PortalResponse doHandle( final WebRequest webRequest, final WebRespons worker.contentResolver = new ContentResolver( contentService ); worker.rendererDelegate = rendererDelegate; worker.pageDescriptorService = pageDescriptorService; - worker.pageResolver = new PageResolver( pageTemplateService, pageDescriptorService, layoutDescriptorService ); + worker.pageResolver = getPageResolver(); worker.portalUrlService = portalUrlService; final Trace trace = Tracer.newTrace( "renderComponent" ); if ( trace == null ) @@ -68,6 +70,13 @@ protected PortalResponse doHandle( final WebRequest webRequest, final WebRespons return Tracer.traceEx( trace, worker::execute ); } + private PageResolver getPageResolver() + { + return configReader.getResolveEmptyRegions() + ? new PageResolver( pageTemplateService ) + : new FullPageResolver( pageTemplateService, pageDescriptorService, layoutDescriptorService ); + } + @Reference public void setContentService( final ContentService contentService ) { @@ -103,4 +112,10 @@ public void setPortalUrlService( final PortalUrlService portalUrlService ) { this.portalUrlService = portalUrlService; } + + @Reference + public void setConfigReader( final ContentConfigReader configReader ) + { + this.configReader = configReader; + } } diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandlerWorker.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandlerWorker.java index a9e70b5f356..6178c519ac2 100644 --- a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandlerWorker.java +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageHandlerWorker.java @@ -7,6 +7,7 @@ import com.enonic.xp.content.Content; import com.enonic.xp.data.Property; import com.enonic.xp.data.PropertySet; +import com.enonic.xp.page.DescriptorKey; import com.enonic.xp.page.PageDescriptorService; import com.enonic.xp.portal.PortalRequest; import com.enonic.xp.portal.PortalResponse; @@ -62,10 +63,12 @@ public PortalResponse execute() final Content effectiveContent = Content.create( content ).page( resolvedPage.getEffectivePage() ).build(); + final DescriptorKey pageDescriptorKey = resolvedPage.getController(); this.request.setSite( site ); this.request.setContent( effectiveContent ); - this.request.setApplicationKey( resolvedPage.getApplicationKey() ); - this.request.setPageDescriptor( resolvedPage.getPageDescriptor() ); + + this.request.setApplicationKey( pageDescriptorKey != null ? pageDescriptorKey.getApplicationKey() : null ); + this.request.setPageDescriptor( pageDescriptorKey != null ? this.pageDescriptorService.getByKey( pageDescriptorKey ) : null ); final Trace trace = Tracer.current(); if ( trace != null ) diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolver.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolver.java index bc80a9e8c9a..9085c401549 100644 --- a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolver.java +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolver.java @@ -1,27 +1,15 @@ package com.enonic.xp.portal.impl.handler.render; -import com.google.common.collect.ImmutableList; - import com.enonic.xp.content.Content; import com.enonic.xp.content.ContentNotFoundException; import com.enonic.xp.content.ContentPath; import com.enonic.xp.page.DescriptorKey; import com.enonic.xp.page.GetDefaultPageTemplateParams; import com.enonic.xp.page.Page; -import com.enonic.xp.page.PageDescriptor; -import com.enonic.xp.page.PageDescriptorService; -import com.enonic.xp.page.PageRegions; import com.enonic.xp.page.PageTemplate; import com.enonic.xp.page.PageTemplateKey; import com.enonic.xp.page.PageTemplateService; import com.enonic.xp.portal.RenderMode; -import com.enonic.xp.region.Component; -import com.enonic.xp.region.LayoutComponent; -import com.enonic.xp.region.LayoutDescriptor; -import com.enonic.xp.region.LayoutDescriptorService; -import com.enonic.xp.region.LayoutRegions; -import com.enonic.xp.region.Region; -import com.enonic.xp.region.RegionDescriptor; import com.enonic.xp.schema.content.ContentTypeName; import com.enonic.xp.site.Site; import com.enonic.xp.web.HttpStatus; @@ -29,18 +17,11 @@ public class PageResolver { - private final PageTemplateService pageTemplateService; - - private final PageDescriptorService pageDescriptorService; - - private final LayoutDescriptorService layoutDescriptorService; + protected final PageTemplateService pageTemplateService; - public PageResolver( final PageTemplateService pageTemplateService, final PageDescriptorService pageDescriptorService, - final LayoutDescriptorService layoutDescriptorService ) + public PageResolver( final PageTemplateService pageTemplateService ) { this.pageTemplateService = pageTemplateService; - this.pageDescriptorService = pageDescriptorService; - this.layoutDescriptorService = layoutDescriptorService; } public PageResolverResult resolve( final RenderMode mode, final Content content, final Site site ) @@ -61,7 +42,7 @@ else if ( page != null ) if ( page.getFragment() != null ) { controller = null; - effectivePage = buildPageFromFragment( page ); + effectivePage = makeEffectivePageForFragment( page ); } else if ( page.getDescriptor() != null ) { @@ -108,15 +89,20 @@ else if ( page.getTemplate() != null ) } } - if ( controller == null ) - { - return new PageResolverResult( effectivePage, null, null ); - } + return createResult( effectivePage, controller ); + } - return buildPageWithRegionsFromController( effectivePage, controller ); + protected Page makeEffectivePageForFragment( final Page page ) + { + return page; } - private PageTemplate getPageTemplateOrFindDefault( final PageTemplateKey pageTemplate, final ContentTypeName contentType, + protected PageResolverResult createResult( final Page effectivePage, final DescriptorKey controller ) + { + return new PageResolverResult( effectivePage, controller ); + } + + protected PageTemplate getPageTemplateOrFindDefault( final PageTemplateKey pageTemplate, final ContentTypeName contentType, final ContentPath sitePath ) { try @@ -130,13 +116,13 @@ private PageTemplate getPageTemplateOrFindDefault( final PageTemplateKey pageTem } } - private static DescriptorKey getControllerFromTemplate( final PageTemplate pageTemplate, final RenderMode mode ) + protected DescriptorKey getControllerFromTemplate( final PageTemplate pageTemplate, final RenderMode mode ) { return errorOrNull( pageTemplate.getController(), mode, String.format( "Template [%s] has no page descriptor", pageTemplate.getName() ) ); } - private static T errorOrNull( final T object, final RenderMode mode, final String message ) + protected T errorOrNull( final T object, final RenderMode mode, final String message ) { if ( object == null ) { @@ -157,7 +143,7 @@ private static T errorOrNull( final T object, final RenderMode mode, final S } } - private static Page mergePageFromPageTemplate( final PageTemplate pageTemplate, final Page page ) + protected Page mergePageFromPageTemplate( final PageTemplate pageTemplate, final Page page ) { final Page templatePage = pageTemplate.getPage(); final PageTemplateKey templateKey = pageTemplate.getKey(); @@ -184,111 +170,4 @@ private static Page mergePageFromPageTemplate( final PageTemplate pageTemplate, } } - private Page buildPageFromFragment( final Page effectivePage ) - { - final Component fragmentComponent = effectivePage.getFragment(); - - if ( fragmentComponent instanceof LayoutComponent ) - { - final Page.Builder pageBuilder = Page.create( effectivePage ); - pageBuilder.fragment( processLayoutComponent( (LayoutComponent) fragmentComponent ) ); - return pageBuilder.build(); - } - - return effectivePage; - } - - private PageResolverResult buildPageWithRegionsFromController( final Page effectivePage, final DescriptorKey controller ) - { - final PageDescriptor pageDescriptor = pageDescriptorService.getByKey( controller ); - - if ( pageDescriptor == null || pageDescriptor.getModifiedTime() == null ) - { - return new PageResolverResult( effectivePage, controller, null ); - } - - final Page resultingPage = buildPageWithRegions( effectivePage, pageDescriptor ); - - return new PageResolverResult( resultingPage, controller, pageDescriptor ); - } - - private Page buildPageWithRegions( final Page sourcePage, final PageDescriptor pageDescriptor ) - { - final Page.Builder pageBuilder = Page.create( sourcePage ); - final PageRegions.Builder pageRegionsBuilder = PageRegions.create(); - - if ( pageDescriptor.getRegions() != null ) - { - pageDescriptor.getRegions().forEach( regionDescriptor -> { - pageRegionsBuilder.add( getOrCreatePageRegion( regionDescriptor, sourcePage ) ); - } ); - } - - return pageBuilder.regions( pageRegionsBuilder.build() ).build(); - } - - private Region getOrCreatePageRegion( final RegionDescriptor regionDescriptor, final Page sourcePage ) - { - final Region existingRegion = sourcePage.getRegion( regionDescriptor.getName() ); - - return existingRegion == null - ? Region.create().name( regionDescriptor.getName() ).build() - : processExistingPageRegion( existingRegion ); - } - - private Region processExistingPageRegion( final Region existingRegion ) - { - final Region.Builder builder = Region.create( existingRegion ); - final ImmutableList components = existingRegion.getComponents(); - - for ( int i = 0; i < components.size(); i++) - { - builder.set( i, processComponent( components.get( i ) ) ); - } - - return builder.build(); - } - - private Component processComponent( final Component component ) - { - if ( component instanceof LayoutComponent ) - { - return processLayoutComponent( (LayoutComponent) component ); - } - else - { - return component; - } - } - - private LayoutComponent processLayoutComponent( final LayoutComponent component ) - { - final LayoutDescriptor layoutDescriptor = - component.hasDescriptor() ? layoutDescriptorService.getByKey( component.getDescriptor() ) : null; - - if ( layoutDescriptor == null || layoutDescriptor.getModifiedTime() == null ) - { - return component; - } - - return buildLayoutWithRegions( component, layoutDescriptor ); - } - - private LayoutComponent buildLayoutWithRegions( final LayoutComponent existingLayout, final LayoutDescriptor layoutDescriptor ) - { - final LayoutComponent.Builder layoutBuilder = LayoutComponent.create( existingLayout ); - final LayoutRegions.Builder regionsBuilder = LayoutRegions.create(); - - if ( layoutDescriptor.getRegions() != null ) - { - layoutDescriptor.getRegions().forEach( region -> { - final Region existingRegion = existingLayout.getRegion( region.getName() ); - final Region regionToAdd = existingRegion == null ? Region.create().name( region.getName() ).build() : existingRegion; - regionsBuilder.add( regionToAdd ); - } ); - } - - return layoutBuilder.regions( regionsBuilder.build() ).build(); - } - } diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolverResult.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolverResult.java index 475af95d24a..1d17354869c 100644 --- a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolverResult.java +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/handler/render/PageResolverResult.java @@ -1,23 +1,18 @@ package com.enonic.xp.portal.impl.handler.render; -import com.enonic.xp.app.ApplicationKey; import com.enonic.xp.page.DescriptorKey; import com.enonic.xp.page.Page; -import com.enonic.xp.page.PageDescriptor; -public final class PageResolverResult +public class PageResolverResult { - private final Page effectivePage; + protected final Page effectivePage; - private final DescriptorKey controller; + protected final DescriptorKey controller; - private final PageDescriptor pageDescriptor; - - public PageResolverResult( final Page effectivePage, final DescriptorKey controller, final PageDescriptor pageDescriptor ) + public PageResolverResult( final Page effectivePage, final DescriptorKey controller ) { this.effectivePage = effectivePage; this.controller = controller; - this.pageDescriptor = pageDescriptor; } public Page getEffectivePage() @@ -29,14 +24,4 @@ public DescriptorKey getController() { return controller; } - - public ApplicationKey getApplicationKey() - { - return this.pageDescriptor == null ? null : pageDescriptor.getApplicationKey(); - } - - public PageDescriptor getPageDescriptor() - { - return pageDescriptor; - } } diff --git a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstruction.java b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstruction.java index 8ecf6a93da0..49f55697d51 100644 --- a/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstruction.java +++ b/modules/portal/portal-impl/src/main/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstruction.java @@ -13,6 +13,7 @@ import com.enonic.xp.page.Page; import com.enonic.xp.portal.PortalRequest; import com.enonic.xp.portal.PortalResponse; +import com.enonic.xp.portal.impl.handler.render.ContentConfigReader; import com.enonic.xp.portal.impl.rendering.RenderException; import com.enonic.xp.portal.impl.rendering.RendererDelegate; import com.enonic.xp.portal.postprocess.PostProcessInstruction; @@ -39,6 +40,8 @@ public final class ComponentInstruction private ComponentService componentService; + private ContentConfigReader configReader; + @Reference public void setRendererDelegate( final RendererDelegate rendererDelegate ) { @@ -51,197 +54,321 @@ public void setComponentService( final ComponentService componentService ) this.componentService = componentService; } + @Reference + public void setConfigReader( final ContentConfigReader configReader ) + { + this.configReader = configReader; + } + @Override public PortalResponse evaluate( final PortalRequest portalRequest, final String instruction ) { - final String componentPath = getComponentPathFromInstruction( instruction ); - final PortalResponse portalResponse = componentPath == null ? null : renderComponent( portalRequest, componentPath ); - - return portalResponse; + return configReader.getResolveEmptyRegions() + ? new RawInstructionEvaluator().evaluate( portalRequest, instruction ) + : new FullInstructionEvaluator().evaluate( portalRequest, instruction ); } - private String getComponentPathFromInstruction( final String instruction ) + private final class FullInstructionEvaluator { - if ( !Instruction.isInstruction( instruction, COMPONENT_INSTRUCTION_PREFIX ) ) + public PortalResponse evaluate( final PortalRequest portalRequest, final String instruction ) { - return null; + final String componentPath = getComponentPathFromInstruction( instruction ); + return componentPath == null ? null : renderComponent( portalRequest, componentPath ); } - final List list = Splitter.on( ' ' ).omitEmptyStrings().splitToList( instruction ); - - if ( list.size() != 2 ) + private String getComponentPathFromInstruction( final String instruction ) { - return null; - } + if ( !Instruction.isInstruction( instruction, COMPONENT_INSTRUCTION_PREFIX ) ) + { + return null; + } - return list.get( 1 ); - } + final List list = Splitter.on( ' ' ).omitEmptyStrings().splitToList( instruction ); - private PortalResponse renderComponent( final PortalRequest portalRequest, final String componentSelector ) - { - final Component component = resolveComponent( portalRequest, componentSelector ); - return renderComponent( portalRequest, component ); - } + if ( list.size() != 2 ) + { + return null; + } - private Component resolveComponent( final PortalRequest portalRequest, final String componentSelector ) - { - if ( FRAGMENT_COMPONENT.equalsIgnoreCase( componentSelector ) ) - { - return resolveFragmentComponent( portalRequest ); + return list.get( 1 ); } - if ( componentSelector.startsWith( APPLICATION_COMPONENT_PREFIX ) ) + private PortalResponse renderComponent( final PortalRequest portalRequest, final String componentSelector ) { - return resolveComponentFromModule( componentSelector, portalRequest.getApplicationKey() ); + final Component component = resolveComponent( portalRequest, componentSelector ); + return renderComponent( portalRequest, component ); } - return resolveComponent( portalRequest, ComponentPath.from( componentSelector ) ); - } + private Component resolveComponent( final PortalRequest portalRequest, final String componentSelector ) + { + if ( FRAGMENT_COMPONENT.equalsIgnoreCase( componentSelector ) ) + { + return resolveFragmentComponent( portalRequest ); + } - private Component resolveComponentFromModule( final String componentSelector, final ApplicationKey currentApplication ) - { - final String name = componentSelector.substring( APPLICATION_COMPONENT_PREFIX.length() ); - return currentApplication == null ? null : componentService.getByKey( DescriptorKey.from( currentApplication, name ) ); - } + if ( componentSelector.startsWith( APPLICATION_COMPONENT_PREFIX ) ) + { + return resolveComponentFromModule( componentSelector, portalRequest.getApplicationKey() ); + } - private PortalResponse renderComponent( final PortalRequest portalRequest, final Component component ) - { - final Trace trace = Tracer.newTrace( "renderComponent" ); - if ( trace == null ) + return resolveComponent( portalRequest, ComponentPath.from( componentSelector ) ); + } + + private Component resolveComponentFromModule( final String componentSelector, final ApplicationKey currentApplication ) { - return rendererDelegate.render( component, portalRequest ); + final String name = componentSelector.substring( APPLICATION_COMPONENT_PREFIX.length() ); + return currentApplication == null ? null : componentService.getByKey( DescriptorKey.from( currentApplication, name ) ); } - trace.put( "componentPath", component.getPath() ); - trace.put( "type", component.getType().toString() ); - return Tracer.trace( trace, () -> rendererDelegate.render( component, portalRequest ) ); - } + private PortalResponse renderComponent( final PortalRequest portalRequest, final Component component ) + { + final Trace trace = Tracer.newTrace( "renderComponent" ); + if ( trace == null ) + { + return rendererDelegate.render( component, portalRequest ); + } - private Component resolveComponent( final PortalRequest portalRequest, final ComponentPath path ) - { - final Content content = portalRequest.getContent(); + trace.put( "componentPath", component.getPath() ); + trace.put( "type", component.getType().toString() ); + return Tracer.trace( trace, () -> rendererDelegate.render( component, portalRequest ) ); + } - if ( content == null ) + private Component resolveComponent( final PortalRequest portalRequest, final ComponentPath path ) { - return null; + final Content content = portalRequest.getContent(); + + if ( content == null ) + { + return null; + } + + if ( content.getType().isFragment() ) + { + return resolveComponentInFragment( content, path ); + } + + Component component = content.getPage().getRegions().getComponent( path ); + + if ( component == null ) + { + throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + } + + if ( component instanceof LayoutComponent ) + { + return resolveLayoutWithRegions( (LayoutComponent) component, content.getPage() ); + } + + return component; } - if ( content.getType().isFragment() ) + private LayoutComponent resolveLayoutWithRegions( final LayoutComponent existingLayout, final Page page ) { - return resolveComponentInFragment( content, path ); - } + if ( !existingLayout.hasDescriptor() ) + { + return existingLayout; + } - Component component = content.getPage().getRegions().getComponent( path ); + final LayoutComponent layoutFromDescriptor = (LayoutComponent) componentService.getByKey( existingLayout.getDescriptor() ); - if ( component == null ) - { - throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + if ( layoutFromDescriptor == null ) + { + return existingLayout; + } + + final LayoutComponent layoutComponent = buildLayoutWithRegions( existingLayout, layoutFromDescriptor ); + setParentRegionOnLayout( page, existingLayout, layoutComponent ); + return layoutComponent; } - if ( component instanceof LayoutComponent ) + private LayoutComponent buildLayoutWithRegions( final LayoutComponent existingLayout, final LayoutComponent layoutFromDescriptor ) { - return resolveLayoutWithRegions( (LayoutComponent) component, content.getPage() ); - } + final LayoutComponent.Builder layoutBuilder = LayoutComponent.create( existingLayout ); + final LayoutRegions.Builder regionsBuilder = LayoutRegions.create(); - return component; - } + layoutFromDescriptor.getRegions().forEach( region -> { + final Region existingRegion = existingLayout.getRegion( region.getName() ); + final Region regionToAdd = existingRegion == null ? Region.create().name( region.getName() ).build() : existingRegion; + regionsBuilder.add( regionToAdd ); + } ); - private LayoutComponent resolveLayoutWithRegions( final LayoutComponent existingLayout, final Page page ) - { - if ( !existingLayout.hasDescriptor() ) - { - return existingLayout; + return layoutBuilder.regions( regionsBuilder.build() ).build(); } - final LayoutComponent layoutFromDescriptor = (LayoutComponent) componentService.getByKey( existingLayout.getDescriptor() ); - - if ( layoutFromDescriptor == null ) + private void setParentRegionOnLayout( final Page page, final LayoutComponent existingLayout, final LayoutComponent resultingLayout ) { - return existingLayout; + if ( page == null || page.getRegions() == null ) + { + return; + } + + page.getRegions().forEach( region -> { + final int index = region.getIndex( existingLayout ); + + if ( index > -1 ) + { + Region.create( region ).set( index, resultingLayout ).build(); // The only way to set layout's parent region + } + } ); } - final LayoutComponent layoutComponent = buildLayoutWithRegions( existingLayout, layoutFromDescriptor ); - setParentRegionOnLayout( page, existingLayout, layoutComponent ); - return layoutComponent; - } + private Component resolveComponentInFragment( final Content content, final ComponentPath path ) + { + final Component fragmentComponent = content.getPage().getFragment(); - private LayoutComponent buildLayoutWithRegions( final LayoutComponent existingLayout, final LayoutComponent layoutFromDescriptor ) - { - final LayoutComponent.Builder layoutBuilder = LayoutComponent.create( existingLayout ); - final LayoutRegions.Builder regionsBuilder = LayoutRegions.create(); + if ( !( fragmentComponent instanceof LayoutComponent ) ) + { + throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + } - layoutFromDescriptor.getRegions().forEach( region -> { - final Region existingRegion = existingLayout.getRegion( region.getName() ); - final Region regionToAdd = existingRegion == null ? Region.create().name( region.getName() ).build() : existingRegion; - regionsBuilder.add( regionToAdd ); - } ); + final LayoutComponent layout = (LayoutComponent) fragmentComponent; + final LayoutRegions pageRegions = layout.getRegions(); + final Component component = pageRegions.getComponent( path ); - return layoutBuilder.regions( regionsBuilder.build() ).build(); - } + if ( component == null ) + { + throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + } - private void setParentRegionOnLayout( final Page page, final LayoutComponent existingLayout, final LayoutComponent resultingLayout ) - { - if ( page == null || page.getRegions() == null ) + return component; + } + + private Component resolveFragmentComponent( final PortalRequest portalRequest ) + { + final Component fragmentComponent = getPageFragment( portalRequest ); + return processFragment( fragmentComponent ); + } + + private Component processFragment( final Component fragmentComponent ) { - return; + if ( fragmentComponent instanceof LayoutComponent ) + { + return resolveLayoutWithRegions( (LayoutComponent) fragmentComponent, null ); + } + + return fragmentComponent; } - page.getRegions().forEach( region -> { - final int index = region.getIndex( existingLayout ); + private Component getPageFragment( final PortalRequest portalRequest ) + { + final Content content = portalRequest.getContent(); - if ( index > -1 ) + if ( content == null || content.getPage() == null ) { - Region.create( region ).set( index, resultingLayout ).build(); // The only way to set layout's parent region + return null; } - } ); + + return content.getPage().getFragment(); + } } - private Component resolveComponentInFragment( final Content content, final ComponentPath path ) + private final class RawInstructionEvaluator { - final Component fragmentComponent = content.getPage().getFragment(); - - if ( !( fragmentComponent instanceof LayoutComponent ) ) + public PortalResponse evaluate( final PortalRequest portalRequest, final String instruction ) { - throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); - } + if ( !Instruction.isInstruction( instruction, COMPONENT_INSTRUCTION_PREFIX ) ) + { + return null; + } + + final List list = Splitter.on( ' ' ).omitEmptyStrings().splitToList( instruction ); + if ( list.size() != 2 ) + { + return null; + } - final LayoutComponent layout = (LayoutComponent) fragmentComponent; - final LayoutRegions pageRegions = layout.getRegions(); - final Component component = pageRegions.getComponent( path ); + final String path = list.get( 1 ); + return renderComponent( portalRequest, path ); + } - if ( component == null ) + private PortalResponse renderComponent( final PortalRequest portalRequest, final String componentSelector ) { - throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + final Component component; + if ( FRAGMENT_COMPONENT.equalsIgnoreCase( componentSelector ) ) + { + component = getPageFragment( portalRequest ); + } + else if ( !componentSelector.startsWith( APPLICATION_COMPONENT_PREFIX ) ) + { + final ComponentPath componentPath = ComponentPath.from( componentSelector ); + component = resolveComponent( portalRequest, componentPath ); + } + else + { + final String name = componentSelector.substring( APPLICATION_COMPONENT_PREFIX.length() ); + final ApplicationKey currentApplication = portalRequest.getApplicationKey(); + component = currentApplication == null ? null : componentService.getByKey( DescriptorKey.from( currentApplication, name ) ); + } + return renderComponent( portalRequest, component ); } - return component; - } + private PortalResponse renderComponent( final PortalRequest portalRequest, final Component component ) + { + final Trace trace = Tracer.newTrace( "renderComponent" ); + if ( trace == null ) + { + return rendererDelegate.render( component, portalRequest ); + } - private Component resolveFragmentComponent( final PortalRequest portalRequest ) - { - final Component fragmentComponent = getPageFragment( portalRequest ); - return processFragment( fragmentComponent ); - } + trace.put( "componentPath", component.getPath() ); + trace.put( "type", component.getType().toString() ); + return Tracer.trace( trace, () -> rendererDelegate.render( component, portalRequest ) ); + } - private Component processFragment( final Component fragmentComponent ) - { - if ( fragmentComponent instanceof LayoutComponent ) + private Component resolveComponent( final PortalRequest portalRequest, final ComponentPath path ) { - return resolveLayoutWithRegions( (LayoutComponent) fragmentComponent, null ); - } + final Content content = portalRequest.getContent(); + if ( content == null ) + { + return null; + } - return fragmentComponent; - } + if ( content.getType().isFragment() ) + { + return resolveComponentInFragment( content, path ); + } - private Component getPageFragment( final PortalRequest portalRequest ) - { - final Content content = portalRequest.getContent(); + Component component = content.getPage().getRegions().getComponent( path ); + if ( component == null ) + { + throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + } + + return component; + } - if ( content == null || content.getPage() == null ) + private Component resolveComponentInFragment( final Content content, final ComponentPath path ) { - return null; + final Component fragmentComponent = content.getPage().getFragment(); + if ( !( fragmentComponent instanceof LayoutComponent ) ) + { + throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + } + final LayoutComponent layout = (LayoutComponent) fragmentComponent; + + final LayoutRegions pageRegions = layout.getRegions(); + final Component component = pageRegions.getComponent( path ); + if ( component == null ) + { + throw new RenderException( MessageFormat.format( "Component not found: [{0}]", path ) ); + } + return component; } - return content.getPage().getFragment(); + private Component getPageFragment( final PortalRequest portalRequest ) + { + final Content content = portalRequest.getContent(); + if ( content == null ) + { + return null; + } + + final Page page = content.getPage(); + if ( page == null ) + { + return null; + } + return page.getFragment(); + } } } diff --git a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/ComponentHandlerTest.java b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/ComponentHandlerTest.java index e043d11fb87..9ab8a5a1047 100644 --- a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/ComponentHandlerTest.java +++ b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/ComponentHandlerTest.java @@ -1,5 +1,7 @@ package com.enonic.xp.portal.impl.handler.render; +import java.util.HashMap; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -48,8 +50,9 @@ public class ComponentHandlerTest public final void setup() throws Exception { + final ContentConfigReader contentConfigReader = new ContentConfigReader( new HashMap<>() ); this.handler = new ComponentHandler( this.contentService, this.rendererDelegate, this.pageTemplateService, this.postProcessor, - this.pageDescriptorService, this.layoutDescriptorService ); + this.pageDescriptorService, this.layoutDescriptorService, contentConfigReader ); this.request.setMethod( HttpMethod.GET ); this.request.setContentPath( ContentPath.from( "/site/somepath/content" ) ); diff --git a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageHandlerTest.java b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageHandlerTest.java index 3022335a596..5fbf95fc285 100644 --- a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageHandlerTest.java +++ b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageHandlerTest.java @@ -1,5 +1,7 @@ package com.enonic.xp.portal.impl.handler.render; +import java.util.HashMap; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -56,6 +58,7 @@ public final void setup() this.handler.setPageTemplateService( this.pageTemplateService ); this.handler.setRendererDelegate( this.rendererDelegate ); this.handler.setPortalUrlService( this.portalUrlService ); + this.handler.setConfigReader( new ContentConfigReader( new HashMap<>() ) ); this.request.setMethod( HttpMethod.GET ); this.request.setContentPath( ContentPath.from( "/site/somepath/content" ) ); diff --git a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageResolverTest.java b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageResolverTest.java index 3cddf9abf61..93dcd4049e5 100644 --- a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageResolverTest.java +++ b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/handler/render/PageResolverTest.java @@ -94,7 +94,7 @@ public void before() .add( Region.create().name( "regionB" ).add( PartComponent.create().descriptor( "myapp:my-part" ).build() ).build() ) .build(); - pageResolver = new PageResolver( pageTemplateService, pageDescriptorService, layoutDescriptorService ); + pageResolver = new FullPageResolver( pageTemplateService, pageDescriptorService, layoutDescriptorService ); } @Test diff --git a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstructionTest.java b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstructionTest.java index 20606e632a3..901fe2ad38f 100644 --- a/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstructionTest.java +++ b/modules/portal/portal-impl/src/test/java/com/enonic/xp/portal/impl/postprocess/instruction/ComponentInstructionTest.java @@ -1,5 +1,7 @@ package com.enonic.xp.portal.impl.postprocess.instruction; +import java.util.HashMap; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -15,6 +17,7 @@ import com.enonic.xp.page.PageTemplateKey; import com.enonic.xp.portal.PortalRequest; import com.enonic.xp.portal.PortalResponse; +import com.enonic.xp.portal.impl.handler.render.ContentConfigReader; import com.enonic.xp.portal.impl.rendering.RenderException; import com.enonic.xp.portal.impl.rendering.RendererDelegate; import com.enonic.xp.region.Component; @@ -55,6 +58,7 @@ public final void setup() instruction.setRendererDelegate( rendererDelegate ); instruction.setComponentService( componentService ); + instruction.setConfigReader( new ContentConfigReader( new HashMap<>() ) ); } @Test @@ -126,7 +130,7 @@ public void testLayoutIsReturnedWithRegions() instruction.evaluate( portalRequest, "COMPONENT myRegion/0" ); - assertEquals( captor.getValue(), layoutFromService ); + assertEquals( layoutFromService, captor.getValue() ); } @Test