blob: 1f61eee834bbcd9c15f132f36d1f5c5e0e264b19 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2019 CEA LIST
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* David Lopez david.lopez@cea.fr(CEA LIST)
*
*****************************************************************************/
package org.eclipse.papyrus.moka.engine.suml.accessor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.papyrus.moka.engine.suml.accessor.structures.ListAccess;
import org.eclipse.papyrus.moka.engine.suml.accessor.structures.MapAccess;
import org.eclipse.papyrus.moka.engine.suml.accessor.structures.OperationAccess;
import org.eclipse.papyrus.moka.fuml.simpleclassifiers.IStructuredValue;
import org.eclipse.uml2.uml.MultiplicityElement;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.TypedElement;
//ComponentType -> IFeatureValue, Slot, ParameterValue
//ValueType -> IValue, ValueSpecification
//They are usually contained in another ValueType
//InstanceSpecification { Slot* }
//IStructuredValue { IFeatureValue* }
public class ComponentAccessor<ComponentType, ValueType> {
public Object componentValueToScript(ComponentType component) {
if( component == null )
return null;
if( this.getDescriptor(component).isMultivalued() )
return new ListAccess<ComponentType, ValueType>(this, component);
return componentValueIndexToScript(component, 0);
}
/** If the component is multivalued will return a ListAccess
* If the component is structured will return a MapAccess
* If the component is univalued will return a Raw value (Double, Integer ...)
* @param component
* @return
*/
public Object componentValueIndexToScript(ComponentType component, int valueIndex) {
List<ValueType> values = getValues(component);
if( values.isEmpty() )
return null;
ValueType value = (ValueType) values.get(valueIndex);
return valueToScript(value);
}
public Object valueToScript(ValueType value) {
if( value == null )
return null;
ValueTypeConverter<ValueType> converter = converter(value);
if( converter.isComposite(value) )
return new MapAccess<ComponentType, ValueType>(this, value, destructure(value), getOperations(value) );
return converter.getRawValue(value);
}
public Object valueListToScript(List<ValueType> values) {
if( values.size() == 0 )
return Void.TYPE;
if( values.size() == 1 )
return valueToScript(values.get(0));
List<Object> objs = new ArrayList<Object>(values.size());
for( ValueType v : values )
objs.add( valueToScript(v) );
return objs;
}
private Map<String, OperationAccess> getOperations(ValueType value){
HashMap<String, OperationAccess> map = new HashMap<String, OperationAccess>();
if( value instanceof IStructuredValue ) {
IStructuredValue structuredValue = (IStructuredValue)value;
List<Operation> ops = structuredValue.getTypes().get(0).getAllOperations();
for( Operation o : ops ) {
map.put(o.getName(), new OperationAccess(value, o));
}
}
return map;
}
protected Map<String, ComponentType> destructure(ValueType value) {
ValueTypeConverter<ValueType> converter = converter(value);
List<ComponentType> parts = converter.getComponents(value);
HashMap<String, ComponentType> map = new HashMap<String, ComponentType>();
for( ComponentType part : parts)
map.put(getDescriptor(part).getName(), part);
return map;
}
public void setValueFromScript(ComponentType component, Object obj) {
if( getDescriptor(component).isMultivalued() ) {
setListValue(component, obj);
return;
}
setSingleValue(component, obj);
}
private void setSingleValue(ComponentType component, Object obj) {
List<ValueType> values = getValues(component);
if( values.isEmpty() ) {
if( obj != null )
values.add(newValue( component, obj ));
return;
}
setValueFromScriptAt(component, 0, obj);
}
private ValueType newValue(ComponentType component, Object obj) {
ValueTypeConverter<ValueType> converter = converterForComponent(component);
if( converter.isValueType(obj) )
return (ValueType) obj;
Type type = getDescriptor(component).getType();
if( !converter.isPrimitive(type) ) {
if( !(obj instanceof MapAccess) )
throw new RuntimeException("Value ["+ obj + "] can't be assigned to type: " + type );
MapAccess map = (MapAccess)obj;
return (ValueType) map.unwrap();
}
return converter.newPrimitiveValue( type, obj);
}
public void setValueFromScriptAt(ComponentType component, int index, Object obj) {
List<ValueType> values = getValues(component);
if( obj == null ) {
values.set(index, null);
return;
}
ValueTypeConverter<ValueType> converter = converterForComponent(component);
if( converter.isValueType(obj) ) {
values.set(index, (ValueType)obj);
return;
}
ValueType value = values.get(index);
if( value == null ) {
value = newValue(component, obj);
values.set(index, value);
return;
}
converter(value).setRawValue(values.get(index), obj);
}
private void setListValue(ComponentType component, Object obj ) {
List<ValueType> values = getValues(component);
if( !(obj instanceof List) )
throw new RuntimeException("Operation not supported for this object");
//This operation should replace the whole list
values.clear();
//Has to create new values
for( Object item : (List<Object>)obj )
values.add( newValue( component, item) );
}
public boolean addValueFromScript(ComponentType component, Object obj) {
List<ValueType> values = getValues(component);
return values.add( newValue( component, obj) );
}
private boolean isComposite(ComponentType component) {
return converterForComponent(component).isPrimitive( getDescriptor(component).getType() );
}
private ValueTypeConverter<ValueType> converter(ValueType value){
return AccessAdapterRegistry.getInstance().getConverterForValue(value);
}
private ValueTypeConverter<ValueType> converterForComponent(ComponentType component){
ComponentAdapter adapter = AccessAdapterRegistry.getInstance().getAdapterForObject(component);
return AccessAdapterRegistry.getInstance().getConverterForClass(adapter.getValueType());
}
public <ValueType> List<ValueType> getValues(ComponentType component){
return AccessAdapterRegistry.getInstance().getAdapterForObject(component).getValues(component);
}
public <DescriptorType extends MultiplicityElement & TypedElement> DescriptorType getDescriptor(ComponentType component) {
return (DescriptorType) AccessAdapterRegistry.getInstance().getAdapterForObject(component).getDescriptor(component);
}
}