/* * Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved. */ package jsystem.framework.system; import java.io.File; import java.io.FileNotFoundException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import jsystem.framework.FrameworkOptions; import jsystem.framework.JSystemProperties; import jsystem.framework.report.ListenerstManager; import jsystem.framework.sut.Sut; import jsystem.framework.sut.SutFactory; import jsystem.runner.loader.LoadersManager; import jsystem.utils.StringUtils; import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestListener; import org.apache.commons.jxpath.JXPathContext; import org.apache.xpath.XPathAPI; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * The SystemManagerImpl is responsible of creating, retrieving and closing * of all SystemObjects in the environment created by the "getSystemObject" method * * All SystemObjects are gathered to a HashMap allowing retrieval of all pre-created SystemObjects */ public class SystemManagerImpl implements SystemObjectManager, TestListener { private static Logger log = Logger.getLogger(SystemManagerImpl.class.getName()); /* * Singleton object */ private static SystemManagerImpl manager = null; /** * Sut object for setup information */ private Sut sut = SutFactory.getInstance().getSutInstance(); /** * Repository for all the running system objects */ private Map<String, SystemObject> systemObjects; private SystemManagerImpl(){ resetSeystemObjectsMap(); ListenerstManager.getInstance().addListener(this); } public static SystemManagerImpl getInstance(){ if (manager == null){ if (JSystemProperties.getInstance().isReporterVm() && JSystemProperties.getInstance().isJsystemRunner()) { return null; } manager = new SystemManagerImpl(); } return manager; } public SystemObject getSystemObject(String name, String sutName, boolean forceNew) throws Exception{ Sut sut = SutFactory.getInstance().getNewSutInstance(); File file = new File(SutFactory.getInstance().getSutDirectory(), sutName.toLowerCase().endsWith(".xml")? sutName: sutName + ".xml"); if(!file.exists()){ throw new FileNotFoundException("Could not find SUT file name: " + file.getAbsolutePath()); } sut.setSutXml(file, false); SystemObject object = getSystemObject("/sut", name, -1, null, forceNew, null, sut); if(object == null){ throw new Exception("Fail to init system object: " + name); } return object; } public SystemObject getSystemObject(String name, Document doc, boolean forceNew) throws Exception{ Sut sut = SutFactory.getInstance().getNewSutInstance(); sut.setDocument(doc); SystemObject object = getSystemObject("/sut", name, -1, null, forceNew, null, sut); if(object == null){ throw new Exception("Fail to init system object: " + name); } return object; } public SystemObject getSystemObject(String name) throws Exception{ SystemObject object = getSystemObject("/sut", name, -1, null, false, null, sut); if(object == null){ throw new Exception("Fail to init system object: " + name); } return object; } public SystemObject getSystemObject(String path, String name, SystemObject parent) throws Exception { return getSystemObject(path,name,-1, parent); } public synchronized SystemObject getSystemObject(String path, String name, int index, SystemObject parent) throws Exception { return getSystemObject(path, name, index, parent, false,null); } public synchronized SystemObject getSystemObject(String path, String name, int index, SystemObject parent, boolean isNew,String referenceXPath, Sut usedSut) throws Exception { String xPath; String tag; if(index < 0){ tag = name; } else { tag = name + "[@index=\"" + index + "\"]"; name = name + "[" + index + "]"; } xPath = path + "/" + tag; SystemObject systemObject = null; /* * if isNew is set to true will not check if the object is in the repository * and will init it in any case. */ if(!isNew){ systemObject = (SystemObject)systemObjects.get(xPath); if (systemObject != null && !systemObject.isClosed()){ if (systemObject instanceof SystemObjectImpl){ ((SystemObjectImpl)systemObject).initFields(); } return systemObject; } } String ref = null; /* * check if the ref tag exits. If exist will try to init the object * from the referance. */ try { ref = usedSut.getValue(xPath +"/@ref"); } catch(Exception e){ log.log(Level.FINE,"the ref: " + xPath + " was not found",e); } if(ref != null){ // will init the object from the referance systemObject = processReferance(ref, xPath, parent, tag, name); return systemObject; } else { // will init the object from the sut by class name String className; try { className = usedSut.getValue(xPath + "/class/text()"); } catch(Exception e){ log.log(Level.FINE,"the object: " + xPath + " wasn't init",e); return null; } if (className == null){ throw new Exception("Unable to find class atribute to systemObject: " + name); } className = className.trim(); if(className.indexOf('#') >= 0){ // look like the xerses implemantation. We should fix the class name // the inputs look like: [#text: com....] className = className.substring(className.lastIndexOf(' ') + 1, className.length() - 1); } Class<?> c = LoadersManager.getInstance().getLoader().loadClass(className); systemObject = (SystemObject)c.newInstance(); } if(systemObject instanceof SystemObjectImpl){ ((SystemObjectImpl)systemObject).sut = usedSut; } systemObject.setTagName(tag); systemObject.setName(name); recursiveUpdateOfXPath(systemObject,xPath,xPath); if (referenceXPath != null){ referenceXPath = ref !=null? referenceXPath+ref :referenceXPath; } systemObject.setReferenceXPath(referenceXPath); systemObject.setParent(parent); systemObject.init(); systemObject.setClose(false); /* * If set to new will not add it to the systemObjects repository. * The calling process should manage it (in our case the recursive call). */ if(!isNew){ systemObjects.remove(xPath); systemObjects.put(xPath, systemObject); } return systemObject; } public SystemObject getSystemObjectByXPath(String xpath) throws Exception{ int startIndex = 1; String[] paths = xpath.split("/"); if(paths[startIndex].equals("sut")){ startIndex++; } String soName = paths[startIndex]; startIndex++; SystemObject current = getSystemObject(soName); main: for(int i = startIndex; i < paths.length; i++){ if(paths[i].trim().isEmpty()){ continue; } ArrayList<Field> fields = getSystemObjectField(current.getClass()); String path = paths[i]; if(path.contains("[")){ path = path.substring(0, path.indexOf("[")); } for(Field f: fields){ if(f.getName().equals(path)){ if(f.getType().isArray()){ SystemObject[] array = (SystemObject[])f.get(current); Matcher matcher = Pattern.compile("\\[(.*)\\]").matcher(paths[i]); if(matcher.find()){ String condition = matcher.group(1); JXPathContext context = JXPathContext.newContext(array); current = (SystemObject)context.getValue(".[" + condition + "]"); } else { current = array[0]; } break main; } else { current = (SystemObject)f.get(current); break main; } } } throw new Exception("Could not found path " + paths[i]); } return current; } /** * Get all the fields that are system object themself of a given class * @param object the class to process. * @return a list of all the system objects fields. */ public static ArrayList<Field> getSystemObjectField(Class<? extends SystemObject> baseClass){ ArrayList<Field> systemObjectFields = new ArrayList<Field>(); try { Field[] allFields = baseClass.getFields(); for(Field f: allFields){ /* * It should be assignable from SystemObject or * array that it's component can be assign. */ if(SystemObject.class.isAssignableFrom(f.getType())){ systemObjectFields.add(f); } else if(f.getType().isArray() && SystemObject.class.isAssignableFrom(f.getType().getComponentType())){ systemObjectFields.add(f); } } } catch (Throwable t){ } return systemObjectFields; } public synchronized SystemObject getSystemObject(String path, String name, int index, SystemObject parent, boolean isNew,String referenceXPath) throws Exception { return getSystemObject(path, name, index, parent, isNew, referenceXPath, sut); } private void recursiveUpdateOfXPath(SystemObject sysObj,String oldPath, String newPath) { String currentPath = sysObj.getXPath(); if (currentPath == null || "".equals(currentPath)){ currentPath = newPath; } String afterUpdate = StringUtils.replace(currentPath, oldPath, newPath); sysObj.setXPath(afterUpdate); Iterator<?> i = sysObj.getChildren().iterator(); while (i.hasNext()){ SystemObject son = (SystemObject)i.next(); if (son == null){ continue; } recursiveUpdateOfXPath(son, currentPath, afterUpdate); } } private SystemObject processReferance(String ref, String xPath, SystemObject parent, String tag, String name) throws Exception{ if(ref.indexOf('#') >= 0){ // look like the xerses implemantation. We should fix the class name // the inputs look like: [#text: com....] ref = ref.substring(ref.lastIndexOf(' ') + 1, ref.length() - 1); } if(!ref.startsWith("/")){ // if the referance is not start with / add it ref = "/" + ref; } if(!ref.startsWith("/sut/")){ // if the referance is not start with /sut add it ref = "/sut" + ref; } /* * setNew if set to false will use an existing system object. */ boolean setNew = true; try { if("false".equals(sut.getValue(xPath +"/@new"))){ setNew = false; } } catch(Exception e){ // the attribute is not found } /* * System object name */ String soName = null; /* * System object path */ String soPath = null; /* * System object index */ int soIndex = -1; /* * Extract the soName and soIndex from the ref */ int lastSleshIndex = ref.lastIndexOf('/'); /* * The soPath is th estring before the last '/' * For example: /sut/cli * the path will be /sut and the name will be cli */ soPath = ref.substring(0, lastSleshIndex); String namePlusIndex = ref.substring(lastSleshIndex + 1); int indexStart = namePlusIndex.indexOf("[@index=\'"); /* * Process the option that index atribute is found in the name * For example /sut/cli[@index="3"] */ if( indexStart >= 0){ soName = namePlusIndex.substring(0, indexStart); StringBuffer number = new StringBuffer(); for(int i = indexStart + "[@index=\'".length(); i < namePlusIndex.length(); i++){ char c = namePlusIndex.charAt(i); if(Character.isDigit(c)){ number.append(c); } else { break; } } if(number.length() > 0){ soIndex = Integer.parseInt(number.toString()); } else { throw new Exception("The referance could not be parsed: " + ref); } } else { soName = namePlusIndex; } /* * Recursivly get the system object */ SystemObject systemObject = getSystemObject(soPath, soName, soIndex, parent, setNew,xPath); if(systemObject == null){ throw new Exception("Init system object fail ref: " + ref +" was not found"); } /* * If the object is a new object all the object information like * xpath, parent and more is init. */ if(setNew){ systemObject.setTagName(tag); systemObject.setName(name); recursiveUpdateOfXPath(systemObject,systemObject.getXPath(),xPath); systemObject.setReferenceXPath(ref); systemObject.setParent(parent); systemObject.setClose(false); systemObjects.remove(xPath); systemObjects.put(xPath, systemObject); } return systemObject; } public synchronized void addError(Test test, Throwable t) { Iterator<?> iter = systemObjects.values().iterator(); while (iter.hasNext()) { SystemObject d = (SystemObject) iter.next(); if (d == null) { continue; } if (d instanceof TestListener) { TestListener tl = (TestListener) d; tl.addError(test, t); } } } private long totalExitTimeout = 15000; /** * @return total time to wait for all system objects to close */ public long getTotalExitTimeout() { return totalExitTimeout; } /** * @param totalExitTimeout * total time to wait for all system objects to close */ public void setTotalExitTimeout(long totalExitTimeout) { this.totalExitTimeout = totalExitTimeout; } public void closeAllObjects() { long exitTimeout = JSystemProperties.getInstance().getLongPreference(FrameworkOptions.EXIT_TIMEOUT, getTotalExitTimeout()); SystemObject[] sos = new SystemObject[0]; synchronized (this) { sos = systemObjects.values().toArray(new SystemObject[0]); resetSeystemObjectsMap(); } //we want to close only root system objects. //system objects which has a parent will be closed by their parent. ArrayList<SystemObject> objectsWithoutParents = new ArrayList<SystemObject>(); for (SystemObject sysObj:sos){ if (sysObj.getParent() == null){ objectsWithoutParents.add(sysObj); } } sos = objectsWithoutParents.toArray(new SystemObject[0]); //if there are no system objects to close no need //to create a thread pool. if (sos.length == 0){ return; } ArrayList<SystemObjectCloseThread>threads = new ArrayList<SystemObjectCloseThread>(); for(SystemObject so: sos){ SystemObjectCloseThread thread = new SystemObjectCloseThread(so); threads.add(thread); thread.start(); } if (exitTimeout == 0) { // not waiting return; } // Wait for all system objects to close at least exitTimeout milliseconds while (System.currentTimeMillis() - System.currentTimeMillis() < exitTimeout){ if (threads.size() == 0) { break; } for(int i = 0; i < threads.size(); i++){ try { // Wait for the system object close at least os.timeOut milliseconds threads.get(i).join(threads.get(i).getExitTimeout()); } catch (InterruptedException e) { // ignored } if (!threads.get(i).isAlive()) { threads.remove(i); i--; } } } } public void removeSystemObject(SystemObject o) { systemObjects.remove(o.getXPath()); } public void lockObject(SystemObject sobject) throws Exception { sobject.getLockObject().acquire(); } private synchronized void initLockObjects() { Iterator<?> iter = systemObjects.values().iterator(); while (iter.hasNext()) { SystemObject o = (SystemObject) iter.next(); synchronized (o.getLockObject()) { o.getLockObject().release(); } } } public void releaseObject(SystemObject sobject) { sobject.getLockObject().release(); } public synchronized void addFailure(Test test, AssertionFailedError t) { Iterator<?> iter = systemObjects.values().iterator(); while (iter.hasNext()) { SystemObject d = (SystemObject) iter.next(); if (d == null) { continue; } if (d instanceof TestListener) { TestListener tl = (TestListener) d; tl.addFailure(test, t); } } } public synchronized void endTest(Test test) { initLockObjects(); Object[] devs = systemObjects.values().toArray(); for (int i = 0; i < devs.length; i++) { SystemObject d = (SystemObject) devs[i]; if (d == null) { continue; } if (d.getLifeTime() == SystemObject.TEST_LIFETIME) { try { if (!d.isClosed()) { d.close(); } } finally { systemObjects.remove(d.getXPath()); } } else if (d instanceof TestListener) { TestListener tl = (TestListener) d; tl.endTest(test); } } } public synchronized void startTest(Test test) { initLockObjects(); Iterator<?> iter = systemObjects.values().iterator(); while (iter.hasNext()) { SystemObject d = (SystemObject) iter.next(); if (d == null) { continue; } if (d instanceof TestListener) { TestListener tl = (TestListener) d; tl.startTest(test); } } } public void checkObject(String sobjectName) throws Exception { SystemObjectImpl so = (SystemObjectImpl) getSystemObject(sobjectName); so.check(); } /** * * @param onlySO * true for getting only the Objects implementing SystemObject * * * @return Vector of System Object Class Names */ public static Vector<String> getAllObjects(boolean onlySO) { Vector<String> sysObjs = new Vector<String>(); List<?> list = null; try { /** * get "sut" node */ list = SutFactory.getInstance().getSutInstance().getAllValues("/sut"); Element node = (Element) list.get(0); /** * get all childes for sut node */ NodeList nl = node.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Element el; if ((nl.item(i)) instanceof Element) { boolean addObject = false; el = (Element) nl.item(i); /** * bring only SOs. */ if (onlySO) { /** * get Class Element */ Element subEl = (Element) XPathAPI.selectSingleNode(el, "./class"); if (subEl != null) { /** * getting right Class Loader */ ClassLoader cl = LoadersManager.getInstance().getLoader(); /** * Getting SO Class */ Class<?> soClass = cl.loadClass(subEl.getTextContent()); /** * find out if in any level the class is implenting * SystemObject */ while (soClass != null && !addObject) { Class<?>[] interfaces = soClass.getInterfaces(); for (int j = 0; j < interfaces.length; j++) { if (interfaces[j].getClass().equals(SystemObject.class.getClass())) { addObject = true; break; } } soClass = soClass.getSuperclass(); } } } else { addObject = true; } if (addObject) sysObjs.add(el.getNodeName()); } } } catch (Exception e) { log.log(Level.WARNING, "Fail To get all System Objects"); } return sysObjs; } /** * return All Objects class name from sut * * @return Vector */ public static Vector<String> getAllObjects() { return getAllObjects(false); } public void pausedAllObjects() { Iterator<?> iter = systemObjects.values().iterator(); while (iter.hasNext()) { SystemObject d = (SystemObject) iter.next(); if (d == null) { continue; } d.pause(); } } public void resumeAllObjects() { Iterator<?> iter = systemObjects.values().iterator(); while (iter.hasNext()) { SystemObject d = (SystemObject) iter.next(); if (d == null) { continue; } d.resume(); } } /** * Resets the systemObjects map and creates a new thread safe map. */ private void resetSeystemObjectsMap(){ systemObjects = new HashMap<String, SystemObject>(); } /** * Add a system object to the list of managed system objects.<br> * It is assumed that the system object was already initialized elsewhere.<br> * This causes the system object to close when closeAllObjects is called.<br> * * @param systemObject - the system object to add. */ public void addSystemObject(SystemObject systemObject) { String xPath = "/sut/" + systemObject.getName(); systemObjects.put(xPath, systemObject); } } class SystemObjectCloseThread extends Thread{ private static Logger log = Logger.getLogger(SystemObjectCloseThread.class.getName()); SystemObject so; public SystemObjectCloseThread(SystemObject so){ this.so = so; } public void run(){ if(so != null){ setName("Close" + so.getName()); log.fine("Closing " + so.getName()); so.close(); } } /** * @return time to wait for the system object to close */ public long getExitTimeout() { return so.getExitTimeout(); } }