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: ObligationImpl.java,v 1.3 2008/11/10 22:57:06 veiming Exp $
026 *
027 */
028
029package com.sun.identity.xacml.policy.impl;
030
031import com.sun.identity.shared.xml.XMLUtils;
032import com.sun.identity.xacml.common.XACMLConstants;
033import com.sun.identity.xacml.common.XACMLException;
034import com.sun.identity.xacml.common.XACMLSDKUtils;
035import com.sun.identity.xacml.policy.Obligation;
036
037import java.net.URI;
038import java.util.ArrayList;
039import java.util.Iterator;
040import java.util.List;
041
042import org.w3c.dom.Document;
043import org.w3c.dom.Element;
044import org.w3c.dom.NamedNodeMap;
045import org.w3c.dom.Node;
046import org.w3c.dom.NodeList;
047
048/**
049 * The <code>Obligation</code> element is a container of 
050 * one or more <code>AttributeAssignment</code>s issuded by 
051 * authorization authority.
052 * @supported.all.api
053 *
054 * <p>
055 * <pre>
056 *
057 *   &lt;xs:element name="Obligation" type="xacml:ObligationType"/>
058 *      &lt;xs:complexType name="ObligationType">
059 *          &lt;xs:sequence>
060 *              &lt;xs:element ref="xacml:AttributeAssignment" minOccurs="0" 
061 *                  maxOccurs="unbounded"/>
062 *              &lt;/xs:sequence>
063 *              &lt;xs:attribute name="ObligationId" type="xs:anyURI" 
064 *                  use="required"/>
065 *              &lt;xs:attribute name="FulfillOn" type="xacml:EffectType" 
066 *                  use="required"/>
067 *          &lt;/xs:complexType>
068 *   &lt;/xs:element>
069 * </pre>
070 */
071public class ObligationImpl implements Obligation {
072
073    // AttributeAssignment rquires AttributeId and DataType
074
075    private URI obligationId = null; //required
076    private String fulfillOn = null; //optional
077    private List attributeAssignments = null; //required
078    private boolean mutable = true;
079
080    /**
081     * Default constructor
082     */
083    public ObligationImpl() {
084    }
085
086    /**
087     * This constructor is used to build <code>Obligation</code> object 
088     * from an XML string.
089     *
090     * @param xml  a <code>String</code> representation of 
091     * <code>Obligation</code> object
092     * @exception XACMLException if it could not process the XML string
093     */
094    public ObligationImpl(String xml) throws XACMLException {
095        Document document = XMLUtils.toDOMDocument(xml, XACMLSDKUtils.debug);
096        if (document != null) {
097            Element rootElement = document.getDocumentElement();
098            processElement(rootElement);
099            makeImmutable();
100        } else {
101            XACMLSDKUtils.debug.error(
102                "ObligationImpl.processElement(): invalid XML input");
103            throw new XACMLException(XACMLSDKUtils.xacmlResourceBundle.getString(
104                "errorObtainingElement"));
105        }
106    }
107    
108    /**
109     * This constructor is used to build <code>ObligationImpl</code> object 
110     * from a  block of existing XML that has already been built into a DOM.
111     *
112     * @param element  DOM tree for <code>Request</code> object
113     * @exception XACML2Exception if it could not process the Element
114     */
115    public ObligationImpl(Element element) throws XACMLException {
116        processElement(element);
117        makeImmutable();
118    }
119
120    private void processElement(Element element) throws XACMLException {
121        String value = null;
122        if (element == null) {
123            XACMLSDKUtils.debug.error(
124                "ObligationImpl.processElement(): invalid root element");
125            throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString(
126                "invalid_element"));
127        }
128
129      // First check that we're really parsing an Obligation
130      if (! element.getLocalName().equals(XACMLConstants.OBLIGATION)) {
131            XACMLSDKUtils.debug.error(
132                "ObligationImpl.processElement(): invalid root element");
133            throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString(
134                "invalid_element"));
135      }
136      NamedNodeMap attrs = element.getAttributes();
137
138      try {
139          obligationId = new URI(attrs.getNamedItem(XACMLConstants.OBLIGATION_ID)
140                .getNodeValue());
141      } catch (Exception e) {
142            throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString(
143                "attribute_not_uri"));
144      }
145      if (obligationId == null) {
146            throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString(
147                "attribute_missing"));
148      }
149      try {
150          fulfillOn = attrs.getNamedItem(XACMLConstants.FULFILL_ON)
151                .getNodeValue();
152      } catch (Exception e) {
153            throw new XACMLException( XACMLSDKUtils.xacmlResourceBundle.getString(
154                "error_parsing_attribute"));
155      }
156 
157      // now we get the AttributeAssignment(s)
158      // AttributeAssignment requires AttributeId and DataType 
159      NodeList nodes = element.getChildNodes();
160      for (int i = 0; i < nodes.getLength(); i++) {
161          Node node = nodes.item(i);
162          if ((node.getNodeType() == Node.ELEMENT_NODE) ) {
163              if (node.getLocalName().equals(
164                        XACMLConstants.ATTRIBUTE_ASSIGNMENT)) {
165                  if (attributeAssignments == null) {
166                      attributeAssignments = new ArrayList();
167                  }
168                  Element aa = (Element)node;
169                  // aa should have attributes AtributeId, DataType
170                  String aid = aa.getAttribute(XACMLConstants.ATTRIBUTE_ID);
171                  if ((aid == null) || (aid.length() == 0)) {
172                        throw new XACMLException(
173                            XACMLSDKUtils.xacmlResourceBundle.getString(
174                            "missing_attribute"));
175                  }
176                  String dt = aa.getAttribute(XACMLConstants.DATA_TYPE);
177                  if ((dt == null) || (dt.length() == 0)) {
178                        throw new XACMLException(
179                            XACMLSDKUtils.xacmlResourceBundle.getString(
180                            "missing_attribute"));
181                  }
182                  attributeAssignments.add(aa);
183              } else {
184                    throw new XACMLException(
185                        XACMLSDKUtils.xacmlResourceBundle.getString(
186                        "missing_element"));
187              }
188          } 
189      }
190    }
191
192
193
194    /**
195     * Returns the ObligationId of this <code>Obligation</code>
196     * @return the <code>URI</code> representing ObligationId of this 
197     * <code>Obligation</code>
198     */
199    public URI getObligationId() {
200        return obligationId;
201    }
202
203    /**
204     * Sets the ObligationId of the <code>Obligation</code>
205     * @param obligationId <code>URI</code> representing the ObligationId.
206     * @exception XACMLException if the object is immutable
207     */
208    public void setObligationId(URI obligationId) 
209            throws XACMLException {
210        this.obligationId = obligationId;
211    }
212
213    /**
214     * Returns the FullFillOn effect type of this obligation
215     * @return the FullFillOn effect type of this obligation
216     */
217    public String getFulfillOn() {
218        return fulfillOn;
219    }
220
221    /**
222     * Sets the FullFillOn effect type of this obligation
223     *
224     * @param fulfillOn FullFillOn effect type of this obligation
225     */
226    public void setFulfillOn(String fulfillOn) 
227            throws XACMLException {
228        this.fulfillOn = fulfillOn;
229    }
230
231    /**
232     * Returns XML elements corresponding to 
233     * <code>AttributeAssignment</code> elements for  this obligation.
234     *
235     * @return the XML elements corresponding to 
236     * <code>AttributeAssignment</code> elements for  this obligation.
237     */
238    public List getAttributeAssignments() {
239        return attributeAssignments;
240    }
241
242    /**
243     * Sets XML elements corresponding to 
244     * <code>AttributeAssignment</code> elements for  this obligation.
245     *
246     * @param attributeAssignments XML elements corresponding to 
247     * <code>AttributeAssignment</code> elements for  this obligation.
248     */
249    public void setAttributeAssignments(List attributeAssignments) 
250            throws XACMLException {
251      if (attributeAssignments == null) {
252          return;
253      }
254      Iterator iter = attributeAssignments.iterator();
255      while (iter.hasNext()) {
256          Object obj = iter.next();
257          if (!(obj instanceof Element)) {
258                throw new XACMLException(
259                    XACMLSDKUtils.xacmlResourceBundle.getString(
260                    "not_xml_element"));
261          }
262          Element elem = (Element)obj;
263          String aid = elem.getAttribute(XACMLConstants.ATTRIBUTE_ID);
264          if ((aid == null) || (aid.length() == 0)) {
265                throw new XACMLException(
266                    XACMLSDKUtils.xacmlResourceBundle.getString(
267                    "missing_attribute"));
268          }
269          String dt = elem.getAttribute(XACMLConstants.DATA_TYPE);
270          if ((dt == null) || (dt.length() == 0)) {
271                throw new XACMLException(
272                    XACMLSDKUtils.xacmlResourceBundle.getString(
273                    "missing_attribute"));
274          }
275      }
276      this.attributeAssignments = attributeAssignments;
277    }
278
279   /**
280    * Returns a string representation of this object
281    * @param includeNSPrefix Determines whether or not the namespace qualifier
282    *        is prepended to the Element when converted
283    * @param declareNS Determines whether or not the namespace is declared
284    *        within the Element.
285    * @return a string representation
286    * @exception XACMLException if conversion fails for any reason
287     */
288    public String toXMLString(boolean includeNSPrefix, boolean declareNS)
289            throws XACMLException {
290        StringBuffer sb = new StringBuffer(2000);
291        String nsPrefix = "";
292        String nsDeclaration = "";
293        if (includeNSPrefix) {
294            nsPrefix = XACMLConstants.XACML_NS_PREFIX + ":";
295        }
296        if (declareNS) {
297            nsDeclaration = XACMLConstants.XACML_NS_DECLARATION;
298        }
299        sb.append("<").append(nsPrefix)
300                .append(XACMLConstants.OBLIGATION);
301        if(declareNS) {
302            sb.append(" ").append(nsDeclaration);
303        }
304        if (obligationId != null) {
305            sb.append(" ").append(XACMLConstants.OBLIGATION_ID).append("=")
306                .append(XACMLSDKUtils.quote(obligationId.toString()));
307        }
308        if (fulfillOn != null) {
309            sb.append(" ").append(XACMLConstants.FULFILL_ON).append("=")
310                .append(XACMLSDKUtils.quote(fulfillOn));
311        }
312        sb.append(">\n");
313        int length = 0;
314        if (attributeAssignments != null) {
315            length = attributeAssignments.size();
316            for (int i = 0; i < length; i++) {
317                Element elem = (Element)attributeAssignments.get(i);
318                sb.append(XMLUtils.print(elem));
319            }
320        }
321        sb.append("</").append(nsPrefix)
322                .append(XACMLConstants.OBLIGATION).append(">\n");
323        return sb.toString();
324    }
325
326   /**
327    * Returns a string representation of this object
328    *
329    * @return a string representation
330    * @exception XACMLException if conversion fails for any reason
331    */
332    public String toXMLString() throws XACMLException {
333        return toXMLString(true, true);
334    }
335
336   /**
337    * Makes this object immutable
338    */
339    public void makeImmutable() {
340        mutable = false;
341    }
342
343   /**
344    * Checks if this object is mutable
345    *
346    * @return <code>true</code> if the object is mutable,
347    *         <code>false</code> otherwise
348    */
349    public boolean isMutable() {
350        return mutable;
351    }
352    
353}