View Javadoc

1   /* 
2    * Copyright (c) 2005-2011, 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 javax.persistence.EntityManager;
38  import javax.persistence.RollbackException;
39  import javax.security.auth.Subject;
40  import javax.xml.namespace.QName;
41  
42  import org.apache.log4j.Logger;
43  import org.apache.muse.core.Resource;
44  import org.apache.muse.ws.addressing.EndpointReference;
45  import org.apache.muse.ws.resource.faults.ResourceUnavailableFault;
46  import org.apache.muse.ws.resource.faults.ResourceUnknownFault;
47  import org.apache.xmlbeans.XmlObject;
48  import org.apache.xmlbeans.XmlOptions;
49  import org.ogf.graap.wsag.api.Agreement;
50  import org.ogf.graap.wsag.api.AgreementOffer;
51  import org.ogf.graap.wsag.api.WsagConstants;
52  import org.ogf.graap.wsag.api.exceptions.AgreementFactoryException;
53  import org.ogf.graap.wsag.api.exceptions.ResourceUnavailableException;
54  import org.ogf.graap.wsag.api.exceptions.ResourceUnknownException;
55  import org.ogf.graap.wsag.api.exceptions.WSAgreementException;
56  import org.ogf.graap.wsag.security.core.SecurityConstants;
57  import org.ogf.graap.wsag.server.api.WsagSession;
58  import org.ogf.graap.wsag.server.api.WsagSessionManager;
59  import org.ogf.graap.wsag.server.engine.WsagEngine;
60  import org.ogf.graap.wsag.server.persistence.EmfRegistry;
61  import org.ogf.graap.wsag.server.persistence.PersistentAgreementFactory;
62  import org.ogf.graap.wsag.wsrf.AgreementAcceptanceClient;
63  import org.ogf.graap.wsag.wsrf.WSAG4JCapability;
64  import org.ogf.graap.wsag.wsrf.XmlUtils;
65  import org.ogf.graap.wsag.wsrf.faults.AgreementFactoryFault;
66  import org.ogf.graap.wsag.wsrf.persistence.AgreementEprContainer;
67  import org.ogf.graap.wsag4j.types.engine.WSAG4JSessionDocument;
68  import org.ogf.graap.wsag4j.types.engine.WSAG4JSessionType;
69  import org.ogf.schemas.graap.wsAgreement.AgreementContextType;
70  import org.ogf.schemas.graap.wsAgreement.AgreementFactoryPropertiesDocument;
71  import org.ogf.schemas.graap.wsAgreement.AgreementTemplateType;
72  import org.ogf.schemas.graap.wsAgreement.AgreementType;
73  import org.ogf.schemas.graap.wsAgreement.CreateAgreementInputDocument;
74  import org.ogf.schemas.graap.wsAgreement.CreateAgreementInputType;
75  import org.ogf.schemas.graap.wsAgreement.CreateAgreementOutputType;
76  import org.ogf.schemas.graap.wsAgreement.CreateAgreementResponseDocument;
77  import org.ogf.schemas.graap.wsAgreement.CreatePendingAgreementInputDocument;
78  import org.ogf.schemas.graap.wsAgreement.CreatePendingAgreementInputType;
79  import org.ogf.schemas.graap.wsAgreement.CreatePendingAgreementOutputType;
80  import org.ogf.schemas.graap.wsAgreement.CreatePendingAgreementResponseDocument;
81  import org.ogf.schemas.graap.wsAgreement.NoncriticalExtensionType;
82  import org.ogf.schemas.graap.wsAgreement.TermTreeType;
83  import org.w3.x2005.x08.addressing.EndpointReferenceType;
84  import org.w3c.dom.Element;
85  
86  /*
87   * TODO: Persistence does not work for pending agreements. There is a change of the server API required in order to
88   * persist agreements even for pending agreement calls.
89   * 
90   * => will be done in next major release
91   */
92  
93  /**
94   * Default implementation of the agreement factory port type.
95   * 
96   * @author Oliver Waeldrich
97   * 
98   */
99  public class AgreementFactoryCapability extends WSAG4JCapability
100 {
101 
102     private static final Logger LOG = Logger.getLogger( AgreementFactoryCapability.class );
103 
104     private PersistentAgreementFactory getFactoryPersistence()
105     {
106         return ( (AgreementFactoryWsResource) getResource() ).getAgreementFactory();
107     }
108 
109     /**
110      * @return the resource property QNames
111      */
112     public QName[] getPropertyNames()
113     {
114         return WsagConstants.WSAG_AGREEMENT_FACTORY_PROPERTIES;
115     }
116 
117     /**
118      * 
119      * @return the agreement templates exposed by the factory
120      * 
121      * @throws ResourceUnknownFault
122      *             the referenced resource is unknown
123      * 
124      * @throws ResourceUnavailableFault
125      *             the referenced resource is unavailable
126      */
127     public Element[] getTemplate() throws ResourceUnknownFault, ResourceUnavailableFault
128     {
129 
130         // if the resource router is not initialized we return an empty template array
131         if ( !getResource().getResourceManager().hasBeenInitialized()
132             || getResource().getResourceManager().hasBeenShutdown() )
133         {
134             return new Element[] {};
135         }
136 
137         try
138         {
139 
140             AgreementTemplateType[] templates = getFactoryPersistence().getTemplates();
141 
142             AgreementFactoryPropertiesDocument doc = AgreementFactoryPropertiesDocument.Factory.newInstance();
143             doc.addNewAgreementFactoryProperties().setTemplateArray( templates );
144 
145             // assure that we convert xml-elements
146             return toElementArray( doc.getAgreementFactoryProperties().getTemplateArray() );
147         }
148         catch ( ResourceUnknownException e )
149         {
150             throw new ResourceUnknownFault( e );
151         }
152         catch ( ResourceUnavailableException e )
153         {
154             throw new ResourceUnavailableFault( e );
155         }
156         catch ( WSAgreementException e )
157         {
158             throw new ResourceUnavailableFault( e );
159         }
160         catch ( Exception e )
161         {
162             String message = "Illegal state in GetTemplates method. Error: " + e.getMessage();
163             LOG.error( message, e );
164 
165             throw new ResourceUnavailableFault( message, e );
166         }
167     }
168 
169     /**
170      * Creates an agreement offer for further processing from a create agreement request.
171      * 
172      * @return the new agreement offer
173      */
174     private AgreementOffer createAgreementOffer( final AgreementType offer,
175                                                  final EndpointReferenceType initiatorEPR,
176                                                  final NoncriticalExtensionType[] nce )
177     {
178 
179         return new AgreementOffer()
180         {
181 
182             private AgreementType nOffer = offer;
183 
184             private EndpointReferenceType nInitiatorEPR = initiatorEPR;
185 
186             private NoncriticalExtensionType[] nNCE = nce;
187 
188             public AgreementContextType getContext()
189             {
190                 return nOffer.getContext();
191             }
192 
193             public EndpointReferenceType getInitiatorEPR()
194             {
195                 return nInitiatorEPR;
196             }
197 
198             public String getName()
199             {
200                 return nOffer.getName();
201             }
202 
203             public NoncriticalExtensionType[] getNoncriticalExtensions()
204             {
205                 return nNCE;
206             }
207 
208             public TermTreeType getTerms()
209             {
210                 return nOffer.getTerms();
211             }
212 
213             public void setContext( AgreementContextType context )
214             {
215                 nOffer.setContext( context );
216             }
217 
218             public void setInitiatorEPR( EndpointReferenceType initiator )
219             {
220                 nInitiatorEPR = initiator;
221             }
222 
223             public void setName( String name )
224             {
225                 nOffer.setName( name );
226             }
227 
228             public void setNoncriticalExtensions( NoncriticalExtensionType[] extension )
229             {
230                 nNCE = extension;
231             }
232 
233             public void setTerms( TermTreeType terms )
234             {
235                 nOffer.setTerms( terms );
236             }
237 
238             public AgreementType getXMLObject()
239             {
240                 return nOffer;
241             }
242 
243             public String getAgreementId()
244             {
245                 return nOffer.getAgreementId();
246             }
247 
248             public void setAgreementId( String id )
249             {
250                 nOffer.setAgreementId( id );
251             }
252 
253         };
254     }
255 
256     /**
257      * Creates an agreement for an offer.
258      * 
259      * @param inputDoc
260      *            the agreement offer
261      * 
262      * @return the endpoint of the new created agreement
263      * 
264      * @throws AgreementFactoryFault
265      *             an AgreementFactoryFault indicates that the agreement offer was rejected
266      * 
267      * @throws ResourceUnknownFault
268      *             the referenced resource is unknown
269      * 
270      * @throws ResourceUnavailableFault
271      *             the referenced resource is unavailable
272      */
273     public CreateAgreementOutputType createAgreement( CreateAgreementInputDocument inputDoc )
274         throws AgreementFactoryFault, ResourceUnknownFault, ResourceUnavailableFault
275     {
276         final CreateAgreementInputType input = inputDoc.getCreateAgreementInput();
277 
278         AgreementOffer offer =
279             createAgreementOffer( input.getAgreementOffer(), input.getInitiatorAgreementEPR(),
280                                   input.getNoncriticalExtensionArray() );
281 
282         Agreement createdAgreement = null;
283 
284         try
285         {
286             createdAgreement = getFactoryPersistence().createAgreement( offer );
287 
288         }
289         catch ( AgreementFactoryException e )
290         {
291             throw new AgreementFactoryFault( e );
292         }
293         catch ( Exception e )
294         {
295             String message = "Illegal state in CreateAgreement method. Error: " + e.getMessage();
296             LOG.error( message );
297 
298             if ( LOG.isDebugEnabled() )
299             {
300                 LOG.debug( "failed to process create agreement request" );
301                 LOG.debug( inputDoc.xmlText( new XmlOptions().setSavePrettyPrint() ) );
302                 LOG.debug( e );
303             }
304 
305             throw new ResourceUnavailableFault( message, e );
306         }
307 
308         EndpointReferenceType epr = addNewAgreement( createdAgreement );
309 
310         CreateAgreementResponseDocument response = CreateAgreementResponseDocument.Factory.newInstance();
311         response.addNewCreateAgreementResponse().setCreatedAgreementEPR( epr );
312         return response.getCreateAgreementResponse();
313     }
314 
315     /**
316      * Creates an agreement for the given offer. The decision of agreement acceptance or rejection is delayed
317      * to a later time. As long the decision was not made, the returned agreement is in the PENDING state.
318      * 
319      * @param paInput
320      *            the agreement offer
321      * 
322      * @return the endpoint to the pending agreement
323      * 
324      * @throws AgreementFactoryFault
325      *             an error occurred in the agreement creation process
326      * 
327      * 
328      * @throws ResourceUnknownFault
329      *             the referenced agreement factory is unknown
330      * 
331      * @throws ResourceUnavailableFault
332      *             the referenced agreement factory is unavailable
333      */
334     public CreatePendingAgreementOutputType createPendingAgreement( CreatePendingAgreementInputDocument paInput )
335         throws AgreementFactoryFault, ResourceUnknownFault, ResourceUnavailableFault
336     {
337         final CreatePendingAgreementInputType input = paInput.getCreatePendingAgreementInput();
338 
339         AgreementOffer offer =
340             createAgreementOffer( input.getAgreementOffer(), input.getInitiatorAgreementEPR(),
341                                   input.getNoncriticalExtensionArray() );
342 
343         Agreement createdAgreement = null;
344 
345         try
346         {
347 
348             AgreementAcceptanceClient client = null;
349             EndpointReferenceType acceptanceEPR =
350                 paInput.getCreatePendingAgreementInput().getAgreementAcceptanceEPR();
351 
352             if ( acceptanceEPR != null )
353             {
354                 client =
355                     AgreementAcceptanceLocatorImpl.getAcceptanceClient( acceptanceEPR,
356                                                                         WsagEngine.getLoginContext() );
357             }
358 
359             createdAgreement = createPendingAgreementImpl( offer, client );
360         }
361         catch ( AgreementFactoryException e )
362         {
363             throw new AgreementFactoryFault( e );
364         }
365         catch ( ResourceUnknownException e )
366         {
367             throw new ResourceUnknownFault( e );
368         }
369         catch ( ResourceUnavailableException e )
370         {
371             throw new ResourceUnavailableFault( e );
372         }
373         catch ( Exception e )
374         {
375             String message = "Illegal state in CreateAgreement method. Error: " + e.getMessage();
376             LOG.error( message );
377 
378             if ( LOG.isDebugEnabled() )
379             {
380                 LOG.debug( e );
381             }
382 
383             throw new ResourceUnavailableFault( message, e );
384         }
385 
386         EndpointReferenceType epr = addNewAgreement( createdAgreement );
387 
388         CreatePendingAgreementResponseDocument response =
389             CreatePendingAgreementResponseDocument.Factory.newInstance();
390         response.addNewCreatePendingAgreementResponse().setCreatedAgreementEPR( epr );
391         return response.getCreatePendingAgreementResponse();
392     }
393 
394     /**
395      * Creates a new Agreement WS-Resource and returns the EPR.
396      * 
397      * @param agreement
398      *            the agreement to add
399      * 
400      * @return the ERP of the added agreement
401      * 
402      * @throws AgreementFactoryFault
403      *             an error occurred in the agreement creation process
404      * 
405      * 
406      * @throws ResourceUnknownFault
407      *             the referenced agreement factory is unknown
408      * 
409      * @throws ResourceUnavailableFault
410      *             the referenced agreement factory is unavailable
411      */
412     protected EndpointReferenceType addNewAgreement( Agreement agreement )
413         throws AgreementFactoryFault, ResourceUnknownFault, ResourceUnavailableFault
414     {
415         try
416         {
417             //
418             // create a new agreement WS resource
419             //
420             Resource agreementInstance = getResource().getResourceManager().createResource( "Agreement" );
421 
422             //
423             // lookup and set the WSAG4J session object
424             //
425             XmlObject[] sessionDocuments =
426                 agreement.getContext().selectChildren( WSAG4JSessionDocument.type.getDocumentElementName() );
427             if ( sessionDocuments.length > 0 )
428             {
429                 if ( sessionDocuments.length > 1 )
430                 {
431                     String message =
432                         "Found multiple wsag4j session documents in agreement context. "
433                             + "Using the first, ignoring the rest.";
434                     LOG.warn( message );
435                 }
436 
437                 WSAG4JSessionType sessionToken = (WSAG4JSessionType) sessionDocuments[0];
438 
439                 WsagSession session = WsagSessionManager.getSession( sessionToken.getSessionID() );
440                 if ( session != null )
441                 {
442                     ( (AgreementWsResource) agreementInstance ).setSession( session );
443                 }
444                 else
445                 {
446                     LOG.error( "WSAG4J session with id [" + sessionToken.getSessionID() + "] not found." );
447                 }
448             }
449 
450             //
451             // initialize the agreement WS resource object, initialize the WS resources,
452             // and add it to the resource manager
453             //
454             EndpointReference museFactoryEPR = getResource().getEndpointReference();
455             EndpointReferenceType factoryEPR = XmlUtils.convertMuseEPRToEndpoint( museFactoryEPR );
456 
457             ( (AgreementWsResource) agreementInstance ).setFactoryEPR( factoryEPR );
458             ( (AgreementWsResource) agreementInstance ).setAgreement( agreement );
459 
460             agreementInstance.initialize();
461             getResource().getResourceManager().addResource( agreementInstance.getEndpointReference(),
462                                                             agreementInstance );
463 
464             //
465             // add the new created agreement to the WSAG4J persistence layer
466             //
467             EndpointReference museAgreementEPR = agreementInstance.getEndpointReference();
468             EndpointReferenceType agreementEPR = XmlUtils.convertMuseEPRToEndpoint( museAgreementEPR );
469             // getFactoryPersistence().addAgreement(agreement, agreementEPR);
470 
471             //
472             // store the agreement <-> epr kombination
473             //
474             AgreementEprContainer agreementEprContainer = new AgreementEprContainer();
475             agreementEprContainer.setAgreementId( agreement.getAgreementId() );
476             agreementEprContainer.setEpr( agreementEPR );
477             agreementEprContainer.setAgreementFactoryId( getFactoryPersistence().getResourceId() );
478 
479             if ( LOG.isDebugEnabled() )
480             {
481                 LOG.debug( "Create a new AgreementEprContainer. Try to persist it." );
482             }
483 
484             EntityManager em = EmfRegistry.getEntityManager();
485             em.getTransaction().begin();
486 
487             try
488             {
489                 em.persist( agreementEprContainer );
490                 em.getTransaction().commit();
491             }
492             catch ( RollbackException ex )
493             {
494                 LOG.error( "Could not persist container storing the agreement id and EPR.", ex );
495                 em.getTransaction().rollback();
496             }
497             finally
498             {
499                 em.close();
500             }
501 
502             if ( LOG.isDebugEnabled() )
503             {
504                 LOG.debug( "AgreementEprContainer persisted." );
505             }
506 
507             //
508             // store the creator of the agreement instance and notify observers of change of persistent properties
509             //
510             Subject subject = (Subject) WsagEngine.getWsagMessageContext().get( SecurityConstants.AUTHENTICATED_USER );
511             ( (AgreementWsResource) agreementInstance ).setSubject( subject );
512             agreement.getAgreementInstance().notifyObservers();
513             
514             //
515             // return the EPR of the new agreement instance
516             //
517             EndpointReferenceType epr =
518                 XmlUtils.convertMuseEPRToEndpoint( agreementInstance.getEndpointReference() );
519 
520             return epr;
521         }
522         catch ( Exception ex )
523         {
524             // This should not happen, but if it does we have to throw an
525             // exception, since we can't handle this here
526             throw new IllegalStateException(
527                                              "An internal error occured while adding a new agreement. Message: "
528                                                  + ex.getMessage() );
529         }
530     }
531 
532     /**
533      * Creates a new pending agreement instance. If an acceptance EPR is provided, the initiator is notified
534      * of the result.
535      * 
536      * @param offer
537      *            the agreement offer
538      * @param acceptanceClient
539      *            the agreement acceptance client
540      * 
541      * @return the created agreement instance
542      * 
543      * @throws AgreementFactoryException
544      *             indicates that the agreement offer was rejected by the factory
545      * 
546      * @throws ResourceUnknownException
547      *             the referenced resource is unknown
548      * 
549      * @throws ResourceUnavailableException
550      *             the referenced resource is unavailable
551      */
552     protected Agreement createPendingAgreementImpl( AgreementOffer offer,
553                                                     AgreementAcceptanceClient acceptanceClient )
554         throws AgreementFactoryException, ResourceUnknownException, ResourceUnavailableException
555     {
556         PendingAgreementFacade agreement =
557             new PendingAgreementFacade( offer, getFactoryPersistence(), acceptanceClient );
558         Thread runner = new Thread( agreement );
559         runner.start();
560         return agreement;
561     }
562 
563 }