How to get default application name in cli? - java

I want to create a framework that shows the application name on statup. Targeting command line interface applications.
Question: how can I get such an application name in a generic way?
Eg spring offers a property, but which is not set by default:
#Value("${spring.application.name}")
private String appname;
And I don't want to set that property explicit. Looking for some kind of "default application name".
In a Java EE container there is also the following option:
String myApplicationName = (String) initialContext.lookup("java:app/AppName");
But how about CLI apps? How can I get some kind of generic application name?

The closest you can get, if I interpreted correctly your question, is to:
find which class is running public static void main(String [] args) method
get its simpleName
store aforementioned name into a system property
and in order to do so, you have two options:
call Thread.currentThread().getStackTrace(), and inspect its tail element. But this has to be executed in the main thread as well, otherwise you wont retrieve the correct StackTraceElement;
call Thread:getAllStackTraces(), and parse the entire map to identify the main Thread, get the corresponding value, and pick its last StackTraceElement
Once you have StackTraceElement, you can call StackTraceElement:getClassName() which will return something like
scala.tools.nsc.MainGenericRunner
Split the string, save it into a system property, and you're good to go.
Hope it will help you.

Related

Logback add custom field/fields in all the logs

For a Spring application I want to add a custom field to the log.
Currently I use the default format but I want to add a custom field (category field) which should be present in all the logs:
W:Action D:2022-01-10 23:21:03.285 L:INFO C:c.h.l.LoggingDemoApplication F:StartupInfoLogger.java(61) Fn:logStarted T:main R: - Hello World
What are the best solution to add a custom field to the logback log?
What I studied until now are the following possible solutions:
Use marker. The disadvantage with this is that it's not scalable: if in future you need another custom field can't add another marker. Further based on some other posts the marker is best suited to mark special logs that need to be handle differently.
Use MDC.
Also using this it seems not the best solution because:
It keeps the context so if there are multiple log statements in the same function, before each logger.info() there should be MDC.put("category", "action")
The code becomes to verbose.
Create a custom convertor (link). Get the arguments from the ILoggingEvent, get argument of 0. If this is the same type as category enum, then use it. The call for this is like logger.info("Message here: {} {} {}", CatEnum.Action.getValue(), msg1, msg2, msg3).
Create some static method in which the final format is generated.
Pattern is similar to: <pattern>%m%n</pattern>
To log, something like this should be used: logger.info(customFormatter.fmtLog(CatEnum.Action.getValue(), msg)). The returned value of fmtLog should be all the info from default logging + the category field.
Are there any built in solutions to add a custom field?

How to identify which class is calling a specific method?

Let's assume that we have an abstract class with a method that prints a WARN log entry (WARNING: Cannot set header. Response already committed), this method is being called by class X lots of times (it is flooding the logs).
Based on the log entry that was generated from the Application Server, I have managed to identify the abstract class and found its jar (using jarscan), the JAR is an OOTB Component of the application server so it is not supposed to be modified in any sense. I have hacked the JAR and introduced a line within the method that generates the log entry:
new Exception().printStackTrace()
This approach should give me the stack trace to identify class X.
However, I don't know how to reproduce this error in my test environment, there are a lot of projects that I don't have in my workspace and I can't just check hundreds of classes to see which one is setting something into the response object, I have tried to find a match between the log entries timestamps and Selenium test reports that are running against the test environment but it is not showing up in the logs.
Question: What would be a good troubleshooting approach to identify Class X without any intrusive changes on the environment that presents the issue?
If you cannot use debugger because of your environemnt specific, you can investigate classes loaded into your server's JVM and find classes that inherit from your abstract class.
Run jvisualvm and connect to your server's JVM, then go to OQL console in jvisualvm and run such query:
select heap.findClass("com.xyz.my.AbstractClass").subclasses()
This will find all subclasses of your abstract class currently loaded.
public String getMethodName(final int depth) {
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
return ste[depth].getMethodName();
}
Usage:
public void doSysOutTest() {
String getMetNameFunc = getMethodName(1);
String callingMethod = getMethodName(2);
System.out.println(getMetNameFunc);
System.out.println(callingMethod);
}
Output:
getMethodName
doSysOutTest
To get more information out of the stack you could also use these methods:
ste[depth].getClassName()
ste[depth].getFileName()
ste[depth].getLineNumber()
Take a look here: http://docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html

Guice IOC: Manual (and Optional) Creation of a Singleton

Trying to get started with Guice, and struggling to see how my use-case fits in.
I have a command-line application, which takes several optional parameters.
Let's say I've got the tool shows a customer's orders, for example
order-tool display --customerId 123
This shows all the orders owned by customer with ID 123. Now, the user can also specify a user's name:
order-tool display --customerName "Bob Smith"
BUT the interface to query for orders relies on customer IDs. Thus, we need to map from a customer name to a customer ID. To do this, we need a connection to the customer API. Thus, the user has to specify:
order-tool display --customerName "Bob Smith" --customerApi "http://localhost:8080/customer"
When starting the application, I want to parse all the arguments. In the case where --customerApi is specified, I want to place a CustomerApi singleton in my IoC context - which is parameterized by the CLI arg with the API URL.
Then, when the code runs to display a customer by name - it asks the context if it has a CustomerApi singleton. If it doesn't it throws an exception, telling the CLI user that they need to specify --customerApi if they want to use --customerName. However, if one has been created - then it simply retrieves it from the IoC context.
It sounds like "optionally creating a singleton" isn't exactly what you're trying to do here. I mean, it is, but that's as simple as:
if (args.hasCustomerApi()) {
bind(CustomerApi.class).toInstance(new CustomerApi(args.getCustomerApi()));
}
To allow for optional bindings, you will probably need to annotate their use with #Nullable.
I think your real question is how to structure an application so that you can partially configure it, use the configuration to read and validate some command-line flags, then use the flags to finish configuring your application. I think the best way to do that is with a child injector.
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AModule(), new BModule(), ...);
Arguments arguments = injector.getInstance(ArgParser.class).parse(args);
validateArguments(arguments); // throw if required arguments are missing
Injector childInjector =
injector.createChildInjector(new ArgsModule(arguments));
childInjector.getInstance(Application.class).run();
}
Child injectors are just like normal injectors that defer to a parent if they don't contain the given bindings themselves. You can also read documents on how Guice resolves bindings.

Renaming the argument name in JAX-WS

I created a web service using JAX-WS in RSA 7.5 and Websphere 7 using bottom-up approach. When I open the WSDL in SOAP UI, then the arguments section is appearing like this:
<!--Optional-->
<arg0>
<empID>?</empId>
</arg0>
<!--Optional-->
<arg1>
<empName>?</empName>
</arg1>
<!--Optional-->
<arg2>
<empAddress>?</empAddress>
</arg2>
<!--Optional-->
<arg3>
<empCountry>?</empCountry>
</arg3>
The service method takes the above 4 elements as the parameters to return the employee details.
1) I want to rename this arg0, arg1, and so on with some valid names.
2) I want to remove the <!--optional--> present above the arg tags. (For removing the <!--optional--> from elements name, I used #XMLElement(required=true)). But I am not sure where exactly to use this annotation in this case :(
Please help.
Regards,
You put the #XMLElement(required=true) above the variables in your class that are being returned from your service. I just learned about that option about a month ago. So right above where you declare empName put the tag and required.
To rename the parameters of your service use the #WebParam(name="<name you want in soap>") in front of each input variable to the service.
For example, if you have a service method called get(String name) it would look something like get(#WebParam(name = "name") String name)
You are correct, now that I read your comment again. The services I support use Objects in the input and output, which is why I put the XMLElement tag in the class of those objects.
You need to put the tag in the class that declares your variables that are passed in or returned to the service. If those happen to be declared in your service class that is fine. The main point is that you put that XMLElement tag above the variable declaration, versus putting it on a getter or setter.
This tutorial shows some examples of the usage. JAXB tutorial

Play 2.0: Push a URL parameter to the view

I'm just learning how the Play 2.0 framework. So I have a quite basic question: I just want to take a URL parameter and display it in the view. How do you do that?
I created the URL pattern:
GET /test/:id controllers.Application.testOutput(id: Long)
And an apporoptiate methode in Application:
public static Result testOutput(long id) {
return ok(
views.html.test.render(id)
);
}
How do I call the id variable form the view? I know how to call methodes defined in the model in the view, but I don't know how to display the id variable in the view. Is it the right way to pass the id variable to the render methode?
I'd like to understand the underlying concept, so an detailed explanation to the answer would be great!
Our test URL will be http://localhost:9000/greeter?message=hello and this will output a text/plain response with the content of the parameter message (ie hello). First, let's define the route
GET /greeter controllers.Greeter.say(message: String)
Then, create a Greeter controller (I use Java)
package controllers;
import play.*;
import play.mvc.*;
// This lets you call the template without the views.html prefix
// import views.html.*;
import views.txt.*;
public class Greeter extends Controller {
public static Result say(String message) {
return ok(greeter.render(message));
}
}
You can see that ok() calls a scala function defined in the file app/views/greeter.scala.txt Here is the content of that file (the first line defines the message parameter of type String used inside the function
#(message: String)
I'm the content. Note that you can place
anything you want here. Scala expressions
begin with the '##' character. For example
next line contains the content of message:
#message
In this case I used .txt for file extensions because I wanted plain text response. If you want to produce HTML output, simply make a .scala.html file
The client request is handled by the Play router, which in turn forwards it to some action (which is a method inside a Controller)
GET /greeter Greeter.say
From the Play doc
The last part of a route definition is the Java call. This part is
defined by the fully-qualified name of an action method. The action
method must be a public static void method of a Controller class. A
Controller class must be defined in the controllers package and must
be a subclass of play.mvc.Controller.
You can add a Java package before the Controller class name if it
isn’t defined directly under the controllers package. The controllers
package itself is implicit, so you don’t need to specify it
Inside the action, you can get the parameters via the param object or directly by the method signature:
public static void say(String what) {
...
}
and you can pass objects to the template via render(what) like you do in your sample.
Finally your template can access those object with the ${what} syntax.
EDIT This is the Play 1.x way of doing things. I didn't notice your tag, but still hope this helps. Play2 uses the new Scala template engine, here is the guide. It seems you must declare your parameters at the beginning of the template, then you can access them via the #what syntax. That's because the template is now a compiled Scala function, so it can do type checking at compile time and things like this. You pass parameters to this function with render(what) (like you do) . I personally don't use Play2.0 myself: it's a big improvement from the technical point of view, at the cost of being less intuitive and more verbose. I don't think that simpler projects benefit from these improvements
In Play 2 templates are just plain functions, so you can call them as you would call any function.

Categories

Resources