| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.api.dsmlv2; |
| |
| |
| import java.util.Arrays; |
| import java.util.Collection; |
| |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.stream.StreamSource; |
| |
| import org.apache.directory.api.dsmlv2.actions.ReadSoapHeader; |
| import org.apache.directory.api.dsmlv2.request.BatchRequestDsml; |
| import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing; |
| import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder; |
| import org.apache.directory.api.i18n.I18n; |
| import org.apache.directory.api.ldap.codec.api.CodecControl; |
| import org.apache.directory.api.ldap.codec.api.LdapApiService; |
| import org.apache.directory.api.ldap.model.entry.BinaryValue; |
| import org.apache.directory.api.ldap.model.entry.StringValue; |
| import org.apache.directory.api.ldap.model.ldif.LdifUtils; |
| import org.apache.directory.api.ldap.model.message.Control; |
| import org.apache.directory.api.util.Base64; |
| import org.apache.directory.api.util.Strings; |
| import org.dom4j.Document; |
| import org.dom4j.Element; |
| import org.dom4j.Namespace; |
| import org.dom4j.QName; |
| import org.dom4j.io.DocumentResult; |
| import org.dom4j.io.DocumentSource; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.xmlpull.v1.XmlPullParser; |
| import org.xmlpull.v1.XmlPullParserException; |
| |
| |
| /** |
| * This class is a Helper class for the DSML Parser |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public final class ParserUtils |
| { |
| /** W3C XML Schema URI. */ |
| public static final String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema"; |
| |
| /** W3C XML Schema Instance URI. */ |
| public static final String XML_SCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance"; |
| |
| /** Base-64 identifier. */ |
| public static final String BASE64BINARY = "base64Binary"; |
| |
| /** XSI namespace prefix. */ |
| public static final String XSI = "xsi"; |
| |
| /** XSD namespace prefix. */ |
| public static final String XSD = "xsd"; |
| |
| /** The DSML namespace */ |
| public static final Namespace DSML_NAMESPACE = new Namespace( null, "urn:oasis:names:tc:DSML:2:0:core" ); |
| |
| /** The XSD namespace */ |
| public static final Namespace XSD_NAMESPACE = new Namespace( XSD, XML_SCHEMA_URI ); |
| |
| /** The XSI namespace */ |
| public static final Namespace XSI_NAMESPACE = new Namespace( XSI, XML_SCHEMA_INSTANCE_URI ); |
| |
| /** A logger for this class */ |
| private static final Logger LOG = LoggerFactory.getLogger( ParserUtils.class ); |
| |
| |
| private ParserUtils() |
| { |
| } |
| |
| |
| /** |
| * Returns the value of the attribute 'type' of the "XMLSchema-instance' namespace if it exists |
| * |
| * @param xpp the XPP parser to use |
| * @return the value of the attribute 'type' of the "XMLSchema-instance' namespace if it exists |
| */ |
| public static String getXsiTypeAttributeValue( XmlPullParser xpp ) |
| { |
| String type = null; |
| int nbAttributes = xpp.getAttributeCount(); |
| |
| for ( int i = 0; i < nbAttributes; i++ ) |
| { |
| // Checking if the attribute 'type' from XML Schema Instance namespace is used. |
| if ( xpp.getAttributeName( i ).equals( "type" ) |
| && xpp.getNamespace( xpp.getAttributePrefix( i ) ).equals( XML_SCHEMA_INSTANCE_URI ) ) |
| { |
| type = xpp.getAttributeValue( i ); |
| break; |
| } |
| } |
| |
| return type; |
| } |
| |
| |
| /** |
| * Tells is the given value is a Base64 binary value |
| * |
| * @param parser the XPP parser to use |
| * @param attrValue the attribute value |
| * @return true if the value of the current tag is Base64BinaryEncoded, false if not |
| */ |
| public static boolean isBase64BinaryValue( XmlPullParser parser, String attrValue ) |
| { |
| if ( attrValue == null ) |
| { |
| return false; |
| } |
| |
| // We are looking for something that should look like that: "aNameSpace:base64Binary" |
| // We split the String. The first element should be the namespace prefix and the second "base64Binary" |
| String[] splitedString = attrValue.split( ":" ); |
| |
| return ( splitedString.length == 2 ) && ( XML_SCHEMA_URI.equals( parser.getNamespace( splitedString[0] ) ) ) |
| && ( BASE64BINARY.equals( splitedString[1] ) ); |
| } |
| |
| |
| /** |
| * Indicates if the value needs to be encoded as Base64 |
| * |
| * @param value the value to check |
| * @return true if the value needs to be encoded as Base64 |
| */ |
| public static boolean needsBase64Encoding( Object value ) |
| { |
| if ( value instanceof StringValue ) |
| { |
| return false; |
| } |
| else if ( value instanceof BinaryValue ) |
| { |
| return false; |
| } |
| else if ( value instanceof byte[] ) |
| { |
| return true; |
| } |
| else if ( value instanceof String ) |
| { |
| return !LdifUtils.isLDIFSafe( ( String ) value ); |
| } |
| |
| return true; |
| } |
| |
| |
| /** |
| * Encodes the value as a Base64 String |
| * |
| * @param value the value to encode |
| * @return the value encoded as a Base64 String |
| */ |
| public static String base64Encode( Object value ) |
| { |
| if ( value instanceof byte[] ) |
| { |
| return new String( Base64.encode( ( byte[] ) value ) ); |
| } |
| else if ( value instanceof String ) |
| { |
| return new String( Base64.encode( Strings.getBytesUtf8( ( String ) value ) ) ); |
| } |
| |
| return ""; |
| } |
| |
| |
| /** |
| * Parses and verify the parsed value of the requestID |
| * |
| * @param attributeValue the value of the attribute |
| * @param xpp the XmlPullParser |
| * @return the int value of the resquestID |
| * @throws XmlPullParserException if RequestID isn't an Integer and if requestID is below 0 |
| */ |
| public static int parseAndVerifyRequestID( String attributeValue, XmlPullParser xpp ) throws XmlPullParserException |
| { |
| try |
| { |
| int requestID = Integer.parseInt( attributeValue ); |
| |
| if ( requestID < 0 ) |
| { |
| throw new XmlPullParserException( I18n.err( I18n.ERR_03038, requestID ), xpp, null ); |
| } |
| |
| return requestID; |
| } |
| catch ( NumberFormatException nfe ) |
| { |
| throw new XmlPullParserException( I18n.err( I18n.ERR_03039 ), xpp, nfe ); |
| } |
| } |
| |
| |
| /** |
| * Adds Controls to the given Element. |
| * |
| * @param element the element to add the Controls to |
| * @param controls a List of Controls |
| */ |
| public static void addControls( LdapApiService codec, Element element, Collection<Control> controls ) |
| { |
| if ( controls != null ) |
| { |
| for ( Control control : controls ) |
| { |
| Element controlElement = element.addElement( "control" ); |
| |
| if ( control.getOid() != null ) |
| { |
| controlElement.addAttribute( "type", control.getOid() ); |
| } |
| |
| if ( control.isCritical() ) |
| { |
| controlElement.addAttribute( "criticality", "true" ); |
| } |
| |
| byte[] value; |
| |
| if ( control instanceof CodecControl<?> ) |
| { |
| value = ( ( org.apache.directory.api.ldap.codec.api.CodecControl<?> ) control ).getValue(); |
| } |
| else |
| { |
| value = codec.newControl( control ).getValue(); |
| } |
| |
| if ( value != null ) |
| { |
| if ( ParserUtils.needsBase64Encoding( value ) ) |
| { |
| element.getDocument().getRootElement().add( XSD_NAMESPACE ); |
| element.getDocument().getRootElement().add( XSI_NAMESPACE ); |
| |
| Element valueElement = controlElement.addElement( "controlValue" ).addText( |
| ParserUtils.base64Encode( value ) ); |
| valueElement.addAttribute( new QName( "type", XSI_NAMESPACE ), ParserUtils.XSD + ":" |
| + ParserUtils.BASE64BINARY ); |
| } |
| else |
| { |
| controlElement.addElement( "controlValue" ).setText( Arrays.toString( value ) ); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Indicates if a request ID is needed. |
| * |
| * @param container the associated container |
| * @return true if a request ID is needed (ie Processing=Parallel and ResponseOrder=Unordered) |
| * @throws XmlPullParserException if the batch request has not been parsed yet |
| */ |
| public static boolean isRequestIdNeeded( Dsmlv2Container container ) throws XmlPullParserException |
| { |
| BatchRequestDsml batchRequest = container.getBatchRequest(); |
| |
| if ( batchRequest == null ) |
| { |
| throw new XmlPullParserException( I18n.err( I18n.ERR_03040 ), container.getParser(), null ); |
| } |
| |
| return ( ( batchRequest.getProcessing() == Processing.PARALLEL ) && ( batchRequest.getResponseOrder() == ResponseOrder.UNORDERED ) ); |
| } |
| |
| |
| /** |
| * XML Pretty Printer XSLT Transformation |
| * |
| * @param document the Dom4j Document |
| * @return the transformed document |
| */ |
| public static Document styleDocument( Document document ) |
| { |
| // load the transformer using JAXP |
| TransformerFactory factory = TransformerFactory.newInstance(); |
| Transformer transformer = null; |
| |
| try |
| { |
| transformer = factory.newTransformer( new StreamSource( ParserUtils.class |
| .getResourceAsStream( "/org/apache/directory/shared/dsmlv2/DSMLv2.xslt" ) ) ); |
| } |
| catch ( TransformerConfigurationException e1 ) |
| { |
| LOG.warn( "Failed to create the XSLT transformer", e1 ); |
| // return original document |
| return document; |
| } |
| |
| // now lets style the given document |
| DocumentSource source = new DocumentSource( document ); |
| DocumentResult result = new DocumentResult(); |
| |
| try |
| { |
| transformer.transform( source, result ); |
| } |
| catch ( TransformerException e ) |
| { |
| // return original document |
| return document; |
| } |
| |
| // return the transformed document |
| Document transformedDoc = result.getDocument(); |
| return transformedDoc; |
| } |
| |
| /** |
| * GrammarAction that reads the SOAP header data |
| */ |
| public static final GrammarAction READ_SOAP_HEADER = new ReadSoapHeader(); |
| } |