You are viewing a plain text version of this content. The canonical link for it is here.
Posted to muse-commits@ws.apache.org by da...@apache.org on 2006/06/12 18:12:21 UTC

svn commit: r413698 [4/7] - in /webservices/muse/trunk/modules/muse-wsrf: specs/ src/org/apache/muse/ws/resource/ src/org/apache/muse/ws/resource/basefaults/ src/org/apache/muse/ws/resource/ext/ src/org/apache/muse/ws/resource/ext/faults/ src/org/apach...

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/GetResponse.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/GetResponse.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/GetResponse.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/GetResponse.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,126 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.get.impl;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.apache.muse.util.messages.Messages;
+import org.apache.muse.util.messages.MessagesFactory;
+import org.apache.muse.ws.resource.properties.WsrpConstants;
+import org.apache.muse.util.xml.XmlSerializable;
+import org.apache.muse.util.xml.XmlUtils;
+
+/**
+ *
+ * GetResponse is a serializer/deserializer for the WS-ResourceProperties 
+ * GetResourceProperty operation's response content.
+ *
+ * @author Dan Jemiolo (danj)
+ *
+ */
+
+public class GetResponse implements XmlSerializable
+{
+    //
+    // Used to lookup all exception messages
+    //
+    private static Messages _MESSAGES = MessagesFactory.get(GetResponse.class);
+    
+    //
+    // The property instances retrieved for a GetResourceProperty request. 
+    // This may be empty.
+    //
+    private Element[] _properties = null;
+    
+    public GetResponse()
+    {
+        this(new Element[]{});
+    }
+    
+    public GetResponse(Element property)
+    {
+        this(new Element[]{ property });
+    }
+    
+    public GetResponse(Element[] properties)
+    {
+        if (properties == null)
+            throw new NullPointerException(_MESSAGES.get("NullElementArray"));
+        
+        for (int n = 0; n < properties.length; ++n)
+        {
+            if (properties[n] == null)
+            {
+                Object[] filler = { new Integer(n) };
+                throw new NullPointerException(_MESSAGES.get("NullPropertyN", filler));
+            }
+        }
+        
+        _properties = properties;
+    }
+
+    
+    public Element[] getProperties()
+    {
+        return _properties;
+    }
+    
+    public Element getProperty(int index)
+    {
+        return _properties[index];
+    }
+    
+    public QName getPropertyName()
+    {
+        return XmlUtils.getElementQName(_properties[0]);
+    }
+    
+    public boolean isEmpty()
+    {
+        return _properties.length == 0;
+    }
+    
+    public String toString()
+    {
+        return XmlUtils.toString(toXML(), false);
+    }
+    
+    public Element toXML()
+    {
+        return toXML(XmlUtils.EMPTY_DOC);
+    }
+    
+    public Element toXML(Document doc)
+    {
+        if (doc == null)
+            throw new NullPointerException(_MESSAGES.get("NullDocument"));
+        
+        Element root = XmlUtils.createElement(doc, WsrpConstants.GET_RESPONSE_QNAME);
+        
+        for (int n = 0; n < _properties.length; ++n)
+        {
+            Node property = doc.importNode(_properties[n], true);
+            root.appendChild(property);
+        }
+        
+        return root;
+    }
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/Messages.properties
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/Messages.properties?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/Messages.properties (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/Messages.properties Mon Jun 12 09:12:15 2006
@@ -0,0 +1,10 @@
+NullQName = The QName reference is null.
+NullQNameArray = The array of QNames is null.
+NullQNameN = In the array of QNames, reference #XXX is null.
+NullDocument = The XML document needed to build the XML fragment is null.
+NullRequestElement = The DOM Element with the request's SOAP body is null.
+NoPropertiesInGet = The GetMultipleResourceProperties request did not contain any ResourceProperty elements. The request must specify at least one property name.
+NullPropertyN = The ResourceProperty element #XXX (inside the GetMultipleResourceProperties element) has a null QName value.
+NullElementArray = The Element array holding the property instances is null.
+NullInstanceN = In the array of Elements, reference #XXX is null.
+NullGetProperty = The property QName in the GetResourceProperty request is null.

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/SimpleGetCapability.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/SimpleGetCapability.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/SimpleGetCapability.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/get/impl/SimpleGetCapability.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,97 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.get.impl;
+
+import java.lang.reflect.Method;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+
+import org.apache.muse.core.routing.MessageHandler;
+import org.apache.muse.util.ReflectUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+import org.apache.muse.ws.resource.impl.AbstractWsResourceCapability;
+import org.apache.muse.ws.resource.properties.ResourcePropertyCollection;
+import org.apache.muse.ws.resource.properties.get.GetCapability;
+import org.apache.muse.ws.resource.properties.get.faults.InvalidResourcePropertyQNameFault;
+
+public class SimpleGetCapability 
+    extends AbstractWsResourceCapability implements GetCapability
+{
+    protected MessageHandler createGetHandler()
+    {
+        MessageHandler handler = new GetHandler();
+        
+        Method method = ReflectUtils.getFirstMethod(getClass(), "getResourceProperty");
+        handler.setMethod(method);
+        
+        return handler;
+    }
+    
+    protected MessageHandler createGetDocumentHandler()
+    {
+        MessageHandler handler = new GetDocumentHandler();
+        
+        Method method = ReflectUtils.getFirstMethod(getClass(), "getResourcePropertyDocument");
+        handler.setMethod(method);
+        
+        return handler;
+    }
+    
+    protected MessageHandler createGetMultipleHandler()
+    {
+        MessageHandler handler = new GetMultipleHandler();
+        
+        Method method = ReflectUtils.getFirstMethod(getClass(), "getMultipleResourceProperties");
+        handler.setMethod(method);
+        
+        return handler;
+    }
+    
+    public Element[] getMultipleResourceProperties(QName[] qnames)
+        throws InvalidResourcePropertyQNameFault, BaseFault
+    {
+        ResourcePropertyCollection props = getWsResource().getPropertyCollection();
+        return props.getMultipleResourceProperties(qnames);
+    }
+
+    public Element[] getResourceProperty(QName qname) 
+        throws InvalidResourcePropertyQNameFault, BaseFault
+    {
+        ResourcePropertyCollection props = getWsResource().getPropertyCollection();
+        return props.getResourceProperty(qname);
+    }
+
+    public Element getResourcePropertyDocument() 
+        throws BaseFault
+    {
+        ResourcePropertyCollection props = getWsResource().getPropertyCollection();
+        return props.getResourcePropertyDocument();
+    }
+    
+    public void initialize() 
+        throws SoapFault
+    {
+        super.initialize();
+        
+        setMessageHandler(createGetHandler());
+        setMessageHandler(createGetDocumentHandler());
+        setMessageHandler(createGetMultipleHandler());
+    }
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/Messages.properties
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/Messages.properties?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/Messages.properties (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/Messages.properties Mon Jun 12 09:12:15 2006
@@ -0,0 +1,45 @@
+NullWSDLDocument = The WSDL Document reference is null.
+NoPortTypesFound = There are no portType definitions in the touchpoint's WSDL. The WSDL must have one portType that defines the touchpoint's interface and includes attribute links to its WS-RP and WS-RMD documents.
+NoPropertiesAttribute = The WSDL portType that defines the touchpoint's interface does not have a wsrp:ResourceProperties attribute. This attribute is needed to find the WS-ResourceProperties definition in the WSDL's types section. The attribute value should be a QName that maps to one of the type definitions in the WSDL.
+NullQName = The QName reference is null.
+NullQNameArray = The QName array is null.
+NullTopic = The Topic reference is null.
+NullPropertyElement = The DOM Element with the WS-RP property definition is null.
+NullPropertiesElement = The DOM Element with the WS-ResourceProperties definition is null.
+NotAnElement = The DOM Element with the WS-ResourceProperties definition is not an xsd:element. A WS-RP definition must be an xsd:element.
+NoPropertiesName = The WS-ResourceProperties element has no name attribute. What is the name of the properties document?
+NoTypeDeclaration = The property 'XXX' has no definition in the WSDL's types section. A common error is that the property's QName has an invalid namespace URI.
+PropertyNotFound = The schema has no property with the name 'XXX'. Use the hasProperty method to determine if a property exists.
+NullDocument = The DOM Document is null.
+NullPCA = The PropertyChangeApprover is null.
+NullPCL = The PropertyChangeListener is null.
+NullPRL = The PropertyReadListener is null.
+QueryNotProperty = The query 'XXX' does not resolve to a property element. Deletion via query string can only be done if the query maps to complete property instances in the DOM; that is, all results must be child elements of the document's root node. Appropriate queries include '/*/MyName', '/*/MyName[@attr]', etc.
+EmptyDocument = The DOM Document that represents the WS-RP document is empty. The Document must be a valid XML document, which means it must have at least a root node.
+NullValuesArray = The array of property values is null. If you want to set properties to null, you still need a valid array - just add null value(s) to it.
+EmptyValuesArray = The array of property values is null. If you want to set properties to null, you still need a non-empty array - just add null value(s) to it.
+NullQuery = The query string is null. What are we looking for?
+NullDialect = The dialect is null. The only dialect supported by this implementation is XPath 1.0 (see XPathUtils for the full XPath 1.0 URI).
+NullMetadataDescriptor = The MetadataDescriptor is null.
+NullSchema = The ResourcePropertiesSchema is null. The properties document must have a schema, even if it has no constraints. If you want to place no schema constraints on your properties, you can rely on the default schema, which is an instance of OpenPropertiesSchema.
+EmptySetRequest = The SetResourceProperties request has no concrete set operations (Insert/Update/Delete). Each SetRequest must have at least one operation.
+BelowMinimumPotential = The property 'XXX' has a minOccurs value of XXX. If the deletion were performed, there would only be XXX instances of the property left, which is below the minimum.
+AboveMaximumPotential = The property 'XXX' has a maxOccurs value of XXX. If the insertion were performed, there would be XXX instances of the property left, which is above the maximum.
+BelowMinimum = The property 'XXX' has a minOccurs value of XXX, but there are only XXX instances in the document.
+AboveMaximum = The property 'XXX' has a maxOccurs value of XXX, but there are XXX instances in the document.
+NotNillable = The property 'XXX' is not nillable, but there is an instance of it with no child nodes (a null value).
+NoMetadata = The WS-RP collection has no metadata descriptor - you must set the metadata with setMetadata() before you can try to validate the properties. Use the EmptyMetadataDescriptor class if you want to avoid making metadata restrictions.
+NoSchema = The WS-RP collection has no XML Schema definition - you must set the schema with setSchema() before you can try to validate the properties. Use the OpenPropertiesSchema class if you want to avoid making schema restrictions.
+NullNLF = The NotificationListenerFactory is null.
+NoNLF = You are trying to create WS-N Topics for the resource properties, but no NotificationListenerFactory has been provided for the WS-RP container. You must call setNotificationListenerFactory() before you can create Topics (and accept subscriptions) for the resource properties.
+NullTopicPath = The Topic path expression is null.
+NoNotificationElement = The WS-N NotificationMessage does not have any message content in Element form. Property change notifications should be represented by (at the very least) a wsrp:ResourcePropertyValueChangeNotification element under the wsn:Message.
+InvalidNotification = The property change subscriber failed to parse the WS-N NotificationMessage. It found the element 'XXX' when looking for 'XXX'. Make sure the WS-RP change notifications are formatted according to the WS-RP spec.
+PropertyNotInSchema = There is no property named 'XXX' defined in the schema. A property should not have any operations or metadata applied to it if it is not in the WS-RP document.
+InvalidValue = The property 'XXX' has a value that is not valid according to its metadata. The invalid value is: XXX
+DeletingStaticValue = Could not delete a value for the property 'XXX' because it is static. The static value was: XXX
+NoExternalChanges = The metadata for property 'XXX' allows it to be changed, but not by other services. You cannot modify the value of this property via WS-RP SetResourceProperties.
+InsertOnly = The metadata for property 'XXX' only allows it to be inserted ('appended'), not updated or deleted.
+ReadOnly = The metadata for property 'XXX' makes it read-only. It cannot be modified in any way via WS-RP SetResourceProperties.
+NoInstancesToDelete = There are no instances of the property 'XXX', so it cannot be deleted.
+NoCapabilityForProperty = There is no capability that defines the property XXX. If you have a capability that is supposed to define this property, make sure the name is returned as part of WsResourceCapability.getPropertyNames().

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/SimpleResourcePropertyCollection.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/SimpleResourcePropertyCollection.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/SimpleResourcePropertyCollection.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/SimpleResourcePropertyCollection.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,1103 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.muse.util.MultiMap;
+import org.apache.muse.util.messages.Messages;
+import org.apache.muse.util.messages.MessagesFactory;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.WsResourceCapability;
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+import org.apache.muse.ws.resource.metadata.MetadataDescriptor;
+import org.apache.muse.ws.resource.metadata.faults.MetadataValidationErrorFault;
+import org.apache.muse.ws.resource.metadata.impl.ExternalChangeApprover;
+import org.apache.muse.ws.resource.metadata.impl.InsertOnlyApprover;
+import org.apache.muse.ws.resource.metadata.impl.ReadOnlyApprover;
+import org.apache.muse.ws.resource.metadata.impl.StaticValuesApprover;
+import org.apache.muse.ws.resource.metadata.impl.ValidValuesApprover;
+import org.apache.muse.ws.resource.properties.ResourcePropertyCollection;
+import org.apache.muse.ws.resource.properties.WsrpConstants;
+import org.apache.muse.ws.resource.properties.get.faults.InvalidResourcePropertyQNameFault;
+import org.apache.muse.ws.resource.properties.listeners.PropertyChangeApprover;
+import org.apache.muse.ws.resource.properties.listeners.PropertyChangeListener;
+import org.apache.muse.ws.resource.properties.listeners.PropertyReadListener;
+import org.apache.muse.ws.resource.properties.schema.ResourcePropertiesSchema;
+import org.apache.muse.ws.resource.properties.schema.faults.SchemaValidationErrorFault;
+import org.apache.muse.ws.resource.properties.set.SetRequest;
+import org.apache.muse.ws.resource.properties.set.SetRequestComponent;
+import org.apache.muse.ws.resource.properties.set.faults.UnableToModifyResourcePropertyFault;
+import org.apache.muse.ws.resource.properties.set.impl.InsertRequest;
+import org.apache.muse.ws.resource.properties.set.impl.UpdateRequest;
+
+/**
+ *
+ * SimpleResourcePropertyCollection is an abstract class that provides a 
+ * generic listener and validation framework for a WS-RP implemenation. 
+ * Concrete subclasses of this class must provide the actual data model 
+ * of the WS-RP document, but as long as they can provide property instances 
+ * as XML fragments for evaluation (already required in order to service 
+ * external requests), they can rely on the methods of this class to enforce 
+ * their schema and metadata and fire any user-defined listeners.
+ * <br><br>
+ * As part of the notification and validation framework, this class also 
+ * provides the WS-Topics integration needed for publishing changes to 
+ * properties. Users should leverage the protected addTopic(QName), 
+ * hasTopic(QName), and removeTopic(QName) to make sure WS-N subscriptions 
+ * are handled correctly.
+ *
+ * @author Dan Jemiolo (danj)
+ *
+ */
+
+public class SimpleResourcePropertyCollection implements ResourcePropertyCollection
+{
+    //
+    // Used to lookup all exception messages
+    //
+    private static Messages _MESSAGES = 
+        MessagesFactory.get(SimpleResourcePropertyCollection.class);
+    
+    //
+    // All PropertyChangeApprovers by property name
+    //
+    private MultiMap _approversByQName = new MultiMap();
+    
+    //
+    // All PropertyChangeListeners by property name
+    //
+    private MultiMap _listenersByQName = new MultiMap();
+    
+    //
+    // The RMD file that holds the metadata for these properties.
+    //
+    private MetadataDescriptor _metadata = null;
+    
+    //
+    // All PropertyReadListeners by property name
+    //
+    private MultiMap _readersByQName = new MultiMap();
+    
+    //
+    // The schema that describes the property types and their constraints.
+    //
+    private ResourcePropertiesSchema _schema = null;
+    
+    //
+    // The security token allows other components in the touchpoint to 
+    // modify read-only properties that are not accessible by clients. 
+    // Properties that are read-only may still be mutable (or appendable), 
+    // which means that they may change, but cannot be explicitly modified 
+    // by touchpoint consumers.
+    //
+    // Our security token is just a unique reference (which cannot be 
+    // duplicated within the JVM).
+    //
+    private Object _securityToken = new Object();
+    
+    public synchronized void addCapability(WsResourceCapability capability)
+    {
+        QName[] names = capability.getPropertyNames();
+        ResourcePropertiesSchema schema = getSchema();
+        
+        for (int n = 0; n < names.length; ++n)
+            schema.setCapability(names[n], capability);
+    }
+    
+    public synchronized final void addChangeApprover(PropertyChangeApprover approver)
+    {
+        if (approver == null)
+            throw new NullPointerException(_MESSAGES.get("NullPCA"));
+        
+        QName qname = approver.getPropertyName();
+        
+        if (!hasPropertyDefinition(qname))
+        {
+            Object[] filler = { qname };
+            throw new IllegalArgumentException(_MESSAGES.get("PropertyNotInSchema", filler));
+        }
+        
+        _approversByQName.put(qname, approver);
+    }
+    
+    public synchronized final void addChangeListener(PropertyChangeListener listener)
+    {
+        if (listener == null)
+            throw new NullPointerException(_MESSAGES.get("NullPCL"));
+
+        QName qname = listener.getPropertyName();
+        
+        if (!hasPropertyDefinition(qname))
+        {
+            Object[] filler = { qname };
+            throw new IllegalArgumentException(_MESSAGES.get("PropertyNotInSchema", filler));
+        }
+        
+        _listenersByQName.put(qname, listener);
+    }
+    
+    public synchronized final void addReadListener(PropertyReadListener listener)
+    {
+        if (listener == null)
+            throw new NullPointerException(_MESSAGES.get("NullPRL"));
+
+        QName qname = listener.getPropertyName();
+        
+        if (!hasPropertyDefinition(qname))
+        {
+            Object[] filler = { qname };
+            throw new IllegalArgumentException(_MESSAGES.get("PropertyNotInSchema", filler));
+        }
+        
+        _readersByQName.put(qname, listener);
+    }
+    
+    public synchronized void applyMetadata()
+    {
+        if (_metadata == null)
+            throw new IllegalStateException(_MESSAGES.get("NoMetadata"));
+        
+        Iterator i = _metadata.getPropertyNames().iterator();
+        
+        //
+        // for each property in the RMD, read its constraints and add 
+        // approvers that enforce those constraints
+        //
+        while (i.hasNext())
+        {
+            QName qname = (QName)i.next();
+            
+            Collection staticValues = _metadata.getStaticValues(qname);
+            
+            //
+            // make sure instances that are StaticValues aren't deleted
+            //
+            if (!staticValues.isEmpty())
+            {
+                PropertyChangeApprover staticValuesListener = 
+                    new StaticValuesApprover(qname, _metadata);
+                addChangeApprover(staticValuesListener);
+                        
+                Iterator j = staticValues.iterator();
+                
+                //
+                // insert all the static (required) values
+                //
+                try
+                {
+                    while (j.hasNext())
+                        insertResourceProperty(qname, new Object[]{ j.next() });
+                }
+                
+                //
+                // if we get an error inserting a "required" value, 
+                // something is totally awry - throw unchecked
+                //
+                catch (SoapFault fault)
+                {
+                    throw new RuntimeException(fault.getMessage(), fault);
+                }
+            }
+            
+            //
+            // make sure only ValidValues are inserted (if any)
+            // 
+            // NOTE: this does NOT handle ValidValueRange. the user will 
+            //       need to provide a PCA for that, because it is highly-
+            //       dependent on the semantics of the property type.
+            //
+            addChangeApprover(new ValidValuesApprover(qname, _metadata));
+            
+            //
+            // make sure read-only properties aren't modified from the 
+            // outside (can still be mutable inside)
+            //
+            boolean readOnly = _metadata.isReadOnlyExternal(qname);
+            PropertyChangeApprover security = 
+                new ExternalChangeApprover(qname, readOnly);
+            security.setSecurityToken(getSecurityToken());
+            addChangeApprover(security);
+            
+            //
+            // if we can't update, we're either appendable (insert only) 
+            // or constant (read only). we need an enforcer!
+            //
+            if (!_metadata.canUpdate(qname))
+            {
+                PropertyChangeApprover approver = null;
+                
+                //
+                // insert only
+                //
+                if (_metadata.canInsert(qname))
+                    approver = new InsertOnlyApprover(qname);
+                
+                //
+                // read only
+                //
+                else
+                    approver = new ReadOnlyApprover(qname);
+                
+                addChangeApprover(approver);
+            }
+        }
+    }
+    
+    /**
+     * 
+     * Reports the completed property change to all PropertyChangeListeners. 
+     * If one of the listeners fails and throws an exception, the method is 
+     * over - it will not report the change to all remaining listeners
+     *
+     * @param qname
+     * @param oldValue
+     * @param newValue
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If one of the listeners fails while responding to the 
+     *         change; this does not indicate that the change was invalid, 
+     *         just that the listener's reaction failed.</li>
+     *         </ul>
+     *
+     */
+    protected final void changeCompleted(QName qname, Element oldValue, Element newValue)
+        throws BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        Collection listeners = (Collection)_listenersByQName.get(qname);
+        
+        if (listeners != null)
+        {
+            Iterator i = listeners.iterator();
+            
+            while (i.hasNext())
+            {
+                PropertyChangeListener listener = (PropertyChangeListener)i.next();
+                listener.propertyChanged(oldValue, newValue);
+            }
+        }
+    }
+    
+    /**
+     * 
+     * Reports the pending property change to all PropertyChangeApprovers. 
+     * As soon as one approver cancels the change by throwing an exception, 
+     * the method is over - it does not report to all approvers once one 
+     * has objected.
+     *
+     * @param qname
+     * @param oldValue
+     * @param newValue
+     * @param securityToken
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If one of the approvers does not approve!</li>
+     *         </ul>
+     *
+     */
+    protected final void changeRequested(QName qname, 
+                                         Element oldValue, 
+                                         Element newValue, 
+                                         Object securityToken)
+        throws BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        Collection approvers = (Collection)_approversByQName.get(qname);
+        
+        if (approvers != null)
+        {
+            Iterator i = approvers.iterator();
+            
+            while (i.hasNext())
+            {
+                PropertyChangeApprover approver = 
+                    (PropertyChangeApprover)i.next();
+                approver.validateChange(oldValue, newValue, securityToken);
+            }
+        }
+    }
+    
+    public void deleteResourceProperty(QName qname) 
+        throws BaseFault
+    {
+        deleteResourceProperty(qname, getSecurityToken());
+    }
+    
+    public synchronized void deleteResourceProperty(QName qname, Object securityToken) 
+        throws BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        //
+        // find all properties with the given name...
+        //
+        Element[] results = getResourceProperty(qname);
+        
+        if (results.length == 0)
+        {
+            Object[] filler = { qname };
+            throw new UnableToModifyResourcePropertyFault(_MESSAGES.get("NoInstancesToDelete", filler));
+        }
+        
+        //
+        // make sure deletion is okay from a SCHEMA point-of-view. this 
+        // does not validate deletion from a read-only/immutable. that 
+        // is done by PCAs
+        //
+        validateDelete(qname, results.length, results.length);
+
+        //
+        // inform approvers of the pending deletion - this could 
+        // throw and cancel the deletion
+        //
+        for (int n = 0; n < results.length; ++n)
+            changeRequested(qname, results[n], null, securityToken);
+        
+        WsResourceCapability capability = getCapability(qname);
+        capability.deleteProperty(qname);
+        
+        //
+        // inform listeners of deletion
+        //
+        for (int n = 0; n < results.length; ++n)
+            changeCompleted(qname, results[n], null);
+    }
+    
+    /**
+     * 
+     * @param map
+     * 
+     * @return A Collection containing a copy of all of the values in the 
+     *         given MultiMap.
+     *
+     */
+    private Collection getAllValues(MultiMap map)
+    {
+        int size = map.size();
+        Collection all = new ArrayList(size);
+        
+        Iterator i = map.values().iterator();
+        
+        while (i.hasNext())
+            all.addAll((Collection)i.next());
+        
+        return all;
+    }
+    
+    public WsResourceCapability getCapability(QName qname)
+    {
+        return getSchema().getCapability(qname);
+    }
+    
+    public synchronized final Iterator getChangeApprovers()
+    {
+        return getAllValues(_approversByQName).iterator();
+    }
+    
+    public synchronized final Iterator getChangeListeners()
+    {
+        return getAllValues(_listenersByQName).iterator();
+    }
+    
+    public synchronized final MetadataDescriptor getMetadata()
+    {
+        return _metadata;
+    }
+    
+    /**
+     * 
+     * {@inheritDoc}
+     * <br><br>
+     * This method returns the actual Elements that are stored in the 
+     * underlying DOM Document - modifying them will modify the WS-RP 
+     * document. Be careful!
+     *
+     */
+    public synchronized Element[] getMultipleResourceProperties(QName[] qnames)
+        throws InvalidResourcePropertyQNameFault, BaseFault
+    {
+        if (qnames == null)
+            throw new NullPointerException(_MESSAGES.get("NullQNameArray"));
+        
+        //
+        // first get all instances of each property named...
+        //
+        Element[][] results = new Element[qnames.length][];
+        int total = 0;
+        
+        for (int n = 0; n < qnames.length; ++n)
+        {
+            results[n] = getResourceProperty(qnames[n]);
+            total += results[n].length;
+        }
+        
+        //
+        // ...then copy them into one array to return
+        //
+        Element[] oneBigArray = new Element[total];
+        
+        //
+        // all property instances are copied in order, so all instances 
+        // of the same name are together
+        //
+        for (int n = 0, current = 0; n < results.length; ++n)
+        {
+            System.arraycopy(results[n], 0, oneBigArray, current, results[n].length);
+            current += results[n].length;
+        }
+        
+        return oneBigArray;
+    }
+    
+    /**
+     * 
+     * {@inheritDoc}
+     * <br><br>
+     * Unlike getResourceProperty(QName), the values returned from this 
+     * method have been transformed from Elements to POJOs and do <b>not</b> 
+     * represent the values in the underlying DOM Document. The implementation 
+     * uses the Serializers registered with Muse to parse the properties.
+     * 
+     * @see #getResourceProperty(QName)
+     * 
+     * @see WsrpUtils#convertToObjects(Element[], Class)
+     *
+     */
+    public synchronized Object getPropertyAsObject(QName qname, Class type)
+        throws BaseFault
+    {
+        Element[] properties = getResourceProperty(qname);
+        return WsrpUtils.convertToObjects(properties, type);
+    }
+    
+    public synchronized Collection getPropertyNames()
+    {
+        return getSchema().getPropertyNames();
+    }
+    
+    public synchronized final Iterator getReadListeners()
+    {
+        return getAllValues(_readersByQName).iterator();
+    }
+    
+    /**
+     * 
+     * {@inheritDoc}
+     * <br><br>
+     * This method returns the actual Elements that are stored in the 
+     * underlying DOM Document - modifying them will modify the WS-RP 
+     * document. Be careful!
+     * <br><br>
+     * Users who want more type safety and better encapsulation should 
+     * use getPropertyAsObject(QName, Class). 
+     * 
+     * @see #getPropertyAsObject(QName, Class)
+     *
+     */
+    public synchronized Element[] getResourceProperty(QName qname)
+        throws InvalidResourcePropertyQNameFault, BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        //
+        // it's invalid to read a property whose type is undefined
+        //
+        // NOTE: this is DIFFERENT from reading a property whose 
+        //       type is undefined but currently has zero instances
+        //        
+        if (!hasPropertyDefinition(qname))
+        {
+            Object[] filler = { qname };
+            throw new InvalidResourcePropertyQNameFault(_MESSAGES.get("PropertyNotInSchema", filler));
+        }
+        
+        WsResourceCapability capability = getCapability(qname);
+        Element[] results = capability.getProperty(qname);
+        
+        //
+        // let listeners/updaters know of the read request - the first 
+        // listener will have no values to work with
+        //
+        return readRequested(qname, results);
+    }
+    
+    public synchronized Element getResourcePropertyDocument() 
+        throws BaseFault
+    {
+        Document doc = XmlUtils.createDocument();
+        Element root = XmlUtils.createElement(doc, WsrpConstants.DEFAULT_DOCUMENT_QNAME);
+        doc.appendChild(root);
+        
+        Collection names = getPropertyNames();
+        QName[] namesAsArray = new QName[names.size()];
+        namesAsArray = (QName[])names.toArray(namesAsArray);
+        
+        Element[] values = getMultipleResourceProperties(namesAsArray);
+        
+        for (int n = 0; n < values.length; ++n)
+        {
+            values[n] = (Element)doc.importNode(values[n], true);
+            root.appendChild(values[n]);
+        }
+        
+        return root;
+    }
+    
+    public synchronized final ResourcePropertiesSchema getSchema()
+    {
+        return _schema;
+    }
+
+    public Object getSecurityToken()
+    {
+        return _securityToken;
+    }
+    
+    public boolean hasPropertyDefinition(QName qname)
+    {
+        if (_schema == null)
+            throw new IllegalStateException(_MESSAGES.get("NoSchema"));
+        
+        return _schema.hasProperty(qname);
+    }
+    
+    public synchronized void insertOrUpdate(QName property, Object value)
+        throws BaseFault
+    {
+        insertOrUpdate(property, new Object[]{ value });
+    }
+    
+    public synchronized void insertOrUpdate(QName property, Object[] values)
+        throws BaseFault
+    {
+        if (getResourceProperty(property).length == 0)
+            insertResourceProperty(property, values);
+        
+        else
+            updateResourceProperty(property, values);
+    }
+    
+    public synchronized void insertResourceProperty(QName qname, Object[] values)
+        throws BaseFault
+    {
+        insertResourceProperty(qname, values, getSecurityToken());
+    }
+    
+    public synchronized void insertResourceProperty(QName qname, 
+                                                    Object[] values, 
+                                                    Object securityToken)
+        throws BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        if (values == null)
+            throw new NullPointerException(_MESSAGES.get("NullValuesArray"));
+        
+        if (values.length == 0)
+            throw new IllegalArgumentException(_MESSAGES.get("EmptyValuesArray"));
+        
+        //
+        // find all current instances of the property...
+        //        
+        Element[] current = getResourceProperty(qname);
+
+        InsertRequest request = new InsertRequest(qname, values);
+        Element[] valuesXML = request.getValues();
+        
+        //
+        // make sure that the insert is valid according to the SCHEMA
+        //
+        validateInsert(qname, current.length, valuesXML);
+        
+        for (int n = 0; n < valuesXML.length; ++n)
+            changeRequested(qname, null, valuesXML[n], securityToken);
+
+        WsResourceCapability capability = getCapability(qname);
+        capability.insertProperty(qname, valuesXML);
+        
+        for (int n = 0; n < valuesXML.length; ++n)
+            changeCompleted(qname, null, valuesXML[n]);
+    }
+    
+    public synchronized Element putResourcePropertyDocument(Element newDoc)
+    {
+        return newDoc;  // FIXME: implement - this is harder than it first appears
+    }
+    
+    /**
+     * 
+     * Reports all property read requests to the PropertyReadListeners. If 
+     * one of the listeners fails and throws an exception, the method is 
+     * over - it will not report to all remaining listeners once one has 
+     * failed. Listeners will receive the actual values that will be given 
+     * to the caller, so they can modify them if desired.
+     *
+     * @param qname
+     *        The name of the property being read.
+     * 
+     * @param properties
+     *        The current values of the property, which will be given to 
+     *        the caller once all listeners have been invoked.
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If one of the listeners fails.</li>
+     *         </ul>
+     *
+     */
+    protected final Element[] readRequested(QName qname, Element[] properties)
+        throws BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        Collection readers = (Collection)_readersByQName.get(qname);
+        
+        if (readers != null)
+        {
+            Iterator i = readers.iterator();
+            
+            while (i.hasNext())
+            {
+                PropertyReadListener reader = (PropertyReadListener)i.next();
+                properties = reader.readRequested(properties);
+            }
+        }
+        
+        return properties;
+    }
+    
+    public synchronized final void removeChangeApprover(PropertyChangeApprover approver)
+    {
+        if (approver == null)
+            throw new NullPointerException(_MESSAGES.get("NullPCA"));
+        
+        removeItem(_approversByQName, approver.getPropertyName(), approver);
+    }
+        
+    public synchronized final void removeChangeListener(PropertyChangeListener listener)
+    {
+        if (listener == null)
+            throw new NullPointerException(_MESSAGES.get("NullPCL"));        
+
+        removeItem(_listenersByQName, listener.getPropertyName(), listener);
+    }
+    
+    /**
+     * 
+     * Removes the given value from the collection of values associated with 
+     * the given key. If removing the value results in the key having no 
+     * more entries associated with it, the key itself is removed.
+     * 
+     * @param map
+     * @param key
+     * @param value
+     *
+     */
+    private void removeItem(MultiMap map, Object key, Object value)
+    {
+        Collection all = (Collection)map.get(key);
+        all.remove(value);
+        
+        if (all.isEmpty())
+            map.remove(key);
+    }
+    
+    public synchronized final void removeReadListener(PropertyReadListener listener)
+    {
+        if (listener == null)
+            throw new NullPointerException(_MESSAGES.get("NullPRL"));
+        
+        removeItem(_readersByQName, listener.getPropertyName(), listener);
+    }
+    
+    public synchronized void setMetadata(MetadataDescriptor metadata)
+    {
+        if (metadata == null)
+            throw new NullPointerException(_MESSAGES.get("NullMetadataDescriptor"));
+        
+        _metadata = metadata;
+    }
+    
+    public synchronized void setResourceProperties(SetRequest request)
+        throws SoapFault
+    {
+        List ops = request.getRequestComponents();
+        
+        //
+        // we must have at least one set operation
+        //
+        if (ops.isEmpty())
+            throw new IllegalArgumentException(_MESSAGES.get("EmptySetRequest"));
+        
+        //
+        // execute each operation in order
+        //
+        // NOTE: This is not a transaction system, so if one operation 
+        //       fails in the middle, the operations that have been 
+        //       performed to that point are not rolled back. This is 
+        //       consistent with the WS-RP spec but may not be adequate 
+        //       for building manageable resources.
+        //
+        Iterator i = ops.iterator();
+        
+        while (i.hasNext())
+        {
+            SetRequestComponent next = (SetRequestComponent)i.next();
+            next.execute(this);
+        }
+    }
+
+    public synchronized void setSchema(ResourcePropertiesSchema schema)
+    {
+        if (schema == null)
+            throw new NullPointerException(_MESSAGES.get("NullSchema"));
+        
+        _schema = schema;
+    }
+    
+    /**
+     * 
+     * @return An XML representation of the current WS-RP document, without 
+     *         the XML header.
+     *
+     */
+    public synchronized String toString()
+    {
+        return XmlUtils.toString(toXML(), false);
+    }
+    
+    public synchronized Element toXML()
+    {
+        try
+        {
+            return getResourcePropertyDocument();
+        }
+        
+        catch (SoapFault error)
+        {
+            throw new RuntimeException(error.getMessage(), error);
+        }
+    }
+    
+    /**
+     * 
+     * @return A <b>copy</b> of the underlying DOM Document that is used to 
+     *         store the properties. 
+     *
+     */
+    public synchronized Element toXML(Document factory)
+    {
+        try
+        {
+            Element wsrp = getResourcePropertyDocument();
+            return (Element)factory.importNode(wsrp, true);
+        }
+        
+        catch (SoapFault error)
+        {
+            throw new RuntimeException(error.getMessage(), error);
+        }
+    }
+    
+    public synchronized void updateResourceProperty(QName qname, Object[] values)
+        throws BaseFault
+    {
+        updateResourceProperty(qname, values, getSecurityToken());
+    }
+    
+    public synchronized void updateResourceProperty(QName qname, 
+                                                    Object[] values, 
+                                                    Object securityToken)
+        throws BaseFault
+    {
+        if (qname == null)
+            throw new NullPointerException(_MESSAGES.get("NullQName"));
+        
+        if (values == null)
+            throw new NullPointerException(_MESSAGES.get("NullValuesArray"));
+        
+        //
+        // get all current instances of the property
+        //
+        Element[] current = getResourceProperty(qname);
+        
+        //
+        // we can't update if there are no instances of the property. 
+        // callers must insert, THEN update
+        //
+        if (current.length == 0)
+        {
+            Object[] filler = { qname };
+            throw new UnableToModifyResourcePropertyFault(_MESSAGES.get("PropertyNotFound", filler));
+        }
+        
+        UpdateRequest request = new UpdateRequest(qname, values);
+        Element[] valuesXML = request.getValues();
+        
+        //
+        // make sure the update is valid according to the SCHEMA - this 
+        // test assumes we will remove all current values and insert 
+        // new ones
+        //
+        validateInsert(qname, 0, valuesXML);
+        
+        int lcd = Math.min(current.length, valuesXML.length);
+
+        for (int n = 0; n < lcd; ++n)
+            changeRequested(qname, current[n], valuesXML[n], securityToken);
+        
+        WsResourceCapability capability = getCapability(qname);
+        capability.updateProperty(qname, valuesXML);
+
+        for (int n = 0; n < lcd; ++n)
+            changeCompleted(qname, current[n], valuesXML[n]);
+        
+        //
+        // if there were more copies before the update than after, 
+        // we need to send deletion notifications about the extras
+        //
+        for (int n = lcd; n < current.length; ++n)
+            changeCompleted(qname, current[n], null);
+        
+        //
+        // the other possibility is that there are more copies after 
+        // the update than before, so we still have some values to 
+        // report that are not "replacements"
+        //
+        for (int n = lcd; n < valuesXML.length; ++n)
+            changeCompleted(qname, null, valuesXML[n]);
+    }
+    
+    /**
+     * 
+     * Confirms that deleting the desired number of property instances will 
+     * result in a WS-RP document that is valid according to the schema.
+     * 
+     * @param qname
+     *        The name of the property whose instances are being deleted.
+     * 
+     * @param currentSize
+     *        The current number of instances (before the delete).
+     * 
+     * @param toDelete
+     *        The number of instances being deleted.
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If the property name is undefined.</li>
+     *         <li>If deleting the instances would put the property below 
+     *         its minimum value ("minOccurs").</li>
+     *         </ul>
+     *
+     */
+    protected void validateDelete(QName qname, int currentSize, int toDelete)
+        throws BaseFault
+    {
+        //
+        // make sure that deleting 'toDelete' instances won't put us 
+        // below the minimum
+        //
+        int min = _schema.getMinOccurs(qname);
+        
+        if (currentSize - toDelete < min)
+        {
+            Object[] filler = { 
+                qname, new Integer(min), new Integer(currentSize - toDelete) 
+            };
+            throw new SchemaValidationErrorFault(_MESSAGES.get("BelowMinimumPotential", filler));
+        }
+    }
+    
+    /**
+     * 
+     * Confirms that inserting the desired property instances will result in 
+     * a WS-RP document that is valid according to the schema.
+     * 
+     * @param qname
+     *        The name of the property that is being inserted.
+     * 
+     * @param currentSize
+     *        The current number of instances (before the insertion).
+     * 
+     * @param values
+     *        The property values to insert into the document.
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If the property name is undefined.</li>
+     *         <li>If inserting the instances would put the property above 
+     *         its maximum value ("maxOccurs").</li>
+     *         <li>If any of the values is null, and the property is not 
+     *         nillable.</li>
+     *         </ul>
+     *
+     */
+    protected void validateInsert(QName qname, int currentSize, Element[] values)
+        throws BaseFault
+    {
+        ResourcePropertiesSchema schema = getSchema();
+        
+        //
+        // make sure that adding value.length instances will not put us 
+        // above the maximum (if any)
+        //
+        int max = schema.getMaxOccurs(qname);
+        int total = currentSize + values.length;
+        
+        if (!_schema.isMaxUnbounded(qname) && total > max)
+        {
+            Object[] filler = { qname, new Integer(max), new Integer(total) };
+            throw new SchemaValidationErrorFault(_MESSAGES.get("AboveMaximumPotential", filler));
+        }
+        
+        //
+        // are we trying to set to null when we shouldn't be?
+        //
+        boolean isNillable = schema.isNillable(qname);
+        
+        for (int n = 0; n < values.length; ++n)
+        {
+            if (!isNillable && !values[n].hasChildNodes())
+            {
+                Object[] filler = { qname };
+                throw new SchemaValidationErrorFault(_MESSAGES.get("NotNillable", filler));
+            }
+        }
+    }
+    
+    public synchronized void validateMetadata()
+        throws BaseFault
+    {
+        if (_metadata == null)
+            throw new IllegalStateException(_MESSAGES.get("NoMetadata"));
+        
+        Iterator i = _metadata.getPropertyNames().iterator();
+        
+        //
+        // for each wsrmd:Property, make sure it's in the schema and 
+        // that all current values are valid
+        //
+        while (i.hasNext())
+        {
+            QName qname = (QName)i.next();            
+            Element[] current = getResourceProperty(qname);
+            
+            //
+            // no instances OR the RMD does not have any metadata - skip
+            //
+            if (current.length == 0 || !_metadata.hasProperty(qname))
+                continue;
+            
+            //
+            // validate current values
+            //
+            for (int n = 0; n < current.length; ++n)
+            {
+                if (!_metadata.isValidValue(qname, current[n]))
+                {
+                    Object[] filler = { qname, XmlUtils.toString(current[n], false) };
+                    throw new MetadataValidationErrorFault(_MESSAGES.get("InvalidValue", filler));
+                }
+            }
+        }
+    }
+    
+    public synchronized void validateSchema()
+        throws BaseFault
+    {        
+        //
+        // for every property in the schema, check the size constraints 
+        //
+        ResourcePropertiesSchema schema = getSchema();
+        Iterator i = schema.getPropertyNames().iterator();
+        
+        while (i.hasNext())
+        {
+            QName qname = (QName)i.next();
+            
+            if (!schema.hasCapability(qname))
+            {
+                Object[] filler = { qname };
+                throw new IllegalStateException(_MESSAGES.get("NoCapabilityForProperty", filler));
+            }
+            
+            int max = schema.getMaxOccurs(qname);
+            boolean maxUnbounded = schema.isMaxUnbounded(qname);
+            
+            int min = schema.getMinOccurs(qname);
+            
+            boolean isNillable = schema.isNillable(qname);
+            
+            //
+            // get all current instances
+            //
+            Element[] instances = getResourceProperty(qname);
+            
+            //
+            // minimum number of instances?
+            //
+            if (instances.length < min)
+            {
+                Object[] filler = {
+                    qname, new Integer(min), new Integer(instances.length)
+                };
+                throw new SchemaValidationErrorFault(_MESSAGES.get("BelowMinimum", filler));
+            }
+            
+            //
+            // under the max?
+            //
+            if (!maxUnbounded && instances.length > max)
+            {
+                Object[] filler = {
+                    qname, new Integer(min), new Integer(instances.length)
+                };
+                throw new SchemaValidationErrorFault(_MESSAGES.get("AboveMaximum", filler));
+            }
+            
+            //
+            // are any instances null that shouldn't be?
+            //
+            String message = _MESSAGES.get("NotNillable", new Object[]{ qname });
+            
+            if (!isNillable)
+                for (int n = 0; n < instances.length; ++n)
+                    if (!instances[n].hasChildNodes())
+                        throw new SchemaValidationErrorFault(message);
+        }
+    }
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/WsrpUtils.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/WsrpUtils.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/WsrpUtils.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/impl/WsrpUtils.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,179 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.impl;
+
+import java.lang.reflect.Array;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.apache.muse.core.serializer.Serializer;
+import org.apache.muse.core.serializer.SerializerRegistry;
+import org.apache.muse.util.messages.Messages;
+import org.apache.muse.util.messages.MessagesFactory;
+import org.apache.muse.util.xml.XmlUtils;
+import org.apache.muse.ws.addressing.soap.SoapFault;
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+import org.apache.muse.ws.resource.ext.faults.SerializationErrorFault;
+import org.apache.muse.ws.resource.properties.WsrpConstants;
+import org.apache.muse.ws.wsdl.WsdlUtils;
+
+public class WsrpUtils
+{
+    //
+    // Used to lookup all exception messages
+    //
+    private static Messages _MESSAGES = MessagesFactory.get(WsrpUtils.class);
+    
+    /**
+     * 
+     * Uses Muse's registered Serializers to convert the given objects 
+     * into XML elements.
+     *
+     * @param properties
+     *        The property values to serialize.
+     * 
+     * @param type
+     *        The type whose registered Serializer will be used to parse 
+     *        the property values.
+     * 
+     * @param qname
+     *        The QName of the XML elements that will represent the 
+     *        property values.
+     * 
+     * @return An array with the POJO representation of the given property 
+     *         values. The array will be the same length as the one given. 
+     *         The order of the objects will be the same as the order of the 
+     *         values.
+     * 
+     * @throws SoapFault
+     *         <ul>
+     *         <li>If any of the values could not be serialized.</li>
+     *         </ul>
+     *
+     */
+    public static Element[] convertToElements(Object[] properties, 
+                                              Class type, 
+                                              QName qname)
+        throws SoapFault
+    {
+        SerializerRegistry registry = SerializerRegistry.getInstance();
+        Serializer ser = registry.getSerializer(type);        
+        Element[] xml = new Element[properties.length];
+        
+        for (int n = 0; n < properties.length; ++n)
+            xml[n] = ser.toXML(properties[n], qname);
+        
+        return xml;
+    }
+
+    /**
+     * 
+     * Uses Muse's registered Serializers to convert the given Elements 
+     * into instances of the given type.
+     *
+     * @param properties
+     *        The property values to deserialize.
+     * 
+     * @param type
+     *        The type whose registered Serializer will be used to parse 
+     *        the property values.
+     * 
+     * @return An array with the POJO representation of the given property 
+     *         values. The array will be the same length as the one given. 
+     *         The order of the objects will be the same as the order of the 
+     *         values.
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If any of the values could not be deserialized.</li>
+     *         </ul>
+     *
+     */
+    public static Object convertToObjects(Element[] properties, Class type)
+        throws BaseFault
+    {
+        SerializerRegistry registry = SerializerRegistry.getInstance();
+        Serializer deser = registry.getSerializer(type);
+        
+        Object objects = Array.newInstance(type, properties.length);
+        
+        try
+        {
+            for (int n = 0; n < properties.length; ++n)
+                Array.set(objects, n, deser.fromXML(properties[n]));
+        }
+        
+        catch (SoapFault fault)
+        {
+            throw new SerializationErrorFault(fault);
+        }
+        
+        return objects;
+    }
+
+    /**
+     * 
+     * Searches a WSDL document for the schema definition of a resource's 
+     * WS-RP document. The WS-RP document is defined in the WSDL's <em>types</em> 
+     * section and is an aggregate properties defined in other schemas (all 
+     * properties listed in the WS-RP definition use the <em>ref</em> attribute 
+     * to refer to their complete type definitions).
+     *
+     * @param wsdl
+     *        The WSDL document that contains the WS-RP definition.
+     * 
+     * @param portType
+     *        The WSDL portType that has the name of the WS-RP definition.
+     * 
+     * @return The Element that is the definition of the WS-RP document.
+     *         This element is a sequence of other XSD elements that use the 
+     *         <em>ref</em> attribute to define their types.
+     *
+     */
+    public static Element getPropertiesDefinition(Node wsdl, QName portType)
+    {
+        if (wsdl == null)
+            throw new NullPointerException(_MESSAGES.get("NullWSDLDocument"));
+        
+        //
+        // get the resource's portType from the WSDL
+        //
+        Element portTypeXML = WsdlUtils.getPortType(wsdl, portType);
+        
+        if (portTypeXML == null)
+            throw new RuntimeException(_MESSAGES.get("NoPortTypesFound"));
+        
+        //
+        // get the name of the WS-RP element
+        //
+        String definitionName = 
+            portTypeXML.getAttributeNS(WsrpConstants.NAMESPACE_URI, WsrpConstants.RESOURCE_PROPERTIES);
+        
+        if (definitionName == null || definitionName.length() == 0)
+            throw new RuntimeException(_MESSAGES.get("NoPropertiesAttribute"));
+        
+        QName definitionQName = XmlUtils.parseQName(definitionName, portTypeXML);
+        
+        //
+        // find the element that corresponds to the WS-RP name
+        // 
+        return WsdlUtils.getTypeDeclaration(wsdl, definitionQName);
+    }
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/AbstractChangeApprover.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/AbstractChangeApprover.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/AbstractChangeApprover.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/AbstractChangeApprover.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,81 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.listeners;
+
+import javax.xml.namespace.QName;
+
+/**
+ *
+ * AbstractChangeApprover is an abstract base class that implements the 
+ * identification and security aspects of 
+ * {@linkplain PropertyChangeApprover PropertyChangeApprover}. Concrete 
+ * approvers that subclass this class only have to implement the 
+ * PropertyChangeApprover.validateChange() method. 
+ *
+ * @author Dan Jemiolo (danj)
+ *
+ */
+
+public abstract class AbstractChangeApprover implements PropertyChangeApprover
+{
+    //
+    // The name of the property to protect
+    //
+    private QName _qname = null;
+    
+    //
+    // The security token of the WS-RP container - we can compare this 
+    // against other tokens to determine of the request is coming from 
+    // inside the touchpoint or from external requests.
+    //
+    private Object _securityToken = null;
+    
+    /**
+     * 
+     * Creates a new approver for the property with the given name.
+     *
+     * @param qname
+     *        The QName of the property to monitor.
+     *
+     */
+    public AbstractChangeApprover(QName qname)
+    {
+        _qname = qname;
+    }
+    
+    public QName getPropertyName()
+    {
+        return _qname;
+    }
+    
+    /**
+     * 
+     * @return True if the given token is the same object as the internal 
+     *         security token, or if they match according to equals().
+     *
+     */
+    public boolean isSecure(Object outsideToken)
+    {
+        return _securityToken == outsideToken || 
+               (_securityToken != null && _securityToken.equals(outsideToken));
+    }
+    
+    public void setSecurityToken(Object securityToken)
+    {
+        _securityToken = securityToken;
+    }
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeApprover.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeApprover.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeApprover.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeApprover.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,99 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.listeners;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+
+/**
+ *
+ * PropertyChangeApprover describes a type of property listener that is 
+ * invoked when a property change is about to occur (through the WS-RP 
+ * SetResourceProperties operation). Approvers can prevent the change by 
+ * throwing an exception from the validateChange() method. Before writing 
+ * your own approver, make sure that Muse's WS-RMD support doesn't already 
+ * do what you are trying to do.
+ *
+ * @author Dan Jemiolo (danj)
+ * 
+ * @see org.apache.muse.ws.resource.metadata.MetadataDescriptor
+ *
+ */
+
+public interface PropertyChangeApprover
+{
+    /**
+     * 
+     * @return The QName of the property being monitored.
+     *
+     */
+    QName getPropertyName();
+    
+    /**
+     * 
+     * @param securityToken
+     *        The security token provided by the caller who wishes to make 
+     *        the property change.
+     * 
+     * @return True if the token matches one the approver knows to be valid.
+     * 
+     * @see #setSecurityToken(Object)
+     *
+     */
+    boolean isSecure(Object securityToken);
+    
+    /**
+     * 
+     * Analyzes the property change being made and throws an exception if 
+     * the change is invalid.
+     *
+     * @param oldValue
+     *        The current (about to be "old") value of the resource property.
+     *        This should be null if the change is a WS-RP Insert.
+     * 
+     * @param newValue
+     *        The potential new value of the resource property. This should 
+     *        be null if the change is a WS-RP Delete.
+     * 
+     * @param token
+     *        The security token provided by the caller who wishes to make 
+     *        the property change.
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If the modification is not allowed for any reason.</li>
+     *         </ul>
+     *
+     */
+    void validateChange(Element oldValue, Element newValue, Object token)
+        throws BaseFault;
+    
+    /**
+     * 
+     * Sets the security token that will be used in all security checks 
+     * via isSecure(Object).
+     *
+     * @param securityToken
+     * 
+     * @see #isSecure(Object)
+     *
+     */
+    void setSecurityToken(Object securityToken);
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeListener.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeListener.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeListener.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyChangeListener.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,66 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.listeners;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+
+/**
+ *
+ * PropertyChangeListener describes a type of property listener that is 
+ * invoked after a property change has occurred (through the WS-RP 
+ * SetResourceProperties operation). Listeners can react to or report the 
+ * change from the propertyChanged() method. If you want to prevent changes, 
+ * you should use a {@linkplain PropertyChangeApprover PropertyChangeApprover}. 
+ *
+ * @author Dan Jemiolo (danj)
+ *
+ */
+
+public interface PropertyChangeListener
+{
+    /**
+     * 
+     * @return The QName of the property to monitor.
+     *
+     */
+    QName getPropertyName();
+    
+    /**
+     * 
+     * Receives the old and new value of the property after it has been 
+     * changed; there are no requirements on the actions taken in response 
+     * to a property change.
+     *
+     * @param oldValue
+     *        A copy of the property instance before it was changed.
+     * 
+     * @param newValue
+     *        The current value of the property instance.
+     * 
+     * @throws BaseFault
+     *         <ul>
+     *         <li>If the change reaction fails for any reason.</li>
+     *         </ul>
+     *
+     */
+    void propertyChanged(Element oldValue, Element newValue)
+        throws BaseFault;
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyReadListener.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyReadListener.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyReadListener.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/PropertyReadListener.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,60 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.listeners;
+
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Element;
+
+import org.apache.muse.ws.resource.basefaults.BaseFault;
+
+/**
+ *
+ * PropertyReadListener describes a type of property listener that is 
+ * invoked before a property read request is completed (through the WS-RP 
+ * GetResourceProperty and GetMultipleResourceProperties operations). Listeners 
+ * can react to the read request in any way: the read can be prevented by 
+ * throwing an exception, the value returned to the reader can be modified, etc. 
+ * This is very useful when defining "dynamic properties", properties that change 
+ * constantly and whose values are only updated when a read request is made.
+ *
+ * @author Dan Jemiolo (danj)
+ *
+ */
+
+public interface PropertyReadListener
+{
+    /**
+     * 
+     * @return The name of the property to monitor.
+     *
+     */
+    QName getPropertyName();
+    
+    /**
+     * 
+     * @param properties
+     *        The actual property values that will be returned to the caller 
+     *        at the end of the read operation. WS-RP collections should not 
+     *        pass copies of the values to a listener, since that prevents 
+     *        the ability to define dynamic property values (properties that 
+     *        constantly change and are only updated on read requests).
+     *
+     */
+    Element[] readRequested(Element[] properties)
+        throws BaseFault;
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/ResourcePropertyListeners.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/ResourcePropertyListeners.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/ResourcePropertyListeners.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/listeners/ResourcePropertyListeners.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,144 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.listeners;
+
+import java.util.Iterator;
+
+/**
+ *
+ * ResourcePropertyListeners defines operations for WS-RP documents 
+ * that allow users to monitor activity on the document and subscribe to 
+ * notifications about that activity. Because the concepts of validation 
+ * and notifications are often used together, this interface also defines 
+ * a set of operations for applying a schema and metadata for the properties 
+ * document. Implementations of this interface will provide all of the 
+ * standard WS-RP operations plus the ability to react to asynchronous 
+ * events on the properties. 
+ *
+ * @author Dan Jemiolo (danj)
+ * 
+ * @see org.apache.muse.ws.resource.properties.impl.SimpleResourcePropertyCollection
+ * 
+ */
+
+public interface ResourcePropertyListeners
+{
+    /**
+     * 
+     * Associates the given approver with the appropriate property. All 
+     * approvers will be notified of pending changes to their property; if 
+     * one of the approvers rejects the change (by throwing an exception), 
+     * the change will not be completed. Each approver will continue to 
+     * exist until it is removed with removeChangeApprover(PropertyChangeApprover). 
+     *
+     * @param approver
+     *        The approver that will be notified of all pending changes.
+     * 
+     * @see PropertyChangeApprover#getPropertyName()
+     * @see #removeChangeApprover(PropertyChangeApprover)
+     *
+     */
+    void addChangeApprover(PropertyChangeApprover approver);
+    
+    /**
+     * 
+     * Associates the given listener with the appropriate property. The 
+     * listeners will be notified of completed changes to their property. 
+     * Each listener will continue to exist until it is removed with 
+     * removeChangeListener(PropertyChangeListener).
+     *
+     * @param listener
+     *        The listener that will be notified of all completed changes.
+     * 
+     * @see PropertyChangeListener#getPropertyName()
+     * @see #removeChangeListener(PropertyChangeListener)
+     *
+     */
+    void addChangeListener(PropertyChangeListener listener);
+
+    /**
+     * 
+     * Associates the given listener with the appropriate property. The 
+     * listeners will be notified of all pending read requests for a 
+     * property, giving them the opportunity to reject the read or to modify 
+     * the value of the property before it is returned to the caller. Each 
+     * listener will continue to exist until it is removed with 
+     * removeReadListener(PropertyReadListener).
+     *
+     * @param listener
+     *        The listener that will be notified of all pending read requests.
+     * 
+     * @see PropertyReadListener#getPropertyName()
+     * @see #removeReadListener(PropertyReadListener)
+     *
+     */
+    void addReadListener(PropertyReadListener listener);
+    
+    /**
+     * 
+     * @return An iterator for the collection of PropertyChangeApprovers. 
+     *         The approvers are not guaranteed to be in a particular order.
+     *
+     */
+    Iterator getChangeApprovers();
+    
+    /**
+     * 
+     * @return An iterator for the collection of PropertyChangeListeners. 
+     *         The listeners are not guaranteed to be in a particular order.
+     *
+     */
+    Iterator getChangeListeners();
+    
+    /**
+     * 
+     * @return An iterator for the collection of PropertyReadListeners. 
+     *         The listeners are not guaranteed to be in a particular order.
+     *
+     */
+    Iterator getReadListeners();
+    
+    /**
+     * 
+     * Removes the assocation between the given approver and its property.
+     * The approver will no longer be notified of pending changes.
+     *
+     * @param approver
+     *
+     */
+    void removeChangeApprover(PropertyChangeApprover approver);
+    
+    /**
+     * 
+     * Removes the assocation between the given listener and its property.
+     * The approver will no longer be notified of completed changes.
+     *
+     * @param listener
+     *
+     */
+    void removeChangeListener(PropertyChangeListener listener);
+
+    /**
+     * 
+     * Removes the assocation between the given listener and its property.
+     * The approver will no longer be notified of pending read requests.
+     *
+     * @param listener
+     *
+     */
+    void removeReadListener(PropertyReadListener listener);
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryCapability.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryCapability.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryCapability.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryCapability.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,28 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.query;
+
+import org.apache.muse.ws.resource.WsResourceCapability;
+
+
+public interface QueryCapability 
+    extends WsResourceCapability, QueryResourceProperties
+{
+    //
+    // no additional methos - we just expose the WS-RP query operation
+    //
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpression.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpression.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpression.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpression.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,32 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.query;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.apache.muse.ws.resource.properties.query.faults.InvalidQueryExpressionFault;
+import org.apache.muse.ws.resource.properties.query.faults.QueryEvaluationErrorFault;
+
+public interface QueryExpression
+{
+    String getDialect();
+    
+    Node[] evaluate(Element wsrpDoc, String query) 
+        throws InvalidQueryExpressionFault, 
+               QueryEvaluationErrorFault;
+}

Added: webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpressionFactory.java
URL: http://svn.apache.org/viewvc/webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpressionFactory.java?rev=413698&view=auto
==============================================================================
--- webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpressionFactory.java (added)
+++ webservices/muse/trunk/modules/muse-wsrf/src/org/apache/muse/ws/resource/properties/query/QueryExpressionFactory.java Mon Jun 12 09:12:15 2006
@@ -0,0 +1,27 @@
+/*=============================================================================*
+ *  Copyright 2006 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.muse.ws.resource.properties.query;
+
+import org.apache.muse.ws.resource.properties.query.faults.UnknownQueryExpressionDialectFault;
+
+public interface QueryExpressionFactory
+{
+    boolean hasDialect(String dialect);
+    
+    QueryExpression newInstance(String dialect) 
+        throws UnknownQueryExpressionDialectFault;
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: muse-commits-unsubscribe@ws.apache.org
For additional commands, e-mail: muse-commits-help@ws.apache.org