/*******************************************************************************
* 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.client.core.commands;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections.list.UnmodifiableList;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jubula.client.core.businessprocess.ComponentNamesBP;
import org.eclipse.jubula.client.core.businessprocess.ComponentNamesBP.CompNameCreationContext;
import org.eclipse.jubula.client.core.businessprocess.IWritableComponentNameCache;
import org.eclipse.jubula.client.core.businessprocess.TestExecution;
import org.eclipse.jubula.client.core.businessprocess.compcheck.CompletenessGuard;
import org.eclipse.jubula.client.core.events.IRecordListener;
import org.eclipse.jubula.client.core.i18n.Messages;
import org.eclipse.jubula.client.core.model.IAUTMainPO;
import org.eclipse.jubula.client.core.model.ICapPO;
import org.eclipse.jubula.client.core.model.IComponentNamePO;
import org.eclipse.jubula.client.core.model.IObjectMappingAssoziationPO;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.ITDManager;
import org.eclipse.jubula.client.core.model.NodeMaker;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.communication.internal.ICommand;
import org.eclipse.jubula.communication.internal.message.CAPRecordedMessage;
import org.eclipse.jubula.communication.internal.message.ChangeAUTModeMessage;
import org.eclipse.jubula.communication.internal.message.Message;
import org.eclipse.jubula.communication.internal.message.MessageCap;
import org.eclipse.jubula.communication.internal.message.MessageParam;
import org.eclipse.jubula.communication.internal.message.ShowObservInfoMessage;
import org.eclipse.jubula.communication.internal.message.ShowRecordedActionMessage;
import org.eclipse.jubula.toolkit.common.xml.businessprocess.ComponentBuilder;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.constants.TestDataConstants;
import org.eclipse.jubula.tools.internal.i18n.CompSystemI18n;
import org.eclipse.jubula.tools.internal.objects.MappingConstants;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Action;
import org.eclipse.jubula.tools.internal.xml.businessmodell.CompSystem;
import org.eclipse.jubula.tools.internal.xml.businessmodell.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is used by record mode of Jubula. Server sends a recorded CAP,
* which is added to specification store. (CAP + Objectmapping)
*
* @author BREDEX GmbH
* @created 02.09.2004
*
*/
public class CAPRecordedCommand implements ICommand {
/** symbol for single quote */
public static final char COMMENT_SYMBOL =
TestDataConstants.COMMENT_SYMBOL;
/**
* The logger
*/
private static final Logger LOG =
LoggerFactory.getLogger(CAPRecordedCommand.class);
/** The TestCase to record in */
private static ISpecTestCasePO recSpecTestCase;
/** The component names cache for adding new component names */
private static IWritableComponentNameCache compNamesCache;
/**
* The Editor/ContentProvider listening to recorded Caps
*/
private static IRecordListener recordListener;
/**
* The message.
*/
private CAPRecordedMessage m_capRecordedMessage;
/** name of recorded action */
private String m_recAction = null;
/** additional Message for Observation Console */
private String m_extraMsg = null;
/** info Message for actions that are not supported for selected toolkit */
private String m_wrongToolkit =
Messages.CurrenActionNotAvailabelForSelectedToolkit;
/**
* get name of recorded action
* @return String
*/
public String getRecAction() {
return m_recAction;
}
/**
* set name of recorded action
* @param recAction String
*/
public void setRecAction(String recAction) {
m_recAction = recAction;
}
/**
* {@inheritDoc}
*/
public Message getMessage() {
return m_capRecordedMessage;
}
/**
* {@inheritDoc}
*/
public void setMessage(Message message) {
m_capRecordedMessage = (CAPRecordedMessage)message;
}
/**
* call the method of the implementation class per reflection
*
* {@inheritDoc}
*/
public Message execute() {
MessageCap messageCap = m_capRecordedMessage.getMessageCap();
//only actions supported by selected toolkit recorded
String compType = getComponentType(messageCap);
boolean belongsToToolkit = belongsToToolkit(compType);
if (belongsToToolkit) {
try {
// here handle to Save CAP
setCapIntoSpecModel(messageCap, compType);
String recAction = m_recAction;
String extraMsg = m_extraMsg;
return new ShowRecordedActionMessage(true, recAction, extraMsg);
} catch (IllegalArgumentException e) {
LOG.error(Messages.ExecutedFailed, e);
}
return new ShowRecordedActionMessage(false);
}
return new ShowObservInfoMessage(m_wrongToolkit);
}
/**
* Sets a recorded CAP into the Specification-Model.
* @param messageCap the recorded CAP
* @param compType String
*/
private void setCapIntoSpecModel(MessageCap messageCap, String compType) {
ICapPO cap = buildCapPO(messageCap, compType);
// GUI updates
if (recordListener != null) {
recordListener.capRecorded(cap, messageCap.getCi(),
messageCap.hasDefaultMapping());
}
}
/**
* Builds a CapPO instance from the given MessageCap.
* @param messageCap the MessageCap.
* @param componentType String
* @return a CapPO instance, or <code>null</code> if the Test Step could
* not be created.
*/
private ICapPO buildCapPO(MessageCap messageCap, String componentType) {
String componentName = null;
boolean isAppAction = isApplication(componentType);
if (isAppAction) {
componentName = null;
} else {
componentName = getOrCreateLogicalName(messageCap);
}
String actionName = messageCap.getAction().getName();
String capName = null;
capName = CompSystemI18n.getString(actionName);
if (isAppAction || messageCap.hasDefaultMapping()) {
capName = CompSystemI18n.getString(actionName);
} else {
capName = CompSystemI18n.getString(actionName);
String normName = removeMnemonics(
messageCap.getCi().getComponentName());
String altName = removeMnemonics(
messageCap.getCi().getAlternativeDisplayName());
capName = altName == null ? capName.concat(" on " //$NON-NLS-1$
+ minimizeCapName(normName)) : capName.concat(" on " //$NON-NLS-1$
+ altName);
}
m_recAction = capName;
m_extraMsg = messageCap.getExtraMessage();
ICapPO recCap = NodeMaker.createCapPO(capName, componentName,
componentType, actionName);
// Set the Component Name to null so that the Component Name
// cache doesn't remove the instance of reuse
// for <code>componentName</code>.
recCap.setComponentName(null);
if (!messageCap.hasDefaultMapping()) {
ComponentNamesBP.setCompName(recCap, componentName,
CompNameCreationContext.STEP, compNamesCache);
}
recSpecTestCase.addNode(recCap);
List params = messageCap.getMessageParams();
addTestData(recCap, params);
return recCap;
}
/**
* gets componentType of recorded Action
* @param messageCap MessageCap
* @return component type of action
*/
private String getComponentType(MessageCap messageCap) {
String componentType = messageCap.getCi().getSupportedClassName();
CompSystem compSystem = ComponentBuilder.getInstance().getCompSystem();
Component component = null;
if (isApplication(componentType)) {
component = compSystem.findComponent(messageCap.getCi()
.getComponentClassName());
} else {
if (componentType.equals(MappingConstants.SWT_MENU_CLASSNAME)) {
componentType = MappingConstants
.SWT_MENU_DEFAULT_MAPPING_CLASSNAME;
}
if (componentType.equals(MappingConstants.SWING_MENU_CLASSNAME)) {
componentType = MappingConstants
.SWING_MENU_DEFAULT_MAPPING_CLASSNAME;
}
component = getComponentToUse(
messageCap, compSystem, componentType);
}
while (component != null && (!component.isVisible()
|| !component.isObservable())
&& !component.getRealized().isEmpty()) {
List realizedComponents = component.getRealized();
component = (Component)realizedComponents.get(0);
}
componentType = getAbstrCompType(component, messageCap);
return componentType;
}
/**
* Check if current Action is supported by current toolkit
* @param compType Type of Component
* @return true if action is supported, false otherwise
*/
private boolean belongsToToolkit(String compType) {
CompSystem cs = ComponentBuilder.getInstance().getCompSystem();
String toolkit = GeneralStorage.getInstance().getProject().getToolkit();
String[] toolkitTypes = cs.getComponentTypes(toolkit);
for (int i = 0; i < toolkitTypes.length; i++) {
String kitType = toolkitTypes[i];
if (kitType.equals(compType)) {
return true;
}
}
return false;
}
/**
* Add the appropriate Test Data to the Test Step.
*
* @param recCap The recorded Test Step.
* @param params The Test Step's Parameters.
*/
private void addTestData(ICapPO recCap, List params) {
ITDManager tdManager = recCap.getDataManager();
GeneralStorage genStorage = GeneralStorage.getInstance();
int paramNumber = 0;
Iterator msgParamIt = params.iterator();
Iterator paramIt = recCap.getMetaAction().getParams().iterator();
while (msgParamIt.hasNext() && paramIt.hasNext()) {
MessageParam msgParam = (MessageParam)msgParamIt.next();
String value = msgParam.getValue();
if (value != null && !(value.equals(StringUtils.EMPTY))) {
tdManager.updateCell(value, 0, paramNumber);
}
boolean bool =
!(value == null) && !(value.equals(StringUtils.EMPTY));
CompletenessGuard.setCompletenessTestData(recCap, bool);
paramNumber++;
}
}
/**
* @param componentType The type to check.
* @return <code>true</code> if <code>componentType</code> is an
* "Application" component. Otherwise, <code>false</code>.
*/
private boolean isApplication(String componentType) {
return componentType.equals(
MappingConstants.SWING_APPLICATION_CLASSNAME)
|| componentType.equals(
MappingConstants.SWING_APPLICATION_COMPONENT_IDENTIFIER)
|| componentType.equals(
MappingConstants.SWT_APPLICATION_CLASSNAME)
|| componentType.equals(
MappingConstants.WEB_APPLICATION_CLASSNAME)
|| componentType.equals(
MappingConstants.CONCR_APPLICATION_CLASSNAME);
}
/**
* @param comp Component
* @param mc MessageCap
* @return String of more AbstractType then the old concrete one
*/
private String getAbstrCompType(Component comp, MessageCap mc) {
String compTyp = null;
String [] argArray = createArgTypeArray(
UnmodifiableList.decorate(mc.getMessageParams()));
String actionName = comp.findActionByMethodSignature(
mc.getMethod(),
argArray).getName();
if (actionName.equals("CompSystem.Click") //$NON-NLS-1$
|| actionName.equals("CompSystem.VerifyEnabled") //$NON-NLS-1$
|| actionName.equals("CompSystem.VerifyExists") //$NON-NLS-1$
|| actionName.equals("CompSystem.VerifyFocus") //$NON-NLS-1$
|| actionName.equals("CompSystem.VerifyProperty") //$NON-NLS-1$
|| actionName.equals("CompSystem.PopupSelectByTextPath")) { //$NON-NLS-1$
compTyp = "guidancer.abstract.Widget"; //$NON-NLS-1$
} else if (actionName.equals("CompSystem.InputTextDirect") //$NON-NLS-1$
|| actionName.equals("CompSystem.InputText") //$NON-NLS-1$
|| actionName.equals("CompSystem.VerifyEditable")) { //$NON-NLS-1$
compTyp = "guidancer.abstract.TextInputSupport"; //$NON-NLS-1$
} else if (actionName.equals("CompSystem.VerifyText")) { //$NON-NLS-1$
compTyp = "guidancer.abstract.TextVerifiable"; //$NON-NLS-1$
} else if (actionName.equals("CompSystem.VerifySelected")) { //$NON-NLS-1$
compTyp = "guidancer.abstract.ButtonComp"; //$NON-NLS-1$
} else {
compTyp = comp.getType();
}
return compTyp;
}
/**
* check if component has already a logical name and use it or generate
* new one
* @param messageCap MessageCap
* @return new or existing logical name
*/
private String getOrCreateLogicalName(MessageCap messageCap) {
String compName = null;
IAUTMainPO connectedAut = TestExecution.getInstance().getConnectedAut();
if (connectedAut != null) {
boolean checkTechNameExists = connectedAut.getObjMap()
.existTechnicalName(messageCap.getCi());
if (checkTechNameExists) {
for (IObjectMappingAssoziationPO oma : connectedAut.getObjMap()
.getMappings()) {
Set<String> logicalNames = oma.getLogicalNames();
if (!(logicalNames.isEmpty())
&& oma.getTechnicalName() != null
&& oma.getTechnicalName()
.equals(messageCap.getCi())) {
for (String compNameGuid : logicalNames) {
IComponentNamePO compNamePo = compNamesCache.
getResCompNamePOByGuid(compNameGuid);
if (compNamePo != null) {
if (compNamePo.getParentProjectId().equals(
GeneralStorage.getInstance()
.getProject().getId())) {
compName = compNamePo.getName();
}
}
}
}
}
}
}
if (compName == null) {
compName = messageCap.getLogicalName();
if (compName == null) {
compName = messageCap.getCi().generateLogicalName();
}
}
return compName;
}
/**
* @param messageCap MessageCap
* @param compSystem Component
* @param componentType String
* @return the highest component that supports the current action (e.g.
* gdSelect on TreeTable will return Tree)
*/
private Component getComponentToUse(MessageCap messageCap,
CompSystem compSystem, String componentType) {
List<Component> supportedComponents =
compSystem.findComponents(componentType);
Set<Component> compsWithAction = new HashSet<Component>();
for (Component c : supportedComponents) {
List<Action> actionList =
new LinkedList<Action>(c.getActions());
if (actionList.contains(messageCap.getAction())) {
compsWithAction.add(c);
}
}
Component theComponentToUse = null;
for (Component c : compsWithAction) {
Set<Component> realizedIntersection =
new HashSet<Component>(c.getAllRealized());
realizedIntersection.retainAll(compsWithAction);
if (realizedIntersection.isEmpty()) {
theComponentToUse = c;
break;
}
}
return theComponentToUse;
}
/**
* minimizes the component name, e.g. javax.swing.JButton_1 to Button_1
* @param capName String
* @return the minimized CapName
*/
private String minimizeCapName(String capName) {
String minCapName = capName;
String[] nameParts = null;
nameParts = minCapName.split("\\(", 2); //$NON-NLS-1$
if (nameParts[0].lastIndexOf(".") > -1 //$NON-NLS-1$
&& nameParts[0].length() > (nameParts[0].lastIndexOf(".") + 1)) { //$NON-NLS-1$
nameParts[0] = nameParts[0].substring(
nameParts[0].lastIndexOf(".") + 1); //$NON-NLS-1$
}
minCapName = nameParts[0];
if (nameParts.length > 1) {
minCapName = minCapName + "(" + nameParts[1]; //$NON-NLS-1$
}
return minCapName;
}
/**
* @param name String
* @return name of component without mnemonics-sign "&"
*/
public String removeMnemonics(String name) {
String fixedName = name;
if (fixedName != null) {
fixedName = fixedName.replaceAll("&", StringConstants.EMPTY); //$NON-NLS-1$
}
return fixedName;
}
/**
* @param argList The arguments as a list.
* @return An array containing the types of the given arguments.
*/
private String[] createArgTypeArray(List argList) {
String [] argTypeArray = new String [argList.size()];
for (int i = 0; i < argTypeArray.length; i++) {
MessageParam param = (MessageParam)argList.get(i);
argTypeArray[i] = param.getType();
}
return argTypeArray;
}
/**
* {@inheritDoc}
*/
public void timeout() {
LOG.error(this.getClass().getName() + Messages.TimeoutCalled);
}
/**
* @param r The recSpecTestCase to set.
*/
public static void setRecSpecTestCase(ISpecTestCasePO r) {
CAPRecordedCommand.recSpecTestCase = r;
}
/**
*
* @return the recSpecTestCase
*/
public static ISpecTestCasePO getRecSpecTestCase() {
return CAPRecordedCommand.recSpecTestCase;
}
/**
* @param compCache The comp names cache to set.
*/
public static void setCompNamesCache(
IWritableComponentNameCache compCache) {
CAPRecordedCommand.compNamesCache = compCache;
}
/**
* sets the RecordListener
* @param rc
* IRecordListener
*/
public static void setRecordListener(IRecordListener
rc) {
recordListener = rc;
}
/**
*
* @return IRecordListener
*/
public static IRecordListener getRecordListener() {
return recordListener;
}
/**
* Checks if there is a Aut and obseravtion mode running
* @return true, if observation mode is running, false otherwise
*/
public static boolean isObserving() {
if (TestExecution.getInstance().getConnectedAut() != null) {
switch (AUTModeChangedCommand.getAutMode()) {
case ChangeAUTModeMessage.RECORD_MODE:
case ChangeAUTModeMessage.CHECK_MODE:
return true;
default :
return false;
}
}
return false;
}
}