blob: 2ff5ffc00111f9430bfcb0f4ce09d147aa5e9d02 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.jena.riot.checker;
import java.util.Iterator ;
import org.apache.jena.atlas.lib.Cache ;
import org.apache.jena.atlas.lib.CacheFactory ;
import org.apache.jena.graph.Node ;
import org.apache.jena.iri.IRI ;
import org.apache.jena.iri.IRIFactory ;
import org.apache.jena.iri.Violation ;
import org.apache.jena.riot.system.ErrorHandler ;
import org.apache.jena.riot.system.ErrorHandlerFactory ;
import org.apache.jena.riot.system.IRIResolver ;
public class CheckerIRI implements NodeChecker
{
private boolean allowRelativeIRIs = false ;
private ErrorHandler handler ;
private IRIFactory iriFactory ;
public CheckerIRI() {
this(ErrorHandlerFactory.getDefaultErrorHandler(), IRIResolver.iriFactory()) ;
}
public CheckerIRI(ErrorHandler handler, IRIFactory iriFactory) {
this.handler = handler ;
this.iriFactory = iriFactory ;
}
@Override
public boolean check(Node node, long line, long col)
{ return node.isURI() && checkURI(node, line, col) ; }
// An LRU cache is slower.
// An unbounded cache is fastest but does not scale.
private final Cache<Node, IRI> cache = CacheFactory.createSimpleCache(5000) ;
// abstract
public final boolean checkURI(Node node, long line, long col) {
if ( cache != null && cache.containsKey(node) )
return true ;
IRI iri = iriFactory.create(node.getURI()) ; // always works - no exceptions.
boolean b = checkIRI(iri, line, col) ;
// If OK, put in cache.
if ( cache != null && b )
cache.put(node, iri) ;
return b ;
}
final public boolean checkIRI(IRI iri, long line, long col) {
iriViolations(iri, handler, allowRelativeIRIs, true, line, col) ;
return !iri.hasViolation(true) ;
}
/** Process violations on an IRI
* Calls the errorhandler on all errors and warnings (as warning).
* Assumes error handler throws exceptions on errors if needbe
* @param iri IRI to check
* @param errorHandler The error handler to call on each warning or error.
*
*/
public static void iriViolations(IRI iri, ErrorHandler errorHandler) {
iriViolations(iri, errorHandler, -1L, -1L) ;
}
/** Process violations on an IRI
* Calls the errorhandler on all errors and warnings (as warning).
* Assumes error handler throws exceptions on errors if needbe
* @param iri IRI to check
* @param errorHandler The error handler to call on each warning or error.
*
*/
public static void iriViolations(IRI iri, ErrorHandler errorHandler, long line, long col) {
iriViolations(iri, errorHandler, false, true, line, col) ;
}
/** Process violations on an IRI
* Calls the errorhandler on all errors and warnings (as warning).
* Assumes error handler throws exceptions on errors if needbe
* @param iri IRI to check
* @param errorHandler The error handler to call on each warning or error.
* @param allowRelativeIRIs Allow relative URIs (discouraged)
*/
private static void iriViolations(IRI iri, ErrorHandler errorHandler, boolean allowRelativeIRIs) {
iriViolations(iri, errorHandler, allowRelativeIRIs, -1, -1) ;
}
/** Process violations on an IRI
* Calls the errorhandler on all errors and warnings (as warning).
* Assumes error handler throws exceptions on errors if needbe
* @param iri IRI to check
* @param errorHandler The error handler to call on each warning or error.
* @param allowRelativeIRIs Allow relative URIs (discouraged)
*/
private static void iriViolations(IRI iri, ErrorHandler errorHandler, boolean allowRelativeIRIs, long line, long col) {
iriViolations(iri, errorHandler, allowRelativeIRIs, true, line, col) ;
}
/** Process violations on an IRI
* Calls the errorhandler on all errors and warnings (as warning).
* Assumes error handler throws exceptions on errors if needbe
*/
public static void iriViolations(IRI iri, ErrorHandler errorHandler,
boolean allowRelativeIRIs,
boolean includeIRIwarnings,
long line, long col) {
if ( !allowRelativeIRIs && iri.isRelative() )
errorHandler.error("Relative IRI: " + iri, line, col) ;
if ( iri.hasViolation(includeIRIwarnings) ) {
Iterator<Violation> iter = iri.violations(includeIRIwarnings) ;
boolean errorSeen = false ;
boolean warningSeen = false ;
// What to finally report.
Violation vError = null ;
Violation vWarning = null ;
Violation xvSub = null ;
for ( ; iter.hasNext() ; ) {
Violation v = iter.next() ;
int code = v.getViolationCode() ;
boolean isError = v.isError() ;
// Ignore these.
if ( code == Violation.LOWERCASE_PREFERRED
|| code == Violation.PERCENT_ENCODING_SHOULD_BE_UPPERCASE
|| code == Violation.SCHEME_PATTERN_MATCH_FAILED )
continue ;
// Anything we want to reprioritise?
// [nothing at present]
// Remember first error and first warning.
if ( isError ) {
errorSeen = true ;
if ( vError == null )
// Remember first error
vError = v ;
} else {
warningSeen = true ;
if ( vWarning == null )
vWarning = v ;
}
String msg = v.getShortMessage() ;
String iriStr = iri.toString() ;
// Ideally, we might want to output all messages relating to this IRI
// then cause the error or continue.
// But that's tricky given the current errorhandler architecture.
// // Put out warnings for all IRI issues - later, exception for errors.
// if (v.getViolationCode() == ViolationCodes.REQUIRED_COMPONENT_MISSING &&
// v.getComponent() == IRIComponents.SCHEME)
// {
// if (! allowRelativeIRIs )
// handler.error("Relative URIs are not permitted in RDF: <"+iriStr+">", line, col);
// }
// else
{
if ( isError )
// IRI errors are warning at the level of parsing - they got through syntax checks.
errorHandler.warning("Bad IRI: "+msg, line, col);
else
errorHandler.warning("Not advised IRI: "+msg, line, col);
}
}
// // and report our choosen error.
// if ( errorSeen || (warningsAreErrors && warningSeen) )
// {
// String msg = null ;
// if ( vError != null ) msg = vError.getShortMessage() ;
// if ( msg == null && vWarning != null ) msg = vWarning.getShortMessage() ;
// if ( msg == null )
// handler.error("Bad IRI: <"+iri+">", line, col) ;
// else
// handler.error("Bad IRI: "+msg, line, col) ;
// }
}
}
}