001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2007 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: StatusDetailImpl.java,v 1.3 2008/06/25 05:48:13 qcheng Exp $
026 *
027 */
028
029package com.sun.identity.xacml.context.impl;
030
031import com.sun.identity.shared.xml.XMLUtils;
032
033import com.sun.identity.xacml.common.XACMLConstants;
034import com.sun.identity.xacml.common.XACMLException;
035import com.sun.identity.xacml.common.XACMLSDKUtils;
036import com.sun.identity.xacml.context.StatusDetail;
037
038import java.util.StringTokenizer;
039
040import org.w3c.dom.Document;
041import org.w3c.dom.Element;
042
043/**
044 * The <code>StatusCode</code> element is a container of 
045 * one or more <code>Status</code>s issuded by authorization authority.
046 * @supported.all.api
047 * <p/>
048 *  Schema:
049 * <pre>
050 *  &lt;xs:element name="StatusDetail" type="xacml-context:StatusDetailType"/>
051 *  &lt;xs:complexType name="StatusDetailType">
052 *      &lt;xs:sequence>
053 *      &lt;xs:any namespace="##any" processContents="lax" 
054 *          minOccurs="0" maxOccurs="unbounded"/>
055 *      &lt;xs:sequence>
056 *  &lt;xs:complexType>
057 * >/pre>
058 */
059public class StatusDetailImpl implements StatusDetail {
060
061
062    private Element element;
063    private boolean mutable = true;
064
065    /** 
066     * Constructs a <code>StatusDetail</code> object
067     */
068    public StatusDetailImpl() throws XACMLException {
069        String xmlString = "<xacml-context:StatusDetail xmlns:xacml-context="
070                + "\"urn:oasis:names:tc:xacml:2.0:context:schema:cd:04\"/>";
071        element = new StatusDetailImpl(xmlString).getElement();
072    }
073
074    /** 
075     * Constructs a <code>StatusDetail</code> object from an XML string
076     *
077     * @param xml string representing a <code>StatusDetail</code> object
078     * @throws SAMLException if the XML string could not be processed
079     */
080    public StatusDetailImpl(String xml) throws XACMLException {
081        Document document = XMLUtils.toDOMDocument(xml, XACMLSDKUtils.debug);
082        if (document != null) {
083            Element rootElement = document.getDocumentElement();
084            processElement(rootElement);
085            makeImmutable();
086        } else {
087            XACMLSDKUtils.debug.error(
088                "StatusDetailImpl.processElement(): invalid XML input");
089            throw new XACMLException(
090                XACMLSDKUtils.xacmlResourceBundle.getString(
091                "errorObtainingElement"));
092        }
093    }
094
095    /** 
096     * Constructs a <code>StatusDetail</code> object from an XML DOM element
097     *
098     * @param element XML DOM element representing a <code>StatusDetail</code> 
099     * object
100     *
101     * @throws SAMLException if the DOM element could not be processed
102     */
103    public StatusDetailImpl(Element element) throws XACMLException {
104        processElement(element);
105        makeImmutable();
106    }
107
108    public Element getElement() {
109        return element;
110    }
111
112    public void setElement(Element element) throws XACMLException {
113        if (!mutable) {
114            throw new XACMLException(
115                XACMLSDKUtils.xacmlResourceBundle.getString("objectImmutable"));
116        }
117
118        if (element == null) {
119            throw new XACMLException(
120                XACMLSDKUtils.xacmlResourceBundle.getString("null_not_valid"));
121        }
122
123        String elemName = element.getLocalName();
124        if (elemName == null) {
125            XACMLSDKUtils.debug.error(
126                "StatusMessageImpl.processElement(): local name missing");
127            throw new XACMLException(
128                XACMLSDKUtils.xacmlResourceBundle.getString(
129                "missing_local_name"));
130        }
131        this.element = element;
132    }
133
134   /**
135    * Returns a string representation
136    *
137    * @return a string representation
138    * @exception XACMLException if conversion fails for any reason
139    */
140    public String toXMLString() throws XACMLException {
141        return toXMLString(true, false);
142    }
143
144   /**
145    * Returns a string representation
146    * @param includeNSPrefix Determines whether or not the namespace qualifier
147    *        is prepended to the Element when converted
148    * @param declareNS Determines whether or not the namespace is declared
149    *        within the Element.
150    * @return a string representation
151    * @exception XACMLException if conversion fails for any reason
152     */
153    public String toXMLString(boolean includeNSPrefix, boolean declareNS)
154            throws XACMLException {
155        String xmlString = null;
156        String nsPrefix = "";
157        String nsDeclaration = "";
158        if (includeNSPrefix) {
159            nsPrefix = XACMLConstants.CONTEXT_NS_PREFIX + ":";
160        }
161        if (declareNS) {
162            nsDeclaration = XACMLConstants.CONTEXT_NS_DECLARATION;
163        }
164        if (element != null) {
165            if (includeNSPrefix && (element.getPrefix() == null)) {
166                element.setPrefix(nsPrefix);
167            }
168            if(declareNS) {
169                StringTokenizer st = new StringTokenizer(nsDeclaration, "=");
170                String nsName = st.nextToken();
171                String nsUri = st.nextToken();
172                if (element.getAttribute(nsName) == null) {
173                    element.setAttribute(nsName, nsUri);
174                }
175            }
176            xmlString = XMLUtils.print(element) + "\n";
177        } else {
178            StringBuffer sb = new StringBuffer(2000);
179            sb.append("<").append(nsPrefix)
180                    .append(XACMLConstants.STATUS_DETAIL)
181                    .append(" ")
182                    .append(nsDeclaration)
183                    .append(">")
184                    .append("</")
185                    .append(nsPrefix)
186                    .append(XACMLConstants.STATUS_DETAIL)
187                    .append(">\n");
188            xmlString = sb.toString();
189        }
190        return xmlString;
191    }
192
193   /**
194    * Checks if the object is mutable
195    *
196    * @return <code>true</code> if the object is mutable,
197    *         <code>false</code> otherwise
198    */
199    public boolean isMutable() {
200        return mutable;
201    }
202    
203   /**
204    * Makes the object immutable
205    */
206    public void makeImmutable() {
207        mutable = false;
208    }
209
210    private void processElement(Element element) throws XACMLException {
211        if (element == null) {
212            XACMLSDKUtils.debug.error(
213                "StatusMessageImpl.processElement(): invalid root element");
214            throw new XACMLException(
215                XACMLSDKUtils.xacmlResourceBundle.getString(
216                "invalid_element"));
217        }
218        String elemName = element.getLocalName();
219        if (elemName == null) {
220            XACMLSDKUtils.debug.error(
221                "StatusMessageImpl.processElement(): local name missing");
222            throw new XACMLException(
223                XACMLSDKUtils.xacmlResourceBundle.getString(
224                "missing_local_name"));
225        }
226
227        if (!elemName.equals(XACMLConstants.STATUS_DETAIL)) {
228            XACMLSDKUtils.debug.error(
229                    "StatusMessageImpl.processElement(): invalid local name " 
230                    + elemName);
231            throw new XACMLException(
232                    XACMLSDKUtils.xacmlResourceBundle.getString(
233                    "invalid_local_name"));
234        }
235        this.element = element;
236    }
237
238}