Showing posts with label Tutorial/Guide. Show all posts
Showing posts with label Tutorial/Guide. Show all posts

Friday, January 08, 2010

WSF/PHP Code First Approach: Returning an Array of String

Here is a problem that many people have asked me how to do it. "Returning an array of string" with the code first approach. The API or WSDL generation annotation guide, http://wso2.org/project/wsf/php/2.0.0/docs/wsdl_generation_api.html contain all the things required in details. Here is an example of a service that return an array of string.
<?php

/** splitMe function
* @param string $string_to_split string to split
* (maps to the xs:string XML schema type )
* @return array of string $result split to array
*(maps to the xs:double XML schema type )
*/

function splitMe($string_to_split)
{
return array("result" => split(":", $string_to_split));

}

$operations = array("splitMe"=>"splitMe");
$opParams = array("splitMe"=>"MIXED");

$svr = new WSService(array("operations"=>$operations,
"bindingStyle"=>"doclit",
"opParams"=>$opParams));

$svr->reply();
?>

Note that the annotation corresponding to the return value.
 * @return array of spring $result split to array

This will generate an schema with an element of maxOccurs='unbounded'. Note that you can get the wsdl from the 'serviceurl?wsdl'.
<xsd:element name="splitMeResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="result" maxOccurs="unbounded" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

Now just generate a client for this service using wsdl2php and try invoke it. You will get an array of string as the response.
    $input = new splitMe();
$input->string_to_split = "a:b:c:d";

 
// call the operation
$response = $proxy->splitMe($input);
print_r($response);

Thursday, January 07, 2010

Writing Business Rules in WSO2 Carbon Platform

If you want to write rules in a Java program you have lot of choices. You can use a third party library like Drools or use the JAVA built-in JSR-94 reference implementation. In WSO2 Carbon, there is a component that abstract the behaviour of different rule engine and give you a unified API. Currently it has plugged into Drools and JAVA built-in JSR-94 implementation.

The rule component in WSO2 Carbon platform mainly used by WSO2 ESB product to mediate messages according to the given business rules. But the component is written to facilitate any requirement of using business rules in WSO2 Carbon platform. I had such a requirement in past few days and manage to use the rule component easily with the help of the component author, indika@wso2.com. So I thought it is worth sharing my experience in here.

Here You will be preparing the following stuff.

1. Rule configuration -

We can use this to provide the information about the rule implementation we are going to use, the rules (You can write rules inline or provide a reference to an external file) and the input and output adapter information.
<configuration xmlns="http://www.wso2.org/products/rule/drools">
<executionSet uri="simpleItemRuleXML">
<source key="file:src/test/resources/rules/simple-rules.drl"/>

<!-- <source>

<x><![CDATA[
rule InvokeABC
// rules inbuilt to the rule conf
end

]]>
</x>
</source> -->
<creation>
<property name="source" value="drl"/>

</creation>
</executionSet>
<session type="stateless"/>
<input name="facts" type="itemData" key="dataContext"></input>

<output name="results" type="itemData" key="dataContext"></output>
</configuration>



2. The Rules  -

You can write rules inline in the above configuration or put it in a file and refer it from a key which can be refered from the ResourceHelper (described below).
import java.util.Calendar;

rule YearEndDiscount
when
$item : org.test.pojo.SimpleItem(price > 100 )

then

Calendar calendar = Calendar.getInstance();
if (calendar.get(Calendar.MONTH) == Calendar.JANUARY) {

$item.setPrice($item.getPrice() * 80/100);
}

end

3. Data Context -

The context object that can be used to feed and retrieve data from and to rule engine. Here is the data context for my application.
public class SimpleDataContext {

public List<NameValuePair> getInput() {

// in reality the data will be retrieve from a database or some datasource
List<NameValuePair> itemPairList = new ArrayList<NameValuePair>();
SimpleItem item1 = new SimpleItem();
item1.setName("item1");
item1.setPrice(50);
itemPairList.add(new NameValuePair(item1.getName(), item1));

SimpleItem item2 = new SimpleItem();
item2.setName("item2");
item2.setPrice(120);
itemPairList.add(new NameValuePair(item2.getName(), item2));

SimpleItem item3 = new SimpleItem();
item3.setName("item3");
item3.setPrice(130);
itemPairList.add(new NameValuePair(item3.getName(), item3));

return itemPairList;
}

public void setResult(Object result) {

if (!(result instanceof SimpleItem)) {
System.out.println("it is not a SimpleItem");
}

SimpleItem item = (SimpleItem)result;
System.out.println("Item: " + item.getName() + ", Price: " + item.getPrice());
}

}

And the Item I'm going to manipulate using rule is a simple bean like this,
public class SimpleItem {
String name;
int price;
public String getName() {

return name;
}

public void setName(String name) {

this.name = name;
}

public int getPrice() {

return price;
}

public void setPrice(int price) {

this.price = price;
}
}

4. Data Adapter

You have to adapt the input and output with the rule engine. Mostly here you only have to wrap the data context. The advantage of having the data adapter is, a data adapter always associated with a input/output type. So in the rule configuration I can provide the type for the input and output. If you see my rule configuration above, you see the input/output type is marked as "ItemData". Here is my custom data adapter that is associated with the "itemData" type.
public class SimpleDataAdapter implements
ResourceAdapter, InputAdaptable, OutputAdaptable {

// the type associated with the adapter
private final static String TYPE = "itemData";
public String getType() {

return TYPE;
}

public Object adaptInput(ResourceDescription resourceDescription, Object tobeadapted) {

if (!(tobeadapted instanceof SimpleDataContext)) {
return null;
}

SimpleDataContext dataContext = (SimpleDataContext)tobeadapted;
return dataContext.getInput();
}

public boolean adaptOutput(ResourceDescription description,
Object value,
Object context,
ResourceHelper resourceHelper) {

if (!(context instanceof SimpleDataContext)) {
return false;
}

((SimpleDataContext)context).setResult(value);
return true;
}

public boolean canAdapt(ResourceDescription description, Object ouptput) {
String key = description.getKey();
return key != null && !"".equals(key);
}

}

5. Resource Helper

Resource Helper will map the keys refered from the configuration to JAVA objects. This is mostly used in mediation rule configurations which can extract the message data using a key or an xpath. In this example, we don't have much keys refering from the configuration only the rule file and the data context.
public class SimpleResourceHelper extends ResourceHelper {

public ReturnValue findByKey(String key, Object source, Object defaultValue) {

if (!(source instanceof SimpleDataContext)) {
return new ReturnValue(defaultValue);
}

SimpleDataContext dataContext = (SimpleDataContext)source;
if (key.startsWith("file:")) {

String filename = key.substring("file:".length());
try {

BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));
return new ReturnValue(in);
} catch (Exception e) {

return new ReturnValue(defaultValue);
}
}
if (key.startsWith("dataContext")) {

return new ReturnValue(dataContext);
}
return new ReturnValue(defaultValue);
}

// there are few more methods to be implemented, which can just leave not implemented for this example
}
}

That is all the accessories. Now you will be able to write the rule engine execution code.
File ruleConfigFile = new File(ruleConfigFilename);
XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(new FileInputStream(ruleConfigFile));

//create the builder
StAXOMBuilder builder = new StAXOMBuilder(parser);
//get the root element (in this case the envelope)

OMElement ruleConfig = builder.getDocumentElement();
EngineConfiguration configuration =
new EngineConfigurationFactory().create(ruleConfig, new AXIOMXPathFactory());

EngineController
engineController = new EngineController(configuration, new SimpleResourceHelper());
final ResourceAdapterFactory factory = ResourceAdapterFactory.getInstance();

ResourceAdapter adapter = new SimpleDataAdapter();
String adapterType = adapter.getType();
if (!factory.containsResourceAdapter(adapterType)) {

factory.addResourceAdapter(adapter);
}

SimpleDataContext simpleContext = new SimpleDataContext();

if (!engineController.isInitialized()) {
engineController.init(simpleContext);

}

if (engineController.isInitialized()) {
engineController.execute(simpleContext, simpleContext);

}

Wednesday, January 06, 2010

Getting the size of BLOB in MySql

If you want to store binary in database, you can use BLOB as the data type of that column. In Mysql you can use TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB depending on your space requirement. Here is an example of database table using BLOB as a column type.
CREATE TABLE BloBTest (
id INT NOT NULL AUTO_INCREMENT,
filename VARCHAR( 32 ) NOT NULL,
content BLOB NOT NULL,
PRIMARY KEY ( id )
)

Storing Data

PHP:
$filename = "myimage.png";
$filecontent = file_get_contents($filename);
$filecontent_escaped = mysql_real_escape_string($filecontent);

$sql = "INSERT INTO BloBTest(filename, content) " +
"VALUES('$filename','$filecontent_escaped')";
mysql_query($sql, $link);

Java:
String filename = "myimage.png";
InputStream filecontent = new FileInputStream(filename);

String sql = "INSERT INTO BloBTest(filename, content) VALUES(?, ?)";

int size = filecontent.available();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, filename);
ps.setBinaryStream(2, filecontent, size);
ps.executeUpdate();

Retrieving Data

PHP
$sql = "SELECT filename, content FROM BloBTest";
$result = mysql_query($sql, $link);
while ($row = mysql_fetch_assoc($result)) {

$filename = $row["filename"];
$content = $row["content"];
$new_filename = "new_" . $filename;
file_put_contents($new_filename, $content);
}

Java:
String sql = "SELECT filename, content FROM BloBTest";

PrepareStatement ps = conn.prepareStatement(resourceContentSQL);
ResultSet result = ps.executeQuery();

if (result.next()){
String filename = result.getString("filename");
InputStream contentStream = result.getBinaryStream("content");
String newFilename = "new_" + filename;
// storing the input stream in the file

OutputStream out=new FileOutputStream(newFilename);
byte buf[]=new byte[1024];
int len;
while((len=contentStream.read(buf))>0)

out.write(buf,0,len);
out.close();
}

Retrieving the Size of the Blob

After you store your data as a blob, you can manipulate or query the data with some of the in-built String functions in mysql. For an example if you want to query the size of the blob you just stored, you can use OCTET_LENGTH function. Here is an example,  (this will give you the size in bytes.)
SELECT OCTET_LENGTH(content) FROM BloBTest WHERE filename='myimage.png'


.

Tuesday, January 05, 2010

Register Today for WSO2 Governance as a Service

WSO2 Governance as a Service is an online multi-tenant supported instance of WSO2 Governance Registry which is the solution for SOA Governance from the WSO2 SOA stack. You can start trying out WSO2 Governance as a Service by accessing the http://governance.cloud.wso2.com and creating an account for your organization (free for limited use).

In order to identify your account, you have to provide the domain name of your organization. I will demonstrate how to create an account using the "ws.dimuthu.org" as my domain name.

1. First go to http://governance.cloud.wso2.com from a web browser and click the 'Register' button. You will be asked to enter the domain name as the first step.

[caption id="attachment_1036" align="aligncenter" width="773" caption="Enter the domain"]Enter the domain[/caption]

After that, you have the option of validating the ownership of the domain right at the registration process, or you can skip the validation and continue to the next step in which case your domain will be appended '-trial' suffix. You can validate the ownership of the domain later at any stage.

Here I want to validate the domain right now, so I click 'Take me to the domain ownership confirmation page straight-away' and click the 'Submit' button.

2. This will redirect you to the domain ownership validation page. You can validate the ownership of your domain in one of two ways.

Method i). Just create a text file named 'wso2gaas.txt' in the web root of your domain and enter the given text. This is the most simplest method of two.

[caption id="attachment_1039" align="aligncenter" width="722" caption="Validate domain name using Textfile"]Validate domain name using Textfile[/caption]

Method ii). You can put a DNS entry according to the given instructions. This is a little tedious approch to validate the domain. In fact it may take a while to propagate the new DNS information, so you may have to wait hours without refreshing the page until you finally validate the domain ownership.



Click the continue button after the domain validation done. Then you will be redirected to a page requesting more information.

3. Tenant Registration Page

[caption id="attachment_1041" align="aligncenter" width="787" caption="Tenant Registration"]Tenant Registration[/caption]

4) After this step, you will be notified to check for your email which will contain a mail with a link to proceed with the registration. There you will be able to select a theme for your organization and finalize creating your account. Login to the admin account for your tenant with the credential you provided a the time of the registration.

The domain ownership validation was introduced to WSO2 Governance as a Service account registration only now. So for organizations who have already have account will have a message similar to this when they are trying to login to their account.

[caption id="attachment_1046" align="aligncenter" width="460" caption="Info box at login"]Info box at login[/caption]

So the account I have registered using the domain name 'example.com' has been renamed to 'example.com-trial'. As the instruction of the message says you can go to the account management page after the login and validate the domain ownership.

[caption id="attachment_1043" align="aligncenter" width="808" caption="Account Management Page"]Account Management Page[/caption]