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.wsrf.impl;
36  
37  import java.util.Iterator;
38  
39  import javax.xml.namespace.QName;
40  
41  import org.apache.axis2.context.MessageContext;
42  import org.apache.log4j.Logger;
43  import org.apache.muse.core.Environment;
44  import org.apache.muse.core.Resource;
45  import org.apache.muse.core.ResourceManager;
46  import org.apache.muse.util.xml.XmlUtils;
47  import org.apache.muse.ws.addressing.EndpointReference;
48  import org.apache.muse.ws.addressing.MessageHeaders;
49  import org.apache.muse.ws.addressing.WsaConstants;
50  import org.apache.muse.ws.addressing.soap.SoapConstants;
51  import org.apache.muse.ws.addressing.soap.SoapFault;
52  import org.apache.muse.ws.resource.WsrfConstants;
53  import org.apache.muse.ws.resource.faults.ResourceUnknownFault;
54  import org.apache.xmlbeans.XmlObject;
55  import org.ogf.graap.wsag.api.AgreementFactory;
56  import org.ogf.graap.wsag.api.WsagConstants;
57  import org.ogf.graap.wsag.security.core.server.ServerSecurityHandler;
58  import org.ogf.graap.wsag.server.api.AgreementAcceptanceFactory;
59  import org.ogf.graap.wsag.server.api.IAgreementFactory;
60  import org.ogf.graap.wsag.server.api.IAgreementFactoryContext;
61  import org.ogf.graap.wsag.server.api.WsagMessageContext;
62  import org.ogf.graap.wsag.server.engine.WsagEngine;
63  import org.ogf.graap.wsag.server.persistence.IAgreementFactoryHome;
64  import org.ogf.graap.wsag.wsrf.persistence.IWsAgreementFactoryHome;
65  import org.ogf.graap.wsag.wsrf.persistence.WsDatabasePersistentAgreement;
66  import org.ogf.graap.wsag.wsrf.persistence.WsDatabaseWSAG4JPersistence;
67  import org.ogf.graap.wsag.wsrf.persistence.WsPersistentAgreementFactory;
68  import org.ogf.graap.wsag.wsrf.sg.impl.MembershipContentRuleContext;
69  import org.ogf.graap.wsag4j.types.configuration.HandlerType;
70  import org.w3.x2005.x08.addressing.EndpointReferenceType;
71  import org.w3c.dom.Document;
72  import org.w3c.dom.Element;
73  
74  /**
75   * SimpleResourceRouter
76   * 
77   * @author Oliver Waeldrich
78   * 
79   */
80  public class WSAG4JResourceRouter extends org.apache.muse.core.routing.SimpleResourceRouter
81  {
82  
83      private static final Logger LOG = Logger.getLogger( WSAG4JResourceRouter.class );
84  
85      private boolean initialized = false;
86  
87      private boolean hasBeenShutdown = false;
88  
89      private static ThreadLocal<ServerSecurityHandler[]> securityHandlerPool = null;
90  
91      /**
92       * Initializes the WS Resource Router.
93       * 
94       * @throws SoapFault
95       *             indicates a initialization fault
96       * 
97       * @see org.apache.muse.core.routing.SimpleResourceRouter#initialize()
98       */
99      public void initialize() throws SoapFault
100     {
101         super.initialize();
102 
103         if ( LOG.isDebugEnabled() )
104         {
105             LOG.debug( "Initializing WSAG4JResourceRouter..." );
106         }
107 
108         synchronized ( this )
109         {
110             if ( !initialized )
111             {
112                 //
113                 // initialize security handler pool
114                 //
115                 securityHandlerPool = new ThreadLocal<ServerSecurityHandler[]>()
116                 {
117                     //
118                     // method is called on first invocation of securityHandlerPool.get(),
119                     // at this time the wsrf-configuration was already set.
120                     //
121                     protected synchronized ServerSecurityHandler[] initialValue()
122                     {
123                         return getMessageHandler();
124                     }
125 
126                 };
127 
128                 MembershipContentRuleContext.initializeContext();
129 
130                 //
131                 // Load the agreement factories
132                 //
133                 IAgreementFactoryHome persistence = WsagEngine.getAgreementFactoryHome();
134 
135                 //
136                 // wrap in ws persistence layer instance
137                 //
138                 IWsAgreementFactoryHome wsPersistence = new WsDatabaseWSAG4JPersistence( persistence );
139 
140                 //
141                 // initialize the persistence layer
142                 //
143                 try
144                 {
145                     wsPersistence.initialize();
146                 }
147                 catch ( Exception e )
148                 {
149                     LOG.error( "Failed to initialize WSAG4J persistent layer. Error: " + e.getMessage() );
150                 }
151 
152                 //
153                 // load the agreement factories and initialize the WS resources
154                 //
155                 WsPersistentAgreementFactory[] wsFactories = new WsPersistentAgreementFactory[0];
156 
157                 try
158                 {
159                     wsFactories = wsPersistence.list();
160                 }
161                 catch ( Exception e )
162                 {
163                     LOG.error( "Failed to load persistent agreement factories. " + e.getMessage() );
164                 }
165 
166                 deployPersistentFactories( wsFactories );
167 
168                 if ( LOG.isDebugEnabled() )
169                 {
170                     LOG.debug( "Deployed " + wsFactories.length + " agreement factories." );
171                 }
172 
173                 //
174                 // load the agreement of the factory and initialize the WS resources
175                 //
176                 for ( int j = 0; j < wsFactories.length; j++ )
177                 {
178                     if ( LOG.isDebugEnabled() )
179                     {
180                         LOG.debug( "Load and initialize agreements of agreement factory '"
181                             + wsFactories[j].getResourceId() + "'." );
182                     }
183 
184                     try
185                     {
186                         wsFactories[j].load();
187                     }
188                     catch ( Exception e )
189                     {
190                         throw new SoapFault( "Persistent Agreement Factory failed to load agreements.", e );
191                     }
192 
193                     WsDatabasePersistentAgreement[] wsDatabasePersistentAgreements = wsFactories[j].list();
194                     deployPersistentAgreements( wsDatabasePersistentAgreements,
195                                                 wsFactories[j].getAgreementFactoryEPR() );
196                 }
197 
198                 initialized = true;
199             }
200         }
201 
202         if ( LOG.isDebugEnabled() )
203         {
204             LOG.debug( "Initialization of WSAG4JResourceRouter finished..." );
205         }
206     }
207 
208     private void deployPersistentFactories( WsPersistentAgreementFactory[] factories ) throws SoapFault
209     {
210         //
211         // initialize the agreement factory WS resources and the according registries
212         //
213         for ( int j = 0; j < factories.length; j++ )
214         {
215 
216             if ( LOG.isDebugEnabled() )
217             {
218                 LOG.debug( "Calling deployPersistentFactories() the " + j + "-th time." );
219             }
220 
221             AgreementFactoryWsResource factory =
222                 (AgreementFactoryWsResource) getResourceManager().createResource( "AgreementFactory" );
223 
224             EndpointReferenceType factoryEPR = factories[j].getAgreementFactoryEPR();
225 
226             factory.setAgreementFactory( factories[j] );
227             factory.setEndpointReference( factoryEPR );
228 
229             //
230             // initialize the factory WSRF resource and populate the
231             // factory context with an AgreementAcceptanceFactory instance
232             // in case the agreement factory implements the IAgreementFactory
233             // interface
234             //
235             factory.initialize();
236 
237             AgreementFactory realFactory = factory.getAgreementFactory();
238 
239             if ( realFactory instanceof IAgreementFactory )
240             {
241                 IAgreementFactoryContext context = ( (IAgreementFactory) realFactory ).getFactoryContext();
242 
243                 context.put( AgreementAcceptanceFactory.AGREEMENT_ACCEPTANCE_FACTORY,
244                              new AgreementAcceptanceFactoryImpl( factory ) );
245             }
246 
247             getResourceManager().addResource( factory.getEndpointReference(), factory );
248 
249             if ( LOG.isDebugEnabled() )
250             {
251                 String url = factoryEPR.getAddress().getStringValue();
252                 XmlObject resIdDoc =
253                     factoryEPR.getReferenceParameters().selectChildren( WsagConstants.WSAG4J_RESOURCE_ID_QNAME )[0];
254                 String resId = resIdDoc.getDomNode().getFirstChild().getNodeValue();
255                 LOG.debug( "Successfully deployed agreement factory. URL: " + url + " Resource ID: " + resId );
256                 // log.debug(factoryEPR.xmlText(new XmlOptions().setSavePrettyPrint()));
257             }
258 
259             //
260             // load and initialize the associated agreement registry for the factory.
261             // The registry will have the same reference parameters as the factory,
262             // but is deployed at its own deployment end point.
263             //
264             Resource registry = getResourceManager().createResource( "AgreementServiceGroup" );
265 
266             EndpointReferenceType registryEPR =
267                 org.ogf.graap.wsag.wsrf.XmlUtils.convertMuseEPRToEndpoint( registry.getEndpointReference() );
268 
269             registryEPR.unsetReferenceParameters();
270             registryEPR.addNewReferenceParameters().set( factoryEPR.getReferenceParameters() );
271 
272             EndpointReference museRegistryEPR =
273                 org.ogf.graap.wsag.wsrf.XmlUtils.convertEndpointToMuseEPR( registryEPR );
274             registry.setEndpointReference( museRegistryEPR );
275 
276             registry.initialize();
277             getResourceManager().addResource( registry.getEndpointReference(), registry );
278 
279             if ( LOG.isDebugEnabled() )
280             {
281                 LOG.debug( "Successfully deployed agreement registry." );
282             }
283         }
284     }
285 
286     private void deployPersistentAgreements( WsDatabasePersistentAgreement[] wsDatabasePersistentAgreements,
287                                              EndpointReferenceType factoryEPR ) throws SoapFault
288     {
289         if ( LOG.isDebugEnabled() )
290         {
291             LOG.debug( "Try to load " + wsDatabasePersistentAgreements.length
292                 + " persisted agreements for agreement factory with EPR address '" + factoryEPR.getAddress()
293                 + "'." );
294         }
295 
296         for ( int k = 0; k < wsDatabasePersistentAgreements.length; k++ )
297         {
298             AgreementWsResource agreement =
299                 (AgreementWsResource) getResourceManager().createResource( "Agreement" );
300 
301             WsDatabasePersistentAgreement wsDatabasePersistentAgreement = wsDatabasePersistentAgreements[k];
302             if ( wsDatabasePersistentAgreement == null )
303             {
304                 throw new SoapFault( "WS persistent agreement was NULL." );
305             }
306 
307             EndpointReferenceType agreementEPR = wsDatabasePersistentAgreement.getAgreementEPR();
308             agreement.setEndpointReference( agreementEPR );
309 
310             agreement.setAgreement( wsDatabasePersistentAgreement.getAgreement() );
311             agreement.setFactoryEPR( factoryEPR );
312 
313             agreement.initialize();
314 
315             getResourceManager().addResource( agreement.getEndpointReference(), agreement );
316 
317             if ( LOG.isDebugEnabled() )
318             {
319                 LOG.debug( "Successfully deployed persisted agreement." );
320             }
321         }
322     }
323 
324     /**
325      * 
326      * Queries the Environment to get the WS-A EPR being targeted by the current request and then does a
327      * lookup in the ResourceManager with that EPR. This method is essential to all routing activity. The
328      * resource returned is guaranteed to be the resource specified by the client, but it is not guaranteed to
329      * support the specified operation.
330      * 
331      * @return The resource whose EPR maps to the WS-A data in the current request.
332      * 
333      * @throws SoapFault
334      *             <ul>
335      *             <li>If the EPR (including any unique reference properties) is not associated with any
336      *             resource instance.</li>
337      *             </ul>
338      * 
339      * @see MessageHeaders#getToAddress()
340      * @see ResourceManager#getResource(EndpointReference)
341      * 
342      */
343     protected Resource getTargetResource() throws SoapFault
344     {
345         ResourceManager manager = getResourceManager();
346         Environment env = getEnvironment();
347         MessageHeaders wsa = env.getAddressingContext();
348 
349         if ( wsa == null )
350         {
351             throw new RuntimeException( "NoAddressingContext" );
352         }
353 
354         EndpointReference epr = wsa.getToAddress();
355 
356         Resource resource = manager.getResource( epr );
357 
358         if ( resource == null )
359         {
360             //
361             // construct an error message that has a formatted list of
362             // all of the valid EPRs so that users can determine what
363             // was wrong with the EPR they provided
364             //
365 
366             String museNS = "http://ws.apache.org/muse";
367             Element noEPR = XmlUtils.createElement( new QName( museNS, "EndpointNotFound" ) );
368             Element reqEPR = noEPR.getOwnerDocument().createElementNS( museNS, "RequestedEndpoint" );
369             Element avEPR = noEPR.getOwnerDocument().createElementNS( museNS, "AvailableEndpoints" );
370 
371             noEPR.appendChild( reqEPR );
372             noEPR.appendChild( avEPR );
373 
374             reqEPR.appendChild( epr.toXML( reqEPR.getOwnerDocument() ) );
375 
376             // might be used for the debug log
377             StringBuffer eprNotFound = new StringBuffer( 512 );
378             eprNotFound.append( "\n\n" );
379             eprNotFound.append( epr );
380             eprNotFound.append( '\n' );
381 
382             @SuppressWarnings( "unchecked" )
383             Iterator<Object> i = manager.getResourceEPRs();
384             StringBuffer eprListing = new StringBuffer( 1024 );
385             eprListing.append( '\n' );
386 
387             while ( i.hasNext() )
388             {
389                 eprListing.append( '\n' );
390                 eprListing.append( i.next() );
391             }
392 
393             ResourceUnknownFault fault =
394                 new ResourceUnknownFault( "There is no resource available at the given EPR:\n " + eprNotFound
395                     + ". \nThe existing EPRs hosted by this endpoint are:\n " + eprListing );
396 
397             //
398             // The BaseFault Implementation is buggy. Therefore we switch to
399             // the SOAPFault implementation here, hopefully with more luck.
400             //
401             SoapFault soapFault = new SoapFault( fault.toXML() );
402             Document owner = soapFault.getDetail().getOwnerDocument();
403 
404             Element timestamp = owner.createElementNS( WsrfConstants.NAMESPACE_URI, "Timestamp" );
405             Element description = owner.createElementNS( WsrfConstants.NAMESPACE_URI, "Description" );
406 
407             timestamp.appendChild( XmlUtils.convertToNode( owner, fault.getTimestamp() ) );
408             description.appendChild( XmlUtils.convertToNode( owner, "Resource unknown" ) );
409 
410             soapFault.setCode( SoapConstants.SENDER_QNAME );
411             soapFault.setSubCode( new QName( WsaConstants.NAMESPACE_URI, "DestinationUnreachable", "wsa" ) );
412             soapFault.getDetail().appendChild( timestamp );
413             soapFault.getDetail().appendChild( description );
414             soapFault.getDetail().appendChild( owner.importNode( noEPR, true ) );
415 
416             throw soapFault;
417         }
418 
419         return resource;
420     }
421 
422     /**
423      * Invokes a SOAP request on the resource router.
424      * 
425      * @param request
426      *            the SOAP request as DOM document
427      * 
428      * @return the SOAP response (this might also be a SOAP error)
429      * 
430      * @see org.apache.muse.core.routing.SimpleResourceRouter#invoke(org.w3c.dom.Element)
431      */
432     public Element invoke( Element request )
433     {
434         //
435         // load the configured security handler
436         //
437         ServerSecurityHandler[] securityHandlers = securityHandlerPool.get();
438 
439         //
440         // set a new message context before invoking the server engine
441         //
442         WsagEngine.setWsagMessageContext( new WsagMessageContext() );
443 
444         //
445         // initially populate the message context
446         //
447         WsagEngine.getWsagMessageContext().put( WsagMessageContext.AXIS_MESSAGE_CONTEXT,
448                                                 MessageContext.getCurrentMessageContext() );
449 
450         //
451         // let the security handler process the message
452         // before invoking the server engine
453         //
454         for ( int i = 0; i < securityHandlers.length; i++ )
455         {
456             try
457             {
458                 securityHandlers[i].handleRequest( request );
459             }
460             catch ( Exception e )
461             {
462                 String message =
463                     "[" + securityHandlers[i].getClass().getName()
464                         + "]: Error while processing the message request headers. (" + e.getMessage() + ")";
465                 LOG.error( message );
466 
467                 throw new RuntimeException( message );
468             }
469         }
470 
471         Element result = super.invoke( request );
472 
473         //
474         // let the security handler process the result message
475         // before handing it back to the isolation layer
476         //
477         for ( int i = 0; i < securityHandlers.length; i++ )
478         {
479             try
480             {
481                 securityHandlers[i].handleResponse( result );
482             }
483             catch ( Exception e )
484             {
485                 String message =
486                     "[" + securityHandlers[i].getClass().getName()
487                         + "]: Error while processing the message response headers. (" + e.getMessage() + ")";
488                 LOG.error( message );
489 
490                 throw new RuntimeException( message );
491             }
492         }
493 
494         //
495         // cleanup after usage
496         //
497         WsagEngine.setWsagMessageContext( null );
498 
499         //
500         // return the response to the isolation layer
501         //
502         return result;
503     }
504 
505     /**
506      * loads the security handler configured for this WSAG4J engine
507      */
508     private static ServerSecurityHandler[] getMessageHandler()
509     {
510 
511         if ( WsagEngine.getWSRFConfiguration().isSetSecurityHandlerChain() )
512         {
513             HandlerType[] handler =
514                 WsagEngine.getWSRFConfiguration().getSecurityHandlerChain().getHandlerArray();
515             ServerSecurityHandler[] result = new ServerSecurityHandler[handler.length];
516 
517             for ( int i = 0; i < handler.length; i++ )
518             {
519                 try
520                 {
521                     @SuppressWarnings( "unchecked" )
522                     Class<ServerSecurityHandler> implementation =
523                         (Class<ServerSecurityHandler>) Class.forName( handler[i].getImplementationClass() );
524                     result[i] = (ServerSecurityHandler) implementation.newInstance();
525                 }
526                 catch ( ClassNotFoundException e )
527                 {
528                     throw new RuntimeException( "The implementation class "
529                         + handler[i].getImplementationClass() + " for handler " + handler[i].getHandlerName()
530                         + " could not be found." );
531                 }
532                 catch ( IllegalAccessException e )
533                 {
534                     throw new RuntimeException( "The implementation class "
535                         + handler[i].getImplementationClass() + " for handler " + handler[i].getHandlerName()
536                         + " could not be accessed. [" + e.getMessage() + "]" );
537                 }
538                 catch ( InstantiationException e )
539                 {
540                     throw new RuntimeException( "The implementation class "
541                         + handler[i].getImplementationClass() + " for handler " + handler[i].getHandlerName()
542                         + " could not be instantiated. [" + e.getMessage() + "]" );
543                 }
544                 catch ( ClassCastException e )
545                 {
546                     throw new RuntimeException( "The implementation class "
547                         + handler[i].getImplementationClass() + " does not implement the interface "
548                         + ServerSecurityHandler.class.getName() + "." );
549                 }
550             }
551 
552             return result;
553         }
554         else
555         {
556             return new ServerSecurityHandler[0];
557         }
558 
559     }
560 
561     /*
562      * (non-Javadoc)
563      * 
564      * @see org.apache.muse.core.routing.SimpleResourceRouter#shutdown()
565      */
566     @SuppressWarnings( "unchecked" )
567     @Override
568     public void shutdown()
569     {
570         try
571         {
572             Iterator<EndpointReference> i = getResourceManager().getResourceEPRs();
573 
574             while ( i.hasNext() )
575             {
576                 EndpointReference epr = i.next();
577                 Resource next = getResourceManager().getResource( epr );
578                 next.shutdown();
579                 i = getResourceManager().getResourceEPRs();
580             }
581         }
582         catch ( SoapFault e )
583         {
584             LOG.error( e );
585         }
586 
587         //
588         // prevent meory leak
589         //
590         if ( securityHandlerPool != null )
591         {
592             securityHandlerPool.set( null );
593             securityHandlerPool = null;
594         }
595 
596         MembershipContentRuleContext.finalizeContext();
597 
598         hasBeenShutdown = true;
599     }
600 
601     /*
602      * (non-Javadoc)
603      * 
604      * @see org.apache.muse.core.routing.SimpleResourceRouter#hasBeenShutdown()
605      */
606     @Override
607     public boolean hasBeenShutdown()
608     {
609         return hasBeenShutdown;
610     }
611 }