/*=============================================================================*
* 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.impl;
import org.apache.commons.lang.SerializationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.ResourcePropertyMetaData;
import org.apache.ws.resource.properties.ResourcePropertySet;
import org.apache.ws.resource.properties.ResourcePropertySetMetaData;
import org.apache.ws.util.XmlBeanNameUtils;
import org.apache.ws.util.XmlBeanUtils;
import org.apache.ws.util.i18n.Messages;
import org.apache.xmlbeans.SchemaProperty;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* An Apache XMLBeans-based implementation of a resource property set.
*
* @author Ian P. Springer
*/
public class XmlBeansResourcePropertySet
implements ResourcePropertySet
{
private static final Log LOG = LogFactory.getLog( XmlBeansResourcePropertySet.class );
private static final Messages MSG = MessagesImpl.getInstance();
private XmlObject m_propsDocXBean;
private XmlObject m_propsXBean;
private Map m_propsMap = new HashMap();
private ResourcePropertySetMetaData m_metaData;
/**
* Creates a new {@link XmlBeansResourcePropertySet} object.
*
* @param propsDocXBean DOCUMENT_ME
*/
public XmlBeansResourcePropertySet( XmlObject propsDocXBean )
throws MetaDataViolationException
{
this( propsDocXBean, new XmlBeansResourcePropertySetMetaData( propsDocXBean.schemaType() ) );
}
/**
* Creates a new {@link XmlBeansResourcePropertySet} object.
*
* @param propsDocXBean DOCUMENT_ME
* @param metaData metadata describing this property set
*/
public XmlBeansResourcePropertySet( XmlObject propsDocXBean, ResourcePropertySetMetaData metaData )
throws MetaDataViolationException
{
if ( !XmlBeanUtils.isDocument( propsDocXBean ) )
{
throw new IllegalArgumentException(
MSG.getMessage( Keys.XMLOBJECT_DOC, propsDocXBean.getClass().getName() ) );
}
m_propsDocXBean = propsDocXBean;
m_propsXBean = getPropsDocRootElem();
m_metaData = metaData;
initProperties( metaData );
}
/**
* Gets the XmlBean Java classname representing the resource property document.
*
* @param resourcePropsDocElemQName the QName of the resource property document
*
* @return XmlBean classname that represents the resource property document
*/
protected String getPropsDocClassName( QName resourcePropsDocElemQName )
{
String resourcePropertiesClassName =
XmlBeanNameUtils.getElementXmlBeanClassName( resourcePropsDocElemQName );
if ( resourcePropertiesClassName == null )
{
throw new NoClassDefFoundError( "Could not determine name of the Resource Properties Document XML Bean class for document element: "
+ resourcePropsDocElemQName );
}
return resourcePropertiesClassName;
}
/**
* @return
*/
public boolean isEmpty()
{
return m_propsMap.isEmpty();
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public ResourcePropertySetMetaData getMetaData()
{
return m_metaData;
}
/**
* DOCUMENT_ME
*
* @param prop DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public boolean add( ResourceProperty prop )
throws MetaDataViolationException
{
if ( !m_metaData.isOpenContent() )
{
throw new MetaDataViolationException( MSG.getMessage( Keys.NON_ANY_PROP_CANNOT_BE_REMOVED ) );
}
if ( m_propsMap.containsKey( prop.getMetaData().getName() ) )
{
throw new MetaDataViolationException(
MSG.getMessage( Keys.PROP_DOC_ALREADY_CONTAINS_PROPERTY, prop.getMetaData().getName() ) );
}
addProperty( prop );
return true;
}
/**
* @throws MetaDataViolationException
*/
public void clear()
throws MetaDataViolationException
{
LOG.debug( MSG.getMessage( Keys.CLEAR_PROP_SET ) );
Collection props = m_propsMap.values();
for ( Iterator iterator = props.iterator(); iterator.hasNext(); )
{
ResourceProperty prop = (ResourceProperty) iterator.next();
prop.clear();
m_propsMap.remove( prop.getMetaData().getName() );
}
}
/**
* A factory method for creating
*
* @param metaData
*
* @return ResourceProperty
*/
public ResourceProperty create( ResourcePropertyMetaData metaData )
{
return new XmlBeansResourceProperty( metaData, this );
}
/**
* DOCUMENT_ME
*
* @param propName DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public ResourceProperty get( QName propName )
{
return (ResourceProperty) m_propsMap.get( propName );
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Iterator iterator()
{
return m_propsMap.values().iterator();
}
/**
* DOCUMENT_ME
*
* @param propName DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public boolean remove( QName propName )
throws MetaDataViolationException
{
if ( !m_metaData.isOpenContent() )
{
throw new MetaDataViolationException( MSG.getMessage( Keys.NON_ANY_PROP_CANNOT_BE_REMOVED ) );
}
LOG.debug( MSG.getMessage( Keys.REMOVING_PROP, propName.toString() ) );
ResourceProperty resourceProp = (ResourceProperty) m_propsMap.get( propName );
resourceProp.clear();
m_propsMap.remove( propName );
return true;
}
/**
* Forces the removal/addition of a ResourceProperty...This will not check with the schema and is intended
* to be used when the user intends to "replace" the internal ResourceProperty with something else.
*
* @param prop The ResourceProperty which will be overwritten
* @return true
*/
public boolean set(ResourceProperty prop)
{
QName propName = prop.getMetaData().getName();
LOG.debug( MSG.getMessage( Keys.REMOVING_PROP, propName.toString() ) );
ResourceProperty resourceProp = (ResourceProperty) m_propsMap.get( propName );
resourceProp.clear();
m_propsMap.remove( propName );
addProperty( prop );
return true;
}
/**
* @return
*/
public int size()
{
return m_propsMap.size();
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*
* @throws SerializationException DOCUMENT_ME
*/
public Element toElement()
throws SerializationException
{
// TODO: shouldn't this method return a Document instead of an Element?
Document doc = (Document) m_propsDocXBean.newDomNode();
return doc.getDocumentElement();
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*
* @throws SerializationException DOCUMENT_ME
*/
public SOAPElement toSOAPElement()
throws SerializationException
{
try
{
return XmlBeanUtils.toSOAPElement( m_propsXBean );
}
catch ( Exception e )
{
throw new SerializationException( e );
}
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public String toString()
{
return toXML();
}
/**
* @return
*/
public String toXML()
{
return m_propsDocXBean.xmlText( new XmlOptions().setSavePrettyPrint() );
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public XmlObject toXmlObject()
{
return m_propsDocXBean;
}
private ResourceProperty addProperty( ResourceProperty prop )
{
Iterator iter = prop.iterator();
while ( iter.hasNext() )
{
XmlObject propElemXBean = (XmlObject) iter.next();
XmlBeanUtils.addChildElement( m_propsDocXBean, propElemXBean );
}
addPropertyToMap( prop );
return prop;
}
private void addPropertyToMap( ResourceProperty resourceProp )
{
QName name = resourceProp.getMetaData().getName();
LOG.debug( MSG.getMessage( Keys.ADDING_PROP, name.toString() ) );
m_propsMap.put( name,
resourceProp );
}
private XmlBeansResourceProperty createProperty( SchemaProperty elemSchemaProp,
boolean isReadOnly )
{
return new XmlBeansResourceProperty( new XmlBeansResourcePropertyMetaData( elemSchemaProp, isReadOnly ),
this );
}
private void initProperties( ResourcePropertySetMetaData setMetaData )
throws MetaDataViolationException
{
SchemaProperty[] propElemDefs = m_propsXBean.schemaType().getElementProperties();
for ( int i = 0; i < propElemDefs.length; i++ )
{
XmlBeansResourceProperty prop = createProperty( propElemDefs[i],
setMetaData.getPropertyMetaData( propElemDefs[i].getName() ).isReadOnly() );
populateProperty( prop );
addPropertyToMap( prop );
}
}
private void populateProperty( XmlBeansResourceProperty prop )
throws MetaDataViolationException
{
XmlObject[] propXBeans = XmlBeanUtils.getChildElements( m_propsXBean,
prop.getMetaData().getName() );
for ( int j = 0; j < propXBeans.length; j++ )
{
prop.load( propXBeans[j] );
}
}
private XmlObject getPropsDocRootElem()
{
XmlObject propsXBean = XmlBeanUtils.getRootElement( m_propsDocXBean );
if ( propsXBean == null )
{
// user did not initialize the props doc root element, so do it for them...
String propsElemJavaPropName = m_propsDocXBean.schemaType().getElementProperties()[0].getJavaPropertyName();
try
{
Method addNewMethod = m_propsDocXBean.getClass().getMethod( "addNew" + propsElemJavaPropName,
new Class[0] );
propsXBean = (XmlObject) addNewMethod.invoke( m_propsDocXBean, new Object[0] );
}
catch ( Exception e )
{
e.printStackTrace();
throw new RuntimeException( e );
}
}
return propsXBean;
}
}