package com.yahoo.dtf.actions.component;
import java.util.ArrayList;
import com.yahoo.dtf.actions.Action;
import com.yahoo.dtf.actions.flowcontrol.Sequence;
import com.yahoo.dtf.actions.protocol.Lock;
import com.yahoo.dtf.comm.Comm;
import com.yahoo.dtf.comm.CommClient;
import com.yahoo.dtf.comm.CommRMIClient;
import com.yahoo.dtf.components.LockHook;
import com.yahoo.dtf.config.Config;
import com.yahoo.dtf.exception.DTFException;
import com.yahoo.dtf.exception.ParseException;
import com.yahoo.dtf.util.TimeUtil;
/**
* @dtf.tag lockcomponent
*
* @dtf.since 1.0
* @dtf.author Rodney Gomes
*
* @dtf.tag.desc This tag is used to identify and lock the components required
* for the execution of the current test case. When you lock a
* {@dtf.link Component} you can then define a global alias
* by which it will be known for use by other tags such as the
* {@dtf.link Component} tag.
*
* @dtf.tag.example
* <local>
* <echo>Remote counter retrieval</echo>
* <lockcomponent id="DTFA1">
* <attrib name="type" value="DTFA"/>
* </lockcomponent>
* </local>
*/
public class Lockcomponent extends Action {
/**
* @dtf.attr id
* @dtf.attr.desc Specifies the internal ID that will be used to identify
* this component in the test case.
*/
private String id = null;
/**
* @dtf.attr name
* @dtf.attr.desc Specifies the exact name of the component we want to lock,
* this name will identify one and only one component that
* has been registered with the DTFC.
*/
private String name = null;
/**
* @dtf.attr timeout
* @dtf.attr.desc The timeout in seconds to wait for the component to
* become available to the DTFC. This timeout is useful when
* automating testing and wanting to start up the framework
* along with the test driver (DTFX) and not knowing when
* the necessary components are available. Using the timeout
* you can estimate the component will be come available with
* in X amount of time.
*/
private String timeout = null;
public Lockcomponent() { }
/**
* internal method which is responsible for assembling the the Lock
* to be sent to the DTFC.
*
* @return
* @throws ParseException
*/
protected Lock assembleLock() throws DTFException {
Lock lock = new Lock(getName(),getId(),getTimeout());
lock.setXMLLocation(this);
ArrayList aux = findActions(Attrib.class);
ArrayList<Attrib> attribs = new ArrayList<Attrib>();
/*
* Add all Attribs that we're looking for in a component
* make sure to resolve all properties before shipping this off...
*/
for (int i = 0; i < aux.size(); i++) {
Attrib cur = (Attrib)aux.get(i);
Attrib tmp = new Attrib(cur.getName(),
cur.getValue(),
cur.isTestProp());
attribs.add(tmp);
}
lock.addActions(attribs);
return lock;
}
/**
* internal method which is responsible for handling the returned lock and
* calling the required lock hooks.
*
* @param lock
* @throws DTFException
*/
protected void handleLockResponse(Lock lock) throws DTFException {
/*
* If the connection from the controller is tunneled then we have
* no other choice but to connect through the controller.
*/
if (!lock.getTunneled()) {
CommClient client = new CommRMIClient(lock.getAddress(),
lock.getPort());
if (client.heartbeat().booleanValue()) {
if (getLogger().isDebugEnabled())
getLogger().debug("Direct connection to component " +
"being used.");
Comm.addClient(lock.getId(), client);
}
} else {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Tunneling detected, talking to the " +
"component throught the controller");
}
}
/*
* Record the right attributes as test properties in the record
* and set the right test properties for the others.
*/
ArrayList<Attrib> attribs = lock.findActions(Attrib.class);
Config config = getConfig();
for(int i = 0; i < attribs.size(); i++) {
Attrib attrib = (Attrib)attribs.get(i);
if (attrib.isTestProp())
config.setProperty(getId() + "." + attrib.getName(),
attrib.getValue());
getResults().recordProperty(getId() + "." + attrib.getName(),
attrib.getValue());
}
getComponents().registerComponent(getId(), lock);
if ( getLogger().isDebugEnabled() ) {
getLogger().debug("Locked " + lock + " as " + getId());
} else {
getLogger().info("Locked " + lock.getId() + " as " + getId());
}
// execute LockHooks!
for (int i = 0; i < _lockhooks.size(); i++) {
ArrayList<Action> actions = _lockhooks.get(i).init(this.getId());
Sequence sequence = new Sequence();
sequence.addActions(actions);
getComm().executeOnComponent(id, sequence);
}
}
// tricky code not for anyone to change.. :)
public void execute() throws DTFException {
// Whenever we haven't been named lets make sure to register first.
getComm().checkAndConnectToDTFC();
Lock lock = assembleLock();
Action result = getComm().sendActionToCaller("dtfc", lock);
if (result != null) {
Lock returnedLock = (Lock)result.findAllActions(Lock.class).get(0);
handleLockResponse(returnedLock);
} else {
throw new DTFException("Unable to register component :(.");
}
}
private static ArrayList<LockHook> _lockhooks = new ArrayList<LockHook>();
public static void registerLockHook(LockHook hook) {
_lockhooks.add(hook);
}
public static ArrayList<LockHook> getLockHooks() { return _lockhooks; }
public String getId() throws ParseException { return replaceProperties(id); }
public void setId(String id) { this.id = id; }
public String getName() throws ParseException { return replaceProperties(name); }
public void setName(String name) { this.name = name; }
public long getTimeout() throws ParseException {
return TimeUtil.parseTime("timeout",replaceProperties(timeout));
}
public void setTimeout(String timeout) { this.timeout = timeout; }
}