001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: Utils.java,v 1.9 2008/11/10 22:56:59 veiming Exp $
026 *
027 */
028
029/*
030 * Portions Copyright 2013 ForgeRock AS
031 */
032package com.sun.identity.liberty.ws.soapbinding; 
033
034import java.io.ByteArrayInputStream;
035import java.io.ByteArrayOutputStream;
036
037import java.text.MessageFormat;
038
039import java.util.ArrayList;
040import java.util.Date;
041import java.util.HashMap;
042import java.util.HashSet;
043import java.util.Iterator;
044import java.util.List;
045import java.util.Map;
046import java.util.Set;
047import java.util.StringTokenizer;
048
049import javax.xml.bind.Marshaller;
050import javax.xml.bind.Unmarshaller;
051import javax.xml.bind.JAXBContext;
052import javax.xml.bind.JAXBException;
053import javax.xml.bind.NotIdentifiableEvent;
054import javax.xml.bind.PropertyException;
055import javax.xml.bind.ValidationEvent;
056import javax.xml.bind.helpers.DefaultValidationEventHandler;
057import javax.xml.namespace.QName;
058import javax.xml.soap.MessageFactory;
059import javax.xml.soap.SOAPMessage;
060import javax.xml.soap.MimeHeaders;
061import java.util.ResourceBundle;
062import com.sun.identity.common.PeriodicCleanUpMap;
063import com.sun.identity.common.SystemTimerPool;
064import com.sun.identity.common.TaskRunnable;
065import com.sun.identity.common.TimerPool;
066import com.sun.identity.liberty.ws.util.ProviderManager;
067import com.sun.identity.liberty.ws.util.ProviderUtil;
068import com.sun.identity.shared.debug.Debug;
069import com.sun.identity.shared.locale.Locale;
070import com.sun.identity.shared.configuration.SystemPropertiesManager;
071import com.sun.identity.shared.xml.XMLUtils;
072
073import org.w3c.dom.Document;
074import org.w3c.dom.Element;
075import com.sun.org.apache.xml.internal.utils.PrefixResolverDefault;
076
077/**
078 * This class contains utility methods.
079 *
080 * @supported.api
081 */
082
083public class Utils {
084    static final String NAMESPACE_PREFIX_MAPPING_LIST_PROP =
085                "com.sun.identity.liberty.ws.jaxb.namespacePrefixMappingList";
086    static final String JAXB_PACKAGE_LIST_PROP =
087                "com.sun.identity.liberty.ws.jaxb.packageList";
088
089
090    static final String DEFAULT_JAXB_PACKAGES =
091        "com.sun.identity.liberty.ws.common.jaxb.soap:" +
092        "com.sun.identity.liberty.ws.common.jaxb.assertion:" +
093        "com.sun.identity.liberty.ws.common.jaxb.protocol:" +
094        "com.sun.identity.liberty.ws.common.jaxb.ac:" +
095        "com.sun.identity.liberty.ws.disco.jaxb:" +
096        "com.sun.identity.liberty.ws.disco.jaxb11:" +
097        "com.sun.identity.liberty.ws.disco.plugins.jaxb:" +
098        "com.sun.identity.liberty.ws.interaction.jaxb:" +
099        "com.sun.identity.liberty.ws.meta.jaxb:" +
100        "com.sun.identity.liberty.ws.paos.jaxb:" +
101        "com.sun.identity.liberty.ws.common.jaxb.ps:" +
102        "com.sun.identity.liberty.ws.common.jaxb.security:" +
103        "com.sun.identity.liberty.ws.soapbinding.jaxb:" +
104        "com.sun.identity.liberty.ws.soapbinding.jaxb11:" +
105        "com.sun.identity.liberty.ws.idpp.jaxb:" +
106        "com.sun.identity.liberty.ws.idpp.plugin.jaxb:" +
107        "com.sun.identity.liberty.ws.common.jaxb.secext:" +
108        "com.sun.identity.liberty.ws.common.jaxb.utility:" +
109        "com.sun.identity.liberty.ws.common.jaxb.xmlenc:" +
110        "com.sun.identity.liberty.ws.common.jaxb.xmlsig";
111
112    static com.sun.identity.liberty.ws.common.jaxb.soap.ObjectFactory soapOF =
113        new com.sun.identity.liberty.ws.common.jaxb.soap.ObjectFactory();
114
115    static com.sun.identity.liberty.ws.soapbinding.jaxb.ObjectFactory soapBOF =
116        new com.sun.identity.liberty.ws.soapbinding.jaxb.ObjectFactory();
117
118    static com.sun.identity.liberty.ws.common.jaxb.secext.ObjectFactory secOF =
119        new com.sun.identity.liberty.ws.common.jaxb.secext.ObjectFactory();
120
121    static final QName FAULT_CODE_SERVER =
122                             new QName(SOAPBindingConstants.NS_SOAP, "Server");
123    static String faultStringServerError = null;
124    static Debug debug = null;
125    public static ResourceBundle bundle = null;
126
127    static MessageFactory messageFactory = null;
128
129    static HashMap nsPrefix = new HashMap();
130    static String jaxbPackages = null;
131    static JAXBContext jc = null;
132
133    static final String STALE_TIME_LIMIT_PROP =
134                "com.sun.identity.liberty.ws.soap.staleTimeLimit";
135    static int stale_time_limit = 300000; // millisec
136
137    static final String SUPPORTED_ACTORS_PROP =
138               "com.sun.identity.liberty.ws.soap.supportedActors";
139    static final String LIBERTY_WSF_VERSION =
140        "com.sun.identity.liberty.wsf.version";
141    static Set supportedActors = new HashSet();
142
143    static final String MESSAGE_ID_CACHE_CLEANUP_INTERVAL_PROP =
144        "com.sun.identity.liberty.ws.soap.messageIDCacheCleanupInterval";
145    static int message_ID_cleanup_interval = 60000; // millisec    
146    private static Map messageIDMap = null;
147
148    static {
149        bundle = Locale.getInstallResourceBundle("libSOAPBinding");
150        faultStringServerError = bundle.getString("ServerError");
151        debug = Debug.getInstance("libIDWSF");
152
153        try {
154            messageFactory = MessageFactory.newInstance();
155        } catch (Exception ex) {
156            debug.error("Utils.static: Unable to create SOAP Message Factory",
157                        ex);
158        }
159
160        String tmpNSPre =
161                  SystemPropertiesManager.get(NAMESPACE_PREFIX_MAPPING_LIST_PROP);
162        if (tmpNSPre != null && tmpNSPre.length() > 0) {
163            StringTokenizer stz = new StringTokenizer(tmpNSPre, "|");
164            while(stz.hasMoreTokens()) {
165                String token = stz.nextToken().trim();
166                int index = token.indexOf('=');
167                if (index != -1 && index != 0 && index != token.length() - 1) {
168                    String prefix = token.substring(0, index);
169                    String ns = token.substring(index + 1);
170                    if (debug.messageEnabled()) {
171                        debug.message("Utils.static: add ns = " + ns +
172                                      ", prefix = " + prefix);
173                    }
174                    nsPrefix.put(ns, prefix);
175                } else {
176                    if (debug.warningEnabled()) {
177                        debug.warning("Utils.static: Invalid syntax " +
178                                      "for Namespace Prefix Mapping List: " +
179                                      token);
180                    }
181                }
182            }          
183        }
184
185        String tmpJaxbPkgs = SystemPropertiesManager.get(JAXB_PACKAGE_LIST_PROP);
186        if (tmpJaxbPkgs != null && tmpJaxbPkgs.length() > 0) {
187            jaxbPackages = DEFAULT_JAXB_PACKAGES + ":" + tmpJaxbPkgs;
188        } else {
189            jaxbPackages = DEFAULT_JAXB_PACKAGES;
190        }
191        if (debug.messageEnabled()) {
192            debug.message("Utils.static: jaxbPackages = " + jaxbPackages);
193        }
194
195        try {
196            jc = JAXBContext.newInstance(jaxbPackages);
197        } catch (JAXBException jaxbe) {
198            Utils.debug.error("Utils.static:", jaxbe);
199        }
200
201        String tmpstr = SystemPropertiesManager.get(STALE_TIME_LIMIT_PROP);
202        if (tmpstr != null) {
203            try {
204                stale_time_limit = Integer.parseInt(tmpstr);
205            } catch (Exception ex) {
206                if (debug.warningEnabled()) {
207                    debug.warning("Utils.static: Unable to get stale time " +
208                                  "limit. Default value will be used");
209                }
210            }
211        }
212
213        tmpstr = SystemPropertiesManager.get(SUPPORTED_ACTORS_PROP);
214        if (tmpstr != null) {
215            StringTokenizer stz = new StringTokenizer(tmpstr, "|");
216            while(stz.hasMoreTokens()) {
217                String token = stz.nextToken();
218                if (token.length() > 0) {
219                    supportedActors.add(token);
220                }
221            }
222        }
223        tmpstr =
224            SystemPropertiesManager.get(MESSAGE_ID_CACHE_CLEANUP_INTERVAL_PROP);
225        if (tmpstr != null) {
226            try {
227                message_ID_cleanup_interval = Integer.parseInt(tmpstr);
228            } catch (Exception ex) {
229                if (debug.warningEnabled()) {
230                    debug.warning("Utils.CleanUpThread.static: Unable to" +
231                            " get stale time limit. Default value " +
232                            "will be used");
233                }
234            }
235        }
236        messageIDMap = new PeriodicCleanUpMap(
237            message_ID_cleanup_interval, stale_time_limit);
238        SystemTimerPool.getTimerPool().schedule((TaskRunnable) messageIDMap,
239            new Date(((System.currentTimeMillis() + message_ID_cleanup_interval)
240            / 1000) * 1000));
241    }
242
243    /**
244     * Returns JAXB namespace prefix mapping. Key is the namespace and value
245     * is the prefix.
246     *
247     * @return a Map of JAXB namespace prefix mapping
248     * @supported.api
249     */
250    static public Map getNamespacePrefixMapping() {
251        return nsPrefix;
252    }
253
254    /**
255     * Returns a String of JAXB packages seperated by ":".
256     *
257     * @return a String of JAXB packages seperated by ":".
258     * @supported.api
259     */
260    public static String getJAXBPackages() {
261        return jaxbPackages;
262    }
263
264    /**
265     * Converts Document to SOAPMessage
266     *
267     * @param doc the source Document
268     * @return SOAPMessage
269     * @throws SOAPBindingException if an error occurs while converting
270     *         the document
271     * @supported.api
272     */
273    public static SOAPMessage DocumentToSOAPMessage(Document doc)
274    throws SOAPBindingException {
275        SOAPMessage msg = null;
276        try {
277            MimeHeaders mimeHeaders = new MimeHeaders();
278            mimeHeaders.addHeader("Content-Type", "text/xml");
279            
280            String xmlstr = XMLUtils.print(doc);
281            if (debug.messageEnabled()) {
282                debug.message("Utils.DocumentToSOAPMessage: xmlstr = " +
283                        xmlstr);
284            }
285            msg = messageFactory.createMessage(
286                    mimeHeaders,
287                    new ByteArrayInputStream(
288                    xmlstr.getBytes(SOAPBindingConstants.DEFAULT_ENCODING)));
289        } catch (Exception e) {
290            debug.error("Utils.DocumentToSOAPMessage", e);
291            throw new SOAPBindingException(e.getMessage());
292        }
293        return msg;
294    }
295
296    /**
297     * Converts a list of JAXB objects to a list of 
298     * <code>org.w3c.dom.Element</code>
299     *
300     * @param jaxbObjs a list of JAXB objects
301     * @return a list of <code>org.w3c.dom.Element</code>
302     * @throws JAXBException if an error occurs while converting JAXB objects.
303     *
304     * @supported.api
305     */
306    public static List convertJAXBToElement(List jaxbObjs) 
307                                            throws JAXBException{
308        List result = new ArrayList();
309        if (jaxbObjs != null && !jaxbObjs.isEmpty()) {
310            Iterator iter = jaxbObjs.iterator();
311            while(iter.hasNext()) {
312                result.add(convertJAXBToElement(iter.next()));
313            }
314        }
315        return result;
316    }
317
318    /**
319     * Converts a JAXB object to a <code>org.w3c.dom.Element</code>.
320     *
321     * @param jaxbObj a JAXB object
322     * @return a <code>org.w3c.dom.Element</code>
323     * @throws JAXBException if an error occurs while converting JAXB object.
324     * @supported.api
325     */
326    public static Element convertJAXBToElement(Object jaxbObj)
327                          throws JAXBException {
328        Marshaller m = jc.createMarshaller();
329        try {
330            m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
331                    new NamespacePrefixMapperImpl());
332        } catch(PropertyException ex) {
333            debug.error("Utils.convertJAXBToElement", ex);
334        }
335        Document doc = null;
336        try {
337            doc = XMLUtils.newDocument();
338        } catch (Exception ex) {
339            debug.error("Utils.convertJAXBToElement:", ex);
340        }
341        m.marshal(jaxbObj, doc);
342        return doc.getDocumentElement();
343    }
344
345    /**
346     * Converts a JAXB object to a <code>org.w3c.dom.Element</code>.
347     *
348     * @param jaxbObj a JAXB object
349     * @return a <code>org.w3c.dom.Element</code>
350     * @throws JAXBException if an error occurs while converting JAXB object.
351     * @supported.api
352     */
353    public static Element convertJAXBToElement(Object jaxbObj,
354            boolean checkIdref) throws JAXBException {
355        Marshaller m = jc.createMarshaller();
356        try {
357            m.setProperty("com.sun.xml.bind.namespacePrefixMapper",
358                    new NamespacePrefixMapperImpl());
359            
360        } catch(PropertyException ex) {
361            debug.error("Utils.convertJAXBToElement", ex);
362        }
363        
364        if (!checkIdref) {
365            m.setEventHandler(
366                    new DefaultValidationEventHandler() {
367                public boolean handleEvent(ValidationEvent event) {
368                    if (event instanceof NotIdentifiableEvent) {
369                        return true;
370                    }
371                    return super.handleEvent(event);
372                }
373            });
374        }
375        
376        Document doc = null;
377        try {
378            doc = XMLUtils.newDocument();
379        } catch (Exception ex) {
380            debug.error("Utils.convertJAXBToElement:", ex);
381        }
382        m.marshal(jaxbObj, doc);
383        return doc.getDocumentElement();
384    }
385
386    /**
387     * Converts a list of <code>org.w3c.dom.Element</code> to a list of 
388     * JAXB objects.
389     *
390     * @param elements a list of <code>org.w3c.dom.Element</code>
391     * @return a list of JAXB objects
392     * @throws JAXBException if an error occurs while converting
393     *                          <code>org.w3c.dom.Element</code>.
394     * @supported.api
395     */
396    public static List convertElementToJAXB(List elements) 
397                                            throws JAXBException{
398        List result = new ArrayList();
399        if (elements != null && !elements.isEmpty()) {
400            Iterator iter = elements.iterator();
401            while(iter.hasNext()) {
402                result.add(convertElementToJAXB((Element)iter.next()));
403            }
404        }
405        return result;
406    }
407
408    /**
409     * Converts a <code>org.w3c.dom.Element</code> to a JAXB object.
410     *
411     * @param element a <code>org.w3c.dom.Element</code>.
412     * @return a JAXB object
413     * @throws JAXBException if an error occurs while converting
414     *                          <code>org.w3c.dom.Element</code>
415     * @supported.api
416     */
417    public static Object convertElementToJAXB(Element element)
418                         throws JAXBException {
419        Unmarshaller u = jc.createUnmarshaller();
420        return u.unmarshal(element);
421    }
422
423    /**
424     * Converts a value of XML boolean type to Boolean object.
425     *
426     * @param str a value of XML boolean type
427     * @return a Boolean object
428     * @throws Exception if there is a syntax error
429     * @supported.api
430     */
431    public static Boolean StringToBoolean(String str) throws Exception {
432        if (str == null) {
433            return null;
434        }
435        
436        if (str.equals("true") || str.equals("1")) {
437            return Boolean.TRUE;
438        }
439        
440        if (str.equals("false") || str.equals("0")) {
441            return Boolean.FALSE;
442        }
443        
444        throw new Exception();
445    }
446
447    /**
448     * Converts a Boolean object to a String representing XML boolean.
449     *
450     * @param bool a Boolean object.
451     * @return a String representing the boolean value.
452     * @supported.api
453     */
454    public static String BooleanToString(Boolean bool) {
455        if (bool == null) {
456            return "";
457        }
458        
459        return bool.booleanValue() ? "1" : "0";
460    }
461
462    /**
463     * Converts a string value to a QName. The prefix of the string value
464     * is resolved to a namespace relative to the element.
465     *
466     * @param str the String to be converted.
467     * @param element the Element object.
468     * @return the QName Object.
469     * @supported.api
470     */
471    public static QName convertStringToQName(String str,Element element) {
472        if (str == null) {
473            return null;
474        }
475        
476        String prefix = "";
477        String localPart;
478        int index = str.indexOf(":");
479        if (index == -1) {
480            localPart = str;
481        } else {
482            prefix = str.substring(0, index);
483            localPart = str.substring(index + 1);
484        }
485        PrefixResolverDefault prd =
486                new PrefixResolverDefault(element.getOwnerDocument());
487        String ns = prd.getNamespaceForPrefix(prefix, element);
488        return new QName(ns, localPart);
489    }
490
491    /**
492     * Enforces message processiong rules defined in the spec.
493     *
494     * @param message a message
495     * @param requestMessageID the request messageID if we are checking a
496     *                         response message or null if we are checking a
497     *                         request message
498     * @param isServer true if this is a server
499     * @throws SOAPBindingException if the message violates rules on client.
500     * @throws SOAPFaultException if the message violates rules on server.
501     */
502    public static void enforceProcessingRules(Message message, String requestMessageID,
503            boolean isServer)
504            throws SOAPBindingException, SOAPFaultException {
505        CorrelationHeader corrH = message.getCorrelationHeader();
506        String messageID = corrH.getMessageID();
507        checkCorrelationHeader(corrH, requestMessageID, isServer);
508        checkProviderHeader(message.getProviderHeader(), messageID, isServer);
509        checkProcessingContextHeader(message.getProcessingContextHeader(),
510                messageID, isServer);
511        checkConsentHeader(message.getConsentHeader(), messageID, isServer);
512        List usagHs = message.getUsageDirectiveHeaders();
513        if (usagHs != null && !usagHs.isEmpty()) {
514            Iterator iter = usagHs.iterator();
515            while(iter.hasNext()) {
516                UsageDirectiveHeader usagH = (UsageDirectiveHeader)iter.next();
517                checkUsageDirectiveHeader(usagH, messageID, isServer);
518            }
519        }
520    }
521    
522    /**
523     * Enforces message Correlation header processiong rules defined
524     * in the spec.
525     *
526     * @param  corrH a Correlation header
527     * @param  requestMessageID the request messageID if we are checking a
528     *                         response message or null if we are checking a
529     *                         request message
530     * @param  isServer true if this is a server
531     * @throws SOAPBindingException if the Correlation header violates rules
532     *         on client side
533     * @throws SOAPFaultException if the Correlation header violates rules
534     *                               on server side
535     */
536    static void checkCorrelationHeader(CorrelationHeader corrH,
537            String  requestMessageID, boolean isServer)
538            throws SOAPBindingException, SOAPFaultException {
539        if (corrH == null) {
540            if (isServer) {
541                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
542                        faultStringServerError, null,
543                        new SOAPFaultDetail(
544                        SOAPFaultDetail.ID_STAR_MSG_NOT_UNSTD,null,null));
545                throw new SOAPFaultException(new Message(sf));
546            } else {
547                throw new SOAPBindingException(
548                        bundle.getString("CorrelationHeaderNull"));
549            }
550        }
551        
552        String messageID = corrH.getMessageID();
553        
554        try {
555            checkActorAndMustUnderstand(corrH.getActor(),
556                    corrH.getMustUnderstand(),
557                    messageID, isServer);
558        } catch (SOAPFaultException sfe) {
559            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
560            .setCorrelationHeader(corrH);
561            throw sfe;
562        }
563        
564        Date timestamp = corrH.getTimestamp();
565        Date now = new Date();
566        if ((now.getTime() - timestamp.getTime()) > stale_time_limit) {
567            if (isServer) {
568                SOAPFaultDetail sfd =
569                        new SOAPFaultDetail(SOAPFaultDetail.STALE_MSG,
570                        messageID, null);
571                sfd.setCorrelationHeader(corrH);
572                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
573                        faultStringServerError, null, sfd);
574                throw new SOAPFaultException(new Message(sf));
575                
576            } else {
577                throw new SOAPBindingException(bundle.getString("staleMsg"));
578            }
579        }
580        
581        Long prevMsgIDTime = (Long)messageIDMap.get(messageID);
582        long currentTime = System.currentTimeMillis();
583        if (prevMsgIDTime != null &&
584                currentTime - prevMsgIDTime.longValue() < stale_time_limit) {
585            
586            if (isServer) {
587                SOAPFaultDetail sfd =
588                        new SOAPFaultDetail(SOAPFaultDetail.DUPLICATE_MSG,
589                        messageID, null);
590                sfd.setCorrelationHeader(corrH);
591                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
592                        faultStringServerError, null, sfd);
593                throw new SOAPFaultException(new Message(sf));
594                
595            } else {
596                throw new SOAPBindingException(bundle.getString("dupMsg"));
597            }
598        } else {
599            synchronized (messageIDMap) {
600                if (debug.messageEnabled()) {
601                    debug.message("Utils.checkCorrelationHeader: adding " +
602                            "messageID: " + messageID);
603                }
604                messageIDMap.put(messageID, new Long(currentTime));
605            }
606        }
607        
608        String refToMessageID = corrH.getRefToMessageID();
609        if (refToMessageID != null && requestMessageID != null &&
610                !refToMessageID.equals(requestMessageID)) {
611            
612            if (isServer) {
613                SOAPFaultDetail sfd =
614                        new SOAPFaultDetail(
615                        SOAPFaultDetail.INVALID_REF_TO_MSG_ID,messageID, null);
616                sfd.setCorrelationHeader(corrH);
617                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
618                        faultStringServerError, null, sfd);
619                throw new SOAPFaultException(new Message(sf));
620                
621            } else {
622                throw new SOAPBindingException(bundle.getString("invalidRef"));
623            }
624        }
625    }
626
627    /**
628     * Enforces message Provider header processiong rules defined
629     * in the spec.
630     *
631     * @param corrH a Correlation header
632     * @param messageID the messageID in Correlation header
633     * @param isServer true if this is a server
634     * @throws SOAPBindingException if the Provider header violates rules
635     *                                 on client side
636     * @throws SOAPFaultException if the Provider header violates rules
637     *                               on server side
638     */
639    static void checkProviderHeader(ProviderHeader provH,
640            String messageID,boolean isServer)
641            throws SOAPBindingException, SOAPFaultException {
642
643        if (provH == null) {
644            return;
645        }
646        
647        try {
648            checkActorAndMustUnderstand(provH.getActor(),
649                    provH.getMustUnderstand(),
650                    messageID, isServer);
651        } catch (SOAPFaultException sfe) {
652            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
653            .setProviderHeader(provH);
654            throw sfe;
655        }
656        
657        if (isServer && SOAPBindingService.enforceOnlyKnownProviders()) {
658            String providerID = provH.getProviderID();
659            ProviderManager providerManager = ProviderUtil.getProviderManager();
660
661            if (!providerManager.containsProvider(providerID)) {
662                SOAPFaultDetail sfd = new SOAPFaultDetail(
663                    SOAPFaultDetail.PROVIDER_ID_NOT_VALID, messageID, null);
664                sfd.setProviderHeader(provH);
665                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
666                    faultStringServerError, null, sfd);
667                throw new SOAPFaultException(new Message(sf));
668            }
669            
670            String affID = provH.getAffiliationID();
671            if ((affID != null) &&
672                (!providerManager.isAffiliationMember(providerID, affID))) {
673
674                SOAPFaultDetail sfd = new SOAPFaultDetail(
675                    SOAPFaultDetail.AFFILIATION_ID_NOT_VALID, messageID, null);
676                sfd.setProviderHeader(provH);
677                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
678                    faultStringServerError, null, sfd);
679                throw new SOAPFaultException(new Message(sf));
680            }
681        }
682    }
683
684    /**
685     * Enforces message Processing Context header processiong rules defined
686     * in the spec.
687     * @param procH a Processing Context header
688     * @param messageID the messageID in Correlation header
689     * @param isServer true if this is a server
690     * @throws SOAPBindingException if the Processing Context header
691     *                                 violates rules on client side
692     * @throws SOAPFaultException if the Processing Context header violates
693     *                               rules on server side
694     */
695    static void checkProcessingContextHeader(ProcessingContextHeader procH,
696            String messageID, boolean isServer)
697            throws SOAPBindingException, SOAPFaultException {
698        if (procH == null) {
699            return;
700        }
701
702        try {
703            checkActorAndMustUnderstand(procH.getActor(),
704                                        procH.getMustUnderstand(),
705                                        messageID, isServer);
706        } catch (SOAPFaultException sfe) {
707            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
708               .setProcessingContextHeader(procH);
709            throw sfe;
710        }
711
712        if (isServer) {
713            SOAPFaultDetail sfd =
714                    new SOAPFaultDetail(SOAPFaultDetail.PROC_CTX_URI_NOT_UNSTD,
715                                        messageID, null);
716            sfd.setProcessingContextHeader(procH);
717            SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
718                                         faultStringServerError, null, sfd);
719            throw new SOAPFaultException(new Message(sf));
720        } else {
721            throw new SOAPBindingException(
722                            bundle.getString("ProcessingContextUnsupported"));
723        }
724    }
725
726    /**
727     * Enforces message Consent header processiong rules defined in the spec.
728     *
729     * @param consH a Consent header
730     * @param messageID the messageID in Correlation header
731     * @param isServer true if this is a server
732     * @throws SOAPBindingException if the Consent header violates rules on
733     *                                 client side
734     * @throws SOAPFaultException if the Consent header violates rules
735     *                               on server side
736     */
737    static void checkConsentHeader(ConsentHeader consH,String messageID,
738            boolean isServer) throws SOAPBindingException, SOAPFaultException {
739        if (consH == null) {
740            return;
741        }
742        
743        try {
744            checkActorAndMustUnderstand(consH.getActor(),
745                    consH.getMustUnderstand(),
746                    messageID, isServer);
747        } catch (SOAPFaultException sfe) {
748            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
749            .setConsentHeader(consH);
750            throw sfe;
751        }
752    }
753
754    /**
755     * Enforces message Usage Directive header processiong rules defined in
756     * the spec.
757     *
758     * @param usagH a Usage Directive header
759     * @param messageID the messageID in Correlation header
760     * @param isServer true if this is a server
761     * @throws SOAPBindingException if the Usage Directive header violates
762     *                                 rules on client side
763     * @throws SOAPFaultException if the Usage Directive header violates
764     *                               rules on server side
765     */
766    static void checkUsageDirectiveHeader(UsageDirectiveHeader usagH,
767            String messageID,boolean isServer)
768            throws SOAPBindingException, SOAPFaultException {
769        if (usagH == null) {
770            return;
771        }
772        
773        try {
774            checkActorAndMustUnderstand(usagH.getActor(),
775                    usagH.getMustUnderstand(),
776                    messageID, isServer);
777        } catch (SOAPFaultException sfe) {
778            List usagHs = new ArrayList();
779            usagHs.add(usagH);
780            sfe.getSOAPFaultMessage().getSOAPFault().getDetail()
781            .setUsageDirectiveHeaders(usagHs);
782            throw sfe;
783        }
784    }
785
786    /**
787     * Checks 'actor' and 'mustUnderstand' attribute of a header.
788     *
789     * @param actor the value of 'actor' attribute of a header.
790     * @param mustUnderstand the value of 'mustUnderstand' attribute of a
791     *                       header.
792     * @param messageID the messageID in Correlation header.
793     * @param isServer true if this is a server.
794     * @throws SOAPBindingException if the actor and mustUnderstand violates
795     *                                 rules on client side
796     * @throws SOAPFaultException if the actor and mustUnderstand violates
797     *                               rules on server side
798     */
799    static void checkActorAndMustUnderstand(String actor,Boolean mustUnderstand,
800            String messageID,boolean isServer)
801            throws SOAPBindingException, SOAPFaultException {
802        if (actor != null && !supportedActors.contains(actor)) {
803            if (isServer) {
804                SOAPFaultDetail sfd =
805                        new SOAPFaultDetail(SOAPFaultDetail.BOGUS_ACTOR,
806                        messageID, null);
807                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
808                        faultStringServerError, null, sfd);
809                throw new SOAPFaultException(new Message(sf));
810            } else {
811                throw new SOAPBindingException(
812                        bundle.getString("bogusActor"));
813            }
814        }
815        
816        if (mustUnderstand != null && !mustUnderstand.booleanValue()) {
817            if (isServer) {
818                SOAPFaultDetail sfd =
819                        new SOAPFaultDetail(SOAPFaultDetail.BOGUS_MUST_UNSTND,
820                        messageID, null);
821                SOAPFault sf = new SOAPFault(FAULT_CODE_SERVER,
822                        faultStringServerError, null, sfd);
823                throw new SOAPFaultException(new Message(sf));
824            } else {
825                throw new SOAPBindingException(
826                        bundle.getString("bogusMustUnderstand"));
827            }
828        }
829    }
830    
831    /**
832     * Gets localized string from resource bundle.
833     *
834     * @param key a key to a resource bundle
835     * @param params parameters to MessageFormat
836     * @return a localized string.
837     * @supported.api
838     */
839    public static String getString(String key, Object[] params) {
840        return MessageFormat.format(bundle.getString(key), params);
841    }
842    
843    /**
844     * Returns the default web services version.
845     *
846     * @return the default web services version.
847     */
848    public static String getDefaultWSFVersion() {
849        return SystemPropertiesManager.get(LIBERTY_WSF_VERSION,
850            SOAPBindingConstants.WSF_11_VERSION);
851    }
852
853}