I am using transfer and I have a ManyToMany relationship between articles and videos. What I need to be able to do is to stick a timestamp against each video when it is added to an article. i.e. I have two tables:
article (ID, title, body)
video (ID, url)
I then have a linked table:
article_videos(articleID, videoID)
I need to add in an extra column timeStamp to article_videos:
article_videos(articleID, videoID, timeStamp)
The problem I have is that when I try and create an extra property in the link table it does not work.
My Transfer ORM configuration:
<package name="article">
<object name="Article" table="article">
<id name="ID" type="numeric"/>
<property name="Title" type="string" column="title"/>
<property name="Body" type="string" column="body"/>
<manytomany name="Videos" table="article_videos">
<link to="article.Atricle" column="articleID"/>
<link to="assets.Video" column="videoID"/>
<collection type="array">
<order property="OrderIndex" order="asc"/>
</collection>
<property name="TimeStamp" type="timestamp" column="timeStamp"/>
</manytomany>
</object>
</package>
<package name="assets">
<object name="Video" table="video">
<id name="ID" type="numeric"/>
<property name="url" type="string" column="url"/>
</object>
</package>
The problem is that the new property inside the ManyToMany is not allowed, it throws an error saying that the Transfer configuration is malformed.
Where and how should I add the timestamp baring in mind that the timestamp needs to be for that video in that article as the video may be used in multiple articles?
Thanks in advance.
What you will likely have to do is create a new object for your article_videos join.
Because Transfer ORM handles many-to-many joins transparently so you don't directly interact with the join table if you wanted to add and access additional properties on the join you will need to create a new object. There are a couple of ways to achieve this.
If you still wanted to handle the many-to-many relationship transparently and the timestamp will be automatically populated by the database you can keep the relationship as is and add a new object representing article_videos and a new relationship joining that object to both article and video objects.
So you would add a new object representing the article_videos, I might also add a surrogate key to the database or you might want to use a composite ID:
<object name="ArticleVideo" table="article_videos">
<id name="ID" type="numeric"/>
<property name="TimeStamp" type="timestamp" column="timeStamp"/>
</object>
Then you would update your Article object to reference this new object:
<object name="Article" table="article">
<id name="ID" type="numeric"/>
<property name="Title" type="string" column="title"/>
<property name="Body" type="string" column="body"/>
<manytomany name="Videos" table="article_videos">
<link to="article.Article" column="articleID"/>
<link to="assets.Video" column="videoID"/>
<collection type="array">
<order property="OrderIndex" order="asc"/>
</collection>
</manytomany>
<onetomany name="ArticleVideo">
<link to="article.ArticleVideo" column="articleID"/>
<collection type="array">
<order property="TimeStamp" order="asc"/>
</collection>
</onetomany>
</object>
And you would also update your Video object:
<object name="Video" table="video">
<id name="ID" type="numeric"/>
<property name="url" type="string" column="url"/>
<onetomany name="ArticleVideo">
<link to="article.ArticleVideo" column="videoID"/>
<collection type="array">
<order property="TimeStamp" order="asc"/>
</collection>
</onetomany>
</object>
This way you can use the Article to Video object relationship as normal but access the additional properties if you need to:
// Creating the join using the many-to-many relationship
article = transfer.get("article.Article", 1);
article.addVideo(video);
You can also then access the join, how you get the information to correlate the above relationship to the join might require a bit of work, so you will likely have to decide up front whether the join you are creating you will want more info:
// Creating the join using the ArticleVideo object
articleVideo = transfer.new("article.ArticleVideo");
articleVideo.addParentArticle(article);
articleVideo.addParentVideo(video);
transfer.save(articleVideo);
// Using a composite ID to access the ArticleVideo
articleVideo = transfer.get("article.ArticleVideo", {
"ArticleID" = 1,
"VideoID" = 1
});
WriteOutput("The timestamp is: #articleVideo.getTimeStamp()#");
Otherwise you can adjust all of the relationships, but this will require you using an intermediate object between your videos and articles. If it is just a timestamp, then it may be unnecessary.
Related
I need to copy the value of one property in a propertyfile to a second property, and add that to the propertyfile.
For example, if I have a property file Test.properties containing
2018=jan;feb;mar
2019=jan;feb;mar
2020=jan;feb;mar
********************************
name=john,math,sudha
my input property is "2020" and output is "2021", after running Ant Test.properties should contain
2018=jan;feb;mar
2019=jan;feb;mar
2020=jan;feb;mar
2021=jan;feb;mar
********************************
name=john,math,sudha
with out changing the order How could I do that?
You might be able to use something based on the following:
The idea is to read the propertyfile, then use two <propertyset> instances with the <echoproperties> task to update the file.
<property name="prop.file" value="Test.properties" />
<property name="input" value="2020" />
<property name="output" value="2021" />
<property name="pf" value="prefix" />
<property name="input.prop" value="${pf}.${input}" />
<loadproperties srcfile="${prop.file}" prefix="${pf}" />
<echoproperties destfile="${prop.file}">
<propertyset>
<propertyref prefix="${pf}" />
<mapper type="glob" from="${pf}.*" to="*" />
</propertyset>
<propertyset>
<propertyref name="${input.prop}" />
<mapper type="glob" from="${input.prop}*" to="${output}*" />
</propertyset>
</echoproperties>
There's more code there than you might expect: the "prefix" is being used to ensure that the properties loaded from the file don't clash with any in your Ant buildfile as properties are imutable.
The order of the propertysets in the echoproperties task is important, especially if there is already a value for property "2021" in the file that you are updating. Where properties appear in both sets, the value in the last propertyset seen "wins" and is echoed to the output file.
<property name="prop.file" value="test.properties" />
<property name="input" value="2020" />
<property name="output" value="2021" />
<replaceregexp file="${prop.file}"
match="${input}(=)(.*)"
replace="${input}=\2${line.separator}${output}=\2"
flags="gi"
byline="true" />
I am new to wso2 6.4.0. I have to insert excel data to sql so i choose wso2 dss. Using dss records fetching correctly and inserting too but inserting only one record(top one only) remain records getting skipped. I used nested query option also to retrieve as well as insertion.
<query id="readExcelData" useConfig="excelConfig">
<excel>
<workbookname>sheet1</workbookname>
<hasheader>true</hasheader>
<startingrow>2</startingrow>
<maxrowcount>-1</maxrowcount>
<headerrow>1</headerrow>
</excel>
<result element="Products" rowName="Product">
<element column="ID" name="ID" xsdType="xs:string"/>
<element column="Model" name="Model" xsdType="xs:string"/>
<element column="Classification" name="Classification" xsdType="xs:string"/>
<call-query href="insertIntoSql" requiredRoles="">
<with-param name="ID" query-param="ID" />
<with-param name="Model" query-param="Model" />
<with-param name="Classification" query-param="Classification" />
</call-query>
</result>
</query>
<operation name="excelFileProcessing" returnRequestStatus="true">
<call-query href="readExcelData"/>
</operation>
<query id="insertIntoSql" useConfig="sqlConfig">
<sql>insert into dbo.myProductList(ID,Model,Classification) values(:ID,:Model,:Classification)</sql>
<param name="ID" sqlType="STRING" />
<param name="Model" sqlType="STRING" />
<param name="Classification" sqlType="STRING" />
</query>
Once you retrieve records from Excel sheet you are getting sets of records. Therefore you have to write a synapse config to insert each record. For that, you have iterate over the payload of excel sheet's data (for each record) and insert. You can use iterate mediator. For an example you can implement something similar to this.
You can follow,
In the proxy service/ API call the dataservice to get excel sheet's
data.
Iterate over the result set.
In each iteration, create the
payload to insert data to DB and call the dataservice to invoke the
insert data query.
Invoke the proxy service / API.
I have an object in my data class and I want only a specific attribute of this object in the WsDTO class.
Declaration of custom B2BUnitData
<bean class="de.hybris.platform.b2bcommercefacades.company.data.B2BUnitData">
<property name="PointOfServiceData"
type="de.hybris.platform.commercefacades.storelocator.data.PointOfServiceData"/>
</bean>
Declaration of B2bUnitWsDTO
<bean class="de.hybris.platform.b2boccaddon.dto.b2bunit.B2bUnitWsDTO">
<property name="PointOfServiceData" type="PointOfServiceWsDTO" />
</bean>
file : dto-level-mappings-v2-spring.xml
<bean parent="fieldSetLevelMapping" id="b2bunitWsDTOFieldSetLevelMapping">
<property name="dtoClass"
value="de.hybris.platform.b2boccaddon.dto.pricerow.B2bUnitWsDTO"/>
<property name="levelMapping">
<map>
<entry key="FULL" value="PointOfServiceData" />
</map>
</property>
</bean>
this implementation give me all the object pointOfService but I only want the UID attribute in the B2bUnitWsDTO
The only solution I know, will be to create a PointOfServiceUID attribute in the data and map it directly in the b2bunitWsDTOFieldSetLevelMapping bean.
I would know if it's possible to map in the dto-level-mappings-v2-spring.xml only one attribute of my object :
Exemple :
Or if it exist some solution to do that
As you already mentioned, you could change the dto-level-mappings-v2-spring.xml so that for all levels (BASIC, DEFAULT, FULL) only the uid is returned.
<bean parent="fieldSetLevelMapping" id="b2bunitWsDTOFieldSetLevelMapping">
<property name="dtoClass"
value="de.hybris.platform.b2boccaddon.dto.pricerow.B2bUnitWsDTO"/>
<property name="levelMapping">
<map>
<entry key="BASIC" value="PointOfServiceData(uid)" />
<entry key="DEFAULT" value="PointOfServiceData(uid)" />
<entry key="FULL" value="PointOfServiceData(uid)" />
</map>
</property>
</bean>
Beware, the fieldSetLevelMapping beans only define how your response looks like!
If you want to change how a B2BUnitData is mapped to a B2bUnitWsDTO, you have to define a custom field mapper (you can find examples in dto-mappings-v2-spring.xml)
Assuming your B2bUnitWsDTO now only has pointOfServiceUID as property, this may look like this (disclaimer: you need to test this):
<bean id="b2bUnitFieldMapper" parent="fieldMapper">
<property name="sourceClass"
value="de.hybris.platform.b2bcommercefacades.company.data.B2BUnitData"/>
<property name="destClass"
value="com.customer.some.package.B2bUnitWsDTO"/>
<property name="fieldMapping">
<map>
<entry key="PointOfServiceData.uid" value="pointOfServiceUID"/>
</map>
</property>
</bean>
Here is a good documentation entry point regarding Field Mappings and Field Level Definitions:
https://help.hybris.com/1808/hcd/8c404c5886691014a48c88f4a49f9bf3.html
I am new to CXF,I have a requirement to drop few tags from the input XML .so I am using CXF Transform feature ,which should drop the version tag from my input XML ,I am able change but not drop. Kindly let me know how can I achieve it
<bean id="transformFeature" class="org.`enter code here`apache`enter code here`.cxf.feature.StaxTransformFeature">
<property name="inTransformElem`enter code here`ents">
<map>
<entry key="version" value=""/>
</map>
</property>
</bean>
You need to specify the namespace of the element. For example, if the version element has a namespace of http://www.example.org/test, you would need to configure the CXF transformation feature as follows:
<bean id="transformFeature" class="org.apache.cxf.feature.StaxTransformFeature">
<property name="inTransformElements">
<map>
<entry key="{http://www.example.org/test}version value=""/>
</map>
</property>
</bean>
You also need to add the feature to your jaxws:endpoint configuration, if you have not already done so.
<jaxws:endpoint ...>
<jaxws:features>
<ref bean="transformFeature" />
</jaxws:features>
</jaxws:endpoint>
Would anyone be able to advise me on the best way of handling access to multiple Rest web services using Springs RestTemplate?
I know that the RestTemplate object has a message converter reference (MarshallingHttpMessageConverter) which in turn has a reference to an unmarshaller. In my case I am using the Spring Frameworks CastorMarshaller object with associated mapping file.
Normally I could have just added all my mappings to one Castor mapping file. However in my case all the web services are of this format (block below) with the < rows ... /> holding different entities depending on the service called.
<data>
<output>
<dataset>
<row id="" .... />
<row id="" .... />
<row id="" .... />
<row id="" .... />
<row id="" .... />
</dataset>
</output>
<nextUpdate><nextUpdate/>
</data>
The CastorMarshaller is injected into the MessageConverter which itself is injected into the RestTemplate in the application context configuration file.
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller"/>
<property name="unmarshaller" ref="castorMarshaller"/>
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<constructor-arg index="0" value="application"/>
<constructor-arg index="1" value="xml"/>
</bean>
<bean class="org.springframework.http.MediaType">
<constructor-arg index="0" value="text"/>
<constructor-arg index="1" value="xml"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocation" value="classpath:oxm-mapping-worldweather.xml"/>
</bean>
Possible options that I have been thinking about:
1 Create multiple RestTemplates for each Rest service.
2 Create multiple MessageConverters for the different services and change the message converters on the template when accessing a different service.
3 Create multiple CasterMarshaller objects for the different services and update the message converter with the new unmarshaller
What is the best way to approach handling multiple services like this with the same root and sub elements?
Thanks in advance
Sman UK
If specifying multiple mapping files is the issue then below is the solution.
Use mappingLocations property instead of mappingLocation as given below,
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocations">
<list>
<value>classpath:oxm-mapping-worldweather.xml</value>
<value>classpath:sample-mapping.xml</value>
</list>
</property>
</bean>