Page level synchronisation issue | Hybris - sap-commerce-cloud

In our CMSCockpit for staged content when any component is updated then its synchronisation button turns into red, but the synchronisation button remains green at page level in the same case as show in the fig. However if any page level attribute is updated the synchronisation button turns into red. Also if the synhcronisation button is clicked then the updates/changes happened in its child component those don't get synchronized.
Is this expected behavior if not then how it can be fixed or if yes then how can it be customised?
Thanks in advance

If I am understanding correct, you have issue with the nested Synchronization.
You need to add child component information (if any) in synchronizationService as well.
Open cmscockpit-spring-services.xml and check you will see a bean named with synchronizationService. Have a look OOTB RotatingImagesComponent entry. Hybris have added RotatingImagesComponent.banners in the list map because whenever any banner attribute will changes, it should get reflected.
<alias alias="synchronizationService" name="defaultCMSSynchronizationService" />
<alias alias="defaultSynchronizationService" name="defaultCMSSynchronizationService" />
<bean id="defaultCMSSynchronizationService" class="de.hybris.platform.cmscockpit.sync.CMSSynchronizationService" scope="tenant" autowire="byName">
<property name="relatedReferencesTypesMap">
<map>
<entry key="AbstractPage">
<list>
<value>AbstractPage.restrictions</value>
<value>AbstractPage.contentSlots</value>
<value>ContentSlotForPage.contentSlot</value>
<value>ContentSlot.cmsComponents</value>
<value>AbstractCMSComponentContainer.simpleCMSComponents</value>
<value>AbstractCMSComponentContainer.currentCMSComponents</value>
<value>RotatingImagesComponent.banners</value>
<value>AbstractCMSComponent.restrictions</value>
<value>abstractMediaContainerComponent.media</value>
</list>
</entry>
<entry key="AbstractCMSComponent">
<list>
<value>AbstractCMSComponentContainer.simpleCMSComponents</value>
<value>AbstractCMSComponentContainer.currentCMSComponents</value>
<value>RotatingImagesComponent.banners</value>
<value>AbstractCMSComponent.restrictions</value>
<value>abstractMediaContainerComponent.media</value>
<value>MediaContainer.medias</value>
<value>NavigationBarCollectionComponent.components</value>
<value>NavigationBarComponent.navigationNode</value>
<value>NavigationBarComponent.link</value>
</list>
</entry>
<entry key="CMSNavigationNode">
<list>
<value>CMSNavigationNode.children</value>
<value>CMSNavigationNode.entries</value>
<value>CMSNavigationNode.links</value>
<value>CMSNavigationEntry.item</value>
<value>CMSLinkComponent</value>
</list>
</entry>
<entry key="ContentSlot">
<list>
<value>ContentSlot.cmsComponents</value>
<value>abstractMediaContainerComponent.media</value>
<value>NavigationBarCollectionComponent.components</value>
<value>NavigationBarComponent.navigationNode</value>
<value>NavigationBarComponent.link</value>
</list>
</entry>
<entry key="MediaContainer">
<list>
<value>MediaContainer.medias</value>
</list>
</entry>
</map>
</property>
<property name="searchRestrictionsDisabled" value="true"/>
</bean>
You need to override this bean in your cmscockpit-services.xml to add your customer attribute items entry as well.

Related

How can we make OOTB Component Attribute optional in Child component in SmartEdit?

Is there any way to make OOTB Component field optional in Child component in SmartEdit ?
For example, I extended CMSParagraphComponent by creating child component e.g. MyCustomParagraphComponent which extends CMSParagraphComponent.
OOTB CMSParagraphComponent -> content attribute is mandatory as defined in its CMS Structure API
<bean class="de.hybris.platform.cmsfacades.types.service.impl.DefaultComponentTypeAttributeStructure" p:typecode="CMSParagraphComponent" p:qualifier="content">
<property name="populators">
<set>
<ref bean="richTextComponentTypeAttributePopulator" />
<ref bean="requiredComponentTypeAttributePopulator" />
</set>
</property>
</bean>
requiredComponentTypeAttributePopulator makes this attribute mandatory. In addition, OOTB SmartEdit using cmsParagraphComponentValidator as well for backend validation.
Now I want to make content attribute optional for my custom MyCustomParagraphComponent
I tried creating new populator bean unRequiredComponentTypeAttributePopulator with required=false and assign it to content attribute of my custom component but that doesn’t work
Trying something like this ...
<bean id="unRequiredComponentTypeAttributePopulator" class="de.hybris.platform.cmsfacades.types.populator.RequiredComponentTypeAttributePopulator">
<property name="required" value="false" />
</bean>
<bean class="de.hybris.platform.cmsfacades.types.service.impl.DefaultComponentTypeAttributeStructure" p:typecode="PromotionalBannerComponent" p:qualifier="content">
<property name="populators">
<set>
<ref bean="unRequiredComponentTypeAttributePopulator" />
</set>
</property>
</bean>
But this is not working. It look like CMS Structure API works on only those attribute assigned directly to that component not parent one.
Then what is the correct way to do that ?
In your custom "facade-spring.xml", define the bean:
<bean id="optionalComponentTypeAttributePopulator" class="de.hybris.platform.cmsfacades.types.populator.RequiredComponentTypeAttributePopulator">
<property name="required" value="false" />
</bean>
Now, in your custom "facade-spring.xml", try overriding the bean of the Out of the Box:
<bean class="de.hybris.platform.cmsfacades.types.service.impl.DefaultComponentTypeAttributeStructure" p:typecode="CMSLinkComponent" p:qualifier="product">
<property name="populators">
<set>
<ref bean="optionalComponentTypeAttributePopulator" />
</set>
</property>
</bean>
I have tested this locally and it works perfectly.

Which way of specifiying my beans in spring-integration.xml is better?

I have two different ways of declaring a spring integration bean. They both seem to work. I'm using the Spring STS Eclipse based IDE.
This way:
<bean id="int-ftp:request-handler-advice-chain"
class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="trapException" value="true"></property>
<property name="onFailureExpression" value="#root"></property>
<property name="failureChannel" ref="errorChannel"></property>
</bean>
or this way:
<int-ftp:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="trapException" value="true" />
<property name="onFailureExpression" value="#root" />
<property name="failureChannel" ref="errorChannel" />
</bean>
</int-ftp:request-handler-advice-chain>
Which way is better?
For the target <int-ftp:outbound-gateway> it doesn't matter. Works well, as you noticed already.
Only the difference that the second declaration is nested and the final bean is visible only from the <int-ftp:request-handler-advice-chain> context.
The first definition is top-level global bean, which is visible everywhere and can be reused from other bean as well.
You can find more info about Inner Beans in the Spring Framework.

Spring Batch - How to achieve multi-threading/partitioning with Single large XML - StaxEventItemReader

I am using Spring Batch 3.2 for bulk migration of data from XML to Database.
My XML contains around 140K users and I want to dump it into DB.
I do not want to proceed it in a single thread.
I tried using TaskExecutor but not able to succeed due to below error.
at java.lang.Thread.run(Thread.java:724)
Caused by: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag </consumerName>; expected </first>.
at [row,col {unknown-source}]: [4814,26]
at com.ctc.wstx.sr.StreamScanner.constructWfcException(StreamScanner.java:606)
at com.ctc.wstx.sr.StreamScanner.throwParseError(StreamScanner.java:479)
at com.ctc.wstx.sr.StreamScanner.throwParseError(StreamScanner.java:464)
at com.ctc.wstx.sr.BasicStreamReader.reportWrongEndElem(BasicStreamReader.java:3283)
at com.ctc.wstx.sr.BasicStreamReader.readEndElem(BasicStreamReader.java:3210)
at com.ctc.wstx.sr.BasicStreamReader.nextFromTree(BasicStreamReader.java:2829)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1072)
at org.codehaus.stax2.ri.Stax2EventReaderImpl.peek(Stax2EventReaderImpl.java:367)
at org.springframework.batch.item.xml.stax.DefaultFragmentEventReader.nextEvent(DefaultFragmentEventReader.java:114)
at org.springframework.batch.item.xml.stax.DefaultFragmentEventReader.markFragmentProcessed(DefaultFragmentEventReader.java:184)
where consumerName and first are XML nodes.
I knew StaxEventItemReader is not a thread safe and multiple threads are using XML and due to that issue, there is some problem in marking fragments as processed and I am not able to get unique record as well as complete fragment to process.
Can any one suggest me how Can I use multi-threading/partitioning in my case.
What I want
By using multi-threading, how can I make sure that each thread get unique chuck i.e (Thread 1 - fragement 1-100, Thread 2 - fragement 101-200.... so on)
Each thread process unique chuck and dump into DB.
My configuration
<batch:job id="sampleJob">
<batch:step id="multiThreadStep" allow-start-if-complete="true">
<batch:tasklet transaction-manager="transactionManager" task-executor="taskExecutor" throttle-limit="10">
<batch:chunk reader="xmlItemReader" writer="itemWriter"
processor="itemProcessor" commit-interval="10" skip-limit="1500000">
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception" />
</batch:skippable-exception-classes>
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<!-- <bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor">
<property name="concurrencyLimit" value="10"/>
</bean> -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="10" />
<property name="allowCoreThreadTimeOut" value="true" />
</bean>
<bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="fragmentRootElementName" value="userItem" />
<property name="unmarshaller" ref="userDetailUnmarshaller" />
<property name="saveState" value="false" />
</bean>
Sample XML
<userItems>
<userItem>
<...>
<...>
</userItem>
<userItem>
<...>
<...>
</userItem>
...
...
</userItems>

Spring MVC 3 content negotiation restrict to actions which support it

I have configured content negotiation in my Spring MVC 3 app as follows:
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="0" />
<property name="favorPathExtension" value="true" />
<property name="defaultContentType">
<ref bean="htmlMediaType" />
</property>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.castor.CastorMarshaller" />
</property>
</bean>
</list>
</property>
<property name="viewResolvers">
<ref bean="tilesViewResolver" />
</property>
</bean>
This works very well -- all my views will render as html views with the 'normal' view templates, or as JSON or XML dumps of the view model data depending on the 'Accept' header.
However, this seems to be a bit of a security hole to me. Some of my actions are API-style actions, and are legitimately available in HTML or JSON or XML. However, some views are intended to be HTML-only. I don't really want end-users to be able to see all the view data just by adding ".json" to the url.
Is there any way to do content negotiation in Spring MVC, but only on actions which have explicitly opted-in to it? Can I set up a controller annotation like #RespondsTo("xml", "json")?
Why don't you use a filter through DelegatingFilterProxy to block users from accessing unnecessary content types ?
I was just facing the same problem. produces attribute of #RequestMapping helps for that. Although it's the opposite of what you asked for - kind of opt-out instead of opt-in, but I think it's what can please you.
#Controller
#RequestMapping("/categories")
public class CategoriesController
{
#RequestMapping(value = "/create", method = RequestMethod.GET, produces = "application/xhtml+xml")
public String createForm(Model model)
{
}
}
/create - works fine by displaying JSP view
/create.json - 406 Error
One way to do it would be to use Spring Security to restrict which pages can be seen based on the content-type (or whatever other method(s) you are using for content negotiation.

How to give site page as an url to SearchResultPageURL property of sharepoint searchbox control?

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Control
Id="SmallSearchInputBox"
Sequence="24"
ControlClass="Microsoft.SharePoint.Portal.WebControls.SearchBoxEx"
ControlAssembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
<Property Name="SearchResultPageURL">**~Site/Pages/Customsearchresults.aspx**"></Property>
<Property Name="FrameType">None</Property>
<Property Name="DropDownMode">HideDD_NoScope</Property>
<Property Name="TextBoxWidth">140</Property>
<Property Name="ShowAdvancedSearch">false</Property>
</Control>
</Elements>
The ~ operator doesnt work. I dont want to give an application page url.
true
UseSiteDefaults property is a must if you want a custom site page to be the target searchresults page.

Resources