/* * Software Name : ATK * * Copyright (C) 2007 - 2012 France Télécom * * 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. * * ------------------------------------------------------------------ * File Name : ResultLogger.java * * Created : 02/03/2009 * Author(s) : Yvain Leyral */ package com.orange.atk.results.logger.log; import java.awt.image.RenderedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.imageio.ImageIO; import javax.swing.event.EventListenerList; import org.apache.log4j.Logger; import com.orange.atk.interpreter.atkCore.JATKInterpreter; import com.orange.atk.manageListener.IMeasureListener; import com.orange.atk.phone.PhoneException; import com.orange.atk.phone.PhoneInterface; import com.orange.atk.platform.Platform; import com.orange.atk.results.logger.documentGenerator.DocumentGenerator; import com.orange.atk.results.logger.documentGenerator.GraphGenerator; import com.orange.atk.results.measurement.MeasurementThread; import com.orange.atk.results.measurement.PlotList; import com.orange.atk.util.FileUtil; /** * This class is used to manage measurements and log informations */ // TODO : separate the thread and the render system public class ResultLogger { private final static EventListenerList LISETENERS = new EventListenerList(); // type of saved pictures private static final String EXT_PICTURE = "png"; // document where data and messages would be saved private DocumentLogger documentLogger = null; // class which would created the document private DocumentGenerator documentGenerator = null; // folder and files where pictures are stored private String folderWhereResultsAreSaved = null; // Thread which periodically saves data private MeasurementThread logThread = null; private PhoneInterface phoneInterface = null; private ActionsLogger actionsLogger = null; private boolean isResourceslogged = true; private String confilepath; private boolean stopATK = false; /** * Constructor * * @param folderWhereResultsAreSaved * folder where files will be saved * @param documentGenerator * generator for the document * @throws NullPointerException * if documentGenerator is null of if folderWhereResultsAreSaved * is null * @throws IllegalArgumentException * if folderWhereResultsAreSaved is not a valid folder (exists * and write right) */ public ResultLogger(String folderWhereResultsAreSaved, DocumentGenerator documentGenerator, String confilepath, boolean isResourceslogged) { this.isResourceslogged = isResourceslogged; this.confilepath = confilepath; if (folderWhereResultsAreSaved == null) { throw new NullPointerException( "folderWhereResultsAreSaved is null in Logger.<init>"); } File folder = new File(folderWhereResultsAreSaved); if (!(folder.exists() && folder.canWrite())) { throw new IllegalArgumentException(folderWhereResultsAreSaved + " does not exist or can be written."); } this.folderWhereResultsAreSaved = folderWhereResultsAreSaved; this.documentGenerator = documentGenerator; actionsLogger = new ActionsLogger(folderWhereResultsAreSaved); if (isResourceslogged) { documentLogger = new DocumentLogger(folderWhereResultsAreSaved); documentLogger.readconffile(confilepath); } } public ResultLogger(String folderWhereResultsAreSaved, DocumentGenerator documentGenerator, String confilepath) { this(folderWhereResultsAreSaved, documentGenerator, confilepath, true); } /** * generateGraphFile */ public void generateGraphFile() { // log the min/max/avg values from measurements if (isResourceslogged) { Map<String, PlotList> mapgraph = documentLogger.getMapint(); Set<String> cles = mapgraph.keySet(); Iterator<String> it = cles.iterator(); while (it.hasNext()) { String cle = (String) it.next(); PlotList plotlist = documentLogger.getPlotList((cle)); GraphGenerator.generateGraphWithJFreeChart( plotlist, cle, plotlist.getFolder(), plotlist.getYComment(), plotlist.getPngpath(), plotlist.getScale()); } } } /** * generate Plt File */ public void generatepltFile() { // log the min/max/avg values from measurements if (isResourceslogged) { Map<String, PlotList> mapgraph = documentLogger.getMapint(); Set<String> cles = mapgraph.keySet(); Iterator<String> it = cles.iterator(); while (it.hasNext()) { String cle = (String) it.next(); PlotList plotlist = documentLogger.getPlotList((cle)); // Save measurements in a file try { Logger.getLogger(this.getClass()). debug("Logger: " + folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + cle + ".csv"); GraphGenerator.dumpInFile(plotlist, folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + cle + ".csv"); plotlist.closefile(); } catch (ArrayIndexOutOfBoundsException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } } } /** * Store the action * * @param actionName * name of the action * @param startTime * time when the action has started * @param endTime * time when the action has finished */ public void addInfotoActionLogger(String MsgType, String actionName, Date startTime, Date endTime) { actionsLogger.addAction(MsgType, actionName, startTime, endTime); // insert event on the graph if (actionsLogger.isStopJATK()) phoneInterface.stopTestingMode(); } /** * Save actions made by the interpreter in the file actions.log uder the log * folderwq */ public void writeActionLogFile() { // close temp file action logger this.actionsLogger.closetempfiles(); File fichier = new File(folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + "actions.xml"); File fichierconf = new File(folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + "Confile.xml"); try { actionsLogger.save(new FileOutputStream(fichier)); } catch (FileNotFoundException e) { e.printStackTrace(); } // Copy confile to allow the analyser to read csv files FileUtil.copyfile(fichierconf, new File(confilepath)); } /** * Save actions made by the interpreter in the file actions.log uder the log * folderwq */ public void writeActionLogFile(String xmlfilepath) { // close temp file action logger this.actionsLogger.closetempfiles(); File fichier = new File(folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + "actions.xml"); File fichierconf = new File(folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + "Confile.xml"); try { actionsLogger.save(new FileOutputStream(fichier)); } catch (FileNotFoundException e) { e.printStackTrace(); } // Copy confile to allow the analyser to read csv files FileUtil.copyfile(fichierconf, new File(xmlfilepath)); } /** * Log an information message. It is generated by Log and screenshot * * @param s * message * @param line * line where this message is generated * @param currentScript * script where this message is generated */ public void addInfoToDocumentLogger(String s, int line, String currentScript) { if (isResourceslogged) documentLogger.addInfoToLog(s, line, currentScript); } /** * Log a warning message. Bad number of parameters, invalid function name, * include file not found, ... produce this kind of message * * @param s * message * @param line * line where this message is generated * @param currentScript * script where this message is generated */ public void addWarningToDocumentLogger(String s, int line, String currentScript) { if (isResourceslogged) documentLogger.addWarningToLog(s, line, currentScript); Logger.getLogger(this.getClass()).warn(currentScript + " (" + line + ") : " + s); } /** * Log an error message. Parse error in the main file, ... produce this kind * of message. * * @param s * message * @param line * line where this message is generated * @param currentScript * script where this message is generated */ public void addErrorToDocumentLogger(String s, int line, String currentScript) { if (isResourceslogged) documentLogger.addErrorToLog(s, line, currentScript); Logger.getLogger(this.getClass()).warn(currentScript + " (" + line + ") : " + s); } /** * Save cpu * * @throws NullPointerException * if setInterpreter function has not been correctly called * before */ public void addToDocumentLogger(float value, String doctype) { if (getPhoneInterface() == null || actionsLogger.isStopJATK()) { setStopATK(true); this.interrupt(); } if (isResourceslogged) { Date d = new Date(); documentLogger.addDataToList(doctype, d.getTime(), value); } } /** * Save memory, cpu, battery and storage used * * @throws PhoneException * * @throws NullPointerException * if setInterpreter function has not been correctly called * before */ public void addResourcesInfoToDocumentLogger() throws PhoneException { if (getPhoneInterface() == null || actionsLogger.isStopJATK()) { setStopATK(true); this.interrupt(); // TODO return ? } if (isResourceslogged) { Date d = new Date(); // TODO modifier pour rendre generic ?? Map<String, PlotList> mapint = documentLogger.getMapint(); Set<String> cles = mapint.keySet(); Iterator<String> it = cles.iterator(); List<String> sampledKeys = new ArrayList<String>(); while (it.hasNext()) { String cle = (String) it.next(); PlotList plotlist = mapint.get(cle); if (plotlist.isSampled()) sampledKeys.add(cle); } if (getPhoneInterface() != null && logThread != null && logThread.isRunning()) { try { HashMap<String, Long> values = getPhoneInterface().getResources(sampledKeys); cles = values.keySet(); it = cles.iterator(); while (it.hasNext()) { String cle = (String) it.next(); float v = values.get(cle).floatValue(); documentLogger.addDataToList(cle, d.getTime(), v); // fireResourceChanged(String.valueOf(v)); } } catch (PhoneException e) { addInfotoActionLogger("Error JATK", "Monitor connection lost", new Date(), new Date()); getPhoneInterface().stopTestingMode(); getPhoneInterface().startTestingMode(); } } } } protected void fireResourceChanged(String newMemValue) { for (IMeasureListener listener : getPerfListeners()) { // listener.memoryChangee( newMemValue+ Platform.LINE_SEP); } } protected void fireStorageChanged(String newMemValue) { for (IMeasureListener listener : getPerfListeners()) { // listener.storageChangee( newMemValue+ Platform.LINE_SEP); } } protected void fireActionChanged(String newMemValue) { for (IMeasureListener listener : getPerfListeners()) { listener.addactionChangee(newMemValue); } } protected void fireoutputChanged(String newMemValue) { for (IMeasureListener listener : getPerfListeners()) { listener.addOutputChangee(newMemValue); } } public void addPerfListener(IMeasureListener listener) { LISETENERS.add(IMeasureListener.class, listener); } public void removePerfListener(IMeasureListener listener) { LISETENERS.remove(IMeasureListener.class, listener); } public IMeasureListener[] getPerfListeners() { return LISETENERS.getListeners(IMeasureListener.class); } /** * Save the image image under the log folder with the name fileName * * @param fileName * name of the picture, without the extension. Not null * @param image * image to save. Not null. * @return true if the screenshot has been correctly save, false otherwise * * @throws NullPointerException * if fileName or image are null. */ public boolean saveScreenshot(String fileName, RenderedImage image) { if (fileName == null) { throw new NullPointerException("fileName is null"); } if (image == null) { throw new NullPointerException("image is null"); } File fichier = new File(folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + "screenshots" + Platform.FILE_SEPARATOR + fileName + "." + EXT_PICTURE); File directory = new File(folderWhereResultsAreSaved + Platform.FILE_SEPARATOR + "screenshots"); if (!directory.exists()) { if (!directory.mkdirs()) Logger.getLogger(this.getClass()).warn("Can't make dir " + directory.getPath()); } try { if (!ImageIO.write(image, EXT_PICTURE, fichier)) { return false; } } catch (IOException e) { e.printStackTrace(); return false; } return true; } /** * Set the currently {@link PhoneInterface} used. * * @param phoneInterface * PhoneInterface * @throws NullPointerException * if phoneInterface is null */ public void setPhoneInterface(PhoneInterface phoneInterface) { if (phoneInterface == null) { throw new NullPointerException( "A valid PhoneInterface should be provided"); } this.phoneInterface = phoneInterface; } /** * Set the currently {@link JATKInterpreter} used. This function must be * called before calling the {@link ResultLogger}.start(int iInterval) * function. This function also defines the good PhoneInterface. * * @param interpreter * interpreter * @throws NullPointerException * if interpreter is null */ public void setInterpreter(JATKInterpreter interpreter) { if (interpreter == null) { throw new NullPointerException( "A valid Interpreter should be provided"); } setPhoneInterface(interpreter.getPhoneInterface()); } /** * Start the main log of measurements * * @param iInterval * interval between each measurement * @throws IllegalArgumentException * if iInterval is equal to 0 or less * @throws NullPointerException * if a PhoneInterface has not been set before * @throws IllegalStateException * if start the thread is always alive */ public void start(int iInterval) { if (getPhoneInterface() == null) { throw new NullPointerException( "A valid PhoneInterface should be provided before calling Logger.start"); } if (logThread != null) { if (logThread.isAlive()) { throw new IllegalStateException( "The thread is always alive, called interrupt first"); } } // lance le thread de mesure logThread = new MeasurementThread(this); logThread.start(iInterval); } /** * Interrupt the log thread. * * @throws NullPointerException * if start has not been called successfully before */ public void interrupt() { if (logThread != null) { try { logThread.interrupt(); } catch (SecurityException ex) { Logger.getLogger(this.getClass()) . warn("Internal error : Current Thread is not allow to interrupt the logThread in Logger.interrupt()"); } } } /** * Wait for log thread to be totally stopped. Logger.interrupt() should be * called first. */ public void join() { if (logThread != null) { logThread.join(); logThread = null; } } /** * Indicate if the current log system is working. * * @return true if the main log system is running, false otherwise. */ public boolean isAlive() { if (logThread == null) { return false; } return logThread.isAlive(); } /** * This function saves the informations logged in the DocumentLogger in a * human readable file. * * @param isParseErrorHappened * if true, prevent the file system from saving measurements * graphs */ public void dumpInStream(boolean isParseErrorHappened) { if (isResourceslogged && documentGenerator != null) documentGenerator.dumpInStream(isParseErrorHappened, documentLogger); } public PhoneInterface getPhoneInterface() { return phoneInterface; } public void setStopATK(boolean stopATK) { this.stopATK = stopATK; } public boolean isStopATK() { return stopATK; } public DocumentLogger getDocumentLogger() { return documentLogger; } public void setDocumentLogger(DocumentLogger documentLogger) { this.documentLogger = documentLogger; } public ActionsLogger getActionsLogger() { return actionsLogger; } }