1 /* Copyright 2004 The Apache Software Foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package org.apache.xmlbeans.impl.config; 17 18 import org.apache.xmlbeans.impl.xb.xmlconfig.ConfigDocument.Config; 19 import org.apache.xmlbeans.impl.xb.xmlconfig.Extensionconfig; 20 import org.apache.xmlbeans.impl.xb.xmlconfig.Nsconfig; 21 import org.apache.xmlbeans.impl.xb.xmlconfig.Qnameconfig; 22 import org.apache.xmlbeans.impl.xb.xmlconfig.Qnametargetenum; 23 import org.apache.xmlbeans.impl.xb.xmlconfig.Usertypeconfig; 24 import org.apache.xmlbeans.BindingConfig; 25 import org.apache.xmlbeans.UserType; 26 import org.apache.xmlbeans.XmlObject; 27 import org.apache.xmlbeans.XmlError; 28 import org.apache.xmlbeans.InterfaceExtension; 29 import org.apache.xmlbeans.PrePostExtension; 30 import org.apache.xmlbeans.impl.jam.JamClassLoader; 31 import org.apache.xmlbeans.impl.jam.JamService; 32 import org.apache.xmlbeans.impl.jam.JamServiceFactory; 33 import org.apache.xmlbeans.impl.jam.JamServiceParams; 34 import org.apache.xmlbeans.impl.schema.StscState; 35 36 import javax.xml.namespace.QName; 37 import java.io.File; 38 import java.io.IOException; 39 import java.util; 40 41 /** 42 * An implementation of BindingConfig 43 */ 44 public class BindingConfigImpl extends BindingConfig 45 { 46 private Map _packageMap; 47 private Map _prefixMap; 48 private Map _suffixMap; 49 private Map _packageMapByUriPrefix; // uri prefix -> package 50 private Map _prefixMapByUriPrefix; // uri prefix -> name prefix 51 private Map _suffixMapByUriPrefix; // uri prefix -> name suffix 52 private Map _qnameTypeMap; 53 private Map _qnameDocTypeMap; 54 private Map _qnameElemMap; 55 private Map _qnameAttMap; 56 57 private List _interfaceExtensions; 58 private List _prePostExtensions; 59 private Map _userTypes; 60 61 private BindingConfigImpl() 62 { 63 _packageMap = Collections.EMPTY_MAP; 64 _prefixMap = Collections.EMPTY_MAP; 65 _suffixMap = Collections.EMPTY_MAP; 66 _packageMapByUriPrefix = Collections.EMPTY_MAP; 67 _prefixMapByUriPrefix = Collections.EMPTY_MAP; 68 _suffixMapByUriPrefix = Collections.EMPTY_MAP; 69 _qnameTypeMap = Collections.EMPTY_MAP; 70 _qnameDocTypeMap = Collections.EMPTY_MAP; 71 _qnameElemMap = Collections.EMPTY_MAP; 72 _qnameAttMap = Collections.EMPTY_MAP; 73 _interfaceExtensions = new ArrayList(); 74 _prePostExtensions = new ArrayList(); 75 _userTypes = Collections.EMPTY_MAP; 76 } 77 78 public static BindingConfig forConfigDocuments(Config[] configs, File[] javaFiles, File[] classpath) 79 { 80 return new BindingConfigImpl(configs, javaFiles, classpath); 81 } 82 83 private BindingConfigImpl(Config[] configs, File[] javaFiles, File[] classpath) 84 { 85 _packageMap = new LinkedHashMap(); 86 _prefixMap = new LinkedHashMap(); 87 _suffixMap = new LinkedHashMap(); 88 _packageMapByUriPrefix = new LinkedHashMap(); 89 _prefixMapByUriPrefix = new LinkedHashMap(); 90 _suffixMapByUriPrefix = new LinkedHashMap(); 91 _qnameTypeMap = new LinkedHashMap(); 92 _qnameDocTypeMap = new LinkedHashMap(); 93 _qnameElemMap = new LinkedHashMap(); 94 _qnameAttMap = new LinkedHashMap(); 95 _interfaceExtensions = new ArrayList(); 96 _prePostExtensions = new ArrayList(); 97 _userTypes = new LinkedHashMap(); 98 99 for (int i = 0; i < configs.length; i++) 100 { 101 Config config = configs[i]; 102 Nsconfig[] nsa = config.getNamespaceArray(); 103 for (int j = 0; j < nsa.length; j++) 104 { 105 recordNamespaceSetting(nsa[j].getUri(), nsa[j].getPackage(), _packageMap); 106 recordNamespaceSetting(nsa[j].getUri(), nsa[j].getPrefix(), _prefixMap); 107 recordNamespaceSetting(nsa[j].getUri(), nsa[j].getSuffix(), _suffixMap); 108 recordNamespacePrefixSetting(nsa[j].getUriprefix(), nsa[j].getPackage(), _packageMapByUriPrefix); 109 recordNamespacePrefixSetting(nsa[j].getUriprefix(), nsa[j].getPrefix(), _prefixMapByUriPrefix); 110 recordNamespacePrefixSetting(nsa[j].getUriprefix(), nsa[j].getSuffix(), _suffixMapByUriPrefix); 111 } 112 113 Qnameconfig[] qnc = config.getQnameArray(); 114 for (int j = 0; j < qnc.length; j++) 115 { 116 List applyto = qnc[j].xgetTarget().xgetListValue(); 117 QName name = qnc[j].getName(); 118 String javaname = qnc[j].getJavaname(); 119 for (int k = 0; k < applyto.size(); k++) 120 { 121 Qnametargetenum a = (Qnametargetenum) applyto.get(k); 122 switch (a.enumValue().intValue()) 123 { 124 case Qnametargetenum.INT_TYPE: 125 _qnameTypeMap.put(name, javaname); 126 break; 127 case Qnametargetenum.INT_DOCUMENT_TYPE: 128 _qnameDocTypeMap.put(name, javaname); 129 break; 130 case Qnametargetenum.INT_ACCESSOR_ELEMENT: 131 _qnameElemMap.put(name, javaname); 132 break; 133 case Qnametargetenum.INT_ACCESSOR_ATTRIBUTE: 134 _qnameAttMap.put(name, javaname); 135 break; 136 } 137 } 138 } 139 140 Extensionconfig[] ext = config.getExtensionArray(); 141 for (int j = 0; j < ext.length; j++) 142 { 143 recordExtensionSetting(javaFiles, classpath, ext[j]); 144 } 145 146 Usertypeconfig[] utypes = config.getUsertypeArray(); 147 for (int j = 0; j < utypes.length; j++) 148 { 149 recordUserTypeSetting(javaFiles, classpath, utypes[j]); 150 } 151 } 152 153 secondPhaseValidation(); 154 //todo normalize(); 155 } 156 157 void addInterfaceExtension(InterfaceExtensionImpl ext) 158 { 159 if (ext==null) 160 return; 161 162 _interfaceExtensions.add(ext); 163 } 164 165 void addPrePostExtension(PrePostExtensionImpl ext) 166 { 167 if (ext==null) 168 return; 169 170 _prePostExtensions.add(ext); 171 } 172 173 void secondPhaseValidation() 174 { 175 // validate interface methods collisions 176 Map methodSignatures = new HashMap(); 177 178 for (int i = 0; i < _interfaceExtensions.size(); i++) 179 { 180 InterfaceExtensionImpl interfaceExtension = (InterfaceExtensionImpl) _interfaceExtensions.get(i); 181 182 InterfaceExtensionImpl.MethodSignatureImpl[] methods = (InterfaceExtensionImpl.MethodSignatureImpl[])interfaceExtension.getMethods(); 183 for (int j = 0; j < methods.length; j++) 184 { 185 InterfaceExtensionImpl.MethodSignatureImpl ms = methods[j]; 186 187 if (methodSignatures.containsKey(methods[j])) 188 { 189 190 InterfaceExtensionImpl.MethodSignatureImpl ms2 = (InterfaceExtensionImpl.MethodSignatureImpl) methodSignatures.get(methods[j]); 191 if (!ms.getReturnType().equals(ms2.getReturnType())) 192 { 193 BindingConfigImpl.error("Colliding methods '" + ms.getSignature() + "' in interfaces " + 194 ms.getInterfaceName() + " and " + ms2.getInterfaceName() + ".", null); 195 } 196 197 return; 198 } 199 200 // store it into hashmap 201 methodSignatures.put(methods[j], methods[j]); 202 } 203 } 204 205 // validate that PrePostExtension-s do not intersect 206 for (int i = 0; i < _prePostExtensions.size() - 1; i++) 207 { 208 PrePostExtensionImpl a = (PrePostExtensionImpl) _prePostExtensions.get(i); 209 for (int j = 1; j < _prePostExtensions.size(); j++) 210 { 211 PrePostExtensionImpl b = (PrePostExtensionImpl) _prePostExtensions.get(j); 212 if (a.hasNameSetIntersection(b)) 213 BindingConfigImpl.error("The applicable domain for handler '" + a.getHandlerNameForJavaSource() + 214 "' intersects with the one for '" + b.getHandlerNameForJavaSource() + "'.", null); 215 } 216 } 217 } 218 219 private static void recordNamespaceSetting(Object key, String value, Map result) 220 { 221 if (value == null) 222 return; 223 else if (key == null) 224 result.put("", value); 225 else if (key instanceof String && "##any".equals(key)) 226 result.put(key, value); 227 else if (key instanceof List) 228 { 229 for (Iterator i = ((List)key).iterator(); i.hasNext(); ) 230 { 231 String uri = (String)i.next(); 232 if ("##local".equals(uri)) 233 uri = ""; 234 result.put(uri, value); 235 } 236 } 237 } 238 239 private static void recordNamespacePrefixSetting(List list, String value, Map result) 240 { 241 if (value == null) 242 return; 243 else if (list == null) 244 return; 245 for (Iterator i = list.iterator(); i.hasNext(); ) 246 { 247 result.put(i.next(), value); 248 } 249 } 250 251 private void recordExtensionSetting(File[] javaFiles, File[] classpath, Extensionconfig ext) 252 { 253 NameSet xbeanSet = null; 254 Object key = ext.getFor(); 255 256 257 if (key instanceof String && "*".equals(key)) 258 xbeanSet = NameSet.EVERYTHING; 259 else if (key instanceof List) 260 { 261 NameSetBuilder xbeanSetBuilder = new NameSetBuilder(); 262 for (Iterator i = ((List) key).iterator(); i.hasNext();) 263 { 264 String xbeanName = (String) i.next(); 265 xbeanSetBuilder.add(xbeanName); 266 } 267 xbeanSet = xbeanSetBuilder.toNameSet(); 268 } 269 270 if (xbeanSet == null) 271 error("Invalid value of attribute 'for' : '" + key + "'.", ext); 272 273 Extensionconfig.Interface[] intfXO = ext.getInterfaceArray(); 274 Extensionconfig.PrePostSet ppXO = ext.getPrePostSet(); 275 276 if (intfXO.length > 0 || ppXO != null) 277 { 278 JamClassLoader jamLoader = getJamLoader(javaFiles, classpath); 279 for (int i = 0; i < intfXO.length; i++) 280 { 281 addInterfaceExtension(InterfaceExtensionImpl.newInstance(jamLoader, xbeanSet, intfXO[i])); 282 } 283 284 addPrePostExtension(PrePostExtensionImpl.newInstance(jamLoader, xbeanSet, ppXO)); 285 } 286 } 287 288 private void recordUserTypeSetting(File[] javaFiles, File[] classpath, 289 Usertypeconfig usertypeconfig) 290 { 291 JamClassLoader jamLoader = getJamLoader(javaFiles, classpath); 292 UserTypeImpl userType = UserTypeImpl.newInstance(jamLoader, usertypeconfig); 293 _userTypes.put(userType.getName(), userType); 294 } 295 296 297 private String lookup(Map map, Map mapByUriPrefix, String uri) 298 { 299 if (uri == null) 300 uri = ""; 301 String result = (String)map.get(uri); 302 if (result != null) 303 return result; 304 if (mapByUriPrefix != null) 305 { 306 result = lookupByUriPrefix(mapByUriPrefix, uri); 307 if (result != null) 308 return result; 309 } 310 311 return (String)map.get("##any"); 312 } 313 314 private String lookupByUriPrefix(Map mapByUriPrefix, String uri) 315 { 316 if (uri == null) 317 return null; 318 if (!mapByUriPrefix.isEmpty()) 319 { 320 String uriprefix = null; 321 Iterator i = mapByUriPrefix.keySet().iterator(); 322 while (i.hasNext()) 323 { 324 String nextprefix = (String)i.next(); 325 if (uriprefix != null && nextprefix.length() < uriprefix.length()) 326 continue; 327 if (uri.startsWith(nextprefix)) 328 uriprefix = nextprefix; 329 } 330 331 if (uriprefix != null) 332 return (String)mapByUriPrefix.get(uriprefix); 333 } 334 return null; 335 } 336 337 //package methods 338 static void warning(String s, XmlObject xo) 339 { 340 StscState.get().error(s, XmlError.SEVERITY_WARNING, xo); 341 } 342 343 static void error(String s, XmlObject xo) 344 { 345 StscState.get().error(s, XmlError.SEVERITY_ERROR, xo); 346 } 347 348 //public methods 349 350 public String lookupPackageForNamespace(String uri) 351 { 352 return lookup(_packageMap, _packageMapByUriPrefix, uri); 353 } 354 355 public String lookupPrefixForNamespace(String uri) 356 { 357 return lookup(_prefixMap, _prefixMapByUriPrefix, uri); 358 } 359 360 public String lookupSuffixForNamespace(String uri) 361 { 362 return lookup(_suffixMap, _suffixMapByUriPrefix, uri); 363 } 364 365 /** @deprecated replaced with {@link #lookupJavanameForQName(QName, int)} */ 366 public String lookupJavanameForQName(QName qname) 367 { 368 String result = (String)_qnameTypeMap.get(qname); 369 if (result != null) 370 return result; 371 return (String)_qnameDocTypeMap.get(qname); 372 } 373 374 public String lookupJavanameForQName(QName qname, int kind) 375 { 376 switch (kind) 377 { 378 case QNAME_TYPE: 379 return (String)_qnameTypeMap.get(qname); 380 case QNAME_DOCUMENT_TYPE: 381 return (String)_qnameDocTypeMap.get(qname); 382 case QNAME_ACCESSOR_ELEMENT: 383 return (String)_qnameElemMap.get(qname); 384 case QNAME_ACCESSOR_ATTRIBUTE: 385 return (String)_qnameAttMap.get(qname); 386 } 387 return null; 388 } 389 390 public UserType lookupUserTypeForQName(QName qname) 391 { 392 if (qname == null) 393 return null; 394 395 return (UserType) _userTypes.get(qname); 396 } 397 398 public InterfaceExtension[] getInterfaceExtensions() 399 { 400 return (InterfaceExtension[])_interfaceExtensions.toArray(new InterfaceExtension[_interfaceExtensions.size()]); 401 } 402 403 public InterfaceExtension[] getInterfaceExtensions(String fullJavaName) 404 { 405 List result = new ArrayList(); 406 for (int i = 0; i < _interfaceExtensions.size(); i++) 407 { 408 InterfaceExtensionImpl intfExt = (InterfaceExtensionImpl) _interfaceExtensions.get(i); 409 if (intfExt.contains(fullJavaName)) 410 result.add(intfExt); 411 } 412 413 return (InterfaceExtension[])result.toArray(new InterfaceExtension[result.size()]); 414 } 415 416 public PrePostExtension[] getPrePostExtensions() 417 { 418 return (PrePostExtension[])_prePostExtensions.toArray(new PrePostExtension[_prePostExtensions.size()]); 419 } 420 421 public PrePostExtension getPrePostExtension(String fullJavaName) 422 { 423 for (int i = 0; i < _prePostExtensions.size(); i++) 424 { 425 PrePostExtensionImpl prePostExt = (PrePostExtensionImpl) _prePostExtensions.get(i); 426 if (prePostExt.contains(fullJavaName)) 427 return prePostExt; 428 } 429 return null; 430 } 431 432 private JamClassLoader getJamLoader(File[] javaFiles, File[] classpath) 433 { 434 JamServiceFactory jf = JamServiceFactory.getInstance(); 435 JamServiceParams params = jf.createServiceParams(); 436 params.set14WarningsEnabled(false); 437 // BUGBUG(radup) This is here because the above doesn't do the trick 438 params.setShowWarnings(false); 439 440 // process the included sources 441 if (javaFiles!=null) 442 for (int i = 0; i < javaFiles.length; i++) 443 params.includeSourceFile(javaFiles[i]); 444 445 //params.setVerbose(DirectoryScanner.class); 446 447 // add the sourcepath and classpath, if specified 448 params.addClassLoader(this.getClass().getClassLoader()); 449 if (classpath != null) 450 for (int i = 0; i < classpath.length; i++) 451 params.addClasspath(classpath[i]); 452 453 // create service, get classes, return compiler 454 JamService service; 455 try 456 { 457 service = jf.createService(params); 458 } 459 catch (IOException ioe) 460 { 461 error("Error when accessing .java files.", null); 462 return null; 463 } 464 465 // JClass[] cls = service.getAllClasses(); 466 // for (int i = 0; i < cls.length; i++) 467 // { 468 // JClass cl = cls[i]; 469 // System.out.println("CL: " + cl + " " + cl.getQualifiedName()); 470 // JMethod[] methods = cl.getMethods(); 471 // for (int j = 0; j < methods.length; j++) 472 // { 473 // JMethod method = methods[j]; 474 // System.out.println(" " + method.getQualifiedName()); 475 // } 476 // } 477 478 return service.getClassLoader(); 479 } 480 }