| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.axiom.om.impl.common.builder; |
| |
| import java.util.ArrayList; |
| |
| import org.apache.axiom.core.CoreModelException; |
| import org.apache.axiom.core.CoreNode; |
| import org.apache.axiom.core.impl.builder.BuilderListener; |
| import org.apache.axiom.om.OMDataSource; |
| import org.apache.axiom.om.ds.custombuilder.CustomBuilder; |
| import org.apache.axiom.om.impl.common.AxiomExceptionTranslator; |
| import org.apache.axiom.om.impl.common.AxiomSemantics; |
| import org.apache.axiom.om.impl.common.OMNamespaceImpl; |
| import org.apache.axiom.om.impl.intf.AxiomElement; |
| import org.apache.axiom.om.impl.intf.AxiomSourcedElement; |
| import org.apache.axiom.soap.impl.intf.AxiomSOAPElement; |
| import org.apache.axiom.soap.impl.intf.AxiomSOAPHeaderBlock; |
| import org.apache.axiom.soap.impl.intf.soap11.AxiomSOAP11HeaderBlock; |
| import org.apache.axiom.soap.impl.intf.soap12.AxiomSOAP12HeaderBlock; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| final class CustomBuilderManager implements BuilderListener { |
| private static final Log log = LogFactory.getLog(CustomBuilderManager.class); |
| |
| private ArrayList<CustomBuilderRegistration> registrations; |
| private AxiomElement lastCandidateElement; |
| private int lastCandidateDepth = -1; |
| |
| void register(CustomBuilder.Selector selector, CustomBuilder customBuilder) { |
| if (registrations == null) { |
| registrations = new ArrayList<CustomBuilderRegistration>(); |
| } |
| registrations.add(new CustomBuilderRegistration(selector, customBuilder)); |
| // Try to apply the new custom builder to the element currently being built (unless it has |
| // already been processed by another custom builder). This is important for custom builders |
| // used to process the payload of a SOAP message: by the time the custom builder is |
| // registered the payload root element may already have been created (e.g. because code |
| // executed before the custom builder registration may have checked if the payload is a |
| // SOAP fault). |
| if (lastCandidateElement != null) { |
| Runnable action = getAction(lastCandidateElement, lastCandidateDepth, registrations.size()-1); |
| if (action != null) { |
| action.run(); |
| } |
| } |
| } |
| |
| @Override |
| public Runnable nodeAdded(CoreNode node, int depth) { |
| return getAction(node, depth, 0); |
| } |
| |
| private Runnable getAction(CoreNode node, int depth, int firstCustomBuilder) { |
| lastCandidateElement = null; |
| lastCandidateDepth = -1; |
| if (node instanceof AxiomElement && (node instanceof AxiomSOAPHeaderBlock || !(node instanceof AxiomSOAPElement))) { |
| final AxiomElement element = (AxiomElement)node; |
| if (registrations != null) { |
| for (int i=firstCustomBuilder; i<registrations.size(); i++) { |
| CustomBuilderRegistration registration = registrations.get(i); |
| final String namespaceURI = element.coreGetNamespaceURI(); |
| final String localName = element.coreGetLocalName(); |
| if (registration.getSelector().accepts(element.getParent(), depth, namespaceURI, localName)) { |
| final CustomBuilder customBuilder = registration.getCustomBuilder(); |
| if (log.isDebugEnabled()) { |
| log.debug("Custom builder " + customBuilder + " accepted element {" + namespaceURI + "}" + localName + " at depth " + depth); |
| } |
| return new Runnable() { |
| @Override |
| public void run() { |
| if (log.isDebugEnabled()) { |
| log.debug("Invoking custom builder " + customBuilder); |
| } |
| OMDataSource dataSource = customBuilder.create(element); |
| Class<? extends AxiomSourcedElement> type; |
| if (element instanceof AxiomSOAP11HeaderBlock) { |
| type = AxiomSOAP11HeaderBlock.class; |
| } else if (element instanceof AxiomSOAP12HeaderBlock) { |
| type = AxiomSOAP12HeaderBlock.class; |
| } else { |
| type = AxiomSourcedElement.class; |
| } |
| if (log.isDebugEnabled()) { |
| log.debug("Replacing element with new sourced element of type " + type); |
| } |
| AxiomSourcedElement newElement = element.coreCreateNode(type); |
| newElement.init(localName, new OMNamespaceImpl(namespaceURI, null), dataSource); |
| try { |
| element.coreReplaceWith(newElement, AxiomSemantics.INSTANCE); |
| } catch (CoreModelException ex) { |
| throw AxiomExceptionTranslator.translate(ex); |
| } |
| } |
| }; |
| } |
| } |
| } |
| // Save a reference to the element so that we can process it when another custom builder is registered |
| lastCandidateElement = element; |
| lastCandidateDepth = depth; |
| } |
| return null; |
| } |
| } |