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
015 package org.apache.hivemind.parse;
016
017 import java.util.ArrayList;
018 import java.util.HashMap;
019 import java.util.Iterator;
020 import java.util.List;
021 import java.util.ListIterator;
022 import java.util.Map;
023
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026 import org.apache.hivemind.Element;
027 import org.apache.hivemind.ErrorHandler;
028 import org.apache.hivemind.schema.AttributeModel;
029 import org.apache.hivemind.schema.ElementModel;
030 import org.apache.hivemind.schema.Rule;
031 import org.apache.hivemind.schema.SchemaProcessor;
032 import org.apache.hivemind.schema.rules.BaseRule;
033 import org.apache.hivemind.schema.rules.CreateObjectRule;
034 import org.apache.hivemind.schema.rules.InvokeParentRule;
035 import 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 */
045 public 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 }