/*
* Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.yang.data.jaxen;
import com.google.common.base.Converter;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
import javax.annotation.Nonnull;
import javax.xml.xpath.XPathExpressionException;
import org.jaxen.BaseXPath;
import org.jaxen.ContextSupport;
import org.jaxen.JaxenException;
import org.jaxen.expr.Expr;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathBooleanResult;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathExpression;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathNodesetResult;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathNumberResult;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathResult;
import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathStringResult;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class JaxenXPath implements XPathExpression {
private static final Logger LOG = LoggerFactory.getLogger(JaxenXPath.class);
private final Converter<String, QNameModule> converter;
private final SchemaPath schemaPath;
private final BaseXPath xpath;
private JaxenXPath(final Converter<String, QNameModule> converter, final SchemaPath schemaPath,
final BaseXPath xpath) {
this.converter = Preconditions.checkNotNull(converter);
this.schemaPath = Preconditions.checkNotNull(schemaPath);
this.xpath = Preconditions.checkNotNull(xpath);
}
static JaxenXPath create(final Converter<String, QNameModule> converter, final SchemaPath schemaPath,
final String xpath) throws JaxenException {
final BaseXPath compiled = new BaseXPath(xpath) {
private static final long serialVersionUID = 1L;
@Override
protected ContextSupport getContextSupport() {
throw new UnsupportedOperationException(xpath);
}
};
final Expr expr = compiled.getRootExpr();
LOG.debug("Compiled {} to expression {}", xpath, expr);
new ExprWalker(new ExprListener() {
// FIXME: perform expression introspection to understand things like apex, etc.
}).walk(expr);
return new JaxenXPath(converter, schemaPath, compiled);
}
@Override
public Optional<? extends XPathResult<?>> evaluate(@Nonnull final XPathDocument document, @Nonnull final YangInstanceIdentifier path)
throws XPathExpressionException {
Preconditions.checkArgument(document instanceof JaxenDocument);
final NormalizedNodeContextSupport contextSupport = NormalizedNodeContextSupport.create(
(JaxenDocument)document, converter);
final Object result;
try {
result = xpath.evaluate(contextSupport.createContext(path));
} catch (JaxenException e) {
throw new XPathExpressionException(e);
}
if (result instanceof String) {
return Optional.of((XPathStringResult) () -> (String)result);
} else if (result instanceof Number) {
return Optional.of((XPathNumberResult) () -> (Number) result);
} else if (result instanceof Boolean) {
return Optional.of((XPathBooleanResult) () -> (Boolean) result);
} else if (result != null){
return Optional.of((XPathNodesetResult) () -> {
// XXX: Will this really work, or do we need to perform deep transformation?
return Lists.transform((List<NormalizedNodeContext>) result, NormalizedNodeContext::getNode);
});
} else {
return Optional.absent();
}
}
@Nonnull
@Override
public SchemaPath getEvaluationPath() {
return schemaPath;
}
@Nonnull
@Override
public SchemaPath getApexPath() {
// TODO: improve this
return SchemaPath.ROOT;
}
}