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 }