/*
* Copyright (c) 2007, Fraunhofer-Gesellschaft
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* (1) Redistributions of source code must retain the above copyright
* notice, this list of conditions and the disclaimer at the end.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* (2) Neither the name of Fraunhofer nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* DISCLAIMER
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.ogf.graap.wsag.server.engine;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlObject;
import org.ogf.graap.wsag.api.Agreement;
import org.ogf.graap.wsag.api.AgreementOffer;
import org.ogf.graap.wsag.api.Negotiation;
import org.ogf.graap.wsag.api.PendingAgreementListener;
import org.ogf.graap.wsag.api.WsagConstants;
import org.ogf.graap.wsag.api.exceptions.AgreementFactoryException;
import org.ogf.graap.wsag.api.exceptions.NegotiationFactoryException;
import org.ogf.graap.wsag.api.logging.LogMessage;
import org.ogf.graap.wsag.server.actions.ActionBuilder;
import org.ogf.graap.wsag.server.actions.impl.AgreementFactoryAction;
import org.ogf.graap.wsag.server.api.impl.AbstractAgreementFactory;
import org.ogf.graap.wsag.server.api.impl.PendingAgreementFacade;
import org.ogf.graap.wsag4j.types.configuration.ActionType;
import org.ogf.schemas.graap.wsAgreement.AgreementTemplateType;
import org.ogf.schemas.graap.wsAgreement.negotiation.NegotiationContextType;
/**
* The {@link GenericAgreementFactory} is the default implementation of an agreement factory. It support
* configuration of {@link AgreementFactoryAction}'s and automatic offer validation out of the box.
*
* @author Oliver Waeldrich
*
* @see AgreementFactoryAction
*/
public class GenericAgreementFactory extends AbstractAgreementFactory
{
private static final Logger LOG = Logger.getLogger( GenericAgreementFactory.class );
private boolean initialized = false;
private final TemplateRegistry registry = new TemplateRegistry();
private TemplateValidator validator;
/**
* Load the agreement factory actions based on the WSAG4J factory configuration. The factory configuration
* is stored in the factory context under the key {@link WsagConstants#WSAG4J_FACTORY_CONFIGURATION}.
*
* @return the actions that are configured with the factory
*
* @throws Exception
* indicates that an error occurred while loading the actions
*/
protected AgreementFactoryAction[] loadActions() throws Exception
{
//
// Populate the factory context with the factory
// configuration, so that action implementations may
// look up the factory configuration
//
getFactoryContext().put( WsagConstants.WSAG4J_FACTORY_CONFIGURATION, getEngine().getConfiguration() );
//
// initialize the actions
//
Vector<AgreementFactoryAction> actions = new Vector<AgreementFactoryAction>();
//
// for each action configuration section
//
ActionType[] actionConfig = getEngine().getConfiguration().getActionArray();
for ( int i = 0; i < actionConfig.length; i++ )
{
actionConfig[i].setName( actionConfig[i].getName() == null ? "<not specified"
: actionConfig[i].getName() );
Object[] filler =
new Object[] { new Integer( i + 1 ), new Integer( actionConfig.length ),
actionConfig[i].getName() };
String message = MessageFormat.format( "Load action {0} of {1}: {2}", filler );
LOG.info( message );
try
{
AgreementFactoryAction action =
ActionBuilder.getInstance().createAgreementFactoryAction( actionConfig[i],
getFactoryContext() );
actions.add( action );
}
catch ( Exception ex )
{
filler = new Object[] { actionConfig[i].getName(), ex.getMessage() };
message = MessageFormat.format( "Action [{0}] was not loaded. Reason {1}", filler );
LOG.error( message );
}
}
return actions.toArray( new AgreementFactoryAction[actions.size()] );
}
/**
* Initializes a {@link GenericAgreementFactory} instance based on a provided EngineConfiguration. The
* initialize method loads the engine configuration, initializes the configured actions, and populates the
* action registry.
*
* @param engine
* the WsagEngine for this factory
*/
@Override
public synchronized void doInitialize()
{
if ( initialized )
{
return;
}
try
{
if ( getEngine().getConfiguration() == null )
{
String message = "Engine configuration must not be null.";
throw new Exception( message );
}
initializeEngine();
}
catch ( Exception e )
{
Object[] filler = new Object[] { e.getMessage() };
String message = MessageFormat.format( "Failed to initialize WSAG4J engine. Error: {0}", filler );
LOG.error( message );
}
finally
{
initialized = true;
}
}
/**
* Initializes the WSAG4J engine and instantiates the configrued factory actions.
*/
private void initializeEngine()
{
AgreementFactoryAction[] actions = new AgreementFactoryAction[0];
try
{
actions = loadActions();
}
catch ( Exception ex )
{
actions = new AgreementFactoryAction[0];
Object[] filler = new Object[] { ex.getMessage() };
String msgErrorLoadActions =
"Error while loading agreement factory actions. No actions were loaded. Reason: {0}";
String message = MessageFormat.format( msgErrorLoadActions, filler );
LOG.error( message );
}
for ( int i = 0; i < actions.length; i++ )
{
try
{
LOG.debug( LogMessage.getMessage( "Initialize factory action: {0}", actions[i].getName() ) );
actions[i].setEngine( getEngine() );
actions[i].initialize();
LOG.debug( LogMessage.getMessage( "Deploy factory action: {0}", actions[i].getName() ) );
registry.add( actions[i] );
}
catch ( Exception e )
{
String message = "Error while initializing action {0}. Action was not loaded. Reason: {1}";
LOG.error( LogMessage.getMessage( message, actions[i].getName(), e.getMessage() ) );
}
}
validator = new TemplateValidator();
validator.setConfiguration( getEngine().getConfiguration().getValidator() );
}
/**
* {@inheritDoc}
*
* @see org.ogf.graap.wsag.api.AgreementFactory#createAgreement(org.ogf.graap.wsag.api.AgreementOffer)
*/
@Override
public Agreement createAgreement( AgreementOffer offer, Map<String, Object> context )
throws AgreementFactoryException
{
AgreementFactoryAction action = getActionForOffer( offer );
if ( action == null )
{
Object[] filler =
new Object[] { offer.getContext().getTemplateName(), offer.getContext().getTemplateId() };
String msgNoActionFound =
"No ICreateAgreementAction found for offer (template name [{0}] : template id [{1}])";
String message = MessageFormat.format( msgNoActionFound, filler );
throw new AgreementFactoryException( message );
}
AgreementTemplateType template = getTemplateForOffer( offer );
StringBuffer error = new StringBuffer();
if ( getValidator().validate( offer, template, error ) )
{
LOG.info( "Agreement offer successfully validated." );
Agreement agreement = action.createAgreement( offer, context );
return agreement;
}
else
{
LOG.info( "Agreement offer validation failed." );
AgreementFactoryException ex = new AgreementFactoryException( error.toString() );
String msgOfferValidationFailed =
"Agreement offer validation failed. The offer is not valid with respect to the template constraints.";
throw new AgreementFactoryException( msgOfferValidationFailed, ex );
}
}
/**
* {@inheritDoc}
*/
@Override
public Negotiation
initiateNegotiation( NegotiationContextType context, XmlObject[] criticalExtensions,
XmlObject[] nonCriticalExtensions, Map<String, Object> environment )
throws NegotiationFactoryException
{
Map<String, Object> properties = new HashMap<String, Object>();
properties.putAll( environment );
properties.put( GenericNegotiation.CRITICAL_EXTENSIONS, criticalExtensions );
properties.put( GenericNegotiation.NON_CRITICAL_EXTENSIONS, nonCriticalExtensions );
return new GenericNegotiation( this, registry, context, properties );
}
/**
* {@inheritDoc}
*
* @see org.ogf.graap.wsag.api.AgreementFactory#getTemplates()
*/
@Override
public AgreementTemplateType[] getTemplates()
{
return registry.getAllTemplates();
}
private AgreementTemplateType getTemplateForOffer( AgreementOffer offer )
{
String templateName = offer.getContext().getTemplateName();
String templateId = offer.getContext().getTemplateId();
return registry.findTemplate( templateName, templateId );
}
private AgreementFactoryAction getActionForOffer( AgreementOffer offer )
{
String templateName = offer.getContext().getTemplateName();
String templateId = offer.getContext().getTemplateId();
return registry.findAction( templateName, templateId );
}
private synchronized TemplateValidator getValidator()
{
if ( validator == null )
{
validator = new TemplateValidator();
validator.setConfiguration( getEngine().getConfiguration().getValidator() );
}
return validator;
}
/**
* The template registry stores the templates of this factory instance along with the associated
* {@link AgreementFactoryAction}.
*
* @return the template registry of this factory instance
*/
public TemplateRegistry getTemplateRegistry()
{
return registry;
}
/*
* (non-Javadoc)
*
* @see
* org.ogf.graap.wsag.api.AgreementFactory#createPendingAgreement(org.ogf.graap.wsag.api.AgreementOffer)
*/
@Override
public Agreement createPendingAgreement( AgreementOffer offer, PendingAgreementListener listener,
Map<String, Object> context ) throws AgreementFactoryException
{
PendingAgreementFacade agreement = new PendingAgreementFacade( offer, this, listener, context );
Thread runner = new Thread( agreement );
runner.start();
return agreement;
}
}