/** * Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.roboconf.core.dsl.converters; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.roboconf.core.dsl.ParsingConstants; import net.roboconf.core.dsl.parsing.AbstractBlock; import net.roboconf.core.dsl.parsing.BlockBlank; import net.roboconf.core.dsl.parsing.BlockComment; import net.roboconf.core.dsl.parsing.BlockComponent; import net.roboconf.core.dsl.parsing.BlockFacet; import net.roboconf.core.dsl.parsing.BlockProperty; import net.roboconf.core.dsl.parsing.FileDefinition; import net.roboconf.core.model.beans.AbstractType; import net.roboconf.core.model.beans.Component; import net.roboconf.core.model.beans.ExportedVariable; import net.roboconf.core.model.beans.Facet; import net.roboconf.core.model.beans.Graphs; import net.roboconf.core.model.beans.ImportedVariable; import net.roboconf.core.model.helpers.ComponentHelpers; import net.roboconf.core.utils.Utils; /** * To dump a {@link Graphs} into a file. * @author Vincent Zurczak - Linagora */ public class FromGraphs { /** * Builds a file definition from a graph. * @param graphs the graphs * @param targetFile the target file (will not be written) * @param addComment true to insert generated comments * @return a non-null file definition */ public FileDefinition buildFileDefinition( Graphs graphs, File targetFile, boolean addComment ) { // Build the global structure FileDefinition result = new FileDefinition( targetFile ); result.setFileType( FileDefinition.GRAPH ); if( addComment ) { String s = "# File created from an in-memory model,\n# without a binding to existing files."; BlockComment initialComment = new BlockComment( result, s ); result.getBlocks().add( initialComment ); result.getBlocks().add( new BlockBlank( result, "\n" )); } // Process and serialize the components Set<String> alreadySerializedNames = new HashSet<> (); for( Component c : ComponentHelpers.findAllComponents( graphs )) { if( alreadySerializedNames.contains( c.getName())) continue; alreadySerializedNames.add( c.getName()); result.getBlocks().addAll( buildComponent( result, c, addComment )); for( Facet f : ComponentHelpers.findAllFacets( c )) { if( alreadySerializedNames.contains( f.getName())) continue; alreadySerializedNames.add( f.getName()); result.getBlocks().addAll( buildFacet( result, f, addComment )); } } // There may be orphan facets too for( Facet f : graphs.getFacetNameToFacet().values()) { if( alreadySerializedNames.contains( f.getName())) continue; alreadySerializedNames.add( f.getName()); result.getBlocks().addAll( buildFacet( result, f, addComment )); } return result; } private Collection<AbstractBlock> buildComponent( FileDefinition file, Component component, boolean addComment ) { Collection<AbstractBlock> result = new ArrayList<> (); // Add a comment if( addComment ) { StringBuilder sb = new StringBuilder(); sb.append( "# Component '" ); sb.append( component.getName()); sb.append( "'" ); result.add( new BlockComment( file, sb.toString())); } // Basic properties BlockComponent blockComponent = new BlockComponent( file ); blockComponent.setName( component.getName()); result.add( blockComponent ); result.add( new BlockBlank( file, "\n" )); BlockProperty p; if( component.getExtendedComponent() != null ) { p = new BlockProperty( file, ParsingConstants.PROPERTY_GRAPH_EXTENDS, component.getExtendedComponent().getName()); blockComponent.getInnerBlocks().add( p ); } if( ! Utils.isEmptyOrWhitespaces( component.getInstallerName())) { p = new BlockProperty( file, ParsingConstants.PROPERTY_COMPONENT_INSTALLER, component.getInstallerName()); blockComponent.getInnerBlocks().add( p ); } // Facets String s = writeCollection( component.getFacets()); if( ! Utils.isEmptyOrWhitespaces( s )) { p = new BlockProperty( file, ParsingConstants.PROPERTY_COMPONENT_FACETS, s ); blockComponent.getInnerBlocks().add( p ); } // Imported Variables StringBuilder sb = new StringBuilder(); for( Iterator<ImportedVariable> it=component.importedVariables.values().iterator(); it.hasNext(); ) { ImportedVariable var = it.next(); if( var.isExternal()) { sb.append( ParsingConstants.PROPERTY_COMPONENT_EXTERNAL_IMPORT ); sb.append( " " ); } sb.append( var.getName()); if( var.isOptional()) { sb.append( " " ); sb.append( ParsingConstants.PROPERTY_COMPONENT_OPTIONAL_IMPORT ); } if( it.hasNext()) sb.append( ", " ); } if( ! Utils.isEmptyOrWhitespaces( sb.toString())) { p = new BlockProperty( file, ParsingConstants.PROPERTY_COMPONENT_IMPORTS, sb.toString()); blockComponent.getInnerBlocks().add( p ); } // Exported variables s = writeExportedVariables( component ); if( ! Utils.isEmptyOrWhitespaces( s )) { p = new BlockProperty( file, ParsingConstants.PROPERTY_GRAPH_EXPORTS, s ); blockComponent.getInnerBlocks().add( p ); } // Children s = writeCollection( component.getChildren()); if( ! Utils.isEmptyOrWhitespaces( s )) { p = new BlockProperty( file, ParsingConstants.PROPERTY_GRAPH_CHILDREN, s ); blockComponent.getInnerBlocks().add( p ); } return result; } private Collection<AbstractBlock> buildFacet( FileDefinition file, Facet facet, boolean addComment ) { Collection<AbstractBlock> result = new ArrayList<> (); // Add a comment if( addComment ) { StringBuilder sb = new StringBuilder(); sb.append( "# Facet '" ); sb.append( facet.getName()); sb.append( "'" ); result.add( new BlockComment( file, sb.toString())); } // Basic properties BlockFacet blockFacet = new BlockFacet( file ); blockFacet.setName( facet.getName()); result.add( blockFacet ); result.add( new BlockBlank( file, "\n" )); // Extended facets BlockProperty p; String s = writeCollection( facet.getExtendedFacets()); if( ! Utils.isEmptyOrWhitespaces( s )) { p = new BlockProperty( file, ParsingConstants.PROPERTY_GRAPH_EXTENDS, s ); blockFacet.getInnerBlocks().add( p ); } // Exported variables s = writeExportedVariables( facet ); if( ! Utils.isEmptyOrWhitespaces( s )) { p = new BlockProperty( file, ParsingConstants.PROPERTY_GRAPH_EXPORTS, s ); blockFacet.getInnerBlocks().add( p ); } // Children s = writeCollection( facet.getChildren()); if( ! Utils.isEmptyOrWhitespaces( s )) { p = new BlockProperty( file, ParsingConstants.PROPERTY_GRAPH_CHILDREN, s ); blockFacet.getInnerBlocks().add( p ); } return result; } private String writeExportedVariables( AbstractType type ) { StringBuilder sb = new StringBuilder(); for( Iterator<Map.Entry<String,ExportedVariable>> it=type.exportedVariables.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String,ExportedVariable> entry = it.next(); sb.append( entry.getKey()); String variableValue = entry.getValue().getValue(); if( ! Utils.isEmptyOrWhitespaces( variableValue )) { sb.append( "=\"" ); sb.append( variableValue ); sb.append( "\"" ); } if( it.hasNext()) sb.append( ", " ); } return sb.toString(); } private String writeCollection( Collection<? extends AbstractType> types ) { StringBuilder sb = new StringBuilder(); for( Iterator<? extends AbstractType> it=types.iterator(); it.hasNext(); ) { sb.append( it.next().getName()); if( it.hasNext()) sb.append( ", " ); } return sb.toString(); } }