How to retry requests using MS JAVA SDK for GRAPH API? - azure-active-directory

I am a beginner using Graph API and currently trying to handle throttling related errors in my code. In the sdk's github page there is a RetryHandler class. But i can't seem to find an implementation of the code for a sample request. Is there any examples which i can inspect and try?
As an example i can give my own code below.
#Override
public JsonObject getUserList(String accessToken){
LOGGER.trace("Querying directRoutingEnabled users");
final String selectQuery = "mail,givenName,surname,displayName";
final List<Option> requestOptions = new LinkedList<>();
final String filterQuery = createFilterQuery();
requestOptions.add(new HeaderOption(CONSISTENCY_LEVEL, EVENTUAL));
requestOptions.add(new QueryOption(SELECT, selectQuery));
requestOptions.add(new QueryOption(COUNT, true));
requestOptions.add(new QueryOption(FILTER, filterQuery));
IGraphServiceClient graphServiceClient = GraphServiceClient.builder().authenticationProvider(new SimpleAuthProvider(accessToken)).buildClient();
IUserCollectionRequest request = graphServiceClient
.users()
.buildRequest(requestOptions);
IUserCollectionPage users = request.get();
return users.getRawObject();
}
How can i cover this code with retry-after mechanism (and maybe also Error Handling) using Graph SDK for Java?.

The default middleware from the core library comes with the default RetryHandler implementation. And thanks to a recent fix, it works with throttling errors as well.
Starting from V3 of the SDK, you can specify custom OkHttpClient with custom interceptors. Customization guidelines can be found here: https://learn.microsoft.com/en-us/graph/sdks/customize-client?tabs=java.
Default RetryHandler implementation: https://github.com/microsoftgraph/msgraph-sdk-java-core/blob/dev/src/main/java/com/microsoft/graph/httpcore/RetryHandler.java
Default RetryHandler design: https://microsoftgraph.github.io/msgraph-sdk-design/middleware/RetryHandler.html

Related

Apache Camel CXF difficulty calling an RPC/Encoded WSDL when updating list of elements

While not officially supported, with a few minor modifications to the WSDL I was able to successfully generate CXF Objects for the WSDL and get Camel CXF to talk to an RPC/Encoded WSDL endpoint. The code is incredibly simple and most request/responses work without issue except for attempting to send updates of a list of elements. Here is what the service expects:
<elements arrayType="UpdateElement">
VS here is what is being sent:
<elements>
I need to add the arrayType into the outgoing message. I looked into a number of ways of doing this:
1) An interceptor right before the SOAP message is sent by CXF then use XPath to add the element but I was not clear how to accomplish this using Apache Camel + Camel CXF. How to retrieve the CXF client from the Camel Context?
MyService client = ???
2) Fix it via WSDL? Is it possible to add this element to the WSDL so it is generated as a part of the CXF Objects? It is defined like this presently:
<message name="wsdlElementRequest">
<part name="elements" type="tns:UpdateElements" /></message>
'message' and 'part' come from http://schemas.xmlsoap.org/wsdl/.
Any ideas or suggestions would be appreciated. Thanks!
In case anyone ever stumbles on this with a similar issue, I figured it out myself. I was able to retrieve the CxfEndpoint via CamelContext:
camelContext.getEndpoint(endpointUrl, CxfEndpoint.class);
Then I was able to add the interceptor I created:
public class MyCxfInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
...
Using the CxfEndpoint methods:
cxfEndpoint.getOutInterceptors().add(new MyCxfInterceptor());
In my interceptor I also incorporated another interceptor, SAAJOutInterceptor, that converts the SOAP into an easy to work with object:
private List<PhaseInterceptor<? extends Message>> extras = new ArrayList<>(1);
public MyCxfInterceptor() {
super(Phase.USER_PROTOCOL);
extras.add(new SAAJOutInterceptor());
}
public Collection<PhaseInterceptor<? extends Message>> getAdditionalInterceptors() {
return extras;
}
The easy to work with SOAP message:
#Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
SOAPMessage msg = soapMessage.getContent(SOAPMessage.class);
try {
SOAPBody soapBody = msg.getSOAPBody();
Then it was a simple matter of using XPATH to make the correction to the outgoing SOAP message.
private XPath xpath = XPathFactory.newInstance().newXPath();
...
NodeList nodeList = soapBody.getElementsByTagName("tagName");
for (int x = 0; x < nodeList.getLength(); x++) {
Node node = nodeList.item(x);
((Element) node).setAttribute("missingAttributeName", "missingAttributeValue");
}
I hope this helps anyone working with challenging SOAP services!
Credit to the blog which played a big part in enabling me to implement this solution: https://xceptionale.wordpress.com/2016/06/26/message-interceptor-to-modify-outbound-soap-request/

Solr - How to trigger the DIH from SolrNet API with C# code

Solr version :: 6.6.1
SolrNet API with the C# based application
I wish to invoke or trigger the data import handler from the C# code with
the help of SolrNet. But i am unable to locate any tutorial in the SolrNet
API. I can easily invoke the DIH from the solr admin UI, but my need is to invoke it from an external application.
Please suggest the code snippet how do i invoke the data import action from the C# based
application ?
I don't think it's possible to do completely from Solr.NET, a brief look gives me an idea, that currently there is only class responsible for DIH status page, which is good, but not covering the initial process. I think this was discarded recently, since this functionality wasn't needed.
In the SolrBasicServer class you have:
public SolrDIHStatus GetDIHStatus(KeyValuePair<string, string> options) {
var response = connection.Get("/dataimport", null);
var dihstatus = XDocument.Parse(response);
return dihStatusParser.Parse(dihstatus);
}
which is getting the DIH. Most likely, you need to extend this class and do something similar (I'm not C# developer, so not 100% sure about the code):
connection.Post("/dataimport?command=full-import", null);
or something similar with delta-import command and then later get the status part.
If updating Solr.NET is not the case for you, you still could just trigger it via usual HTTP call with some preferable C# library and do POST request to http://host:port/solr/collection-name/dataimport?command=full-import
string solrTargetDIHUrl = "http://localhost:8983/solr/dih/dataimport?command=delta-import";
try
{
using (var solrClient = new HttpClient())
{
var resultObj = solrClient.GetAsync(new Uri(solrTargetDIHUrl)).Result;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\t\t Data Import Triggered Successfully !");
Console.ResetColor();
}
}
catch(Exception ex)
{
Console.WriteLine("ERROR in DIH Trigger >>>>> " + ex.Message + "||" + ex.StackTrace);
}

Configuring Webpack build for file:// use in CEF

I have to develop a webapp for a CEF-Browser environment. There is no HTTP server available, everything will be served over file:// protocol.
When developing a Webapp nowadays one doesn't get round working with a framework like react/vue for frontend. The standard webpack build scripts of those build a bundle which only works served over HTTP.
Is it possible to configure webpacks build bundle to work on file:// or is there another way to use react or vue via file://?
I'm suggest read CEF wiki more carefully. You are especially interested in https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-request-handling
In short:
You can register custom scheme handler to serve resources over http+custom fake domain.
You can pack resources in zip for example if you like, or leave them at file system as is (but in that case you can expect that some funny users can edit your files, and then report back unexisting errors back to you).
Important helpers already done (but you can write own when need.)
You can... many other things.
Main thing that "file" scheme are more restricted, and for example you can't do XHR requests. But for custom handler you can. Even if dynamic loader for some reason use XHR instead DOM-based loading it will work again same as on http without touching network.
cefclient itself also has usage of custom schemes. Check URL of Tests->Other... in menu. :)
PS: Sorry that my answer doesnt have direct answer for your question. But, custom resource handling in CEF is so common, that i'm just should say about.
fddima is right - you don't need to configure your webpack (although it would be theoretically possible). Instead you can use custom scheme handler in CEF. I made it work with angular at work.
I wrote blog post on how to serve web application via 'file' protocol in CEF.
What you want to add is your scheme handler and its factory:
using System;
using System.IO;
using CefSharp;
namespace MyProject.CustomProtocol
{
public class CustomProtocolSchemeHandler : ResourceHandler
{
// Specifies where you bundled app resides.
// Basically path to your index.html
private string frontendFolderPath;
public CustomProtocolSchemeHandler()
{
frontendFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "./bundle/");
}
// Process request and craft response.
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var uri = new Uri(request.Url);
var fileName = uri.AbsolutePath;
var requestedFilePath = frontendFolderPath + fileName;
if (File.Exists(requestedFilePath))
{
byte[] bytes = File.ReadAllBytes(requestedFilePath);
Stream = new MemoryStream(bytes);
var fileExtension = Path.GetExtension(fileName);
MimeType = GetMimeType(fileExtension);
callback.Continue();
return true;
}
callback.Dispose();
return false;
}
}
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "customFileProtocol";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new CustomProtocolSchemeHandler();
}
}
}
And then register it before calling Cef.Initialize:
var settings = new CefSettings
{
BrowserSubprocessPath = GetCefExecutablePath()
};
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});

NoClassDefFoundError: javax.naming.directory.InitialDirContext is a restricted class. Using CCS (GCM) in Google App Engine

Im trying to implement google's Cloud Connection Server with Google App Engine following this tutorial -
Implementing an XMPP-based App Server. I copied latest smack jars from http://www.igniterealtime.org/projects/smack/ (smack.jar and smackx.jar), put them in WEB-INF/lib and added them to the classpath (im using eclipse).
In the code sample in the first link i posted, the XMPPConnection is initiated in a 'main' method. Since this is not really suitable to GAE i created a ServletContextListener and added it to web.xml.
public class GCMContextListener implements ServletContextListener {
private static final String GCM_SENDER_ID = "*GCM_SENDER_ID*";
private static final String API_KEY = "*API_KEY*";
private SmackCcsClient ccsClient;
public GCMContextListener() {
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
final String userName = GCM_SENDER_ID + "#gcm.googleapis.com";
final String password = API_KEY;
ccsClient = new SmackCcsClient();
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
try {
ccsClient.disconnect();
} catch (XMPPException e) {
e.printStackTrace();
}
}
}
web.xml
<web-app>
<listener>
<listener-class>com.myserver.bootstrap.GCMContextListener</listener-class>
</listener>
</web-app>
Now, when i start the GAE server i get the following exception :
java.lang.NoClassDefFoundError: javax.naming.directory.InitialDirContext is a restricted class. Please see the Google App Engine developer's guide for more details.
i searched the "Google App Engine developer's guide for more details" but couldnt find anything about this. can you please help me ?
Google App Engine restricts access to certain JRE classes. In fact they published a whitelist that shows you which classes are useable. It seems to me that the Smack library might require some reference to a directory context (maybe to create the XMPP messages?) and that is why your servlet causes this exception. The javax.naming.directory is not in the whitelist.
I'm currently working on setting up a GCM Server as well. It seems to me that you need to read through the example and see what that main method is doing. What I see is a connection to the GCM server:
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
Then a downstream message being sent to a device:
// Send a sample hello downstream message to a device.
String toRegId = "RegistrationIdOfTheTargetDevice";
String messageId = ccsClient.getRandomMessageId();
Map<String, String> payload = new HashMap<String, String>();
payload.put("Hello", "World");
payload.put("CCS", "Dummy Message");
payload.put("EmbeddedMessageId", messageId);
String collapseKey = "sample";
Long timeToLive = 10000L;
Boolean delayWhileIdle = true;
ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
timeToLive, delayWhileIdle));
}
These operations would be completed at some point during your application's lifecycle, so your servlet should support them by providing the methods the example is implementing, such as the connect method that appears in the first piece of code that I pasted here. It's implementation is in the example at line 235 if I'm not mistaken.
As the documentation says, the 3rd party application server, which is what you're trying to implement using GAE, should be:
Able to communicate with your client.
Able to fire off properly formatted requests to the GCM server.
Able to handle requests and resend them as needed, using exponential back-off.
Able to store the API key and client registration IDs. The API key is included in the header of POST requests that send messages.
Able to store the API key and client registration IDs.
Able to generate message IDs to uniquely identify each message it sends.

GWT form upload using BlobstoreService App Engine

I am using GWT and Google App Engine Java for my application. I have a profile screen where
user enters profile information like name, age and address, saves it and gets success or failure message. I developed this initial application using GWT-RPC and it worked fine. I had a new requirement where I have to store image of the user. I am using BlobstoreService to store images. This has created complications in the flow. I had to use FormPanel as it is the only way to do a FileUpload in GWT. The BlobStore service servlet expects a redirect on completion. As a result it cannot now return any status back to my GWT application once the profile is saved. Is there easy to store images using GWT along with other form fields and show a status message back to user once the profile is saved.
i struggled a lot with this problem until yesterday I figured out the solution with much help from Ikai Lan's blog. Basicaly what I did is follow his steps but with a few modifications because doing it exactly how he did it did'nt work for me:
Create a form panel : set encoding multipart, method post.
Make a GWT Remote Service that just has one method:public String getUploadURL() or something like that and in the IMPL write this:
BlobstoreService service = BlobstoreServiceFactory.getBlobstoreService();
return service.createUploadUrl("/XXX/YYY");
In XXX you must put your project path, for example mine is com.fer.pyn.PictureYourNews
In YYY you must put the servlet mapping name for a new servlet that we will have to create: I put XXX = BlobUploader, I created a BlobUploader extends HttpServlet and you have to update the web.xml.
Okey, so this is the weird part that I could'nt figure out, thing is that when we make a RPC call to getUploadURL() in the remote ervice from step 2 that returns a weird addres, like: '/_ah/img/eq871HJL_bYxhWQbTeYYoA' and that is the .fromAction you have to put in your form from step one. You need to update the form's action every time so i suggest the following:
public void initBlobStoreSession()
{
imageService.getBlobStoreUploadURL(new AsyncCallback()
{
#Override
public void onSuccess(String result) {
uploadFormPanel.setAction(result);
System.out.println("Upload Form Panel Action set");
}
#Override
public void onFailure(Throwable caught) {
//oops
}
});
}
So when you submit your fromPanel, IT WILL UPLOAD THE BLOB and you dont have to do anything, the tricky part is how to get the blob:
What you need to do now is create the YYY servlet we where talking about in step 4.
In the post method, this is important:
private BlobstoreService blobService = BlobstoreServiceFactory.getBlobstoreService();
Map<String, BlobKey> blobMap = blobService.getUploadedBlobs(request);
BlobKey blobKey = blobMap.get(UPLOAD_WIDJET_NAME);
UPLOAD_WIDJET_NAME is the .setName for the FileUpload widjet.
What you are doing there is getting a key for yout BLob so you can reference it later.
Our next step is showing the uploaded image back to the GWT layer:
//In the same post method from step 7
ImagesService imagesService = ImagesServiceFactory.getImagesService();
String imageURL = imagesService.getServingUrl(blobKey);
response.sendRedirect("/XXX/YYY?imgURL="+imageURL);
Now in the get method:
String imageUrl = request.getParameter("imgURL");
response.setHeader("Content-Type", "text/html");
response.getWriter().println(imageUrl);
We are done, now you just have to
uploadFormPanel.addSubmitCompleteHandler(new SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
uploadFormPanel.reset();
initBlobStoreSession();
String imageUrl = event.getResults();
Image image = new Image();
image.setUrl(imageUrl);
//if you are using jetty, leave this on
//or else it wont work
//Don't use GWT.getModuleBaseURL(), it doesnt
//work well in development mode
imageUrl.replace("http://0.0.0.0:8888/", "");
System.out.println(imageUrl);
final PopupPanel imagePopup = new PopupPanel(true);
imagePopup.setWidget(image);
// Add some effects
imagePopup.setAnimationEnabled(true); // animate opening the image
imagePopup.setGlassEnabled(true); // darken everything under the image
imagePopup.setAutoHideEnabled(true); // close image when the user clicks
imagePopup.center(); // center the image
}
});
check out upload4gwt which address uploading in GWT on AppEngine.
(disclosure: I created upload4gwt; it's not mature yet, however may be useful)
I had the same problem. As a workaround I'm using a redirection to a servlet that print a status message for the client to parse.
I'm passing the websafe string representation of the key to that result servlet.
That's a bit hackey, I'd like someone to come with a better answer, or explain why the blobstore servlet have to redirect.
Yeah, things get more complicated with uploads in GWT.
You can save the form data and image in separate RPCs, and either include a status message in the response to the image upload, or fire off a 3rd RPC when the form returns to get any status or metadata you need.

Resources