001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.soap.bindings.soap.interceptors;
018    
019    import java.net.URI;
020    import java.util.HashSet;
021    import java.util.Set;
022    
023    import javax.xml.namespace.QName;
024    
025    import org.apache.servicemix.soap.api.Interceptor;
026    import org.apache.servicemix.soap.api.InterceptorChain;
027    import org.apache.servicemix.soap.api.Message;
028    import org.apache.servicemix.soap.api.model.Operation;
029    import org.apache.servicemix.soap.bindings.soap.SoapConstants;
030    import org.apache.servicemix.soap.bindings.soap.SoapFault;
031    import org.apache.servicemix.soap.bindings.soap.SoapInterceptor;
032    import org.apache.servicemix.soap.bindings.soap.SoapVersion;
033    import org.apache.servicemix.soap.bindings.soap.model.wsdl1.Wsdl1SoapOperation;
034    import org.apache.servicemix.soap.bindings.soap.model.wsdl1.Wsdl1SoapPart;
035    import org.apache.servicemix.soap.core.AbstractInterceptor;
036    import org.w3c.dom.DocumentFragment;
037    import org.w3c.dom.Element;
038    
039    public class MustUnderstandInterceptor extends AbstractInterceptor {
040    
041        public MustUnderstandInterceptor() {
042        }
043    
044        public void handleMessage(Message message) {
045            Set<URI> serviceRoles = new HashSet<URI>();
046            Set<QName> headerQNames = new HashSet<QName>();
047            Set<QName> understoodQNames = new HashSet<QName>();
048    
049            buildMustUnderstandHeaders(headerQNames, message, serviceRoles);
050            initServiceSideInfo(understoodQNames, message, serviceRoles);
051            headerQNames.removeAll(understoodQNames);
052            if (!headerQNames.isEmpty()) {
053                StringBuffer sb = new StringBuffer(300);
054                int pos = 0;
055                for (QName qname : headerQNames) {
056                    pos = pos + qname.toString().length() + 2;
057                    if (sb.length() > 0) {
058                        sb.append(", ");
059                    }
060                    sb.append(qname.toString());
061                }
062                throw new SoapFault(SoapConstants.SOAP_12_CODE_MUSTUNDERSTAND, sb.toString());
063            }
064        }
065    
066        private void initServiceSideInfo(Set<QName> understoodQNames, 
067                                         Message message,
068                                         Set<URI> serviceRoles) {
069            // Retrieve soap headers bound to message parts
070            Operation operation = message.get(Operation.class);
071            if (operation instanceof Wsdl1SoapOperation) {
072                Wsdl1SoapOperation soapOper = (Wsdl1SoapOperation) operation;
073                for (Wsdl1SoapPart part : soapOper.getInput().getParts()) {
074                    if (part.isHeader()) {
075                        understoodQNames.add(part.getElement());
076                    }
077                }
078            }
079            InterceptorChain chain = message.get(InterceptorChain.class);
080            for (Interceptor interceptorInstance : chain.getInterceptors()) {
081                if (interceptorInstance instanceof SoapInterceptor) {
082                    SoapInterceptor si = (SoapInterceptor) interceptorInstance;
083                    serviceRoles.addAll(si.getRoles());
084                    understoodQNames.addAll(si.getUnderstoodHeaders());
085                }
086            }
087        }
088    
089        private void buildMustUnderstandHeaders(Set<QName> mustUnderstandHeaders, 
090                                                Message message,
091                                                Set<URI> serviceRoles) {
092            SoapVersion soapVersion = message.get(SoapVersion.class);
093            for(DocumentFragment df : message.getSoapHeaders().values()) {
094                for (int i = 0; i < df.getChildNodes().getLength(); i++) {
095                    if (df.getChildNodes().item(i) instanceof Element) {
096                        Element header = (Element) df.getChildNodes().item(i);
097                        String mustUnderstand = header.getAttributeNS(soapVersion.getNamespace(),
098                                                                      soapVersion.getAttrNameMustUnderstand());
099                        if (Boolean.valueOf(mustUnderstand) || "1".equals(mustUnderstand.trim())) {
100                            String role = header.getAttributeNS(soapVersion.getNamespace(), 
101                                                                soapVersion.getAttrNameRole());
102                            QName headerName = new QName(header.getNamespaceURI(), header.getLocalName());
103                            role = role.trim();
104                            if (role != null && role.length() > 0) {
105                                role = role.trim();
106                                if (role.equals(soapVersion.getNextRole()) || role.equals(soapVersion.getUltimateReceiverRole())) {
107                                    mustUnderstandHeaders.add(headerName);
108                                } else {
109                                    for (URI roleFromBinding : serviceRoles) {
110                                        if (role.equals(roleFromBinding)) {
111                                            mustUnderstandHeaders.add(headerName);
112                                        }
113                                    }
114                                }
115                            } else {
116                                // if role omitted, the soap node is ultimate receiver,
117                                // needs to understand
118                                mustUnderstandHeaders.add(headerName);
119                            }
120                        }
121                    }
122                }            
123            }
124        }
125    
126    }