Wednesday, August 19, 2015

JSF Style Verifier

In a JSF project we had a very long list of principles for UI components.

Example : p:panel inside p:fieldset must have style ed_borderless

I was told to check screens for these things. Unfortunately I am not good at
design things. Most people were able to say what is wrong in a panel at 1st glance.
But I was not.

I taught i can write a verifier for style and process all of pages at once.

One more thing about project was ,it's GUI was so heavy so there was deep
path for components.

p:panelGrid : ->p:column : ->p:row : ->p:panelGrid :

I put a search depth parameter to check for under each component.


Program will geneate an output like below :


p:panel inside h:form must have reset_uipanel : missing style (reset_uipanel) having ed_borderless
>>> h:form : mytForm->p:dialog : personDialog->h:form : form->ui:define : ->ui:composition : ->h:body : ->f:view : ->html : ->

It tells which style is missing and missing path.


import java.io.File ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.HashSet ;

import javax.xml.parsers.DocumentBuilder ;
import javax.xml.parsers.DocumentBuilderFactory ;

import org.w3c.dom.Document ;
import org.w3c.dom.Element ;
import org.w3c.dom.NamedNodeMap ;
import org.w3c.dom.Node ;
import org.w3c.dom.NodeList ;



public class StyleVerifier
{

    public static String NODE_Panel = "p:panel" ;

    public static String NODE_Panelgrid = "p:panelgrid" ;

    protected StringBuffer logs = new StringBuffer( ) ;

    public int globalCheckDepth = -1 ;

    public StringBuffer getLogs( )
    {
        return this.logs ;
    }

    public void setLogs( StringBuffer logs )
    {
        this.logs = logs ;
    }

    public void getChildsOfType( Node node, String type, ArrayList res )
    {

        if( res == null )
        {
            res = new ArrayList( ) ;
        }

        NodeList nodeList = node.getChildNodes( ) ;

        for( int i = 0; i < nodeList.getLength( ); i++ )
        {

            Node n = nodeList.item( i ) ;

            System.err.println( " verifying " + n.getNodeName( ) ) ;

            if( n.getNodeName( ).equals( type ) )
            {

                Node actualNode = n.getFirstChild( ) ;

                if( actualNode != null )
                {
                    res.add( actualNode ) ;
                }
            }

            getChildsOfType( n, type, res ) ;
        }

    }

    public String getParentPath( Element element )
    {

        if( !( element.getParentNode( ) instanceof Element ) )
            return "" ;

        Element par = ( Element )element.getParentNode( ) ;

        if( par == null )
            return "" ;

        String nodDisp = par.getNodeName( ) + " : " + par.getAttribute( "id" ) ;

        return nodDisp + "->" + getParentPath( par ) ;
    }

    //breakingParent  is for items like panel.
    //If panel is inside h:form before fieldset we can not say it is under fieldset.
    public Element hasParentOfType( Element element, String parentType, String breakingParent, int checkDepth )
    {
        if( checkDepth == 0 )
            return null ;

        if( !( element.getParentNode( ) instanceof Element ) )
            return null ;

        Element par = ( Element )element.getParentNode( ) ;

        if( par == null )
            return null ;

        String nodnam = par.getNodeName( ) ;

        if( breakingParent != null && breakingParent.equals( nodnam ) )
        {
            return null ;
        }

        if( parentType.equals( nodnam ) )
        {
            return par ;
        }

        checkDepth-- ;
        return hasParentOfType( par, parentType, breakingParent, checkDepth ) ;
    }

    public boolean isPanel( Element element )
    {
        String nodnam = element.getNodeName( ) ;

        System.out.println( nodnam + "=" + element.getAttribute( "styleClass" ) ) ;

        if( NODE_Panel.equalsIgnoreCase( nodnam ) )
        {
            return true ;
        }
        return false ;
    }

    public boolean isType( Element element, String type )
    {
        String nodnam = element.getNodeName( ) ;

        if( type.equalsIgnoreCase( nodnam ) )
        {
            return true ;
        }
        return false ;
    }

    public void validateFile( File fileToVerify ) throws Exception
    {

        if( !fileToVerify.getName( ).endsWith( ".xhtml" ) )
            return ;

        System.err.println( "Parse beginnig" ) ;
        
        //"D:\verify\webapp\"
        

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance( ) ;
        dbf.setNamespaceAware( false ) ;
        dbf.setValidating( false ) ;
        dbf.setFeature( "http://xml.org/sax/features/namespaces", false ) ;
        dbf.setFeature( "http://xml.org/sax/features/validation", false ) ;
        dbf.setFeature( "http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false ) ;
        dbf.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false ) ;

        DocumentBuilder db = dbf.newDocumentBuilder( ) ;
        Document document = db.parse( fileToVerify ) ;

        NodeList alllist = document.getElementsByTagName( "*" ) ;

        System.err.println( "Parse step 2" ) ;

        for( int i = 0; i < alllist.getLength( ); i++ )
        {

            Element element = ( Element )alllist.item( i ) ;

            verifyStyleUnderParent( element, "p:panel", "h:form", "p:fieldset", "reset_uipanel", "p:panel inside h:form must have reset_uipanel", this.globalCheckDepth ) ;

            System.err.println( "Parse step 3" ) ;

            verifyStyleUnderParent( element, "p:panel", "p:fieldset", "h:form", "ed_borderless", "p:panel inside p:fieldset must have ed_borderless", this.globalCheckDepth ) ;

            System.err.println( "Parse step 4" ) ;

            verifyStyleUnderParent( element, "p:panelgrid", "p:panelgrid", null, "ed_gridcellborderless", "p:panelgrid inside p:panelgrid must have ed_gridcellborderless", this.globalCheckDepth ) ;

            System.err.println( "Parse step 5" ) ;

            //
            HashMap styleValues = new HashMap( ) ;
            styleValues.put( "closable", "false" ) ;

            HashSet notNullStyles = new HashSet( ) ;
            notNullStyles.add( "header" ) ;

            verifyStyleMustHave( element, "p:dialog", styleValues, notNullStyles, "Dialog not having proper rules" ) ;
        }

    }




    public String verifyStyleUnderParent( Element element, String mytype, String parenttype, String breakingParent, String mustHaveStyle, String breakMessage, int checkDepth )
    {

        boolean isTargetType = isType( element, mytype ) ;
        if( isTargetType )
        {
            boolean isInside = hasParentOfType( element, parenttype, breakingParent, checkDepth ) != null ;

            if( isInside )
            {

                String styleClass = element.getAttribute( "styleClass" ) ;
                if( styleClass == null || !mustHaveStyle.equals( styleClass ) )
                {

                    String msg = element.getAttribute( "id" ) + " missing style (" + mustHaveStyle + ") having " + styleClass + "\n" ;
                    msg += ">>> " + getParentPath( element ) + "\n\n" ;

                    this.logs.append( breakMessage + " : " + msg ) ;
                    this.logs.append( getItemXML( element ) ) ;
                    
                    return msg ;
                }
            }
        }

        return null ;
    }

    
    public String getItemXML( Element element )
    {
        NamedNodeMap nameNodeMap = element.getAttributes( ) ;

        String s = "<" + element.getNodeName( ) + " " ;
        for( int i = 0; i < nameNodeMap.getLength( ); ++i )
        {
            Node attr = nameNodeMap.item( i ) ;
            s += " " + attr.getNodeName( ) + "=\"" + attr.getNodeValue( ) + "\"" ;
        }
        return s + " >\n\n" ;

    }

    //Checks whether element have stated styles with stated values
    public String verifyStyleMustHave( Element element, String mytype, HashMap styleValues, HashSet notNullStyles, String breakMessage ) throws Exception
    {

        String missingStyles = "" ;
        boolean isTargetType = isType( element, mytype ) ;
        if( isTargetType )
        {
            for( String key : styleValues.keySet( ) )
            {
                String styleClass = element.getAttribute( key ) ;
                String mustHaveStyle = styleValues.get( key ) ;
                if( styleClass == null || !mustHaveStyle.equals( styleClass ) )
                {

                    String msg = element.getAttribute( "id" ) + " , " + key + " must style (" + mustHaveStyle + ") having " + styleClass + "\n" ;
                    msg += ">>> " + getParentPath( element ) + "\n\n" ;

                    missingStyles += msg ;
                }
            }

            for( String key : notNullStyles )
            {
                String styleClass = element.getAttribute( key ) ;
                if( styleClass == null )
                {

                    String msg = "id= " + element.getAttribute( "id" ) + " , " + key + " missing style   \n" ;
                    msg += ">>> " + getParentPath( element ) + "\n\n" ;

                    missingStyles += msg ;
                }
            }
        }

        if( missingStyles != null && missingStyles.trim( ).length( ) > 0 )
        {
            this.logs.append( getItemXML( element ) ) ;
            this.logs.append( breakMessage + " : " + missingStyles ) ;

        }

        return null ;
    }

    //h:form içerisindeki p:panel reset_uipanel
    //fieldset içerisindeki p:panel        ed_borderless
    //p:panelgrid içerisindeki p:panelgrid        ed_gridcellborderless

    public void verifyFileOrDirectory( File fileOrDir ) throws Exception
    {

        if( fileOrDir.isDirectory( ) )
        {
            File[ ] subitems = fileOrDir.listFiles( ) ;

            for( File subitem : subitems )
            {

                this.verifyFileOrDirectory( subitem ) ;
            }

        }
        else
        {
            this.logs.append( fileOrDir.getName( ) + "\n\n" ) ;
            
            String absolutePath = fileOrDir.getAbsolutePath( );
            String plink = "\nlocalhost:7001/aydes" +absolutePath.substring( absolutePath.indexOf( "webapp" ) +"webapp".length( ) );
            plink = plink.replaceAll( "xhtml", "jsf" ) + "\n";
            
            this.logs.append( plink + "\n\n" ) ;
            
            System.err.println( fileOrDir.getAbsolutePath( ) ) ;

            if( !fileOrDir.getName( ).endsWith( ".xhtml" ) )
                return ;

            //validateFile( FileUtils.fileToString( fileOrDir.getAbsolutePath( ), "utf-8" ) );

            validateFile( fileOrDir ) ;

            
        }

    }

    public int getGlobalCheckDepth( )
    {
        return this.globalCheckDepth ;
    }

    public void setGlobalCheckDepth( int globalCheckDepth )
    {
        this.globalCheckDepth = globalCheckDepth ;
    }

    public static void runForDepth( int depth, String path )
    {
        StyleVerifier uiVerifier_ByXml = new StyleVerifier( ) ;
        try
        {
            uiVerifier_ByXml.setGlobalCheckDepth( depth ) ;
            uiVerifier_ByXml.verifyFileOrDirectory( new File( path ) ) ;
            
            FileUtils.stringToFile( "D:\\verify_log_" + uiVerifier_ByXml.globalCheckDepth + ".txt", uiVerifier_ByXml.logs.toString( ), "utf-8", true ) ;
            uiVerifier_ByXml.logs.setLength( 0 ) ;

        }
        catch( Exception e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace( ) ;
        }
    }

    public static void main( String[ ] args )
    {

        String sample = "D:\\verify" ;

        StyleVerifier uiVerifier_ByXml = new StyleVerifier( ) ;
        try
        {
            runForDepth( -1, sample ) ;
            runForDepth( 1, sample ) ;
            runForDepth( 2, sample ) ;
            runForDepth( 3, sample ) ;
            runForDepth( 4, sample ) ;
        }
        catch( Exception e )
        {
            e.printStackTrace( ) ;
        }

        System.err.println( uiVerifier_ByXml.logs.toString( ) ) ;

    }

}


No comments:

Post a Comment