Role based access control to WSO Message Broker Hierarchical Topic - jms

I've recently started experimenting with a Message exchange between WSO2 ESB's via WSO2's MB for a requirement. Created a JMS sender Proxy Service which concatenates endpoint URL based on SOAP Input (used Header property and defaultEndpoint).
On Message Broker:
Have set up a Hierarchical topic as
Root|
Node1
Node2
With 3 users and their specific roles as Root, Node1, Node2. Requirement is Node 1 should be able to subscribe for both Node 1 and Root, Similarly for Node2, Only Node2 and Root.
The problem is When creating a proxy service subscriber can only set it to subscribe one Node only (Root or Node1 or Node2). Tried setting destination as Root.# but then All Nodes are subscribed (even when Node USer is not set to Subscribe the other based on Role based Topic access). Following is the code for subscriber
enter code here
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="Subscriber_Node2"
transports="jms"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<property name="OUT_ONLY" value="true"/>
<log level="full"/>
<log level="custom" separator="###">
<property name="STATE"
value="**************** RECEIVED AT Node 2 ***************"/>
</log>
<drop/>
</inSequence>
<outSequence/>
<faultSequence>
<log level="custom">
<property name="text" value="An unexpected error occured"/>
<property name="message" expression="get-property('ERROR_MESSAGE')"/>
<property name="code" expression="get-property('ERROR_CODE')"/>
<property name="detail" expression="get-property('ERROR_DETAIL')"/>
<property name="exception" expression="get-property('ERROR_EXCEPTION')"/>
</log>
</faultSequence>
</target>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>application/xml</default>
</rules>
</parameter>
<parameter name="java.naming.factory.initial">
org.wso2.andes.jndi.PropertiesFileInitialContextFactory
</parameter>
<parameter name="transport.jms.ConnectionFactory">
Store2TopicConnectionFactory</parameter>
<parameter name="java.naming.provider.url">
repository/conf/jndi.properties</parameter>
<parameter name="transport.jms.DestinationType">topic</parameter>
<parameter name="transport.jms.Destination">HQ.Store_2</parameter>
<description/>
</proxy>
jndi.properties:
connectionfactory.Node1TopicConnectionFactory = amqp://Node1:Node1#clientID/carbon?
brokerlist='tcp://localhost:5680'
connectionfactory.Node2TopicConnectionFactory = amqp://Node2:Node2#clientID/carbon?
brokerlist='tcp://localhost:5680'
connectionfactory.RootTopicConnectionFactory = amqp://Root1:Root1#clientID/carbon?
brokerlist='tcp://localhost:5680'
topic.Root = Root
topic.Root.Node1 = Root.Node1
topic.Root.Node2 = Root.Node2
Is there a way a Subscriber can subscribe to Multiple Topics in a hierrarchy and its access be controlled by User and Role?

Related

how i can add values to my Adress endpoint in wso2 ESB/EI

i want to add values dynamically to adress endpoint in the proxy in wso2 ESB/EI
<address uri="mqtt:/SampleProxy?mqtt.server.host.name=thingsboard.cloud&mqtt.server.port=1883&mqtt.client.id=esb.test.sender&mqtt.topic.name=v1/devices/me/telemetry&mqtt.subscription.qos=0&mqtt.blocking.sender=true&mqtt.subscription.username=25416990;">
lets say for exemple i want to add "test" at the end of the endpoint how i can do this ?
For a similar problem, but with sending msg to rabbitmq, I created template, where i set exchangeName and routingKey dynamicaly. In the same manner, you can create your own template. You need to create Header named "To" and using XPATH concate interesting address endpoint, and for dynamic values you just use $func:{parameter name}
Something like below:
<?xml version="1.0" encoding="UTF-8"?>
<template xmlns="http://ws.apache.org/ns/synapse" name="rabbitmq.sender">
<parameter name="exchangeName"/>
<parameter name="routingKey"/>
<sequence>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"/>
<header name="To"
scope="default"
expression="concat('rabbitmq:/?rabbitmq.connection.factory=CachedRabbitMQConnectionFactory&rabbitmq.exchange.name=',$func:exchangeName,'&rabbitmq.queue.routing.key=',$func:routingKey)"/>
<send/>
</sequence>
</template>
To use that, call-template mediator is needed. In brackets you can put expression, like below:
<call-template target="send.rabbitmq">
<with-param name="exchangeName" value="test"/>
<with-param name="routingKey" value="{get-property('testValue')}"/>
</call-template>

Error occurred in the mediation of the class mediator WSO2 ESB

I used wso2 esb 5.0 for create proxy services. I created proxy service using class mediator. Below is the java class.
public class CalculatePaymentAmount extends AbstractMediator {
public boolean mediate(MessageContext messageContext) {
String noOfMonths = messageContext.getEnvelope().getBody().getFirstElement().
getFirstChildWithName(new QName("noOfMonths")).getText();
String InsuranceRate = messageContext.getEnvelope().getBody().getFirstElement().
getFirstChildWithName(new QName("InsuranceRate")).getText();
DecimalFormat decimalFormat = new DecimalFormat("#.##");
double totalAmount = Double.parseDouble(noOfMonths) * Double.parseDouble(InsuranceRate);
messageContext.setProperty("noOfMonths", noOfMonths);
messageContext.setProperty("paymentAmount", decimalFormat.format(totalAmount));
return true;
}
public String getType() {
return null;
}
public void setTraceState(int traceState) {
traceState = 0;
}
public int getTraceState() {
return 0;
}
}
I created the proxy service using class mediator. Below define the proxy code.
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="PaymentAmountProxy"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="http,https">
<target>
<inSequence>
<log/>
<class name="com.mediator.java.CalculatePaymentAmount"/>
<property expression="get-property('default','noOfMonths')"
name="getNoOfMonths"
scope="default"
type="STRING"/>
<property expression="get-property('default','paymentAmount')"
name="getPaymentAmount"
scope="default"
type="STRING"/>
<log>
<property expression="get-property('default','getNoOfMonths')"
name="No.Of Months:"/>
<property expression="get-property('default','getPaymentAmount')"
name="Paymrent Amount:"/>
</log>
</inSequence>
</target>
<description/>
</proxy>
This one working fine and gave expected response.
But when I use this class mediator with other mediators, it getting errors when I invoked the proxy service.
Below mentioned the proxy service that I used with class mediator.
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="LatestLicenseRenewalSystem"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="http,https">
<target>
<inSequence>
<log/>
<property expression="get-property('transport','VehicleNo')"
name="vehicleNo"
scope="default"
type="STRING"/>
<log>
<property expression="get-property('default','vehicleNo')" name="VehicleNo"/>
</log>
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:sam="http://sample.esb.org">
<soapenv:Header/>
<soapenv:Body>
<sam:getPolicyID>
<sam:vehicleNumber>$1</sam:vehicleNumber>
</sam:getPolicyID>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg evaluator="xml" expression="get-property('default','vehicleNo')"/>
</args>
</payloadFactory>
<log level="full"/>
<header name="Action" scope="default" value="urn:getCertificateID"/>
<call>
<endpoint>
<address format="soap12"
uri="http://172.17.0.1:9763/services/EmissionTestService.EmissionTestServiceHttpSoap12Endpoint/">
<enableAddressing/>
</address>
</endpoint>
</call>
<log level="full"/>
<property xmlns:ns="http://sample.esb.org"
expression="//ns:getCertificateIDResponse/ns:return"
name="certificateID"
scope="default"
type="STRING"/>
<log>
<property expression="get-property('default','certificateID')"
name="CertificateID"/>
</log>
<class name="com.mediator.java.CalculatePaymentAmount"/>
<property expression="get-property('default','noOfMonths')"
name="getNoOfMonths"
scope="default"
type="STRING"/>
<property expression="get-property('default','paymentAmount')"
name="getPaymentAmount"
scope="default"
type="STRING"/>
<log>
<property expression="get-property('default','getNoOfMonths')"
name="No.Of Months:"/>
<property expression="get-property('default','getPaymentAmount')"
name="Paymrent Amount:"/>
</log>
<respond/>
</inSequence>
</target>
<description/>
</proxy>
Below error is occurred when invoking the above proxy service.
LogMediator To: http://www.w3.org/2005/08/addressing/anonymous, WSAction: urn:getCertificateIDResponse, SOAPAction: urn:getCertificateIDResponse, ReplyTo: http://www.w3.org/2005/08/addressing/anonymous, MessageID: urn:uuid:6f4557eb-b8ff-4c19-bbe8-4c7e929d8386, Direction: request, MESSAGE = Executing default 'fault' sequence, ERROR_CODE = 0, ERROR_MESSAGE = Error occured in the mediation of the class mediator, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>urn:getCertificateIDResponse</wsa:Action><wsa:RelatesTo>urn:uuid:6f4557eb-b8ff-4c19-bbe8-4c7e929d8386</wsa:RelatesTo></soapenv:Header><soapenv:Body><ns:getCertificateIDResponse xmlns:ns="http://sample.esb.org"><ns:return>-1250719063</ns:return></ns:getCertificateIDResponse></soapenv:Body></soapenv:Envelope>
Can anyone help me to solve this. Any help or workarounds are really appreciated.
Your class mediator is accessing the elements 'noOfMonths' and 'InsuranceRate' from the message context. But according to the error log, the message context is having a different soap envelope which does not have the above elements.
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>urn:getCertificateIDResponse</wsa:Action><wsa:RelatesTo>urn:uuid:6f4557eb-b8ff-4c19-bbe8-4c7e929d8386</wsa:RelatesTo></soapenv:Header><soapenv:Body><ns:getCertificateIDResponse xmlns:ns="http://sample.esb.org"><ns:return>-1250719063</ns:return></ns:getCertificateIDResponse></soapenv:Body></soapenv:Envelope>
This must me the response received from the call operation before the class mediator.
You have to either isolate the class mediator from the call operation and use different proxy services or move the class mediator above the payload factory.
For solve this issue, use payloadFactory mediator before the class mediator and set the parameters for the payload. I mentioned below the code.
<payloadFactory media-type="xml">
<format>
<paymentDetails xmlns="">
<noOfMonths>$1</noOfMonths>
<InsuranceRate>$2</InsuranceRate>
</paymentDetails>
</format>
<args>
<arg evaluator="xml" expression="get-property('default','noOfMonths')"/>
<arg evaluator="xml" expression="get-property('default','InsuranceRate')"/>
</args>
</payloadFactory>
<class name="com.mediator.java.CalculatePaymentAmount"/>

Search a user in multiple systems through WSO2 ESB proxy

I need to send just one request (can be a proxy url) which takes user id as input and call multiple endpoints and return the response after aggregating all of them.
Currently I am using a proxy service implementation to achieve it but is returns just one response(can be from any of the endpoints) and not able to combine responses from other systems/endpoints. Though I can see the response from another endpoint in my server console.
Below is the code I implemented so far:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="ProxyTestTwoW"
transports="http,https"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<log/>
<clone>
<target>
<sequence>
<property name="Application" value="Application1"/>
<property name="messageType"
value="application/xacml+json"
scope="axis2"
type="STRING"/>
<property name="Authorization"
expression="fn:concat('Basic ', base64Encode('username:password'))"
scope="transport"/>
<send>
<endpoint>
<address uri="localhost:8080/iiq/rest/identities/9000070"/>
</endpoint>
</send>
</sequence>
</target>
<target>
<sequence>
<property name="Application" value="Application2"/>
<property name="messageType"
value="application/xacml+json"
scope="axis2"
type="STRING"/>
<property name="Authorization"
expression="fn:concat('Basic ', base64Encode('username:password'))"
scope="transport"/>
<send>
<endpoint>
<address uri="http://localhost:8080/iiq/rest/identities/9000071"/>
</endpoint>
</send>
</sequence>
</target>
</clone>
</inSequence>
<outSequence>
<log level="full" description="">
<property name="Component" expression="get-property('Application')"/>
</log>
<aggregate>
<completeCondition>
<messageCount min="2"/>
</completeCondition>
<onComplete expression="$body/*[1]">
<property name="messageType"
value="application/xacml+json"
scope="axis2"
type="STRING"
description="messageType"/>
<send/>
</onComplete>
</aggregate>
</outSequence>
<faultSequence>
<log level="full" category="WARN"/>
</faultSequence>
</target>
<description/>
</proxy>
Result :
After hitting proxy URL in browser: - Only one response as below:
<jsonObject><viewableIdentityAttributes><Email>Kevin.Mollo#companyb.com</Email><cn>Kevin Mollo</cn><Last Name>Mollo</Last Name><First Name>Kevin</First Name></viewableIdentityAttributes><listAttributes>First Name</listAttributes><listAttributes>Last Name</listAttributes><listAttributes>Email</listAttributes><listAttributes>cn</listAttributes></jsonObject>
In server logs:
[2016-07-14 11:46:35,057] INFO - LogMediator To: http://www.w3.org/2005/08/addr
essing/anonymous, WSAction: , SOAPAction: , MessageID: urn:uuid:3beaaf16-7b94-4e
08-a3e0-7605869572c7, Direction: response, Component = Application1, Payload: {"vi
ewableIdentityAttributes":{"Email":"Kevin.Mollo#companyb.com","cn":"Kevin Mollo"
,"Last Name":"Mollo","First Name":"Kevin"},"assignedRoles":[],"listAttributes":[
"First Name","Last Name","Email","cn"]}
[2016-07-14 11:46:35,057] INFO - LogMediator To: http://www.w3.org/2005/08/addr
essing/anonymous, WSAction: , SOAPAction: , MessageID: urn:uuid:c878c7db-ad4c-49
46-94d6-75aebc75ad8e, Direction: response, Component = Application1, Payload: {"vi
ewableIdentityAttributes":{"Email":"Michelle.Lassauze#companyb.com","cn":"Michel
le Lassauze","Last Name":"Lassauze","First Name":"Michelle"},"assignedRoles":[],
"listAttributes":["First Name","Last Name","Email","cn"]}
As we can see I get responses from both the endpoints in server logs.
As per analysis, I feel to make it work properly and get the responses from both the endpoints, we need change the following:
1. Using call mediator instead of send if we have multiple endpoints to be called.
2. Using enrich mediator to store the responses.
I tried following the above approaches but I am unable to get the expected results as I am not sure how to use enrich mediator in this case.
Please help me in fixing the above issues.
Clone mediator will be used to send identical copies of message to different endpoints.
Iterate mediator will be used to send message chunks of one particular message to different endpoints.
Enrich mediator will be used to change message (Ex: removing content, adding etc.) [1]
Check your endpoints and check whether they provide proper responses to work with aggregate mediator.
I add sample scenario here. You can test that with your ESB pack to understand the above three mediators usage. You just have to start 2 instances of SimpleStockQuote service [2] and publish message to proxy via SOAPUI.
<proxy name="ScatterGatherProxy" startOnLoad="true" trace="disable" transports="https http">
<description/>
<target>
<inSequence>
<clone>
<target>
<sequence>
<send>
<endpoint name="vendorA">
<address uri="http://localhost:9001/services/SimpleStockQuoteService/"/>
</endpoint>
</send>
</sequence>
</target>
<target>
<sequence>
<send>
<endpoint name="vendorB">
<address uri="http://localhost:9002/services/SimpleStockQuoteService/"/>
</endpoint>
</send>
</sequence>
</target>
</clone>
</inSequence>
<outSequence>
<log level="full"/>
<aggregate>
<completeCondition>
<messageCount min="2"/>
</completeCondition>
<onComplete expression="//m0:return"
xmlns:m0="http://services.samples" xmlns:m1="http://services.samples/xsd">
<enrich>
<source clone="true" xpath="//m0:return[not(preceding-sibling::m0:return/m1:last <= m1:last) and not(following-sibling::m0:return/m1:last < m1:last)]"/>
<target type="body"/>
</enrich>
<send/>
</onComplete>
</aggregate>
</outSequence>
</target>
</proxy>
If you need further assistance, please attach more details like responses of your service.
[1] http://dilshanilive.blogspot.com/2016/03/enrich-mediator-wso2-esb.html
[2] https://docs.wso2.com/display/ESB490/Setting+Up+the+ESB+Samples#Starting%20the%20Axis2%20server

Switching OutSequence in WSO2 ESB Proxy Service based oh SOAP response

I deployed a proxy service in WSO2 ESB for dataset retrieving from a SOAP WS, and i have an OutSequence based on a sequence calling a template.
I have to channel various WS response based on the different request routing them on different files written by the vfs transport.
Actual sequence is the following:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="seq_prova_con_template">
<call-template target="file">
<with-param name="filename" value="IstatAllDataflow-template.xml"></with-param>
</call-template>
</sequence>
I think about a switch-case mediator but i'd like to understand how "catch" the information for choosing the right case. In the example:
`<switch source="//m0:getQuote/m0:request/m0:symbol" xmlns:m0="http://services.samples/xsd">
<case regex="IBM">
<!-- the property mediator sets a local property on the *current* message -->
<property name="symbol" value="Great stock - IBM"/>
</case>
<case regex="MSFT">
<property name="symbol" value="Are you sure? - MSFT"/>
</case>
<default>
<!-- it is possible to assign the result of an XPath or JSON Path expression as well -->
<property name="symbol"
expression="fn:concat('Normal Stock - ', //m0:getQuote/m0:request/m0:symbol)"
xmlns:m0="http://services.samples/xsd"/>
</default>
`
i ask myself how to set the source param of the switch case, and i'd like to know if someone has already implemented a solution like this in order to use a single proxy service for differentiate various answer from the WS.
My sequence is the following:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="seq_template_switch">
<switch xmlns:ns="http://org.apache.synapse/xsd" xmlns:m0="http://services.samples" source="??????">
<case regex="QueryStructure">
<call-template target="file">
<with-param name="filename" value="IstatAllDataflow-template.xml"></with-param>
</call-template>
</case>
<case regex="GetCompactData">
<call-template target="file">
<with-param name="filename" value="GetCompactData-template.xml"></with-param>
</call-template>
</case>
</switch>
</sequence>
I need to catch the choice for the switch case from che method inside the request of my request message, in order to write a certain file when i ask for a kind of answer, and another file with a different name when i ask for another kind of answer.
[EDIT] Log file has this:
TID: [0] [ESB] [2015-09-18 10:33:09,125] INFO {org.apache.synapse.mediators.builtin.LogMediator} - To: http://www.w3.org/2005/08/addressing/anonymous, WSAction: , SOAPAction: , MessageID: urn:uuid:7cc540d3-2893-4b0e-8a24-ab4538236d45, Direction: response, Envelope: <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><QueryStructureResponse xmlns="http://ec.europa.eu/eurostat/sri/service/2.0"><QueryStructureResult><RegistryInterface xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message"><Header><ID>IT1001</ID><Test>true</Test><Name xml:lang="en">ISTAT_JD_237</Name><Prepared>2001-03-11T15:30:47+01:00</Prepared><Sender id="ISTAT"><Name xml:lang="en">Italian Statistical Institute</Name><Contact>
It would be useful making the choice of switch/case mediator about the tag <QueryStructureResponse>. Instead of this tag i could have<GetCompactData> , for example. I'd like to create a switch/case mediator that is driven by the presence of one of this two tags. This would be a good beginning for understanding how to use XPath location and using a single sequence for differentiating SOAP answers in different file by vfs transport.The choice of the file to write in would be taken by the kind of answer from the WS.
Below should work for you. It is checking if QueryStructureResponse exists in SOAP xml or not. If available then it will call IstatAllDataflow-template.xml template otherwise it will invoke GetCompactData-template.xml template.
<switch source="boolean($body//*[local-name() = 'QueryStructureResponse'])">
<case regex="true">
<call-template target="file">
<with-param name="filename" value="IstatAllDataflow-template.xml"></with-param>
</call-template>
</case>
<case regex="false">
<call-template target="file">
<with-param name="filename" value="GetCompactData-template.xml"></with-param>
</call-template>
</case>
</switch>
Another solution using filter in WSO2 esb.
<filter source="boolean($body//*[local-name() = 'QueryStructureResponse'])" regex="true">
<then>
<log>
<property name="======================== TRUE =========================" value="true"/>
</log>
<call-template target="file">
<with-param name="filename" value="IstatAllDataflow-template.xml"/>
</call-template>
</then>
<else>
<log>
<property name="==================== FALSE =========================" value="false"/>
</log>
<call-template target="file">
<with-param name="filename" value="GetCompactData-template.xml"/>
</call-template>
</else>
</filter>

How We Can Break a String in Wso2esb using Xpath

I wish to break a string in wso2esb using xpath
my input like this
<property name="Message" value="assetname:ups,assetcode:452chi,assetid:548935,assetvalue:215" scope="default"/>
i need break in same property using xpath
i need like this
assetname:ups
assetcode=452chi
assetid=54895
assetvalue=215
for this i tried with tokenize function but wso2esb showing errors
my configure file
<proxy xmlns="http://ws.apache.org/ns/synapse" name="Xpathcheck" transports="https,http" statistics="disable" trace="disable" startOnLoad="true">
<target>
<inSequence>
<property name="max" value="1" scope="default" type="STRING"/>
<property name="min" value="1" scope="default" type="STRING"/>
<property name="MessageText" expression="fn:concat('Assetid:',get-property('min'),',','Assetname:',get-property('max'))" scope="default" type="STRING"/>
<property name="Tokenize" expression="fn:tokenize(get-property('Messagetext'),',')" scope="default" type="STRING"/>
<log>
<property name="MessageText" expression="get-property('MessageText')"/>
<property name="Tokenize" expression="get-property('Tokenize')"/>
</log>
</inSequence>
<outSequence/>
</target>
<description></description>
</proxy>
But its throwing errors like this u have any idea for this i need store this in Db table as a one field which look like separate lines
error is
ERROR - SynapseXPath Evaluation of the XPath expression fn:tokenize(get-property('Messagetext'),',') resulted in an error
org.jaxen.UnresolvableException: No Such Function tokenize
tokenize is a function comes with XPath 2.0. To enable XPath 2.0 functions uncomment the following entry in the synapse.properties file which is located at $ESB_HOME/repository/conf directory
synapse.xpath.dom.failover.enabled=true
then you have to specify the mediator as follows,
<property name="Message" value="a,b,c,d,e" scope="default"/>
<property xmlns:fn="http://www.w3.org/2005/xpath-functions" name="Tokenize" expression="fn:tokenize(syn:get-property('Message'),',')" scope="default" type="STRING"/>
I dont think this can be done through XPath, XPath is to navigate elements in an XML. You can do this by using a script mediator and write a JS to break the property values.
use the following to access the ESB params from the script mediator
<script language="js"> var test_param = mc.getProperty('Message')
Use the following to retrieve the params within the script mediator back to the ESB
mc.setProperty("param1",var1)
mc.setProperty("param2",var2)
Use the javascript to carry out the required string manupulations

Resources