SpringBoot how to get full URL of application - spring-boot

Basically, I want to log everything that happens in the life cycle of my SpringBoot REST API, and I'd like to log something like App started at [ip]:[port]/[everything else]
I had already seen a question like this but it was using the embedded Tomcat, I use another web server, can it be done? It would be real cool.

You can retrieve these informations using the ServletUriComponentsBuilder in your Controller :
URI currentUri = ServletUriComponentsBuilder.fromCurrentRequestUri()
.build()
.toUri();
String asString = currentUri.toString(); // "http://localhost:8080/orders/1/items/18"
String host = currentUri.getHost(); // "localhost"
int port = currentUri.getPort(); // 8080
String path = currentUri.getPath(); // "/orders/1/items/18"

Related

How do I inject Heroku's PORT value into a dotnet core 6.0 web api?

I'm not using Docker. Rather, I'm trying to use the jincod/dotnetcore buildpack. However, I need a way to tell dotnet to use Heroku's port number environment variable, and I just don't see a good way of doing that here.
In my Program.cs file, I added the following:
builder.Services.AddHttpsRedirection(options =>
{
options.HttpsPort = int.TryParse(Environment.GetEnvironmentVariable("PORT"), out var p) ? p : null;
});
which actually sort of works in that I'm able to obtain the port number value from Heroku, but this just redirects me to myapp.heroku.com:1234 from myapp.heroku.com and is still not working as expected.
I see in the launchSettings.json file, in the profiles section, there is an applicationUrl that shows two urls, one for https and one for http, both of which have port numbers specified. I think if I can overwrite those port numbers this might work, but I don't know how to inject that environment variable into the launchSettings.json file from Heroku. Anyone know a good way of doing this? Or am I even on the right track here?
I believe if you add the following before the https redirection middleware you won't need to pass any configuration into UseHttpsRedirection
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
});
You can get the port variable and bind it. If you are using dotnet 6 minimal APIs you can do this.
var port = Environment.GetEnvironmentVariable("PORT") ?? "3100";
app.Run("http://0.0.0.0:" + port);
You'll need to add "https_port": 443 to your appsettings.json or set the environment variable ASPNETCORE_HTTPS_PORT to 443 in heroku. You can see this in action here.
https://github.com/TerribleDev/dotnet-mvc-test
https://tp-aspnet-tst.herokuapp.com/
If you are using older versions than 6 you can do something like this...
public static IWebHostBuilder CreateWebHostBuilder(string[] args) {
var builder = WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureKestrel(a =>
{
a.AddServerHeader = false;
});
var port = Environment.GetEnvironmentVariable("PORT");
if(!String.IsNullOrWhiteSpace(port)) {
builder.UseUrls("http://*:" + port);
}
return builder;
}

Modify RewriteContext Host in NetCore 2 rewriting middleware

I need to rewrite not redirect certain requests to GET files to an external storage location (hosted on a different domain)
I am able to accomplish this with redirecting using rewriter middleware, however i would like to rewrite instead.
I need to use some logic to rewrite to a specific file location, so I followed https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-2.0&tabs=aspnetcore2x#method-based-rule tutorial.
When i set the Host and path i can see the absolute url looks correct but when the method exits i get "No webpage was found for the web address:" and url displayed is the original request Url
RewriteRule.cs (also holds redirect url logic in ApplyRule() that i don't want to use)
public static void RewriteStorageFileRequests(RewriteContext context)
{
var request = context.HttpContext.Request;
var path = request.Path.Value;
if (path.Contains("foo/bar"))
{
context.Result = RuleResult.SkipRemainingRules;
request.Host = new HostString("storage/space");
request.Path = path.Replace("foo/bar", string.Empty);
var test2 = request.GetDisplayUrl();
}
}
So essentially, if a call comes in as:
https://localhost:44327/foo/bar/bf34d911-03db-5tda-9c99-c7dd96593159/w3.jpg
I want to rewrite it to:
https://storage/space/bf34d911-03db-5tda-9c99-c7dd96593159/w3.jpg
Startup.cs
app.UseRewriter(new RewriteOptions().Add(RewriteUrlRule.RewriteStorageFileRequests));
test2 displays the correct url in the debugger.
I tried setting host to empty string and passing host value (storage/space) in path but still no luck.
Before Rewriter
After Rewrite
UPDATE: I was able to get rewrite to work by changing
context.Result = RuleResult.SkipRemainingRules;
to
context.Result = RuleResult.EndResponse;
However, when i get to the Url it returns 200OK but does not show the image.
(see attached file)
So, right now the only way i can get images is still with Redirect
Rewrite GET

Can anyone tell me the Java utility to download documents to your local PC from Content Engine in filenet?

Hello Guys I am trying to write the java utility to download the documents to local PC from content engine in filenet can anyone help me out?
You should read about FileNet P8 CE API, you can start here:
You have to know that the FileNet Content Engine has two types of interface that can be used to connect to it: RMI and SOAP. A cmd line app you are planning to write, can connect only by SOAP (I am not sure that this is true for the newest versions, but what is definitely true, that it is much easier to setup the SOAP connection than EJB), so you have to read that part of the documentation, how to establish a connection in this way to your Content Engine.
On the link above, you can see that first of all you have to collect the required jars for SOAP connection: please check the "Required for a Content Engine Java API CEWS transport client" section for the file names.
After you collect them, you will need a SOAP WSDL URL and a proper user and password, the user has to have read properties and read content right to the documents you would like to download. You also need to know the ObjectStore name and the identifier or the location of your documents.
Now we have to continue using this Setting Up a Thick Client Development Environment link (I opened it from the page above.)
Here you have to scroll down to the "CEWS transport protocol (non-application-server dependent)" section.
Here you can see, that you have to create a jaas.conf file with the following content:
FileNetP8WSI {
com.filenet.api.util.WSILoginModule required;
};
This file must be added as the following JVM argument when you run the class we will create:
java -cp %CREATE_PROPER_CLASSPATH% -Djava.security.auth.login.config=jaas.conf DownloadClient
Now, on the top-right corner of the page, you can see links that describes what to do in order to get a connection, like "Getting Connection", "Retrieving an EntireNetwork Object" etc. I used that snipplet to create the class below for you.
public class DownloadClient {
public static void main(String[] args) throws Exception{
String uri = "http://filenetcehost:9080/wsi/FNCEWS40MTOM";
String userId = "ceadmin";
String password = "password";
String osName = "Test";
UserContext uc = UserContext.get();
try {
//Get the connection and default domain
Connection conn = Factory.Connection.getConnection(uri);
Domain domain = Factory.Domain.getInstance(conn, null);
ObjectStore os = Factory.ObjectStore.fetchInstance(domain, osName, null);
// the last value (jaas samza name) must match with the name of the login module in jaas.conf
Subject subject =UserContext.createSubject(connection, userId, password, "FileNetP8WSI");
// set the subject to the local thread via threadlocal
uc.pushSubject(subject);
// from now, we are connected to FileNet CE, and objectStore "Test"
//https://www.ibm.com/support/knowledgecenter/en/SSNW2F_5.2.0/com.ibm.p8.ce.dev.ce.doc/document_procedures.htm
Document doc = Factory.Document.getInstance(os, ClassNames.DOCUMENT, new Id("{F4DD983C-B845-4255-AC7A-257202B557EC}") );
// because in FileNet a document can have more that one associated content element
// (e.g. stores single page tifs and handle it as a multipaged document), we have to
// get the content elements and iterate list.
ContentElementList docContentList = doc.get_ContentElements();
Iterator iter = docContentList.iterator();
while (iter.hasNext() )
{
ContentTransfer ct = (ContentTransfer) iter.next();
// Print element sequence number and content type of the element.
// Get and print the content of the element.
InputStream stream = ct.accessContentStream();
// now you have an inputstream to the document content, you can save it local file,
// or you can do what you want with it, just do not forget to close the stream at the end.
stream.close();
}
} finally {
uc.popSubject();
}
}
}
This code is just shows how can you implement such a thick client, I have created it now using the documentation, not production code. But after specifying the packages to import, and may handle the exceptions it will probably work.
You have to specify the right URL, user, password and docId of course, and you have to implement the copy from the TransferInputStream to a FileOutputStream, e.g. by using commons.io or java NIO, etc.

Sending Images to the client from tomcat server

I am building a framework for e-commerce site. I have used jersey to create REST APIs. I need to send images to the clients as per the request.
How can I do so from my application server as Tomcat and jersey as REST API?
Since I am new to this, I have no clue how to send images to an Android client when they are shown as item.
Every resource is identified by the URI, client will ask for a particular image or a bunch of images by quering the URL, So you just need to expose a service, following service is an example to send single image to client.
#GET
#Path("/images/{imageId}")
#Produces("image/png")
public Response downloadImage(#PathParam("imageId") String imageId) {
MultiMediaDB imageDb = new MultiMediaDB();
String filePath = imageDb.getImage(imageId);
File file = new File(filePath);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition",
"attachment; filename=\"fileName.png\"");
return response.build();
}
MultiMediaDB is my custom class to get the file location from the DB, you can hardcode it as of now for testing purpose like D:\server_image.png.
You need to mention Content-Disposition as an attachment so that file will not be downloaded, instead attached to the form. In android you just need to read inputstream from a HttpURLConnection object and send that to bitmap as shown below
URL url = new URL(BaseUrl + "/images/" + imageId);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
iStream = urlConnection.getInputStream();
bitmap = BitmapFactory.decodeStream(iStream);
The you can set that bitmap to imageview or what ever you have as a container.

In Memory HTTP server Asp.net WebAPI

I am trying to understand how the self host configuration based Integration Tests are running.
In the code below, Should I be registering my config with the WebApiConfig. Registering or not seems to make no difference.
Is the full pipeline really being tested or is this an illusion? Since, If I am not using the config and the routes defined in my API instead declaring my own as I have done here, I am probably just not testing the full pipleine.
Is there any othere way of testing the api completely. The code below is testing a lot of things besides just my pipeline(like the client, SelfHosting etc..). This seems like an overkill to me. Any ideas ?
var config = new HttpSelfHostConfiguration("http://localhost:9090/");
config.Routes.MapHttpRoute("Default", "{api}/{controller}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
MyApiProject.WebApiConfig.Register(config);
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
using (var client = new HttpClient())
{
using (var response = client.PostAsync("http://localhost:9090/api/login",
new FormUrlEncodedContent(new List<KeyValuePair<string,string>> { new KeyValuePair<string, strin("Foo","Bar)}), CancellationToken.None).Result)
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
using (var response = client.GetAsync("http://localhost:9090/api/login").Result)
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}
server.CloseAsync().Wait();
}
If you just want to test your controllers, you can write more targeted unit tests to test them. If you want to test the full pipeline your code looks fine except that instead of using a selfhost, you can just use HttpServer saving the network overhead. Also, if you are testing the full pipeline it is better to use the routes that you have in your actual app rather than adding a new route as that would be testing routing as well.
Also, refer to this blog post by Youssef for some ideas on testing your web APIs.

Resources