org.suren.autotest.web.framework.settings.SettingUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.suren.autotest.web.framework.settings.SettingUtil.java

Source

/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.suren.autotest.web.framework.settings;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.VisitorSupport;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.dom4j.xpath.DefaultXPath;
import org.jaxen.SimpleNamespaceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.suren.autotest.web.framework.core.ConfigException;
import org.suren.autotest.web.framework.core.ConfigNotFoundException;
import org.suren.autotest.web.framework.core.Locator;
import org.suren.autotest.web.framework.core.LocatorAware;
import org.suren.autotest.web.framework.core.PageContext;
import org.suren.autotest.web.framework.core.PageContextAware;
import org.suren.autotest.web.framework.core.ui.AbstractElement;
import org.suren.autotest.web.framework.core.ui.Text;
import org.suren.autotest.web.framework.data.ClasspathResource;
import org.suren.autotest.web.framework.data.DataResource;
import org.suren.autotest.web.framework.data.DataSource;
import org.suren.autotest.web.framework.data.DynamicDataSource;
import org.suren.autotest.web.framework.data.FileResource;
import org.suren.autotest.web.framework.hook.ShutdownHook;
import org.suren.autotest.web.framework.page.Page;
import org.suren.autotest.web.framework.selenium.SeleniumEngine;
import org.suren.autotest.web.framework.util.BeanUtil;
import org.suren.autotest.web.framework.util.StringUtils;
import org.suren.autotest.web.framework.validation.Validation;
import org.xml.sax.SAXException;

/**
 * ?page???
 * @author suren
 * @date Jul 17, 2016 9:01:51 AM
 */
public class SettingUtil implements Closeable {
    private static final Logger logger = LoggerFactory.getLogger(SettingUtil.class);

    private Map<String, Page> pageMap = new HashMap<String, Page>();
    private Map<String, DataSourceInfo> dataSourceMap = new HashMap<String, DataSourceInfo>();
    private Map<String, DynamicDataSource> dynamicDataSourceMap;
    private ApplicationContext context;
    private ShutdownHook shutdownHook;

    /** ? */
    private File configFile;

    private boolean closed = false;

    /** ??Page? */
    private Set<String> excludePageSet = new HashSet<String>();

    /**
     * ?bean?JMX????
     */
    public SettingUtil() {
        context = SpringUtils.getApplicationContext();
        if (context == null || !((AbstractApplicationContext) context).isActive()) {
            context = new ClassPathXmlApplicationContext(new String[] { "classpath*:autoTestContext.xml",
                    "classpath*:applicationContext.xml", "classpath*:beanScope.xml" });
        }

        try {
            //?
            Map<String, PageContextAware> pageContextAwareList = context.getBeansOfType(PageContextAware.class);
            if (pageContextAwareList != null) {
                for (PageContextAware ware : pageContextAwareList.values()) {
                    ware.setPageContext(new PageContext(pageMap));
                }
            }

            //????
            //         IPageMXBean pageMXBean = context.getBean(IPageMXBean.class);
            //         
            //         LocateRegistry.createRegistry(5006);
            //         MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            //         server.registerMBean(pageMXBean,
            //               new ObjectName("org.suren.autotest.web.framework:type=IPageMXBean"));
        } catch (Exception e) {
            logger.error("jmx register process error.", e);
        }

        shutdownHook = new ShutdownHook(this);
        Runtime.getRuntime().addShutdownHook(shutdownHook);

        logger.info("init process done.");
    }

    /**
     * ?
     * 
     * @param filePath
     * @throws DocumentException
     * @throws IOException
     * @throws SAXException 
     */
    public void read(String filePath) throws DocumentException, IOException, SAXException {
        File file = new File(filePath);
        try (FileInputStream fis = new FileInputStream(file)) {
            read(fis);
        }
    }

    /**
     * ??
     * 
     * @param fileName
     * @throws IOException
     * @throws DocumentException xml?
     * @throws SAXException xml?
     */
    public void readFromClassPath(String fileName) throws IOException, DocumentException, SAXException {
        ClassLoader classLoader = this.getClass().getClassLoader();

        try (InputStream inputStream = classLoader.getResourceAsStream(fileName)) {
            if (inputStream == null) {
                throw new ConfigNotFoundException("ClassPath", fileName);
            }

            Validation.validationFramework(inputStream); //?
        } catch (SAXException | IOException e) {
            logger.error("Framework validation process error.", e);
            throw e;
        }

        //??
        try (InputStream confInput = classLoader.getResourceAsStream(fileName)) {
            read(confInput);
        } catch (DocumentException | IOException e) {
            logger.error(String.format("Main config [%s] parse process error.", fileName), e);
            throw e;
        }
    }

    /**
     * ??
     * @param filePath
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws DocumentException 
     * @throws SAXException 
     */
    public void readFromSystemPath(String filePath)
            throws FileNotFoundException, IOException, DocumentException, SAXException {
        configFile = new File(filePath);
        if (!configFile.isFile()) {
            throw new ConfigException(String.format("Target file [%s] is not a file.", filePath));
        } else if (!filePath.endsWith(".xml")) {
            logger.warn("Target file [%s] is not end with .xml", filePath);
        }

        try (InputStream configInput = new FileInputStream(configFile)) {
            read(configInput);
        }
    }

    /**
     * ???
     * 
     * @param inputStream
     * @throws DocumentException
     * @throws IOException 
     * @throws SAXException 
     */
    public void read(InputStream inputStream) throws DocumentException, IOException, SAXException {
        Document document = new SAXReader().read(inputStream);

        parse(document);
    }

    /**
     * ???page
     * @see {@link #initData(int)}
     */
    public void initData() {
        initData(1);
    }

    /**
     * ???page
     * @param ???1
     * @return ??
     */
    public List<DynamicDataSource> initData(int row) {
        List<DynamicDataSource> dynamicDataSourceList = new ArrayList<DynamicDataSource>();
        Iterator<String> pageIterator = pageMap.keySet().iterator();
        while (pageIterator.hasNext()) {
            String pageKey = pageIterator.next();
            if (containExcludePage(pageKey)) {
                logger.warn(
                        String.format("Page [%s] has been exclude, " + "ignore for init data [%s]!", pageKey, row));
                continue;
            }

            Page page = pageMap.get(pageKey);

            DynamicDataSource dynamicDataSource = initPageData(page, row);
            if (dynamicDataSource != null) {
                dynamicDataSourceList.add(dynamicDataSource);
            }
        }

        return dynamicDataSourceList;
    }

    /**
     * ???Page
     * @param page
     * @param row ???1
     * @return
     */
    public DynamicDataSource initPageData(Page page, int row) {
        String dataSourceStr = page.getDataSource();
        if (StringUtils.isBlank(dataSourceStr)) {
            return null;
        }

        final DataSourceInfo dataSourceInfo = dataSourceMap.get(dataSourceStr);
        if (dataSourceInfo == null) {
            return null;
        }

        getDynamicDataSources();
        DataSource dataSource = (DataSource) dynamicDataSourceMap.get(dataSourceInfo.getType());//context.getBean(dataSourceInfo.getType(), DataSource.class);
        DataResource clzResource = new ClasspathResource(SettingUtil.class, dataSourceInfo.getResource());
        try {
            if (clzResource.getUrl() == null) {
                File file = new File(configFile.getParentFile(), dataSourceInfo.getResource());
                if (!file.isFile()) {
                    throw new RuntimeException("Can not found datasource file : " + file.getAbsolutePath());
                }

                clzResource = new FileResource(file);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        dataSource.loadData(clzResource, row, page);

        return dataSource;
    }

    public Collection<DynamicDataSource> getDynamicDataSources() {
        if (dynamicDataSourceMap == null) {
            dynamicDataSourceMap = context.getBeansOfType(DynamicDataSource.class);
        }

        if (dynamicDataSourceMap != null) {
            return dynamicDataSourceMap.values();
        } else {
            return null;
        }
    }

    /**
     * Page??
     * @param pageCls
     */
    public void addExcludePage(String pageCls) {
        excludePageSet.add(pageCls);
    }

    /**
     * ?Page?
     * @param pageCls
     */
    public void removeExcludePage(String pageCls) {
        excludePageSet.remove(pageCls);
    }

    /**
     * ???Page?
     * @param pageCls
     * @return
     */
    public boolean containExcludePage(String pageCls) {
        return excludePageSet.contains(pageCls);
    }

    /**
     * ?Page?
     */
    public void clearExcludePage() {
        excludePageSet.clear();
    }

    /**
     * @return 
     */
    public SeleniumEngine getEngine() {
        return context.getBean(SeleniumEngine.class);
    }

    /**
     * ??
     * @param document
     * @throws DocumentException 
     * @throws IOException 
     * @throws SAXException ?? 
     */
    private void parse(Document doc) throws IOException, DocumentException, SAXException {
        SimpleNamespaceContext simpleNamespaceContext = new SimpleNamespaceContext();
        simpleNamespaceContext.addNamespace("ns", "http://surenpi.com");

        SeleniumEngine seleniumEngine = getEngine();
        if (StringUtils.isBlank(seleniumEngine.getDriverStr())) {
            XPath xpath = new DefaultXPath("/ns:autotest/ns:engine");
            xpath.setNamespaceContext(simpleNamespaceContext);
            // engine parse progress
            Element engineEle = (Element) xpath.selectSingleNode(doc);
            if (engineEle == null) {
                throw new RuntimeException("can not found engine config.");
            }

            String driverStr = engineEle.attributeValue("driver", "chrome");
            String remoteStr = engineEle.attributeValue("remote");
            String timeOutStr = engineEle.attributeValue("timeout");
            String fullScreenStr = engineEle.attributeValue("fullScreen", "false");
            String maximizeStr = engineEle.attributeValue("maximize", "true");
            String widthStr = engineEle.attributeValue("width");
            String heightStr = engineEle.attributeValue("height");
            try {
                seleniumEngine.setDriverStr(driverStr);
                seleniumEngine.setRemoteStr(remoteStr);

                try {
                    seleniumEngine.setTimeout(Long.parseLong(timeOutStr));
                } catch (NumberFormatException e) {
                    logger.warn(String.format("Invalid number string [%s].", timeOutStr));
                    seleniumEngine.setTimeout(5);
                }

                try {
                    seleniumEngine.setWidth(Integer.parseInt(widthStr));
                    seleniumEngine.setHeight(Integer.parseInt(heightStr));
                } catch (NumberFormatException e) {
                    logger.warn(String.format("Invalid number width [%s] or height [%s].", widthStr, heightStr));
                }

                seleniumEngine.setFullScreen(Boolean.parseBoolean(fullScreenStr));
                seleniumEngine.setMaximize(Boolean.parseBoolean(maximizeStr));

                seleniumEngine.init();
            } catch (NoSuchBeanDefinitionException e) {
                logger.error("Can not found bean SeleniumEngine.", e);
            }
        }

        XPath xpath = new DefaultXPath("/ns:autotest/ns:includePage");
        xpath.setNamespaceContext(simpleNamespaceContext);
        @SuppressWarnings("unchecked")
        List<Element> includePageList = xpath.selectNodes(doc);
        if (includePageList != null && includePageList.size() > 0) {
            for (Element includePage : includePageList) {
                String pageConfig = includePage.attributeValue("pageConfig");

                readFromClassPath(pageConfig);
            }
        }

        xpath = new DefaultXPath("/ns:autotest/ns:pages");
        xpath.setNamespaceContext(simpleNamespaceContext);
        Element pagesEle = (Element) xpath.selectSingleNode(doc);
        String pagePackage = pagesEle.attributeValue("pagePackage", "");
        if (StringUtils.isNotBlank(pagePackage)) {
            pagePackage = (pagePackage.trim() + ".");
        }

        // pages parse progress
        xpath = new DefaultXPath("/ns:autotest/ns:pages/ns:page");
        xpath.setNamespaceContext(simpleNamespaceContext);
        @SuppressWarnings("unchecked")
        List<Element> pageNodes = xpath.selectNodes(doc);
        if (pageNodes != null) {
            for (Element ele : pageNodes) {
                String pageClsStr = ele.attributeValue("class");
                if (pageClsStr == null) {
                    logger.warn("can not found class attribute.");
                    continue;
                }

                pageClsStr = (pagePackage + pageClsStr);
                String dataSrcClsStr = ele.attributeValue("dataSource");

                try {
                    parse(pageClsStr, dataSrcClsStr, ele);
                } catch (NoSuchBeanDefinitionException e) {
                    logger.error("Page element [{}] parse error, in document [{}].", pageClsStr, doc);
                    throw e;
                } catch (Exception e) {
                    logger.error("Page element parse error.", e);
                }
            }
        }

        //parse datasources
        xpath = new DefaultXPath("/ns:autotest/ns:dataSources/ns:dataSource");
        xpath.setNamespaceContext(simpleNamespaceContext);
        @SuppressWarnings("unchecked")
        List<Element> dataSourceNodes = xpath.selectNodes(doc);
        if (dataSourceNodes != null) {
            for (Element ele : dataSourceNodes) {
                String name = ele.attributeValue("name");
                String type = ele.attributeValue("type");
                String resource = ele.attributeValue("resource");

                dataSourceMap.put(name, new DataSourceInfo(type, resource));
            }
        }
    }

    /**
     * ??Page
     * 
     * @param pageClsStr
     * @param dataSrcClsStr
     * @param ele
     */
    private void parse(final String pageClsStr, String dataSrcClsStr, Element ele) throws Exception {
        final Object pageInstance = getBean(pageClsStr);
        final Class<?> pageCls = pageInstance.getClass();

        String url = ele.attributeValue("url");
        if (url != null) {
            BeanUtil.set(pageInstance, "url", url);
        }
        String paramPrefix = ele.attributeValue("paramPrefix", "param");
        BeanUtil.set(pageInstance, "paramPrefix", paramPrefix);

        BeanUtil.set(pageInstance, "dataSource", dataSrcClsStr);

        ele.accept(new VisitorSupport() {

            @Override
            public void visit(Element node) {
                if (!"field".equals(node.getName())) {
                    return;
                }

                String fieldName = node.attributeValue("name");
                String byId = node.attributeValue("byId");
                String byCss = node.attributeValue("byCss");
                String byName = node.attributeValue("byName");
                String byXpath = node.attributeValue("byXpath");
                String byLinkText = node.attributeValue("byLinkText");
                String byPartialLinkText = node.attributeValue("byPartialLinkText");
                String byTagName = node.attributeValue("byTagName");
                String data = node.attributeValue("data");
                String type = node.attributeValue("type");
                String strategy = node.attributeValue("strategy");
                String paramPrefix = node.attributeValue("paramPrefix", "param");
                String timeOut = node.attributeValue("timeout", "0");
                if (fieldName == null || "".equals(fieldName)) {
                    return;
                }

                AbstractElement ele = null;
                try {
                    Method getterMethod = BeanUtils.findMethod(pageCls,
                            "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
                    if (getterMethod != null) {
                        ele = (AbstractElement) getterMethod.invoke(pageInstance);

                        if (ele == null) {
                            logger.error(
                                    String.format("element [%s] is null, maybe you not set autowired.", fieldName));
                            return;
                        }

                        if ("input".equals(type)) {
                            Text text = (Text) ele;
                            text.setValue(data);

                            ele = text;
                        }

                        ele.setId(byId);
                        ele.setName(byName);
                        ele.setTagName(byTagName);
                        ele.setXPath(byXpath);
                        ele.setCSS(byCss);
                        ele.setLinkText(byLinkText);
                        ele.setPartialLinkText(byPartialLinkText);
                        ele.setStrategy(strategy);
                        ele.setParamPrefix(paramPrefix);
                        ele.setTimeOut(Long.parseLong(timeOut));
                    } else {
                        logger.error(String.format("page cls [%s], field [%s]", pageClsStr, fieldName));
                    }
                } catch (IllegalAccessException e) {
                    logger.error(e.getMessage(), e);
                } catch (IllegalArgumentException e) {
                    logger.error(e.getMessage(), e);
                } catch (InvocationTargetException e) {
                    logger.error(e.getMessage(), e);
                } catch (ClassCastException e) {
                    logger.error(String.format("fieldName [%s]", fieldName), e);
                }

                node.accept(new FieldLocatorsVisitor(ele));
            }
        });

        pageMap.put(pageClsStr, (Page) pageInstance);
    }

    /**
     * ??
     * @param pageClsStr
     * @return
     */
    private Object getBean(String pageClsStr) {
        String beanName = convertBeanName(pageClsStr);

        Object obj = null;

        try {
            obj = context.getBean(beanName);
        } catch (NoSuchBeanDefinitionException e) {
            obj = context.getBean(pageClsStr);
        }

        return obj;
    }

    /**
     * ??bean??
     * @param pageClsStr
     * @return
     */
    private String convertBeanName(final String pageClsStr) {
        String result = pageClsStr;
        int index = pageClsStr.lastIndexOf(".");

        if (index < 0) {
            result = pageClsStr;
        } else {
            result = pageClsStr.substring(index + 1);
        }

        if (result.length() > 1 && result.charAt(1) >= 'A' && result.charAt(1) <= 'Z') {
            return result;
        }

        return StringUtils.uncapitalize(result);
    }

    /**
     * ???
     * @author suren
     * @date 2016728 ?8:18:01
     */
    class FieldLocatorsVisitor extends VisitorSupport {

        private AbstractElement absEle;

        public FieldLocatorsVisitor(AbstractElement element) {
            this.absEle = element;
        }

        @Override
        public void visit(Element node) {
            if (!"locator".equals(node.getName())) {
                return;
            }

            String name = node.attributeValue("name");
            String value = node.attributeValue("value");
            String timeoutStr = node.attributeValue("timeout");
            String extend = node.attributeValue("extend");

            if (StringUtils.isBlank(name) || StringUtils.isBlank(value)) {
                logger.error("locator has empty name or value.");
            }

            long timeout = 0;
            if (StringUtils.isNotBlank(timeoutStr)) {
                try {
                    timeout = Long.parseLong(timeoutStr);
                } catch (NumberFormatException e) {
                }
            }

            Map<String, Locator> beans = context.getBeansOfType(Locator.class);
            Collection<Locator> locatorList = beans.values();
            for (Locator locator : locatorList) {
                if (!name.equals(locator.getType())) {
                    continue;
                }

                if (locator instanceof LocatorAware) {
                    LocatorAware locatorAware = (LocatorAware) locator;
                    locatorAware.setValue(value);
                    locatorAware.setTimeout(timeout);
                    locatorAware.setExtend(extend);

                    absEle.getLocatorList().add(locator);

                    break;
                }
            }
        }
    }

    /**
     * @param name
     * @return ??Page
     */
    public Object getPage(String name) {
        return pageMap.get(name);
    }

    /**
     * @param type
     * @return Page
     */
    @SuppressWarnings("unchecked")
    @Deprecated
    public <T> T getPage(T type) {
        return (T) getPage(type.getClass().getName());
    }

    /**
     * @param type
     * @return Page
     */
    @SuppressWarnings("unchecked")
    public <T> T getPage(Class<T> type) {
        return (T) getPage(type.getName());
    }

    class DataSourceInfo {
        private String type;
        private String resource;

        public DataSourceInfo(String type, String resource) {
            this.type = type;
            this.resource = resource;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getResource() {
            return resource;
        }

        public void setResource(String resource) {
            this.resource = resource;
        }
    }

    /**
     * 
     */
    @Override
    public void close() throws IOException {
        if (closed) {
            return;
        }

        SeleniumEngine engine = context.getBean(SeleniumEngine.class);
        if (engine != null) {
            engine.close();
            ((AbstractApplicationContext) context).destroy();
            ((AbstractApplicationContext) context).close();
            closed = true;

            Runtime.getRuntime().removeShutdownHook(shutdownHook);
        } else {
            logger.error("Can not fond seleniumEngine, resource close failed.");
        }
    }

    /**
     * @return ??
     */
    public boolean isClosed() {
        return closed;
    }
}