Log4J & Email
Among other appenders, Log4J comes with an SMTP appender that is dramatically useful when you need to alert someone of an event; here's two examples :
- Using unsecured connection
- Using secure connection, such as SSL or TLS.
Using unsecured connection
In order to use a simple and unsecured smpt server, all you have to do is configure log4j.properties so that it includes something like this
log4j.appender.SENDMAIL.To = A_USER@SOMEWHERE.SOMETHING
log4j.appender.SENDMAIL.From = system.alert@fermasoft.com
log4j.appender.SENDMAIL.SMTPHost = some.unsecured.smtp
#some servers do not use the default port : change this as you need
log4j.appender.SENDMAIL.SMTPPort = 25
log4j.appender.SENDMAIL.SMTPDebug = true
log4j.appender.SENDMAIL.SMTPPassword=XXXXXXXX
log4j.appender.SENDMAIL.SMTPUsername=XXXXXXXX
# the maximum number of logging events to collect in a cyclic buffer
log4j.appender.SENDMAIL.BufferSize = 1
log4j.appender.SENDMAIL.LocationInfo = true
log4j.appender.SENDMAIL.Subject = "System Error"
log4j.appender.SENDMAIL.layout = org.apache.log4j.PatternLayout
log4j.appender.SENDMAIL.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} %c{1} [%p] %m%n
and the job is done
Using Secure Connection
The problem comes when your mailserver uses secure connection as TLS or SSL, then you need to add the following javax.mail.Session properties:
System.setProperty("mail.smtp.socketFactory.port", "465");
System.setProperty("mail.smtp.socketFactory.fallback", "false");
so that the following configuration snippet can actually work :
log4j.appender.SMTP=org.apache.log4j.net.SMTPAppender
# the maximum number of logging events to collect in a cyclic buffer
log4j.appender.SMTP.BufferSize=1
log4j.appender.SMTP.From=system.alert@fermasoft.com
log4j.appender.SMTP.LocationInfo=true
log4j.appender.SMTP.SMTPDebug=true
log4j.appender.SMTP.SMTPHost=smtp.gmail.com
log4j.appender.SMTP.SMTPPassword=PASSWORD
log4j.appender.SMTP.SMTPUsername=USER@gmail.com
log4j.appender.SMTP.Subject=System Error
log4j.appender.SMTP.To=A_USER@SOMEWHERE.SOMETHING
Happy logging !
Liferay 5.2.3 javascript injection vulnerability
According to liferay's Jira LPS-5545 is still open and affects liferay 5.2.3 .
I tested the above vulnerability onto Liferay 6 and it looks like this problem was fixed. I looked at the code and what it does ... and it came out that everything you need to prevent this issue is already there in L5 too.
The short path
simply use unix patch to apply this patch ( Attach:LanguageImpl.java.patch ), recompile and generate portal-impl.jar and live happy.
What it does
The patch checks the language id parameter against a white list of languages (namely _localesMap and _charEncodings ) that are already there; we slightly modify the constructor in order to make sure the maps are filled :
String[] localesArray = PropsValues.LOCALES;
_locales = new Locale[localesArray.length];
_localesSet = new HashSet<Locale>(localesArray.length);
_localesMap = new HashMap<String, Locale>(localesArray.length);
_charEncodings = new HashMap<String, String>();
for (int i = 0; i < localesArray.length; i++) {
String languageId = localesArray[i];
int pos = languageId.indexOf(StringPool.UNDERLINE);
String language = languageId.substring(0, pos);
//String country = languageId.substring(pos + 1);
Locale locale = LocaleUtil.fromLanguageId(languageId);
_charEncodings.put(locale.toString(), StringPool.UTF8); // backport of white list of language ids
_locales[i] = locale;
if (!_localesMap.containsKey(language)) {//backport of white list of language ids
_localesMap.put(language, locale);
}
_localesSet.add(locale);
//_localesMap.put(language, locale);//backport of white list of language ids
_charEncodings.put(locale.toString(), StringPool.UTF8);
}
}
and add the check
in
just before returning the language id :
String languageId = ParamUtil.getString(request, "languageId");
if (Validator.isNotNull(languageId)) {
if (_localesMap.containsKey(languageId) || _charEncodings.containsKey(languageId)) {// backport of white list of language ids
return languageId;
}
}
Locale locale = PortalUtil.getLocale(request);
return getLanguageId(locale);
}
Happy patching folks !
Dynamic java.library.path HowTo
on August 09, 2011, at 09:00 AM
Sometimes you need to use native libraries in order to accomplish some tasks ( e.g. : statistics ) that, if written in Java, take more time than they should. The "classic" way of loading a native library is to use one of the following Java call
Runtime.getRuntime().loadLibrary(String s); Runtime.getRuntime().load(String s); that are exactly equivalent to System.loadLibrary(String s); System.load(String s);
The main difference between the two calls is that load(String s) needs an absolute path, while loadLibrary the "core name" of the library that is then resolved by the underlying operating system into a library file. For example, if we wanted to use the library "TestJni" the call
would be resolved into looking for the library file
Windows: TestJni.dll Unix: libTestJni.so
and that file would be looked up in the directories specified in the system variable java.library.path
I prefer loading a library calling the core name because doing so I can create and compile the same native library for as many O.S. as I need to run my software on and load those libraries always in the same way regardless of the platform the software is running onto. The caveats of this method, though, are that of actually finding and loading the library.
There are, in the Java language, three strategies that can be used to achieve this task :
- copy the native library into the default O.S. system paths
- setting the java.library.path variable at JVM startup
- copy the native library in a predefined path within the software and use the System.load call
The main problem with solution 1 is that you can't always suppose that the person installing your software will have the privileges to write in the system library directories; solution 2 consists of firing the Java Vitual Machine with the parameter
-Djava.library.path=path_to_the_directory_where_your_library_is_sitting
doable, but ugly ( IMHO ) especially if you think that modern S.O. can run a jar file ( if it contains a main(String[] args) method by double clicking it.
Solution number 3 implies that java.library.path is modified before you try to load the native library; apart form that, it permits to install/copy all the necessary libraries and jars your application depends on in, my personal flavor, ./lib without having to care where that directory will actually be copied by the installer .
In order to modify java.library.path you need to resolve the absolute path of the "./lib" directory :
Logger.getLogger(getClass()).debug("determining running path");
URL url = Utils.class.getProtectionDomain().getCodeSource().getLocation();
File file;
try {
file = new File(url.toURI().getPath());
} catch (URISyntaxException e) {
file = new File(url.getPath());
}
Logger.getLogger(Utils.class).debug("resolved running path : " + file.getAbsolutePath());
if (file.isDirectory()) {
return file.getAbsolutePath();
} else {
return getPath(file);
}
}
public String getPath(File file) {
Logger.getLogger(Utils.class).debug("resolving path for " + file.getName());
if (file.isDirectory()) {
Logger.getLogger(Utils.class).debug(file.getName() + " is a directory so the running path is "+ file.getAbsolutePath() + File.separator);
return file.getAbsolutePath() + File.separator;
}
String path = file.getAbsolutePath();
path = path.substring(0, path.lastIndexOf(file.getName()));
Logger.getLogger(Utils.class).debug(
file.getName() + " is a file so the running path is " + path);
return path;
}
The method getRunningPath returns the path where the Java Virtual Machine was fired from. If we kept the example nomenclature, out library directory will be
The method that changes the system variable java.library.path is
try {
// This enables the java.library.path to be modified at runtime
// From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176
//
Field field = ClassLoader.class.getDeclaredField("usr_paths");
field.setAccessible(true);
String[] paths = (String[])field.get(null);
for (int i = 0; i < paths.length; i++) {
if (s.equals(paths[i])) {
return;
}
}
String[] tmp = new String[paths.length+1];
System.arraycopy(paths,0,tmp,0,paths.length);
tmp[paths.length] = s;
field.set(null,tmp);
System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s);
} catch (IllegalAccessException e) {
throw new IOException("Failed to get permissions to set library path");
} catch (NoSuchFieldException e) {
throw new IOException("Failed to get field handle to set library path");
}
}
Thus the main call :
this way the call
System.loadLibrary(LIBRARY_CORE_NAME);
will look up your library in ./lib too
Struts2 Convention plugin : e' quasi magia
Oggi mi era una giornata fiacca. Mi sono detto : " Guardiamo un po' di cose che mi ero lasciato da fare" e l'occhio mi e' cascato su Struts2. Intendiamoci, non che non abbia mai visto come funziona questo framwork ( chiunque lavori con Java in ambito Web prima o poi ha a che fare con Struts ), semplicemente non ero mai andato + che tanto a fondo nella versione 2 di Struts.
Ho cominciato a guardare un po' di documentazione ( l'indice ) e l'occhio mi e' caduto su Convention plugin ... e ne sono entusiasta !
Ecco un piccolo diario delle mie prove ...
Per prima cosa, mi sono creato un progetto web dinamico con Eclipse. Poi ho preso tutte le librerie dall'applicazione di esempio "struts2-rest-showcase" ... tanto per non sbagliare o avere dipendenze non risolte ( prima o poi dovro' passare a Maven, ma che ci volete fare ... sono affezionato ad Ant ! ) . Ho quindi velocemente letto la prima parte della pagina linkata prima ( Convention plugin ) e poi ho cominciato a smanettare un po' con i files delle risorse e ... senza una riga di configurazione ( apparte il caricamento del filtro per struts ) mi sono ritrovato per le mani una pagina jsp che ha associato un bean e un file di risorse che risponde in maniera dinamica !!!
Ecco il gioco spiegato in due parole : Per default Convention cerca le pagine in WEB-INF/content, quindi se create una pagina pippo.jsp qui' dentro viene automaticamente creata una azione pippo che risponde sulla root della vostra applicazione ; inoltre, il plugin cerca tutto quello che implementa com.opensymphony.xwork2.Action e lo trasforma in una azione ... o quasi . Tutto quello che si trova all'interno di <un nome package>.action o <un nome package>.actions o <un nome package>.struts diventa un azione e viene mappato a partire dal piu' "anziano" parente. Facciamo un esempio :
com.pippo.action.PippoAction viene mappato in / com.pippo.action.pippo.Paperino ( che implementa com.opensymphony.xwork2.Action ) viene mappato in /pippo/ com.pippo.struts.pippo.paperino.QuackQuackAction viene mappato in /pippo/paperino
e viene fatto senza bisogno che scriviate una riga di configurazione o mappatura !
In piu' il nome dell'azione viene interpretato secondo il camel case e la classe rispondera' a com.pippo.action.PippoAction == /pippo com.pippo.action.pippo.Paperino == /pippo/paperino com.pippo.struts.pippo.paperino.QuackQuackAction == /pippo/paperino/quack-quack
La cosa ancora piu' intrigante e' che, sempre gratis, se create le relative pagine jsp in /WEB-INF/content queste vengono associate alla view dell'azione e automaticamente bindati ai relativi JavaBean !!! E quindi :
com.pippo.action.PippoAction == /pippo == /WEB-INF/content/pippo.jsp com.pippo.action.pippo.Paperino == /pippo/paperino == /WEB-INF/content/pippo/paperino.jsp com.pippo.struts.pippo.paperino.QuackQuackAction == /pippo/paperino/quack-quack == /WEB-INF/content/pippo/paperino/quack-quack.jsp
Ed eccoci all'esempio :
HelloAction.java
package com.fermasoft.prove.convention.action; import java.text.SimpleDateFormat; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class HelloAction extends ActionSupport { public String execute(){ return SUCCESS; } public String getName(){ return "Goofy"; } public String getTime(){ SimpleDateFormat formatter = new SimpleDateFormat("HH.mm"); return formatter.format(new Date(System.currentTimeMillis())); } }
HelloAction.properties
greeting=Hello ${name} ! It's ${time} o' clock ! testing.param= ${name} you passed me {0} value=I am string coming from the class resources
package.properties
package.value=I am a string coming from the package wide resources value=I am another string coming from the package wide resources
hello.jsp
<%@ taglib prefix="s" uri="/struts-tags"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>hello convention !</title> </head> <body> <p>Testing the Convention plugin</p>
here's a greeting that takes parameters from a bean I didn't explicitly declare in this page :
<div style="font-style: italic;"> <s:text name="greeting"/> <br /> </div>
here's a parametrized text that comes from a resource bundle I didn't declare either ; the first part in the result of a call the the same bean as above, the second part is a parameter I directly passed from the page :
<div style="font-style: italic;"> <s:text name="testing.param"> <s:param value="'aValue'" /> </s:text> <br /> </div>
here's a text that comes from a package wide bundle :
<div style="font-style: italic;"><s:property value="getText('package.value')" /></div> <br /> here's a text that comes from a Class bundle that overrides the package bundle : <div style="font-style: italic;"><s:property value="getText('value')" /> </div><br /> </body> </html>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>sanity</display-name> <filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>struts.devMode</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
Recent Comments