/*=============================================================================*
* 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.dm.muws.impl;
import java.util.Collections;
import java.util.List;
import javax.xml.namespace.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
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.EndpointReference;
import org.apache.muse.ws.addressing.soap.SoapFault;
import org.apache.muse.ws.dm.muws.Match;
import org.apache.muse.ws.dm.muws.MuwsConstants;
import org.apache.muse.ws.resource.WsResource;
import org.apache.muse.ws.resource.properties.ResourcePropertyCollection;
import org.apache.muse.ws.resource.remote.WsResourceClient;
/**
*
* SimpleMatch is the most concrete form of pbm:Match - it allows an
* evaluator to compare to resources based on a single property value.
* Instances of SimpleMatch cannot have subexpressions
*
* @author Dan Jemiolo (danj)
*
*/
public class SimpleMatch implements Match
{
//
// Used to lookup all exception messages
//
private static Messages _MESSAGES = MessagesFactory.get(SimpleMatch.class);
//
// The name of the property to be used in evaluation
//
private QName _propertyQName = null;
//
// The local resource that is defining this correlation
//
private WsResource _resource = null;
/**
*
* @param resource
* The resource that is defining the CorrelatableProperties
* capability and thus, this correlation expression.
*
* @param xml
* The DOM Element representing the simple pbm:Match.
*
*/
public SimpleMatch(WsResource resource, Element xml)
{
if (resource == null)
throw new NullPointerException(_MESSAGES.get("NullOwner"));
if (xml == null)
throw new NullPointerException(_MESSAGES.get("NullMatchElement"));
_resource = resource;
_propertyQName = XmlUtils.getQName(xml);
if (_propertyQName == null)
throw new NullPointerException(_MESSAGES.get("NullQName"));
}
/**
*
* @param resource
* The resource that is defining the CorrelatableProperties
* capability and thus, this correlation expression.
*
* @param propertyQName
* The name of the property to compare between the two resources.
*
*/
public SimpleMatch(WsResource resource, QName propertyQName)
{
if (resource == null)
throw new NullPointerException(_MESSAGES.get("NullOwner"));
if (propertyQName == null)
throw new NullPointerException(_MESSAGES.get("NullQName"));
_resource = resource;
_propertyQName = propertyQName;
}
/**
*
* This method always throws an UnsupportedOperationException, because
* simple PBMs can't have children.
*
*/
public void addMatch(Match child)
{
throw new UnsupportedOperationException(_MESSAGES.get("NoChildMatches"));
}
public List getMatches()
{
return Collections.EMPTY_LIST;
}
/**
*
* @return The name of the property that is used during evaluation.
*
*/
public QName getPropertyQName()
{
return _propertyQName;
}
public WsResource getWsResource()
{
return _resource;
}
public boolean matches(EndpointReference epr)
throws SoapFault
{
if (epr == null)
throw new NullPointerException(_MESSAGES.get("NullRemoteResource"));
QName qname = getPropertyQName();
Element[] here = null;
ResourcePropertyCollection props = getWsResource().getPropertyCollection();
here = props.getResourceProperty(qname);
WsResourceClient otherResource = new WsResourceClient(epr);
Element[] there = otherResource.getResourceProperty(qname);
//
// if one has more than the other, we have a problem
//
if (here.length != there.length)
return false;
//
// compare the property instances as a test for resource equality
//
// NOTE: Unfortunately, we HAVE to do this with an O(n^2) comparison
// because there is no guarantee that the two resources have
// their property instances in the same order. Since order is
// not an indicator of equality, we must test each property
// instance here on the local side with all the other instances
// from the remote side until we find a match.
//
// We can alleviate most of the redundancy by nulling-out the
// Elements in the array that are already "matched" (so they're
// not used again). It's not great, but it's the best we can
// do given the lack of restrictions on the Element order.
//
for (int i = 0; i < here.length; ++i)
{
boolean foundMatch = false;
//
// for each local instance, go through the remaining list of
// remote instances and try to find a match
//
for (int j = 0; j < there.length && !foundMatch; ++j)
{
//
// if we find a match, nullify it (so it won't be evaluated
// again) and quit the loop
//
if (XmlUtils.equals(here[i], there[j])) // handles null check
{
there[j] = null;
foundMatch = true;
}
}
//
// if any of the instances is match-less, the test must fail
//
if (!foundMatch)
return false;
}
//
// if we made it this far, every property value had a match, so
// the resources are the same
//
return true;
}
/**
*
* This method always throws an UnsupportedOperationException, because
* simple PBMs can't have children.
*
*/
public void removeMatch(Match child)
{
throw new UnsupportedOperationException(_MESSAGES.get("NoChildMatches"));
}
public Element toXML()
{
return toXML(XmlUtils.EMPTY_DOC);
}
public Element toXML(Document doc)
{
if (doc == null)
throw new NullPointerException(_MESSAGES.get("NullDocument"));
return XmlUtils.createElement(doc, MuwsConstants.MATCH_QNAME, getPropertyQName());
}
}