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