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 }