/* DelegatingAtomFilter.java created 2008-03-04 * */ package org.signalml.domain.book.filter; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import org.apache.log4j.Logger; import org.signalml.compilation.CompilationException; import org.signalml.compilation.DynamicCompilationContext; import org.signalml.compilation.DynamicCompiler; import org.signalml.domain.book.StandardBookAtom; import org.signalml.domain.book.StandardBookSegment; import org.signalml.exception.SanityCheckException; import org.signalml.plugin.export.SignalMLException; import org.signalml.util.Util; import com.thoughtworks.xstream.annotations.XStreamAlias; /** * DelegatingAtomFilter * * * @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe * Sp. z o.o. */ @XStreamAlias("delegatingbookfilter") public class DelegatingAtomFilter extends AbstractAtomFilter { private static final long serialVersionUID = 1L; protected static final Logger logger = Logger.getLogger(DelegatingAtomFilter.class); private static final String[] CODES = new String[] { "delegatingAtomFilter" }; private ArrayList<File> classPath; private String fqClassName; private transient Class<?> delegateClass; private transient Method delegateMethod; private transient AtomFilter delegate; public DelegatingAtomFilter() { super(); classPath = new ArrayList<File>(); } @Override public void initialize() throws SignalMLException { try { getDelegate(); } catch (CompilationException ex) { throw new SignalMLException("error.delegatingAtomFilter.initializationFailed", ex); } catch (InstantiationException ex) { throw new SignalMLException("error.delegatingAtomFilter.initializationFailed", ex); } catch (IllegalAccessException ex) { throw new SignalMLException("error.delegatingAtomFilter.initializationFailed", ex); } } public DelegatingAtomFilter(DelegatingAtomFilter filter) { super(filter); classPath = new ArrayList<File>(filter.classPath); fqClassName = filter.fqClassName; } @Override public AbstractAtomFilter duplicate() { return new DelegatingAtomFilter(this); } public String getFqClassName() { return fqClassName; } public void setFqClassName(String fqClassName) { if (!Util.equalsWithNulls(this.fqClassName, fqClassName)) { this.fqClassName = fqClassName; delegateClass = null; delegateMethod = null; delegate = null; } } public ArrayList<File> getClassPath() { return classPath; } public void setClassPath(ArrayList<File> classPath) { this.classPath = classPath; delegateClass = null; delegateMethod = null; delegate = null; } @Override public boolean matches(StandardBookSegment segment, StandardBookAtom atom) { if (delegate == null) { try { getDelegate(); } catch (InstantiationException ex) { logger.error("Failed to instantiate delegate", ex); throw new SanityCheckException("Failed to instantiate verified filter", ex); } catch (IllegalAccessException ex) { logger.error("Failed to instantiate delegate", ex); throw new SanityCheckException("Failed to instantiate verified filter", ex); } catch (CompilationException ex) { logger.error("Failed to instantiate delegate", ex); throw new SanityCheckException("Failed to instantiate verified filter", ex); } } return delegate.matches(segment, atom); } public Class<?> getDelegateClass() throws CompilationException { if (delegateClass == null) { DynamicCompiler compiler = DynamicCompilationContext.getSharedInstance().getCompiler(); File[] path = new File[classPath.size()]; classPath.toArray(path); Class<?> cls = compiler.compile(path, fqClassName); if (!AtomFilter.class.isAssignableFrom(cls)) { try { delegateMethod = cls.getMethod("matches", StandardBookSegment.class, StandardBookAtom.class); } catch (SecurityException ex) { logger.error("Security exception", ex); throw new CompilationException(ex); } catch (NoSuchMethodException ex) { logger.info("Class doesn't implement filter", ex); throw new CompilationException("error.classNotFilter"); } } delegateClass = cls; } return delegateClass; } public AtomFilter getDelegate() throws CompilationException, InstantiationException, IllegalAccessException { if (delegate == null) { Class<?> cls = getDelegateClass(); if (AtomFilter.class.isAssignableFrom(cls)) { delegate = (AtomFilter) cls.newInstance(); } else { delegate = new UnimplementingFilterWrapper(cls.newInstance(), delegateMethod); } } return delegate; } @Override public Object[] getArguments() { String name = "?"; try { name = getDelegateClass().getSimpleName(); } catch (Throwable t) { // ignore all exceptions & errors } return new Object[] { name }; } @Override public String[] getCodes() { return CODES; } @Override public String getDefaultMessage() { return "Delegating atom filter"; } private class UnimplementingFilterWrapper implements AtomFilter { private Method delegateMethod; private Object delegate; private int warningCount; public UnimplementingFilterWrapper(Object delegate, Method delegateMethod) { if (delegateMethod == null) { throw new NullPointerException("No method"); } this.delegate = delegate; this.delegateMethod = delegateMethod; } @Override public boolean matches(StandardBookSegment segment, StandardBookAtom atom) { try { return ((Boolean) delegateMethod.invoke(this.delegate, segment, atom)).booleanValue(); } catch (IllegalArgumentException ex) { return onException(ex); } catch (IllegalAccessException ex) { return onException(ex); } catch (InvocationTargetException ex) { return onException(ex); } } private boolean onException(Exception ex) { if (warningCount < 10) { logger.error("Invocation failed", ex); if (warningCount == 9) { logger.error("... no more errors logged"); } } warningCount++; return false; } } }