package org.marketcetera.util.l10n;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang.SystemUtils;
import org.marketcetera.util.except.I18NException;
import org.marketcetera.util.misc.ClassVersion;
/**
* A comparator of two message meta-information holders.
*
* @author tlerios@marketcetera.com
* @since 0.6.0
* @version $Id: MessageComparator.java 16154 2012-07-14 16:34:05Z colin $
*/
/* $License$ */
@ClassVersion("$Id: MessageComparator.java 16154 2012-07-14 16:34:05Z colin $")
public class MessageComparator
{
// INSTANCE DATA.
private MessageInfoPair[] mMismatches;
private MessageInfo[] mExtraSrcInfo;
private MessageInfo[] mExtraDstInfo;
// CONSTRUCTORS.
/**
* Creates a new comparator for the given meta-information. For
* both parameters, the order of list elements is unimportant.
*
* @param srcInfo The source meta-information.
* @param dstInfo The destination meta-information.
*/
public MessageComparator
(List<MessageInfo> srcInfo,
List<MessageInfo> dstInfo)
{
// Analyze source and destination.
HashMap<String,MessageInfo> srcMessages=toHashMap(srcInfo);
HashMap<String,MessageInfo> dstMessages=toHashMap(dstInfo);
// Compare.
LinkedList<MessageInfoPair> mismatches=
new LinkedList<MessageInfoPair>();
LinkedList<MessageInfo> extraSrcInfo=new LinkedList<MessageInfo>();
for (String name:srcMessages.keySet()) {
MessageInfo srcMessage=srcMessages.get(name);
// Message missing from destination.
if (!dstMessages.containsKey(name)) {
extraSrcInfo.add(srcMessage);
continue;
}
// Message exists in both source and destination, but
// parameter count differs.
MessageInfo dstMessage=dstMessages.get(name);
if ((srcMessage.getParamCount()!=-1) &&
(dstMessage.getParamCount()!=-1) &&
(srcMessage.getParamCount()!=dstMessage.getParamCount())) {
mismatches.add(new MessageInfoPair(srcMessage,dstMessage));
}
dstMessages.remove(name);
}
// Retain results.
mMismatches=mismatches.toArray(MessageInfoPair.EMPTY_ARRAY);
mExtraSrcInfo=extraSrcInfo.toArray(MessageInfo.EMPTY_ARRAY);
mExtraDstInfo=dstMessages.values().toArray(MessageInfo.EMPTY_ARRAY);
}
/**
* Creates a new comparator for the given meta-information
* providers.
*
* @param srcProvider The source meta-information provider.
* @param dstProvider The destination meta-information provider.
*/
public MessageComparator
(MessageInfoProvider srcProvider,
MessageInfoProvider dstProvider)
{
this(srcProvider.getMessageInfo(),dstProvider.getMessageInfo());
}
/**
* Creates a new comparator for the given container class
* meta-information and the properties file deduced from the
* container's message provider and the given locale.
*
* @param classInfo The meta-information of a container class.
* @param locale The locale. Use {@link Locale#ROOT} for the
* fallback properties file.
*
* @throws I18NException Thrown if there is a problem obtaining
* the meta-information of the properties file.
*/
private MessageComparator
(ContainerClassInfo classInfo,
Locale locale)
throws I18NException
{
this(classInfo,
new PropertiesFileInfo(classInfo.getProvider(),locale));
}
/**
* Creates a new comparator for the given container class
* meta-information and the properties file deduced from the
* container's message provider.
*
* @param classInfo The meta-information of a container class.
*
* @throws I18NException Thrown if there is a problem obtaining
* the meta-information of the properties file.
*/
public MessageComparator
(ContainerClassInfo classInfo)
throws I18NException
{
this(classInfo,Locale.ROOT);
}
/**
* Creates a new comparator for the given container class and the
* properties file deduced from the class's message provider and
* the given locale.
*
* @param container The class.
* @param locale The locale. Use {@link Locale#ROOT} for the
* fallback properties file.
*
* @throws I18NException Thrown if there is a problem obtaining
* the meta-information of either the container or the properties
* file.
*/
public MessageComparator
(Class<?> container,
Locale locale)
throws I18NException
{
this(new ContainerClassInfo(container),locale);
}
/**
* Creates a new comparator for the given container class and the
* fallback properties file deduced from the class's message
* provider.
*
* @param container The class.
*
* @throws I18NException Thrown if there is a problem obtaining
* the meta-information of either the container or the properties
* file.
*/
public MessageComparator
(Class<?> container)
throws I18NException
{
this(new ContainerClassInfo(container));
}
// INSTANCE METHODS.
/**
* Converts the given meta-information list into a map, with the
* map keys being the message keys.
*
* @param infoList The meta-information in list form.
*
* @return The map.
*/
private HashMap<String,MessageInfo> toHashMap
(List<MessageInfo> infoList)
{
HashMap<String,MessageInfo> result=new HashMap<String,MessageInfo>();
for (MessageInfo info:infoList) {
result.put(info.getKey(),info);
}
return result;
}
/**
* Returns the receiver's mismatches. A mismatch occurs when two
* message keys are present in both source and destination, and
* both have known but different parameter counts.
*
* @return The mismatches.
*/
public MessageInfoPair[] getMismatches()
{
return mMismatches;
}
/**
* Returns the receiver's list of source meta-information that is
* absent from the destination.
*
* @return The list.
*/
public MessageInfo[] getExtraSrcInfo()
{
return mExtraSrcInfo;
}
/**
* Returns the receiver's list of destination meta-information
* that is absent from the source.
*
* @return The list.
*/
public MessageInfo[] getExtraDstInfo()
{
return mExtraDstInfo;
}
/**
* Checks whether the receiver found no differences between source
* and destination.
*
* @return True if so.
*/
public boolean isMatch()
{
return ((getMismatches().length==0) &&
(getExtraSrcInfo().length==0) &&
(getExtraDstInfo().length==0));
}
/**
* Returns a textual form of the differences between source and
* destination.
*
* @return The differences. This is the empty string if there are
* no differences.
*/
public String getDifferences()
{
StringBuilder builder=new StringBuilder();
for (MessageInfoPair mismatch:getMismatches()) {
if (builder.length()>0) {
builder.append(SystemUtils.LINE_SEPARATOR);
}
builder.append
(Messages.PARAM_COUNT_MISMATCH.getText
(mismatch.getSrcInfo().getKey(),
mismatch.getSrcInfo().getParamCount(),
mismatch.getDstInfo().getParamCount()));
}
for (MessageInfo info:getExtraSrcInfo()) {
if (builder.length()>0) {
builder.append(SystemUtils.LINE_SEPARATOR);
}
builder.append(Messages.EXTRA_SRC_MESSAGE.getText(info.getKey()));
}
for (MessageInfo info:getExtraDstInfo()) {
if (builder.length()>0) {
builder.append(SystemUtils.LINE_SEPARATOR);
}
builder.append(Messages.EXTRA_DST_MESSAGE.getText(info.getKey()));
}
return builder.toString();
}
}