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: StatusCodeImpl.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.StatusCode;
037
038import java.util.ArrayList;
039import java.util.List;
040
041import org.w3c.dom.Document;
042import org.w3c.dom.Element;
043import org.w3c.dom.Node;
044import org.w3c.dom.NodeList;
045
046/**
047 * The <code>StatusCode</code> element is a container of 
048 * one or more <code>StatusCode</code>s issuded by authorization authority.
049 * @supported.all.api
050 * <p/>
051 * <pre>
052 *
053 * Schema:
054 *  &lt;xs:element name="StatusCode" type="xacml-context:StatusCodeType"/>
055 *  &lt;xs:complexType name="StatusCodeType">
056 *      &lt;xs:sequence>
057 *          &lt;xs:element ref="xacml-context:StatusCode" minOccurs="0"/>
058 *      &lt;xs:sequence>
059 *      &lt;xs:attribute name="Value" type="xs:anyURI" use="required"/>
060 *  &lt;xs:complexType>
061 * </pre>
062 */
063public class StatusCodeImpl implements StatusCode {
064
065
066    String value = null;
067    String minorCodeValue = null;
068    private boolean mutable = true;
069
070    /** 
071     * Constructs a <code>StatusCode</code> object
072     */
073    public StatusCodeImpl() throws XACMLException {
074    }
075
076    /** 
077     * Constructs a <code>StatusCode</code> object from an XML string
078     *
079     * @param xml string representing a <code>StatusCode</code> object
080     * @throws SAMLException if the XML string could not be processed
081     */
082    public StatusCodeImpl(String xml) throws XACMLException {
083        Document document = XMLUtils.toDOMDocument(xml, XACMLSDKUtils.debug);
084        if (document != null) {
085            Element rootElement = document.getDocumentElement();
086            processElement(rootElement);
087            makeImmutable();
088        } else {
089            XACMLSDKUtils.debug.error(
090                "StatusCodeImpl.processElement(): invalid XML input");
091            throw new XACMLException(
092                XACMLSDKUtils.xacmlResourceBundle.getString(
093                "errorObtainingElement"));
094        }
095    }
096
097    /** 
098     * Constructs a <code>StatusCode</code> object from an XML DOM element
099     *
100     * @param element XML DOM element representing a <code>StatusCode</code> 
101     * object
102     *
103     * @throws SAMLException if the DOM element could not be processed
104     */
105    public StatusCodeImpl(Element element) throws XACMLException {
106        processElement(element);
107        makeImmutable();
108    }
109
110    /**
111     * Returns the <code>value</code> of this object
112     *
113     * @return the <code>value</code> of this object
114     */
115    public String getValue() {
116        return value;
117    }
118
119    /**
120     * Sets the <code>value</code> of this object
121     *
122     * @exception XACMLException if the object is immutable
123     */
124    public void setValue(String value) throws XACMLException {
125        if (!mutable) {
126            throw new XACMLException(
127                XACMLSDKUtils.xacmlResourceBundle.getString(
128                "objectImmutable"));
129        }
130
131        if (value == null) {
132            throw new XACMLException(
133                XACMLSDKUtils.xacmlResourceBundle.getString("null_not_valid"));
134        }
135
136        if (!XACMLSDKUtils.isValidStatusCode(value)) {
137            throw new XACMLException(
138                XACMLSDKUtils.xacmlResourceBundle.getString("invalid_value"));
139        }
140        this.value = value;
141    }
142
143    /**
144     * Returns the <code>minorCodeValue</code> of this object
145     *
146     * @return the <code>minorCodeValue</code> of this object
147     */
148    public String getMinorCodeValue() {
149        return minorCodeValue;
150    }
151
152    /**
153     * Sets the <code>minorCodeValue</code> of this object
154     *
155     * @exception XACMLException if the object is immutable
156     */
157    public void setMinorCodeValue(String minorCodeValue) 
158            throws XACMLException {
159        if (!mutable) {
160            throw new XACMLException(
161                XACMLSDKUtils.xacmlResourceBundle.getString("objectImmutable"));
162        }
163
164        if (value == null) {
165            throw new XACMLException(
166                XACMLSDKUtils.xacmlResourceBundle.getString("null_not_valid"));
167        }
168
169        if (!XACMLSDKUtils.isValidMinorStatusCode(value)) {
170            throw new XACMLException(
171                XACMLSDKUtils.xacmlResourceBundle.getString("invalid_value"));
172        }
173        this.minorCodeValue = minorCodeValue;
174    }
175
176   /**
177    * Returns a string representation
178    *
179    * @return a string representation
180    * @exception XACMLException if conversion fails for any reason
181    */
182    public String toXMLString() throws XACMLException {
183        return toXMLString(true, false);
184    }
185
186   /**
187    * Returns a string representation
188    * @param includeNSPrefix Determines whether or not the namespace qualifier
189    *        is prepended to the Element when converted
190    * @param declareNS Determines whether or not the namespace is declared
191    *        within the Element.
192    * @return a string representation
193    * @exception XACMLException if conversion fails for any reason
194     */
195    public String toXMLString(boolean includeNSPrefix, boolean declareNS)
196            throws XACMLException {
197        StringBuffer sb = new StringBuffer(2000);
198        String nsPrefix = "";
199        String nsDeclaration = "";
200        if (includeNSPrefix) {
201            nsPrefix = XACMLConstants.CONTEXT_NS_PREFIX + ":";
202        }
203        if (declareNS) {
204            nsDeclaration = XACMLConstants.CONTEXT_NS_DECLARATION;
205        }
206        sb.append("<").append(nsPrefix)
207                .append(XACMLConstants.STATUS_CODE)
208                .append(" ")
209                .append(nsDeclaration);
210        if (value != null) {
211            sb.append(XACMLConstants.VALUE)
212            .append("=")
213            .append(XACMLSDKUtils.quote(value));
214        }
215        sb.append(">");
216        if (minorCodeValue != null) {
217            sb.append("<").append(nsPrefix)
218                    .append(XACMLConstants.STATUS_CODE)
219                    .append(" ")
220                    .append(nsDeclaration)
221                    .append(XACMLConstants.VALUE)
222                    .append("=")
223                    .append(XACMLSDKUtils.quote(minorCodeValue))
224                    .append(">");
225                    sb.append("</").append(nsPrefix)
226                            .append(XACMLConstants.STATUS_CODE)
227                            .append(">");
228        }
229        sb.append("</").append(nsPrefix).append(XACMLConstants.STATUS_CODE)
230                .append(">\n");
231        return sb.toString();
232    }
233
234   /**
235    * Checks if the object is mutable
236    *
237    * @return <code>true</code> if the object is mutable,
238    *         <code>false</code> otherwise
239    */
240    public boolean isMutable() {
241        return mutable;
242    }
243    
244   /**
245    * Makes the object immutable
246    */
247    public void makeImmutable() {
248        mutable = false;
249    }
250
251    private void processElement(Element element) throws XACMLException {
252        if (element == null) {
253            XACMLSDKUtils.debug.error(
254                "StatusMessageImpl.processElement(): invalid root element");
255            throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString(
256                "invalid_element"));
257        }
258        String elemName = element.getLocalName();
259        if (elemName == null) {
260            XACMLSDKUtils.debug.error(
261                "StatusMessageImpl.processElement(): local name missing");
262            throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString(
263                "missing_local_name"));
264        }
265
266        if (!elemName.equals(XACMLConstants.STATUS_CODE)) {
267            XACMLSDKUtils.debug.error(
268                    "StatusMessageImpl.processElement(): invalid local name " 
269                    + elemName);
270            throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString(
271                    "invalid_local_name"));
272        }
273        String attrValue = element.getAttribute(XACMLConstants.VALUE);
274        if ((attrValue == null) || (attrValue.length() == 0)) {
275            XACMLSDKUtils.debug.error(
276                "StatusCodeImpl.processElement(): statuscode missing");
277            throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString(
278                "missing_status_code")); //i18n
279        } 
280        if (!XACMLSDKUtils.isValidStatusMessage(attrValue.trim())) {
281            throw new XACMLException(
282                    XACMLSDKUtils.xacmlResourceBundle.getString(
283                    "invalid_value"));
284        } else {
285            this.value = attrValue;
286        }
287        //process child StatusCode element
288        NodeList nodes = element.getChildNodes();
289        int numOfNodes = nodes.getLength();
290        List childElements = new ArrayList(); 
291        int i = 0;
292        while (i < numOfNodes) { 
293            Node child = (Node) nodes.item(i);
294            if (child.getNodeType() == Node.ELEMENT_NODE) {
295                childElements.add(child);
296            }
297           i++;
298        }
299        int childCount = childElements.size();
300        if (childCount > 1) {
301            XACMLSDKUtils.debug.error(
302                "ResultImpl.processElement(): invalid child element count: " 
303                        + childCount);
304            throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString(
305                "invalid_child_count"));
306        }
307        if (childCount == 1) {
308            Element childElement = (Element)childElements.get(0);
309            elemName = childElement.getLocalName();
310            if (elemName == null) {
311                XACMLSDKUtils.debug.error(
312                    "StatusMessageImpl.processElement(): local name missing");
313                throw new XACMLException(
314                    XACMLSDKUtils.xacmlResourceBundle.getString(
315                    "missing_local_name"));
316            }
317
318            if (!elemName.equals(XACMLConstants.STATUS_CODE)) {
319                XACMLSDKUtils.debug.error(
320                        "StatusMessageImpl.processElement(): invalid local name " 
321                        + elemName);
322                throw new XACMLException(
323                    XACMLSDKUtils.xacmlResourceBundle.getString(
324                        "invalid_local_name"));
325            }
326            attrValue = childElement.getAttribute(XACMLConstants.VALUE);
327            if ((attrValue == null) || (attrValue.length() == 0)) {
328                XACMLSDKUtils.debug.error(
329                    "StatusCodeImpl.processElement(): minor statuscode missing");
330                throw new XACMLException(
331                    XACMLSDKUtils.xacmlResourceBundle.getString(
332                    "missing_minor_status_code"));
333            } 
334            if (!XACMLSDKUtils.isValidStatusMessage(attrValue.trim())) {
335                throw new XACMLException(
336                        XACMLSDKUtils.xacmlResourceBundle.getString(
337                        "invalid_value"));
338            } else {
339                this.minorCodeValue = attrValue;
340            }
341        } else {
342        }
343    }
344
345}