| /***************************************************************************** |
| * 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); |
| } |
| |
| } |