blob: 3a8112df22d766c25fb80e0a1be5f6b1f850550d [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2010 Atos Origin.
*
*
* 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:
* Caroline Bourdeu d'Aguerre (Atos Origin) caroline.bourdeudaguerre@atosorigin.com - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.gendoc.tags.handlers.impl.context;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.gendoc.services.AbstractService;
import org.eclipse.gendoc.services.exception.ElementNotFoundException;
import org.eclipse.gendoc.services.exception.ModelNotFoundException;
import org.eclipse.gendoc.tags.handlers.IEMFModelLoaderService;
/**
* Description of the class EMFModelLoader.
*
*/
public class EMFModelLoaderService extends AbstractService implements IEMFModelLoaderService
{
private static final String SEPARATOR = "/";
private final Pattern patternForIndex = Pattern.compile("\\{(\\d*)\\}");
private final Pattern patternForAttribut = Pattern.compile("(.*)=\"(.*)\"");
protected ResourceSet resourceSet;
private List<URI> paths;
private boolean isRootVirtual = false;
/**
* Constructor.
*/
public EMFModelLoaderService()
{
super();
}
protected ResourceSet constructResourceSet ()
{
return new ResourceSetImpl();
}
protected Resource getResource (URI uri)
{
return getResourceSet().getResource(uri, true);
}
protected ResourceSet getResourceSet ()
{
if( resourceSet == null){
resourceSet = constructResourceSet();
}
return resourceSet;
}
/**
* Load the model from the given path
*
* @param the model path (uri)
* @return the model
*/
public EObject getModel(URI path) throws ModelNotFoundException
{
checkPath(path);
if( paths == null){
paths = new LinkedList<URI>();
}
EObject model = null;
try
{
// Load model
final Resource resource = getResource(path);
if (!paths.contains(path))
{
paths.add(path);
resolve(resource);
}
switch (resource.getContents().size())
{
case 0:
throw new ModelNotFoundException("Model can not be loaded from URL: \"" + path.toString() + "\"");
case 1:
isRootVirtual = false;
model = resource.getContents().get(0);
break;
default:
// create root object
isRootVirtual = true;
model = new EObject()
{
public TreeIterator<EObject> eAllContents() {
return null;
}
public EClass eClass() {
return null;
}
public EObject eContainer() {
return null;
}
public EStructuralFeature eContainingFeature() {
return null;
}
public EReference eContainmentFeature() {
return null;
}
public EList<EObject> eContents() {
return resource.getContents();
}
public EList<EObject> eCrossReferences() {
return null;
}
public Object eGet(EStructuralFeature arg0) {
return null;
}
public Object eGet(EStructuralFeature arg0, boolean arg1) {
return null;
}
public boolean eIsProxy() {
return false;
}
public boolean eIsSet(EStructuralFeature arg0) {
return false;
}
public Resource eResource() {
return resource;
}
public void eSet(EStructuralFeature arg0, Object arg1) {
}
public void eUnset(EStructuralFeature arg0) {
}
public EList<Adapter> eAdapters() {
return null;
}
public boolean eDeliver() {
return false;
}
public void eNotify(Notification arg0) {
}
public void eSetDeliver(boolean arg0) {
}
public Object eInvoke(EOperation arg0, EList<?> arg1)
throws InvocationTargetException {
return null;
}
};
}
}
catch (RuntimeException e)
{
throw new ModelNotFoundException("Model can not be loaded from URL: \"" + path.toString() + "\"");
}
return model;
}
/**
* Method resolving the resource
* @param resource
*/
protected void resolve(final Resource resource)
{
getResourceSet().eSetDeliver(false);
EcoreUtil.resolveAll(resource);
getResourceSet().eSetDeliver(true);
}
/**
* Preconfition of get Model, override this method if you are using templates without input
* @param path
* @throws ModelNotFoundException
*/
protected void checkPath(URI path) throws ModelNotFoundException
{
if (path == null)
{
throw new ModelNotFoundException("No path provided");
}
}
/**
* Return the element corresponding to the path in the model
*
* @param elementPath
* @param model
* @param i : must be > 0
* @param structuralObject
* @return the current element
* @throws ElementNotFoundException
*/
public EObject getCurrentElement(String elementPath, EObject model, int i, String attribute) throws ElementNotFoundException
{
// Check parameters
if (i < 1)
{
throw new IllegalArgumentException("i must be higher than zero");
}
// if there is no element, root is return
if (i == 1 && (elementPath == null || elementPath.length() == 0))
{
return model;
}
String[] splitAttribute = new String[0];
// Split the path
if (elementPath != null)
{
splitAttribute = elementPath.split(SEPARATOR);
}
if (!isRootVirtual)
{
// If the element to search is the root
if (i == 1 && (splitAttribute.length == 1 && (isEquals(model, attribute, elementPath) || getIndex(elementPath) == 0)))
{
return model;
}
if (i >= splitAttribute.length)
{
throw new IllegalArgumentException("i must be lower than length of segments");
}
}
String toSearch = isRootVirtual ? splitAttribute[i-1] : splitAttribute[i];
String trim = toSearch.trim();
EObject object = null;
// Get an eventual index
int index = getIndex(trim);
// Get the current element
if (index >= 0 && !model.eContents().isEmpty())
{
object = model.eContents().get(index);
}
else
{
for (EObject tmp : model.eContents())
{
if (isEquals(tmp, attribute, toSearch))
{
object = tmp;
break;
}
}
}
// Get the next element
if (object != null)
{
int splitAttributeLength = isRootVirtual ? splitAttribute.length : splitAttribute.length -1;
if (i != splitAttributeLength)
{
return getCurrentElement(elementPath, object, i + 1, attribute);
}
else if (i == splitAttributeLength)
{
return object;
}
}
throw new ElementNotFoundException(elementPath, model.eResource().getURI().toString());
}
/**
* Test if the value of the structural feature of the Object tmp corresponding to attribute is equals to toSearch
*
* @param tmp
* @param attribute
* @param toSearch
* @return true if there are equals else false
*/
public boolean isEquals(EObject tmp, String attribute, String toSearch)
{
String featureName = attribute;
String featureValue = toSearch;
// Check if the element is complex (featureId = 'value')
Matcher m = patternForAttribut.matcher(toSearch);
if (m.matches())
{
if (m.groupCount() == 2)
{
featureName = m.group(1);
featureValue = m.group(2);
}
}
// Get the feature value of the eObject
String content = getEStructuralFeature(tmp, featureName);
return content != null && content.equals(featureValue);
}
/**
* If the element match the pattern {\[\d*\]} return the index [0-9]*
*
* @param element to match
* @return the index found else -1
*/
protected int getIndex(String element)
{
Matcher m = patternForIndex.matcher(element);
if (m.matches())
{
if (m.groupCount() == 1)
{
String group = m.group(1);
try
{
int result = Integer.valueOf(group);
return result;
}
catch (NumberFormatException e)
{
// regex checks if it is a decimal
}
}
}
return -1;
}
/**
* Gets the estructural feature
*
* @param e the specified eObject
* @param attribute the structural feature name to search
*
* @return the estructural feature that match the attribute
*/
protected String getEStructuralFeature(EObject e, String attribute)
{
if (e != null && attribute != null)
{
EList<EStructuralFeature> all = e.eClass().getEAllStructuralFeatures();
for (EStructuralFeature f : all)
{
if (f.getName().equalsIgnoreCase(attribute))
{
Object content = e.eGet(f);
if (content instanceof String)
{
return (String) content;
}
}
}
}
return null;
}
public void clear()
{
// Unload models
EList<Resource> resources = getResourceSet().getResources();
for (int i = 0 ; i < resources.size() ; i++)
{
Resource r = resources.get(i);
try
{
r.unload();
}
catch (Exception e)
{
// Sometimes the unload does not work,
// and throw an exception
}
}
if( paths != null){
paths.clear();
}
}
}