WSO2 Update SQL Query with optional parameters - wso2

I'm writing a sql update query. I have tried to do it both in DbReport and in DataService.
The table has 5 fields (the id + 4 more) and if I only want to update the first parameter, the others will set to null in database.
Example:
Url --> http://localhost/myservice?id=xxx
Body ( only sent "param_1" value:
{
"body":{
"PARAM_1": 1670217
}
}
DataService
<operation name="updateRecargasById">
<call-query href="updateRecargasById">
<with-param name="PARAM_1" query-param="PARAM_1" />
<with-param name="PARAM_2" query-param="PARAM_2" />
<with-param name="PARAM_3" query-param="PARAM_3" />
<with-param name="PARAM_4" query-param="PARAM_4" />
<with-param name="ID" query-param="ID" />
</call-query>
</operation>
<query id="updateQuery" useConfig="configDS">
<sql>UPDATE TABLE SET PARAM_1 = :PARAM_1, PARAM_2= :PARAM_2, PARAM_3= :PARAM_3, PARAM_4= :PARAM_4 WHERE ID</sql>
<param name="PARAM_1" ordinal="1" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="PARAM_2" ordinal="2" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="PARAM_3" ordinal="3" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="PARAM_4" ordinal="4" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="ID" ordinal="5" paramType="SCALAR" sqlType="STRING" type="IN" />
</query>
Sequence
<dataServiceCall serviceName="updateDS">
<operations type="single">
<operation name="updateQuery">
<param evaluator="xml" expression="$body//PARAM_1" name="PARAM_1"/>
<param evaluator="xml" expression="$body//PARAM_2" name="PARAM_2"/>
<param evaluator="xml" expression="$body//PARAM_3" name="PARAM_3"/>
<param evaluator="xml" expression="$body//PARAM_4" name="PARAM_4"/>
<param evaluator="xml" expression="get-property('uri.var.id')" name="ID"/>
</operation>
</operations>
<source type="inline"/>
<target type="body"/>
</dataServiceCall>
Is there any way to write this query to set only the fields setting in the request body?
Kind regards!!
......................

Related

WSO2 MI Validators and Array query parameters for a Data Service

I don't know how to create a validator for 2 variables:
Q1. An user code that needs to be checked if exists prior to running the SQL query. I have an endpoint to check if the user code exists or not, how do I make it into a validator?
Q2. An array of dates, the best I could do was to use a pattern validator. I know there's also the possibility to set a parameter with paramType="array" and sqlType="date", but how can I configure this in the query parameters of the resource?
Please check the Data Service definition below:
<data name="APIDataService" serviceNamespace="" serviceGroup="" transports="http https local">
<description />
<config id="postgresDataService">
<property name="carbon_datasource_name">APIPostgres</property>
</config>
<!-- TODO: Q1. Here is the resource I want to use to validate the user code -->
<query id="validateUserCode" useConfig="postgresDataService">
<sql>
SELECT ( EXISTS ( SELECT 1
FROM user
WHERE code ILIKE :user_code ) )::INT AS does_user_exist
</sql>
<param name="user_code" sqlType="string" />
<result element="result">
<element column="does_user_exist" name="doesUserExist" xsdType="integer" />
</result>
</query>
<resource method="GET" path="validateUserCode">
<call-query href="validateUserCode">
<with-param name="user_code" query-param="user_code" />
</call-query>
</resource>
<query id="apiReportUserTotalEventsByDay" useConfig="postgresDataService">
<sql>
SELECT
calendar_date,
record_date,
user_code,
event_type_id,
event_count
FROM user_event
WHERE 1=1
AND calendar_date BETWEEN :calendar_date_start AND :calendar_date_end
AND record_date = ANY( ('{'||:record_date_array||'}')::DATE[] )
AND user_code = :user_code
</sql>
<!-- TODO: Q1. Here is the user code I want to validate -->
<param name="user_code" paramType="scalar" sqlType="string" />
<param name="calendar_date_start" paramType="scalar" sqlType="date" />
<param name="calendar_date_end" paramType="scalar" sqlType="date" />
<!-- TODO: Q2. Here is the array of date that I want to know
how I could convert into an paramType="array" sqlType="date" -->
<param name="record_date_array" paramType="scalar" sqlType="string" >
<validatePattern pattern="\s*\d{4}-\d{2}-\d{2}\s*(,\s*\d{4}-\d{2}-\d{2}\s*)*" />
</param>
<result element="result">
<element column="calendar_date" name="calendar_date" xsdType="string" />
<element column="record_date" name="record_date" xsdType="string" />
<element column="user_code" name="user_code" xsdType="string" />
<element column="event_type_id" name="event_type_id" xsdType="integer" />
<element column="event_count" name="event_count" xsdType="integer" />
</result>
</query>
<resource method="GET" path="apiReportUserTotalEventsByDay">
<call-query href="apiReportUserTotalEventsByDay">
<with-param name="user_code" query-param="user_code" />
<with-param name="calendar_date_start" query-param="calendar_date_start" />
<with-param name="calendar_date_end" query-param="calendar_date_end" />
<with-param name="record_date_array" query-param="record_date_array" />
</call-query>
</resource>
</data>

In modelglue event use different view files based on conditions/results

Following is a event handler used in a xml file in config folder.
<event-handler name="survey.completioninf">
<broadcasts>
<message name="checkLogin">
<argument name="role" value="suadmin,manager" />
</message>
<message name="getPrograms" />
</broadcasts>
<results>
<result name="NotLoggedIn" do="user.login" redirect="true" />
<result name="NotAuthorized" do="user.notauthorized" redirect="true" />
<result do="view.template" />
</results>
<views>
<include name="body" template="survey/completioninf.cfm" />
</views>
</event-handler>
Is there any way I can include a different view file based on a result value or attribute?
I need to keep the event name consistent.
You can create a new result for each include you need (based on result value or attribute). If you set redirect="false" then it will stay under your survey.completioninf event name. Basically this event becomes a filter and redirects to the appropriate include silently.
<event-handler name="survey.completioninf">
<broadcasts>
<message name="checkLogin">
<argument name="role" value="suadmin,manager" />
</message>
<message name="getPrograms" />
</broadcasts>
<results>
<result name="NotLoggedIn" do="user.login" redirect="true" />
<result name="NotAuthorized" do="user.notauthorized" redirect="true" />
<!-- Add your new results here and redirect to the desired events -->
<result name="SurveyIsNotComplete" do="survey.ContinueSurvey" redirect="false">
<result name="SurveyIsComplete" do="survey.CompletedSurvey" redirect="false">
</results>
</event-handler>
<!-- You will need to create new events to handle these results -->
<event-handler name="survey.CompletedSurvey">
<broadcasts>
<message name="checkLogin">
<argument name="role" value="suadmin,manager" />
</message>
<message name="getPrograms" />
</broadcasts>
<results>
<result name="NotLoggedIn" do="user.login" redirect="true" />
<result name="NotAuthorized" do="user.notauthorized" redirect="true" />
<result do="view.template" />
</results>
<views>
<include name="body" template="survey/completioninf.cfm" />
</views>
</event-handler>
<event-handler name="survey.ContinueSurvey">
<broadcasts>
<message name="checkLogin">
<argument name="role" value="suadmin,manager" />
</message>
<message name="getPrograms" />
</broadcasts>
<results>
<result name="NotLoggedIn" do="user.login" redirect="true" />
<result name="NotAuthorized" do="user.notauthorized" redirect="true" />
<result do="view.template" />
</results>
<views>
<include name="body" template="survey/continueSurvey.cfm" />
</views>
</event-handler>

Need to create WSO2 DSS service which can read parameter from url

I have created a simple dss service which by inputing cust_id it gives me the customer data.
I have exposed this webservice as http get resource with the following url
GET /services/getCustDetailDSS/getDetail?cid=101
Corrsponding xml code for my service is as follows
<data name="getCustomerDetailDSS" serviceGroup="" serviceNamespace="">
<description/>
<config id="mydb">
<property name="carbon_datasource_name">mydb</property>
</config>
<query id="get_customer_detail" useConfig="mydb">
<sql>select identifier,user_status from customer_detail where identifier = :cid</sql>
<param name="cid" paramType="SCALAR" sqlType="STRING"/>
<result element="customer">
<element column="identifier" name="cid" xsdType="xs:string"/>
<element column="user_status" name="status" xsdType="xs:string"/>
</result>
</query>
<operation name="get_customer_detail_operation">
<call-query href="get_customer_detail">
<with-param name="cid" query-param="identifier"/>
</call-query>
</operation>
<resource method="GET" path="/getDetail">
<call-query href="get_customer_detail">
<with-param name="cid" query-param="cid"/>
</call-query>
</resource>
</data>
But now i want the dss service to read cust_id from url instead of passing it as a parameter.
i.e i want to hit dss service as
GET /services/getCustDetailDSS/cid/101/getDetail
How can i do this in DSS ?
Can anyone provide wat changes i need to do in my dss?
For GET /services/getCustDetailDSS/getDetail/cid/101
You have to edit your resource path as follows.
<resource method="GET" path="getDetail/cid/{cid}">
With WSO2 DSS 3.2.1, you can now define your query string parameter as below:
<param name="cid" sqlType="QUERY_STRING"/>
instead of:
<param name="cid" paramType="SCALAR" sqlType="STRING"/>
and your URL should look like:
.../getDetail?cid=101

wso2 dss mysql error

I am getting this error while I am trying to test the data service on the wso2 dss
DS Fault Message: Error in
'SQLQuery.processStoredProcQuery'DS Code: DATABASE_ERRORSource Data
Service:-Name: CustomerDSLocation: \CustomerDS-1.0.0.dbsDescription:
N/ADefault Namespace: http://ws.wso2.org/dataserviceCurrent Request
Name: op1Current Params: {Name=?, NID=?}Nested Exception:-DS Fault
Message: Error in 'createProcessedPreparedStatement'DS Code:
UNKNOWN_ERRORNested Exception:-java.sql.SQLException: Parameter index
of 3 is out of range (1, 0)
any suggestions?
edited: The bds file is as follows, this is a sample case mentioned in the wso2 documentation.
<data name="CustomerDS">
<config id="default">
<property name="org.wso2.ws.dataservice.driver">com.mysql.jdbc.Driver</property>
<property name="org.wso2.ws.dataservice.protocol">jdbc:mysql://localhost:3306/CustomersDatabase</property>
<property name="org.wso2.ws.dataservice.user">root</property>
<property name="org.wso2.ws.dataservice.password">root</property>
</config>
<query id="q1" useConfig="default">
<sql>call getCustomer(?,?,?,?)</sql>
<result element="Entries" rowName="Entry">
<element name="Flag" column="Flag" xsdType="xs:integer" optional="true" />
<element name="Customer" column="Customer" xsdType="xs:string" optional="true" />
</result>
<param name="NID" sqlType="STRING" ordinal="1" />
<param name="Name" sqlType="STRING" ordinal="2" />
<param name="Flag" sqlType="INTEGER" type="OUT" ordinal="3" />
<param name="Customer" sqlType="STRING" type="OUT" ordinal="4" />
</query>
<operation name="op1">
<call-query href="q1">
<with-param name="NID" query-param="NID" />
<with-param name="Name" query-param="Name" />
</call-query>
</operation>
</data>
WHAT WORKED FOR ME!!
I found the reference code at http://svn.wso2.org/repos/wso2/people/kasun/wso2con_2013/starbucks_2.0/dss/StarbucksDataService.dbs
and the procedure call that is finally working for me is (which changes in procedure itself)
<data name="CustomerDS">
<config id="default">
<property name="org.wso2.ws.dataservice.driver">com.mysql.jdbc.Driver</property>
<property name="org.wso2.ws.dataservice.protocol">jdbc:mysql://localhost:3306/CustomersDatabase</property>
<property name="org.wso2.ws.dataservice.user">root</property>
<property name="org.wso2.ws.dataservice.password">root</property>
</config>
<query id="q1" useConfig="default">
<sql>call getCustomer(?,?)</sql>
<result element="Entries" rowName="Entry">
<element name="Flag" column="Flag" xsdType="xs:integer" optional="true" />
<element name="Customer" column="Customer" xsdType="xs:string" optional="true" />
</result>
<param name="NID" sqlType="STRING" ordinal="1" />
<param name="Name" sqlType="STRING" ordinal="2" />
<param name="Flag" sqlType="INTEGER" type="OUT" ordinal="3" />
<param name="Customer" sqlType="STRING" type="OUT" ordinal="4" />
</query>
<operation name="op1">
<call-query href="q1">
<with-param name="NID" query-param="NID" />
<with-param name="Name" query-param="Name" />
</call-query>
</operation>
</data>
And the tentative working procedure call for now is :
DELIMITER //
CREATE procedure getCustomer(NID varchar(200),Name varchar(200))
BEGIN
DECLARE id varchar(200);
DECLARE flag int;
SET Flag = 0;
SET id = CONCAT(NID, '_' , Name);
INSERT INTO Customer(NID, Name, customerID) VALUES(NID, Name, id);
select flag, customerid from customer where customerID = id;
END//
In the query q1 call getCustomer(?,?,?,?) takes 4 arguments and in the input mapping list there are only 2 input params (IN Only). This must be the reason for the this exception. Please refer this tutorial.

is it possible to have a new file for each new day with log4cXX

I know the rollingPolicy parameter for log4cxx config file, but I can't manage to have the config file which can tell the logger to create a new file each new day, how could I achieve this result ?
Yes. Using rolling style of Composite like this:
<appender name="LogAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4j.Util.PatternString" value="LogFile.log" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<datePattern value="yyyyMMdd" />
<maxSizeRollBackups value="7" />
<maximumFileSize value="100MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{ISO8601}: [%2thread] %-5level %logger: '%P{network}.%P{node}' %message%newline" />
</layout>
</appender>
Ref.:
Short introduction to Apache log4cxx
log4net Config Examples
I think the following appender will do the stuff ( can't test it on this pc )
<!-- the following appender with the name "TimeBasedLog.log", every night a few seconds after
12::00PM the old log will be renamed with append the date in filename, and a new log file
with the name "TimeBasedLog.log" will be create.
notice the RollingFileAppender is under "org.apache.log4j.rolling" namespace
-->
<appender name="MyRollingAppenderDaily" class="org.apache.log4j.rolling.RollingFileAppender">
<rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
<param name="FileNamePattern" value="TimeBasedLog.%d{yyyy-MM-dd}.log"/>
<param name="activeFileName" value="TimeBasedLog.log"/>
</rollingPolicy>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %x [%p] (%F:%L) %m%n"/>
</layout>
<param name="file" value="TimeBasedLog.log"/>
<param name="append" value="true"/>
</appender>
I am wondering if it is possible to combine inside an appender both timebasedrollingpolicy and MaxFileSize/MaxBackupIndex feature ?
<param name="MaxFileSize" value="5KB"/>
<param name="MaxBackupIndex" value="5"/>