Worklight Java adapter invoke another adapter get I/O issue - adapter

I have a issue when I try to call adapter (HTTP/MYSQL) from a Java adapter.
When I am using Postmen test it (added Authorization on the header)
It's always get a IO issue:
[I O: Invalid token on line 1, column 14].
First, I guess it should be OAuth issue, I add #OAuthSecurity(enabled=false) at the class but not work.
Would you please help me find out where the problem is.
Code snippet:
DataAccessService service = WorklightBundles.getInstance()
.getDataAccessService();
ProcedureQName name = new ProcedureQName("mysqlAdapter",
"getMysqlAdapters");
String para = ""; // String para = "['a','b','c']";
InvocationResult mysql= service.invokeProcedure(name, para);
JSONObject jsMysql = mysql.toJSON();
//String rst = jsMysql.get("key").toString();
PS following code snippet is working when I test it on Postman:
HttpUriRequest request = api.getAdaptersAPI()
.createJavascriptAdapterRequest("mysqlAdapter", "getMysqlAdapters");
try {
HttpResponse response = api.getAdaptersAPI().executeAdapterRequest(request);
JSONObject jsonObj =api.getAdaptersAPI().getResponseAsJSON(response);
return jsonObj.toString();
}
catch (MFPServerOAuthException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return "error";

I am confused...
You use the tag "worklight", but the Product Worklight 4.x-6.2 does not have Java adapters support. There is JavaScript adapters support and the ability for a JavaScript adapter to call Java code on the server. There is also the ability to call a JavaScript adapter from Java code - but not do be confused as a Java adapter.
Java adapters exists only starting MobileFirst Platform Foundation 7.0 (formerly called "Worklight", tag is "mobilefirst"). I mention this because you've mentioned OAuth support, which was introduced alongside Java adapters in MobileFirst Platform Foundation 7.0. But this has got nothing to do with any of your code snippets. a Java adapter looks nothing like that.
So,
If you are using Worklight, you cannot use any of that OAuth stuff.
If you are using MobileFirst, you shouldn't call your adapters this way at all. Please review the Java adapters tutorial and first create a proper Java adapter: https://developer.ibm.com/mobilefirstplatform/documentation/getting-started-7-0/server-side-development/adapter-framework-overview/
Also note that at this time it is not easily possible to call a Java adapter from a JavaScript adapter (the opposite way of your request, if it is to be understood correctly).

Related

Async Function Fails when called as part of a Constructor

I'm rather new to Blazor, but I am currently trying to get access to some classes from within a class library that I've created and deployed as a Nuget package. As background, the Nuget package is an Api library, which allows me to talk to a webservice (I don't know if this is relevant or not). However, every time I go to the page where I'm testing, the page never loads and instead I left looking at the browser loading circle until I navigate away or close the application. During my testing here, it seems like it's the #inject call of my interface into the Blazor component which is causing the issue as when I remove it and try to load the page normally, the page does so.
So to demonstrate what I have setup, here is where I've added the Singletons to the DI:
builder.Services.AddSingleton<IApiConfigHelper, ApiConfigHelper>();
builder.Services.AddSingleton<IApiHelper, ApiHelper>();
builder.Services.AddSingleton<ISystemEndpoint, SystemEndpoint>();
Then on the blazor page, I have the following declarations at the top of my page:
#using Library.Endpoints
#using Library.Models
#page "/"
#inject ISystemEndpoint _systemEndpoint
Now I am leaning towards is this something to do with the Nuget package and using it with DI. I have tested the library away from this project (In a console application) and can confirm it's working as it should.
I have also created a local class library as a test to, to see if I could inject a data access class into the page and I can confirm that this works without an issue, which suggests to me that DI is working, just not with my Nuget package.
I did have a look into CORS, given that the Nuget package is accessing an external domain, and setup the following simple CORS policy in the app:
builder.Services.AddCors(policy =>
{
policy.AddPolicy("OpenCorsPolicy", opt =>
opt.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
});
Which is added to the app after the AddRouting call like so:
app.UseCors("OpenCorsPolicy");
However again, this wasn't the solution so if anyone is able to point me in the right direction with where I may be going wrong with this or offer any advice, I would be most grateful.
EDIT 1 - Provides details #mason queried
Regarding SystemEndpoint, the constructor is being injected with 2 things, as below:
public SystemEndpoint(IApiHelper apiHelper, IOptions<UriConfigModel> uriOptions)
{
_apiHelper = apiHelper;
_uriOptions = uriOptions.Value;
}
My Nuget Library is dependant on the following:
Azure.Identity
Azure.Security.KeyVault.Secrets
Microsoft.AspNet.WebApi.Client
Microsoft.Extensisons.Options.ConfigurationExtensions
EDIT 2 - Doing some further testing with this I have added a simple Endpoint class to my Nuget library, which returns a string with a basic message, as well as returning the values of the 2 UriConfig properties as below. I added this test to 1) sanity check that my DI was working correctly, and 2) check the values that are being assigned from appsettings to my UriConfig Object.
public class TestEndpoint : ITestEndpoint
{
private readonly IOptions<UriConfigModel> _uriConfig;
public TestEndpoint(IOptions<UriConfigModel> uriConfig)
{
_uriConfig = uriConfig;
}
public string TestMethod()
{
return $"You have successfully called the test method\n\n{_uriConfig.Value.Release} / {_uriConfig.Value.Version}";
}
}
However when adding in the dependency of IApiHelper into the Ctor, the method then breaks and fails to load the page. Looking into ApiHeloer, the Ctor has a dependency being injected into it of IApiConfigHelper. Looking at the implementation, the Ctor of ApiConfigHelper is setting up the values and parameters of the HttpClient that should make the REST calls to the external Api.
Now I believe what is breaking the code at this point is a call I'm making to Azure Key Vault, via REST, to pull out the secret values to connect to the Api. The call to KeyVault is being orchestrated via the following method, making use of the Azure.Security.KeyVault.Secrets Nuget Package, however I assume that at the heart of it, it's making a REST call to Azure on my behalf:
private async Task<KeyVaultSecret> GetKeyVaultValue(string secretName = "")
{
try
{
if (_secretClient is not null)
{
var result = await _secretClient.GetSecretAsync(secretName);
return result.Value;
}
}
catch (ArgumentException ae)
{
Console.WriteLine(ae.Message);
}
catch (Azure.RequestFailedException rfe)
{
Console.WriteLine(rfe.Message);
}
return new(secretName, "");
}
So that's where I stand with this at the moment. I still believe it could be down to CORS, as it seems to be falling over when making a call to an external service / domain, but I still can say 100%. As a closing thought, could it be something as simple as when I call call the above method, it's not being awaited????
So after persisting with this it seems like the reason it was failing was down to "awaiting" the call to Azure KeyVault, which was happening indirectly via the constructor of ApiConfigHelper. The resulting method for getting KeyVault value is now:
private KeyVaultSecret GetKeyVaultValue(string secretName = "")
{
try
{
if (_secretClient is not null)
{
var result = _secretClient.GetSecret(secretName);
if (result is not null)
{
return result.Value;
}
}
}
catch (ArgumentException ae)
{
Console.WriteLine(ae.Message);
}
catch (Azure.RequestFailedException rfe)
{
Console.WriteLine(rfe.Message);
}
return new(secretName, "");
}
I am now able to successfully make calls to my library and return values from the Api it interacts with.
I can also confirm that this IS NOT a CORS issue. Once I saw that removing the await was working, I then removed the CORS policy declarations from the service and the app in my Blazor's start-up code and everything continued to work without an issue.
As a final note, I must stress that this is only seems an issue when using the library with Blazor (possibly webApi projects) as I am able to use the library, awaiting the Azure call just fine in a console application.

How to get Redis key values on Server side Dart with Angel

Having moved my mobile app development to Flutter I am now in the process of experimenting with using Dart as my main server side language. The productivity benefits in using a single coding language in both the app and on the server are considerable. To that end I have set up a server with an Nginx front end which proxies all dynamic web requests to an Angel/Dart server.
Angel is a remarkably well written package and I had a working server written up in no time at all. However, in order to have a fully functional backend I need to be able to use both Redis and PostgreSQL from within my server side Dart code. I am using the resp_client package to access Redis. The issue I have run into is with the fact that RespCommand.get is asynchronous. With my newbie knowledge of both Dart and Angel I am unable to find a way to acquire a Redis key value via RespCommand.get in an Angel route handler and then somehow use that value in the response it returns.
My entire Dart backend server code is shown below
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:postgres/postgres.dart';
import 'package:resp_client/resp_client.dart';
import 'package:resp_client/resp_commands.dart';
class DartWeb
{
static Angel angel;
static AngelHttp http;
static RespCommands redis;
static PostgreSQLConnection db;
static init() async
{
angel = Angel();
http = AngelHttp(angel);
angel.get('/',rootRoute);
await prepareRedis();
await http.startServer('localhost',3000);
}
static prepareRedis() async
{
RespServerConnection rsc = await connectSocket('localhost');
RespClient client = RespClient(rsc);
redis = RespCommands(client);
}
static preparePostgres() async
{
db = new PostgreSQLConnection('serverurl',portNo,'database',username:'user',password:'password');
await db.open();
}
static void rootRoute(RequestContext req,ResponseContext res)
{
try
{
await redis.set('test','foobar',expire:Duration(seconds:10));
String testVal = await redis.get('test');
res.write('Done $testVal');
} catch(e) {res.write('++ $e ++');}
}
}
main() async {await DartWeb.init();}
If I start up this server and then access it through my web browser I end up with a 502 Bad Gateway message. Not surprising. dart2native main.dart -o mainCompiled returns the error await can only be used in async... message.
So I tried instead
try
{
res.write('Before');
redis.set('test','foobar',expire:Duration(seconds:10)).then((bool done)
{
res.write('DONE $done');
});
res.write('After');
} catch(e) {res.write('++ $e ++');}
which simply printed out BeforeAfter in my browser with the DONE bit never showing up although a quick test via redis-cli shows that the key test had in fact been created.
My knowledge of both Dart and Angel is still in its infancy so I guess I am doing something incorrectly here. Shorn of all the detail my questions are essentially these -
how do I call and get the result from async methods in an Angel route dispatcher?
given that I am editing my Dart code in VSCode on my local Windows machine which accesses the relevant dart files on my Ubuntu server I loose the benefits of error reporting provided by the VSCode Dart plugin. dart2native, as I have used here, helps out but it would be nicer if I could somehow get a running error report within VSCode as I do when building Flutter apps locally. How can I accomplish this - if at all possible?
It turns out that Dart/Angel does not impose excessively strict constraints on the signature of a route handler. So you can quite safely declare a route handler like this one
static Future<void> rootRoute(RequestContext req,ResponseContext res) async
{
try
{
res.write('!! Before ');
await redis.set('test','foobar',expire:Duration(seconds:10));
String test = await redis.get('test');
res.write('After $test !!');
} catch(e) {res.write('++ $e ++');}
}
With the route simply returning a Future we can now safely do anything we like there - including calling other asynchronous methods: in this instance to fetch a Redis key value.

Can't save the data to OData controller after updating to Microsoft.AspNet.WebApi.OData 5.3.x

Not sure what's changed exactly and causing this partial error (since it's not happening with retrieving the data) but after updating Microsoft.AspNet.WebApi.OData library to 5.3.x version, breeze has an issue with saving the data to OData controller. It's about the urls of the batch requests.
It can be reproduced with breeze's its own sample OData project as well;
http://www.breezejs.com/samples/breeze-web-api-odata
If you look at ExecuteRequestMessagesAsync method of the BatchHandler class, RequestUri property of the items contain OData route prefix two times.
Microsoft.AspNet.WebApi.OData library 5.2.2 url
http://localhost:55802/odata/TodoItems
Microsoft.AspNet.WebApi.OData library 5.3.1 url
http://localhost:55802/odata/odata/TodoItems
Any ideas how to solve this issue?
breeze version: 1.5.1
Oh joy. Microsoft has changed their Web API OData implementation ... again
Thanks for digging in, #coni2k, and identifying the problem.
Fortunately, you do NOT have to patch Breeze. We deliberately expose the getRoutePrefix method so you can change it externally yourself to meet your needs.
In the following example, I've incorporated your suggestion in the body of the method.
var adapter = breeze.config.getAdapterInstance('dataservice', 'webApiOdata');
adapter.getRoutePrefix = getRoutePrefix531; // plug-in alternative for THIS adapter instance.
function getRoutePrefix531(dataService) {
// Copied from breeze.debug and modified for Web API OData v.5.3.1.
if (typeof document === 'object') { // browser
var parser = document.createElement('a');
parser.href = dataService.serviceName;
} else { // node
parser = url.parse(dataService.serviceName);
}
// THE CHANGE FOR 5.3.1: Add '/' prefix to pathname
var prefix = parser.pathname;
if (prefix[0] !== '/') {
prefix = '/' + prefix;
} // add leading '/' (only in IE)
if (prefix.substr(-1) !== '/') {
prefix += '/';
} // ensure trailing '/'
return prefix;
};
As I write we're not sure how to detect which version of Web API OData you're talking to which makes it difficult for us to say a priori which version of getRoutePrefix is right for your application.
Hope to figure this out eventually. Don't dare change the default to this new version because that would break every existing app that has to talk to an older version of Web API OData. Not sure how we can win this game. We'll look at it. Frustrating for now.

Web Service client generated by wsdl not working with Deployed web service

I have generated a WSDL from a java class using axis2 java2wsdl utility as follows;
java2wsdl -o C:\temp -cn com.temenos.webservices.customer.CustomerServiceWS
Then I have deployed the same web service within an Application Server (say jBoss) in axis2 and I can browse the wsdl on http:// 127.0.0.1:8080/axis2/services/CustomerServiceWS?wsdl and call the methods on this service via standard client like SoapUI etc.
The problem is now that when I generated a client using standard java tooling 'wsimport' by providing a WSDL location as C:\temp (Generated WSDL from java2wsdl utility), my client is unable to communicate with the Deployed Web Service. I am using following code to access the web service;
// Initialise WS
CustomerServiceWS service = null;
CustomerServiceWSPortType servicePort = null;
try {
URL wsdlLocation = new URL("http://127.0.0.1:8080/axis2/services/CustomerServiceWS?wsdl");
QName serviceName = new QName("http://customer.webservices.temenos.com", "CustomerServiceWS");
service = new CustomerServiceWS(wsdlLocation, serviceName);
servicePort = service.getCustomerServiceWSHttpSoap12Endpoint();
} catch (MalformedURLException murle) {
murle.printStackTrace();
return;
}
But while creating an (service Port) Endpoint I am getting following error;
Exception in thread "main" javax.xml.ws.WebServiceException: An attempt was made to construct the ServiceDelegate object with an service name that is not valid: {http://customer.webservices.temenos.com}CustomerServiceWS.
at org.apache.axis2.jaxws.ExceptionFactory.createWebServiceException(ExceptionFactory.java:173)
at org.apache.axis2.jaxws.ExceptionFactory.makeWebServiceException(ExceptionFactory.java:70)
at org.apache.axis2.jaxws.ExceptionFactory.makeWebServiceException(ExceptionFactory.java:118)
at org.apache.axis2.jaxws.spi.ServiceDelegate.<init>(ServiceDelegate.java:218)
at org.apache.axis2.jaxws.spi.Provider.createServiceDelegate(Provider.java:59)
at javax.xml.ws.Service.<init>(Service.java:56)
at com.temenos.webservices.customer.CustomerServiceWS.<init>(CustomerServiceWS.java:42)
at com.temenos.services.customer.client.Client.testGetLanguage(Client.java:32)
at com.temenos.services.customer.client.Client.main(Client.java:21)
I have tried many things but it does not seems to like anything. Am I missing anything?
Thanks,
--
SJunejo
The problem was that I had axis2 in lib path because of that the call happend to org.apache.axis2.jaxws.spi.Provider.createServiceDelegate (Axi2 Provider) instead of Java WS Provider. I removed the axis2 libs from classpath and it seems to be working ok now. (though I am still unable to call my web service via client)
See the description of WSDL file and check the targetNamespace for the url to be given in QName(). Also import necessary packages.

How can I connect from flex 4.5 mobile application to Java back end services

Is it possible to connect to a remote database from my flex4.5 Mobile application ?
I am trying to develop a flex 4.5 mobile application and my data is in Oracle Database.
I choose Java as my back end technology. How can I call the java services from flex.
I wanted my mobile application to run on iOS devices.
Yes. You can connect to any database, as long as that database can be connected to via php or Java (possibly other server-side languages as well). It uses a remote call, similiar to Ajax (but faster).
You can use a RemoteObject component. RemoteObject components use the AMF protocol to send and receive data, while WebService and HTTPService components use the HTTP protocol. AMF is significantly faster than HTTP.
On the Flex Side:
<mx:RemoteObject id="Hello" destination="roDest">
<mx:method name="getHelloData"/>
</mx:RemoteObject>
On the Java side:
...
public void getHelloData() {
try{
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup("/Hello");
HelloHome ejbHome = (HelloHome)
PortableRemoteObject.narrow(obj, HelloHome.class);
HelloObject ejbObject = ejbHome.create();
String message = ejbObject.sayHello();
}
catch (Exception e);
}
...
The code examples were taken from:
http://help.adobe.com/en_US/flex/accessingdata/WS2db454920e96a9e51e63e3d11c0bf69084-7fda.html#WS2db454920e96a9e51e63e3d11c0bf66651-7fd7

Resources