1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.api.dsmlv2;
21
22
23 import java.nio.charset.StandardCharsets;
24 import java.util.Arrays;
25 import java.util.Base64;
26 import java.util.Collection;
27
28 import javax.xml.transform.Transformer;
29 import javax.xml.transform.TransformerConfigurationException;
30 import javax.xml.transform.TransformerException;
31 import javax.xml.transform.TransformerFactory;
32 import javax.xml.transform.stream.StreamSource;
33
34 import org.apache.directory.api.asn1.util.Asn1Buffer;
35 import org.apache.directory.api.dsmlv2.actions.ReadSoapHeader;
36 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml;
37 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.Processing;
38 import org.apache.directory.api.dsmlv2.request.BatchRequestDsml.ResponseOrder;
39 import org.apache.directory.api.i18n.I18n;
40 import org.apache.directory.api.ldap.codec.api.LdapApiService;
41 import org.apache.directory.api.ldap.model.message.Control;
42 import org.apache.directory.api.util.Strings;
43 import org.dom4j.Document;
44 import org.dom4j.Element;
45 import org.dom4j.Namespace;
46 import org.dom4j.QName;
47 import org.dom4j.io.DocumentResult;
48 import org.dom4j.io.DocumentSource;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.xmlpull.v1.XmlPullParser;
52 import org.xmlpull.v1.XmlPullParserException;
53
54
55
56
57
58
59
60 public final class ParserUtils
61 {
62
63 public static final String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema";
64
65
66 public static final String XML_SCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance";
67
68
69 public static final String BASE64BINARY = "base64Binary";
70
71
72 public static final String XSI = "xsi";
73
74
75 public static final String XSD = "xsd";
76
77
78 public static final String XSD_COLON = "xsd:";
79
80
81 public static final Namespace DSML_NAMESPACE = new Namespace( null, "urn:oasis:names:tc:DSML:2:0:core" );
82
83
84 public static final Namespace XSD_NAMESPACE = new Namespace( XSD, XML_SCHEMA_URI );
85
86
87 public static final Namespace XSI_NAMESPACE = new Namespace( XSI, XML_SCHEMA_INSTANCE_URI );
88
89
90 private static final Logger LOG = LoggerFactory.getLogger( ParserUtils.class );
91
92
93
94
95 public static final GrammarAction READ_SOAP_HEADER = new ReadSoapHeader();
96
97 private ParserUtils()
98 {
99 }
100
101
102
103
104
105
106
107
108 public static String getXsiTypeAttributeValue( XmlPullParser xpp )
109 {
110 String type = null;
111 int nbAttributes = xpp.getAttributeCount();
112
113 for ( int i = 0; i < nbAttributes; i++ )
114 {
115
116 if ( DsmlLiterals.TYPE.equals( xpp.getAttributeName( i ) )
117 && xpp.getNamespace( xpp.getAttributePrefix( i ) ).equals( XML_SCHEMA_INSTANCE_URI ) )
118 {
119 type = xpp.getAttributeValue( i );
120 break;
121 }
122 }
123
124 return type;
125 }
126
127
128
129
130
131
132
133
134
135 public static boolean isBase64BinaryValue( XmlPullParser parser, String attrValue )
136 {
137 if ( attrValue == null )
138 {
139 return false;
140 }
141
142
143
144 String[] splitedString = attrValue.split( ":" );
145
146 return ( splitedString.length == 2 ) && ( XML_SCHEMA_URI.equals( parser.getNamespace( splitedString[0] ) ) )
147 && ( BASE64BINARY.equals( splitedString[1] ) );
148 }
149
150
151
152
153
154
155
156
157 public static boolean needsBase64Encoding( Object value )
158 {
159 return ( value instanceof byte[] );
160 }
161
162
163
164
165
166
167
168
169 public static String base64Encode( Object value )
170 {
171 if ( value instanceof byte[] )
172 {
173 return new String( Base64.getEncoder().encode( ( byte[] ) value ), StandardCharsets.UTF_8 );
174 }
175 else if ( value instanceof String )
176 {
177 return new String( Base64.getEncoder().encode( Strings.getBytesUtf8( ( String ) value ) ), StandardCharsets.UTF_8 );
178 }
179
180 return Strings.EMPTY_STRING;
181 }
182
183
184
185
186
187
188
189
190
191
192 public static int parseAndVerifyRequestID( String attributeValue, XmlPullParser xpp ) throws XmlPullParserException
193 {
194 try
195 {
196 int requestID = Integer.parseInt( attributeValue );
197
198 if ( requestID < 0 )
199 {
200 throw new XmlPullParserException( I18n.err( I18n.ERR_03016_BELOW_0_REQUEST_ID, requestID ), xpp, null );
201 }
202
203 return requestID;
204 }
205 catch ( NumberFormatException nfe )
206 {
207 throw new XmlPullParserException( I18n.err( I18n.ERR_03012_REQUEST_ID_NOT_INTEGER ), xpp, nfe );
208 }
209 }
210
211
212
213
214
215
216
217
218
219
220 public static void addControls( LdapApiService codec, Element element, Collection<Control> controls, boolean isRequest )
221 {
222 if ( controls != null )
223 {
224 for ( Control control : controls )
225 {
226 Element controlElement = element.addElement( DsmlLiterals.CONTROL );
227
228 if ( control.getOid() != null )
229 {
230 controlElement.addAttribute( DsmlLiterals.TYPE, control.getOid() );
231 }
232
233 if ( control.isCritical() )
234 {
235 controlElement.addAttribute( DsmlLiterals.CRITICALITY, DsmlLiterals.TRUE );
236 }
237
238 Asn1Buffer asn1Buffer = new Asn1Buffer();
239
240 if ( isRequest )
241 {
242 codec.getRequestControlFactories().get( control.getOid() ).encodeValue( asn1Buffer, control );
243 }
244 else
245 {
246 codec.getResponseControlFactories().get( control.getOid() ).encodeValue( asn1Buffer, control );
247 }
248
249 byte[] value = asn1Buffer.getBytes().array();
250
251 if ( value != null )
252 {
253 if ( ParserUtils.needsBase64Encoding( value ) )
254 {
255 element.getDocument().getRootElement().add( XSD_NAMESPACE );
256 element.getDocument().getRootElement().add( XSI_NAMESPACE );
257
258 Element valueElement = controlElement.addElement( DsmlLiterals.CONTROL_VALUE ).addText(
259 ParserUtils.base64Encode( value ) );
260 valueElement.addAttribute( new QName( DsmlLiterals.TYPE, XSI_NAMESPACE ), ParserUtils.XSD_COLON
261 + ParserUtils.BASE64BINARY );
262 }
263 else
264 {
265 controlElement.addElement( DsmlLiterals.CONTROL_VALUE ).setText( Arrays.toString( value ) );
266 }
267 }
268 }
269 }
270 }
271
272
273
274
275
276
277
278
279
280 public static boolean isRequestIdNeeded( Dsmlv2Container container ) throws XmlPullParserException
281 {
282 BatchRequestDsml batchRequest = container.getBatchRequest();
283
284 if ( batchRequest == null )
285 {
286 throw new XmlPullParserException( I18n.err( I18n.ERR_03003_UNABLE_TO_FIND_BATCH_REQUEST ), container.getParser(), null );
287 }
288
289 return ( batchRequest.getProcessing() == Processing.PARALLEL ) && ( batchRequest.getResponseOrder() == ResponseOrder.UNORDERED );
290 }
291
292
293
294
295
296
297
298
299 public static Document styleDocument( Document document )
300 {
301
302 TransformerFactory factory = TransformerFactory.newInstance();
303 Transformer transformer = null;
304
305 try
306 {
307 factory.setFeature( javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE );
308 try
309 {
310 factory.setAttribute( javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD, Strings.EMPTY_STRING );
311 factory.setAttribute( javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET, Strings.EMPTY_STRING );
312 }
313 catch ( IllegalArgumentException ex )
314 {
315
316 }
317 transformer = factory.newTransformer( new StreamSource( ParserUtils.class
318 .getResourceAsStream( "/org/apache/directory/shared/dsmlv2/DSMLv2.xslt" ) ) );
319 }
320 catch ( TransformerConfigurationException e1 )
321 {
322 if ( LOG.isWarnEnabled() )
323 {
324 LOG.warn( I18n.msg( I18n.MSG_3000_FAILED_TO_CREATE_XSLT_TRANSFORMER ), e1 );
325 }
326
327
328 return document;
329 }
330
331
332 DocumentSource source = new DocumentSource( document );
333 DocumentResult result = new DocumentResult();
334
335 try
336 {
337 transformer.transform( source, result );
338 }
339 catch ( TransformerException e )
340 {
341
342 return document;
343 }
344
345
346 return result.getDocument();
347 }
348 }