/**
* 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.services.resources;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import org.exoplatform.commons.utils.IOUtil;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
/**
* A {@link ClassLoader} extension that will retrieve resources from the parent classloader. For each resource having a
* ".properties" suffix it the classloader will try first to locate a corresponding resource using the same base name but with
* an ".xml" suffix. If such a resource is found, it will be loaded using {@link XMLResourceBundleParser}
*
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
* @version $Revision$
*/
public class PropertiesClassLoader extends ClassLoader {
/**
* Logger.
*/
private static final Log LOG = ExoLogger.getLogger(PropertiesClassLoader.class);
/**
* Indicates whether the resource must be encoded into UTF-8
*/
private boolean unicode;
public PropertiesClassLoader(ClassLoader parent) {
this(parent, false);
}
public PropertiesClassLoader(ClassLoader parent, boolean unicode) {
super(parent);
this.unicode = unicode;
}
public PropertiesClassLoader() {
}
@Override
public URL getResource(String name) {
if (name.endsWith(".properties")) {
URL url = null;
ClassLoader parent = getParent();
while (parent != null) {
url = getResource(parent, name, unicode);
if (url != null) {
return url;
}
parent = parent.getParent();
}
if (url == null) {
url = getResource(this, name, unicode);
}
return url;
}
return super.getResource(name);
}
private static URL getResource(ClassLoader cl, String name, boolean unicode) {
String xmlName = name.substring(0, name.length() - ".properties".length()) + ".xml";
URL url = getResource(cl, xmlName, unicode, true);
if (url == null) {
url = getResource(cl, name, unicode, false);
}
return url;
}
private static URL getResource(ClassLoader cl, String name, boolean unicode, boolean xml) {
Enumeration<URL> urls = null;
try {
urls = cl.getResources(name);
} catch (Exception e) {
LOG.error("An error occured while seeking all the resources with the name " + name, e);
return null;
}
if (urls != null && urls.hasMoreElements()) {
// At least one such resource has been found
ByteArrayOutputStream out = new ByteArrayOutputStream();
URL url = null;
Map<Object, Object> props = unicode ? new TreeMap<Object, Object>() : new Properties();
while (urls.hasMoreElements()) {
url = urls.nextElement();
InputStream in = null;
try {
// Load content
in = url.openStream();
if (xml) {
props.putAll(XMLResourceBundleParser.asProperties(in));
} else {
byte[] buf = IOUtil.getStreamContentAsBytes(in);
ExoResourceBundle bundle = new ExoResourceBundle(new String(buf, "UTF-8"));
bundle.putAll(props);
}
} catch (Exception e) {
LOG.error("An error occured while loading the content of " + url, e);
return null;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// Do nothing
}
}
}
}
try {
// Now serialize as binary
if (unicode) {
// Encoded into UTF-8
for (Map.Entry<Object, Object> entry : props.entrySet()) {
out.write(((String) entry.getKey()).getBytes("UTF-8"));
out.write('=');
out.write(((String) entry.getValue()).getBytes("UTF-8"));
out.write('\n');
}
} else {
// Properties format : encoded into ISO-8859-1 with unicode characters
((Properties) props).store(out, null);
}
out.close();
InputStream in = new ByteArrayInputStream(out.toByteArray());
//
return new URL(url, "", new InputStreamURLStreamHandler(in));
} catch (Exception e) {
LOG.error("An error occured while creating the content of " + url, e);
return null;
}
}
return null;
}
}