001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.hivemind.schema.rules;
016
017import java.util.Collections;
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.commons.logging.Log;
022import org.apache.commons.logging.LogFactory;
023import org.apache.hivemind.ApplicationRuntimeException;
024import org.apache.hivemind.Element;
025import org.apache.hivemind.ErrorHandler;
026import org.apache.hivemind.HiveMind;
027import org.apache.hivemind.internal.Module;
028import org.apache.hivemind.schema.SchemaProcessor;
029import org.apache.hivemind.schema.Translator;
030import org.apache.hivemind.util.PropertyUtils;
031
032/**
033 * Static methods useful to {@link org.apache.hivemind.schema.Rule}s and
034 * {@link org.apache.hivemind.schema.Translator}s.
035 * 
036 * @author Howard Lewis Ship
037 */
038public class RuleUtils
039{
040    private static final Log LOG = LogFactory.getLog(RuleUtils.class);
041
042    /**
043     * Used to convert a {@link org.apache.hivemind.schema.Translator} initializer string of the
044     * form: <code><i>key</i>=<i>value</i>[,<i>key</i>=<i>value<i>]*</code> into a Map of
045     * keys and values. The keys and values are Strings.
046     */
047    public static Map convertInitializer(String initializer)
048    {
049        if (HiveMind.isBlank(initializer))
050            return Collections.EMPTY_MAP;
051
052        Map result = new HashMap();
053
054        int lastCommax = -1;
055        int inputLength = initializer.length();
056
057        while (lastCommax < inputLength)
058        {
059            int nextCommax = initializer.indexOf(',', lastCommax + 1);
060
061            if (nextCommax < 0)
062                nextCommax = inputLength;
063
064            String term = initializer.substring(lastCommax + 1, nextCommax);
065
066            int equalsx = term.indexOf('=');
067
068            if (equalsx <= 0)
069                throw new ApplicationRuntimeException(RulesMessages.invalidInitializer(initializer));
070
071            String key = term.substring(0, equalsx);
072            String value = term.substring(equalsx + 1);
073
074            result.put(key, value);
075
076            lastCommax = nextCommax;
077        }
078
079        return result;
080    }
081
082    /**
083     * Invoked to process text from an attribute or from an element's content. Performs two jobs:
084     * <ul>
085     * <li>Convert localized message references to localized strings
086     * <li>Expand symbols using
087     * {@link org.apache.hivemind.Registry#expandSymbols(String, Location)}
088     * </ul>
089     * <p>
090     * Note: if the input is a localized message then no symbol expansion takes place. Localized
091     * message references are simply strings that begin with '%'. The remainder of the string is the
092     * message key.
093     * <p>
094     * A null input value passes through unchanged.
095     */
096    public static String processText(SchemaProcessor processor, Element element, String inputValue)
097    {
098        if (inputValue == null)
099            return null;
100
101        Module contributingModule = processor.getContributingModule();
102
103        if (inputValue.startsWith("%"))
104        {
105            String key = inputValue.substring(1);
106
107            return contributingModule.getMessages().getMessage(key);
108        }
109
110        return contributingModule.expandSymbols(inputValue, element.getLocation());
111    }
112
113    /**
114     * Sets a property of the target object to the given value. Logs an error if there is a problem.
115     */
116    public static void setProperty(SchemaProcessor processor, Element element, String propertyName,
117            Object target, Object value)
118    {
119        try
120        {
121            PropertyUtils.write(target, propertyName, value);
122        }
123        catch (Exception ex)
124        {
125            // Have to decide if we need to display the location of the rule
126            // or the element.
127
128            ErrorHandler errorHandler = processor.getContributingModule().getErrorHandler();
129            errorHandler.error(LOG, RulesMessages.unableToSetElementProperty(
130                    propertyName,
131                    target,
132                    processor,
133                    element,
134                    ex), element.getLocation(), ex);
135        }
136    }
137
138    /**
139     * Convienience for invoking {@link Module#getTranslator(String)}.
140     * 
141     * @param processor
142     *            the processor for the schema being converted
143     * @param translator
144     *            the string identifying the translator to provide (may be null)
145     * @return a translator obtained via the contributing module, or an instance of
146     *         {@link NullTranslator}
147     */
148    public static Translator getTranslator(SchemaProcessor processor, String translator)
149    {
150        if (translator == null)
151            return new NullTranslator();
152
153        return processor.getContributingModule().getTranslator(translator);
154    }
155}