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