package org.etk.kernel.container.xml; import java.util.Map; import org.etk.kernel.container.ApplicationContainer; import org.etk.kernel.container.KernelContainer; import org.etk.kernel.container.KernelContainerContext; import org.etk.kernel.container.RootContainer; /** * A deserializer used by JIBX that resolve system properties to allow runtime * configuration. * * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> * @version $Revision$ */ public class Deserializer { /** * The name of the variable to use to get the current container name as a * suffix if the current container is a portal container, the value of the * variable will be "-${portal-container-name}", it will be an empty String * otherwise */ public static final String EXO_CONTAINER_PROP_NAME = "container.name.suffix"; /** * The prefix of the name of all the variables tied to the current portal * container */ public static final String PORTAL_CONTAINER_VARIABLE_PREFIX = "portal.container."; /** * Resolve a string value. If the input value is null then the returned * value is null. * * @param s * the input value * @return the resolve value */ public static String resolveString(String s) { return Deserializer.resolveNClean(s); } /** * Resolve a boolean value with the following algorithm: * <ol> * <li>Resolve any system property in the input value</li> * <li>If the input value is null then the returned value is null</li> * <li>If the value is equals to the string litteral true ignoring the case * then true is returned</li> * <li>If the value is equals to the string litteral false ignoring the case * then false is returned</li> * <li>Otherwise an <code>IllegalArgumentException</code> is thrown</li> * </ol> * * @param s * the input value * @return the resolve value * @throws IllegalArgumentException * if the argument is not correct */ public static Boolean resolveBoolean(String s) throws IllegalArgumentException { if (s == null) { return null; } s = Deserializer.resolveNClean(s); if (s.equalsIgnoreCase("true")) { return true; } else if (s.equalsIgnoreCase("false")) { return false; } throw new IllegalArgumentException("Cannot accept boolean value " + s); } /** * Resolve an integer value with the following algorithm: * <ol> * <li>Resolve any system property in the input value</li> * <li>Attempt to parse the value using the {@link Integer#parseInt(String)} * method and returns its value.</li> * <li>If the parsing fails then throws an * <code>IllegalArgumentException</code></li> * </ol> * * @param s * the input value * @return the resolve value * @throws IllegalArgumentException * if the argument is not correct */ public static Integer resolveInteger(String s) throws IllegalArgumentException { if (s == null) { return null; } s = Deserializer.resolveNClean(s); try { return Integer.parseInt(s); } catch (NumberFormatException e) { throw new IllegalArgumentException("Cannot accept integer value " + s, e); } } /** * Resolve a long value with the following algorithm: * <ol> * <li>Resolve any system property in the input value</li> * <li>Attempt to parse the value using the {@link Long#parseLong(String)} * method and returns its value.</li> * <li>If the parsing fails then throws an * <code>IllegalArgumentException</code></li> * </ol> * * @param s * the input value * @return the resolve value * @throws IllegalArgumentException * if the argument is not correct */ public static Long resolveLong(String s) throws IllegalArgumentException { if (s == null) { return null; } s = Deserializer.resolveNClean(s); try { return Long.parseLong(s); } catch (NumberFormatException e) { throw new IllegalArgumentException("Cannot accept integer value " + s, e); } } /** * Resolve a double value with the following algorithm: * <ol> * <li>Resolve any system property in the input value</li> * <li>Attempt to parse the value using the * {@link Double#parseDouble(String)} method and returns its value.</li> * <li>If the parsing fails then throws an * <code>IllegalArgumentException</code></li> * </ol> * * @param s * the input value * @return the resolve value * @throws IllegalArgumentException * if the argument is not correct */ public static Double resolveDouble(String s) throws IllegalArgumentException { if (s == null) { return null; } s = Deserializer.resolveNClean(s); try { return Double.parseDouble(s); } catch (NumberFormatException e) { throw new IllegalArgumentException("Cannot accept integer value " + s, e); } } /** * Resolve the variables of type ${my.var} for the current context which is * composed of the system properties and the portal container settings * * @param input * the input value * @return the resolve value */ public static String resolveVariables(String input) { return resolveVariables(input, null); } /** * Resolve the variables of type ${my.var} for the current context which is * composed of the system properties, the portal container settings and the * given settings * * @param input * the input value * @param props * a set of parameters to add for the variable resolution * @return the resolve value */ public static String resolveVariables(String input, Map<String, Object> props) { final int NORMAL = 0; final int SEEN_DOLLAR = 1; final int IN_BRACKET = 2; if (input == null) return input; char[] chars = input.toCharArray(); StringBuffer buffer = new StringBuffer(); boolean properties = false; int state = NORMAL; int start = 0; for (int i = 0; i < chars.length; ++i) { char c = chars[i]; if (c == '$' && state != IN_BRACKET) state = SEEN_DOLLAR; else if (c == '{' && state == SEEN_DOLLAR) { buffer.append(input.substring(start, i - 1)); state = IN_BRACKET; start = i - 1; } else if (state == SEEN_DOLLAR) state = NORMAL; else if (c == '}' && state == IN_BRACKET) { if (start + 2 == i) { buffer.append("${}"); } else { String value = null; String key = input.substring(start + 2, i); if (key.equals(Deserializer.EXO_CONTAINER_PROP_NAME)) { // The requested key is the name of current container KernelContainer container = KernelContainerContext .getCurrentContainerIfPresent(); if (container instanceof ApplicationContainer) { // The current container is a portal container RootContainer rootContainer = (RootContainer) KernelContainerContext .getTopContainer(); value = rootContainer.isPortalContainerConfigAware() ? "_" + container.getContext().getName() : ""; } } else if (key.startsWith(Deserializer.PORTAL_CONTAINER_VARIABLE_PREFIX)) { // We try to get a value tied to the current portal // container. KernelContainer container = KernelContainerContext .getCurrentContainerIfPresent(); if (container instanceof ApplicationContainer) { // The current container is a portal container Object oValue = ((ApplicationContainer) container) .getSetting(key.substring(Deserializer.PORTAL_CONTAINER_VARIABLE_PREFIX .length())); value = oValue == null ? null : oValue.toString(); } } else { if (props != null) { // Some parameters have been given thus we need to // check inside first Object oValue = props.get(key); value = oValue == null ? null : oValue.toString(); } if (value == null) { // No value could be found so far, thus we try to // get it from the // system properties value = System.getProperty(key); } } if (value != null) { properties = true; buffer.append(value); } } start = i + 1; state = NORMAL; } } if (properties == false) return input; if (start != chars.length) buffer.append(input.substring(start, chars.length)); return buffer.toString(); } /** * This methods will remove useless characters from the given {@link String} * and return the result * * @param s * the input value * @return <code>null</code> if the input value is <code>null</code>, * <code>s.trim()</code> otherwise */ public static String cleanString(String s) { return s == null ? null : s.trim(); } /** * This method will first resolves the variables then it will clean the * results * * @param s * the input value * @return the resolve and clean value */ public static String resolveNClean(String s) { return cleanString(resolveVariables(s)); } }