package org.gluu.jsf2.customization;

import com.sun.faces.config.DbfFactory;
import com.sun.faces.util.FacesLogger;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.LSResourceResolver;

import javax.faces.application.ApplicationConfigurationPopulator;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.logging.Level;

/**
 * Created by eugeniuparvan on 5/1/17.
 */
public class FacesConfigPopulator extends ApplicationConfigurationPopulator {
    /**
     * <p>/faces-config/navigation-rule</p>
     */
    private static final String NAVIGATION_RULE = "navigation-rule";
    private static final String FACES_2_2_XSD = "/com/sun/faces/web-facesconfig_2_2.xsd";
    private static final String FACES_CONFIG_PATTERN = ".*\\.navigation\\.xml$";
    private static final String DEFAULT_NAVIGATION_PATH = "META-INF/navigation";

    @Override
    public void populateApplicationConfiguration(Document toPopulate) {

        if (!Utils.isCustomPagesDirExists())
            return;
        try {
            findAndUpdateNavigationRules(toPopulate, Utils.getCustomPagesPath());
        } catch (Exception e) {
            FacesLogger.CONFIG.getLogger().log(Level.SEVERE, "Can't add customized navigation rules");
        }

        try {
            Enumeration<URL> urlEnumeration = getClass().getClassLoader().getResources(DEFAULT_NAVIGATION_PATH);
            if (urlEnumeration.hasMoreElements()) {
                URL url = urlEnumeration.nextElement();
                findAndUpdateNavigationRules(toPopulate, url.getPath());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Recursively finds all *.navigation.xml files located in custom pages directory, and adds navigation rules to
     * navigation handler
     *
     * @param path to custom pages directory
     * @throws Exception
     */
    private void findAndUpdateNavigationRules(Document toPopulate, String path) throws Exception {
        File file = new File(path);
        RegexFileFilter regexFileFilter = new RegexFileFilter(FACES_CONFIG_PATTERN);
        Collection<File> facesConfigFiles = FileUtils.listFiles(file, regexFileFilter, DirectoryFileFilter.DIRECTORY);

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();

        for (File files : facesConfigFiles) {
            String faceConfig = files.getAbsolutePath();
            updateDocument(toPopulate, builder, faceConfig);
        }
    }

    /**
     * Validates *.faces-config.xml file and creates DocumentInfo class
     *
     * @param docBuilder
     * @param faceConfig
     * @return
     */
    private void updateDocument(Document toPopulate, DocumentBuilder docBuilder, String faceConfig) {
        try {
            InputStream xml = new FileInputStream(faceConfig);
            if (!isValidFacesConfig(xml))
                return;
            Document document = docBuilder.parse(new File(faceConfig));
            Element root = toPopulate.getDocumentElement();
            NodeList navigationRules = getNavigationRules(document);
            for (int i = 0; i < navigationRules.getLength(); ++i) {
                Node importedNode = toPopulate.importNode(navigationRules.item(i), true);
                root.appendChild(importedNode);
            }
        } catch (Exception e) {
        }
    }

    /**
     * Validates *.faces-config.xml file
     *
     * @param xml
     * @return
     */
    private boolean isValidFacesConfig(InputStream xml) {
        try {
            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            factory.setResourceResolver((LSResourceResolver) DbfFactory.FACES_ENTITY_RESOLVER);

            InputStream xsd = this.getClass().getResourceAsStream(FACES_2_2_XSD);
            Schema schema = factory.newSchema(new StreamSource(xsd));

            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(xml));
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    private NodeList getNavigationRules(Document document) {
        String namespace = document.getDocumentElement()
                .getNamespaceURI();
        return document.getDocumentElement().getElementsByTagNameNS(namespace, NAVIGATION_RULE);
    }
}
@@ -260,32 +260,89 @@
 egexFileFilter;%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A
 import org.w3c.d
@@ -350,24 +350,24 @@
 m.Document;%0A
-
 import org.w
@@ -1534,16 +1534,95 @@
 tion%22;%0A%0A
+    private Logger log = LoggerFactory.getLogger(FacesConfigPopulator.class);%0A%0A
     @Ove
@@ -1699,17 +1699,16 @@
 late) %7B%0A
-%0A
         
@@ -1880,32 +1880,33 @@
 tch (Exception e
+x
 ) %7B%0A            
@@ -2349,32 +2349,33 @@
 tch (Exception e
+x
 ) %7B%0A            
@@ -2374,30 +2374,68 @@
     
-    e.printStackTrace(
+%09log.error(%22Failed to populate application configuraton%22, ex
 );%0A 
@@ -3722,32 +3722,34 @@
 am(faceConfig);%0A
+//
             if (
@@ -3740,24 +3740,45 @@
             
+try %7B%0A//            %09
 if (!isValid
@@ -3794,21 +3794,21 @@
 ig(xml))
-%0A    
+ %7B%0A//
         
@@ -3807,32 +3807,34 @@
             
+%09%09
 return;%0A
             
@@ -3813,32 +3813,119 @@
       %09%09return;%0A
+//            %09%7D%0A//            %7D finally %7B%0A//            %09xml.close();%0A//            %7D%0A
             Docu
@@ -4357,20 +4357,82 @@
 eption e
+x
 ) %7B%0A
+        %09log.error(%22Failed to update navigation rules%22, ex);%0A
         

Add more loging. Disable navigation.xml files validation