1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package complex.framework.recovery;
25 
26 import com.sun.star.awt.XDialog;
27 import com.sun.star.awt.XExtendedToolkit;
28 import com.sun.star.awt.XWindow;
29 import com.sun.star.beans.NamedValue;
30 import com.sun.star.frame.XController;
31 import com.sun.star.frame.XDesktop;
32 import com.sun.star.frame.XDispatch;
33 import com.sun.star.frame.XDispatchProvider;
34 import com.sun.star.frame.XModel;
35 import com.sun.star.lang.XComponent;
36 import com.sun.star.lang.XMultiServiceFactory;
37 import com.sun.star.ucb.XSimpleFileAccess;
38 import com.sun.star.uno.UnoRuntime;
39 import com.sun.star.uno.XInterface;
40 import com.sun.star.util.URL;
41 import com.sun.star.util.XURLTransformer;
42 import helper.FileTools;
43 import helper.OfficeProvider;
44 import helper.UnoProvider;
45 import java.io.File;
46 import java.io.PrintWriter;
47 import java.util.HashMap;
48 import lib.TestParameters;
49 import share.LogWriter;
50 import util.PropertyName;
51 import util.UITools;
52 import util.utils;
53 
54 /**
55  * this class supports the <CODE>RecoverTest</CODE>. You will find here some helper
56  * functions.
57  */
58 public class RecoveryTools {
59 
60     private final TestParameters param;
61     private final LogWriter log;
62 
63     /**
64      * Creates new OfficeWatcher
65      * @param param the test parameter
66      * @param log a log writer
67      */
RecoveryTools(TestParameters param, LogWriter log)68     public RecoveryTools(TestParameters param, LogWriter log) {
69         this.param = param;
70         this.log = log;
71 
72     }
73 
74     /**
75      * get the active dialog from the top of the desktop
76      * @param xToolKit xToolKit the <CODE> XExtendedToolkit</CODE> to get the dialog from the top of the desktop.
77      * @return a <CODE>XDialog</CODE> interface of the dialog
78      */
getActiveDialog( XMultiServiceFactory xMSF)79     public XDialog getActiveDialog( XMultiServiceFactory xMSF){
80         XWindow xWin = getActiveWindow(xMSF);
81         return (XDialog) UnoRuntime.queryInterface(XDialog.class, xWin);
82     }
83 
getActiveWindow( XMultiServiceFactory xMSF)84     public XWindow getActiveWindow( XMultiServiceFactory xMSF){
85         XInterface xToolKit = null;
86         try {
87             xToolKit = (XInterface) xMSF.createInstance("com.sun.star.awt.Toolkit") ;
88         } catch (com.sun.star.uno.Exception e) {
89           return null;
90         }
91 
92         XExtendedToolkit tk = (XExtendedToolkit)
93             UnoRuntime.queryInterface(XExtendedToolkit.class, xToolKit);
94         Object atw = tk.getActiveTopWindow();
95         return (XWindow) UnoRuntime.queryInterface(XWindow.class, atw);
96     }
97 
98     /**
99      * After a crash the office start with a recovery diaolg. It could be that the office
100      * is connectable but not all services to get the dialog a loaded. This function
101      * tries to get the dialog until the <CODE>OfficeWatcher</CODE> kills the office.
102      * @param xToolKit the <CODE> XExtendedToolkit</CODE> to get the dialog from the top of the desktop.
103      * @return a <CODE>XDialog</CODE> interface of the dialog
104      */
getActiveDialogAfterStartup(XMultiServiceFactory xMSF)105     public XDialog getActiveDialogAfterStartup(XMultiServiceFactory xMSF){
106         // while the office starts it takes some time to get the dialog.
107 
108         // the dialog is accessible AFTER the office has recoverd all documents.
109         // This could consumes more time then the TimeOut allow.
110         int counter = 0;
111         int multi = 5;
112         int pause = param.getInt(PropertyName.SHORT_WAIT)*10;
113         int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5;
114         int maximum = (timeOut / pause) * multi;
115 
116         XDialog oDialog = getActiveDialog(xMSF);
117 
118         while (oDialog == null && (counter < maximum)){
119             log.println("waiting until the office has recoverd... remaining " + (timeOut * multi - pause * counter)/1000 + " seconds");
120             pause(pause);
121             oDialog = getActiveDialog(xMSF);
122             counter ++;
123         }
124         return oDialog;
125     }
126 
127     /**
128      * halt the thread for some time
129      */
pause()130     public void pause(){
131        pause(param.getInt(PropertyName.SHORT_WAIT));
132     }
133 
134     /**
135      * halt the thread for some time
136      */
pause(int sleepTime)137     public void pause(int sleepTime){
138         sleep(sleepTime);
139     }
140 
sleep(long millis)141     private void sleep(long millis){
142         try{
143             Thread.sleep(millis);
144         }catch (java.lang.InterruptedException e){}
145     }
146 
147     /**
148      * remove the content of the user backup folder and removes the Recovery.xcu. This
149      * was done from the Office via XSimpleFileAccess
150      * @throws com.sun.star.io.IOException the exception was thrown if something goes wrong.
151      */
cleanRecoveryData()152     public void cleanRecoveryData()
153         throws com.sun.star.io.IOException
154     {
155         try{
156             HashMap recFiles = getRecoveryFiles();
157 
158             String recoveryFolder = (String) recFiles.get("recoveryFolder");
159             String recoveryXCU = (String) recFiles.get("recoveryXCU");
160 
161             log.println("try to remove content of '" + recoveryFolder + "'");
162 
163             File rf = new File(recoveryFolder);
164 
165             boolean success = FileTools.cleanDir(rf);
166             log.println("removed " + recoveryFolder + ": " + success);
167 
168             log.println("try to remove '" + recoveryXCU + "'");
169 
170             File xcu = new File(recoveryXCU);
171             if (xcu.isFile()){
172                 success = xcu.delete();
173                 log.println("removed " + recoveryXCU + " : " + success);
174             }
175 
176         } catch (Exception e){
177             throw new com.sun.star.io.IOException("could not remove old recovery data: " + e.toString());
178         }
179     }
180 
getRecoveryFiles()181     public HashMap getRecoveryFiles()
182         throws com.sun.star.io.IOException
183     {
184         try{
185             log.println("try to get UnoProvider...");
186             UnoProvider unoProv = new UnoProvider();
187             XMultiServiceFactory xMSF = (XMultiServiceFactory) unoProv.getManager(param);
188 
189             String userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstraprc:UserInstallation}");
190             System.out.println("userPath:'" + userPath + "'");
191 
192             if (userPath.equals(""))userPath = utils.expandMacro(xMSF, "${$ORIGIN/bootstrap.ini:UserInstallation}");
193             System.out.println("userPath:'" + userPath + "'");
194 
195             if (userPath.equals("")) throw new com.sun.star.io.IOException("could not get user path at bootstraping");
196 
197             String recoveryFolder = utils.getSystemURL(userPath + "/user/backup");
198 
199             String recoveryXCU = utils.getSystemURL(userPath + "/user/registry/data/org/openoffice/Office/Recovery.xcu");
200 
201             HashMap recFiles = new HashMap();
202 
203             recFiles.put("recoveryFolder", recoveryFolder);
204             recFiles.put("recoveryXCU", recoveryXCU);
205             return recFiles;
206 
207         } catch (Exception e){
208             throw new com.sun.star.io.IOException("could not get recovery folder: " + e.toString());
209         }
210 
211     }
212     /**
213      * This function close the office while calling terminate on the desktop. If
214      * this failed, the <CODE>ProcessHandler</CODE> kills the process.
215      * @param xMSF the <CODE>XMultiServiceFactory</CODE>
216      * @return <CODE>TRUE</CODE> if no exception was thrown, otherwise <CODE>FALSE</CODE>
217      */
closeOffice(XMultiServiceFactory xMSF)218     public boolean closeOffice(XMultiServiceFactory xMSF) {
219         try {
220             XDesktop desk = (XDesktop) UnoRuntime.queryInterface(
221                     XDesktop.class, xMSF.createInstance(
222                     "com.sun.star.frame.Desktop"));
223             xMSF = null;
224 
225             desk.terminate();
226             log.println("Waiting until ProcessHandler loose the office...");
227 
228         }
229         catch (java.lang.Exception e) {
230             e.printStackTrace();
231             return false;
232         }
233         waitForClosedOffice();
234         return true;
235     }
236 
237     /**
238      * This function waits until the office is closed. If the closing time reach
239      * the value of parameter <CODE>THREAD_TIME_OUT</CODE> the office was killed.
240      */
waitForClosedOffice()241     public void waitForClosedOffice(){
242         // check for the office process
243         helper.ProcessHandler ph = (helper.ProcessHandler) param.get("AppProvider");
244 
245         int timeOut = param.getInt(PropertyName.THREAD_TIME_OUT)*5;
246         int pause = param.getInt(PropertyName.SHORT_WAIT)*20;
247         int multi = 0;
248         while ((ph != null) && (ph.getExitCode()<0) && (pause*multi < timeOut)) {
249             log.println("waiting until the office is closed... remaining " + (timeOut - pause * multi)/1000 + " seconds");
250             pause(pause);
251             multi ++;
252         }
253 
254         // be sure that office is closed
255         if (ph != null) ph.kill();
256     }
257 
killOffice()258     public void killOffice(){
259         helper.ProcessHandler ph = (helper.ProcessHandler) param.get("AppProvider");
260         ph.kill();
261     }
262 
263     /**
264      * The office must be started WITH restore and crashreporter functionality.
265      * Therefore the parmater '<CODE>-norestore</CODE>' and '<CODE>-nocrashreport</CODE>'
266      * was removed from the <CODE>AppExecutionCommand</CODE> parameter
267      */
removeParametersFromAppExecutionCommand()268     public void removeParametersFromAppExecutionCommand(){
269 
270         //remove some params to start office
271         String office = (String) param.get("AppExecutionCommand");
272         String[] params = {"-norestore", "-nocrashreport"};
273 
274         for (int i = 0; i < params.length; i++){
275             int index = office.indexOf(params[i]);
276             int length = params[i].length();
277             if (index != -1){
278                 office = office.substring(0, index) + office.substring(index + length);
279                 log.println("removed '" + params[i] + "' from AppExecutionCommand: " + office);
280             }
281         }
282         param.put("AppExecutionCommand", office);
283         log.println("connect: " + (String) param.get("AppExecutionCommand"));
284 
285     }
286 
287     /**
288      * This function uses accessibility to handle modal dialogs like the
289      * "Are you sure" dialog.
290      * It cklick the named button given in parameter <CODE>buttonName</CODE>
291      * @param buttonName the name of the button which should be chlicked
292      */
handleModalDialog(XMultiServiceFactory xMSF, String buttonName)293     public void handleModalDialog(XMultiServiceFactory xMSF, String buttonName)
294                 throws com.sun.star.accessibility.IllegalAccessibleComponentStateException
295     {
296 
297         log.println("try to get modal Dialog...");
298 
299         pause();
300 
301         XWindow oDialog = getActiveWindow(xMSF);
302 
303         if (oDialog == null) throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("could not get modal Dialog");
304 
305 
306         UITools oUITools = new UITools(xMSF, oDialog);
307         oUITools.printAccessibleTree((PrintWriter) log, param.getBool(PropertyName.DEBUG_IS_ACTIVE));
308 
309         try{
310             log.println("click ' " + buttonName + "' button..");
311             oUITools.clickButton(buttonName);
312         } catch ( java.lang.Exception e){
313             throw new com.sun.star.accessibility.IllegalAccessibleComponentStateException("Could not klick '"+buttonName +"' at modal dialog: " + e.toString());
314         }
315         pause();
316     }
317 
clickThreadButton(XMultiServiceFactory xMSF, XWindow xWindow, String buttonName)318     public void clickThreadButton(XMultiServiceFactory xMSF, XWindow xWindow, String buttonName)
319                 throws com.sun.star.accessibility.IllegalAccessibleComponentStateException
320     {
321         KlickButtonThread kbt = new KlickButtonThread(xMSF, xWindow, buttonName);
322         kbt.start();
323         pause(param.getInt(PropertyName.SHORT_WAIT) * 10);
324     }
325 
copyRecoveryData(boolean backup)326     public void copyRecoveryData(boolean backup)
327         throws com.sun.star.io.IOException, java.io.IOException
328     {
329         HashMap recFiles = null;
330 
331         try{
332             recFiles = getRecoveryFiles();
333         } catch ( com.sun.star.io.IOException e){
334             throw new  com.sun.star.io.IOException("Could not get recovery files: " + e.toString());
335         }
336 
337         try{
338             String recoveryFolder = (String) recFiles.get("recoveryFolder");
339             String recoveryXCU = (String) recFiles.get("recoveryXCU");
340 
341             File recFolder = new File(recoveryFolder);
342             File recFolderBackup = new File(recoveryFolder+".recoveryTest");
343 
344             File recXCU = new File(recoveryXCU);
345             File recXCUBackup = new File(recoveryXCU + ".recoveryTest");
346 
347             if (backup){
348                 FileTools.copyDirectory(recFolder, recFolderBackup);
349                 FileTools.copyFile(recXCU, recXCUBackup);
350             } else {
351                 FileTools.copyDirectory(recFolderBackup, recFolder);
352                 FileTools.copyFile(recXCUBackup, recXCU);
353 
354             }
355         } catch (java.io.IOException e){
356             throw new java.io.IOException("Could not copy recovery files: " + e.toString());
357         }
358    }
359 
360 
361 }
362