How to register and use a characteristic value provider with parameters
Introduction
Use the SDK to create new plugin, contribute value provider implementation and add value provider to a characteristic.
Create Plugin using SDK
Create new plug-in project similar to "com.heiler.ppm.customizing.sample.valueProvider" and add required dependencies.
Sample plugin is present under sdk→examples→customizing.
Add Extension in MANIFEST.MF
Open Extensions
add extension for "com.heiler.ppm.charateristic.core.characteristicsValueProvider"
Add valueProvider
Identifier : intgerValueProvider
Label : %valueProvider.text (Localized text)
dataType : INTEGER
providerFactory : SampleIntegerCharacteristicValueProviderFactory
Contribute the characteristic value provider
Create class with name: "SampleIntegerCharacteristicValueProviderFactory" in package: "com.heiler.ppm.customizing.sample.valueProvider.integer", implements interface: "CharacteristicValueProviderFactory".
CharacteristicValueProviderFactory: Creates new instance of CharacteristicValueProvider.
import
com.heiler.ppm.characteristic.core.valueProvider.CharacteristicValueProvider;
import
com.heiler.ppm.characteristic.core.valueProvider.CharacteristicValueProviderFactory;
import
com.heiler.ppm.std.core.entity.list.EntityItemList;
public
class
SampleIntegerCharacteristicValueProviderFactory
implements
CharacteristicValueProviderFactory
{
@Override
public
CharacteristicValueProvider createValueProvider( EntityItemList itemList )
{
return
new
SampleIntegerCharacteristicValueProvider( itemList );
}
}
Create class with name "SampleIntegerCharacteristicValueProvider" in package "com.heiler.ppm.customizing.sample.valueProvider.integer", implements interface: "CharacteristicValueProvider".
CharacteriticValueProvider: Provides characteristic values and check for a valid value.
Provide the implementation of interface Value inside the SampleIntegerCharacteristicValueProvider itself.
import
java.util.ArrayList;
import
java.util.Collection;
import
java.util.HashSet;
import
java.util.List;
import
java.util.Locale;
import
java.util.Set;
import
com.heiler.ppm.characteristic.core.record.CharacteristicRecord;
import
com.heiler.ppm.characteristic.core.valueProvider.CharacteristicValueProvider;
import
com.heiler.ppm.lookup.core.LookupValue;
import
com.heiler.ppm.std.core.entity.list.EntityItemList;
@SuppressWarnings
(
"unused"
)
public
class
SampleIntegerCharacteristicValueProvider
implements
CharacteristicValueProvider
{
public
SampleIntegerCharacteristicValueProvider( EntityItemList itemList )
{
//
}
@Override
public
Collection< Value > getValues( LookupValue language, CharacteristicRecord charRecord )
{
List< Value > values = createValues();
return
values;
}
@Override
public
boolean
containsValue( LookupValue language, CharacteristicRecord charRecord,
Object value
/*actual charateristic record value*/
)
{
// make sure values are of datatype Long for Integer type characteristics
Set< Long > values =
new
HashSet();
values.add( 1024L );
values.add( 2048L );
values.add( 4096L );
return
values.contains( value );
}
@SuppressWarnings
(
"nls"
)
private
List< Value > createValues()
{
List< Value > values =
new
ArrayList();
// make sure values are of datatype Long for Integer type characteristics
Value v1 =
new
ValueImpl( 1024L,
"1 MB"
);
Value v2 =
new
ValueImpl( 2048L,
"2 MB"
);
Value v3 =
new
ValueImpl( 4096L,
"4 MB"
);
values.add( v1 );
values.add( v2 );
values.add( v3 );
return
values;
}
public
static
class
ValueImpl
implements
Value
{
private
String label;
private
Object value;
public
ValueImpl( Object value, String label )
{
this
.value = value;
this
.label = label;
}
@Override
public
Object getValue()
{
return
this
.value;
}
@Override
public
String getLabel( Locale locale )
{
return
this
.label;
}
}
}
Deploy the plugin and restart Product 360 server
export the plugin as deployable plug-ins and fragments.
Deploy exported jar inside server → plugins folder
We are good to start the server
Attaching value provider to a characteristic
Characteristic value provider can be attached In characteristic modeling detail view.
Characteristic UI showing the provided values
Provided values will be available to select in the dropdown.
DepedentLookup Characteristic
Introduction
Create lookups lookup values
Country
State
Setup of Lookup Value Reference
referencing lookup |
referenced lookup |
business case |
Country |
State |
A country can have multiple states |
Navigate to lookup context view
Add the referenced values for desired lookup value.
There are two ways you can add referenced values for a lookup value:
Include values table : Only selected values can be referenced.
Exclude values table : All the values can be referenced except selected values.
Refer Importing lookups and lookup value references documentation for importing lookup references.
Contribute the country to state dependent characteristics to value provider
class name: "ParentReferencingChildLookupValueProviderFactory" package: "com.heiler.ppm.customizing.sample.valueProvider.parentchild" interface: "CharacteristicValueProviderFactory".
package
com.heiler.ppm.customizing.sample.valueProvider.parentchild;
import
com.heiler.ppm.characteristic.core.valueProvider.CharacteristicValueProvider;
import
com.heiler.ppm.characteristic.core.valueProvider.CharacteristicValueProviderFactory;
import
com.heiler.ppm.std.core.entity.list.EntityItemList;
public
class
ParentReferencingChildLookupValueProviderFactory
implements
CharacteristicValueProviderFactory
{
@Override
public
CharacteristicValueProvider createValueProvider( EntityItemList itemList )
{
return
new
ParentReferencingChildLookupValueProvider( itemList );
}
}
class name: "ParentReferencingChildLookupValueProvider" package: "com.heiler.ppm.customizing.sample.valueProvider.parentchild" interface: "CharacteristicValueProvider".
package
com.heiler.ppm.customizing.sample.valueProvider.parentchild;
import
java.util.Collection;
import
java.util.HashSet;
import
java.util.Locale;
import
java.util.Set;
import
java.util.stream.Collectors;
import
org.apache.commons.logging.Log;
import
org.apache.commons.logging.LogFactory;
import
org.eclipse.core.runtime.CoreException;
import
com.google.gson.JsonElement;
import
com.google.gson.JsonObject;
import
com.google.gson.JsonParser;
import
com.heiler.ppm.characteristic.core.record.CharacteristicRecord;
import
com.heiler.ppm.characteristic.core.valueProvider.CharacteristicValueProvider;
import
com.heiler.ppm.commons.RuntimeCoreException;
import
com.heiler.ppm.lookup.core.Lookup;
import
com.heiler.ppm.lookup.core.LookupValue;
import
com.heiler.ppm.security.core.SecurityComponent;
import
com.heiler.ppm.std.core.entity.list.EntityItemList;
public
class
ParentReferencingChildLookupValueProvider
implements
CharacteristicValueProvider
{
private
Locale locale;
private
static
final
String PARENT_CHARACTERISTIC =
"parentCharacteristic"
;
//$NON-NLS-1$
private
static
final
Log LOG = LogFactory.getLog( ParentReferencingChildLookupValueProvider.
class
);
public
ParentReferencingChildLookupValueProvider(
@SuppressWarnings
(
"unused"
) EntityItemList itemList )
{
this
.locale = SecurityComponent.getImpersonator()
.getLoginToken()
.getLocale();
}
@Override
public
Collection getValues( LookupValue language, CharacteristicRecord characteristicRecord )
{
Set< LookupValue > dependentLookupValues = fetchDependentLookupValues( language, characteristicRecord );
return
dependentLookupValues.stream()
.map( lookupValue ->
new
ValueImpl( lookupValue, lookupValue.getName(
this
.locale ) ) )
.collect( Collectors.toList() );
}
@Override
public
boolean
containsValue( LookupValue language, CharacteristicRecord characteristicRecord, Object value )
{
Set< LookupValue > dependentLookupValues = fetchDependentLookupValues( language, characteristicRecord );
return
dependentLookupValues.contains( value );
}
private
Set< LookupValue > fetchDependentLookupValues( LookupValue language,
CharacteristicRecord characteristicRecord )
{
Lookup lookup = characteristicRecord.getCharacteristic()
.getLookup();
CharacteristicRecord parent = getParentCharacteristicRecord( characteristicRecord );
Set< LookupValue > values =
new
HashSet();
if
( parent !=
null
)
{
parent.getValues( language )
.forEach( lookupValue -> {
addLookupValueReferences( lookup, values, lookupValue );
} );
}
//In case parent is null then by default all the values present in the characteristic lookup should be returned
else
if
( lookup !=
null
)
{
Collection< LookupValue > lookUpValues = lookup.getValues();
values.addAll( lookUpValues );
}
return
values.stream()
.filter( v -> v.isActive() )
.collect( Collectors.toSet() );
}
private
void
addLookupValueReferences( Lookup lookup, Set< LookupValue > values, Object lookupValue )
{
LookupValue parentLookupValue = ( LookupValue ) lookupValue;
try
{
Collection< LookupValue > lookupValueReference = parentLookupValue.getReferences( lookup );
values.addAll( lookupValueReference );
}
catch
( CoreException e )
{
throw
new
RuntimeCoreException( e );
}
}
private
CharacteristicRecord getParentCharacteristicRecord( CharacteristicRecord characteristicRecord )
{
CharacteristicRecord parent;
if
( characteristicRecord.getCharacteristic()
.getValueProviderParameter() !=
null
)
{
parent = getRequiredCharacteristicRecord( characteristicRecord, characteristicRecord.getCharacteristic()
.getValueProviderParameter() );
}
else
{
parent = characteristicRecord.getParent();
}
return
parent;
}
private
CharacteristicRecord getRequiredCharacteristicRecord( CharacteristicRecord characteristicRecord,
String parameter )
{
CharacteristicRecord parent = characteristicRecord.getParent();
JsonObject charParameter = parseStringtoJson( parameter );
String parentRefParam = ( charParameter !=
null
&& charParameter.get( PARENT_CHARACTERISTIC ) !=
null
) ? charParameter.get( PARENT_CHARACTERISTIC )
.getAsString()
:
null
;
return
getParent( parent, parentRefParam );
}
private
CharacteristicRecord getParent( CharacteristicRecord parent, String parentRefParam )
{
if
( parent ==
null
)
{
return
parent;
}
if
( parentRefParam !=
null
&& parent.getCharacteristic()
.getIdentifier()
.equals( parentRefParam ) )
{
return
parent;
}
return
getParent( parent.getParent(), parentRefParam );
}
private
JsonObject parseStringtoJson( String input )
{
JsonObject jsonObject =
null
;
JsonParser parser =
new
JsonParser();
try
{
JsonElement element = parser.parse( input );
if
( element.isJsonObject() )
{
jsonObject = element.getAsJsonObject();
}
}
catch
( Exception e )
{
LOG.error( e.getMessage() );
}
return
jsonObject;
}
public
static
class
ValueImpl
implements
Value
{
private
String label;
private
Object value;
public
ValueImpl( Object value, String label )
{
this
.value = value;
this
.label = label;
}
@Override
public
Object getValue()
{
return
this
.value;
}
@Override
public
String getLabel( Locale locale )
{
return
this
.label;
}
}
}
class name: "ParentReferencingChildLookupValueProviderParameter" package: "com.heiler.ppm.customizing.sample.valueProvider.parentchild" interface: "ValueProviderParameter".
package
com.heiler.ppm.customizing.sample.valueProvider.parentchild;
import
java.util.ArrayList;
import
java.util.Collection;
import
java.util.Locale;
import
com.heiler.ppm.characteristic.core.model.Characteristic;
import
com.heiler.ppm.characteristic.core.record.CharacteristicRecord;
import
com.heiler.ppm.characteristic.core.valueProvider.ValueProviderParameter;
import
com.heiler.ppm.lookup.core.LookupValue;
/**
* @author rkumhar
*/
public
class
ParentReferencingChildLookupValueProviderParameter
implements
ValueProviderParameter
{
@Override
public
Collection getParameters( LookupValue language, CharacteristicRecord characteristicRecord )
{
Collection< ParameterValue > paramList =
new
ArrayList< ParameterValue >();
Collection< Characteristic > parentList =
new
ArrayList<>();
Characteristic characteristic = characteristicRecord.getCharacteristic();
checkForParent( characteristic.getParent(), parentList );
parentList.forEach( parentCharacteristic -> paramList.add(
new
ParameterValueImpl( parentCharacteristic.getIdentifier(),
parentCharacteristic.getName( Locale.ENGLISH ) ) ) );
return
paramList;
}
Collection< CharacteristicRecord > checkForParent( CharacteristicRecord characteristicRecord,
Collection< CharacteristicRecord > parentCharRecordSetList )
{
if
( characteristicRecord !=
null
)
{
parentCharRecordSetList.add( characteristicRecord );
if
( characteristicRecord.getParent() !=
null
)
{
checkForParent( characteristicRecord.getParent(), parentCharRecordSetList );
}
}
return
parentCharRecordSetList;
}
Collection< Characteristic > checkForParent( Characteristic parentCharacteristic,
Collection< Characteristic > parentCharList )
{
if
( parentCharacteristic !=
null
)
{
parentCharList.add( parentCharacteristic );
if
( parentCharacteristic.getParent() !=
null
)
{
checkForParent( parentCharacteristic.getParent(), parentCharList );
}
}
return
parentCharList;
}
public
static
class
ParameterValueImpl
implements
ParameterValue
{
private
String label;
private
Object value;
public
ParameterValueImpl( Object value, String label )
{
this
.value = value;
this
.label = label;
}
@Override
public
Object getValue()
{
return
this
.value;
}
@Override
public
String getLabel( Locale locale )
{
return
this
.label;
}
}
}
Characteristic modeling:
Create characteristics like the following:
Characteristic |
Name |
Identifier |
Data type |
Lookup |
Parent characteristic |
Country -> state |
Country_to_State |
Lookup value |
Country |
Child characteristic |
Parent referencing child lookup |
parent_referencing_child_lookup |
Lookup value |
State |
Assigning value provider to characteristics in modelling UI
Value provider dropdown lists all the contributed value providers.
Parameter dropdown list appropriate values for corresponding value provider
Characteristic UI showing the provided values
Characteristic showing filtered values of state lookup.