| /***************************************************************************** |
| * Copyright (c) 2016 CEA LIST. |
| * |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * David LOPEZ BETANCUR (CEA LIST) |
| * Sebastien REVOL (CEA LIST) |
| * |
| *****************************************************************************/ |
| package org.eclipse.papyrus.moka.datavisualization.csv; |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.resource.impl.ResourceImpl; |
| import org.eclipse.papyrus.moka.datavisualization.profile.BooleanSeries; |
| import org.eclipse.papyrus.moka.datavisualization.profile.DataSource; |
| import org.eclipse.papyrus.moka.datavisualization.profile.DoubleSeries; |
| import org.eclipse.papyrus.moka.datavisualization.profile.IntegerSeries; |
| import org.eclipse.papyrus.moka.datavisualization.profile.StringSeries; |
| import org.eclipse.papyrus.moka.datavisualization.profile.ValueSeries; |
| import org.eclipse.papyrus.moka.datavisualization.profile.VisualizationPackage; |
| import org.eclipse.papyrus.moka.datavisualization.util.VisualizationUtil; |
| import org.eclipse.uml2.uml.DataType; |
| import org.eclipse.uml2.uml.Package; |
| import org.eclipse.uml2.uml.Property; |
| import org.eclipse.uml2.uml.UMLFactory; |
| import org.eclipse.uml2.uml.UMLPackage; |
| import org.eclipse.uml2.uml.util.UMLUtil; |
| |
| public class CSVResource extends ResourceImpl { |
| |
| |
| |
| |
| private String separator=";"; |
| |
| |
| public static final String OPTION_SEPARATOR= "separator"; |
| public static final String OPTION_TARGET_PACKAGE= "TARGET_PACKAGE"; |
| |
| |
| |
| private static final String VALUES_FEATURE_NAME = "values"; |
| |
| |
| |
| |
| |
| |
| private UMLFactory eFactory = (UMLFactory) UMLPackage.eINSTANCE.getEFactoryInstance(); |
| private Package rootModel; |
| private DataType dataType; |
| private DataSource dataSource; |
| private ArrayList<ValueSeries> seriesList= new ArrayList<>(); |
| |
| private String DEFAULT_SOURCE_NAME= "CSVFile"; |
| |
| |
| |
| |
| |
| @Override |
| protected void doLoad(InputStream inputStream, Map<?, ?> options) throws IOException { |
| |
| initializeOptions(options); |
| |
| URI uri = getURI(); |
| String sourceName = DEFAULT_SOURCE_NAME; |
| if (uri != null){ |
| sourceName = uri.trimFileExtension().lastSegment(); |
| } |
| if (rootModel ==null){ |
| rootModel = eFactory.createModel(); |
| rootModel.setName(sourceName+"Model"); |
| getContents().add(rootModel); |
| } |
| |
| |
| VisualizationUtil.applyVisualizationProfileIfNeeded(rootModel); |
| |
| dataType = (DataType) rootModel.createOwnedType(sourceName, UMLPackage.eINSTANCE.getDataType()); |
| dataType.setName(sourceName); |
| dataType.applyStereotype(VisualizationUtil.getDataSourceStereotype(rootModel)); |
| |
| dataType.eSetDeliver(false); |
| rootModel.getPackagedElements().add(dataType); |
| |
| //first release does not support options |
| //initializeOptions(options); |
| |
| BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); |
| |
| String line =bufferedReader.readLine(); |
| |
| //we skip emptyLines |
| while (line != null && line.trim().isEmpty()){ |
| line = bufferedReader.readLine(); |
| } |
| if (line != null){ |
| initializeProperties(line); |
| |
| line = bufferedReader.readLine(); |
| //we skip emptyLines |
| while (line != null && line.trim().isEmpty()){ |
| line = bufferedReader.readLine(); |
| } |
| initializeSeries(line); |
| |
| while ((line = bufferedReader.readLine()) != null){ |
| populateValues(line); |
| } |
| |
| } |
| |
| bufferedReader.close(); |
| |
| |
| rootModel.eSetDeliver(true); |
| for (ValueSeries serie : seriesList){ |
| serie.eSetDeliver(true); |
| } |
| |
| |
| } |
| |
| |
| |
| private void initializeOptions(Map<?, ?> options) { |
| if (options != null){ |
| |
| Object optionSeparator = options.get(OPTION_SEPARATOR); |
| if (optionSeparator instanceof String){ |
| separator = (String) optionSeparator; |
| } |
| |
| Object optionTargetPackage = options.get(OPTION_TARGET_PACKAGE); |
| |
| if (optionTargetPackage instanceof Package){ |
| rootModel = (Package) optionTargetPackage; |
| } |
| } |
| |
| } |
| |
| |
| |
| private void initializeSeries(String line) { |
| String[] tokens = line.split(separator); |
| if (tokens != null){ |
| for(int i = 0; i< tokens.length; i++){ |
| String token = tokens[i]; |
| ValueSeries serie = getValueSeries(guessType(token), dataType.getOwnedAttributes().get(i)); |
| addInSeries(serie, token); |
| } |
| } |
| } |
| |
| |
| private void initializeProperties(String line) { |
| String[] tokens = line.split(separator); |
| if (tokens != null){ |
| for(int i = 0; i< tokens.length; i++){ |
| dataType.createOwnedAttribute(tokens[i], null); |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| private int computeAlternateType(String token, int unSuccessfulID){ |
| switch (unSuccessfulID){ |
| |
| case VisualizationPackage.BOOLEAN_SERIES : |
| //if we parsed "true or false" once and then failed |
| //the only possible alternative is String |
| return EcorePackage.ESTRING; |
| |
| case VisualizationPackage.INTEGER_SERIES : |
| //we parsed an int once and then failed, maybe it's a double |
| if(isDouble(token)){ |
| return EcorePackage.EDOUBLE; |
| }else { |
| //if it's not a double, it's a string |
| return EcorePackage.ESTRING; |
| } |
| case VisualizationPackage.DOUBLE_SERIES : |
| //if we parsed a double once and then failed, |
| //we fall back to String |
| return EcorePackage.ESTRING; |
| } |
| |
| return EcorePackage.ESTRING; |
| } |
| |
| private int guessType(String token){ |
| if (isBoolean(token)){ |
| return EcorePackage.EBOOLEAN; |
| }else if (isInteger(token)){ |
| return EcorePackage.EINT; |
| }else if (isDouble(token)){ |
| return EcorePackage.EDOUBLE; |
| }else { |
| return EcorePackage.ESTRING; |
| } |
| |
| } |
| |
| |
| |
| private boolean isDouble(String token) { |
| try{ |
| Double.parseDouble(token); |
| return true; |
| }catch(NumberFormatException exDouble){ |
| return false; |
| } |
| } |
| |
| private boolean isInteger(String token) { |
| try{ |
| Integer.decode(token); |
| return true; |
| }catch(NumberFormatException exDouble){ |
| return false; |
| } |
| } |
| |
| |
| |
| private boolean isBoolean(String token) { |
| return "TRUE".equalsIgnoreCase(token) || "FALSE".equalsIgnoreCase(token); |
| } |
| |
| |
| private boolean parseBoolean(String token) throws NumberFormatException{ |
| if ("TRUE".equalsIgnoreCase(token)){ |
| return true; |
| }else if ("FALSE".equalsIgnoreCase(token)){ |
| return false; |
| }else { |
| throw new NumberFormatException(); |
| } |
| } |
| |
| private ValueSeries getValueSeries(int dataTypeID, Property property){ |
| ValueSeries ret= null; |
| |
| switch (dataTypeID){ |
| case EcorePackage.EDOUBLE : |
| ret = (ValueSeries) property.applyStereotype(VisualizationUtil.getStereotype(VisualizationPackage.eINSTANCE.getDoubleSeries(), property)); |
| property.setType(VisualizationUtil.getUMLPrimitiveType(property,VisualizationUtil.REAL_NAME)); |
| break; |
| case EcorePackage.EBOOLEAN: |
| ret = (ValueSeries) property.applyStereotype(VisualizationUtil.getStereotype(VisualizationPackage.eINSTANCE.getBooleanSeries(), property)); |
| property.setType(VisualizationUtil.getUMLPrimitiveType(property,VisualizationUtil.BOOLEAN_NAME)); |
| break; |
| case EcorePackage.EINT : |
| ret = (ValueSeries) property.applyStereotype(VisualizationUtil.getStereotype(VisualizationPackage.eINSTANCE.getIntegerSeries(), property)); |
| property.setType(VisualizationUtil.getUMLPrimitiveType(property,VisualizationUtil.INTEGER_NAME)); |
| break; |
| default: |
| ret = (ValueSeries) property.applyStereotype(VisualizationUtil.getStereotype(VisualizationPackage.eINSTANCE.getStringSeries(), property)); |
| property.setType(VisualizationUtil.getUMLPrimitiveType(property,VisualizationUtil.STRING_NAME)); |
| break; |
| } |
| ret.eSetDeliver(false); |
| seriesList.add(ret); |
| return ret; |
| } |
| |
| |
| private void addInSeries(ValueSeries serie, String token){ |
| try{ |
| int id = serie.eClass().getClassifierID(); |
| if ( VisualizationPackage.DOUBLE_SERIES== id){ |
| ((DoubleSeries)serie).getValues().add(Double.parseDouble(token)); |
| }else if (VisualizationPackage.STRING_SERIES == id){ |
| ((StringSeries)serie).getValues().add(token); |
| }else if ( VisualizationPackage.INTEGER_SERIES == id){ |
| ((IntegerSeries)serie).getValues().add(Integer.decode(token)); |
| }else { |
| ((BooleanSeries)serie).getValues().add(parseBoolean(token)); |
| } |
| |
| }catch(NumberFormatException exeption){ |
| reinitializeSeries(serie, token); |
| } |
| |
| } |
| |
| |
| private void reinitializeSeries(ValueSeries serie, String token) { |
| |
| ValueSeries newSerie = getValueSeries(computeAlternateType(token, serie.eClass().getClassifierID()), serie.getBase_Property()); |
| int index = seriesList.indexOf(serie); |
| seriesList.remove(index); |
| seriesList.add(index,newSerie); |
| |
| @SuppressWarnings("rawtypes") |
| List values = (List) serie.eGet(serie.eClass().getEStructuralFeature(VALUES_FEATURE_NAME)); |
| |
| for (Object value : values){ |
| addInSeries(newSerie, value.toString()); |
| } |
| |
| addInSeries(newSerie, token); |
| |
| serie.getBase_Property().unapplyStereotype(UMLUtil.getStereotype(serie)); |
| |
| |
| } |
| |
| |
| |
| private void populateValues(String line) throws IOException { |
| String[] tokens = line.split(separator); |
| for (int i = 0; i< tokens.length; i++){ |
| //we skip incorrect lines |
| if (tokens.length == dataType.getOwnedAttributes().size()){ |
| addInSeries( seriesList.get(i), tokens[i]); |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| @Override |
| protected void doSave(OutputStream outputStream, Map<?, ?> options) throws IOException { |
| //first release does not support options |
| initializeOptions(options); |
| updateDataType(); |
| if (dataType != null){ |
| BufferedWriter writter = new BufferedWriter(new PrintWriter(outputStream)); |
| |
| |
| if( dataSource != null){ |
| List<ValueSeries> series = dataSource.getSeries(); |
| int seriesNumber = series.size(); |
| |
| for(int i=0; i< seriesNumber; i++){ |
| writter.append(series.get(i).getBase_Property().getName()); |
| if (i < seriesNumber -1){ |
| writter.append(separator); |
| } |
| } |
| writter.newLine(); |
| |
| |
| int lineNumber = dataSource.getSeries().get(0).getSize(); |
| |
| for (int lineIndex =0 ; lineIndex< lineNumber; lineIndex++ ){ |
| for(int serieIndex = 0; serieIndex <seriesNumber; serieIndex++){ |
| writter.append( dataSource.getSeries().get(serieIndex).getStringValue(lineIndex)); |
| if (serieIndex < seriesNumber-1){ |
| writter.append(separator); |
| } |
| } |
| if (lineIndex < lineNumber -1){ |
| writter.newLine(); |
| } |
| |
| } |
| } |
| |
| |
| writter.close(); |
| |
| |
| |
| } |
| |
| } |
| |
| |
| |
| private void updateDataType() { |
| |
| for (EObject content : getContents()){ |
| if( content instanceof DataSource && ((DataSource)content).getBase_DataType() != null){ |
| dataSource = (DataSource) content; |
| dataType = ((DataSource)content).getBase_DataType() ; |
| return; |
| } |
| } |
| |
| } |
| |
| |
| } |