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.impl; 016 017 import java.util.ArrayList; 018 import java.util.HashMap; 019 import java.util.List; 020 import java.util.Map; 021 022 import org.apache.hivemind.Element; 023 import org.apache.hivemind.ErrorLog; 024 import org.apache.hivemind.internal.Module; 025 import org.apache.hivemind.schema.ElementModel; 026 import org.apache.hivemind.schema.Schema; 027 import org.apache.hivemind.schema.SchemaProcessor; 028 import org.apache.hivemind.schema.Translator; 029 030 /** 031 * Used to assemble all the {@link org.apache.hivemind.internal.Contribution}s contributed to an 032 * {@link org.apache.hivemind.internal.ConfigurationPoint} while converting the XML (represented as 033 * {@link org.apache.hivemind.Element}s into Java objects. 034 * 035 * @author Howard Lewis Ship 036 */ 037 public final class SchemaProcessorImpl implements SchemaProcessor 038 { 039 private ErrorLog _errorLog; 040 041 private Schema _schema; 042 043 /** 044 * The assembled elements that will be contributed into the ConfigurationPoint. 045 */ 046 private List _elements = new ArrayList(); 047 048 private boolean _canElementsBeMapped; 049 050 private Map _mappedElements = new HashMap(); 051 052 private List _stack = new ArrayList(); 053 054 private Module _contributingModule; 055 056 /** 057 * Map on element name to {@link SchemaElement}. 058 */ 059 private Map _elementMap = new HashMap(); 060 061 /** 062 * Used to track the nesting of elements. 063 */ 064 private List _elementStack = new ArrayList(); 065 066 public SchemaProcessorImpl(ErrorLog errorLog, Schema schema) 067 { 068 _errorLog = errorLog; 069 _schema = schema; 070 _stack.add(this); 071 072 if (_schema != null) 073 { 074 List l = _schema.getElementModel(); 075 076 int count = l.size(); 077 for (int i = 0; i < count; i++) 078 { 079 ElementModel model = (ElementModel) l.get(i); 080 _elementMap.put(model.getElementName(), new SchemaElement(this, model)); 081 } 082 083 _canElementsBeMapped = schema.canInstancesBeKeyed(); 084 } 085 } 086 087 /** 088 * Invoked over reflection by the {@link org.apache.hivemind.schema.rules.InvokeParentRule}. 089 */ 090 public void addElement(Object element) 091 { 092 _elements.add(element); 093 094 if (_canElementsBeMapped) 095 { 096 Element currentElement = peekElement(); 097 String keyAttribute = _activeElement.getKeyAttribute(); 098 099 String expandedKey = getContributingModule().expandSymbols( 100 currentElement.getAttributeValue(keyAttribute), 101 currentElement.getLocation()); 102 103 Translator t = getAttributeTranslator(keyAttribute); 104 105 Object finalValue = t.translate( 106 getContributingModule(), 107 Object.class, 108 expandedKey, 109 currentElement.getLocation()); 110 111 _mappedElements.put(finalValue, element); 112 } 113 } 114 115 public List getElements() 116 { 117 return _elements; 118 } 119 120 public Map getMappedElements() 121 { 122 if (_canElementsBeMapped) 123 return _mappedElements; 124 125 return null; 126 } 127 128 public void push(Object object) 129 { 130 _stack.add(object); 131 } 132 133 public Object pop() 134 { 135 if (_stack.isEmpty()) 136 throw new ArrayIndexOutOfBoundsException(ImplMessages.schemaStackViolation(this)); 137 138 return _stack.remove(_stack.size() - 1); 139 } 140 141 public Object peek() 142 { 143 return peek(0); 144 } 145 146 public Object peek(int depth) 147 { 148 int count = _stack.size(); 149 150 int position = count - 1 - depth; 151 152 if (position < 0) 153 throw new ArrayIndexOutOfBoundsException(ImplMessages.schemaStackViolation(this)); 154 155 return _stack.get(count - 1 - depth); 156 } 157 158 public Module getContributingModule() 159 { 160 return _contributingModule; 161 } 162 163 /** @since 1.1 */ 164 165 public Module getDefiningModule() 166 { 167 return _schema.getDefiningModule(); 168 } 169 170 public String getElementPath() 171 { 172 StringBuffer buffer = new StringBuffer(); 173 int count = _elementStack.size(); 174 175 for (int i = 0; i < count; i++) 176 { 177 if (i > 0) 178 buffer.append('/'); 179 180 buffer.append(((Element) _elementStack.get(i)).getElementName()); 181 } 182 183 return buffer.toString(); 184 } 185 186 private void pushElement(Element element) 187 { 188 _elementStack.add(element); 189 } 190 191 private Element peekElement() 192 { 193 return (Element) _elementStack.get(_elementStack.size() - 1); 194 } 195 196 private void popElement() 197 { 198 _elementStack.remove(_elementStack.size() - 1); 199 } 200 201 /** 202 * Processes a single extension. 203 */ 204 public void process(List elements, Module contributingModule) 205 { 206 if (elements == null) 207 return; 208 209 if (_schema == null) 210 { 211 _elements.addAll(elements); 212 return; 213 } 214 215 _contributingModule = contributingModule; 216 217 int count = elements.size(); 218 219 for (int i = 0; i < count; i++) 220 { 221 Element e = (Element) elements.get(i); 222 223 processRootElement(e); 224 } 225 226 _contributingModule = null; 227 } 228 229 private void processRootElement(Element element) 230 { 231 String name = element.getElementName(); 232 233 SchemaElement schemaElement = (SchemaElement) _elementMap.get(name); 234 235 processElement(element, schemaElement); 236 } 237 238 private SchemaElement _activeElement; 239 240 private void processElement(Element element, SchemaElement schemaElement) 241 { 242 pushElement(element); 243 244 if (schemaElement == null) 245 _errorLog 246 .error(ImplMessages.unknownElement(this, element), element.getLocation(), null); 247 else 248 { 249 SchemaElement prior = _activeElement; 250 251 schemaElement.validateAttributes(element); 252 253 _activeElement = schemaElement; 254 255 schemaElement.fireBegin(element); 256 257 processNestedElements(element, schemaElement); 258 259 schemaElement.fireEnd(element); 260 261 _activeElement = prior; 262 } 263 264 popElement(); 265 } 266 267 private void processNestedElements(Element element, SchemaElement schemaElement) 268 { 269 List l = element.getElements(); 270 int count = l.size(); 271 272 for (int i = 0; i < count; i++) 273 { 274 Element nested = (Element) l.get(i); 275 String name = nested.getElementName(); 276 277 processElement(nested, schemaElement.getNestedElement(name)); 278 } 279 } 280 281 public Translator getContentTranslator() 282 { 283 return _activeElement.getContentTranslator(); 284 } 285 286 public Translator getAttributeTranslator(String attributeName) 287 { 288 return _activeElement.getAttributeTranslator(attributeName); 289 } 290 291 public Translator getTranslator(String translator) 292 { 293 return getContributingModule().getTranslator(translator); 294 } 295 }