/*=============================================================================*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*=============================================================================*/
package org.apache.ws.resource.properties.v1_2.porttype.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.resource.ResourceContext;
import org.apache.ws.resource.i18n.Keys;
import org.apache.ws.resource.i18n.MessagesImpl;
import org.apache.ws.resource.properties.MetaDataViolationException;
import org.apache.ws.resource.properties.ResourceProperty;
import org.apache.ws.resource.properties.ResourcePropertyCallback;
import org.apache.ws.resource.properties.ResourcePropertyMetaData;
import org.apache.ws.resource.properties.SetResourcePropertyCallback;
import org.apache.ws.resource.properties.faults.InvalidResourcePropertyQNameFaultException;
import org.apache.ws.resource.properties.faults.InvalidSetResourcePropertiesRequestContentFaultException;
import org.apache.ws.resource.properties.faults.SetResourcePropertyRequestFailedFaultException;
import org.apache.ws.resource.properties.faults.UnableToModifyResourcePropertyFaultException;
import org.apache.ws.resource.properties.impl.AnyResourcePropertyMetaData;
import org.apache.ws.resource.properties.v1_2.porttype.SetResourcePropertiesPortType;
import org.apache.ws.util.XmlBeanUtils;
import org.apache.ws.util.i18n.Messages;
import org.apache.xmlbeans.XmlObject;
import org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSResourceProperties12Draft01.DeleteType;
import org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSResourceProperties12Draft01.InsertType;
import org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSResourceProperties12Draft01.SetResourcePropertiesDocument;
import org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSResourceProperties12Draft01.SetResourcePropertiesResponseDocument;
import org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSResourceProperties12Draft01.UpdateType;
import javax.xml.namespace.QName;
import java.util.Iterator;
/**
* LOG-DONE An operation provider for wsrp:SetResourceProperties.
*
* @author Ian P. Springer
*/
public class SetResourcePropertiesProvider
extends AbstractResourcePropertiesPortType
implements SetResourcePropertiesPortType
{
private static final Log LOG = LogFactory.getLog( SetResourcePropertiesProvider.class );
private static final Messages MSG = MessagesImpl.getInstance();
/**
* Creates a new {@link SetResourcePropertiesProvider} object.
*
* @param resourceContext DOCUMENT_ME
*/
public SetResourcePropertiesProvider( ResourceContext resourceContext )
{
super( resourceContext );
}
/**
* Implementation of the wsrp:SetResourceProperties operation.
*
* @param requestDoc the requestDoc XMLBean
*
* @return the response XMLBean
*
* @throws org.apache.ws.resource.properties.faults.InvalidResourcePropertyQNameFaultException
*
* @throws org.apache.ws.resource.faults.ResoureKeyHeaderNotFoundFaultException
*
*/
public SetResourcePropertiesResponseDocument setResourceProperties( SetResourcePropertiesDocument requestDoc )
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( MSG.getMessage( Keys.SET_RP_REQ,
requestDoc.toString() ) );
}
SetResourcePropertiesResponseDocument responseDoc = createResponseDocument();
SetResourcePropertiesDocument.SetResourceProperties requestElem = requestDoc.getSetResourceProperties();
InsertType[] insertElems = requestElem.getInsertArray();
for ( int i = 0; i < insertElems.length; i++ )
{
insertResourceProperty( insertElems[i] );
}
DeleteType[] deleteElems = requestElem.getDeleteArray();
for ( int i = 0; i < deleteElems.length; i++ )
{
deleteResourceProperty( deleteElems[i] );
}
UpdateType[] updateElems = requestElem.getUpdateArray();
for ( int i = 0; i < updateElems.length; i++ )
{
updateResourceProperty( updateElems[i] );
}
return responseDoc;
}
/**
* DOCUMENT_ME
*
* @param deleteElem DOCUMENT_ME
*/
protected void deleteResourceProperty( DeleteType deleteElem )
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( MSG.getMessage( Keys.DEL_RP_REQ,
deleteElem.toString() ) );
}
QName nameOfPropToBeDeleted = deleteElem.getResourceProperty();
if ( nameOfPropToBeDeleted == null )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( MSG.getMessage( Keys.DEL_MISSING_RP_ATTRIB ) );
}
ResourceProperty prop = getProperties().get( nameOfPropToBeDeleted );
if ( prop == null )
{
if ( getProperties().getMetaData().isOpenContent() )
{
return;
} else
{
throw new InvalidResourcePropertyQNameFaultException( nameOfPropToBeDeleted );
}
}
throwFaultIfPropertyIsReadOnly( prop );
throwFaultIfDeletionViolatesSchema( prop );
try
{
deletePropertyCallback( prop );
}
catch ( RuntimeException re )
{
throw new SetResourcePropertyRequestFailedFaultException( re.toString() );
}
Object[] oldValue = getValue( prop );
prop.clear();
Object[] newValue = null;
if ( prop.getChangeListener() != null )
{
firePropChangeEvent( prop, oldValue, newValue );
}
}
/**
* DOCUMENT_ME
*
* @param insertElem DOCUMENT_ME
*/
protected void insertResourceProperty( InsertType insertElem )
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( MSG.getMessage( Keys.INSERT_RP_REQ,
insertElem.toString() ) );
}
XmlObject[] propElemsToBeInserted = XmlBeanUtils.getChildElements( insertElem );
if ( propElemsToBeInserted.length == 0 )
{
return; // nothing to do
}
throwFaultIfElementNamesHeterogenous( propElemsToBeInserted );
QName propName = XmlBeanUtils.getName( propElemsToBeInserted[0] );
ResourceProperty prop = getProperty( propName );
if(prop == null)
{
prop = createAnyProperty(propName);
getProperties().add(prop);
}
if(!prop.getMetaData().isAny())
{
//todo probably need to check this for xsd:any to check for possible violations
//refreshProperty( prop );
throwFaultIfInsertionViolatesSchema( prop, propElemsToBeInserted );
}
throwFaultIfPropertyIsReadOnly( prop );
try
{
insertPropertyCallback( prop, propElemsToBeInserted );
}
catch ( RuntimeException re )
{
throw new SetResourcePropertyRequestFailedFaultException( re.toString() );
}
Object[] oldValue = getValue( prop );
for ( int i = 0; i < propElemsToBeInserted.length; i++ )
{
try
{
prop.add( propElemsToBeInserted[i] );
}
catch ( MetaDataViolationException mdve )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( mdve );
}
}
Object[] newValue = getValue( prop );
if ( prop.getChangeListener() != null )
{
firePropChangeEvent( prop, oldValue, newValue );
}
}
private void firePropChangeEvent( ResourceProperty prop, Object[] oldValue, Object[] newValue )
{
prop.getChangeListener().propertyChanged( new XmlBeansResourcePropertyValueChangeEvent( oldValue, newValue ) );
}
/**
* DOCUMENT_ME
*
* @param updateElem DOCUMENT_ME
*/
protected void updateResourceProperty( UpdateType updateElem )
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( MSG.getMessage( Keys.UPDATE_RP_REQ,
updateElem.toString() ) );
}
XmlObject[] newPropElems = XmlBeanUtils.getChildElements( updateElem );
if ( newPropElems.length == 0 )
{
return; // nothing to do
}
QName propName = XmlBeanUtils.getName( newPropElems[0] );
ResourceProperty prop = getProperty( propName );
throwFaultIfPropertyIsReadOnly( prop );
throwFaultIfElementNamesHeterogenous( newPropElems );
throwFaultIfUpdateViolatesSchema( prop, newPropElems );
try
{
updatePropertyCallback( prop, newPropElems );
}
catch ( RuntimeException re )
{
throw new SetResourcePropertyRequestFailedFaultException( re.toString() );
}
Object[] oldValue = getValue( prop );
// TODO: we might need to clone the oldValue elems, since we might be destroying them when we call clear() below
try
{
prop.clear();
for ( int i = 0; i < newPropElems.length; i++ )
{
prop.add( newPropElems[i] );
}
}
catch ( MetaDataViolationException mdve )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( mdve );
}
Object[] newValue = getValue( prop );
if ( prop.getChangeListener() != null )
{
firePropChangeEvent( prop, oldValue, newValue );
}
}
private ResourceProperty createAnyProperty(QName propName)
{
ResourcePropertyMetaData propMetaData = new AnyResourcePropertyMetaData( propName );
return propMetaData.create( getProperties() );
}
private Object[] getValue( ResourceProperty prop )
{
Object[] value = new Object[prop.size()];
Iterator propElemIter = prop.iterator();
int i = 0;
while ( propElemIter.hasNext() )
{
value[i++] = propElemIter.next();
}
return value;
}
private ResourceProperty getProperty( QName propName )
{
LOG.debug( MSG.getMessage( Keys.GET_RP_WITH_NAME,
propName.toString() ) );
ResourceProperty prop = getProperties().get( propName );
if ( prop == null )
{
if ( !getProperties().getMetaData().isOpenContent() )
{
throw new InvalidResourcePropertyQNameFaultException( propName );
}
}
return prop;
}
private void throwFaultIfElementNamesHeterogenous( XmlObject[] propElems )
{
QName firstPropElemName = XmlBeanUtils.getName( propElems[0] );
for ( int i = 1; i < propElems.length; i++ )
{
QName propElemName = XmlBeanUtils.getName( propElems[i] );
if ( !firstPropElemName.equals( propElemName ) )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( MSG.getMessage( Keys.ERROR_PROPERTY_INSERT_VIOLATES_SCHEMA,
( ( propElems.length > 1 )
? "s" : "" ),
firstPropElemName ) );
}
}
}
private void throwFaultIfDeletionViolatesSchema( ResourceProperty prop )
{
if ( prop.getMetaData().getMinOccurs() != 0 )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( MSG.getMessage( Keys.ERROR_PROPERTY_DELETE_VIOLATES_SCHEMA,
prop.getMetaData().getName() ) );
}
}
private void throwFaultIfInsertionViolatesSchema( ResourceProperty prop, XmlObject[] propElemsToBeInserted )
{
//todo probably need to check this for xsd:any to check for possible violations
if ( prop.getMetaData().getMaxOccurs() != -1 &&( prop.size() + propElemsToBeInserted.length ) > prop.getMetaData().getMaxOccurs() )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( MSG.getMessage( Keys.ERROR_PROPERTY_INSERT_VIOLATES_SCHEMA,
( ( propElemsToBeInserted.length > 1 )
? "s" : "" ),
prop.getMetaData().getName() ) );
}
}
private void throwFaultIfUpdateViolatesSchema( ResourceProperty prop, XmlObject[] newPropElems )
{
if ( prop.getMetaData().getMaxOccurs() != -1 && newPropElems.length > prop.getMetaData().getMaxOccurs() )
{
throw new InvalidSetResourcePropertiesRequestContentFaultException( MSG.getMessage( Keys.ERROR_PROPERTY_UPDATE_VIOLATES_SCHEMA,
prop.getMetaData().getName() ) );
}
}
/**
* Returns SetResourcePropertyCallback or null
*
* @param prop
*
* @return SetResourcePropertyCallback or null
*/
private SetResourcePropertyCallback getSetResourcePropertyCallback( ResourceProperty prop )
{
SetResourcePropertyCallback setResourcePropertyCallback = null;
ResourcePropertyCallback callBack = prop.getCallBack();
if ( callBack instanceof SetResourcePropertyCallback )
{
setResourcePropertyCallback = (SetResourcePropertyCallback) callBack;
}
return setResourcePropertyCallback;
}
private SetResourcePropertiesResponseDocument createResponseDocument()
{
SetResourcePropertiesResponseDocument responseDoc =
SetResourcePropertiesResponseDocument.Factory.newInstance();
responseDoc.addNewSetResourcePropertiesResponse();
return responseDoc;
}
private void deletePropertyCallback( ResourceProperty prop )
{
QName nameOfPropToBeDeleted = prop.getMetaData().getName();
SetResourcePropertyCallback setResourcePropertyCallback = getSetResourcePropertyCallback( prop );
if ( setResourcePropertyCallback != null )
{
setResourcePropertyCallback.deleteProperty( nameOfPropToBeDeleted );
}
}
private void insertPropertyCallback( ResourceProperty prop,
XmlObject[] propElemsToBeInserted )
{
SetResourcePropertyCallback setResourcePropertyCallback = getSetResourcePropertyCallback( prop );
if ( setResourcePropertyCallback != null )
{
setResourcePropertyCallback.insertProperty( propElemsToBeInserted );
}
}
private void throwFaultIfPropertyIsReadOnly( ResourceProperty prop )
{
if ( prop.getMetaData().isReadOnly() )
{
throw new UnableToModifyResourcePropertyFaultException( prop.getMetaData().getName() );
}
}
private void updatePropertyCallback( ResourceProperty prop,
XmlObject[] newPropElems )
{
SetResourcePropertyCallback setResourcePropertyCallback = getSetResourcePropertyCallback( prop );
if ( setResourcePropertyCallback != null )
{
setResourcePropertyCallback.updateProperty( newPropElems );
}
}
}