How to change slf4j log into html link - java

I have java code as:
final URI myUri = new URIBuilder()
.setScheme(azkabanHostProtocol)
.setHost(azkabanHost + ":" + azkabanPort)
.setPath("/executor")
.setParameter("execid", executionID).build();
logger.info(myUri.toString());
I want to display myURI in form of an url/html link into Azkaban's logs so that by clicking on the url it is opened. I am using log4j for logging.

You may create your own Layout class extending HTMLLayout .
Then override the format method to suit your needs.
The actual implementation has the following lines, that you may want to replace :
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
See that all tags in the message String, will be escaped by default.
Your version could be based on a kind of marker, say String mark = "[LINK]"; for instance
if(event.getRenderedMessage().startsWith(mark)){
String uri = event.getRenderedMessage().substring(mark.length());
String link = "" + uri + "";
sbuf.append(link);
}
else
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
And you would call the logger this way :
logger.info(mark + myUri.toString());
The following topic will help you use a custom HTMLLayout : how to change htmllayout in log4j2
Here is the source code for the default HTMLLayout, as a starter.

How do you view the Azkaban log files? If they are just raw text files being viewed with a vanilla text editor then there is no way to accomplish what you want. If you are viewing them in a smarter UI then you need to format them according to what that UI requires.
In short, the answer to your question is completely driven by whatever tool you are using to view the logs.

Related

Eclipse MessageConsole: cannot generate clickable link as (Filename.java:LineNumber)

I am using a MessageConsole in Eclipse to display output information. The output is formatted into Error 1 - (MyClass.java:10), which is expected to generate a clickable link to code (MyClass.java line 10, in this case), since the console should be able to parse the pattern (FileName.java:LineNumber) automatically as suggested in this post.
However, it failed to work this way. But when I use System.out.println() to output this pattern directly in the plugin Eclipse, the link can be generated.
I also considered the possibility of multiple consoles in the plugin, but streaming the patterned text to other consoles did not work either. Any insights?
My code is like below:
ConsolePlugin plugin = ConsolePlugin.getDefault();
IConsoleManager conMan = plugin.getConsoleManager();
MessageConsole myConsole = new MessageConsole( name, null );
conMan.addConsoles( new IConsole[]{myConsole} );
MessageConsoleStream out = myConsole.newMessageStream();
out.println("Error 1 - (MyClass.java:10)");
Matching for Java code links is only done for consoles which have the javaStackTraceConsole console type.
So you can use the org.eclipse.ui.console.consolePatternMatchListeners extension point to define your own pattern matcher to do the same thing for your console.
Or you can use the:
public MessageConsole(String name, String consoleType, ImageDescriptor imageDescriptor, boolean autoLifecycle)
constructor to specify the console type for your console to match the existing matchers.

How to check for a device language in android?

I want my application to check which language the phone is using. This if statement is supposed to do that:
if (Locale.getDefault().getLanguage().equals("en")) {
yourYesResponse = "That is great " + usersName + "!";
}
else if (Locale.getDefault().getLanguage().equals("fr")) {
yourYesResponse = "C\'est bon " + usersName + "!";
}
But even if my device is set to French it still displays the English. Is there anything wrong with this if statement and if yes, then what?
EDIT: Thanks for the help. I appreciate it.
In order to get the device language, you can use this:
Locale.getDefault().getDisplayLanguage();
or,
Locale.getDefault().getLanguage(); //to get usual language code
Use :
Locale.getDefault().getLanguage().contentEquals("en")
The String#equals() not only compares the String's contents, but also checks if the other object is also an instance of a String. The String#contentEquals() methods only compares the contents (the character sequence) and does not check if the other object is also an instance of String. It can be anything as long as it is an implementation of CharSequence or an instance of StringBuffer.
For have the system language:
Locale.getDefault().getDisplayLanguage();
As everyone already explain that i18N (String XMLs in different languages) have to be used to achieve this simple thing but if you are looking for user language for some other purpose then please use one of this.
Locale.getDefault().getLanguage();
This will give language iso code i.e. "de", "ru".
OR
Resources.getSystem().getConfiguration().locale;
This returns global shared Resources object that provides access to only system resources.
You could solve this by declaring a string resource file for each language.
Create resource folders named values-fr and values-en and add a file called strings.xml to both folders.
The string.xml file in values-en:
<resources>
<string name="good">That is great </string>
</resources>
And you load the resource like this:
yourYesResponse = getResources().getText(R.string.good) + usersName + "!";
Niek was faster...
Usually locale is provided with followig format fr_FR where first fr is language code and second one is country code, thats why you should use
Locale.getDefault().getLanguage().startsWith("fr")
but Android way is to use resources
getString(R.string.hello, userName);
Edited: Ok, shame on me, I didn't notice that you call getLanguage(), but second part is correct.
The Android way of doing this, is using xml resources, as explained in Localizing with Resources.
values/strings.xml:
<resources>
<string name="yes_response">That is great, %s!</string>
</resources>
values-fr/strings.xml:
<resources>
<string name="yes_response">C\'est bon, %s!</string>
</resources>
Code:
yourYesResponse = context.getString(R.string.yes_response, usersName);
Motivation:
It is good practice to use the Android resource framework to separate
the localized aspects of your application as much as possible from the
core Java functionality:
You can put most or all of the contents of your application's user
interface into resource files, as described in this document and in
Providing Resources.
The behavior of the user interface, on the other
hand, is driven by your Java code. For example, if users input data
that needs to be formatted or sorted differently depending on locale,
then you would use Java to handle the data programmatically. This
document does not cover how to localize your Java code.

Camel: How to include an ampersand as data in a URI (NOT as a delimiter)?

(Camel 2.9.2)
Very simple use case, but I can't seem to find the answer. My code boils down to this:
String user = "user";
String password = "foo&bar";
String uri = "smtp://hostname:25?username=" + user +
"&password=" + password +
"&to=somthing#something.com"; // etc. You get the idea
from("seda:queue:myqueue").to(uri);
Camel throws a ResolveEndpointFailedException with "Unknown parameters=[{bar=null}]."
If I try "foo%26bar," I get the same result.
If I try "foo&bar" camel responds with "Unknown parameters=[{amp;bar=null}]."
I tried using URISupport to create the URI. It escapes the & to %26, and then I get "Unknown parameters=[{bar=null}]" again.
Any ideas?
As from Camel 2.11 you could use raw syntax
For instance:
.to("ftp:joe#myftpserver.com?password=RAW(se+re?t&23)&binary=true"
In the above example, we have declare the password value as raw, and
the actual password would be as typed, eg se+re?t&23
https://cwiki.apache.org/confluence/display/CAMEL/How+do+I+configure+endpoints
You can specify the password as part of the authority of the uri, eg in the front.
Also the & should be escaped to %26, but there was a bug in Camel that didnt parse the escaped value to well. Try 2.10 when its out.
The RAW() syntax works, yet it is Camel-proprietary syntax. In our usecase it burdened following processing of URI.
We used alternative solution: component configured as using raw URIs (Component.useRawUri() == true). Component parameters are then simply once encoded (foo%26bar) and pass through Camel without change. I consider this solution better as percent-sign encoding is standard way of expressing sensitive characters.

How do I reverse route a static file?

At first I had this link to a twitter icon:
#{'/public/images/twitter-icon.png'/}
But now I want to show a Twitter-, Facebook- or LinkedIn icon depending on type. So, I created a FastTag that takes the type as a parameter and the code looks like this:
In the view:
#{myApp.icon contact.type/}
FastTag Java Code:
String type = (String) args.get("arg");
out.print("/public/images/" + type + "-icon.png");
It works fine. But, on our build server we run the app with a prefix on the uri like this
http://ourdomain.com/appname/...
Obviously /public/images... won't work here. So I figured I have to ask the Router for the proper address. I've tried the following with no success:
Router.reverse("/public/images/" + type + "-icon.png");
Router.reverse("/public/");
Router.reverse("staticDir:public");
All three result in a NoRouteFoundException. How can I get the correct route for my icons?
In the routes file I have the default route for static files
GET /public/ staticDir:public
I believe this is what you want:
String imageUrl = Router.reverse(VirtualFile.fromRelativePath("public/images/" + type + "-icon.png"));
Router.reverse be used generate URL form one action!
maybe you can define a route which include your app name and route one action eg:
GET /appname/public/ TestController.test
now,you can use
Router.reverse("TestController.test")
get the URL.
I think it's better to do something like:
GET /img/ staticDir:public/images
And in the template just:
out.print("/img/" + type + "-icon.png");

Do resource bundles in Java support runtime string substitution?

Can you do the following with a Java ResourceBundle?
In the properties file...
example.dynamicresource=You currently have {0} accounts.
At runtime...
int accountAcount = 3;
bundle.get("example.dynamicresource",accountCount,param2,...);
To give a result of
"You currently have 3 accounts."
Not without using the MessageFormat class, such as:
String pattern = bundle.getString("example.dynamicresource");
String message = MessageFormat.format(pattern, accountCount);
On their own, ResourceBundle does not support property placeholders. The usual idea is to take the String you get from the bundle, and stick it into a MessageFormat, and then use that to get your parameterized message.
If you're using JSP/JSTL, then you can combine <fmt:message> and <fmt:param> to do this, which uses ResourceBundle and MessageFormat under the covers.
If you happen to be using Spring, then it has the ResourceBundleMessageSource which does something similar, and can be used anywhere in your program. This MessageSource abstraction (combined with MessageSourceAccessor) is much nicer to use than ResourceBundle.
There are various ways, depending on the view technology you're using. If you're using "plain vanilla" Java (e.g. Swing), then use MessageFormat API as answered before. If you're using a webapplication framework (which is true, if I judge your question history here correctly), then the way depends on the view technology and/or MVC framework you're using. If it is for example "plain vanilla" JSP, then you can use JSTL fmt:message for this.
<fmt:message key="example.dynamicresource">
<fmt:param value="${bean.accountCount}">
</fmt:message>
If it is for example JSF, you can use h:outputFormat for this.
<h:outputFormat value="#{bundle['example.dynamicresource']}">
<f:param value="#{bean.accountCount}">
</h:outputFormat>
Best place is to just consult the documentation of the technology/framework you're using (or to tell it here so that we can give better suited and more detailed answers).
Struts have a nice util called MessageResources which does exactly what you ask for....
e.g.
MessageResources resources = getResources(request, "my_resource_bundle"); // Call your bundle exactly like ResourceBundle.getBundle() method
resources.getMessage("example.dynamicresource",accountCount,param2,...);
Limitation
It only allows maximum of 3 parameters (i.e. resource attribute, param1, ..., param3).
I suggest using MessageFormat (if you want to use more than 3 parameter values) as suggested by David Sykes.
PS the getResources method is available only in the Struts Action class.
I don't think you can make this work for Non-English properties file.
My message.properties file has the following line:
info.fomat.log.message.start=Starting to parse log message in {0} format.
And my message_fr_FR.properties file has the following line:
info.fomat.log.message.start=A partir d'analyser le message connecter {0} format.
This code works only for the English one
String.format((String) messages .getString(GlobalConstants.MESSAGE_FORMAT_START), GlobalConstants.STR_JSON));
It does NOT replace the placeholder with the value when my language / locale is French :-(
Even MessageFormat.fomat() is no good
I don't believe ResourceBundle can do that itself, but String can:
String.format(bundle.getString("example.dynamicresource"), accountCount);
Remember that when using MessageFormat.format() you need to use a double quote ('') in your resource bundle if you want to express single quote (').
MessageFormoat#format will work for the case like:
greetingTo=Have Param, saying hello {0}
You can declare two methods like this where RB is a instance of ResourceBundle:
/**This is a method that takes the param to substitute the placeholder**/
public String getString(String key, Object... params ) {
try {
return MessageFormat.format(this.RB.getString(key), params);
} catch (MissingResourceException e) {
return "[" + key + "]";
}
}
/**Without a param, this will derectly delegate to ResourceBundle#getString**/
public String getString(String key) {
try {
return this.RB.getString(key);
} catch (MissingResourceException e) {
return "[" + key + "]";
}
}

Categories

Resources