001    /*
002    // $Id: //open/mondrian/src/main/mondrian/recorder/AbstractRecorder.java#8 $
003    // This software is subject to the terms of the Common Public License
004    // Agreement, available at the following URL:
005    // http://www.opensource.org/licenses/cpl.html.
006    // Copyright (C) 2005-2008 Julian Hyde and others
007    // All Rights Reserved.
008    // You must accept the terms of that agreement to use this software.
009    */
010    
011    package mondrian.recorder;
012    
013    import mondrian.resource.MondrianResource;
014    
015    import java.util.*;
016    
017    /**
018     * Abstract implemention of the {@link MessageRecorder} interface.
019     *
020     * @author Richard M. Emberson
021     * @version $Id: //open/mondrian/src/main/mondrian/recorder/AbstractRecorder.java#8 $
022     */
023    public abstract class AbstractRecorder implements MessageRecorder {
024    
025        /**
026         * Helper method to format a message and write to logger.
027         */
028        public static void logMessage(
029                final String context,
030                final String msg,
031                final MsgType msgType,
032                final org.apache.log4j.Logger logger) {
033            StringBuilder buf = new StringBuilder(64);
034            buf.append(context);
035            buf.append(": ");
036            buf.append(msg);
037    
038            switch (msgType) {
039            case INFO:
040                logger.info(buf.toString());
041                break;
042            case WARN:
043                logger.warn(buf.toString());
044                break;
045            case ERROR:
046                logger.error(buf.toString());
047                break;
048            default:
049                logger.warn(
050                    "Unknown message type enum \"" +
051                        msgType +
052                        "\" for message: " +
053                        buf.toString());
054            }
055        }
056    
057        enum MsgType {
058            INFO,
059            WARN,
060            ERROR
061        }
062    
063        public static final int DEFAULT_MSG_LIMIT = 10;
064    
065        private final int errorMsgLimit;
066        private final List<String> contexts;
067        private int errorMsgCount;
068        private int warningMsgCount;
069        private int infoMsgCount;
070        private String contextMsgCache;
071        private long startTime;
072    
073        protected AbstractRecorder() {
074            this(DEFAULT_MSG_LIMIT);
075        }
076        protected AbstractRecorder(final int errorMsgLimit) {
077            this.errorMsgLimit = errorMsgLimit;
078            this.contexts = new ArrayList<String>();
079            this.startTime = System.currentTimeMillis();
080        }
081    
082        /**
083         * Resets this MessageRecorder.
084         */
085        public void clear() {
086            errorMsgCount = 0;
087            warningMsgCount = 0;
088            infoMsgCount = 0;
089            contextMsgCache = null;
090            contexts.clear();
091            this.startTime = System.currentTimeMillis();
092        }
093    
094        public long getStartTimeMillis() {
095            return this.startTime;
096        }
097    
098        public long getRunTimeMillis() {
099            return (System.currentTimeMillis() - this.startTime);
100        }
101    
102        public boolean hasInformation() {
103            return (infoMsgCount > 0);
104        }
105        public boolean hasWarnings() {
106            return (warningMsgCount > 0);
107        }
108        public boolean hasErrors() {
109            return (errorMsgCount > 0);
110        }
111        public int getInfoCount() {
112            return infoMsgCount;
113        }
114        public int getWarningCount() {
115            return warningMsgCount;
116        }
117        public int getErrorCount() {
118            return errorMsgCount;
119        }
120    
121        public String getContext() {
122            // heavy weight
123            if (contextMsgCache == null) {
124                final StringBuilder buf = new StringBuilder();
125                int k = 0;
126                for (String name : contexts) {
127                    if (k++ > 0) {
128                        buf.append(':');
129                    }
130                    buf.append(name);
131                }
132                contextMsgCache = buf.toString();
133            }
134            return contextMsgCache;
135        }
136    
137        public void pushContextName(final String name) {
138            // light weight
139            contexts.add(name);
140            contextMsgCache = null;
141        }
142    
143        public void popContextName() {
144            // light weight
145            contexts.remove(contexts.size() - 1);
146            contextMsgCache = null;
147        }
148    
149        public void throwRTException() throws RecorderException {
150            if (hasErrors()) {
151                final String errorMsg =
152                    MondrianResource.instance().ForceMessageRecorderError.str(
153                        getContext(),
154                        errorMsgCount);
155                throw new RecorderException(errorMsg);
156            }
157        }
158    
159        public void reportError(final Exception ex)
160                throws RecorderException {
161            reportError(ex, null);
162        }
163    
164        public void reportError(final Exception ex, final Object info)
165                throws RecorderException {
166            reportError(ex.toString(), info);
167        }
168    
169        public void reportError(final String msg)
170                throws RecorderException {
171            reportError(msg, null);
172        }
173        public void reportError(final String msg, final Object info)
174                throws RecorderException {
175            errorMsgCount++;
176            recordMessage(msg, info, MsgType.ERROR);
177    
178            if (errorMsgCount >= errorMsgLimit) {
179                final String errorMsg =
180                    MondrianResource.instance().TooManyMessageRecorderErrors.str(
181                        getContext(),
182                        errorMsgCount);
183                throw new RecorderException(errorMsg);
184            }
185        }
186    
187        public void reportWarning(final String msg) {
188            reportWarning(msg, null);
189        }
190        public void reportWarning(final String msg, final Object info) {
191            warningMsgCount++;
192            recordMessage(msg, info, MsgType.WARN);
193        }
194    
195        public void reportInfo(final String msg) {
196            reportInfo(msg, null);
197        }
198        public void reportInfo(final String msg, final Object info) {
199            infoMsgCount++;
200            recordMessage(msg, info, MsgType.INFO);
201        }
202    
203        /**
204         * Handles a message.
205         * Classes implementing this abstract class must provide an implemention
206         * of this method; it receives all warning/error messages.
207         *
208         * @param msg the error or warning message.
209         * @param info the information Object which might be null.
210         * @param msgType one of the message type enum values
211         */
212        protected abstract void recordMessage(
213                String msg,
214                Object info,
215                MsgType msgType);
216    }
217    
218    // End AbstractRecorder.java