diff options
Diffstat (limited to 'framework/qa/complex/framework/autosave')
-rw-r--r-- | framework/qa/complex/framework/autosave/AutoSave.java | 454 | ||||
-rw-r--r-- | framework/qa/complex/framework/autosave/ConfigHelper.java | 124 | ||||
-rw-r--r-- | framework/qa/complex/framework/autosave/Protocol.java | 999 | ||||
-rw-r--r-- | framework/qa/complex/framework/autosave/makefile.mk | 89 |
4 files changed, 1666 insertions, 0 deletions
diff --git a/framework/qa/complex/framework/autosave/AutoSave.java b/framework/qa/complex/framework/autosave/AutoSave.java new file mode 100644 index 000000000000..015d9771be59 --- /dev/null +++ b/framework/qa/complex/framework/autosave/AutoSave.java @@ -0,0 +1,454 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package complex.framework.autosave; + +import com.sun.star.frame.*; +import com.sun.star.lang.*; +import com.sun.star.util.*; +import com.sun.star.beans.*; +import com.sun.star.uno.*; +import com.sun.star.sheet.*; +import com.sun.star.table.*; + +import java.util.*; + +import complexlib.*; +import helper.*; +import util.*; + +//----------------------------------------------- +/** @short Check some use cases of the AutoSave feature + */ +public class AutoSave extends ComplexTestCase +{ + //------------------------------------------- + class AutoSaveListener implements XStatusListener + { + private XDispatch m_xAutoSave; + private URL m_aRegistration; + private Protocol m_aLog; + + public AutoSaveListener(XMultiServiceFactory xSMGR , + XDispatch xAutoSave, + Protocol aLog ) + { + m_aLog = aLog; + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "create listener for AutoSave notifications ..."); + + try + { + m_xAutoSave = xAutoSave; + + XURLTransformer xParser = (XURLTransformer)UnoRuntime.queryInterface( + XURLTransformer.class, + xSMGR.createInstance("com.sun.star.util.URLTransformer")); + URL[] aURL = new URL[1]; + aURL[0] = new URL(); + aURL[0].Complete = "vnd.sun.star.autorecovery:/doAutoSave"; + xParser.parseStrict(aURL); + m_aRegistration = aURL[0]; + + m_xAutoSave.addStatusListener(this, m_aRegistration); + m_aLog.log(Protocol.TYPE_INFO, "successfully registered as AutoSave listener."); + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, ""); + } + + public void disableListener() + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "stop listening for AutoSave notifications ..."); + + XDispatch xAutoSave = null; + URL aRegURL = null; + synchronized (this) + { + xAutoSave = m_xAutoSave; + aRegURL = m_aRegistration; + } + + try + { + if ( + (xAutoSave != null) && + (aRegURL != null) + ) + xAutoSave.removeStatusListener(this, aRegURL); + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, ""); + } + + public void statusChanged(FeatureStateEvent aEvent) + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "statusChanged() called from AutoSave ..."); + + m_aLog.log("FeatureURL = \""+aEvent.FeatureURL.Complete+"\"" ); + m_aLog.log("FeatureDescriptor = \""+aEvent.FeatureDescriptor+"\"" ); + m_aLog.log("IsEnabled = \""+aEvent.IsEnabled+"\"" ); + m_aLog.log("Requery = \""+aEvent.Requery+"\"" ); + m_aLog.log("State:" ); + m_aLog.log(aEvent.State ); + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, ""); + } + + public void disposing(com.sun.star.lang.EventObject aEvent) + { + m_aLog.log(Protocol.TYPE_INFO, "disposing() called from AutoSave."); + synchronized(this) + { + m_xAutoSave = null; + m_aRegistration = null; + } + } + } + + //------------------------------------------- + // some const + + //------------------------------------------- + // member + + private Protocol m_aLog; + + /** points to the global uno service manager. */ + private XMultiServiceFactory m_xSMGR = null; + + private SOfficeFactory m_aSOF; + + /** can be used to trigger/enable/disable the AutoSave feature. */ + private XDispatch m_xAutoSave = null; + + /** a test document, which needs some time for saving to simulate concurrent + * save operations. */ + private XStorable m_xTestDoc = null; + + private XURLTransformer m_xURLParser = null; + + //------------------------------------------- + // test environment + + //------------------------------------------- + /** @short A function to tell the framework, + which test functions are available. + + @return All test methods. + @todo Think about selection of tests from outside ... + */ + public String[] getTestMethodNames() + { + return new String[] + { + "checkConcurrentAutoSaveToNormalUISave", + }; + } + + //------------------------------------------- + /** @short Create the environment for following tests. + + @descr create an empty test frame, where we can load + different components inside. + */ + public void before() + { + m_aLog = new Protocol(Protocol.MODE_HTML | Protocol.MODE_STDOUT, Protocol.FILTER_NONE, utils.getUsersTempDir() + "/complex_log_ascii_01.html"); + + try + { + // get uno service manager from global test environment + m_xSMGR = (XMultiServiceFactory)param.getMSF(); + + // get another helper to e.g. create test documents + m_aSOF = SOfficeFactory.getFactory(m_xSMGR); + + // create AutoSave instance + m_xAutoSave = (XDispatch)UnoRuntime.queryInterface( + XDispatch.class, + m_xSMGR.createInstance("com.sun.star.comp.framework.AutoRecovery")); + + // prepare AutoSave + // make sure it will be started every 1 min + ConfigHelper aConfig = new ConfigHelper(m_xSMGR, "org.openoffice.Office.Recovery", false); + aConfig.writeRelativeKey("AutoSave", "Enabled" , Boolean.TRUE ); + aConfig.writeRelativeKey("AutoSave", "TimeIntervall", new Integer(1)); // 1 min + aConfig.flush(); + aConfig = null; + + // is needed to parse dispatch commands + m_xURLParser = (XURLTransformer)UnoRuntime.queryInterface( + XURLTransformer.class, + m_xSMGR.createInstance("com.sun.star.util.URLTransformer")); + + } + catch(java.lang.Throwable ex) + { + m_aLog.log(ex); + failed("Couldn't create test environment"); + } + } + + //------------------------------------------- + /** @short close the environment. + */ + public void after() + { + // ??? + } + + //------------------------------------------- + // create a calc document with content, which needs some time for saving + private XInterface createBigCalcDoc() + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "createBigCalcDoc() started ..."); + try + { + m_aLog.log("Create empty calc document for testing."); + XSpreadsheetDocument xSheetDoc = m_aSOF.createCalcDoc("_default"); + m_aLog.log("Retrieve first sheet from calc document."); + XSpreadsheets xSheets = xSheetDoc.getSheets(); + XSpreadsheet xSheet = (XSpreadsheet)AnyConverter.toObject( + new Type(XSpreadsheet.class), + xSheets.getByName( + xSheets.getElementNames()[0])); + m_aLog.log("Fill two cells with value and formula."); + xSheet.getCellByPosition(0, 0).setValue(1); + xSheet.getCellByPosition(0, 1).setFormula("=a1+1"); + m_aLog.log("Retrieve big range."); + XCellRange xRange = xSheet.getCellRangeByName("A1:Z9999"); + XCellSeries xSeries = (XCellSeries)UnoRuntime.queryInterface( + XCellSeries.class, + xRange); + m_aLog.log("Duplicate cells from top to bottom inside range."); + xSeries.fillAuto(FillDirection.TO_BOTTOM, 2); + m_aLog.log("Duplicate cells from left to right inside range."); + xSeries.fillAuto(FillDirection.TO_RIGHT , 1); + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE | Protocol.TYPE_OK, "createBigCalcDoc() finished."); + return xSheetDoc; + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "createBigCalcDoc() finished."); + return null; + } + + //------------------------------------------- + private void saveDoc(XInterface xDoc, + String sURL) + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "saveDoc('"+sURL+"') started ..."); + try + { + URL[] aURL = new URL[1]; + aURL[0] = new URL(); + aURL[0].Complete = ".uno:SaveAs"; + m_xURLParser.parseStrict(aURL); + + XModel xModel = (XModel)UnoRuntime.queryInterface( + XModel.class, + xDoc); + XDispatchProvider xProvider = (XDispatchProvider)UnoRuntime.queryInterface( + XDispatchProvider.class, + xModel.getCurrentController()); + XDispatch xDispatch = xProvider.queryDispatch(aURL[0], "_self", 0); + + PropertyValue[] lArgs = new PropertyValue[3]; + lArgs[0] = new PropertyValue(); + lArgs[0].Name = "URL"; + lArgs[0].Value = sURL; + lArgs[1] = new PropertyValue(); + lArgs[1].Name = "Overwrite"; + lArgs[1].Value = Boolean.TRUE; + lArgs[2] = new PropertyValue(); + lArgs[2].Name = "StoreTo"; + lArgs[2].Value = Boolean.TRUE; + + xDispatch.dispatch(aURL[0], lArgs); + + m_aLog.log(Protocol.TYPE_OK, "saveDoc('"+sURL+"') = OK."); + } +/* + catch(com.sun.star.io.IOException exIO) + { + m_aLog.log(Protocol.TYPE_WARNING , "got IOException on calling doc.store()." ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "Please check the reason for that more in detail." ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "A message like \"Concurrent save requests are not allowed.\" was intended and doesnt show an error!"); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "Message of the original exception:" ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, exIO.getMessage()); + } +*/ + catch(Throwable ex) + { + m_aLog.log(ex); + } + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "saveDoc('"+sURL+"') finished."); + } + + //------------------------------------------- + private void closeDoc(XInterface xDoc) + { + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "closeDoc() started ..."); + + try + { + Random aRandom = new Random(); + int nRetry = 5; + while(nRetry>0) + { + try + { + XCloseable xClose = (XCloseable)UnoRuntime.queryInterface( + XCloseable.class, + xDoc); + if (xClose != null) + { + xClose.close(false); + m_aLog.log(Protocol.TYPE_OK, "closeDoc() = OK."); + nRetry = 0; + } + else + m_aLog.log(Protocol.TYPE_ERROR, "closeDoc() = ERROR. Doc doesnt provide needed interface!"); + } + catch(com.sun.star.util.CloseVetoException exVeto) + { + m_aLog.log(Protocol.TYPE_WARNING , "got CloseVetoException on calling doc.close()." ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "Please check the reason for that more in detail." ); + m_aLog.log(Protocol.TYPE_WARNING_INFO, "A message like \"Cant close while saving.\" was intended and doesnt show an error!"); + m_aLog.log(Protocol.TYPE_WARNING_INFO, exVeto.getMessage()); + } + + if (nRetry > 0) + { + --nRetry; + long nWait = (long)aRandom.nextInt(30000); // 30 sec. + try + { + m_aLog.log(Protocol.TYPE_INFO, "sleep for "+nWait+" ms"); + synchronized(this) + { + wait(nWait); + } + } + catch(Throwable ex) + { + m_aLog.log(Protocol.TYPE_WARNING , "got exception for wait() !?"); + m_aLog.log(Protocol.TYPE_WARNING_INFO, ex.getMessage()); + } + } + } + } + catch(Throwable ex) + { + m_aLog.log(ex); + } + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "closeDoc() finished."); + } + + class DocThread extends Thread + { + DocThread() + {} + + public void run() + { + impl_checkConcurrentAutoSaveToNormalUISave(); + } + } + + //------------------------------------------- + /** @short check concurrent save requests to the same document + * at the same time. + * + * @descr First we simulate an UI save by dispatching the right URL + * to the document and at the same time we try to trigger an AutoSave + * from another thread. So these operations should be started at the same time. + * It should not crash. The AutoSave request must be postphoned. + */ + public void checkConcurrentAutoSaveToNormalUISave() + { + m_aLog.log(Protocol.TYPE_TESTMARK , "AutoSave"); + m_aLog.log(Protocol.TYPE_SCOPE_OPEN, "checkConcurrentAutoSaveToNormalUISave()"); + + AutoSaveListener xListener = new AutoSaveListener(m_xSMGR, m_xAutoSave, m_aLog); + + try + { + DocThread aThread = new DocThread(); + aThread.start(); + aThread.join(); + } + catch(Throwable ex) + {} + + xListener.disableListener(); + + m_aLog.log(Protocol.TYPE_SCOPE_CLOSE, "checkConcurrentAutoSaveToNormalUISave()"); + m_aLog.logStatistics(); + } + + public void impl_checkConcurrentAutoSaveToNormalUISave() + { + Random aRandom = new Random(); + + int i = 0; + int c = 5; + for (i=0; i<c; ++i) + { + XInterface xDoc = createBigCalcDoc(); + try + { + long nWait = (long)aRandom.nextInt(120000); + m_aLog.log(Protocol.TYPE_INFO, "sleep for "+nWait+" ms"); + synchronized(this) + { + wait(nWait); + } + } + catch(Throwable ex) + { + m_aLog.log(Protocol.TYPE_WARNING , "got exception for wait() !?"); + m_aLog.log(Protocol.TYPE_WARNING_INFO, ex.getMessage()); + } + saveDoc(xDoc, utils.getOfficeTemp(m_xSMGR) + "/test_calc.ods"); + closeDoc(xDoc); + } + } +} diff --git a/framework/qa/complex/framework/autosave/ConfigHelper.java b/framework/qa/complex/framework/autosave/ConfigHelper.java new file mode 100644 index 000000000000..3bc4683f4fb5 --- /dev/null +++ b/framework/qa/complex/framework/autosave/ConfigHelper.java @@ -0,0 +1,124 @@ +package complex.framework.autosave; + +import java.lang.*; +import com.sun.star.uno.*; +import com.sun.star.lang.*; +import com.sun.star.container.*; +import com.sun.star.beans.*; +import com.sun.star.util.*; + +class ConfigHelper +{ + private XMultiServiceFactory m_xSMGR = null; + private XHierarchicalNameAccess m_xConfig = null; + + //----------------------------------------------- + public ConfigHelper(XMultiServiceFactory xSMGR , + String sConfigPath , + boolean bReadOnly ) + throws com.sun.star.uno.Exception + { + m_xSMGR = xSMGR; + + XMultiServiceFactory xConfigRoot = (XMultiServiceFactory)UnoRuntime.queryInterface( + XMultiServiceFactory.class, + m_xSMGR.createInstance("com.sun.star.configuration.ConfigurationProvider")); + + PropertyValue[] lParams = new PropertyValue[1]; + lParams[0] = new PropertyValue(); + lParams[0].Name = "nodepath"; + lParams[0].Value = sConfigPath; + + Object aConfig; + if (bReadOnly) + aConfig = xConfigRoot.createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + lParams); + else + aConfig = xConfigRoot.createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + lParams); + + m_xConfig = (XHierarchicalNameAccess)UnoRuntime.queryInterface( + XHierarchicalNameAccess.class, + aConfig); + + if (m_xConfig == null) + throw new com.sun.star.uno.Exception("Could not open configuration \""+sConfigPath+"\""); + } + + //----------------------------------------------- + public Object readRelativeKey(String sRelPath, + String sKey ) + throws com.sun.star.container.NoSuchElementException + { + try + { + XPropertySet xPath = (XPropertySet)UnoRuntime.queryInterface( + XPropertySet.class, + m_xConfig.getByHierarchicalName(sRelPath)); + return xPath.getPropertyValue(sKey); + } + catch(com.sun.star.uno.Exception ex) + { + throw new com.sun.star.container.NoSuchElementException(ex.getMessage()); + } + } + + //----------------------------------------------- + public void writeRelativeKey(String sRelPath, + String sKey , + Object aValue ) + throws com.sun.star.container.NoSuchElementException + { + try + { + XPropertySet xPath = (XPropertySet)UnoRuntime.queryInterface( + XPropertySet.class, + m_xConfig.getByHierarchicalName(sRelPath)); + xPath.setPropertyValue(sKey, aValue); + } + catch(com.sun.star.uno.Exception ex) + { + throw new com.sun.star.container.NoSuchElementException(ex.getMessage()); + } + } + + //----------------------------------------------- + public void flush() + { + try + { + XChangesBatch xBatch = (XChangesBatch)UnoRuntime.queryInterface( + XChangesBatch.class, + m_xConfig); + xBatch.commitChanges(); + } + catch(com.sun.star.uno.Exception ex) + {} + } + + //----------------------------------------------- + public static Object readDirectKey(XMultiServiceFactory xSMGR , + String sConfigFile, + String sRelPath , + String sKey ) + throws com.sun.star.uno.Exception + { + ConfigHelper aConfig = new ConfigHelper(xSMGR, sConfigFile, true); + return aConfig.readRelativeKey(sRelPath, sKey); + } + + //----------------------------------------------- + public static void writeDirectKey(XMultiServiceFactory xSMGR , + String sConfigFile, + String sRelPath , + String sKey , + Object aValue ) + throws com.sun.star.uno.Exception + { + ConfigHelper aConfig = new ConfigHelper(xSMGR, sConfigFile, false); + aConfig.writeRelativeKey(sRelPath, sKey, aValue); + aConfig.flush(); + } +} diff --git a/framework/qa/complex/framework/autosave/Protocol.java b/framework/qa/complex/framework/autosave/Protocol.java new file mode 100644 index 000000000000..11f6c4eeeff3 --- /dev/null +++ b/framework/qa/complex/framework/autosave/Protocol.java @@ -0,0 +1,999 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +package complex.framework.autosave; + +// __________ Imports __________ + +// structs, const, ... +import com.sun.star.beans.PropertyValue; +import com.sun.star.bridge.XUnoUrlResolver; + +// exceptions +import com.sun.star.container.NoSuchElementException; +import com.sun.star.uno.Exception; +import com.sun.star.uno.RuntimeException; +import java.io.IOException; +import java.lang.InterruptedException; +import java.net.ConnectException; + +// interfaces +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.Any; + +// helper +import com.sun.star.uno.IBridge; +import com.sun.star.uno.UnoRuntime; + +// others +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.lang.*; +import java.io.*; +import java.util.*; +import java.sql.*; + +// __________ Implementation __________ + +/** + * Implements a log mechanism to create a protocol of all steps of e.g. an api test + * It provides the possibility to write the logged meesages to a file and/or + * to stdout/stderr (if neccessary at the same time!). + * + * TODO + * - implement filter, which e.g. supress showing of INFO data + */ +public class Protocol extends JComponent +{ + // ____________________ + /** + * Note: Following values can be combined - they are interpreted as flags. + * + * @const MODE_STDOUT messages are logged to stdout + * @const MODE_STDERR messages are logged to stderr + * @const MODE_ASCII messages are logged to an ascii file + * @const MODE_HTML messages are logged to a html file + * + * @const TYPE_SCOPE_OPEN open, mark or count a new scope for following log statements + * @const TYPE_SCOPE_CLOSE close, mark or count the current scope + * @const TYPE_TESTMARK it marks the beginning of a (sub)test, can be used for statistic purposes + * @const TYPE_OK this protocol line is marked as a OK message + * @const TYPE_ERROR this protocol line is marked as an error + * @const TYPE_WARNING this protocol line is marked as a warning + * @const TYPE_INFO this protocol line represent some debug data for analyzing + */ + public static final int MODE_STDOUT = 1; + public static final int MODE_STDERR = 2; + public static final int MODE_ASCII = 4; + public static final int MODE_HTML = 8; + + public static final int TYPE_OK = 1; + public static final int TYPE_ERROR = 2; + public static final int TYPE_WARNING = 4; + public static final int TYPE_INFO = 8; + public static final int TYPE_SCOPE_OPEN = 16; + public static final int TYPE_SCOPE_CLOSE = 32; + public static final int TYPE_TESTMARK = 64; + public static final int TYPE_ERROR_INFO = 128; + public static final int TYPE_WARNING_INFO = 256; + public static final int TYPE_STATISTIC = 512; + public static final int TYPE_LINK = 1024; + + public static final int FILTER_NONE = 0; + public static final int FILTER_OK = TYPE_OK; + public static final int FILTER_ERROR = TYPE_ERROR; + public static final int FILTER_WARNING = TYPE_WARNING; + public static final int FILTER_INFO = TYPE_INFO; + public static final int FILTER_SCOPES = TYPE_SCOPE_OPEN | TYPE_SCOPE_CLOSE; + public static final int FILTER_TESTMARK = TYPE_TESTMARK; + public static final int FILTER_ERROR_INFO = TYPE_ERROR_INFO; + public static final int FILTER_WARNING_INFO = TYPE_WARNING_INFO; + public static final int FILTER_STATISTIC = TYPE_STATISTIC; + public static final int FILTER_LINK = TYPE_LINK; + + // ____________________ + /** + */ + private static final int MARK_DIFF = 5; + + private static final String BGCOLOR_LINECOL = "#95CC77"; + private static final String FGCOLOR_LINECOL_NORMAL = "#ffffbd"; + private static final String FGCOLOR_LINECOL_MARKED = "#000088"; + + private static final String BGCOLOR_STANDARD = "#ffffff"; + private static final String FGCOLOR_STANDARD = "#000000"; + + private static final String BGCOLOR_SCOPE = "#eeeeee"; + private static final String FGCOLOR_SCOPE = "#000000"; + + private static final String BGCOLOR_TIMESTAMP = "#e0e0e0"; + private static final String FGCOLOR_TIMESTAMP = "#000000"; + + private static final String BGCOLOR_TESTMARK = "#0000ff"; + private static final String FGCOLOR_TESTMARK = "#ffffff"; + + private static final String BGCOLOR_OK = "#88dd88"; + private static final String FGCOLOR_OK = "#ffffff"; + + private static final String BGCOLOR_WARNING = "#ffff00"; + private static final String FGCOLOR_WARNING = "#000000"; + + private static final String BGCOLOR_WARNING_INFO = "#ffffcc"; + private static final String FGCOLOR_WARNING_INFO = "#000000"; + + private static final String BGCOLOR_ERROR = "#ff0000"; + private static final String FGCOLOR_ERROR = "#ffff00"; + + private static final String BGCOLOR_ERROR_INFO = "#ffbbbb"; + private static final String FGCOLOR_ERROR_INFO = "#000000"; + + private static final String BGCOLOR_INFO = "#eeeeee"; + private static final String FGCOLOR_INFO = "#000000"; + + private static final String BGCOLOR_STATISTIC = "#0000ff"; + private static final String FGCOLOR_STATISTIC = "#ffffff"; + + private static final String BGCOLOR_LINK = BGCOLOR_INFO; + private static final String FGCOLOR_LINK = FGCOLOR_INFO; + + // ____________________ + /** + * @member m_nMode the mode, in which this protocol object runs + * @member m_nFilter can be used to filter log messages by type + * @member m_sFileName we need it to open the log file on demand (if nMode require such log file) + * @member m_nLine used as line number for the protocol + * @member m_nScope used to format scopes + * @member m_nErrors count errors in protocol + * @member m_nWarnings count warnings in protocol + * @member m_nTestMarks count test marker in protocol + */ + private int m_nMode ; + private int m_nFilter ; + private String m_sFileName ; + private long m_nLine ; + private long m_nScope ; + private long m_nErrors ; + private long m_nWarnings ; + private long m_nTestMarks; + private Timestamp m_aStartTime; + private Timestamp m_aEndTime ; + + // ____________________ + /** + * special helper class to represent one line of a protocol. + * Such line can be specified as a special one (ERROR, WARNING ...). + * That makes it possible to analyze the whole protocol using tools. + */ + class ProtocolLine + { + /// the line number of this protocol line (size of the vector of all protocol lines cn be used to count such lines!) + private long m_nLine; + /// deepness of the current scope + private long m_nScope; + /// mark line as an error, warning, data entry ... (see const definitions before) + private int m_nType; + /// of course, we have to know the logged message too :-) + private String m_sMessage; + /// and it can be usefull to know the current time, when this line was created + private Timestamp m_aStamp; + + /** ctor for fast initializing of such line */ + public ProtocolLine( long nLine , + long nScope , + int nType , + String sMessage ) + { + m_aStamp = new Timestamp(System.currentTimeMillis()); + m_nLine = nLine ; + m_nScope = nScope ; + m_nType = nType ; + m_sMessage = sMessage; + } + + /** format this line as an ascii string for writing log files */ + public synchronized String toString() + { + StringBuffer sLine = new StringBuffer(1000); + + // insert line number + // Use right bound notation and format 6 digits! + sLine.append("[" ); + if (m_nLine<10) + sLine.append(" "); + else + if (m_nLine<100) + sLine.append(" "); + else + if (m_nLine<1000) + sLine.append(" "); + else + if (m_nLine<10000) + sLine.append(" "); + else + if (m_nLine<100000) + sLine.append(" "); + sLine.append(m_nLine); + sLine.append("] " ); + + // add time stamp + // close with a "TAB" ... because some time stamps are not normalized to + // a well defined string length .-) + sLine.append(m_aStamp.toString()+" \t"); + + // add special line type + if ((m_nType & TYPE_OK) == TYPE_OK) + sLine.append(" OK "); + else + if ((m_nType & TYPE_ERROR) == TYPE_ERROR) + sLine.append(" ERROR "); + else + if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO) + sLine.append(" ERROR INFO "); + else + if ((m_nType & TYPE_WARNING) == TYPE_WARNING) + sLine.append(" WARNING "); + else + if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO) + sLine.append(" WARNING INFO "); + else + if ((m_nType & TYPE_INFO) == TYPE_INFO) + sLine.append(" INFO "); + else + if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK) + sLine.append(" TEST "); + else + if ((m_nType & TYPE_LINK) == TYPE_LINK) + sLine.append(" LINK "); + else + if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC) + sLine.append(" STATISTIC "); + else + if ( + ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) || + ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + ) + sLine.append(" SCOPE "); + else + sLine.append(" "); + + // add scope information + for (int s=0; s<m_nScope; ++s) + sLine.append(" "); + + if ((m_nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN) + sLine.append(" { "); + else + if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + sLine.append(" } "); + else + sLine.append(" "); + + // add message + sLine.append(m_sMessage); + sLine.append("\n" ); + + return sLine.toString(); + } + + /** + * format this line as a string for writing log files + * using the html format + */ + public synchronized String toHTML() + { + StringBuffer sLine = new StringBuffer(1000); + sLine.append("<tr>"); + + // insert line number + if (m_nLine % MARK_DIFF == 0) + impl_generateColoredHTMLCell(sLine, new Long(m_nLine).toString(), BGCOLOR_LINECOL, FGCOLOR_LINECOL_MARKED, true); + else + impl_generateColoredHTMLCell(sLine, new Long(m_nLine).toString(), BGCOLOR_LINECOL, FGCOLOR_LINECOL_NORMAL, false); + + // add time stamp + impl_generateColoredHTMLCell(sLine, m_aStamp.toString()+" ", BGCOLOR_TIMESTAMP, FGCOLOR_TIMESTAMP, false); + + // add log type info + boolean bTypeCellFilled = false; + if ((m_nType & TYPE_ERROR_INFO) == TYPE_ERROR_INFO) + { + impl_generateColoredHTMLCell(sLine, "ERROR INFO", BGCOLOR_ERROR_INFO, FGCOLOR_ERROR_INFO, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_ERROR) == TYPE_ERROR) + { + impl_generateColoredHTMLCell(sLine, "ERROR", BGCOLOR_ERROR, FGCOLOR_ERROR, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_WARNING_INFO) == TYPE_WARNING_INFO) + { + impl_generateColoredHTMLCell(sLine, "WARNING INFO", BGCOLOR_WARNING_INFO, FGCOLOR_WARNING_INFO, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_WARNING) == TYPE_WARNING) + { + impl_generateColoredHTMLCell(sLine, "WARNING", BGCOLOR_WARNING, FGCOLOR_WARNING, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_OK) == TYPE_OK) + { + impl_generateColoredHTMLCell(sLine, "OK", BGCOLOR_OK, FGCOLOR_OK, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_INFO) == TYPE_INFO) + { + impl_generateColoredHTMLCell(sLine, "INFO", BGCOLOR_INFO, FGCOLOR_INFO, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK) + { + impl_generateColoredHTMLCell(sLine, "TEST", BGCOLOR_TESTMARK, FGCOLOR_TESTMARK, true); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_STATISTIC) == TYPE_STATISTIC) + { + impl_generateColoredHTMLCell(sLine, "STATISTIC", BGCOLOR_STATISTIC, FGCOLOR_STATISTIC, false); + bTypeCellFilled = true; + } + else + if ((m_nType & TYPE_LINK) == TYPE_LINK) + { + impl_generateColoredHTMLCell(sLine, "LINK", BGCOLOR_LINK, FGCOLOR_LINK, false); + bTypeCellFilled = true; + } + else + if ( + ((m_nType & TYPE_SCOPE_OPEN ) == TYPE_SCOPE_OPEN ) || + ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + ) + { + impl_generateColoredHTMLCell(sLine, "SCOPE", BGCOLOR_SCOPE, FGCOLOR_SCOPE, false); + bTypeCellFilled = true; + } + + // if no tyope information was added to the current coloum, we must + // write any content into this cell. Otherwise some browser + // shows a strange layout! + if (! bTypeCellFilled) + impl_generateColoredHTMLCell(sLine, " ", BGCOLOR_STANDARD, FGCOLOR_STANDARD, false); + + // add scope information + sLine.append("<td>"); + for (int s=0; s<m_nScope; ++s) + sLine.append(" "); + String sColor = "#000000"; + if ((m_nScope % 2) == 0) + sColor = "#808080"; + if ((m_nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN) + sLine.append("<font color=\""+sColor+"\">{ "+m_nScope+"</font>"); + else + if ((m_nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + sLine.append("<font color=\""+sColor+"\">"+m_nScope+" }</font>"); + sLine.append("</td>\n"); + + // add message + sLine.append("<td>" ); + sLine.append(m_sMessage); + sLine.append("</td>\n" ); + + sLine.append("</tr>\n" ); + + return sLine.toString(); + } + + /** detect, if this line object represent an error */ + public synchronized boolean isError() + { + return ( + ((m_nType & TYPE_ERROR) == TYPE_ERROR) && + ((m_nType & TYPE_INFO ) != TYPE_INFO ) + ); + } + + /** detect, if this line object represent a warning */ + public synchronized boolean isWarning() + { + return ( + ((m_nType & TYPE_WARNING) == TYPE_WARNING) && + ((m_nType & TYPE_INFO ) != TYPE_INFO ) + ); + } + + /** detect, if this line object represent a marked position */ + public synchronized boolean isTestMark() + { + return ((m_nType & TYPE_TESTMARK) == TYPE_TESTMARK); + } + + /** + * create a colored table cell formated as HTML. + * + * @param sCell + * an outside string buffer, which can be + * used to generate the + * needed HTML code there. + * + * @param sContent + * the text content of this cell. + * + * @param sBGColor + * a string, which represent the background color + * coded in HTML. + * + * @param sFGColor + * a string, which represent the foreground color + * coded in HTML. + * + * @param bBold + * enable/disable bold state for the text content. + */ + private void impl_generateColoredHTMLCell(StringBuffer sCell , + String sContent, + String sBGColor, + String sFGColor, + boolean bBold ) + { + sCell.append("<td bgcolor=\""+sBGColor+"\">"); + sCell.append("<font color=\""+sFGColor+"\">"); + if (bBold) + sCell.append("<b>"); + sCell.append(sContent); + if (bBold) + sCell.append("</b>"); + sCell.append("</font></td>\n"); + } + } + + // ____________________ + /** + * ctor + * It creates a new instance of this class and innitialize it in the right mode. + * + * @param nMode + * specify how the log should be generated. + * + * @param nFilter + * can be used to filter log messages by it's type. + * + * @param sFileName + * the name of the log file (if nMode requires a log file) + */ + public Protocol(int nMode , + int nFilter , + String sFileName) + { + m_nMode = nMode; + m_nFilter = nFilter; + m_sFileName = sFileName; + m_nLine = 0; + m_nScope = 1; + m_nWarnings = 0; + m_nErrors = 0; + m_aStartTime = new Timestamp(System.currentTimeMillis()); + } + + // ____________________ + /** + * For some modes it's neccessary, that we write some additional + * informations to the log. E.g. for html we must generate close targets. + */ + public synchronized void finish() + { + // Preferr HTML ... because we can't write ASCII and HTML contents to the same log file! + String sContent; + if ((m_nMode & MODE_HTML) == MODE_HTML) + sContent = impl_generateHTMLFooter(); + else + if ((m_nMode & MODE_ASCII) == MODE_ASCII) + sContent = impl_generateAsciiFooter(); + else + return; + + impl_writeToLogFile(m_sFileName, true, sContent); + } + + // ____________________ + /** + * log an unspecified message. + * + * Sometimes it's not neccessary to set a special type for an message. + * The pure message seams to be enough. The type of such "pure messages" + * will be set to INFO. + * + * @param sMessage + * the pure message + * + * @see log(type,message) + */ + public synchronized void log( /*IN*/ String sMessage ) + { + log(TYPE_INFO, sMessage); + } + + // ____________________ + /** + * log an exception. + * + * It uses all informations available by this exception object + * to generate the log. So exceptions are printed out using a + * standard format. + * + * @param exThrowable + * the exception + */ + public synchronized void log( /*IN*/ Throwable exThrowable ) + { + log(TYPE_SCOPE_OPEN | TYPE_ERROR, "exception \""+exThrowable.getMessage()+"\""); + + StackTraceElement[] lStack = exThrowable.getStackTrace(); + for (int i=0; i<lStack.length; ++i) + log(TYPE_ERROR_INFO, lStack[i].toString()); + + log(TYPE_SCOPE_CLOSE | TYPE_ERROR_INFO, ""); + } + + // ____________________ + /** + * log different property arrays. + * + * @param lProps + * the array of properties + */ + public synchronized void log( /*IN*/ com.sun.star.beans.NamedValue[] lProps ) + { + StringBuffer sValues = new StringBuffer(1000); + impl_logPropertyArray(sValues, lProps); + + log(TYPE_SCOPE_OPEN | TYPE_INFO, "property array ["+lProps.length+"]:"); + log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValues.toString() ); + } + + public synchronized void log( /*IN*/ com.sun.star.beans.PropertyValue[] lProps ) + { + StringBuffer sValues = new StringBuffer(1000); + impl_logPropertyArray(sValues, lProps); + + log(TYPE_SCOPE_OPEN | TYPE_INFO, "property array ["+lProps.length+"]:"); + log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValues.toString() ); + } + + public synchronized void log( /*IN*/ com.sun.star.beans.NamedValue aProp ) + { + StringBuffer sValue = new StringBuffer(1000); + impl_logProperty(sValue, aProp); + + log(TYPE_SCOPE_OPEN | TYPE_INFO, "property:" ); + log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString()); + } + + public synchronized void log( /*IN*/ com.sun.star.beans.PropertyValue aProp ) + { + StringBuffer sValue = new StringBuffer(1000); + impl_logProperty(sValue, aProp); + + log(TYPE_SCOPE_OPEN | TYPE_INFO, "property:" ); + log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString()); + } + + public synchronized void log( /*IN*/ Object aAny ) + { + StringBuffer sValue = new StringBuffer(1000); + impl_logAny(sValue, aAny); + + log(TYPE_SCOPE_OPEN | TYPE_INFO, "any:" ); + log(TYPE_SCOPE_CLOSE | TYPE_INFO, sValue.toString()); + } + + // ____________________ + /** + * log a message. + * + * It looks for the internal set mode and decide, how this message + * will be handled. Then it generates a special object which represent + * one protocol line, format it and print it out. + * + * @param nType + * mark a line as a special one or open/close scopes + * + * @param sMessage + * the message, which the outside code wish to be written into the log + */ + public synchronized void log( /*IN*/ int nType , + /*IN*/ String sMessage ) + { + nType = (nType & ~m_nFilter); + if (nType == 0) + return; + + ++m_nLine; + + // it's neccessary to open scopes before creatig the protocol line + // to guarantee right tab handling for new scope value! + if ((nType & TYPE_SCOPE_OPEN) == TYPE_SCOPE_OPEN) + ++m_nScope; + + // create the protocol line + ProtocolLine aLine = new ProtocolLine(m_nLine, m_nScope, nType, sMessage); + String sAsciiLog = aLine.toString(); + String sHTMLLog = aLine.toHTML(); + + // it's neccessary to close scope after creatig the protocol line + // to guarantee right tab handling for old scope value! + if ( + ( m_nScope > 0 ) && + ((nType & TYPE_SCOPE_CLOSE) == TYPE_SCOPE_CLOSE) + ) + { + --m_nScope; + } + + // update statistic values + if (aLine.isTestMark()) + ++m_nTestMarks; + if (aLine.isWarning()) + ++m_nWarnings; + if (aLine.isError()) + ++m_nErrors; + + // no else - it's a bit field of possible reactions! + if ((m_nMode & MODE_STDOUT) == MODE_STDOUT) + System.out.print(sAsciiLog); + // no else - it's a bit field of possible reactions! + if ((m_nMode & MODE_STDERR) == MODE_STDERR) + System.err.print(sAsciiLog); + // no else - it's a bit field of possible reactions! + // But these both conditions must be handled together. + // Because we cant generate different types of log contents to the same log file. + // We preferr HTML if both types are set. + if ( + ((m_nMode & MODE_HTML ) == MODE_HTML ) || + ((m_nMode & MODE_ASCII) == MODE_ASCII) + ) + { + boolean bAppend = (m_nLine>1); + String sContent; + if ((m_nMode & MODE_HTML) == MODE_HTML) + { + if (! bAppend) + sContent = impl_generateHTMLHeader()+sHTMLLog; + else + sContent = sHTMLLog; + } + else + { + if (! bAppend) + sContent = impl_generateAsciiHeader()+sAsciiLog; + else + sContent = sAsciiLog; + } + + impl_writeToLogFile(m_sFileName, bAppend, sContent); + } + } + + // ____________________ + public synchronized void defineHyperlink( /*IN*/ String sTarget , + /*IN*/ String sDescription) + { + if ((m_nMode & MODE_HTML) != MODE_HTML) + return; + + StringBuffer sLog = new StringBuffer(1000); + sLog.append("<a href=\""); + sLog.append(sTarget ); + sLog.append("\">" ); + sLog.append(sDescription); + sLog.append("</a>" ); + + log(TYPE_LINK, sLog.toString()); + } + + // ____________________ + /** + * log the current statistic values + * We write it into our protocol buffer and + * reset it. + */ + public synchronized void logStatistics() + { + m_aEndTime = new Timestamp(System.currentTimeMillis()); + Timestamp aDiff = new Timestamp(m_aEndTime.getTime()-m_aStartTime.getTime()); + + int nLogType = TYPE_STATISTIC; + if (m_nErrors > 0) + nLogType = TYPE_ERROR_INFO; + else + if (m_nWarnings > 0) + nLogType = TYPE_WARNING_INFO; + + log(nLogType | TYPE_SCOPE_OPEN , "statistic:" ); + log(nLogType , "tests = "+m_nTestMarks ); + log(nLogType , "errors = "+m_nErrors ); + log(nLogType , "warnings = "+m_nWarnings ); + log(nLogType , "elapsed time = "+aDiff.toString()); + log(nLogType | TYPE_SCOPE_CLOSE, "" ); + + resetStatistics(); + } + + public synchronized void resetStatistics() + { + m_nTestMarks = 0; + m_nWarnings = 0; + m_nErrors = 0; + m_aStartTime = new Timestamp(System.currentTimeMillis()); + } + + // ____________________ + /** + * returns a generic html header for generating html log files + * + * It's used from the method finish() to generate a valid html formated file. + * For that its neccessary to open some special html targets like e.g. <html>. + * + * @return A string, which includes the whole header. + * + * @see finish() + * @see generateHTMLFooter() + */ + private String impl_generateHTMLHeader() + { + return "<html>\n<head>\n<title>"+m_sFileName+"</title>\n</head>\n<body>\n<table>\n"; + } + + private String impl_generateAsciiHeader() + { + return "********************************************************************************\n"; + } + + private String impl_generateHTMLFooter() + { + return "\n</table>\n</body>\n</html>\n"; + } + + private String impl_generateAsciiFooter() + { + return "\n\n"; + } + + // ____________________ + /** + * helper to log different representations of a property(array) + * + * @param sOut + * used to generate the log output there. + * + * @param lProps/aProp + * represent the property(array) to be logged. + */ + private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut , + /*IN */ com.sun.star.beans.PropertyValue[] lProps ) + { + int i = 0; + int c = lProps.length; + + for (i=0; i<c; ++i) + impl_logProperty(sOut, lProps[i]); + } + + private void impl_logPropertyArray( /*OUT*/ StringBuffer sOut , + /*IN */ com.sun.star.beans.NamedValue[] lProps ) + { + int i = 0; + int c = lProps.length; + + for (i=0; i<c; ++i) + impl_logProperty(sOut, lProps[i]); + } + + private void impl_logProperty( /*OUT*/ StringBuffer sOut , + /*IN*/ com.sun.star.beans.NamedValue aProp ) + { + sOut.append("\""+aProp.Name+"\" = "); + impl_logAny(sOut, aProp.Value); + } + + private void impl_logProperty( /*OUT*/ StringBuffer sOut , + /*IN*/ com.sun.star.beans.PropertyValue aProp ) + { + sOut.append("\""+aProp.Name+"\" = "); + impl_logAny(sOut, aProp.Value); + } + + // ____________________ + /** + * it trys to convert the given any into a suitable string notation .-) + */ + private synchronized void impl_logAny( /*OUT*/ StringBuffer sOut , + /*IN */ Object aAny ) + { + try + { + if (com.sun.star.uno.AnyConverter.isVoid(aAny)) + { + sOut.append("[void] {"); + } + else + if (com.sun.star.uno.AnyConverter.isChar(aAny)) + { + sOut.append("[char] {"); + sOut.append(com.sun.star.uno.AnyConverter.toChar(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isBoolean(aAny)) + { + sOut.append("[boolean] {"); + if (com.sun.star.uno.AnyConverter.toBoolean(aAny)) + sOut.append("TRUE"); + else + sOut.append("FALSE"); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isByte(aAny)) + { + sOut.append("[byte] {"); + sOut.append(com.sun.star.uno.AnyConverter.toByte(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isShort(aAny)) + { + sOut.append("[short] {"); + sOut.append(com.sun.star.uno.AnyConverter.toShort(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isInt(aAny)) + { + sOut.append("[int] {"); + sOut.append(com.sun.star.uno.AnyConverter.toInt(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isLong(aAny)) + { + sOut.append("[long] {"); + sOut.append(com.sun.star.uno.AnyConverter.toLong(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isFloat(aAny)) + { + sOut.append("[float] {"); + sOut.append(com.sun.star.uno.AnyConverter.toFloat(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isDouble(aAny)) + { + sOut.append("[double] {"); + sOut.append(com.sun.star.uno.AnyConverter.toDouble(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isString(aAny)) + { + sOut.append("[string] {"); + sOut.append(com.sun.star.uno.AnyConverter.toString(aAny)); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isEnum(aAny)) + { + sOut.append("[enum] {"); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isType(aAny)) + { + sOut.append("[type] {"); + sOut.append("}"); + } + else + if (com.sun.star.uno.AnyConverter.isArray(aAny)) + { + if (aAny instanceof java.lang.String[]) + { + sOut.append("[sequence< string >] {"); + sOut.append("}"); + } + else + if (aAny instanceof com.sun.star.beans.PropertyValue[]) + { + sOut.append("[sequence< PropertyValue >] {"); + com.sun.star.beans.PropertyValue[] lSubProps = (com.sun.star.beans.PropertyValue[])com.sun.star.uno.AnyConverter.toArray(aAny); + impl_logPropertyArray(sOut, lSubProps); + sOut.append("}"); + } + else + if (aAny instanceof com.sun.star.beans.NamedValue[]) + { + sOut.append("[sequence< NamedValue >] {"); + com.sun.star.beans.NamedValue[] lSubProps = (com.sun.star.beans.NamedValue[])com.sun.star.uno.AnyConverter.toArray(aAny); + impl_logPropertyArray(sOut, lSubProps); + sOut.append("}"); + } + else + { + sOut.append("[unknown array] {-}"); + } + } + else + if (com.sun.star.uno.AnyConverter.isObject(aAny)) + { + sOut.append("[object] {"); + // TODO + sOut.append("}"); + } + + if ((m_nMode & MODE_HTML) == MODE_HTML) + sOut.append("<br>"); + else + sOut.append("\n"); + } + catch(com.sun.star.lang.IllegalArgumentException exIll) + { + sOut.append("Got exception during property conversion.\n"); + sOut.append(exIll.getMessage()); + sOut.append("\n"); + } + } + + // ____________________ + /** + * Writes the given content to the specified log file. + */ + private void impl_writeToLogFile(String sFileName, + boolean bAppend , + String sContent ) + { + try + { + FileWriter aLogFile = new FileWriter(sFileName, bAppend); + aLogFile.write(sContent); + aLogFile.flush(); + aLogFile.close(); + aLogFile = null; + } + catch (java.io.IOException exIO) + { + System.err.println("Can't dump protocol into log file."); + System.err.println(exIO); + exIO.printStackTrace(); + } + } +} diff --git a/framework/qa/complex/framework/autosave/makefile.mk b/framework/qa/complex/framework/autosave/makefile.mk new file mode 100644 index 000000000000..e903c9ad5f33 --- /dev/null +++ b/framework/qa/complex/framework/autosave/makefile.mk @@ -0,0 +1,89 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ = ..$/..$/..$/.. +TARGET = AutoSave +PRJNAME = framework +PACKAGE = complex$/framework$/autosave + +# --- Settings ----------------------------------------------------- +.INCLUDE: settings.mk + + +#----- compile .java files ----------------------------------------- + +JARFILES = mysql.jar ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar \ + OOoRunner.jar mysql.jar +JAVAFILES = AutoSave.java ConfigHelper.java Protocol.java +JAVACLASSFILES = $(foreach,i,$(JAVAFILES) $(CLASSDIR)$/$(PACKAGE)$/$(i:b).class) + +#----- make a jar from compiled files ------------------------------ + +MAXLINELENGTH = 100000 + +JARCLASSDIRS = $(PACKAGE) +JARTARGET = $(TARGET).jar +JARCOMPRESS = TRUE + +# --- Parameters for the test -------------------------------------- + +# start an office if the parameter is set for the makefile +.IF "$(OFFICE)" == "" +CT_APPEXECCOMMAND = +.ELSE +CT_APPEXECCOMMAND = -AppExecutionCommand "$(OFFICE)$/soffice -accept=socket,host=localhost,port=8100;urp;" +.ENDIF + +# test base is java complex +CT_TESTBASE = -TestBase java_complex + +# test looks something like the.full.package.TestName +CT_TEST = -o $(PACKAGE:s\$/\.\).$(JAVAFILES:b) + +# start the runner application +CT_APP = org.openoffice.Runner + +# --- Targets ------------------------------------------------------ + +.IF "$(depend)" == "" +$(CLASSDIR)$/$(PACKAGE)$/$(JAVAFILES:b).props : ALLTAR +.ELSE +$(CLASSDIR)$/$(PACKAGE)$/$(JAVAFILES:b).props : ALLDEP +.ENDIF + +.INCLUDE : target.mk + +#$(CLASSDIR)$/$(PACKAGE)$/$(JAVAFILES:b).props : $(JAVAFILES:b).props +# cp $(JAVAFILES:b).props $(CLASSDIR)$/$(PACKAGE)$/$(JAVAFILES:b).props +# jar uf $(CLASSDIR)$/$(JARTARGET) -C $(CLASSDIR) $(PACKAGE)$/$(JAVAFILES:b).props + +RUN: run + +run: + +java -cp $(CLASSPATH) $(CT_APP) $(CT_TESTBASE) $(CT_APPEXECCOMMAND) $(CT_TEST) + + + |