1
+ /*
2
+ * Copyright 2010 the original author or authors.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ package org.springframework.context.groovy
17
+
18
+ import groovy.xml.StreamingMarkupBuilder
19
+ import org.apache.commons.logging.LogFactory
20
+ import org.springframework.beans.factory.config.BeanDefinitionHolder
21
+ import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
22
+ import org.springframework.beans.factory.parsing.Location
23
+ import org.springframework.beans.factory.parsing.Problem
24
+ import org.springframework.beans.factory.xml.DefaultDocumentLoader
25
+ import org.springframework.beans.factory.xml.DelegatingEntityResolver
26
+ import org.springframework.beans.factory.xml.NamespaceHandler
27
+ import org.springframework.beans.factory.xml.ParserContext
28
+ import org.springframework.core.io.ByteArrayResource
29
+ import org.springframework.util.xml.SimpleSaxErrorHandler
30
+ import org.springframework.util.xml.XmlValidationModeDetector
31
+ import org.w3c.dom.Element
32
+ import org.xml.sax.EntityResolver
33
+ import org.xml.sax.ErrorHandler
34
+ import org.xml.sax.InputSource
35
+
36
+ /**
37
+ * Used by GroovyBeanDefinitionReader to read a Spring namespace expression in the Groovy DSL
38
+ *
39
+ * @see GroovyBeanDefinitionReader
40
+ *
41
+ */
42
+
43
+ class DynamicElementReader extends GroovyObjectSupport {
44
+
45
+
46
+ private static final LOG = LogFactory . getLog(GroovyBeanDefinitionReader )
47
+
48
+ private Map xmlNamespaces
49
+ private String rootNamespace
50
+ ErrorHandler errorHandler = new SimpleSaxErrorHandler (LOG );
51
+ int validationMode = XmlValidationModeDetector . VALIDATION_NONE
52
+ EntityResolver entityResolver = new DelegatingEntityResolver (DynamicElementReader . class. getClassLoader())
53
+ ParserContext parserContext
54
+ NamespaceHandler namespaceHandler
55
+ BeanConfiguration beanConfiguration
56
+ boolean beanDecorator = false
57
+ boolean firstCall = true
58
+
59
+ public DynamicElementReader (String namespace , Map namespaceMap = Collections . EMPTY_MAP , NamespaceHandler namespaceHandler = null , ParserContext parserContext = null ) {
60
+ super ();
61
+ this . xmlNamespaces = namespaceMap;
62
+ this . rootNamespace = namespace
63
+ this . namespaceHandler = namespaceHandler
64
+ this . parserContext = parserContext
65
+ }
66
+
67
+ void setClassLoader (ClassLoader classLoader ) {
68
+ entityResolver = new DelegatingEntityResolver (classLoader)
69
+ }
70
+
71
+ /**
72
+ * Hook that subclass or anonymous classes can overwrite to implement custom behavior after invocation
73
+ * completes
74
+ */
75
+ protected void afterInvocation () {
76
+ // NOOP
77
+ }
78
+
79
+ @Override
80
+ public Object invokeMethod (String name , Object args ) {
81
+ boolean invokeAfterInterceptor = false
82
+ if (firstCall) {
83
+ invokeAfterInterceptor = true
84
+ firstCall= false
85
+ }
86
+ if (name. equals(" doCall" )) {
87
+ def callable = args[0 ]
88
+ callable. resolveStrategy = Closure . DELEGATE_FIRST
89
+ callable. delegate = this
90
+ def result = callable. call()
91
+ if (invokeAfterInterceptor) {
92
+ afterInvocation()
93
+ }
94
+ return result
95
+ }
96
+ else {
97
+ StreamingMarkupBuilder builder = new StreamingMarkupBuilder ();
98
+ def myNamespaces = xmlNamespaces
99
+ def myNamespace = rootNamespace
100
+
101
+ def callable = {
102
+ for (namespace in myNamespaces) {
103
+ mkp. declareNamespace( [(namespace. key):namespace. value] )
104
+ }
105
+ if (args && (args[-1 ] instanceof Closure )) {
106
+ args[-1 ]. resolveStrategy = Closure . DELEGATE_FIRST
107
+ args[-1 ]. delegate = builder
108
+ }
109
+ delegate. " $myNamespace " . " $name " (* args)
110
+ }
111
+
112
+ callable. resolveStrategy= Closure . DELEGATE_FIRST
113
+ callable. delegate = builder
114
+ def writable = builder. bind( callable )
115
+
116
+ def sw = new StringWriter ()
117
+ writable. writeTo(sw)
118
+
119
+ def documentLoader = new DefaultDocumentLoader ()
120
+ InputSource is = new InputSource (new StringReader (sw. toString()))
121
+ Element element = documentLoader. loadDocument(is, entityResolver, errorHandler, validationMode, true ). getDocumentElement()
122
+
123
+ parserContext?. delegate?. initDefaults element
124
+ if (namespaceHandler && parserContext) {
125
+ if (beanDecorator && beanConfiguration) {
126
+ BeanDefinitionHolder holder = new BeanDefinitionHolder (beanConfiguration. getBeanDefinition(), beanConfiguration. getName());
127
+ holder = namespaceHandler. decorate(element,holder, parserContext)
128
+ beanConfiguration. setBeanDefinition(holder. getBeanDefinition())
129
+ }
130
+ else {
131
+
132
+ def beanDefinition = namespaceHandler. parse(element, parserContext)
133
+ if (beanDefinition) {
134
+ beanConfiguration?. setBeanDefinition(beanDefinition)
135
+ }
136
+ }
137
+ }
138
+ else {
139
+ throw new BeanDefinitionParsingException (new Problem (" No namespace handler found for element ${ sw} " , new Location (parserContext?. readerContext?. resource ?: new ByteArrayResource (new byte [0 ]))))
140
+ }
141
+ if (invokeAfterInterceptor) {
142
+ afterInvocation()
143
+ }
144
+ return element
145
+
146
+ }
147
+ }
148
+ }
0 commit comments