Modifying config registry resource content during mediation in WSO2 ESB - wso2

I have a scenario where I need to store simple counter in config registry and increment it at end of sequence flow. Reason we need to store in config registry is in case server get restarted we have last counter value persisted. Can someone suggest how to increment the counter in config registry ?

Sample javascript you can use in your mediation to save current message inside registry :
<script language="js"><![CDATA[
importPackage(Packages.org.apache.synapse.config);
mc.getConfiguration().getRegistry().newResource("gov:/trunk/mypath/MyResource.xml",false);
mc.getConfiguration().getRegistry().updateResource("gov:/trunk/mypath/MyResource.xml",mc.getPayloadXML().toString());
]]></script>
newResource is used the first time to create the resource

I have this solution for you!!
<script language="nashornJs"><![CDATA[
var body = mc.getPayloadXML();
print(body);
var registryPath = "gov:/portales/date.xml";
if(body != null && body != ''){
var existingProperty = mc.getConfiguration().getRegistry().getResource(registryPath);
print(body);
if(existingProperty == null){
print(body);
// Create the registry entry if no such entry exists.
mc.getConfiguration().getRegistry().newResource(registryPath, false);
mc.getConfiguration().getRegistry().updateResource(registryPath, body);
} else {
print(body);
// Update the registry entry if it already exists.
mc.getConfiguration().getRegistry().updateResource(registryPath, body);
}
}]]></script>
the idea was taken from http://wso2-oxygen-tank.10903.n7.nabble.com/How-to-Store-Log-Message-in-a-Registry-File-in-EI-td159169.html

I used this way to get json payload from POST request and stored in the registry on xml format
<datamapper config="gov:datamapper/conversionToSaveInRegistry.dmc" description="conversionToSaveInRegistry" inputSchema="gov:datamapper/conversionToSaveInRegistry_inputSchema.json" inputType="JSON" outputSchema="gov:datamapper/conversionToSaveInRegistry_outputSchema.json" outputType="XML" xsltStyleSheet="gov:datamapper/conversionToSaveInRegistry_xsltStyleSheet.xml"/>
<property name="messageType" scope="axis2" type="STRING" value="application/xml"/>
<script language="nashornJs"><![CDATA[
var body = mc.getPayloadXML();
var registryPath = "gov:/generated/date.xml";
if(body != null && body != ''){
var existingProperty = mc.getConfiguration().getRegistry().getResource(registryPath);
if(existingProperty == null){
// Create the registry entry if no such entry exists.
mc.getConfiguration().getRegistry().newResource(registryPath, false);
mc.getConfiguration().getRegistry().updateResource(registryPath, body);
} else {
// Update the registry entry if it already exists.
mc.getConfiguration().getRegistry().updateResource(registryPath, body);
}
}]]></script>
<property name="NO_ENTITY_BODY" scope="axis2" type="BOOLEAN" value="true"/>
<property name="HTTP_SC" scope="axis2" type="STRING" value="201"/>

Related

Logging is not functioning properly after changing Logging Configuration via managemnt console in WSO2 EI 6.5.0

I have developed API which call the class mediator via sequence in WSO2 EI 6.5.0. Initially API logs are getting printed except class mediator logs in Server log.
To enable logs for class mediator as per this, I logged into management console Home> Configure> Logging section and went to section Configure Log4J Loggers , searched log keyword whatever i added inside class mediator to find out class mediator and changed class level to Debug
post this change, nothing is printed when i invoke service via postman, but API response getting. I just restarted server, post this management console url also not getting printed in server logs.
Below is the management console logging configuration image for reference.
Class Mediator:
package com.abc.in;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.core.axis2.Axis2MessageContext;
/*import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;*/
import java.util.ArrayList;
import java.util.Map;
public class DuplicateHeadersMediator extends AbstractMediator {
// private static final Log logger = LogFactory.getLog(DuplicateHeadersMediator.class);
public boolean mediate(MessageContext messageContext) {
log.info("DuplicateHeadersMediator called********** : " );
trace.info("trace DuplicateHeadersMediator called********** :");
org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) messageContext)
.getAxis2MessageContext();
Map excessHeaders = (Map) axis2MessageContext.getProperty("EXCESS_TRANSPORT_HEADERS");
log.info("excessHeaders : " + excessHeaders.entrySet());
trace.info("trace excessHeaders : " + excessHeaders.entrySet());
Map transportHeaders = (Map) axis2MessageContext.getProperty("TRANSPORT_HEADERS");
log.info("transportHeaders : " + transportHeaders.entrySet());
trace.info("trace transportHeaders : " + transportHeaders.entrySet());
if (excessHeaders.size() != 0 && transportHeaders.size() != 0) {
for (Object key : transportHeaders.keySet()) {
addPropertiesForExcessHeaders((String)key,excessHeaders,messageContext);
}
}
return true;
}
// Add extra properties to the synapse message context for duplicated headers.
private void addPropertiesForExcessHeaders(String headerName, Map excessHeaders, MessageContext messageContext) {
if (excessHeaders.get(headerName) != null) {
ArrayList<String> list = (ArrayList) excessHeaders.get(headerName);
if (list.size() > 0) {
int i = 2;
for (String value : list) {
String propName = headerName + i;
messageContext.setProperty(propName, value);
log.info("propName : " + propName);
trace.info("trace propName : " + propName);
i += 1;
}
}
}
}
}
API:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/readcookiesapi" name="ReadCookiesAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<log level="custom">
<property name="ReadCookiesAPI" value="is called *****"/>
</log>
<sequence key="HeaderMediatorCall_Sequecne"/>
<log level="custom">
<property expression="$trp:test" name="test1"/>
<property expression="$ctx:test2" name="test2"/>
<property expression="$ctx:test3" name="test3"/>
</log>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Sequence:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="HeaderMediatorCall_Sequecne" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<log level="custom">
<property name="HeaderMediatorCall_Sequecne" value="B4 *****"/>
</log>
<class name="com.abc.in.DuplicateHeadersMediator"/>
<log level="custom">
<property name="HeaderMediatorCall_Sequecne" value="after *****"/>
</log>
</sequence>
Kindly clarify my doubts mentioned below.
how can I recover default logging mechanism since this change made product logging weird, so that artifacts like API, Sequence etc and server logs i'll get properly
why class mediator logs are not getting printed initially or how can i get those class mediators log in wso2 ei server 6.5.0
When you extend AbstractMediator you should already have an instance of the logger for you to use. Check here. So you don't have to instantiate a new Logger. You can simply use the existing logger.
I have used java.util.logging.Logger to reflect logger inside class mediator. Still not sure why org.apache.commons.logging.LogFactory not printing anything in log.
import java.util.logging.Logger;
public class ParseEmailBody extends AbstractMediator {
private static final Logger logger = Logger.getLogger(ParseEmailBody.class.getName());
public boolean mediate(MessageContext context) {
logger.info("===Inside ParseEmailBody Class Mediator===");
return true;
}

MS Graph beta/applications OData property 'resourceSpecificApplicationPermissions' does not exist on type 'microsoft.graph.apiApplication'

I'm writing some power query against the Graph API and when I try to pull OData from the applications resource I get the error:
DataSource.Error: OData: The property 'resourceSpecificApplicationPermissions' does not exist on type 'microsoft.graph.apiApplication'. Make sure to only use property names that are defined by the type.
Details:
DataSourceKind=OData
DataSourcePath=https://graph.microsoft.com/beta/applications
Source = OData.Feed(AppsURL,[#"Content-Type"="application/json", Authorization = AccessTokenHeader])
If I do the same but as a REST API request I get the JSON but then I need to take care of paging and transformation.
Source = Json.Document(Web.Contents(AppsURL,
[
Headers = [#"Content-Type"="application/json",
Authorization = AccessTokenHeader
]
]))
If I do the same against https://graph.microsoft.com/beta/servicePrincipals the OData.Feed method works like a charm.
Any possible work around or do I need to wait for the API to be fixed before consuming that resource?
After doing some tracing I found the schema is verified at: https://graph.microsoft.com/beta/$metadata and it is missing one definition.
To original response:
<ComplexType Name="apiApplication">
<Property Name="acceptMappedClaims" Type="Edm.Boolean"/>
<Property Name="knownClientApplications" Type="Collection(Edm.Guid)"/>
<Property Name="preAuthorizedApplications" Type="Collection(microsoft.graph.preAuthorizedApplication)"/>
<Property Name="requestedAccessTokenVersion" Type="Edm.Int32"/>
<Property Name="oauth2PermissionScopes" Type="Collection(microsoft.graph.permissionScope)" Nullable="false" />
</ComplexType>
Is missing:
<Property Name="resourceSpecificApplicationPermissions" Type="Collection(microsoft.graph.resourceSpecificPermission)" Nullable="false"/>
As a workaround I added a rule to Fidller:
if (oSession.HostnameIs("graph.microsoft.com") && oSession.oResponse.headers.ExistsAndContains("Content-Type","application/xml;charset=utf-8") && oSession.PathAndQuery == '/beta/$metadata' ){
oSession.utilDecodeResponse();
oSession.utilReplaceInResponse('<Property Name="oauth2PermissionScopes" Type="Collection(microsoft.graph.permissionScope)" Nullable="false" />','<Property Name="oauth2PermissionScopes" Type="Collection(microsoft.graph.permissionScope)" Nullable="false" /><Property Name="resourceSpecificApplicationPermissions" Type="Collection(microsoft.graph.resourceSpecificPermission)" Nullable="false"/>');
}

How read content of local entry from registry resource

I am using local entry to register the parameters and not to leave fixed in the artifacts, I do not know if it is better solution.
Everything works when I create the local entry in ESB Config, but when I create in the project registry resource I can not read correctly.
I am using code below to read local entry and write to a property:
<Property description = "SetPPSUserName" expression = "get-property ('registry', 'conf: /local-entries/PPS_Username.xml')" name = "SetPPSUserName" scope = "default" type = "STRING" />
Problem, is that it loads the entire xml contents of the local entry and not only the content, example as the property:
SetPPSUserName = "<localEntry key="PPS_Username" xmlns="​http://ws.apache.org/ns/synapse"><![CDATA [content test blablab]]></ localEntry>"
Correct would be:
SetPPSUserName = "content test blablab"
NOTE: When I upload the CAR to the site, the local entry of the project registry resource does not appear in the local entry list of the management console.
Message translated from Portuguese to English with google translator
Try this:
Set type = OM in property instead of STRING.
<Property description = "SetPPSUserName" expression = "get-property ('registry', 'conf: /local-entries/PPS_Username.xml')" name = "SetPPSUserName" scope = "default" type = "OM" />
<log level="custom">
<property name="call_testProp" expression="$ctx:SetPPSUserName" type="STRING"/>
</log>
UPDATE 1:
My localEntry inside registry:
<localEntry key="PPS_Usernamelocal" xmlns="http://ws.apache.org/ns/synapse">
<a>
<b>TEST</b>
</a>
</localEntry>
My property and log mediator inside an esb proxy:
<property name="PPS_Username"
expression="get-property('registry','conf:/localentries/PPS_Username.xml')"
scope="default"
type="OM"/>
<log level="custom">
<property name="PPS_UsernameB" expression="$ctx:PPS_Username//syn:a/syn:b" xmlns:syn="http://ws.apache.org/ns/synapse"/>
</log>
My ESB response:
[2017-02-22 16:21:42,680] INFO - LogMediator PPS_UsernameB = TEST
Not sure if I got it right.
If you want to access a registry resource within a proxy you have to execute the following steps.
1.) create "Registry Resource Project"
2.) add a "Registry Resource" to that project. Because I faced some problems in the past with creating resources directly in dev studio, I always create a test/XML file with the content on my local disk and select "Import from file system" wen creating the resource
3.) create a CAR for the "Registry Resource Project"
4.) Open the pom.xml from the CAR project and change the "Server role" to "EnterpriseServiceBus" otherwise it won't get deployed to the ESB.
5.) Export the CAR and deploy it to the Server
Then you're able to access it inside the Proxy like this.
<property name="registryValue" expression="get-property('registry','gov:/path/property1.txt')"/>
Hope that helps.

How to call web service from javascript file in alfresco 4.2.C

I created execute script rule in alfresco and i kept my javascript file in Company Home>Data Dictionary>script folder.
My Rule is as follows:
All Items > Executes script 'dataFilesScript.js' > Items are created or entered this folder >Finish
1). My Js script is as follows.
var simplehttpresult = "";
try {
simplehttpresult = SimpleHttpConnection.getContentAsString("http://myip:myport/alfresco/service/demo/simple");
}catch(ex){
error = String(ex)
}
2).I add following lines in web-scripts-application-context.xml
<bean id="webscript.org.alfresco.demo.simple.get"
class="org.alfresco.module.demoscripts.SimpleWebScript"
parent="webscript">
<property name="repository" ref="repositoryHelper" />
<property name="serviceRegistry" ref="ServiceRegistry" />
</bean>
3).My simple.get.desc.xml file
<webscript>
<shortname>The World's Simplest Webscript</shortname>
<description>Hands back a little bit of JSON</description>
<url>/demo/simple</url>
<authentication>none</authentication>
<format default="">argument</format>
<family>Alfresco Java-Backed WebScripts Demo</family>
</webscript>
4). I add following lines script-services-context.xml
<bean id="httpUtilsScript" parent="baseJavaScriptExtension"
class="org.um.alfresco.SimpleHttpConnection">
<property name="extensionName">
<value>SimpleHttpConnection</value>
</property>
</bean>
5).My Java file is as follows.
public class SimpleWebScript extends AbstractWebScript
{
public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException
{
try
{
// build a json object
JSONObject obj = new JSONObject();
// put some data on it
obj.put("field1", "data1");
// build a JSON string and send it back
String jsonString = obj.toString();
res.getWriter().write(jsonString);
}
catch(JSONException e)
{
throw new WebScriptException("Unable to serialize JSON");
}
}
}
.when my rule is executed. It's working fine in Alfresco 4.0 but it is not working for 4.2.c.
In Alfresco 4.2.C My action code was called only once...Any other configuration settings are Required in 4.2.C
Please suggest.....

WebServiceTransportException: Unauthorized [401] in Spring-WS

We are struggling to configure our web app to be able to connect with web services via Spring WS. We have tried to use the example from the documentation of client-side Spring-WS, but we end up with a WebServiceTransportException. The XML config looks like this:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
<property name="messageSender">
<bean class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
<property name="credentials">
<bean class="org.apache.commons.httpclient.UsernamePasswordCredentials">
<constructor-arg value="john"/>
<constructor-arg value="secret"/>
</bean>
</property>
</bean>
</property>
</bean>
We have been able to configure the application programmatically, but this configuration was not possible to "transfer" to a Spring XML config because some setters did not use the format Spring expects. (HttpState.setCredentials(...) takes two parameters). The config was lifted from some other Spring-WS client code in the company.
This is the configuration that works:
public List<String> getAll() {
List<String> carTypes = new ArrayList<String>();
try {
Source source = new ResourceSource(request);
JDOMResult result = new JDOMResult();
SaajSoapMessageFactory soapMessageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
WebServiceTemplate template = new WebServiceTemplate(soapMessageFactory);
HttpClientParams clientParams = new HttpClientParams();
clientParams.setSoTimeout(60000);
clientParams.setConnectionManagerTimeout(60000);
clientParams.setAuthenticationPreemptive(true);
HttpClient client = new HttpClient(clientParams);
client.getState().setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("username", "password"));
CommonsHttpMessageSender messageSender = new CommonsHttpMessageSender(client);
template.setMessageSender(messageSender);
template.sendSourceAndReceiveToResult(SERVICE_URI,
source, result);
// Handle the XML
} catch (IOException e) {
throw new RuntimeException(e);
} catch (SOAPException e) {
throw new RuntimeException(e);
}
return carTypes;
}
Does anyone know how to solve my problem? Every tutorial I have see out there lists the first configuration. It seems that when I set the credentials on the messageSender object, they are just ignored...
Override HttpClient with a constructor that takes the parameters and wire through Spring using constructor-args
public MyHttpClient(HttpClientParams params, UsernamePasswordCredentials usernamePasswordCredentials) {
super(params);
getState().setCredentials(AuthScope.ANY, usernamePasswordCredentials);
}
How do you distinguish these:
<constructor-arg value="john"/>
<constructor-arg value="secret"/>
try and replace it with this:
<property name="userName" value="john" />
<property name="password" value="secret" />
Hope it helps.
If you are using a defaultHttpClient like you are in your example, Use the afterPropertiesSet method on your HTTPMessageSender and that should fix your problem by applying the credentials correctly
At first we were setting credentials in our project like this:
<bean id="authenticationEnabledCommonsHttpMessageSender" parent="commonsHttpMessageSender"
p:credentials-ref="clientCredentials" lazy-init="true" />
<bean id="clientCredentials"
class="org.apache.commons.httpclient.UsernamePasswordCredentials"
c:userName="${clientCredentials.userName}"
c:password="${clientCredentials.password}"
lazy-init="true" />
This is our cridentials enabled option. A problem occured while we are setting credentials like that.
If the server we send message (has Axis impl) has not got username password credentials we get "Unauthorized" exception. Because ,when we trace vie TCPMon, we realized "username:password:" string was sent, as you can see username and password have no value.
After that we set the credentials like that:
public Message sendRequest(OutgoingRequest message, MessageHeaders headers,
EndpointInfoProvider endpointInfoProvider,
WebServiceMessageCallback requestCallback){
Assert.notNull(endpointInfoProvider, "Destination provider is required!");
final Credentials credentials = endpointInfoProvider.getCredentials();
URI destinationUri = endpointInfoProvider.getDestination();
for (WebServiceMessageSender messageSender : webServiceTemplate.getMessageSenders()) {
if (messageSender instanceof CommonsHttpMessageSender) {
HttpClient httpClient = ((CommonsHttpMessageSender) messageSender).getHttpClient();
httpClient.getState().setCredentials(
new AuthScope(destinationUri.getHost(),
destinationUri.getPort(), AuthScope.ANY_REALM,
AuthScope.ANY_SCHEME), credentials
);
httpClient.getParams().setAuthenticationPreemptive(true);
((CommonsHttpMessageSender) messageSender)
.setConnectionTimeout(endpointInfoProvider
.getTimeOutDuration());
}
}
And the getCredentials methos is:
#Override
public Credentials getCredentials(){
if (credentials != null) {
return credentials;
}
String username = parameterService.usernameFor(getServiceName());
String password = parameterService.passwordFor(getServiceName());
if (username == null && password == null) {
return null;
}
credentials = new UsernamePasswordCredentials(username, password);
return credentials;
}