/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.container.xml;
import org.exoplatform.commons.utils.PrivilegedSystemHelper;
import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.RootContainer;
import java.util.Map;
/**
* 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();
StringBuilder buffer = new StringBuilder();
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);
String defaultValue = null;
int index = key.indexOf(':');
if (index > -1)
{
defaultValue = key.substring(index + 1);
key = key.substring(0, index);
}
if (key.equals(Deserializer.EXO_CONTAINER_PROP_NAME))
{
// The requested key is the name of current container
ExoContainer container = ExoContainerContext.getCurrentContainerIfPresent();
if (container instanceof PortalContainer)
{
// The current container is a portal container
RootContainer rootContainer = (RootContainer)ExoContainerContext.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.
ExoContainer container = ExoContainerContext.getCurrentContainerIfPresent();
if (container instanceof PortalContainer)
{
// The current container is a portal container
Object oValue =
((PortalContainer)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 = PrivilegedSystemHelper.getProperty(key);
}
}
if (value == null && defaultValue != null)
{
value = defaultValue;
}
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));
}
}