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(); } }