/*
* sulky-resources - inheritance-safe class resources.
* Copyright (C) 2002-2011 Joern Huxhorn
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2002-2011 Joern Huxhorn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.huxhorn.sulky.resources;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DOCUMENT: <code>LocalizableFactory</code>
*/
public final class LocalizableFactory
{
/**
* No instances...
*/
private LocalizableFactory()
{
}
/**
* Returns a Localizable for the given object no matter
* what <code>object</code> really is.
* If <code>object</code> implements the <code>Localizable</code>
* interface it's simply casted and returned. Otherwise a proxy is
* created. The proxy calls the objects <code>getLocale</code> and
* <code>setLocale</code> methods if they are available. Otherwise
* <code>setLocale</code> does nothing and <code>getLocale</code>
* always returns <code>null</code>.
*
* @param object the <code>object</code> that will be either casted or wrapped.
* @return either the original <code>object</code> or a proxy wrapping the given <code>object</code>.
* @throws NullPointerException if <code>object</code> is <code>null</code>.
*/
public static Localizable getLocalizable(Object object)
{
final Logger logger = LoggerFactory.getLogger(MapLoader.class);
Class<?> clazz = object.getClass();
Localizable loc;
if(object instanceof Localizable)
{
loc = (Localizable) object;
if(logger.isDebugEnabled()) logger.debug("Casting to Localizable.");
}
else
{
// Important! Use the objects classloader so proxy's may be unloaded as well...
loc = (Localizable)
Proxy.newProxyInstance(clazz.getClassLoader(),
new Class<?>[]{Localizable.class}, new LocalizableInvocationHandler(object));
if(logger.isDebugEnabled()) logger.debug("Created Localizable proxy.");
}
return loc;
}
private static class LocalizableInvocationHandler
implements InvocationHandler
{
private final Logger logger = LoggerFactory.getLogger(LocalizableInvocationHandler.class);
public static final String GETTER_NAME = "getLocale";
public static final String SETTER_NAME = "setLocale";
private final Object object;
private final Method getter;
private final Method setter;
LocalizableInvocationHandler(Object obj)
{
this.object = obj;
Class<?> clazz = obj.getClass();
Method m = null;
try
{
m = clazz.getMethod(GETTER_NAME);
}
catch(NoSuchMethodException ex)
{
if(logger.isInfoEnabled()) logger.info("getLocale-method not found...");
}
this.getter = m;
m = null;
try
{
m = clazz.getMethod(SETTER_NAME, Locale.class);
}
catch(NoSuchMethodException ex)
{
if(logger.isInfoEnabled()) logger.info("setLocale-method not found...");
}
this.setter = m;
}
public Object invoke(Object proxy, Method method, Object[] args)
// see java.lang.reflect.InvocationHandler, yeah, right :p - Illegal Throws : Throwing 'Throwable' is not allowed.
throws Throwable
{
try
{
if(logger.isDebugEnabled())
{
logger.debug("Calling method '" + method + "' on instance of class '" + object.getClass()
.getName() + "' with proxy '" + proxy.getClass() + "'.");
}
if(getter != null && GETTER_NAME.equals(method.getName()))
{
Object result = getter.invoke(object, args);
if(logger.isDebugEnabled()) logger.debug("Call-Result: {}", result);
return result;
}
else if(setter != null && SETTER_NAME.equals(method.getName()))
{
return setter.invoke(object, args);
}
}
catch(Throwable t)
{
if(logger.isWarnEnabled()) logger.warn("Throwable while invoking proxy-method!", t);
throw t;
}
return null;
}
}
}