001    /*
002     * Copyright 2011 Christian Kumpe http://kumpe.de/christian/java
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package de.kumpe.hadooptimizer.impl;
017    
018    import java.io.Serializable;
019    import java.util.Collection;
020    import java.util.concurrent.CopyOnWriteArrayList;
021    
022    import org.apache.commons.logging.Log;
023    import org.apache.commons.logging.LogFactory;
024    
025    import de.kumpe.hadooptimizer.EvaluationResult;
026    import de.kumpe.hadooptimizer.Halter;
027    import de.kumpe.hadooptimizer.Stoppable;
028    
029    /**
030     * The {@link ReportingHalterWrapper} passed the {@link EvaluationResult}s to
031     * each registered {@link Reporter} and then delegates the halt-decision the the
032     * specified {@link Halter}.
033     * 
034     * @param <I>
035     *            the individuals' type
036     * 
037     * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a>
038     */
039    public final class ReportingHalterWrapper<I> extends
040                    NeedsRandomWrapperBase<Halter<I>> implements Halter<I>, Stoppable {
041            private static final long serialVersionUID = 1L;
042            private static final Log log = LogFactory
043                            .getLog(ReportingHalterWrapper.class);
044    
045            /**
046             * The {@link ReportingHalterWrapper.Reporter} is used by the
047             * {@link ReportingHalterWrapper} to report about the passed
048             * evaluation-results every cycle.
049             * 
050             * @param <I>
051             *            the individuals' type
052             * 
053             * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a>
054             */
055            public interface Reporter<I> extends Serializable {
056                    void report(Collection<EvaluationResult<I>> evaluationResults);
057            }
058    
059            private Collection<Reporter<I>> reporters = new CopyOnWriteArrayList<Reporter<I>>();
060    
061            /**
062             * Creates a new {@link ReportingHalterWrapper} with the specified
063             * {@link Halter} delegate.
064             * 
065             * @param delegate
066             *            the {@link Halter} to which the halt-decision is delegated
067             */
068            public ReportingHalterWrapper(final Halter<I> delegate) {
069                    super(delegate);
070    
071                    if (log.isDebugEnabled()) {
072                            log.debug("Constructing new ReportingHalterWrapper with delegate="
073                                            + delegate);
074                    }
075            }
076    
077            @Override
078            public boolean halt(final Collection<EvaluationResult<I>> evaluationResults) {
079                    for (final Reporter<I> reporter : reporters) {
080                            reporter.report(evaluationResults);
081                    }
082                    return delegate.halt(evaluationResults);
083            }
084    
085            @Override
086            public void stop() {
087                    if (delegate instanceof Stoppable) {
088                            ((Stoppable) delegate).stop();
089                    }
090            }
091    
092            /**
093             * Adds a {@link Reporter}.
094             * 
095             * @param reporter
096             *            the {@link Reporter} to add; it will not check if the reporter
097             *            is already registered
098             */
099            public void addReporter(final Reporter<I> reporter) {
100                    if (log.isTraceEnabled()) {
101                            log.trace("Adding reporter: " + reporter);
102                    }
103    
104                    reporters.add(reporter);
105            }
106    
107            /**
108             * Remove a {@link Reporter}.
109             * 
110             * @param reporter
111             *            the {@link Reporter} to remove; it will only remove the first
112             *            occurrence of the specified reporter
113             */
114            public void removeReporter(final Reporter<I> reporter) {
115                    if (log.isTraceEnabled()) {
116                            log.trace("Removing reporter: " + reporter);
117                    }
118                    reporters.remove(reporter);
119            }
120    
121            @Override
122            public String toString() {
123                    return "ReportingHalterWrapper [delegate=" + delegate + ", reporters="
124                                    + reporters + "]";
125            }
126    }