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( ) ) ;
}
}