/*
* Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved.
*/
package jsystem.framework.fixture;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import jsystem.runner.ClassPathFixtureCollector;
import jsystem.runner.loader.LoadersManager;
/**
* Responsible for the fixture navigation and execution. Support the fixture
* model.
*
* @author Guy Arieli
*/
public class FixtureManager {
private static Logger log = Logger.getLogger(FixtureManager.class.getName());
private static FixtureManager fm = null;
private Vector<FixtureListener> listeners = new Vector<FixtureListener>();
private HashMap<String, Fixture> allFixtures = null;
private boolean disableFixture = false;
/**
* Get and instance of the FixtureManager.
*
* @return FixtureManager instance.
*/
public static FixtureManager getInstance() {
if (fm == null) {
fm = new FixtureManager();
fm.initFixtureModel();
}
return fm;
}
String currentFixture = null;
private FixtureManager() {
}
/**
* Check if the pass fixture is the current fixture.
*
* @param f
* The fixture to be tested
*
* @return true if it's the current fixture, false if not.
*/
public boolean isCurrent(Fixture f) {
return f.getName().equals(currentFixture);
}
/**
* init the fixture model. Should be called when the model changes.
*/
public void initFixtureModel() {
currentFixture = RootFixture.getInstance().getName();
allFixtures = new HashMap<String, Fixture>();
allFixtures.put(currentFixture, RootFixture.getInstance());
ClassPathFixtureCollector cpfc = new ClassPathFixtureCollector();
Enumeration<String> enum1 = cpfc.collectTests();
while (enum1.hasMoreElements()) {
Class<?> c = null;
try {
String classToLoad = enum1.nextElement().toString();
c = LoadersManager.getInstance().getLoader().loadClass(classToLoad);
} catch (Exception e) {
log.log(Level.FINE, "Unable to load class", e);
continue;
}
if (!(Fixture.class.isAssignableFrom(c))) {
continue;
}
Object t;
try {
t = createFixtureObject(c);
} catch (Exception e) {
log.log(Level.FINE, "Unable to create fixture object", e);
continue;
}
if (t != null && t instanceof Fixture) {
if (t instanceof RootFixture) {
continue;
}
Fixture f = (Fixture) t;
allFixtures.put(f.getName(), f);
}
}
}
/**
* Get the path to fixture.
*
* @param fixture
* The fixture to find the path to.
*
* @return Return a vector of the fixture in the path.
* @exception Exception
*/
public Vector<Fixture> getFixturePath(Fixture fixture) throws Exception {
Vector<Fixture> v = getFixturePath(fixture.getName());
return v;
}
/**
* Create a Vector of all fixtures on the path to the given Fixture,
* The parents are first in the path
* @param fixtureName
* @return
* @throws Exception
*/
private Vector<Fixture> getFixturePath(String fixtureName) throws Exception {
Vector<Fixture> fixtures = new Vector<Fixture>();
Fixture fixture = (Fixture) allFixtures.get(fixtureName);
if (fixture == null) {
throw new Exception("Unknown fixture: " + fixtureName);
}
fixtures.add(fixture);
while (fixture.getParentFixture() != null) {
Fixture parentFixture = (Fixture) allFixtures.get(fixture.getParentFixture().getName());
if (parentFixture == null) {
throw new Exception("Unknown fixture: " + fixture.getParentFixture().getName());
}
if (fixtures.contains(parentFixture)) {
throw new Exception("Fixture error, loop found");
}
fixtures.add(0, parentFixture);
fixture = parentFixture;
}
return fixtures;
}
private void removeIdenticals(Vector<Fixture> down, Vector<Fixture> up) {
while (true) {
if (down.size() == 0 || up.size() == 0) {
return;
}
if (!down.firstElement().equals(up.firstElement())) {
return;
}
down.removeElementAt(0);
up.removeElementAt(0);
}
}
/**
* Navigate to the fixture.
*
* @param fixtureName
* The fixture to navigate to.
*
* @exception Throwable
*/
public void goTo(String fixtureName) throws Throwable {
if (isDisableFixture()) {
return;
}
fireStart();
try {
Vector<Fixture> down;
Vector<Fixture> up;
down = getFixturePath(currentFixture);
up = getFixturePath(fixtureName);
removeIdenticals(down, up);
Collections.reverse(down);
for (int i = 0 ; i < down.size() ; i++) {
Fixture fixture = (Fixture) down.elementAt(i);
fireAboutToChange(fixture);
fixture.run(Fixture.TEARDOWN_DIRECTION);
Class<?> p = fixture.getParentFixture();
if (p == null) {
break;
}
setCFixture(p.getName());
fireFixtureChange((Fixture) allFixtures.get(currentFixture));
}
for (int i = 0; i < up.size(); i++) {
Fixture fixture = (Fixture) up.elementAt(i);
fixture.run(Fixture.SETUP_DIRECTION);
setCFixture(fixture.getName());
fireFixtureChange(fixture);
}
} finally {
fireEnd();
}
}
/**
* Navigate to the fixture using the failTearDownPath
*
* @param fixtureName
* The fixture name to navigate to.
*
* @exception Throwable
*/
public void failTo(String fixtureName) throws Throwable {
if (isDisableFixture()) {
return;
}
fireStart();
try {
Vector<Fixture> down = getFixturePath(currentFixture);
if (!removeNotInDownPath(down, fixtureName)) {
throw new Exception("No down path to: '" + fixtureName + "' from '" + currentFixture + "'");
}
Collections.reverse(down);
for (int i = 0; i < down.size(); i++) {
Fixture fixture = (Fixture) down.elementAt(i);
fireAboutToChange(fixture);
fixture.run(Fixture.TEARDOWN_FAIL_DIRECTION);
if (fixture.getParentFixture() == null) {
break;
}
setCFixture(fixture.getParentFixture().getName());
fireFixtureChange((Fixture) allFixtures.get(currentFixture));
}
} finally {
fireEnd();
}
}
private boolean removeNotInDownPath(Vector<Fixture> path, String fixtureName) {
if (fixtureName == null) {
return true;
}
while (path.size() > 0) {
Fixture fixture = (Fixture) path.elementAt(0);
if (fixture.getName().equals(fixtureName)) {
path.removeElementAt(0);
return true;
} else {
path.removeElementAt(0);
}
}
return false;
}
/**
* Get all the childrens of a fixture.
*
* @param parent
* The parent fixture to get it childrens.
*
* @return A vector with all the childrens fixtures.
*/
public ArrayList<Fixture> getAllChildrens(Fixture parent) {
ArrayList<Fixture> childrens = new ArrayList<Fixture>();
Iterator<Fixture> iter = allFixtures.values().iterator();
while (iter.hasNext()) {
Fixture fixture = (Fixture) iter.next();
Class<?> fixtureParent = fixture.getParentFixture();
if (fixtureParent != null) {
if (parent.getClass().getName().equals(fixtureParent.getName())) {
childrens.add(fixture);
}
}
}
return childrens;
}
private Object createFixtureObject(Class<?> testClass) throws Exception {
Constructor<?> constructor;
constructor = testClass.getConstructor(new Class<?>[0]);
Object test;
test = constructor.newInstance(new Object[0]);
return test;
}
public void addListener(FixtureListener listener) {
listeners.addElement(listener);
}
/**
* Remove a fixture listener.
*
* @param listener
* the listener to be removed.
*/
public void removeListener(FixtureListener listener) {
listeners.removeElement(listener);
}
private void fireStart() {
Enumeration<FixtureListener> enum1 = listeners.elements();
while (enum1.hasMoreElements()) {
enum1.nextElement().startFixturring();
}
}
private void fireEnd() {
Enumeration<FixtureListener> enum1 = listeners.elements();
while (enum1.hasMoreElements()) {
enum1.nextElement().endFixturring();
}
}
private void fireFixtureChange(Fixture fixture) {
Enumeration<FixtureListener> enum1 = listeners.elements();
while (enum1.hasMoreElements()) {
enum1.nextElement().fixtureChanged(fixture);
}
}
private void fireAboutToChange(Fixture fixture) {
Enumeration<FixtureListener> enum1 = listeners.elements();
while (enum1.hasMoreElements()) {
enum1.nextElement().aboutToChangeTo(fixture);
}
}
/**
* Get the current fixture.
*
* @return The current fixture name.
*/
public String getCurrentFixture() {
return currentFixture;
}
/**
* Set the current fixture. it will be done without executing the fixture
* path.
*
* @param currentFixture
* The new fixture.
*
* @exception Exception
*/
public void setCurrentFixture(String currentFixture) throws Exception {
Fixture f = (Fixture) allFixtures.get(currentFixture);
if (f == null) {
throw new Exception("Unknown fixture: " + currentFixture);
}
fireFixtureChange(f);
setCFixture(currentFixture);
}
private void setCFixture(String cfixture) {
currentFixture = cfixture;
}
public Fixture getFixture(String className) {
return (Fixture) allFixtures.get(className);
}
/**
* Is the fixture modle disabled
*
* @return true if disable, false if not.
*/
public boolean isDisableFixture() {
return disableFixture;
}
/**
* Set the disable status. If disabled no fixture execution will be done.
*
* @param disableFixture
* The disable status to be set.
*/
public void setDisableFixture(boolean disableFixture) {
this.disableFixture = disableFixture;
}
}