| /* |
| * 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) ; |
| // } |
| } |
| } |
| } |