View Javadoc

1   /* 
2    * Copyright (c) 2007, Fraunhofer-Gesellschaft
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are
7    * met:
8    * 
9    * (1) Redistributions of source code must retain the above copyright
10   *     notice, this list of conditions and the disclaimer at the end.
11   *     Redistributions in binary form must reproduce the above copyright
12   *     notice, this list of conditions and the following disclaimer in
13   *     the documentation and/or other materials provided with the
14   *     distribution.
15   * 
16   * (2) Neither the name of Fraunhofer nor the names of its
17   *     contributors may be used to endorse or promote products derived
18   *     from this software without specific prior written permission.
19   * 
20   * DISCLAIMER
21   * 
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   *  
34   */
35  package org.ogf.graap.wsag.client.remote;
36  
37  import java.io.ByteArrayInputStream;
38  import java.io.ByteArrayOutputStream;
39  import java.io.IOException;
40  import java.io.InputStream;
41  import java.math.BigInteger;
42  import java.net.URL;
43  import java.security.cert.X509Certificate;
44  import java.text.MessageFormat;
45  import java.util.Properties;
46  import java.util.Set;
47  import java.util.Vector;
48  
49  import javax.security.auth.login.LoginContext;
50  import javax.xml.namespace.QName;
51  import javax.xml.stream.XMLStreamException;
52  import javax.xml.stream.XMLStreamReader;
53  
54  import org.apache.axiom.om.OMElement;
55  import org.apache.axiom.om.util.StAXUtils;
56  import org.apache.axiom.soap.SOAPEnvelope;
57  import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
58  import org.apache.axis2.AxisFault;
59  import org.apache.axis2.client.OperationClient;
60  import org.apache.axis2.client.ServiceClient;
61  import org.apache.axis2.context.ConfigurationContext;
62  import org.apache.axis2.context.ConfigurationContextFactory;
63  import org.apache.axis2.context.MessageContext;
64  import org.apache.axis2.transport.http.HTTPConstants;
65  import org.apache.log4j.Logger;
66  import org.apache.muse.util.messages.Messages;
67  import org.apache.muse.util.messages.MessagesFactory;
68  import org.apache.muse.util.xml.XmlUtils;
69  import org.apache.muse.ws.addressing.EndpointReference;
70  import org.apache.muse.ws.addressing.soap.SimpleSoapClient;
71  import org.apache.muse.ws.addressing.soap.SoapConstants;
72  import org.apache.muse.ws.addressing.soap.SoapFault;
73  import org.apache.ws.security.WSConstants;
74  import org.apache.ws.security.WSSecurityEngineResult;
75  import org.apache.ws.security.WSSecurityException;
76  import org.apache.ws.security.components.crypto.Crypto;
77  import org.apache.ws.security.handler.WSHandlerConstants;
78  import org.apache.ws.security.handler.WSHandlerResult;
79  import org.apache.xmlbeans.XmlObject;
80  import org.ogf.graap.wsag.api.WsagConstants;
81  import org.ogf.graap.wsag.api.configuration.WSAG4JConfiguration;
82  import org.ogf.graap.wsag.api.security.ISecurityProperties;
83  import org.ogf.graap.wsag.security.core.SecurityConstants;
84  import org.ogf.graap.wsag.security.core.client.ClientSecurityHandler;
85  import org.ogf.graap.wsag4j.types.configuration.ConfigurationType;
86  import org.ogf.graap.wsag4j.types.configuration.HandlerType;
87  import org.ogf.graap.wsag4j.types.configuration.WSRFClientConfigurationType;
88  import org.w3c.dom.Document;
89  import org.w3c.dom.Element;
90  
91  /**
92   * AxisSoapClient
93   * 
94   * @author Oliver Waeldrich
95   * 
96   */
97  public class Axis2SoapClient extends SimpleSoapClient
98  {
99  
100     /**
101      * The SOAP client timeout in milliseconds.
102      */
103     // CHECKSTYLE:OFF - DEFAULT VARIABLE
104     public static int DEFAULT_TIME_OUT_IN_MILLI_SECONDS = 2 * 60 * 1000;
105 
106     // CHECKSTYLE:ON
107 
108     private static final Logger LOG = Logger.getLogger( Axis2SoapClient.class );
109 
110     //
111     // WSAG4J client configuration file
112     //
113     private static ConfigurationType config = null;
114 
115     //
116     // AXIS2 configuration context
117     //
118     private static ConfigurationContext configurationContext = null;
119 
120     //
121     // default definition of an empty SOAP header array
122     //
123     private static final Element[] EMPTY_ARRAY = new Element[0];
124 
125     //
126     // Used to lookup all exception messages
127     //
128     private static final Messages MESSAGES = MessagesFactory.get( SimpleSoapClient.class );
129 
130     //
131     // the properties are used for storing the results of the security processing
132     //
133     private Properties properties = new Properties();
134 
135     //
136     // the security properties
137     //
138     private final ISecurityProperties securityProperties;
139 
140     private Crypto crypto;
141 
142     /**
143      * Creates a new SOAP client with the given security properties.
144      * 
145      * @param securityProperties
146      *            the security properties to use
147      */
148     public Axis2SoapClient( ISecurityProperties securityProperties )
149     {
150         super();
151         this.securityProperties = securityProperties;
152         initialize();
153     }
154 
155     /**
156      * initializes this client instance
157      */
158     protected void initialize()
159     {
160         //
161         // get the login context and read the crypto from the login context
162         //
163         LoginContext context = securityProperties.getLoginContext();
164 
165         if ( context != null )
166         {
167             Set<Crypto> userCrypto = context.getSubject().getPrivateCredentials( Crypto.class );
168             if ( !userCrypto.isEmpty() )
169             {
170                 crypto = userCrypto.iterator().next();
171             }
172         }
173 
174         //
175         // read the client configuration file on the first client invocation
176         //
177         synchronized ( Axis2SoapClient.class )
178         {
179 
180             try
181             {
182                 if ( config == null )
183                 {
184                     config =
185                         WSAG4JConfiguration.findWSAG4JConfiguration( WsagConstants.WSAG4J_WSRF_CLIENT_CONFIG_FILE );
186                 }
187             }
188             catch ( IOException e )
189             {
190                 Object[] filler = new Object[] { WsagConstants.WSAG4J_WSRF_CLIENT_CONFIG_FILE };
191                 String message =
192                     MessageFormat.format( "Failed to read wsag4j client configuration file {0}.", filler );
193                 throw new RuntimeException( message );
194             }
195 
196             try
197             {
198                 //
199                 // the repository URL needs an / at the end,
200                 // otherwise the repository is not loaded correctly
201                 // from the wsag4j-client-resources bundle
202                 //
203                 if ( configurationContext == null )
204                 {
205                     URL repoURL = Axis2SoapClient.class.getResource( "/axis2-client/" );
206                     URL fileURL = Axis2SoapClient.class.getResource( "/axis2-client/client.axis2.xml" );
207                     configurationContext =
208                         ConfigurationContextFactory.createConfigurationContextFromURIs( fileURL, repoURL );
209 
210                     /*
211                      * The following code block is commented out since we use still the default configuration
212                      * of the MultiThreadedHttpConnectionManager.
213                      * 
214                      * There was a problem that the connections are not returned to the connection pool of the
215                      * MultiThreadedHttpConnectionManager after a SOAP call. This issue was solved by calling
216                      * the oc.complete( currentContext ) method after the SOAP call ( see doAxisCall ->
217                      * finalize block )
218                      */
219 
220                     /*
221                      * MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager = new
222                      * MultiThreadedHttpConnectionManager();
223                      * 
224                      * HttpConnectionManagerParams params = new HttpConnectionManagerParams();
225                      * params.setDefaultMaxConnectionsPerHost(20);
226                      * multiThreadedHttpConnectionManager.setParams(params); HttpClient httpClient = new
227                      * HttpClient(multiThreadedHttpConnectionManager);
228                      * configurationContext.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);
229                      */
230                 }
231             }
232             catch ( Exception e )
233             {
234                 Object[] filler = new Object[] { e.getMessage() };
235                 String message =
236                     MessageFormat.format( "Failed to read axis2 client configuration. Error:  {0}.", filler );
237                 throw new RuntimeException( message, e );
238             }
239         }
240     }
241 
242     /**
243      * {@inheritDoc}
244      */
245     @Override
246     protected Element createMessage( EndpointReference source, EndpointReference destination, String action,
247                                      Element[] bodyElements, Element[] extraHeaders )
248     {
249         Element[] additionalHeaders = generateExtraHeaders();
250         if ( additionalHeaders == null )
251         {
252             additionalHeaders = EMPTY_ARRAY;
253         }
254 
255         Element[] headers;
256 
257         if ( extraHeaders.length == 0 )
258         {
259             // extra headers is usually empty
260             headers = additionalHeaders;
261         }
262         else
263         {
264             // merge the extra headers with the additional headers
265             Vector<Element> tmpHeaders = new Vector<Element>();
266             for ( int i = 0; i < extraHeaders.length; i++ )
267             {
268                 tmpHeaders.add( extraHeaders[i] );
269             }
270 
271             for ( int i = 0; i < additionalHeaders.length; i++ )
272             {
273                 tmpHeaders.add( additionalHeaders[i] );
274             }
275 
276             headers = tmpHeaders.toArray( new Element[tmpHeaders.size()] );
277         }
278 
279         // then we let our parent create the SOAP message
280         return super.createMessage( source, destination, action, bodyElements, headers );
281     }
282 
283     /**
284      * {@inheritDoc}
285      */
286     @Override
287     public Element[] send( EndpointReference src, EndpointReference dest, String wsaAction, Element[] body,
288                            Element[] extraHeaders )
289     {
290         if ( dest == null )
291         {
292             throw new NullPointerException( MESSAGES.get( "NullDestinationEPR" ) );
293         }
294 
295         if ( wsaAction == null )
296         {
297             throw new NullPointerException( MESSAGES.get( "NullActionURI" ) );
298         }
299 
300         if ( body == null )
301         {
302             body = EMPTY_ARRAY;
303         }
304 
305         if ( extraHeaders == null )
306         {
307             extraHeaders = EMPTY_ARRAY;
308         }
309 
310         //
311         // create the request message
312         //
313         Element soapRequest = createMessage( src, dest, wsaAction, body, extraHeaders );
314 
315         if ( isUsingTrace() )
316         {
317             trace( soapRequest, false );
318         }
319 
320         Element soapResponse = null;
321 
322         try
323         {
324 
325             //
326             // read in the response and build an XML document from it
327             //
328             soapResponse = doAxisCall( soapRequest, dest, wsaAction );
329         }
330 
331         //
332         // handle errors that are thrown by axis
333         // and create a Muse SOAP fault
334         //
335         catch ( AxisFault error )
336         {
337             SoapFault soapFault = new SoapFault( error.getMessage(), error );
338             if ( error.getFaultCode() != null )
339             {
340                 soapFault.setCode( error.getFaultCode() );
341             }
342 
343             if ( ( error.getFaultSubCodes() != null ) && ( error.getFaultSubCodes().size() > 0 ) )
344             {
345                 soapFault.setSubCode( (QName) error.getFaultSubCodes().get( 0 ) );
346             }
347 
348             try
349             {
350                 OMElement detail = error.getDetail();
351 
352                 ByteArrayOutputStream detailOut = new ByteArrayOutputStream();
353                 detail.serialize( detailOut );
354 
355                 ByteArrayInputStream detailIn = new ByteArrayInputStream( detailOut.toByteArray() );
356                 soapFault.setDetail( XmlUtils.createDocument( detailIn ).getDocumentElement() );
357             }
358             catch ( Exception e )
359             {
360                 return new Element[] { soapFault.toXML() };
361             }
362             return new Element[] { soapFault.toXML() };
363         }
364 
365         // handle any other runtime/IO exceptions as best we can
366         catch ( Throwable error )
367         {
368             SoapFault soapFault = new SoapFault( error.getMessage(), error );
369             return new Element[] { soapFault.toXML() };
370         }
371 
372         if ( isUsingTrace() )
373         {
374             trace( soapResponse, true );
375         }
376 
377         //
378         // return the elements inside the SOAP body
379         //
380         Element responseBody = XmlUtils.getElement( soapResponse, SoapConstants.BODY_QNAME );
381         return XmlUtils.getAllElements( responseBody );
382     }
383 
384     /**
385      * Executes a SOAP call by using the Axis 2 SOAP engine.
386      * 
387      * @param soapRequest
388      *            the SOAP request as a DOM element
389      * @param dest
390      *            the destination EPR
391      * @param wsaAction
392      *            the web service action
393      * 
394      * @return the SOAP response as a DOM element
395      * @throws AxisFault
396      *             indicates a SOAP fault during the request
397      */
398     protected Element doAxisCall( Element soapRequest, EndpointReference dest, String wsaAction )
399         throws AxisFault
400     {
401 
402         //
403         // prepare the AXIS call by saving the old AXIS2 MessageContext
404         // and creating a new MessageContext for the subsequent call.
405         // This MessageContext is used to pass the client crypto to our
406         // Merlin implementation.
407         //
408         MessageContext currentContext = new MessageContext();
409         MessageContext oldContext = MessageContext.getCurrentMessageContext();
410         MessageContext.setCurrentMessageContext( currentContext );
411 
412         ServiceClient client = new org.apache.axis2.client.ServiceClient( configurationContext, null );
413 
414         org.apache.axis2.addressing.EndpointReference to =
415             new org.apache.axis2.addressing.EndpointReference( dest.getAddress().toString() );
416         client.getOptions().setTo( to );
417 
418         // during the initialization of the service client, a set
419         // of operation clients was created. The following types are available:
420         // [ANON_OUT_IN_OP], [ANON_OUT_ONLY_OP], [ANON_ROBUST_OUT_ONLY_OP]
421         OperationClient oc = client.createClient( ServiceClient.ANON_OUT_IN_OP );
422 
423         try
424         {
425 
426             // serialize the message and read it via StAX
427             String serializedMessage = XmlUtils.toString( soapRequest, false, false );
428             InputStream in = new ByteArrayInputStream( serializedMessage.getBytes() );
429 
430             XMLStreamReader reader;
431 
432             try
433             {
434                 reader = StAXUtils.createXMLStreamReader( in );
435             }
436             catch ( XMLStreamException e )
437             {
438                 String message = "Error creating axis call from SOAP request";
439                 throw new AxisFault( message, e );
440             }
441             StAXSOAPModelBuilder builder = new StAXSOAPModelBuilder( reader );
442 
443             // since we have parsed a new created SOAP 1.2 request,
444             // the result of this process is a org.apache.axiom.soap.SOAPEnvelope
445             SOAPEnvelope envelope = (SOAPEnvelope) builder.getDocumentElement();
446 
447             // add the user signing crypto
448             currentContext.setProperty( SecurityConstants.CRYPTO_SIGN, getCrypto() );
449             currentContext.setProperty( HTTPConstants.AUTO_RELEASE_CONNECTION, new Boolean( true ) );
450             // currentContext.getOptions().setUseSeparateListener(true);
451 
452             currentContext.getOptions().setTimeOutInMilliSeconds( DEFAULT_TIME_OUT_IN_MILLI_SECONDS );
453 
454             currentContext.setEnvelope( envelope );
455 
456             oc.addMessageContext( currentContext );
457             oc.getOptions().setAction( wsaAction );
458 
459             // oc.getOptions().setProperty(HTTPConstants.SO_TIMEOUT,new Integer(600000));
460             // oc.getOptions().setProperty(HTTPConstants.CONNECTION_TIMEOUT,new Integer(600000));
461             // oc.getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, new Boolean(true));
462 
463             //
464             // execute the operation client
465             //
466             if ( LOG.isTraceEnabled() )
467             {
468                 LOG.trace( MessageFormat.format( "starting call to ", new Object[] { dest.getAddress() } ) );
469             }
470 
471             oc.execute( true );
472 
473             if ( LOG.isTraceEnabled() )
474             {
475                 LOG.trace( MessageFormat.format( "received response from  ",
476                     new Object[] { dest.getAddress() } ) );
477             }
478 
479             //
480             // now we read the response from the MessageContext,
481             // parse the result and return
482             //
483             MessageContext returnMessageContext =
484                 oc.getMessageContext( org.apache.axis2.wsdl.WSDLConstants.MESSAGE_LABEL_IN_VALUE );
485 
486             SOAPEnvelope returnEnv = returnMessageContext.getEnvelope();
487 
488             XMLStreamReader resultReader = returnEnv.getXMLStreamReaderWithoutCaching();
489 
490             //
491             // Read security handler results from response message context
492             // and place them in the properties object.
493             //
494             processSecurityResults( returnMessageContext );
495 
496             return parseResponse( resultReader );
497 
498         }
499         finally
500         {
501             oc.complete( currentContext );
502             MessageContext.setCurrentMessageContext( oldContext );
503         }
504     }
505 
506     @SuppressWarnings( "unchecked" )
507     private void processSecurityResults( MessageContext context ) throws AxisFault
508     {
509         try
510         {
511             Vector<WSHandlerResult> handlerResults =
512                 (Vector<WSHandlerResult>) context.getProperty( WSHandlerConstants.RECV_RESULTS );
513 
514             //
515             // Only process security handler results if present
516             //
517             if ( handlerResults != null )
518             {
519 
520                 for ( int i = 0; i < handlerResults.size(); i++ )
521                 {
522                     WSHandlerResult currentResult = handlerResults.get( i );
523 
524                     Vector<WSSecurityEngineResult> wsSecEngineResults = currentResult.getResults();
525 
526                     for ( int j = 0; j < wsSecEngineResults.size(); j++ )
527                     {
528                         WSSecurityEngineResult wser = wsSecEngineResults.get( j );
529                         if ( ( (Integer) wser.get( WSSecurityEngineResult.TAG_ACTION ) ).intValue() == WSConstants.SIGN
530                             && wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATE ) != null )
531                         {
532 
533                             // put the server certificate into the client properties
534                             X509Certificate certificate =
535                                 (X509Certificate) wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATE );
536                             properties.put( SecurityConstants.X509_SERVER_CERTIFICATE, certificate );
537 
538                             String issuerString = certificate.getIssuerDN().getName();
539                             BigInteger issuerSerial = certificate.getSerialNumber();
540                             String alias = getCrypto().getAliasForX509Cert( issuerString, issuerSerial );
541 
542                             if ( alias != null )
543                             {
544                                 // Retrieve the certificate for the alias from the keystore
545                                 try
546                                 {
547                                     X509Certificate[] certs = getCrypto().getCertificates( alias );
548                                     properties.put( SecurityConstants.X509_SERVER_CERTIFICATE_CHAIN, certs );
549                                 }
550                                 catch ( WSSecurityException ex )
551                                 {
552                                     String msgError =
553                                         "Axis2SoapClient: Could not get certificates for alias " + alias;
554                                     throw new WSSecurityException( msgError, ex );
555                                 }
556                             }
557                         }
558 
559                         if ( ( (Integer) wser.get( WSSecurityEngineResult.TAG_ACTION ) ).intValue() == WSConstants.BST
560                             && wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATES ) != null )
561                         {
562 
563                             // put the server certificates into the client properties
564                             X509Certificate[] certificates =
565                                 (X509Certificate[]) wser.get( WSSecurityEngineResult.TAG_X509_CERTIFICATES );
566                             properties.put( SecurityConstants.X509_SERVER_CERTIFICATE_CHAIN, certificates );
567                         }
568                     }
569 
570                 }
571             }
572         }
573         catch ( Exception e )
574         {
575             throw new AxisFault( "Axis2SoapClient: Error while processing security handler results.", e );
576         }
577     }
578 
579     private Element parseResponse( XMLStreamReader reader ) throws AxisFault
580     {
581         try
582         {
583             XmlObject parsedResult = XmlObject.Factory.parse( reader );
584 
585             if ( parsedResult.getDomNode() instanceof Document )
586             {
587                 return XmlUtils.getFirstElement( parsedResult.getDomNode() );
588             }
589             if ( parsedResult.getDomNode() instanceof Element )
590             {
591                 return (Element) parsedResult.getDomNode();
592             }
593 
594             String message = "Response document is not of type document or element or null.";
595             throw new AxisFault( message );
596         }
597         catch ( Exception e )
598         {
599             String message = "Error in deserializing the Axis response.";
600             throw new AxisFault( message, e );
601         }
602     }
603 
604     /**
605      * 
606      * @return Returns a set of extra header elements that is included in the SOAP message.
607      * @throws SecurityException
608      */
609     protected Element[] generateExtraHeaders()
610     {
611 
612         Vector<Element> extraHeaders = new Vector<Element>();
613         ClientSecurityHandler[] handler = getSecurityHandler();
614         for ( int i = 0; i < handler.length; i++ )
615         {
616             Element[] tmpHeaders = handler[i].createHeader( securityProperties );
617             for ( int j = 0; j < tmpHeaders.length; j++ )
618             {
619                 extraHeaders.add( tmpHeaders[j] );
620             }
621         }
622 
623         return extraHeaders.toArray( new Element[extraHeaders.size()] );
624     }
625 
626     /**
627      * @return the security handler of this client instance
628      */
629     protected ClientSecurityHandler[] getSecurityHandler()
630     {
631 
632         if ( config == null )
633         {
634             Object[] filler = new Object[] { WsagConstants.WSAG4J_WSRF_CLIENT_CONFIG_FILE };
635             String message =
636                 MessageFormat.format( "The client configuration file {0} was not found.", filler );
637             LOG.warn( message );
638 
639             return new ClientSecurityHandler[0];
640         }
641 
642         WSRFClientConfigurationType wsrfConfig = config.getWSRFClientConfiguration();
643 
644         if ( wsrfConfig.isSetSecurityHandlerChain() )
645         {
646             HandlerType[] handler = wsrfConfig.getSecurityHandlerChain().getHandlerArray();
647             ClientSecurityHandler[] result = new ClientSecurityHandler[handler.length];
648 
649             for ( int i = 0; i < handler.length; i++ )
650             {
651                 String implementationClass = handler[i].getImplementationClass();
652                 String handlerName = handler[i].getHandlerName();
653 
654                 try
655                 {
656                     @SuppressWarnings( "unchecked" )
657                     Class<ClientSecurityHandler> implementation =
658                         (Class<ClientSecurityHandler>) Class.forName( implementationClass );
659                     result[i] = implementation.newInstance();
660                 }
661                 catch ( ClassNotFoundException e )
662                 {
663                     Object[] filler = new Object[] { implementationClass, handlerName };
664                     String message =
665                         MessageFormat.format(
666                             "The implementation class {0} for handler {1} could not be found.", filler );
667                     throw new RuntimeException( message );
668                 }
669                 catch ( IllegalAccessException e )
670                 {
671                     Object[] filler = new Object[] { implementationClass, handlerName, e.getMessage() };
672                     String msgError =
673                         "The implementation class {0} for handler {1} could not be accessed. [{2}]";
674                     String message = MessageFormat.format( msgError, filler );
675                     throw new RuntimeException( message );
676                 }
677                 catch ( InstantiationException e )
678                 {
679                     Object[] filler = new Object[] { implementationClass, handlerName, e.getMessage() };
680                     String msgError =
681                         "The implementation class {0} for handler {1} could not be instantiated. [{2}]";
682                     String message = MessageFormat.format( msgError, filler );
683                     throw new RuntimeException( message );
684                 }
685                 catch ( ClassCastException e )
686                 {
687                     Object[] filler =
688                         new Object[] { implementationClass, ClientSecurityHandler.class.getName() };
689                     String msgError = "The implementation class {0} does not implement the interface {1}.";
690                     String message = MessageFormat.format( msgError, filler );
691                     throw new RuntimeException( message );
692                 }
693             }
694 
695             return result;
696         }
697         else
698         {
699             return new ClientSecurityHandler[0];
700         }
701 
702     }
703 
704     /**
705      * @return the properties
706      */
707     public Properties getProperties()
708     {
709         return properties;
710     }
711 
712     /**
713      * @param properties
714      *            the properties to set
715      */
716     public void setProperties( Properties properties )
717     {
718         this.properties = properties;
719     }
720 
721     /**
722      * @return the crypto
723      */
724     public Crypto getCrypto()
725     {
726         return crypto;
727     }
728 }