001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 021 package org.apache.directory.shared.dsmlv2; 022 023 024 import java.util.List; 025 026 import javax.xml.transform.Transformer; 027 import javax.xml.transform.TransformerConfigurationException; 028 import javax.xml.transform.TransformerException; 029 import javax.xml.transform.TransformerFactory; 030 import javax.xml.transform.stream.StreamSource; 031 032 import org.apache.directory.shared.dsmlv2.engine.Dsmlv2Engine; 033 import org.apache.directory.shared.dsmlv2.request.BatchRequest; 034 import org.apache.directory.shared.dsmlv2.request.BatchRequest.Processing; 035 import org.apache.directory.shared.dsmlv2.request.BatchRequest.ResponseOrder; 036 import org.apache.directory.shared.i18n.I18n; 037 import org.apache.directory.shared.ldap.ldif.LdifUtils; 038 import org.apache.directory.shared.ldap.message.control.Control; 039 import org.apache.directory.shared.ldap.util.Base64; 040 import org.apache.directory.shared.ldap.util.StringTools; 041 import org.dom4j.Document; 042 import org.dom4j.Element; 043 import org.dom4j.Namespace; 044 import org.dom4j.QName; 045 import org.dom4j.io.DocumentResult; 046 import org.dom4j.io.DocumentSource; 047 import org.xmlpull.v1.XmlPullParser; 048 import org.xmlpull.v1.XmlPullParserException; 049 050 051 /** 052 * This class is a Helper class for the DSML Parser 053 * 054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 055 * @version $Rev$, $Date$ 056 */ 057 public class ParserUtils 058 { 059 public static final String XML_SCHEMA_URI = "http://www.w3c.org/2001/XMLSchema"; 060 public static final String XML_SCHEMA_INSTANCE_URI = "http://www.w3c.org/2001/XMLSchema-instance"; 061 public static final String BASE64BINARY = "base64Binary"; 062 public static final String XSI = "xsi"; 063 public static final String XSD = "xsd"; 064 065 066 /** 067 * Returns the value of the attribute 'type' of the "XMLSchema-instance' namespace if it exists 068 * 069 * @param xpp 070 * the XPP parser to use 071 * @return 072 * the value of the attribute 'type' of the "XMLSchema-instance' namespace if it exists 073 */ 074 public static String getXsiTypeAttributeValue( XmlPullParser xpp ) 075 { 076 String type = null; 077 int nbAttributes = xpp.getAttributeCount(); 078 for ( int i = 0; i < nbAttributes; i++ ) 079 { 080 // Checking if the attribute 'type' from XML Schema Instance namespace is used. 081 if ( xpp.getAttributeName( i ).equals( "type" ) 082 && xpp.getNamespace( xpp.getAttributePrefix( i ) ).equals( XML_SCHEMA_INSTANCE_URI ) ) 083 { 084 type = xpp.getAttributeValue( i ); 085 break; 086 } 087 } 088 return type; 089 } 090 091 092 /** 093 * Tells is the given value is a Base64 binary value 094 * 095 * @param parser 096 * the XPP parser to use 097 * @param attrValue 098 * the attribute value 099 * @return 100 * true if the value of the current tag is Base64BinaryEncoded, false if not 101 */ 102 public static boolean isBase64BinaryValue( XmlPullParser parser, String attrValue ) 103 { 104 if ( attrValue == null ) 105 { 106 return false; 107 } 108 // We are looking for something that should look like that: "aNameSpace:base64Binary" 109 // We split the String. The first element should be the namespace prefix and the second "base64Binary" 110 String[] splitedString = attrValue.split( ":" ); 111 return ( splitedString.length == 2 ) && ( XML_SCHEMA_URI.equals( parser.getNamespace( splitedString[0] ) ) ) 112 && ( BASE64BINARY.equals( splitedString[1] ) ); 113 } 114 115 116 /** 117 * Indicates if the value needs to be encoded as Base64 118 * 119 * @param value 120 * the value to check 121 * @return 122 * true if the value needs to be encoded as Base64 123 */ 124 public static boolean needsBase64Encoding( Object value ) 125 { 126 if ( value instanceof byte[] ) 127 { 128 return true; 129 } 130 else if ( value instanceof String ) 131 { 132 return !LdifUtils.isLDIFSafe( ( String ) value ); 133 } 134 return true; 135 } 136 137 138 /** 139 * Encodes the value as a Base64 String 140 * 141 * @param value 142 * the value to encode 143 * @return 144 * the value encoded as a Base64 String 145 */ 146 public static String base64Encode( Object value ) 147 { 148 if ( value instanceof byte[] ) 149 { 150 return new String( Base64.encode( ( byte[] ) value ) ); 151 } 152 else if ( value instanceof String ) 153 { 154 return new String( Base64.encode( StringTools.getBytesUtf8( ( String ) value ) ) ); 155 } 156 157 return ""; 158 } 159 160 161 /** 162 * Parses and verify the parsed value of the requestID 163 * 164 * @param attributeValue 165 * the value of the attribute 166 * @param xpp 167 * the XmlPullParser 168 * @return 169 * the int value of the resquestID 170 * @throws XmlPullParserException 171 * if RequestID isn't an Integer and if requestID equals 0 172 */ 173 public static int parseAndVerifyRequestID( String attributeValue, XmlPullParser xpp ) throws XmlPullParserException 174 { 175 try 176 { 177 int requestID = Integer.parseInt( attributeValue ); 178 179 if ( requestID == 0 ) 180 { 181 throw new XmlPullParserException( I18n.err( I18n.ERR_03038 ), xpp, null ); 182 } 183 184 return requestID; 185 } 186 catch ( NumberFormatException e ) 187 { 188 throw new XmlPullParserException( I18n.err( I18n.ERR_03039 ), xpp, null ); 189 } 190 } 191 192 193 /** 194 * Adds Controls to the given Element. 195 * 196 * @param element 197 * the element to add the Controls to 198 * @param controls 199 * a List of Controls 200 */ 201 public static void addControls( Element element, List<Control> controls ) 202 { 203 if ( controls != null ) 204 { 205 for ( int i = 0; i < controls.size(); i++ ) 206 { 207 Control control = controls.get( i ); 208 209 Element controlElement = element.addElement( "control" ); 210 211 if ( control.getOid() != null ) 212 { 213 controlElement.addAttribute( "type", control.getOid() ); 214 } 215 216 if ( control.isCritical() ) 217 { 218 controlElement.addAttribute( "criticality", "true" ); 219 } 220 221 Object value = control.getValue(); 222 223 if ( value != null ) 224 { 225 if ( ParserUtils.needsBase64Encoding( value ) ) 226 { 227 Namespace xsdNamespace = new Namespace( ParserUtils.XSD, ParserUtils.XML_SCHEMA_URI ); 228 Namespace xsiNamespace = new Namespace( ParserUtils.XSI, ParserUtils.XML_SCHEMA_INSTANCE_URI ); 229 element.getDocument().getRootElement().add( xsdNamespace ); 230 element.getDocument().getRootElement().add( xsiNamespace ); 231 232 Element valueElement = controlElement.addElement( "controlValue" ).addText( 233 ParserUtils.base64Encode( value ) ); 234 valueElement.addAttribute( new QName( "type", xsiNamespace ), ParserUtils.XSD + ":" 235 + ParserUtils.BASE64BINARY ); 236 } 237 else 238 { 239 controlElement.addElement( "controlValue" ).setText( ( String ) value ); 240 } 241 } 242 } 243 } 244 } 245 246 247 /** 248 * Indicates if a request ID is needed. 249 * 250 * @param container 251 * the associated container 252 * @return 253 * true if a request ID is needed (ie Processing=Parallel and ResponseOrder=Unordered) 254 * @throws XmlPullParserException 255 * if the batch request has not been parsed yet 256 */ 257 public static boolean isRequestIdNeeded( Dsmlv2Container container ) throws XmlPullParserException 258 { 259 BatchRequest batchRequest = container.getBatchRequest(); 260 261 if ( batchRequest == null ) 262 { 263 throw new XmlPullParserException( I18n.err( I18n.ERR_03040 ), container.getParser(), null ); 264 } 265 266 return ( ( batchRequest.getProcessing() == Processing.PARALLEL ) && ( batchRequest.getResponseOrder() == ResponseOrder.UNORDERED ) ); 267 } 268 269 270 /** 271 * XML Pretty Printer XSLT Tranformation 272 * 273 * @param document 274 * the Dom4j Document 275 * @return 276 * the transformed document 277 */ 278 public static Document styleDocument( Document document ) 279 { 280 // load the transformer using JAXP 281 TransformerFactory factory = TransformerFactory.newInstance(); 282 Transformer transformer = null; 283 try 284 { 285 transformer = factory.newTransformer( new StreamSource( Dsmlv2Engine.class 286 .getResourceAsStream( "DSMLv2.xslt" ) ) ); 287 } 288 catch ( TransformerConfigurationException e1 ) 289 { 290 // TODO Auto-generated catch block 291 e1.printStackTrace(); 292 } 293 294 // now lets style the given document 295 DocumentSource source = new DocumentSource( document ); 296 DocumentResult result = new DocumentResult(); 297 try 298 { 299 transformer.transform( source, result ); 300 } 301 catch ( TransformerException e ) 302 { 303 // TODO Auto-generated catch block 304 e.printStackTrace(); 305 } 306 307 // return the transformed document 308 Document transformedDoc = result.getDocument(); 309 return transformedDoc; 310 } 311 }