blob: 0d82aa3110cc1654c26ad8bbfee97b028f58a808 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2014 Atos.
*
*
* 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:
* Anne Haugommard (Atos) anne.haugommard@atos.net - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.gendoc.script.services.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.acceleo.model.mtl.Module;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gendoc.m2t.IFragmentService;
import org.eclipse.gendoc.m2t.IFragmentableM2TProcessor;
import org.eclipse.gendoc.m2t.IM2TProcessor;
import org.eclipse.gendoc.m2t.IScriptLanguageExtensionService;
import org.eclipse.gendoc.m2t.model.Fragment;
import org.eclipse.gendoc.script.acceleo.Generator;
import org.eclipse.gendoc.script.acceleo.IFileAndMMRegistry;
import org.eclipse.gendoc.script.acceleo.Messages;
import org.eclipse.gendoc.script.services.IModuleManagerService;
import org.eclipse.gendoc.script.services.impl.TopologicalSort.CycleException;
import org.eclipse.gendoc.services.AbstractService;
import org.eclipse.gendoc.services.GendocServices;
import org.eclipse.gendoc.services.exception.GenDocException;
import org.eclipse.gendoc.services.exception.GenerationException;
import org.eclipse.gendoc.services.exception.UnknownScriptLanguageException;
import org.eclipse.gendoc.tags.handlers.IConfigurationService;
public class ModuleManagerService extends AbstractService implements IModuleManagerService
{
// the metamodels are converted to a string used by uris and are stored as ids
Map<String, Set<Module>> mapMetamodels2CompiledBundlesIds = new HashMap<String, Set<Module>>();
/*
* (non-Javadoc)
*
* @see org.eclipse.gendoc.script.services.IModuleManagerService#getImportedModules(org.eclipse.emf.ecore.EObject)
*/
public List<String> getImportedModules(EObject element) throws GenDocException
{
IConfigurationService config = GendocServices.getDefault().getService(IConfigurationService.class);
IScriptLanguageExtensionService scriptLanguageExtensionService = GendocServices.getDefault().getService(IScriptLanguageExtensionService.class);
try
{
IM2TProcessor processor = scriptLanguageExtensionService.getProcessor(config.getLanguage());
if (processor instanceof IFragmentableM2TProcessor)
{
IFragmentableM2TProcessor fragmentable = (IFragmentableM2TProcessor) processor;
IFragmentService fragmentService = GendocServices.getDefault().getService(IFragmentService.class);
List<Fragment> fragments = fragmentService.getAllFragments();
if (fragments != null)
{
return manageFragments(element, fragments, fragmentable);
}
}
}
catch (UnknownScriptLanguageException e)
{
e.printStackTrace();
}
return null;
}
/**
* @param element
* @param fragments
* @param fragmentable
* @return
* @throws GenDocException
*/
protected List<String> manageFragments(EObject element, List<Fragment> fragments, IFragmentableM2TProcessor fragmentable) throws GenDocException
{
Collection<String> metamodels = getMetamodels(element);
String id = getMMString(metamodels);
Set<Module> result = mapMetamodels2CompiledBundlesIds.get(id);
if (result == null)
{
result = new HashSet<Module>();
// result is put at the start to remember the compiled modules
mapMetamodels2CompiledBundlesIds.put(id, result);
Map<String, Fragment> map = getFragmentsMap();
// dependency analysis for compilation
try
{
fragments = topologicalSort(fragments);
}
// the fragment comparator throws a runtime exception
// as the method compare declare any
catch (CycleException e)
{
// if the exception is catched a gendoc Exception is catched
throw new GenDocException("fragment dependency error from " + (e.getNode() != null ? e.getNode().toString() : ""))
{
private static final long serialVersionUID = 1L;
};
}
// the fragments are sorted
// the first ones have no dependencies to their followers
String script = fragmentable.runFragmentsScript(element, fragments);
Generator generator;
try
{
List<URI> dependencies = new ArrayList<URI>();
dependencies.add(getModuleURIForFragmentName(metamodels, IFragmentService.FRAGMENT_MODULE_NAME));
generator = new Generator(element, script, dependencies);
Module m = generator.getModule();
m.eResource().setURI(generateURI(id, m));
if (m != null)
{
result.add(m);
}
}
catch (IOException e)
{
throw new GenerationException("Error during generation of the following script : \n" + script, e);
}
}
List<String> toReturn = new LinkedList<String>();
for (Module m : result)
{
toReturn.add(m.getName());
}
return toReturn;
}
private List<Fragment> topologicalSort(List<Fragment> fragments) throws CycleException {
FragmentEdge edge = new FragmentEdge(getFragmentsMap());
List<Fragment> result = TopologicalSort.sort(fragments, edge);
Collections.reverse(result);
return result;
}
Map<String, Fragment> getFragmentsMap()
{
IFragmentService service = GendocServices.getDefault().getService(IFragmentService.class);
Map<String, Fragment> allFragments = new HashMap<String, Fragment>();
for (Fragment f : service.getAllFragments())
{
allFragments.put(f.getName(), f);
}
return allFragments;
}
/**
* Returns an unique id for collection of metamodels uri
*
* @param metamodels
* @return
*/
private String getMMString(Collection<String> metamodels)
{
StringBuilder id = new StringBuilder();
List<String> list = new ArrayList<String>(metamodels);
// the sort method ensure the order of the metamodels is always the same
Collections.sort(list);
for (String s : list)
{
id.append(s.replace(':', '_').replace('/', '_').replace('.', '_'));
}
return id.toString();
}
/**
* Get the module uri for a list of metamodels and for a dependency
*
* @param metamodels
* @param dep
* @return
*/
private URI getModuleURIForFragmentName(Collection<String> metamodels, String dep)
{
return generateURI(getMMString(metamodels), dep);
}
@Override
public void clear()
{
super.clear();
for (Set<Module> list : mapMetamodels2CompiledBundlesIds.values())
{
for (Module m : list)
{
if (m.eResource() != null)
{
m.eResource().unload();
}
}
}
mapMetamodels2CompiledBundlesIds.clear();
}
/**
* Generate URI for a given module
*
* @param generateUUID
* @param m
* @return
*/
protected URI generateURI(String generateUUID, Module m)
{
return generateURI(generateUUID, m.getName());
}
/**
* Create the URI for a unique id and a module name
*
* @param generateUUID
* @param m
* @return
*/
protected URI generateURI(String generateUUID, String moduleName)
{
return URI.createURI(Messages.GendocResourceFactory_BUNDLE_URI_SCHEME + "://" + generateUUID + "/" + moduleName + ".emtl");
}
/**
* @param element
* @return
*/
protected Collection<String> getMetamodels(EObject element)
{
IFileAndMMRegistry registry = GendocServices.getDefault().getService(IFileAndMMRegistry.class);
Collection<String> metamodels = registry.getMetamodels(element);
return metamodels;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gendoc.script.services.IModuleManagerService#getModuleURIs(org.eclipse.emf.ecore.EObject)
*/
public List<URI> getModuleURIs(EObject element)
{
List<URI> result = new LinkedList<URI>();
IFileAndMMRegistry registry = GendocServices.getDefault().getService(IFileAndMMRegistry.class);
Collection<String> metamodels = registry.getMetamodels(element);
Set<Module> modules = mapMetamodels2CompiledBundlesIds.get(getMMString(metamodels));
for (Module m : modules)
{
result.add(m.eResource().getURI());
}
return result;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gendoc.script.services.IModuleManagerService#getModule(org.eclipse.emf.common.util.URI)
*/
public Module getModule(URI uri)
{
if (uri == null)
{
return null;
}
if (uri.segmentCount() != 1)
{
return null;
}
uri = uri.trimFileExtension();
String id = uri.host();
if (id != null)
{
Set<Module> modules = mapMetamodels2CompiledBundlesIds.get(id);
if (modules != null)
{
String name = uri.segment(0);
if (name != null)
{
for (Module m : modules)
{
if (name.equals(m.getName()))
{
return m;
}
}
}
}
}
return null;
}
class DependencyCycleRuntimeException extends RuntimeException
{
private static final long serialVersionUID = 1L;
public DependencyCycleRuntimeException(String message)
{
super(message);
}
}
}