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.parse;
016
017import java.util.ArrayList;
018import java.util.HashMap;
019import java.util.Iterator;
020import java.util.List;
021import java.util.ListIterator;
022import java.util.Map;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026import org.apache.hivemind.Element;
027import org.apache.hivemind.ErrorHandler;
028import org.apache.hivemind.schema.AttributeModel;
029import org.apache.hivemind.schema.ElementModel;
030import org.apache.hivemind.schema.Rule;
031import org.apache.hivemind.schema.SchemaProcessor;
032import org.apache.hivemind.schema.rules.BaseRule;
033import org.apache.hivemind.schema.rules.CreateObjectRule;
034import org.apache.hivemind.schema.rules.InvokeParentRule;
035import org.apache.hivemind.schema.rules.ReadAttributeRule;
036
037/**
038 * Descriptor for the <conversion> module descriptor element. This descriptor implements the
039 * {@link Rule}interface and is added as a standard rule to the containing {@link ElementModel}.
040 * When processed it delegates to a {@link CreateObjectRule}, a bunch of {@link ReadAttributeRule},
041 * and finally an {@link InvokeParentRule}.
042 * 
043 * @author Howard Lewis Ship
044 */
045public class ConversionDescriptor extends BaseRule
046{
047    private static final Log LOG = LogFactory.getLog(ConversionDescriptor.class);
048
049    private ErrorHandler _errorHandler;
050
051    private String _className;
052
053    private String _parentMethodName = "addElement";
054
055    private Map _attributeNameMappingMap = new HashMap();
056
057    /** @since 1.1 */
058    private List _attributeMappings = new ArrayList();
059
060    private List _rules;
061
062    private ElementModel _elementModel;
063
064    public ConversionDescriptor(ErrorHandler errorHandler, ElementModel elementModel)
065    {
066        _errorHandler = errorHandler;
067        _elementModel = elementModel;
068    }
069
070    /**
071     * @since 1.1
072     */
073    public List getAttributeMappings()
074    {
075        return _attributeMappings;
076    }
077
078    /**
079     * Adds a mapping for an attribute; these come from <map> elements nested within the
080     * <conversion> element. A check for duplicate attribute mappings (that is, duplicated
081     * attribute name), and an error is logged (and the duplicate ignored).
082     */
083    public void addAttributeMapping(AttributeMappingDescriptor descriptor)
084    {
085        String attributeName = descriptor.getAttributeName();
086
087        AttributeMappingDescriptor existing = (AttributeMappingDescriptor) _attributeNameMappingMap
088                .get(attributeName);
089
090        if (existing != null)
091        {
092            _errorHandler.error(
093                    LOG,
094                    ParseMessages.dupeAttributeMapping(descriptor, existing),
095                    descriptor.getLocation(),
096                    null);
097
098            return;
099        }
100
101        _attributeNameMappingMap.put(attributeName, descriptor);
102
103        _attributeMappings.add(descriptor);
104    }
105
106    /**
107     * @since 1.1
108     */
109    public String getClassName()
110    {
111        return _className;
112    }
113
114    public void setClassName(String string)
115    {
116        _className = string;
117    }
118
119    /**
120     * @since 1.1
121     */
122    public String getParentMethodName()
123    {
124        return _parentMethodName;
125    }
126
127    public void setParentMethodName(String string)
128    {
129        _parentMethodName = string;
130    }
131
132    /**
133     * @since 1.1
134     */
135    public void begin(SchemaProcessor processor, Element element)
136    {
137        for (Iterator i = _rules.iterator(); i.hasNext();)
138        {
139            Rule rule = (Rule) i.next();
140
141            rule.begin(processor, element);
142        }
143    }
144
145    /**
146     * @since 1.1
147     */
148    public void end(SchemaProcessor processor, Element element)
149    {
150        for (ListIterator i = _rules.listIterator(_rules.size()); i.hasPrevious();)
151        {
152            Rule rule = (Rule) i.previous();
153
154            rule.end(processor, element);
155        }
156    }
157
158    public void addRulesForModel()
159    {
160        _rules = new ArrayList();
161
162        _rules.add(new CreateObjectRule(_className));
163
164        addAttributeRules();
165
166        _rules.add(new InvokeParentRule(_parentMethodName));
167    }
168
169    private void addAttributeRules()
170    {
171        Iterator i = _elementModel.getAttributeModels().iterator();
172
173        while (i.hasNext())
174        {
175            AttributeModel am = (AttributeModel) i.next();
176            String attributeName = am.getName();
177
178            AttributeMappingDescriptor amd = (AttributeMappingDescriptor) _attributeNameMappingMap
179                    .get(attributeName);
180
181            if (amd == null)
182            {
183                _rules.add(new ReadAttributeRule(attributeName,
184                        constructPropertyName(attributeName), null, getLocation()));
185            }
186            else
187            {
188                String propertyName = amd.getPropertyName();
189                if (propertyName == null)
190                    propertyName = constructPropertyName(attributeName);
191
192                _rules.add(new ReadAttributeRule(attributeName, propertyName, null, amd
193                        .getLocation()));
194
195                _attributeNameMappingMap.remove(attributeName);
196            }
197        }
198
199        if (!_attributeNameMappingMap.isEmpty())
200            _errorHandler.error(LOG, ParseMessages.extraMappings(
201                    _attributeNameMappingMap.keySet(),
202                    _elementModel), _elementModel.getLocation(), null);
203    }
204
205    private String constructPropertyName(String attributeName)
206    {
207        int dashx = attributeName.indexOf('-');
208        if (dashx < 0)
209            return attributeName;
210
211        int length = attributeName.length();
212        StringBuffer buffer = new StringBuffer(length);
213
214        buffer.append(attributeName.substring(0, dashx));
215        boolean toUpper = true;
216
217        for (int i = dashx + 1; i < length; i++)
218        {
219            char ch = attributeName.charAt(i);
220
221            if (ch == '-')
222            {
223                toUpper = true;
224                continue;
225            }
226
227            if (toUpper)
228                ch = Character.toUpperCase(ch);
229
230            buffer.append(ch);
231
232            toUpper = false;
233        }
234
235        return buffer.toString();
236    }
237}