001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.configuration.spring;
019:
020: import java.util.StringTokenizer;
021:
022: import javax.xml.bind.JAXBContext;
023: import javax.xml.bind.JAXBElement;
024: import javax.xml.bind.JAXBException;
025: import javax.xml.bind.Unmarshaller;
026: import javax.xml.namespace.QName;
027:
028: import org.w3c.dom.Attr;
029: import org.w3c.dom.Element;
030: import org.w3c.dom.NamedNodeMap;
031: import org.w3c.dom.Node;
032: import org.w3c.dom.NodeList;
033:
034: import org.apache.cxf.helpers.DOMUtils;
035: import org.springframework.beans.factory.BeanDefinitionStoreException;
036: import org.springframework.beans.factory.config.BeanDefinition;
037: import org.springframework.beans.factory.config.BeanDefinitionHolder;
038: import org.springframework.beans.factory.support.AbstractBeanDefinition;
039: import org.springframework.beans.factory.support.BeanDefinitionBuilder;
040: import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
041: import org.springframework.beans.factory.xml.ParserContext;
042: import org.springframework.util.StringUtils;
043:
044: public abstract class AbstractBeanDefinitionParser
045: extends
046: org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser {
047:
048: private Class beanClass;
049:
050: @Override
051: protected void doParse(Element element, ParserContext ctx,
052: BeanDefinitionBuilder bean) {
053: NamedNodeMap atts = element.getAttributes();
054: boolean setBus = false;
055: for (int i = 0; i < atts.getLength(); i++) {
056: Attr node = (Attr) atts.item(i);
057: String val = node.getValue();
058: String name = node.getLocalName();
059:
060: if ("createdFromAPI".equals(name)) {
061: bean.setAbstract(true);
062: } else if ("abstract".equals(name)) {
063: bean.setAbstract(true);
064: } else if (!"id".equals(name) && !"name".equals(name)) {
065: if ("bus".equals(name)) {
066: setBus = true;
067: }
068: mapAttribute(bean, element, name, val);
069: }
070: }
071:
072: if (!setBus && ctx.getRegistry().containsBeanDefinition("cxf")
073: && hasBusProperty()) {
074: wireBus(bean, "cxf");
075: }
076:
077: NodeList children = element.getChildNodes();
078: for (int i = 0; i < children.getLength(); i++) {
079: Node n = children.item(i);
080: if (n.getNodeType() == Node.ELEMENT_NODE) {
081: String name = n.getLocalName();
082:
083: mapElement(ctx, bean, (Element) n, name);
084: }
085: }
086: }
087:
088: public Class getBeanClass() {
089: return beanClass;
090: }
091:
092: public void setBeanClass(Class beanClass) {
093: this .beanClass = beanClass;
094: }
095:
096: @Override
097: protected Class getBeanClass(Element e) {
098: return beanClass;
099: }
100:
101: protected void mapAttribute(BeanDefinitionBuilder bean, Element e,
102: String name, String val) {
103: mapAttribute(bean, name, val);
104: }
105:
106: protected void mapAttribute(BeanDefinitionBuilder bean,
107: String name, String val) {
108: mapToProperty(bean, name, val);
109: }
110:
111: protected void mapElement(ParserContext ctx,
112: BeanDefinitionBuilder bean, Element e, String name) {
113: }
114:
115: @Override
116: protected String resolveId(Element elem,
117: AbstractBeanDefinition definition, ParserContext ctx)
118: throws BeanDefinitionStoreException {
119:
120: // REVISIT: use getAttributeNS instead
121:
122: String id = getIdOrName(elem);
123: String createdFromAPI = elem
124: .getAttribute(BeanConstants.CREATED_FROM_API_ATTR);
125:
126: if (null == id || "".equals(id)) {
127: return super .resolveId(elem, definition, ctx);
128: }
129:
130: if (createdFromAPI != null
131: && "true".equals(createdFromAPI.toLowerCase())) {
132: return id + getSuffix();
133: }
134: return id;
135: }
136:
137: protected boolean hasBusProperty() {
138: return false;
139: }
140:
141: protected String getSuffix() {
142: return "";
143: }
144:
145: protected void setFirstChildAsProperty(Element element,
146: ParserContext ctx, BeanDefinitionBuilder bean,
147: String propertyName) {
148: String id = getAndRegisterFirstChild(element, ctx, bean,
149: propertyName);
150: bean.addPropertyReference(propertyName, id);
151:
152: }
153:
154: protected String getAndRegisterFirstChild(Element element,
155: ParserContext ctx, BeanDefinitionBuilder bean,
156: String propertyName) {
157: Element first = getFirstChild(element);
158:
159: if (first == null) {
160: throw new IllegalStateException(propertyName
161: + " property must have child elements!");
162: }
163:
164: // Seems odd that we have to do the registration, I wonder if there is a better way
165: String id;
166: BeanDefinition child;
167: if (first.getNamespaceURI().equals(
168: BeanDefinitionParserDelegate.BEANS_NAMESPACE_URI)) {
169: String name = first.getLocalName();
170: if ("ref".equals(name)) {
171: id = first.getAttribute("bean");
172: if (id == null) {
173: throw new IllegalStateException(
174: "<ref> elements must have a \"bean\" attribute!");
175: }
176: return id;
177: } else if ("bean".equals(name)) {
178: BeanDefinitionHolder bdh = ctx.getDelegate()
179: .parseBeanDefinitionElement(first);
180: child = bdh.getBeanDefinition();
181: id = bdh.getBeanName();
182: } else {
183: throw new UnsupportedOperationException(
184: "Elements with the name " + name
185: + " are not currently "
186: + "supported as sub elements of "
187: + element.getLocalName());
188: }
189:
190: } else {
191: child = ctx.getDelegate().parseCustomElement(first,
192: bean.getBeanDefinition());
193: id = child.toString();
194: }
195:
196: ctx.getRegistry().registerBeanDefinition(id, child);
197: return id;
198: }
199:
200: protected Element getFirstChild(Element element) {
201: Element first = null;
202: NodeList children = element.getChildNodes();
203: for (int i = 0; i < children.getLength(); i++) {
204: Node n = children.item(i);
205: if (n.getNodeType() == Node.ELEMENT_NODE) {
206: first = (Element) n;
207: }
208: }
209: return first;
210: }
211:
212: protected void wireBus(BeanDefinitionBuilder bean, String busId) {
213: bean.addPropertyReference("bus", busId);
214: }
215:
216: protected void mapElementToJaxbProperty(Element parent,
217: BeanDefinitionBuilder bean, QName name, String propertyName) {
218: mapElementToJaxbProperty(parent, bean, name, propertyName, null);
219: }
220:
221: protected void mapElementToJaxbProperty(Element parent,
222: BeanDefinitionBuilder bean, QName name,
223: String propertyName, Class<?> c) {
224: Node data = null;
225: NodeList nl = parent.getChildNodes();
226: for (int i = 0; i < nl.getLength(); i++) {
227: Node n = nl.item(i);
228: if (n.getNodeType() == Node.ELEMENT_NODE
229: && name.getLocalPart().equals(n.getLocalName())
230: && name.getNamespaceURI().equals(
231: n.getNamespaceURI())) {
232: data = n;
233: break;
234: }
235: }
236:
237: if (data == null) {
238: return;
239: }
240:
241: JAXBContext context = null;
242: Object obj = null;
243: try {
244: String pkg = getJaxbPackage();
245: if (null != c) {
246: pkg = c.getPackage().getName();
247: }
248: context = JAXBContext.newInstance(pkg, getClass()
249: .getClassLoader());
250: Unmarshaller u = context.createUnmarshaller();
251: if (c != null) {
252: obj = u.unmarshal(data, c);
253: } else {
254: obj = u.unmarshal(data);
255: }
256:
257: if (obj instanceof JAXBElement<?>) {
258: JAXBElement<?> el = (JAXBElement<?>) obj;
259: obj = el.getValue();
260:
261: }
262: } catch (JAXBException e) {
263: throw new RuntimeException(
264: "Could not parse configuration.", e);
265: }
266:
267: if (obj != null) {
268: bean.addPropertyValue(propertyName, obj);
269: }
270: }
271:
272: protected String getJaxbPackage() {
273: return "";
274: }
275:
276: protected void mapToProperty(BeanDefinitionBuilder bean,
277: String propertyName, String val) {
278: if (ID_ATTRIBUTE.equals(propertyName)) {
279: return;
280: }
281:
282: if (StringUtils.hasText(val)) {
283: if (val.startsWith("#")) {
284: bean.addPropertyReference(propertyName, val
285: .substring(1));
286: } else {
287: bean.addPropertyValue(propertyName, val);
288: }
289: }
290: }
291:
292: protected boolean isAttribute(String pre, String name) {
293: return !"xmlns".equals(name)
294: && (pre == null || !pre.equals("xmlns"))
295: && !"abstract".equals(name)
296: && !"lazy-init".equals(name) && !"id".equals(name);
297: }
298:
299: protected QName parseQName(Element element, String t) {
300: String ns = null;
301: String pre = null;
302: String local = null;
303:
304: if (t.startsWith("{")) {
305: int i = t.indexOf('}');
306: if (i == -1) {
307: throw new RuntimeException(
308: "Namespace bracket '{' must having a closing bracket '}'.");
309: }
310:
311: ns = t.substring(1, i);
312: t = t.substring(i + 1);
313: }
314:
315: int colIdx = t.indexOf(':');
316: if (colIdx == -1) {
317: local = t;
318: pre = "";
319:
320: ns = DOMUtils.getNamespace(element, "");
321: } else {
322: pre = t.substring(0, colIdx);
323: local = t.substring(colIdx + 1);
324:
325: ns = DOMUtils.getNamespace(element, pre);
326: }
327:
328: return new QName(ns, local, pre);
329: }
330:
331: /* This id-or-name resolution logic follows that in Spring's
332: * org.springframework.beans.factory.xml.BeanDefinitionParserDelegate object
333: * Intent is to have resolution of CXF custom beans follow that of Spring beans
334: */
335: protected String getIdOrName(Element elem) {
336: String id = elem
337: .getAttribute(BeanDefinitionParserDelegate.ID_ATTRIBUTE);
338:
339: if (null == id || "".equals(id)) {
340: String names = elem.getAttribute(BeanConstants.NAME_ATTR);
341: if (null != names) {
342: StringTokenizer st = new StringTokenizer(
343: names,
344: BeanDefinitionParserDelegate.BEAN_NAME_DELIMITERS);
345: if (st.countTokens() > 0) {
346: id = st.nextToken();
347: }
348: }
349: }
350: return id;
351: }
352:
353: }
|