001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.actor;
031
032import java.io.File;
033import java.io.IOException;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.kepler.io.MappedLog;
038
039import ptolemy.actor.TypedAtomicActor;
040import ptolemy.actor.TypedIOPort;
041import ptolemy.data.BooleanToken;
042import ptolemy.data.StringToken;
043import ptolemy.data.expr.FileParameter;
044import ptolemy.data.expr.Parameter;
045import ptolemy.data.type.BaseType;
046import ptolemy.kernel.CompositeEntity;
047import ptolemy.kernel.util.IllegalActionException;
048import ptolemy.kernel.util.NameDuplicationException;
049
050//////////////////////////////////////////////////////////////////////////
051//// MappedLogger
052
053/**
054 * Log a string (single-line) into a file but also keep all text in a HashSet so
055 * that the strings can quickly looked up. This actor is useful to create simple
056 * checkpoint mechanism.
057 * 
058 * At first call, MappedLogger looks for the specified file and reads it into
059 * memory if exists.
060 * 
061 * At each call, the MappedLogger checks if a the input line already is in the
062 * set. If not, it writes the line into the set and the file. It returns the
063 * boolean flag indicating whether the line was already found (true) or not
064 * (false). The check and write is an atomic operation, so two actors cannot mix
065 * up this behaviour.
066 * 
067 * All MappedLogger actors can write into the same file, if their parameter
068 * points to the same file. This allows checking if others already did (and
069 * logged) something.
070 * 
071 * Query only (not writing out a line, but only checking its existence) can be
072 * achieved by setting the boolean flag 'checkOnly'.
073 * 
074 * If the line is empty (or only white spaces), nothing will be written and
075 * false will be returned.
076 * 
077 * @author Norbert Podhorszki
078 * @version $Id: MappedLogger.java 24234 2010-05-06 05:21:26Z welker $
079 * @since Ptolemy II 5.0.1
080 */
081public class MappedLogger extends TypedAtomicActor {
082        /**
083         * Construct an actor with the given container and name.
084         * 
085         * @param container
086         *            The container.
087         * @param name
088         *            The name of this actor.
089         * @exception IllegalActionException
090         *                If the actor cannot be contained by the proposed
091         *                container.
092         * @exception NameDuplicationException
093         *                If the container already has an actor with this name.
094         */
095        public MappedLogger(CompositeEntity container, String name)
096                        throws NameDuplicationException, IllegalActionException {
097                super(container, name);
098
099                // Logger file parameter
100                logfile = new FileParameter(this, "logfile");
101                logfile.setExpression("$CWD" + File.separator + "kepler.ckpt");
102
103                // line
104                line = new TypedIOPort(this, "line", true, false);
105                line.setTypeEquals(BaseType.STRING);
106                new Parameter(line, "_showName", BooleanToken.FALSE);
107
108                // flag: check only the line in already existing text
109                checkOnly = new Parameter(this, "checkOnly", new BooleanToken(false));
110                checkOnly.setTypeEquals(BaseType.BOOLEAN);
111
112                // return value: true if the text is found in the map
113                found = new TypedIOPort(this, "found", false, true);
114                found.setTypeEquals(BaseType.BOOLEAN);
115                new Parameter(found, "_showName", BooleanToken.FALSE);
116
117        }
118
119        /***********************************************************
120         * ports and parameters
121         */
122
123        /**
124         * The log file. It can be changed between firings. The file will be created
125         * if does not exists. If exists its content will be read before the first
126         * execution.
127         */
128        public FileParameter logfile;
129
130        /**
131         * The text to be printed into the log. It must be single-line (no newline)
132         * This port expects strings.
133         */
134        public TypedIOPort line;
135
136        /**
137         * Boolean flag. If true, input will only be checked against already
138         * existing texts but will not be printed out.
139         */
140        public Parameter checkOnly;
141
142        /**
143         * The boolean return value. True if the line is found in the already
144         * existing text.
145         */
146        public TypedIOPort found;
147
148        /***********************************************************
149         * public methods
150         */
151
152        /**
153         * Nothing to do currently.
154         */
155        public void initialize() throws IllegalActionException {
156                super.initialize();
157                _mappedLog = new MappedLog();
158        }
159
160        /**
161         * fire
162         * 
163         * @exception IllegalActionException
164         *                Not thrown.
165         */
166        public void fire() throws IllegalActionException {
167                super.fire();
168
169                String logText = ((StringToken) line.get(0)).stringValue();
170                boolean bCheckOnly = ((BooleanToken) checkOnly.getToken())
171                                .booleanValue();
172
173                // do the work
174                boolean bFound;
175                if (bCheckOnly) {
176                        bFound = _mappedLog.check(logfile.asFile(), logText);
177                } else {
178                        bFound = _mappedLog.add(logfile.asFile(), logText);
179                }
180
181                if (isDebugging)
182                        log.debug("Return " + bFound);
183                found.send(0, new BooleanToken(bFound));
184        }
185
186        /**
187         * Close all opened log files. This method is invoked exactly once per
188         * execution of an application. None of the other action methods should be
189         * be invoked after it.
190         * 
191         * @exception IllegalActionException
192         *                Not thrown in this base class.
193         */
194        public void wrapup() throws IllegalActionException {
195                super.wrapup();
196                if (isDebugging)
197                        log.debug("wrapup begin");
198                try {
199                        _mappedLog.closeAll();
200                } catch (IOException ex) {
201                        log.error("Error at wrapup: " + ex);
202                }
203                if (isDebugging)
204                        log.debug("wrapup end");
205        }
206
207        /**
208         * Close all opened log files. This method is invoked exactly once per
209         * execution of an application. None of the other action methods should be
210         * be invoked after it.
211         * 
212         * @exception IllegalActionException
213         *                Not thrown in this base class.
214         */
215        public void stop() {
216                if (isDebugging)
217                        log.debug("stop begin");
218                super.stop();
219                try {
220                        _mappedLog.closeAll();
221                } catch (IOException ex) {
222                        log.error("Error at stop: " + ex);
223                }
224                if (isDebugging)
225                        log.debug("stop end");
226        }
227
228        private MappedLog _mappedLog;
229
230        // apache commons log for the source code logging.
231        private static final Log log = LogFactory.getLog(MappedLogger.class
232                        .getName());
233        private static final boolean isDebugging = log.isDebugEnabled();
234
235}