de.tudarmstadt.ukp.clarin.webanno.brat.diag.CasDoctor.java Source code

Java tutorial

Introduction

Here is the source code for de.tudarmstadt.ukp.clarin.webanno.brat.diag.CasDoctor.java

Source

/*******************************************************************************
 * Copyright 2015
 * Ubiquitous Knowledge Processing (UKP) Lab and FG Language Technology
 * Technische Universitt Darmstadt
 *
 * 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 de.tudarmstadt.ukp.clarin.webanno.brat.diag;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.uima.cas.CAS;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;

import de.tudarmstadt.ukp.clarin.webanno.brat.diag.checks.Check;
import de.tudarmstadt.ukp.clarin.webanno.brat.diag.repairs.Repair;

public class CasDoctor implements InitializingBean {
    private Log log = LogFactory.getLog(getClass());

    @Value(value = "${debug.casDoctor.checks}")
    private String activeChecks;

    @Value(value = "${debug.casDoctor.fatal}")
    private boolean fatalChecks = true;

    @Value(value = "${debug.casDoctor.repairs}")
    private String activeRepairs;

    private List<Class<? extends Check>> checkClasses = new ArrayList<>();
    private List<Class<? extends Repair>> repairClasses = new ArrayList<>();

    public CasDoctor() {
        // Bean operation
    }

    public CasDoctor(Class<?>... aChecksRepairs) {
        // For testing
        StringBuilder checks = new StringBuilder();
        StringBuilder repairs = new StringBuilder();
        for (Class<?> clazz : aChecksRepairs) {
            boolean isCheck = Check.class.isAssignableFrom(clazz);
            boolean isRepair = Repair.class.isAssignableFrom(clazz);

            if (isCheck) {
                if (checks.length() > 0) {
                    checks.append(',');
                }
                checks.append(clazz.getSimpleName());
            }

            if (isRepair) {
                if (repairs.length() > 0) {
                    repairs.append(',');
                }
                repairs.append(clazz.getSimpleName());
            }

            if (!isCheck && !isRepair) {
                throw new IllegalArgumentException("[" + clazz.getName() + "] is neither a check nor a repair");
            }
        }
        activeChecks = checks.toString();
        fatalChecks = false;

        activeRepairs = repairs.toString();

        afterPropertiesSet();
    }

    public void setFatalChecks(boolean aFatalChecks) {
        fatalChecks = aFatalChecks;
    }

    public boolean isFatalChecks() {
        return fatalChecks;
    }

    public void repair(CAS aCas) {
        List<LogMessage> messages = new ArrayList<>();
        repair(aCas, messages);
        if (log.isWarnEnabled() && !messages.isEmpty()) {
            messages.forEach(s -> log.warn(s));
        }
    }

    public void repair(CAS aCas, List<LogMessage> aMessages) {
        boolean exception = false;
        for (Class<? extends Repair> repairClass : repairClasses) {
            try {
                Repair repair = repairClass.newInstance();
                repair.repair(aCas, aMessages);
            } catch (Exception e) {
                aMessages.add(new LogMessage(this, LogLevel.ERROR, "Cannot perform repair [%s]: %s",
                        repairClass.getSimpleName(), ExceptionUtils.getRootCauseMessage(e)));
                log.error(e);
                exception = true;
            }
        }

        if (!repairClasses.isEmpty() && (exception || !analyze(aCas, aMessages, false))) {
            aMessages.forEach(s -> log.error(s));
            throw new IllegalStateException("Repair attempt failed - ask system administrator " + "for details.");
        }
    }

    public boolean analyze(CAS aCas) {
        List<LogMessage> messages = new ArrayList<>();
        boolean result = analyze(aCas, messages);
        if (log.isDebugEnabled()) {
            messages.forEach(s -> log.debug(s));
        }
        return result;
    }

    public boolean analyze(CAS aCas, List<LogMessage> aMessages) {
        return analyze(aCas, aMessages, isFatalChecks());
    }

    private boolean analyze(CAS aCas, List<LogMessage> aMessages, boolean aFatalChecks) {
        boolean ok = true;
        for (Class<? extends Check> checkClass : checkClasses) {
            try {
                Check check = checkClass.newInstance();
                ok &= check.check(aCas, aMessages);
            } catch (InstantiationException | IllegalAccessException e) {
                aMessages.add(new LogMessage(this, LogLevel.ERROR, "Cannot instantiate [%s]: %s",
                        checkClass.getSimpleName(), ExceptionUtils.getRootCauseMessage(e)));
                log.error(e);
            }
        }

        if (!ok && aFatalChecks) {
            aMessages.forEach(s -> log.error(s));
            throw new IllegalStateException("CasDoctor has detected problems and checks are fatal.");
        }

        return ok;
    }

    public void setActiveChecks(String aActiveChecks) {
        activeChecks = aActiveChecks;
    }

    public void setActiveRepairs(String aActiveRepairs) {
        activeRepairs = aActiveRepairs;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void afterPropertiesSet() {
        if (StringUtils.isNotBlank(activeChecks)) {
            for (String check : activeChecks.split(",")) {
                try {
                    checkClasses.add((Class<? extends Check>) Class
                            .forName(Check.class.getPackage().getName() + "." + check.trim()));
                } catch (ClassNotFoundException e) {
                    throw new IllegalStateException(e);
                }
            }
        }

        if (StringUtils.isNotBlank(activeRepairs)) {
            for (String check : activeRepairs.split(",")) {
                try {
                    repairClasses.add((Class<? extends Repair>) Class
                            .forName(Repair.class.getPackage().getName() + "." + check.trim()));
                } catch (ClassNotFoundException e) {
                    throw new IllegalStateException(e);
                }
            }
        }
    }

    public static enum LogLevel {
        INFO, ERROR
    }

    public static class LogMessage {
        public final LogLevel level;
        public final Class<?> source;
        public final String message;

        public LogMessage(Object aSource, LogLevel aLevel, String aMessage) {
            this(aSource, aLevel, "%s", aMessage);
        }

        public LogMessage(Object aSource, LogLevel aLevel, String aFormat, Object... aValues) {
            super();
            source = aSource != null ? aSource.getClass() : null;
            level = aLevel;
            message = String.format(aFormat, aValues);
        }

        @Override
        public String toString() {
            return String.format("[%s] %s", source != null ? source.getSimpleName() : "<unknown>", message);
        }
    }
}