/* * Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved. */ package jsystem.framework.system; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Properties; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import jsystem.framework.IgnoreMethod; import jsystem.framework.RunProperties; import jsystem.framework.analyzer.AnalyzerImpl; import jsystem.framework.report.ListenerstManager; import jsystem.framework.report.Reporter; import jsystem.framework.report.Reporter.EnumReportLevel; import jsystem.framework.sut.Sut; import jsystem.framework.sut.SutFactory; import jsystem.utils.beans.BeanElement; import jsystem.utils.beans.BeanUtils; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /* * import electric.xml.Element; import electric.xml.Text; import * electric.xml.Attribute; */ /** * System Object is a convention to represent the setup/system you are working on with a single object. The steps in the tests will be * operations on the setup/system object. * * @author Guy Arieli */ public abstract class SystemObjectImpl extends AnalyzerImpl implements SystemObject { private static Logger log = Logger.getLogger(SystemObjectImpl.class.getName()); private String tagName = null; private String name = null; private String path = null; private String referencePath = null; protected boolean isClosed = false; private int lifeTime = SystemObject.PERMANENT_LIFETIME; protected SystemObjectManager system = SystemManagerImpl.getInstance(); protected Sut sut = SutFactory.getInstance().getSutInstance(); protected Reporter report = ListenerstManager.getInstance(); /** * Properties service that can be used to save properties and share it with other tests. Properties that are saved in one test can be * read in other tests as long as they are in the same run. */ protected RunProperties runProperties = RunProperties.getInstance(); protected SystemObjectManager systemManager = SystemManagerImpl.getInstance(); protected Vector<SystemObject> systemObjects = new Vector<SystemObject>(); protected Properties properties = new Properties(); SystemObject parent = null; private Semaphore lockObject = new Semaphore(1); private int checkStatus; private int soArrayIndex = -1; /** * Set the System Object name. * * @param name * The object name. */ @Override @IgnoreMethod public void setTagName(String name) { this.tagName = name; } /** * Get the system object name. * * @return The system object name. */ @Override @IgnoreMethod public String getName() { return name; } /** * Get the object lifetime. The default lifetime is PERMANENT_LIFETIME. * * @return the object lifetime. */ @Override @IgnoreMethod public int getLifeTime() { return lifeTime; } /** * Set the object lifetime. Can be one of two: TEST_LIFETIME or PERMANENT_LIFETIME. * * @param lifeTime * The object lifetime. */ @Override @IgnoreMethod public void setLifeTime(int lifeTime) { this.lifeTime = lifeTime; } /** * Get the object XPath in the sut XML file. * * @return Object XPath. */ @Override @IgnoreMethod public String getXPath() { return path; } /** * Set the object XPath. * * @param path * Object XPath. */ @Override @IgnoreMethod public void setXPath(String path) { this.path = path; } /** * see interface doc */ @Override @IgnoreMethod public String getReferenceXPath() { return referencePath; } /** * see interface doc */ @Override @IgnoreMethod public void setReferenceXPath(String path) { this.referencePath = path; } /** * Is the object close. * * @return Return true if closed else return false. */ @Override @IgnoreMethod public boolean isClosed() { return isClosed; } /** * Set the object isClosed status. * * @param isClosed * the isClosed status. */ @Override @IgnoreMethod public void setClose(boolean isClosed) { this.isClosed = isClosed; } /** * Init all the class field from the xml * * @throws Exception */ @IgnoreMethod protected void initFields() throws Exception { Class<?> thisClass = this.getClass(); Field[] fields = thisClass.getFields(); for (Field currentField : fields) { String fieldName = currentField.getName(); if (SystemObject.class.isAssignableFrom(currentField.getType())) { SystemObject sObject = (SystemObject) currentField.get(this); if (sObject == null || sObject.isClosed()) { sObject = getChildSystemObject(fieldName, -1); try { currentField.set(this, sObject); } catch (Exception t) { log.warning("Fail to init field: " + fieldName); } } systemObjects.remove(sObject); systemObjects.addElement(sObject); } else { if (currentField.getType().isArray() && SystemObject.class.isAssignableFrom(currentField.getType().getComponentType())) { int lastIndex = getObjectLastIndex(getXPath(), fieldName); if (lastIndex < 0) { continue; } SystemObject[] array = (SystemObject[]) currentField.get(this); if (array == null) { Object arrayObject = Array.newInstance(currentField.getType().getComponentType(), lastIndex + 1); for (int arrayIndex = 0; arrayIndex <= lastIndex; arrayIndex++) { SystemObject childSystemObject = getChildSystemObject(fieldName, arrayIndex); Array.set(arrayObject, arrayIndex, childSystemObject); systemObjects.remove(childSystemObject); systemObjects.addElement(childSystemObject); if (childSystemObject != null) { childSystemObject.setSOArrayIndex(arrayIndex); } } currentField.set(this, arrayObject); } else { for (int arrayIndex = 0; arrayIndex < array.length; arrayIndex++) { if (array[arrayIndex] == null || array[arrayIndex].isClosed()) { array[arrayIndex] = getChildSystemObject(fieldName, arrayIndex); systemObjects.remove(array[arrayIndex]); systemObjects.addElement(array[arrayIndex]); } } } } } } } private SystemObject getChildSystemObject(String fieldName, int index) throws Exception { SystemObject res = ((SystemManagerImpl) system).getSystemObject(getXPath(), fieldName, index, this, true, getReferenceXPath(), sut); return res; } @IgnoreMethod protected void setSetters() { // *** Class<?> thisClass = this.getClass(); HashMap<String, BeanElement> beans = BeanUtils.getBeanMap(thisClass, false, true, BeanUtils.getBasicTypes()); try { Enumeration<Object> propertiesKeys = properties.keys(); while (propertiesKeys.hasMoreElements()) { String name = (String) propertiesKeys.nextElement(); BeanElement beanElement = beans.get(name); if (beanElement == null) { continue; } try { BeanUtils.invoke(this, beanElement.getSetMethod(), properties.getProperty(name), beanElement.getType()); } catch (Throwable tt) { log.log(Level.INFO, "Fail to set setters: " + beanElement.getSetMethod().getName(), tt); } } } catch (Throwable t) { log.log(Level.INFO, "Fail to set setters", t); } // --- } /** * Please note: If a system object (SystemObject A) is created by reference to another system object (SystemObject B) when this method * is called (at the initiation of the SystemObject), the getXPath method return the path to B and the get getReferenceXPath returns the * path to A At the end of the initiation process the paths are replaced by the SystemManagerImpl * */ @IgnoreMethod protected void initProperties() { initPropertiesFromPath(getXPath()); String referenceXPath = getReferenceXPath(); if (referenceXPath != null && !"".equals(referenceXPath.trim())) { initPropertiesFromPath(referenceXPath); } } private void initPropertiesFromPath(String path) { try { List<Node> nodeList = sut.getAllValues(path + "/*"); for (Node currentNode : nodeList) { Element element = (Element) currentNode; String name = element.getNodeName(); String text = null; NodeList childNodeList = element.getChildNodes(); for (int childIndex = 0; childIndex < childNodeList.getLength(); childIndex++) { Node currentChild = childNodeList.item(childIndex); if (currentChild.getNodeType() == Node.TEXT_NODE) { text = currentChild.getNodeValue(); break; } } if (text != null) { properties.setProperty(name, text); } } } catch (Exception e) { log.log(Level.INFO, "Fail to init properties", e); } } @Override @IgnoreMethod public void init() throws Exception { initProperties(); initFields(); setSetters(); } /** * Close all children of the system object. */ @IgnoreMethod protected void closeFields() { // Why creating a new array from vector ? SystemObjectImpl[] sysObjs = systemObjects.toArray(new SystemObjectImpl[systemObjects.size()]); for (int i = 0; i < sysObjs.length; i++) { if (sysObjs[i] != null) { sysObjs[i].close(); } } systemObjects = new Vector<SystemObject>(); } /** * Close the system object. */ @Override @IgnoreMethod public void close() { // Close all children closeFields(); // Indicate system object is closed setClose(true); // Remove system object from parent system object SystemObject parent = getParent(); if (parent != null) { parent.getChildren().remove(this); } if (SystemManagerImpl.getInstance() != null) { // Remove system object from system objects manager SystemManagerImpl.getInstance().removeSystemObject(this); } } protected String fixPath(String relativePath) { return pathConcat(path, relativePath); } @IgnoreMethod private String pathConcat(String path1, String path2) { return path1 + (path1.endsWith("/") ? "" : "/") + path2; } @IgnoreMethod private int getObjectLastIndex(String path, String name) throws Exception { String xPath = path + "/" + name; List<Node> nodeList = sut.getAllValues(xPath); if (nodeList == null || nodeList.size() == 0) { return -1; } int lastIndex = -1; for (Node currentNode : nodeList) { String indexAttrib = ((Element) currentNode).getAttribute("index"); if (indexAttrib == null) { throw new Exception("No index attribute was found"); } try { int currentIndex = Integer.parseInt(indexAttrib); if (currentIndex > lastIndex) { lastIndex = currentIndex; } } catch (NumberFormatException e) { throw new Exception("Index attribute is not integer: " + indexAttrib, e); } } return lastIndex; } /** * @return Returns the tagName. */ @Override @IgnoreMethod public String getTagName() { return tagName; } /** * @param name * The name to set. */ @Override @IgnoreMethod public void setName(String name) { this.name = name; } /** * return the parent system object null in case of root. */ @Override @IgnoreMethod public SystemObject getParent() { return parent; } @Override @IgnoreMethod public void setParent(SystemObject parent) { this.parent = parent; } @Override @IgnoreMethod public Properties getProperties() { return properties; } @IgnoreMethod public void setProperties(Properties properties) { this.properties = properties; } @Override @IgnoreMethod public void setOpenCloseStatusAll(boolean status) { setClose(status); if (systemObjects != null) { for (int systemObjectIndex = 0; systemObjectIndex < systemObjects.size(); systemObjectIndex++) { SystemObject currentSystemObject = systemObjects.elementAt(systemObjectIndex); if (currentSystemObject != null) { currentSystemObject.setOpenCloseStatusAll(status); } } } } @Override @IgnoreMethod public Vector<SystemObject> getChildren() { return systemObjects; } @Override @IgnoreMethod public String getProperty(String key) { return properties.getProperty(key); } @Override @IgnoreMethod public void lock() throws Exception { system.lockObject(this); } @Override @IgnoreMethod public void release() { system.releaseObject(this); } @Override public Semaphore getLockObject() { return lockObject; } @Override @IgnoreMethod public void check() throws Exception { report.report(name + ": Perform Check"); setCheckStatus(SystemObject.CHECK_NOT_IMPL); } @Override @IgnoreMethod public int getCheckStatus() { return checkStatus; } @IgnoreMethod public void setCheckStatus(int checkStatus) { this.checkStatus = checkStatus; } @Override @IgnoreMethod public void pause() { // defualt empty implementation } @Override @IgnoreMethod public void resume() { // defualt empty implementation } @Override @IgnoreMethod public int getSOArrayIndex() { return soArrayIndex; } @Override @IgnoreMethod public void setSOArrayIndex(int index) { this.soArrayIndex = index; } private long exitTimeout = 1000; /** * @return time to wait for the system object to close */ @Override public long getExitTimeout() { return exitTimeout; } /** * @param exitTimeout * time to wait for the system object to close */ @Override @IgnoreMethod public void setExitTimeout(long exitTimeout) { this.exitTimeout = exitTimeout; } /** * This flag allows the test to control the amount of messages the system object sends to the reporter. <br> * {@link SystemObjectImpl#report(String)} <br> {@link SystemObjectImpl#report(String, int)} <br> * {@link SystemObjectImpl#report(String, String, int)} <br> {@link SystemObjectImpl#report(String, String, boolean)} <br> * {@link SystemObjectImpl#startLevel(String, EnumReportLevel)} <br> {@link SystemObjectImpl#stopLevel()} */ protected boolean printStatuses = true; public boolean isPrintStatuses() { return printStatuses; } /** * @param printStatuses * true - send report messages, false don't send report messages */ @IgnoreMethod public void setPrintStatuses(boolean printStatuses) { this.printStatuses = printStatuses; } /** * This method sends report message only if {@link SystemObjectImpl#printStatuses} == true * * @param title */ protected void report(String title) { report(title, Reporter.PASS); } /** * This method sends report message only if {@link SystemObjectImpl#printStatuses} == true * * @param title * @param status */ protected void report(String title, int status) { if (isPrintStatuses()) { report(title, null, status); } } /** * This method sends report message only if {@link SystemObjectImpl#printStatuses} == true * * @param title * @param message * @param status */ protected void report(String title, String message, int status) { if (isPrintStatuses()) { report.report(title, message, status); } } /** * This method sends report message only if {@link SystemObjectImpl#printStatuses} == true */ protected void report(String title, String message, boolean status) { if (isPrintStatuses()) { report.report(title, message, status); } } /** * This method starts report level only if {@link SystemObjectImpl#printStatuses} == true The level will start in CurrentPlace. * * @param message * @throws IOException */ protected void startLevel(String message) throws IOException { startLevel(message, EnumReportLevel.CurrentPlace); } /** * This method starts report level only if {@link SystemObjectImpl#printStatuses} == true * * @param message * @param level * Where to start the level * @throws IOException */ protected void startLevel(String message, EnumReportLevel level) throws IOException { if (isPrintStatuses()) { report.startLevel(message, level); } } /** * This method stops report level only if {@link SystemObjectImpl#printStatuses} == true * * @throws IOException */ protected void stopLevel() throws IOException { if (isPrintStatuses()) { report.stopLevel(); } } }