/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/search/basic/NotNormalizer.java,v 1.4.2.1 2004/02/05 16:05:10 mholz Exp $
* $Revision: 1.4.2.1 $
* $Date: 2004/02/05 16:05:10 $
*
* ====================================================================
*
* Copyright 1999 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.slide.search.basic;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.search.BadQueryException;
import org.apache.slide.search.InvalidQueryException;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.Namespace;
/**
* This class recursivly removes all <code><not></code> expressions
* and replaces their successors by appropriate negated expressions. Since
* an example explains more than a thousand words:
*
* <pre>
* <D:not>
* <D:or>
* <D:lt>
* <D:prop>
* <D:getcontentlength>
* </D:prop>
* <D:literal>1000</D:literal>
* </D:lt>
* <D:eq>
* <D:prop>
* <D:getcontenttype>
* </D:prop>
* <D:literal>text/xml</D:literal>
* </D:eq>
* </D:or>
* </D:not>
* </pre>
*
* will be transformed to
*
* <pre>
* <D:and>
* <D:not-lt>
* <D:prop>
* <D:getcontentlength>
* </D:prop>
* <D:literal>1000</D:literal>
* </D:not-lt>
* <D:not-eq>
* <D:prop>
* <D:getcontenttype>
* </D:prop>
* <D:literal>text/xml</D:literal>
* </D:not-eq>
* </D:and>
* </pre>
*
* @version $Revision: 1.4.2.1 $
*
* @author <a href="mailto:ralf.stuckert@softwareag.com">Ralf Stuckert</a>
**/
public class NotNormalizer {
/**
* The message of the {@link org.apache.slide.search.InvalidQueryException
* InvalidQueryException} which is thrown by {@link #getQueryWithoutNotExpression
* getQueryWithoutNotExpression} if a <code><not></code> expression has
* NOT exactly one successor.
*/
public static final String BAD_NOT_EXPRESSION_EXCEPTION_MESSAGE =
"not expression must contain exactly one nested expression";
/**
* Returns the transformed query where all <code><not></code> elements
* has been removed.
*
* @param expressionElement the (root) Element of the query to transform.
*
* @return the transformed query where all <code><not></code> elements
* has been removed.
*
* @throws BadQueryException if transformin the query failed
* (see {@link #BAD_NOT_EXPRESSION_EXCEPTION_MESSAGE
* BAD_NOT_EXPRESSION_EXCEPTION_MESSAGE}).
*/
public Element getQueryWithoutNotExpression(Element expressionElement) throws BadQueryException {
return getProcessedElement(expressionElement, false);
}
/**
* Returns the appropriate replacement for the given <code>expressionElement</code>.
* If <code>negate</code> is true, the Element has to be negated.
*
* @param expressionElement the Element for which to return the
* appropriate replacement.
* @param negate if <code>negate</code> is true, the given
* Element has to be negated.
*
* @return the appropriate replacement for the given <code>expressionElement</code>.
*
* @throws BadQueryException if the Element could not be processed.
*/
protected Element getProcessedElement(Element expressionElement, boolean negate) throws BadQueryException {
Element result = null;
if ( Literals.NOT.equals(expressionElement.getName()) &&
NamespaceCache.DEFAULT_URI.equals(expressionElement.getNamespaceURI()) ) {
List children = expressionElement.getChildren();
if (children.size() != 1) {
throw new InvalidQueryException(BAD_NOT_EXPRESSION_EXCEPTION_MESSAGE);
}
return getProcessedElement((Element)children.get(0), ! negate);
}
if (negate) {
result = getNegatedQueryElement(expressionElement);
}
else {
result = getNamedClone(expressionElement, expressionElement.getName(), expressionElement.getNamespace());
}
Iterator childrenIterator = expressionElement.getChildren().iterator();
while (childrenIterator.hasNext()) {
result.addContent(getProcessedElement((Element)childrenIterator.next(), negate));
}
return result;
}
/**
* Returns the negation of the given <code>expressionElement</code>.
*
* @param expressionElement the Element to return the appropriate
* negation for.
*
* @return the negation of the given <code>expressionElement</code>.
*
* @throws BadQueryException if the Element could not be processed.
*/
protected Element getNegatedQueryElement(Element expressionElement) throws BadQueryException {
if (NamespaceCache.DEFAULT_URI.equals(expressionElement.getNamespaceURI())) {
return getNegatedDAVQueryElement(expressionElement);
}
if (NamespaceCache.SLIDE_URI.equals(expressionElement.getNamespaceURI())) {
return getNegatedSlideQueryElement(expressionElement);
}
else {
return getNegatedUnknownQueryElement(expressionElement);
}
}
/**
* Returns the negation of the given <code>expressionElement</code>,
* which is neither in <code>DAV:</code> nor
* <code>http://jakarta.apache.org/slide/</code> namespace.
*
* @param expressionElement the Element to return the appropriate
* negation for.
*
* @return the negation of the given <code>expressionElement</code>.
*
* @throws BadQueryException if the Element could not be processed.
*/
protected Element getNegatedUnknownQueryElement(Element expressionElement) throws BadQueryException {
return getNamedClone(expressionElement, expressionElement.getName(), expressionElement.getNamespace());
}
/**
* Returns the negation of the given <code>expressionElement</code>,
* which is in the <code>DAV:</code> namespace.
*
* @param expressionElement the Element to return the appropriate
* negation for.
*
* @return the negation of the given <code>expressionElement</code>.
*
* @throws BadQueryException if the Element could not be processed.
*/
protected Element getNegatedDAVQueryElement(Element expressionElement) throws BadQueryException {
String name = expressionElement.getName();
if (Literals.AND.equals(name)) {
return getNamedClone(expressionElement, Literals.OR, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.OR.equals(name)) {
return getNamedClone(expressionElement, Literals.AND, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.GT.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_GT, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_GT.equals(name)) {
return getNamedClone(expressionElement, Literals.GT, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.GTE.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_GTE, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_GTE.equals(name)) {
return getNamedClone(expressionElement, Literals.GTE, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.LT.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_LT, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_LT.equals(name)) {
return getNamedClone(expressionElement, Literals.LT, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.LTE.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_LTE, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_LTE.equals(name)) {
return getNamedClone(expressionElement, Literals.LTE, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.EQ.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_EQ, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_EQ.equals(name)) {
return getNamedClone(expressionElement, Literals.EQ, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.CONTAINS.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_CONTAINS, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_CONTAINS.equals(name)) {
return getNamedClone(expressionElement, Literals.CONTAINS, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.ISCOLLECTION.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_ISCOLLECTION, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_ISCOLLECTION.equals(name)) {
return getNamedClone(expressionElement, Literals.ISCOLLECTION, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.ISDEFINED.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_ISDEFINED, NamespaceCache.DEFAULT_NAMESPACE);
}
if (Literals.NOT_ISDEFINED.equals(name)) {
return getNamedClone(expressionElement, Literals.ISDEFINED, NamespaceCache.DEFAULT_NAMESPACE);
}
return getNamedClone(expressionElement, expressionElement.getName(), expressionElement.getNamespace());
}
/**
* Returns the negation of the given <code>expressionElement</code>,
* which is in the <code>http://jakarta.apache.org/slide/</code> namespace.
*
* @param expressionElement the Element to return the appropriate
* negation for.
*
* @return the negation of the given <code>expressionElement</code>.
*
* @throws BadQueryException if the Element could not be processed.
*/
protected Element getNegatedSlideQueryElement(Element expressionElement) throws BadQueryException {
String name = expressionElement.getName();
if (Literals.ISPRINCIPAL.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_ISPRINCIPAL, NamespaceCache.SLIDE_NAMESPACE);
}
if (Literals.NOT_ISPRINCIPAL.equals(name)) {
return getNamedClone(expressionElement, Literals.ISPRINCIPAL, NamespaceCache.SLIDE_NAMESPACE);
}
if (Literals.PROPCONTAINS.equals(name)) {
return getNamedClone(expressionElement, Literals.NOT_PROPCONTAINS, NamespaceCache.SLIDE_NAMESPACE);
}
if (Literals.NOT_PROPCONTAINS.equals(name)) {
return getNamedClone(expressionElement, Literals.PROPCONTAINS, NamespaceCache.SLIDE_NAMESPACE);
}
return getNamedClone(expressionElement, expressionElement.getName(), expressionElement.getNamespace());
}
/**
* Creates a new Element with the given <code>newName</code> in the
* <code>newNamespace</code> and sets the value (text) and attributes
* of the given <code>source</code> element.
*
* @param source the Element from which to copy the value and attributes.
* @param newName the name to use for the Element to create.
* @param newNamespace the Namespace to use for the Element to create.
*
* @return the created Element.
*/
protected Element getNamedClone(Element source, String newName, Namespace newNamespace) {
Element copy = new Element(newName, newNamespace);
copy.setText(source.getText());
Iterator it = source.getAttributes().iterator();
while (it.hasNext()) {
Attribute attr = (Attribute)it.next();
copy.setAttribute ((Attribute)attr.clone());
}
return copy;
}
}