Recently worked on a GWT app. This app has a components laid out in a hierarchy.
A Primary Page has a set of Tabs. Each Tab has a primary Section listing primary
objects and a secondary section listing contents for the selected primary object.
Also each tab has a command bar to which commands can be contributed. Since this is a GWT app, every section here is a GWT Presenter widget.
The requirement here was to be able to contribute commands in one or more sections mentioned above using wildcards in a GIN module. And in the code for the given section, we should be able to retrieve commands contributed for that section.
Here was my solution to this problem :
Every Presenter is assigned a unique ID (let say PresenterContext) based on where its contributed. E.g.
"Inbox:_:SignOff:_:SecondaryWorkArea" signifies a presenter in Inbox (Primary Page) > SignOff (Tab) > SecondaryWorkArea.
Commands are contributed in GIN module using such presenter context IDs. And same command can be contributed to multiple Presenter Contexts. Here are different examples of Contributions for a command :
The requirement here was to be able to contribute commands in one or more sections mentioned above using wildcards in a GIN module. And in the code for the given section, we should be able to retrieve commands contributed for that section.
Here was my solution to this problem :
Every Presenter is assigned a unique ID (let say PresenterContext) based on where its contributed. E.g.
"Inbox:_:SignOff:_:SecondaryWorkArea" signifies a presenter in Inbox (Primary Page) > SignOff (Tab) > SecondaryWorkArea.
Commands are contributed in GIN module using such presenter context IDs. And same command can be contributed to multiple Presenter Contexts. Here are different examples of Contributions for a command :
private String m_contributions[] = new String[] { "", "Inbox", "Inbox:_:PrimaryWorkArea", "Inbox:_:SecondaryWorkArea", "Inbox:_:SecondaryWorkArea:_:SignOff", "Inbox:_:SignOff:_:PrimaryWorkArea", "Inbox:_:SignOff:_:SecondaryWorkArea", "Inbox:_:SignOff", "Inbox:_:MyTasks", "Inbox:_:MyTasks:_:SignOff", "Inbox:_:MyTasks:_:SecondaryWorkArea", "Inbox:_:MyTasks:_:SecondaryWorkArea:_:SignOff", "PrimaryWorkArea", "SecondaryWorkArea", "SecondaryWorkArea:_:SignOff", "SignOff", "ShowObject:_:SecondaryWorkArea:_:Attachments" };
And here is a test method with desired output :
@Test public void testGetClosestMatchingContext() { String input = "Inbox:_:AllTasks:_:SecondaryWorkArea:_:Attachments"; String matchingContribution = .getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "Inbox:_:SecondaryWorkArea", matchingContribution ); input = "Inbox:_:AllTasks:_:SignOff"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "Inbox:_:SignOff", matchingContribution ); input = "MyTasks:_:SecondaryWorkArea:_:SignOff"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "SecondaryWorkArea:_:SignOff", matchingContribution ); input = "AllTasks:_:SecondaryWorkArea:_:SignOff"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "SecondaryWorkArea:_:SignOff", matchingContribution ); input = "Inbox:_:AllTasks:_:SecondaryWorkArea:_:SignOff"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "Inbox:_:SecondaryWorkArea:_:SignOff", matchingContribution ); input = "ShowObject:_:Attachements"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertNull( matchingContribution ); input = "ShowObject:_:PrimaryWorkArea:_:Attachements"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "PrimaryWorkArea", matchingContribution ); input = "ShowObject:_:SignOff"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "SignOff", matchingContribution ); input = "ShowObject:_:SecondaryWorkArea:_:SignOff"; matchingContribution = getClosestMatchingContext( input, m_contributions ); Assert.assertEquals( "SecondaryWorkArea:_:SignOff", matchingContribution ); }
Here is the Algo to get closest matching context for an input presenter context:
public String getClosestMatchingContext( String targetContext, String[] contributedContextIDs ) { String tokens[] = split( targetContext ); String[] lastMatch = contributedContextIDs; String result = null; int index = 0; for( String token : tokens ) { String[] currentMatch = startingWithToken( token, lastMatch, index ); if( currentMatch != null && currentMatch.length > 0 ) { String match = endingWithToken( token, currentMatch ); if( match != null ) { result = match; } if( result != null ) { lastMatch = currentMatch; index++; } } } return result; } /** * Splits the context id into separate tokens * * @param contextID presenter context ID * @return array of tokens */ private String[] split( String contextID ) { String[] tokens = contextID.split( IPresenterContext.ID_SEPARATOR ); if( tokens == null ) { tokens = new String[0]; } return tokens; } /** * Finds the contributions that end with given token * * @param token context token * @param contributions contributed context IDs * @return closest matching context contribution for the specified token, else null is returned. */ private String endingWithToken( String token, String[] contributions ) { assert token != null; assert contributions != null; String tokenWithSperator = IPresenterContext.ID_SEPARATOR + token; for( String contribution : contributions ) { if( contribution.equals( token ) || contribution.endsWith( tokenWithSperator ) ) { return contribution; } } return null; } /** * Finds the contributions that start with specified token. * * @param iToken input token * @param contributions context contributions * @param index index in the specified contributions array to search for in the contributions array * @return contributions starting with specified token, else an empty Array is returned. */ private String[] startingWithToken( String iToken, String[] contributions, int index ) { assert iToken != null; assert contributions != null; assert index >= 0; List<String> matches = new ArrayList<>(); for( String contribution : contributions ) { String[] tokens = split( contribution ); if( tokens.length > index && tokens[index].equals( iToken ) ) { matches.add( contribution ); } } return matches.toArray( new String[0] ); }