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: Extension.java,v 1.2 2008/06/25 05:46:46 qcheng Exp $ 026 * 027 */ 028 029package com.sun.identity.federation.message.common; 030 031import java.util.ArrayList; 032import java.util.Enumeration; 033import java.util.HashMap; 034import java.util.Iterator; 035import java.util.List; 036import java.util.Map; 037import javax.servlet.http.HttpServletRequest; 038import org.w3c.dom.Document; 039import org.w3c.dom.Element; 040import org.w3c.dom.Node; 041import org.w3c.dom.NodeList; 042 043import com.sun.identity.federation.common.FSUtils; 044import com.sun.identity.federation.common.IFSConstants; 045import com.sun.identity.federation.message.common.FSMsgException; 046import com.sun.identity.shared.encode.URLEncDec; 047import com.sun.identity.shared.xml.XMLUtils; 048 049/** 050 * The class <code>Extension</code> is used to create , parse 051 * <code>Extension</code> object. 052 * 053 * @supported.all.api 054 */ 055public class Extension { 056 private List children = null; 057 private Map avpairs = null; 058 private int minorVersion = 0; 059 060 /** 061 * Constructor to create <code>Extension</code> object. 062 * 063 * @param children a list of XML <code>String</code> object. 064 * @throws FSMsgException on error. 065 */ 066 public Extension(List children) throws FSMsgException { 067 validateChildren(children); 068 this.children = children; 069 } 070 071 /** 072 * Constructor to create <code>Extension</code> object. 073 * 074 * @param element the <code>Extension</code> Element object. 075 * @throws FSMsgException on error. 076 */ 077 public Extension(Element element) throws FSMsgException { 078 if (element == null) { 079 FSUtils.debug.error("Extension.Extension: null input."); 080 throw new FSMsgException("nullInput", null); 081 } 082 String nodeName = element.getLocalName(); 083 if (!IFSConstants.EXTENSION.equals(nodeName)) { 084 FSUtils.debug.error("Extension.Extension: wrong input"); 085 throw new FSMsgException("wrongInput", null); 086 } 087 088 NodeList childNodes = element.getChildNodes(); 089 int length = childNodes.getLength(); 090 for(int i = 0; i < length; i++) { 091 Node child = childNodes.item(i); 092 if (child.getNodeType() == Node.ELEMENT_NODE) { 093 if (children == null) { 094 children = new ArrayList(); 095 } 096 children.add(XMLUtils.print(child)); 097 addToAvpairs((Element)child); 098 } 099 } 100 } 101 102 /** 103 * Constructor to create <code>Extension</code> object. Each attribute 104 * value pair will be converted to a XML string. The converted XML string 105 * has only one element. The local name of the element will be the key of 106 * the map entry and the value of the element will be the value of the map 107 * entry. Both key and value of the map entry should be a 108 * <code>String</code> object. 109 * 110 * @param avpairs attribute value pairs. 111 * @throws FSMsgException on error. 112 */ 113 public Extension(Map avpairs) throws FSMsgException { 114 setAttributeMap(avpairs); 115 } 116 117 /** 118 * Returns a list of XML <code>String</code> objects. 119 * 120 * @return a list of XML <code>String</code> objects. 121 * @see #setChildren(List) 122 */ 123 public List getChildren() { 124 return children; 125 } 126 127 /** 128 * Sets a list of XML <code>String</code> object. 129 * 130 * @param children a list of XML <code>String</code> object. 131 * @see #getChildren() 132 */ 133 public void setChildren(List children) throws FSMsgException { 134 validateChildren(children); 135 this.children = children; 136 } 137 138 /* 139 * Gets attribute value pairs. Each attribute value pair is converted from 140 * a XML string. The XML string can have only one element. The element 141 * element can't have namespace and must have a simple content. The local 142 * name of the element will be the key of the map entry and the value of 143 * the element will be the value of the map entry. Both key and value of 144 * the map entry will be a <code>String</code> object. If a XML string 145 * can't be converted, it will not be added to the map. 146 * 147 * @return an attribute value pairs. 148 */ 149 public Map getAttributeMap() { 150 if ((children == null) || (children.isEmpty())) { 151 return null; 152 } 153 154 if (avpairs != null) { 155 return avpairs; 156 } 157 for(Iterator iter = children.iterator(); iter.hasNext(); ) { 158 String xml = (String)iter.next(); 159 160 Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug); 161 if (doc == null) { 162 continue; 163 } 164 Element element = doc.getDocumentElement(); 165 addToAvpairs(element); 166 } 167 168 return avpairs; 169 } 170 171 /** 172 * Converts attribute value pairs to a list of XML <code>String</code> 173 * objects. Each attribute value pair will be converted to a XML string. 174 * The converted XML string has only one element. The local name of the 175 * element will be the key of the map entry and the value of the element 176 * will be the value of the map entry. Both key and value of the map entry 177 * should be a <code>String</code> object. 178 * 179 * @param avpairs attribute value pairs. 180 * @throws FSMsgException on error. 181 */ 182 public void setAttributeMap(Map avpairs) throws FSMsgException { 183 this.avpairs = avpairs; 184 if ((avpairs != null) && (!avpairs.isEmpty())) { 185 for(Iterator iter = avpairs.keySet().iterator(); iter.hasNext();) { 186 String key = (String)iter.next(); 187 String value = (String)avpairs.get(key); 188 String xml = IFSConstants.LEFT_ANGLE + key + 189 IFSConstants.RIGHT_ANGLE + 190 XMLUtils.escapeSpecialCharacters(value) + 191 IFSConstants.START_END_ELEMENT + key + 192 IFSConstants.RIGHT_ANGLE; 193 if (children == null) { 194 children = new ArrayList(); 195 } 196 children.add(xml); 197 } 198 } 199 } 200 201 /** 202 * Returns the <code>MinorVersion</code>. 203 * 204 * @return the <code>MinorVersion</code>. 205 * @see #setMinorVersion(int) 206 */ 207 public int getMinorVersion() { 208 return minorVersion; 209 } 210 211 /** 212 * Sets the <code>MinorVersion</code>. 213 * 214 * @param minorVersion the <code>MinorVersion</code>. 215 * @see #getMinorVersion() 216 */ 217 public void setMinorVersion(int minorVersion) { 218 this.minorVersion = minorVersion; 219 } 220 221 /** 222 * Returns a String representation of the <Code>Extension</Code> element. 223 * 224 * @return a string containing the valid XML for this element 225 * @throws FSMsgException if there is an error converting this object to 226 * a string. 227 */ 228 public String toXMLString() throws FSMsgException { 229 return this.toXMLString(true, false); 230 } 231 232 /** 233 * Creates a String representation of the <Code>Extension</Code> element. 234 * 235 * @param includeNS : Determines whether or not the namespace qualifier 236 * is prepended to the Element when converted 237 * @param declareNS : Determines whether or not the namespace is declared 238 * within the Element. 239 * @return string containing the valid XML for this element. 240 * @throws FSMsgException if there is an error. 241 */ 242 public String toXMLString(boolean includeNS, boolean declareNS) 243 throws FSMsgException { 244 245 String prefix = ""; 246 String uri = ""; 247 248 StringBuffer xml = new StringBuffer(); 249 if (includeNS) { 250 prefix = IFSConstants.LIB_PREFIX; 251 } 252 if (declareNS) { 253 if(minorVersion == IFSConstants.FF_12_PROTOCOL_MINOR_VERSION) { 254 uri = IFSConstants.LIB_12_NAMESPACE_STRING; 255 } else { 256 uri = IFSConstants.LIB_NAMESPACE_STRING; 257 } 258 } 259 xml.append(IFSConstants.LEFT_ANGLE) 260 .append(prefix) 261 .append(IFSConstants.EXTENSION) 262 .append(uri) 263 .append(IFSConstants.RIGHT_ANGLE); 264 if ((children != null) && (!children.isEmpty())) { 265 for(Iterator iter = children.iterator(); iter.hasNext();) { 266 String child = (String)iter.next(); 267 xml.append(child); 268 } 269 } 270 xml.append(IFSConstants.START_END_ELEMENT) 271 .append(prefix) 272 .append(IFSConstants.EXTENSION) 273 .append(IFSConstants.RIGHT_ANGLE); 274 275 return xml.toString(); 276 } 277 278 /** 279 * Returns <code>Extension</code> object. The object is creating by 280 * parsing the <code>HttpServletRequest</code> object. 281 * 282 * @param request the <code>HttpServletRequest</code> object. 283 * @param prefix the string that is prepended to the key of query 284 * string. 285 * @param minorVersion the <code>MinorVersion</code>. 286 * @return <code><Extension/code> object. 287 * @throws FSMsgException if there is an error creating 288 * <code>Extension</code> object. 289 */ 290 public static Extension parseURLEncodedRequest(HttpServletRequest request, 291 String prefix, int minorVersion) throws FSMsgException { 292 293 Map attrMap = null; 294 for(Enumeration e=request.getParameterNames(); e.hasMoreElements();) { 295 String paraName = (String)e.nextElement(); 296 if (paraName.startsWith(prefix)) { 297 String key = paraName.substring(prefix.length()); 298 String value = request.getParameter(paraName); 299 if (attrMap == null) { 300 attrMap = new HashMap(); 301 } 302 attrMap.put(key, value); 303 } 304 } 305 306 if (attrMap == null) { 307 return null; 308 } 309 310 Extension extension = new Extension(attrMap); 311 extension.setMinorVersion(minorVersion); 312 return extension; 313 } 314 315 /** 316 * Returns an URL Encoded String. 317 * 318 * @param prefix the string that will be prepended to the key of query 319 * string. 320 * @return a url encoded query string. 321 * @throws FSMsgException if there is an error. 322 */ 323 public String toURLEncodedQueryString(String prefix) 324 throws FSMsgException { 325 326 Map attrMap = getAttributeMap(); 327 if ((attrMap == null) || (attrMap.isEmpty())) { 328 return ""; 329 } 330 331 StringBuffer queryString = new StringBuffer(); 332 for(Iterator iter = attrMap.keySet().iterator();iter.hasNext();) { 333 String key = (String)iter.next(); 334 String value = URLEncDec.encode((String)attrMap.get(key)); 335 key = URLEncDec.encode(prefix + key); 336 if (queryString.length() > 0) { 337 queryString.append(IFSConstants.AMPERSAND); 338 } 339 queryString.append(key).append(IFSConstants.EQUAL_TO) 340 .append(value); 341 } 342 343 return queryString.toString(); 344 } 345 346 private void addToAvpairs(Element element) { 347 String ns = element.getNamespaceURI(); 348 if ((ns == null) && (!XMLUtils.hasElementChild(element))) { 349 String key = element.getLocalName(); 350 String value = XMLUtils.getElementValue(element); 351 if (avpairs == null) { 352 avpairs = new HashMap(); 353 } 354 avpairs.put(key, value); 355 } 356 } 357 358 private static void validateChildren(List children) throws FSMsgException { 359 if ((children != null) && (!children.isEmpty())) { 360 for(Iterator iter = children.iterator(); iter.hasNext(); ) { 361 String xml = (String)iter.next(); 362 Document doc = XMLUtils.toDOMDocument(xml, FSUtils.debug); 363 if (doc == null) { 364 FSUtils.debug.error("Extension.validateChildren: Error " 365 + "while parsing input xml string"); 366 throw new FSMsgException("parseError", null); 367 } 368 } 369 } 370 } 371}