All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.rdf4j.federated.exception.ExceptionUtil Maven / Gradle / Ivy

There is a newer version: 5.1.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2019 Eclipse RDF4J contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *******************************************************************************/
package org.eclipse.rdf4j.federated.exception;

import java.lang.reflect.Constructor;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.rdf4j.federated.endpoint.Endpoint;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.QueryInterruptedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Convenience functions to handle exceptions.
 *
 * @author Andreas Schwarte
 *
 */
public class ExceptionUtil {

	protected static final Logger log = LoggerFactory.getLogger(ExceptionUtil.class);

	/**
	 * Regex pattern to identify http error codes from the title of the returned document:
	 *
	 * 
	 * Matcher m = httpErrorPattern.matcher("[..] 503 Service Unavailable [..]");
	 * if (m.matches()) {
	 * 		System.out.println("HTTP Error: " + m.group(1);
	 * }
	 * 
	 */
	protected static final Pattern httpErrorPattern = Pattern.compile(".*(.*).*", Pattern.DOTALL);

	/**
	 * Trace the exception source within the exceptions to identify the originating endpoint. The message of the
	 * provided exception is adapted to "@ endpoint.getId() - %orginalMessage".
	 * 

* * Note that in addition HTTP error codes are extracted from the title, if the exception resulted from an HTTP * error, such as for instance "503 Service unavailable" * * @param endpoint the the endpoint * @param ex the exception * @param additionalInfo additional information that might be helpful, e.g. the subquery * * @return a modified exception with endpoint source */ public static QueryEvaluationException traceExceptionSource(Endpoint endpoint, Throwable ex, String additionalInfo) { if (ex instanceof InterruptedException) { Thread.currentThread().interrupt(); } String eID; if (endpoint == null) { log.warn("No endpoint found for connection, probably changed from different thread."); eID = "unknown"; } else { eID = endpoint.getId(); } // check for http error code (heuristic) String message = ex.getMessage(); message = message == null ? "n/a" : message; Matcher m = httpErrorPattern.matcher(message); if (m.matches()) { log.debug("HTTP error detected for endpoint " + eID + ":\n" + message); message = "HTTP Error: " + m.group(1); } else { log.trace("No http error found"); } if (!(ex instanceof QueryEvaluationException)) { message += ". Original exception type: " + ex.getClass().getName(); } QueryEvaluationException res = new QueryEvaluationException( "@ " + eID + " - " + message + ". " + additionalInfo, ex.getCause()); res.setStackTrace(ex.getStackTrace()); return res; } /** * Repair the connection and then trace the exception source. * * @param endpoint * @param ex * @return the exception */ public static QueryEvaluationException traceExceptionSourceAndRepair(Endpoint endpoint, Throwable ex, String additionalInfo) { return traceExceptionSource(endpoint, ex, additionalInfo); } /** * Return the exception in a convenient representation, i.e. '%msg% (%CLASS%): %ex.getMessage()%' * * @param msg * @param ex * * @return the exception in a convenient representation */ public static String getExceptionString(String msg, Throwable ex) { return msg + " " + ex.getClass().getSimpleName() + ": " + ex.getMessage(); } /** * If possible change the message text of the specified exception. This is only possible if the provided exception * has a public constructor with String and Throwable as argument. The new message is set to 'msgPrefix. * ex.getMessage()', all other exception elements remain the same. * * @param * @param msgPrefix * @param ex * @param exClazz * * @return the updated exception */ public static E changeExceptionMessage(String msgPrefix, E ex, Class exClazz) { Constructor constructor; try { // try to find the constructor 'public Exception(String, Throwable)' constructor = exClazz.getConstructor(new Class[] { String.class, Throwable.class }); } catch (SecurityException e) { log.warn("Cannot change the message of exception class " + exClazz.getCanonicalName() + " due to SecurityException: " + e.getMessage()); return ex; } catch (NoSuchMethodException e) { log.warn("Cannot change the message of exception class " + exClazz.getCanonicalName() + ": Constructor not found."); return ex; } E newEx; try { newEx = constructor.newInstance(new Object[] { msgPrefix + "." + ex.getMessage(), ex.getCause() }); } catch (Exception e) { log.warn("Cannot change the message of exception class " + exClazz.getCanonicalName() + " due to " + e.getClass().getSimpleName() + ": " + e.getMessage()); return ex; } newEx.setStackTrace(ex.getStackTrace()); return newEx; } /** * Converts the {@link Throwable} to an {@link Exception}. If it is already of type exception, it is returned as is. * Otherwise, we create a new {@link QueryEvaluationException}, and attach the stack trace and a meaningful message. * * @param t * @return the {@link Exception} */ public static Exception toException(Throwable t) { Exception e; if (t instanceof QueryEvaluationException) { return (QueryEvaluationException) t; } if (t instanceof TimeoutException) { e = new QueryInterruptedException("Query evaluation has run into a timeout.", t); } else if (t instanceof Exception) { e = (Exception) t; } else { e = new QueryEvaluationException("" + t.getMessage() + ". Original type: " + t.getClass()); e.setStackTrace(t.getStackTrace()); } return e; } /** * Converts the given Throwable to a {@link QueryEvaluationException}. If it is already of type * {@link QueryEvaluationException} no transformation is done, otherwise the throwable is wrapped. * * @param t * @return the {@link QueryEvaluationException} */ public static QueryEvaluationException toQueryEvaluationException(Throwable t) { Exception res = toException(t); if (res instanceof QueryEvaluationException) { return (QueryEvaluationException) res; } if (t instanceof InterruptedException) { Thread.currentThread().interrupt(); } return new QueryEvaluationException(res); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy