/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.rc.swt.listener;
import org.eclipse.jubula.communication.internal.message.ChangeAUTModeMessage;
import org.eclipse.jubula.rc.common.AUTServer;
import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer;
import org.eclipse.jubula.rc.common.driver.IRunnable;
import org.eclipse.jubula.rc.common.exception.ComponentNotFoundException;
import org.eclipse.jubula.rc.common.exception.ComponentNotManagedException;
import org.eclipse.jubula.rc.common.exception.NoIdentifierForComponentException;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.listener.BaseAUTListener;
import org.eclipse.jubula.rc.swt.SwtAUTServer;
import org.eclipse.jubula.rc.swt.components.SwtAUTHierarchy;
import org.eclipse.jubula.rc.swt.driver.EventThreadQueuerSwtImpl;
import org.eclipse.jubula.tools.internal.constants.TimingConstantsServer;
import org.eclipse.jubula.tools.internal.exception.InvalidDataException;
import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs;
import org.eclipse.jubula.tools.internal.objects.IComponentIdentifier;
import org.eclipse.jubula.tools.internal.utils.TimeUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Widget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is responsible for handling the components of the AUT. <br>
* This class implements the SWTEventListener interface, listening to
* <code>ShellEvent.Activated</code>.
*
* An instance of <code>AUTSWTHierarchy</code> is notified for WindowEvents. <br>
*
* The static methods for fetching an identifier for a component and getting the
* component for an identifer delegates to this AUTSWTHierarchy.
*
* @author BREDEX GmbH
* @created 19.04.2006
*/
public class ComponentHandler extends BaseSwtEventListener
implements BaseAUTListener {
/** the logger */
private static Logger log = LoggerFactory.getLogger(ComponentHandler.class);
/** the Container hierarchy of the AUT*/
private static SwtAUTHierarchy autHierarchy = new SwtAUTHierarchy();
/**
* private constructor
*/
public ComponentHandler() {
super();
EventThreadQueuerSwtImpl etQueuer = new EventThreadQueuerSwtImpl();
etQueuer.invokeAndWait(this.getClass().getName()
+ "Add active shell to AUT Hierarchy", new IRunnable<Void>() { //$NON-NLS-1$
public Void run() throws StepExecutionException {
Shell activeShell =
((SwtAUTServer)AUTServer.getInstance())
.getAutDisplay().getActiveShell();
if (activeShell != null) {
autHierarchy.add(activeShell);
}
// Return value not used
return null;
}
});
}
/**
* Investigates the given <code>component</code> for an identifier. It
* must be distinct for the whole AUT. To obtain this identifier the
* AUTSWTHierarchy is queried.
* @param component the component to get an identifier for
* @throws NoIdentifierForComponentException if an identifer could not created for <code>component</code>.
* @return the identifier, containing the identification
*/
public static IComponentIdentifier getIdentifier(Widget component)
throws NoIdentifierForComponentException {
try {
return autHierarchy.getComponentIdentifier(component);
} catch (ComponentNotManagedException cnme) {
log.warn(cnme.getLocalizedMessage(), cnme);
throw new NoIdentifierForComponentException(
"unable to create an identifier for '" //$NON-NLS-1$
+ component + "'", //$NON-NLS-1$
MessageIDs.E_COMPONENT_ID_CREATION);
}
}
/**
* returns an array of all componentIdentifier of (supported) components,
* which are currently instantiated by the AUT. <br>
* delegate to AUTSWTHierarchy.getAllComponentId()
* @return array with componentIdentifier, never null
*/
public static IComponentIdentifier[] getAllComponentId() {
return autHierarchy.getAllComponentId();
}
/**
* Searchs the component in the AUT, which belongs to the given
* <code>componentIdentifier</code>.
* @param componentIdentifier the identifier of the component to search for
* @param retry number of tries to get object
* @param timeout timeout for retries
* @throws ComponentNotFoundException if no component is found for the given identifier.
* @throws IllegalArgumentException if the identifier is null or contains invalid data
* {@inheritDoc}
* @return the found component
*/
public static Widget findComponent(
final IComponentIdentifier componentIdentifier, boolean retry,
int timeout)
throws ComponentNotFoundException, IllegalArgumentException {
long start = System.currentTimeMillis();
// FIXME Dennis : waitForComponent
try {
return autHierarchy.findComponent(componentIdentifier);
} catch (ComponentNotManagedException cnme) {
log.debug(cnme.getLocalizedMessage(), cnme);
if (retry) {
while (System.currentTimeMillis() - start < timeout) {
try {
Thread.sleep(TimingConstantsServer
.POLLING_DELAY_FIND_COMPONENT);
// Execute the search synchronously on the event queue.
// This prevents threading issues, as the AUT hierarchy
// is only modified from the event thread.
IEventThreadQueuer queuer =
new EventThreadQueuerSwtImpl();
Widget component = queuer.invokeAndWait("findComponent", new IRunnable<Widget>() { //$NON-NLS-1$
public Widget run() throws StepExecutionException {
try {
return autHierarchy.
findComponent(componentIdentifier);
} catch (ComponentNotManagedException e) { // NOPMD by zeb on 10.04.07 15:26
// OK, we will throw a corresponding exception later
// if we really can't find the component
} catch (InvalidDataException ide) { // NOPMD by zeb on 10.04.07 15:26
// OK, we will throw a corresponding exception later
// if we really can't find the component
}
return null;
}
});
if (component != null) {
return component;
}
} catch (InterruptedException e) {
// ok
}
}
}
throw new ComponentNotFoundException(
cnme.getMessage(), MessageIDs.E_COMPONENT_NOT_FOUND);
} catch (IllegalArgumentException iae) {
log.error(iae.getLocalizedMessage(), iae);
throw iae;
} catch (InvalidDataException ide) {
log.error(ide.getLocalizedMessage(), ide);
throw new ComponentNotFoundException(
ide.getMessage(), MessageIDs.E_COMPONENT_NOT_FOUND);
}
}
/**
* Checks the component in the AUT, which belongs to the given
* <code>componentIdentifier</code> is disappeared or nor.
*
* @param componentIdentifier
* the identifier of the component to search for
* @param timeout
* timeout for retry
* @throws ComponentNotFoundException
* if no component is found for the given identifier.
* @throws IllegalArgumentException
* if the identifier is null or contains invalid data
* {@inheritDoc}
* @return true if the component is disappeared else false
*/
public static boolean isComponentDisappeared(
IComponentIdentifier componentIdentifier, int timeout)
throws ComponentNotFoundException, IllegalArgumentException {
long start = System.currentTimeMillis();
try {
final Widget component = autHierarchy
.findComponent(componentIdentifier);
while (System.currentTimeMillis() - start < timeout) {
TimeUtil.delay(
TimingConstantsServer.POLLING_DELAY_FIND_COMPONENT);
IEventThreadQueuer queuer = new EventThreadQueuerSwtImpl();
boolean isComponentDisappeared = queuer.invokeAndWait(
"isComponentInHierarchy", new IRunnable<Boolean>() { //$NON-NLS-1$
public Boolean run() throws StepExecutionException {
return !autHierarchy
.isComponentInHierarchy(component);
}
});
if (isComponentDisappeared) {
return true;
}
}
return false;
} catch (ComponentNotManagedException cnme) {
return true;
} catch (IllegalArgumentException iae) {
log.error(iae.getLocalizedMessage(), iae);
throw iae;
} catch (InvalidDataException ide) {
log.error(ide.getLocalizedMessage(), ide);
throw new ComponentNotFoundException(
ide.getMessage(), MessageIDs.E_COMPONENT_NOT_FOUND);
}
}
/**
* {@inheritDoc}
*/
public long[] getEventMask() {
return new long[]{SWT.Activate, SWT.Show, SWT.Paint, SWT.Hide};
}
/**
* @param event event
*/
private void eventDispatched(Event event) {
ClassLoader originalCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(
this.getClass().getClassLoader());
try {
if (log.isDebugEnabled()) {
log.debug(event.toString());
}
int id = event.type;
switch (id) {
case SWT.Activate:
case SWT.Show:
case SWT.Paint:
// add recursively all components to AUTSWTHierarchy
// and create names for unnamed components
if (event.widget instanceof Shell) {
Shell window = (Shell)event.widget;
autHierarchy.refreshShell(window);
} else {
refreshComponent(event.widget);
}
break;
case SWT.Hide:
autHierarchy.componentRemoved(event.widget);
break;
default:
// do nothing
}
if (AUTServer.getInstance().getMode()
== ChangeAUTModeMessage.OBJECT_MAPPING) {
AUTServer.getInstance().updateHighLighter();
}
} catch (Throwable t) {
log.error("exception during ComponentHandler", t); //$NON-NLS-1$
} finally {
Thread.currentThread().setContextClassLoader(originalCL);
}
}
/**
* Refreshes the component within the AUTSWTHierarchy.
*
* @param toRefresh the component to refresh.
*/
private void refreshComponent(Widget toRefresh) {
// Refresh the component entry in the AutHierarchy
if (toRefresh != null && !toRefresh.isDisposed()) {
autHierarchy.refreshComponent(toRefresh);
}
}
/**
*
* @return the AUT Hierarchy
*/
public static SwtAUTHierarchy getAutHierarchy() {
return autHierarchy;
}
/**
* {@inheritDoc}
*/
public void handleEvent(Event event) {
eventDispatched(event);
}
}