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: EnvironmentImpl.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.xacml.common.XACMLException;
032import com.sun.identity.xacml.common.XACMLConstants;
033import com.sun.identity.xacml.common.XACMLSDKUtils;
034import com.sun.identity.xacml.context.Environment;
035import com.sun.identity.xacml.context.Attribute;
036import com.sun.identity.xacml.context.ContextFactory;
037import com.sun.identity.shared.xml.XMLUtils;
038
039import java.util.List;
040import java.net.URI;
041import java.util.ArrayList;
042import org.w3c.dom.Document;
043import org.w3c.dom.Element;
044import org.w3c.dom.Node;
045import org.w3c.dom.NodeList;
046
047
048/**
049 * The <code>Environment</code> element specifies information about the
050 * environment requested in the <code>Request</code> context by listing a 
051 * sequence of <code>Attribute</code> elements associated with the
052 * environment.
053 * <p>
054 * <pre>
055 * &lt;xs:element name="Environment" type="xacml-context:EnvironmentType"/>
056 * &lt;xs:complexType name="EnvironmentType">
057 *    &lt;xs:sequence>
058 *       &lt;xs:element ref="xacml-context:Attribute" minOccurs="0"
059 *       maxOccurs="unbounded"/>
060 *    &lt;xs:sequence>
061 * &lt;xs:complexType>
062 * </pre>
063 *@supported.all.api
064 */
065public class EnvironmentImpl implements Environment {
066    
067    private List  attributes ;
068    private boolean mutable = true;
069 
070    
071    /** Creates a new instance of EnvironmentImpl */
072    public EnvironmentImpl() {
073    }
074    
075    /**
076     * This constructor is used to build <code>Environment</code> object from a
077     * XML string.
078     *
079     * @param xml A <code>java.lang.String</code> representing
080     *        a <code>Environment</code> object
081     * @exception XACMLException if it could not process the XML string
082     */
083    
084    public EnvironmentImpl(String xml) throws XACMLException {
085        Document document = XMLUtils.toDOMDocument(xml, XACMLSDKUtils.debug);
086        if (document != null) {
087            Element rootElement = document.getDocumentElement();
088            processElement(rootElement);
089            makeImmutable();
090        } else {
091            XACMLSDKUtils.debug.error(
092                "EnvironmentImpl.processElement(): invalid XML input");
093            throw new XACMLException(
094                 XACMLSDKUtils.xacmlResourceBundle.getString(
095                "errorObtainingElement"));
096        }
097    }
098    
099    /**
100     * This constructor is used to build <code>Environment</code> object from a
101     * block of existing XML that has already been built into a DOM.
102     *
103     * @param element A <code>org.w3c.dom.Element</code> representing
104     *        DOM tree for <code>Environment</code> object
105     * @exception XACMLException if it could not process the Element
106     */
107    public EnvironmentImpl(Element element) throws XACMLException {
108        processElement(element);
109        makeImmutable();
110    }
111
112    private void processElement(Element element) throws XACMLException {
113        if (element == null) {
114            XACMLSDKUtils.debug.error(
115                "EnvironmentImpl.processElement(): invalid root element");
116            throw new XACMLException( 
117                XACMLSDKUtils.xacmlResourceBundle.getString(
118                "invalid_element"));
119        }
120        String elemName = element.getLocalName(); 
121        if (elemName == null) {
122             XACMLSDKUtils.debug.error(
123                "EnvironmentImpl.processElement(): local name missing");
124            throw new XACMLException( 
125                XACMLSDKUtils.xacmlResourceBundle.getString(
126                "missing_local_name"));
127        }
128
129        if (!elemName.equals(XACMLConstants.ENVIRONMENT)) {
130            XACMLSDKUtils.debug.error(
131                "EnvironmentImpl.processElement(): invalid local name " +
132                 elemName);
133            throw new XACMLException(
134                XACMLSDKUtils.xacmlResourceBundle.getString(
135                "invalid_local_name"));
136        }
137        // starts processing subelements
138        NodeList nodes = element.getChildNodes();
139        int numOfNodes = nodes.getLength();
140        if (numOfNodes >= 1) {
141            ContextFactory factory = ContextFactory.getInstance();
142            for (int nextElem = 0; nextElem < numOfNodes; nextElem++) {
143                Node child = (Node)nodes.item(nextElem);
144                if (child.getNodeType() == Node.ELEMENT_NODE) {
145                    // The child nodes should be <Attribute> 
146                    String attrChildName = child.getLocalName();
147                    if (attrChildName.equals(XACMLConstants.ATTRIBUTE)) {
148                        if (this.attributes == null) {
149                        this.attributes = new ArrayList();
150                        }
151                        Attribute attribute = factory.getInstance().
152                                createAttribute((Element)child);
153                        attributes.add(attribute);
154                    } else {
155                        XACMLSDKUtils.debug.error("EnvironmentImpl."
156                            +"processElement(): Invalid element :"
157                            +attrChildName);
158                        throw new XACMLException(
159                            XACMLSDKUtils.xacmlResourceBundle.getString( 
160                                "invalid_element"));
161                    }
162                }
163            }
164         }
165    }
166    
167    public java.util.List getAttributes() {
168        return attributes;
169    }
170    
171    /**
172     * Sets the <code>Attribute</code> elements of this object
173     *
174     * @param attributes <code>Attribute</code> elements of this object
175     * attributes could be an empty <code>List</code>, if no attributes
176     * are present.
177     *
178     * @exception XACMLException if the object is immutable
179     * An object is considered <code>immutable</code> if <code>
180     * makeImmutable()</code> has been invoked on it. It can
181     * be determined by calling <code>mutable</code> on the object.
182     */
183    public void setAttributes(java.util.List attributes) 
184        throws XACMLException {
185        if (!mutable) {
186            throw new XACMLException(
187                XACMLSDKUtils.xacmlResourceBundle.getString(
188                "objectImmutable"));
189        }
190        if (attributes != null &&  !attributes.isEmpty()) {
191            if (this.attributes == null) {
192                this.attributes = new ArrayList();
193            }
194            this.attributes.addAll(attributes);
195        }
196    }
197    
198    /**
199    * Returns a <code>String</code> representation of this object
200    * @param includeNSPrefix Determines whether or not the namespace qualifier
201    *        is prepended to the Element when converted
202    * @param declareNS Determines whether or not the namespace is declared
203    *        within the Element.
204    * @return a string representation of this object
205    * @exception XACMLException if conversion fails for any reason
206     */
207    public String toXMLString(boolean includeNSPrefix, boolean declareNS) 
208        throws XACMLException {
209        StringBuffer sb = new StringBuffer(2000);
210        StringBuffer namespaceBuffer = new StringBuffer(100);
211        String nsDeclaration = "";
212        if (declareNS) {
213            namespaceBuffer.append(XACMLConstants.CONTEXT_NS_DECLARATION).
214                append(XACMLConstants.SPACE);
215            namespaceBuffer.append(XACMLConstants.XSI_NS_URI).
216                append(XACMLConstants.SPACE).append(XACMLConstants.
217                CONTEXT_SCHEMA_LOCATION);
218        }
219        if (includeNSPrefix) {
220            nsDeclaration = XACMLConstants.CONTEXT_NS_PREFIX + ":";
221        }
222        sb.append("<").append(nsDeclaration).append(XACMLConstants.
223            ENVIRONMENT).append(namespaceBuffer);
224        sb.append(">");
225        int length = 0;
226        if (attributes != null) {
227            sb.append("\n");
228            length = attributes.size();
229            for (int i = 0; i < length; i++) {
230                Attribute attr = (Attribute)attributes.get(i);
231                sb.append(attr.toXMLString(includeNSPrefix, false));
232            }
233        }
234        sb.append("</").append(nsDeclaration).
235            append(XACMLConstants.ENVIRONMENT);
236        sb.append(">\n");
237        return sb.toString();
238    }
239    
240    /**
241    * Returns a string representation of this object
242    *
243    * @return a string representation of this object
244    * @exception XACMLException if conversion fails for any reason
245    */
246    public String toXMLString() throws XACMLException {
247        return toXMLString(true, false);
248    }
249    
250    /**
251    * Makes the object immutable
252    */
253    public void makeImmutable() {
254        mutable = false;
255    }
256    
257    /**
258    * Checks if the object is mutable
259    *
260    * @return <code>true</code> if the object is mutable,
261    *         <code>false</code> otherwise
262    */
263    public boolean isMutable() {
264        return mutable;
265    }
266    
267}