/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.deltaspike.core.impl.message;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.apache.deltaspike.core.api.literal.AnyLiteral;
import org.apache.deltaspike.core.api.message.LocaleResolver;
import org.apache.deltaspike.core.api.message.Message;
import org.apache.deltaspike.core.api.message.MessageContext;
import org.apache.deltaspike.core.api.message.MessageInterpolator;
import org.apache.deltaspike.core.api.message.MessageResolver;
import org.apache.deltaspike.core.api.message.MessageContextConfig;
import org.apache.deltaspike.core.api.message.MessageTemplate;
import org.apache.deltaspike.core.api.provider.BeanProvider;
import org.apache.deltaspike.core.util.ClassUtils;
/**
* This Proxy InvocationHandler implements the handling for all our
* {@link org.apache.deltaspike.core.api.message.MessageBundle}s.
*/
@Dependent
public class MessageBundleInvocationHandler implements InvocationHandler, Serializable
{
@Inject
private MessageContext baseMessageContext = null;
/**
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
{
if (method.getDeclaringClass().equals(Object.class))
{
// this sometimes gets invoked directly by the container
// there is no perfect solution for those methods,
// so we try to use the best info we have atm.
if ("hashCode".equals(method.getName()))
{
return proxy.getClass().hashCode();
}
if ("toString".equals(method.getName()))
{
return proxy.getClass().toString();
}
if ("equals".equals(method.getName()))
{
return proxy.getClass().equals(args[0].getClass());
}
return null;
}
final MessageTemplate messageTemplate = method.getAnnotation(MessageTemplate.class);
String messageTemplateValue;
if (messageTemplate != null)
{
messageTemplateValue = messageTemplate.value();
}
else
{
messageTemplateValue = "{" + method.getName() + "}";
}
MessageContext messageContext = resolveMessageContextFromArguments(args);
List<Serializable> arguments = resolveMessageArguments(args);
if (messageContext == null)
{
messageContext = baseMessageContext.clone();
MessageContextConfig messageContextConfig =
method.getDeclaringClass().getAnnotation(MessageContextConfig.class);
if (messageContextConfig != null)
{
applyMessageContextConfig(messageContext, messageContextConfig);
}
}
String messageBundleName = method.getDeclaringClass().getName();
Message message = messageContext
.messageSource(messageBundleName).message()
.template(messageTemplateValue)
.argument(arguments.toArray(new Serializable[arguments.size()]));
if (String.class.isAssignableFrom(method.getReturnType()))
{
return message.toString();
}
return message;
}
private void applyMessageContextConfig(MessageContext messageContext, MessageContextConfig messageContextConfig)
{
if (!MessageResolver.class.equals(messageContextConfig.messageResolver()))
{
Class<? extends MessageResolver> messageResolverClass =
ClassUtils.tryToLoadClassForName(messageContextConfig.messageResolver().getName());
messageContext.messageResolver(
BeanProvider.getContextualReference(messageResolverClass, new AnyLiteral()));
}
if (!MessageInterpolator.class.equals(messageContextConfig.messageInterpolator()))
{
Class<? extends MessageInterpolator> messageInterpolatorClass =
ClassUtils.tryToLoadClassForName(messageContextConfig.messageInterpolator().getName());
messageContext.messageInterpolator(
BeanProvider.getContextualReference(messageInterpolatorClass, new AnyLiteral()));
}
if (!LocaleResolver.class.equals(messageContextConfig.localeResolver()))
{
Class<? extends LocaleResolver> localeResolverClass =
ClassUtils.tryToLoadClassForName(messageContextConfig.localeResolver().getName());
messageContext.localeResolver(
BeanProvider.getContextualReference(localeResolverClass, new AnyLiteral()));
}
String[] messageSources = messageContextConfig.messageSource();
messageContext.messageSource(messageSources);
}
private List<Serializable> resolveMessageArguments(Object[] args)
{
List<Serializable> arguments = new ArrayList<Serializable>();
if (args != null && args.length > 0)
{
for (int i = 0; i < args.length; i++)
{
Object arg = args[i];
if (i == 0 && arg != null && MessageContext.class.isAssignableFrom(arg.getClass()))
{
continue;
}
if (arg == null)
{
arguments.add("'null'");
}
else if (arg instanceof Serializable)
{
arguments.add((Serializable) arg);
}
else
{
// for non-serializable objects we perform an immediate toString() instead
arguments.add(arg.toString());
}
}
}
return arguments;
}
private MessageContext resolveMessageContextFromArguments(Object[] args)
{
if (args != null && args.length > 0 && args[0] != null &&
MessageContext.class.isAssignableFrom(args[0].getClass()))
{
return (MessageContext) args[0];
}
return null;
}
}