This documents covers code changes that need to be made by Sapphire adopters as part of migrating
to 0.4 release. Only changes from the previous release are covered.
The "href" attribute of the @Documentation.Topic has been renamed to "url" for consistency with
other API.
The method for attaching custom code to produce documentation content has changed to align with Sapphire services architecture
and for general API consistency.
Some of the hints used to customize behavior in the UI definitions have been turned into explicit
properties.
The @ValidFileExtensions annotation has been replaced with @FileExtensions annotation that supports Sapphire
expression language.
The services API has undergone changes to make it more general and to cleanup various inconsistencies.
Before |
After |
public class CustomService extends ModelElementService
{
@Override
public void init( IModelElement element, String[] params )
{
super.init( element, params );
String p1 = params[ 0 ];
String p2 = params[ 1 ];
...
}
public Object perform()
{
IModelElement element = element();
...
}
}
|
public class CustomService extends Service
{
@Override
protected void init()
{
super.init();
IModelElement element = context( IModelElement.class );
String p1 = params( "p1" );
String p2 = params( "p2" );
...
}
public Object perform()
{
IModelElement element = context( IModelElement.class );
...
}
}
|
public class CustomServiceFactory extends ModelElementServiceFactory
{
@Override
public boolean applicable( IModelElement element,
Class<? extends ModelElementService> service )
{
...
}
@Override
public ModelElementService create( IModelElement element,
Class<? extends ModelElementService> service )
{
...
}
}
|
public class CustomServiceFactory extends ServiceFactory
{
@Override
public boolean applicable( ServiceContext context,
Class<? extends Service> service )
{
IModelElement element = context.find( IModelElement.class );
...
}
@Override
public Service create( ServiceContext context,
Class<? extends Service> service )
{
IModelElement element = context.find( IModelElement.class );
...
}
}
|
<extension>
<model-element-service>
<id>Sample.CustomService</id>
<type>org.eclipse.sapphire.samples.CustomService</type>
<factory>org.eclipse.sapphire.samples.internal.CustomServiceFactory</factory>
</model-element-service>
</extension>
|
<extension>
<service>
<id>Sample.CustomService</id>
<type>org.eclipse.sapphire.samples.CustomService</type>
<factory>org.eclipse.sapphire.samples.internal.CustomServiceFactory</factory>
<context>Sapphire.Element.Instance</context>
</service>
</extension>
|
public class CustomService extends ModelPropertyService
{
@Override
public void init( IModelElement element, ModelProperty property, String[] params )
{
super.init( element, property, params );
String p1 = params[ 0 ];
String p2 = params[ 1 ];
...
}
public Object perform()
{
IModelElement element = element();
ModelProperty property = property();
...
}
}
|
public class CustomService extends Service
{
@Override
protected void init()
{
super.init();
IModelElement element = context( IModelElement.class );
ModelProperty property = context( ModelProperty.class );
String p1 = params( "p1" );
String p2 = params( "p2" );
...
}
public Object perform()
{
IModelElement element = context( IModelElement.class );
ModelProperty property = context( ModelProperty.class );
...
}
}
|
public class CustomServiceFactory extends ModelPropertyServiceFactory
{
@Override
public boolean applicable( IModelElement element,
ModelProperty property,
Class<? extends ModelPropertyService> service )
{
...
}
@Override
public ModelPropertyService create( IModelElement element,
ModelProperty property,
Class<? extends ModelPropertyService> service )
{
...
}
}
|
public class CustomServiceFactory extends ServiceFactory
{
@Override
public boolean applicable( ServiceContext context,
Class<? extends Service> service )
{
IModelElement element = context.find( IModelElement.class );
ModelProperty property = context.find( ModelProperty.class );
...
}
@Override
public Service create( ServiceContext context,
Class<? extends Service> service )
{
IModelElement element = context.find( IModelElement.class );
ModelProperty property = context.find( ModelProperty.class );
...
}
}
|
<extension>
<model-property-service>
<id>Sample.CustomService</id>
<type>org.eclipse.sapphire.samples.CustomService</type>
<factory>org.eclipse.sapphire.samples.internal.CustomServiceFactory</factory>
</model-property-service>
</extension>
|
<extension>
<service>
<id>Sample.CustomService</id>
<type>org.eclipse.sapphire.samples.CustomService</type>
<factory>org.eclipse.sapphire.samples.internal.CustomServiceFactory</factory>
<context>Sapphire.Property.Instance</context>
</service>
</extension>
|
ValueProperty PROP_SAMPLE = new ValueProperty( TYPE, "Sample" );
@Service( impl = CustomService.class, params = { "a", "b" } )
Value<String> getSample();
void setSample( String value );
|
ValueProperty PROP_SAMPLE = new ValueProperty( TYPE, "Sample" );
@Service
(
impl = CustomService.class,
params =
{
@Service.Param( name = "p1", value = "a" ),
@Service.Param( name = "p2", value = "b" )
}
)
Value<String> getSample();
void setSample( String value );
|
<extension>
<value-serialization-service>
<type>org.eclipse.sapphire.samples.Circle</type>
<impl>org.eclipse.sapphire.samples.internal.CircleSerializationService</impl>
</value-serialization-service>
</extension>
|
<extension>
<service>
<id>Sample.ValueSerializationService.Circle</id>
<type>org.eclipse.sapphire.services.ValueSerializationService</type>
<context>Sapphire.Property.Instance</context>
<factory>org.eclipse.sapphire.samples.internal.CircleSerializationServiceFactory</factory>
</service>
</extension>
public class CircleSerializationServiceFactory extends ServiceFactory
{
@Override
public boolean applicable( ServiceContext context,
Class<? extends Service> service )
{
ValueProperty property = context.find( ValueProperty.class );
return ( property != null && property.isOfType( Circle.class ) );
}
@Override
public Service create( ServiceContext context,
Class<? extends Service> service )
{
return new CircleSerializationService();
}
}
|
ValueProperty PROP_SAMPLE = new ValueProperty( TYPE, "Sample" );
@Type( base = Circle.class )
@ValueSerialization( service = CircleSerializationService.class )
Value<Circle> getSample();
void setSample( String value );
void setSample( Circle value );
|
ValueProperty PROP_SAMPLE = new ValueProperty( TYPE, "Sample" );
@Type( base = Circle.class )
@Service( impl = CircleSerializationService.class )
Value<Circle> getSample();
void setSample( String value );
void setSample( Circle value );
|
ValueProperty PROP_SAMPLE = new ValueProperty( TYPE, "Sample" );
@DerivedValue( service = SampleDerivedValueService.class )
Value<String> getSample();
|
ValueProperty PROP_SAMPLE = new ValueProperty( TYPE, "Sample" );
@Derived
@Service( impl = SampleDerivedValueService.class )
Value<String> getSample();
|
public class CustomValidationService extends ModelPropertyValidationService<Value<String>>
{
@Override
public Status validate()
{
final Value<String> value = target();
...
}
}
|
public class CustomValidationService extends ValidationService
{
@Override
public Status validate()
{
final Value<String> value = context( IModelElement.class ).read( context( ValueProperty.class ) );
...
}
}
|
public class CustomDefaultValueService extends DefaultValueService
{
@Override
public String getDefaultValue()
{
String value;
...
return value;
}
...
}
|
public class CustomDefaultValueService extends DefaultValueService
{
@Override
protected DefaultValueServiceData data()
{
refresh();
return super.data();
}
@Override
protected DefaultValueServiceData compute()
{
String value;
...
return new DefaultValueServiceData( value );
}
...
}
The above represents the quickest way to migrate an existing default value service, but is far from
ideal. A better solution would be to not override the data() method with a refresh on every invocation.
To do that, the service would need to listen on changes to data used in the compute() method and call
refresh() method when that data changes.
|
public class CustomDependenciesService extends DependenciesService
{
@Override
protected void compute( Set<ModelPath> dependencies )
{
dependencies.add( ... );
dependencies.add( ... );
...
}
...
}
|
public class CustomDependenciesService extends DependenciesService
{
@Override
protected DependenciesServiceData compute()
{
List<ModelPath> dependencies = new ArrayList<ModelPath>();
dependencies.add( ... );
dependencies.add( ... );
...
return new DependenciesServiceData( dependencies );
}
...
}
|
public class CustomDerivedValueService extends DerivedValueService
{
@Override
public String getDerivedValue()
{
String value;
...
return value;
}
...
}
|
public class CustomDerivedValueService extends DerivedValueService
{
@Override
protected DerivedValueServiceData compute()
{
String value;
...
return new DerivedValueServiceData( value );
}
...
}
|
public class CustomEnablementService extends EnablementService
{
@Override
protected void initEnablementService( IModelElement element,
ModelProperty property,
String[] params )
{
...
}
@Override
protected boolean compute()
{
boolean enablement;
...
return enablement;
}
...
}
|
public class CustomEnablementService extends EnablementService
{
@Override
protected void initEnablementService()
{
final IModelElement element = context( IModelElement.class );
final ModelProperty property = context( ModelProperty.class );
final String p1 = param( "p1" );
final String p2 = param( "p2" );
...
}
@Override
protected EnablementServiceData compute()
{
boolean enablement;
...
return new EnablementServiceData( enablement );
}
...
}
|
public class CustomFileExtensionsService extends FileExtensionsService
{
@Override
protected void initFileExtensionsService( IModelElement element,
ModelProperty property,
String[] params )
{
...
}
@Override
protected void compute( List<String> extensions )
{
extensions.add( ... );
extensions.add( ... );
...
}
...
}
|
public class CustomFileExtensionsService extends FileExtensionsService
{
@Override
protected void initFileExtensionsService()
{
final IModelElement element = context( IModelElement.class );
final ModelProperty property = context( ModelProperty.class );
final String p1 = param( "p1" );
final String p2 = param( "p2" );
...
}
@Override
protected FileExtensionsServiceData compute()
{
List<String> extensions = new ArrayList<String>();
extensions.add( ... );
extensions.add( ... );
...
return new FileExtensionsServiceData( extensions );
}
...
}
|
public class CustomImageService extends ImageService
{
@Override
protected void init()
{
super.init();
// Listen on entities that influence image choice.
// Call broadcast() when something has changed.
...
}
@Override
public ImageData provide()
{
ImageData image;
...
return image;
}
...
}
|
public class CustomImageService extends ImageService
{
@Override
protected void initImageService()
{
// Listen on entities that influence image choice.
// Call refresh() when something has changed.
...
}
@Override
protected ImageServiceData compute()
{
ImageData image;
...
return new ImageServiceData( image );
}
...
}
|
ModelService.Listener listener = new ModelService.Listener()
{
public void handleEvent( ModelService.Event event )
{
...
}
}
service.addListener( listener );
...
service.removeListener( listener );
...
while inside service
{
notifyListeners( new ModelService.Event( this ) );
}
|
Listener listener = new Listener()
{
public void handle( Event event )
{
...
}
}
service.attach( listener );
...
service.detach( listener );
...
while inside service
{
broadcast();
}
|
@Type( base = Date.class )
@ValueSerialization
(
service = DateSerializationService.class,
params = { "yyyy.MM.dd", "MM/dd/yyyy" }
)
ValueProperty PROP_DATE = new ValueProperty( TYPE, "Date" );
Value getDate();
void setDate( String value );
void setDate( Date value );
|
@Type( base = Date.class )
@Service
(
impl = DateSerializationService.class,
params =
{
@Service.Param( name = "format-1", value = "yyyy.MM.dd" ),
@Service.Param( name = "format-2", value = "MM/dd/yyyy" )
}
)
ValueProperty PROP_DATE = new ValueProperty( TYPE, "Date" );
Value getDate();
void setDate( String value );
void setDate( Date value );
|
public class CustomValidationService extends UniqueValueValidationService<String>
{
@Override
protected boolean isUniqueValue( Value<String> value )
{
...
}
}
|
public class CustomValidationService extends UniqueValueValidationService
{
@Override
protected boolean isUniqueValue( Value<?> value )
{
...
}
}
|
All core services have been consolidated in a single package. Some of them were renamed in the process.
Before |
After |
org.eclipse.sapphire.modeling.DefaultValueService |
org.eclipse.sapphire.services.DefaultValueService |
org.eclipse.sapphire.modeling.DerivedValueService |
org.eclipse.sapphire.services.DerivedValueService |
org.eclipse.sapphire.modeling.EnablementService |
org.eclipse.sapphire.services.EnablementService |
org.eclipse.sapphire.modeling.ImageService |
org.eclipse.sapphire.services.ImageService |
org.eclipse.sapphire.modeling.PossibleValuesService |
org.eclipse.sapphire.services.PossibleValuesService |
org.eclipse.sapphire.modeling.ReferenceService |
org.eclipse.sapphire.services.ReferenceService |
org.eclipse.sapphire.modeling.RelativePathService |
org.eclipse.sapphire.services.RelativePathService |
org.eclipse.sapphire.modeling.StandardValueNormalizationService |
org.eclipse.sapphire.services.StandardValueNormalizationService |
org.eclipse.sapphire.modeling.ModelPropertyValidationService |
org.eclipse.sapphire.services.ValidationService |
org.eclipse.sapphire.modeling.ValueImageService |
org.eclipse.sapphire.services.ValueImageService |
org.eclipse.sapphire.modeling.ValueLabelService |
org.eclipse.sapphire.services.ValueLabelService |
org.eclipse.sapphire.modeling.ValueNormalizationService |
org.eclipse.sapphire.services.ValueNormalizationService |
org.eclipse.sapphire.modeling.serialization.DateSerializationService |
org.eclipse.sapphire.services.DateSerializationService |
org.eclipse.sapphire.modeling.serialization.ValueSerializationService |
org.eclipse.sapphire.services.ValueSerializationService |
org.eclipse.sapphire.modeling.validation.PathValidationService |
org.eclipse.sapphire.services.PathValidationService |
org.eclipse.sapphire.modeling.validation.UniqueValueValidationService |
org.eclipse.sapphire.services.UniqueValueValidationService |
The set of possible types for a list or an element property is no longer restricted to be static. As such, previous API for
retrieving possible types for a property has been replaced with a more flexible service API.
The pattern of overriding the dispose method on SapphireActionHandler has been replaced with a dispose event. This
architecture eliminates resource leaks caused by failing to call super.dispose() when overriding the dispose method.
The @XmlRootBinding annotation has been re-worked to reduce functional overlap with other annotations and to allow
the XML binding API to more easily adapt to different kinds of XML document type specification technologies. Scenarios
previously handled by @XmlRootBinding annotation are now handled by different combinations of @XmlBinding, @XmlNamespace,
@XmlSchema and @XmlDocumentType annotations.
The PropertyEditorAssistContribution API has changed to remove dependencies on SWT/JFace and to make contribution
immutable once created.