Commit 1f9289eb authored by Dominique Marcadet's avatar Dominique Marcadet

Merge branch '19-redesign-resource-resourceset-use' into 'master'

Resolve "redesign Resource / ResourceSet use"

Closes #19

See merge request RiseClipseGroup/RiseClipseMain!20
parents 63a15582 0f32bdf4
......@@ -98,6 +98,16 @@
</appinfo>
</annotation>
</attribute>
<attribute name="resourceSetFactory" type="string">
<annotation>
<documentation>
</documentation>
<appinfo>
<meta.attribute kind="java" basedOn="fr.centralesupelec.edf.riseclipse.util.RiseClipseResourceSetFactory:"/>
</appinfo>
</annotation>
</attribute>
</complexType>
</element>
......@@ -158,7 +168,6 @@
aurelie.dehouck-neveu@edf.fr
Web site:
http://wdi.supelec.fr/software/RiseClipse/
</documentation>
</annotation>
......
......@@ -18,10 +18,38 @@
*/
package fr.centralesupelec.edf.riseclipse.util;
public interface IRiseClipseResource {
import org.eclipse.emf.ecore.resource.Resource;
void printStatistics( IRiseClipseConsole console );
/**
* Interface which must be implemented by all Resource of RiseClipse conforming metamodels.
* It specifies minimal needed services.
* Those are defined as default methods so that implementation is not needed.
*
* @author Dominique Marcadet
*
*/
public interface IRiseClipseResource extends Resource {
/**
* Display on given console information about content of this resource.
* Standard information should be displayed at the INFO_LEVEL.
* More detailed information can be displayed at the VERBOSE_LEVEL
*
* @param console the IRiseClipseConsole to use for display
*/
default void printStatistics( IRiseClipseConsole console ) {
// Nothing
}
void finalizeLoad( boolean ignore_unresolved_reference );
/**
* Execute any needed action after the model is loaded in the resource but before
* it is displayed or used.
*
* @param console the IRiseClipseConsole to use for displaying any message
* when running this method
*/
default void finalizeLoad( IRiseClipseConsole console ) {
// Nothing
}
}
/**
* Copyright (c) 2018 CentraleSupélec & EDF.
* 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
*
* This file is part of the RiseClipse tool
*
* Contributors:
* Computer Science Department, CentraleSupélec
* EDF R&D
* Contacts:
* dominique.marcadet@centralesupelec.fr
* aurelie.dehouck-neveu@edf.fr
* Web site:
* http://wdi.supelec.fr/software/RiseClipse/
*/
package fr.centralesupelec.edf.riseclipse.util;
import org.eclipse.emf.ecore.resource.ResourceSet;
/**
* Interface which must be implemented by all ResourceSet of RiseClipse conforming metamodels.
* It specifies minimal needed services.
* Those are defined as default methods so that implementation is not needed.
*
* @author Dominique Marcadet
*
*/
public interface IRiseClipseResourceSet extends ResourceSet {
/**
* Display on given console information about content of this resourceSet.
* Standard information should be displayed at the INFO_LEVEL.
* More detailed information can be displayed at the VERBOSE_LEVEL
*
* @param console the IRiseClipseConsole to use for display
*/
default void printStatistics( IRiseClipseConsole console ) {
// Nothing
}
/**
* Execute any needed action after the model is loaded in the resourcesnof
* this resourceSet but before it is displayed or used.
*
* @param console the IRiseClipseConsole to use for displaying any message
* when running this method
*/
default void finalizeLoad( IRiseClipseConsole console ) {
// Nothing
}
}
......@@ -27,8 +27,6 @@ import java.util.zip.ZipInputStream;
import org.eclipse.emf.common.util.URI;
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.xmi.IllegalValueException;
import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole;
......@@ -36,7 +34,7 @@ import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole;
public abstract class RiseClipseModelLoader {
protected ResourceSet resourceSet;
protected IRiseClipseResourceSet resourceSet;
protected IRiseClipseConsole console;
protected RiseClipseModelLoader( IRiseClipseConsole console ) {
......@@ -46,14 +44,14 @@ public abstract class RiseClipseModelLoader {
}
public void reset() {
this.resourceSet = new ResourceSetImpl();
this.resourceSet = new RiseClipseResourceSet( true, console );
}
public void reset( ResourceSet resourceSet ) {
public void reset( IRiseClipseResourceSet resourceSet ) {
this.resourceSet = resourceSet;
}
public ResourceSet getResourceSet() {
public IRiseClipseResourceSet getResourceSet() {
return resourceSet;
}
......@@ -137,10 +135,7 @@ public abstract class RiseClipseModelLoader {
}
public void finalizeLoad() {
for ( Resource resource : resourceSet.getResources() ) {
// we do not ignore unresolved references
(( IRiseClipseResource ) resource ).finalizeLoad( false );
}
resourceSet.finalizeLoad( console );
}
}
......@@ -18,123 +18,106 @@
*/
package fr.centralesupelec.edf.riseclipse.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.Resource.Factory;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class RiseClipseResourceSet extends ResourceSetImpl {
private static final String XMLNS_ATTRIBUTE_NAME = "xmlns";
private HashMap< String, Factory > resourceFactories;
/**
* Minimal implementation of ResourceSet for RiseClipse conforming metamodels.
* It checks that only IRiseClipseResource are used, and give access to
* contained resources as IRiseClipseResource
*
* @author Dominique Marcadet
*
*/
public class RiseClipseResourceSet extends ResourceSetImpl implements IRiseClipseResourceSet {
protected IRiseClipseConsole console;
// If true, only IRiseClipseResource can be added
protected boolean strictContent;
private ResourceFactoryFinder factoryFinder;
// When the resourceSet will load several resources at once, it is
// useless to call finalizeLoad() after each one. Indeed, such a call
// can lead to wrong error messages.
// As the resourceSet do not know when the last resource is loaded,
// it is the client that must call finalizeLoad() in this case.
//
// When a resource is added to an existing resourceSet, the client
// may not have an easy way to call finalizeLoad() after (the "load
// resource" command in RiseClipse editor use directly the editing
// domain). If set, this boolean will then call finalizeLoad() after
// a getResource().
private boolean callFinalizeLoadAfterGetResource;
public RiseClipseResourceSet( HashMap< String, Resource.Factory > resourceFactories ) {
this.resourceFactories = resourceFactories;
this.factoryFinder = new ResourceFactoryFinder();
public RiseClipseResourceSet( boolean strictContent, IRiseClipseConsole console ) {
this.console = console;
this.strictContent = strictContent;
this.callFinalizeLoadAfterGetResource = false;
}
// TODO: is unset needed ?
public void setCallFinalizeLoadAfterGetResource() {
callFinalizeLoadAfterGetResource = true;
}
@Override
public Resource createResource( URI uri, String contentType ) {
Resource.Factory f = this.factoryFinder.findFactoryFor( uri );
// If we don't find any factory registered as RiseClipse metamodel, use the
// standard mechanism. This is at least needed for OCL documents
if( f != null ) {
Resource result = f.createResource( uri );
getResources().add( result );
return result;
public void printStatistics( IRiseClipseConsole console ) {
for( IRiseClipseResource r : getRiseClipseResources() ) {
r.printStatistics( console );
}
return super.createResource( uri, contentType );
}
@SuppressWarnings( "serial" )
private static class FactoryFoundException extends SAXException {
private Resource.Factory factory;
public FactoryFoundException( Resource.Factory factory ) {
this.factory = factory;
}
public Resource.Factory getFactory() {
return factory;
@Override
public void finalizeLoad( IRiseClipseConsole console ) {
for( IRiseClipseResource r : getRiseClipseResources() ) {
r.finalizeLoad( console );
}
}
protected class ResourceFactoryFinder {
private SAXParser saxParser;
public EList< IRiseClipseResource > getRiseClipseResources() {
// The list is copied, but it is expected that the number of resources is low,
// so this should not be a problem.
EList< IRiseClipseResource > res = new BasicEList<>();
for( Resource r : super.getResources() ) {
if( r instanceof IRiseClipseResource ) {
res.add(( IRiseClipseResource ) r );
}
}
return res;
}
public ResourceFactoryFinder() {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
try {
saxParser = saxParserFactory.newSAXParser();
}
catch( ParserConfigurationException e ) {
throw new RiseClipseRuntimeException( "RiseClipseResourceSet.ResourceFactoryFinder", e );
}
catch( SAXException e ) {
throw new RiseClipseRuntimeException( "RiseClipseResourceSet.ResourceFactoryFinder", e );
}
/* (non-Javadoc)
* @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#getResource(org.eclipse.emf.common.util.URI, boolean)
*/
@Override
public Resource getResource( URI uri, boolean loadOnDemand ) {
Resource res = super.getResource( uri, loadOnDemand );
// createResource has been called before, so check is useless
// if(( res != null ) && strictContent && ( ! ( res instanceof IRiseClipseResource ))) {
// throw new RiseClipseFatalException( "RiseClipseResourceSet.getResource(): not an IRiseClipseResource", null );
// }
if( callFinalizeLoadAfterGetResource && ( res instanceof IRiseClipseResource )) {
finalizeLoad( console );
}
return res;
}
public Resource.Factory findFactoryFor( URI uri ) {
DefaultHandler defaultHandler = new DefaultHandler() {
public void startElement( String uri, String localName, String qName, Attributes attributes )
throws SAXException {
for( int i = 0; i < attributes.getLength(); ++i ) {
String furi = attributes.getURI( i );
if( furi.length() == 0 ) {
furi = attributes.getQName( i );
int dc = furi.indexOf( ':' );
if( dc != -1 ) {
furi = furi.substring( 0, dc );
}
}
if( XMLNS_ATTRIBUTE_NAME.equals( furi ) ) {
String ns = attributes.getValue( i );
if( RiseClipseResourceSet.this.resourceFactories.containsKey( ns )) {
Resource.Factory factory = RiseClipseResourceSet.this.resourceFactories.get( ns );
// Stop parsing and give back result
throw new FactoryFoundException( factory );
}
}
}
}
};
try {
URIConverter uriConverter = getURIConverter();
InputStream inputStream = uriConverter.createInputStream( uri );
saxParser.parse( inputStream, defaultHandler );
}
catch( FactoryFoundException e ) {
return e.getFactory();
}
catch( SAXException e ) {
// Not an xml file or any other error : we will use the standard mechanism
return null;
}
catch( IOException e ) {
// Not an xml file or any other error : we will use the standard mechanism
return null;
}
return null;
/* (non-Javadoc)
* @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#createResource(org.eclipse.emf.common.util.URI, java.lang.String)
*/
@Override
public Resource createResource( URI uri, String contentType ) {
Resource res = super.createResource( uri, contentType );
if(( res != null ) && strictContent && ( ! ( res instanceof IRiseClipseResource ))) {
throw new RiseClipseFatalException( "RiseClipseResourceSet.getResource(): not an IRiseClipseResource", null );
}
return res;
}
}
/**
* Copyright (c) 2019 CentraleSupélec & EDF.
* 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
*
* This file is part of the RiseClipse tool
*
* Contributors:
* Computer Science Department, CentraleSupélec
* EDF R&D
* Contacts:
* dominique.marcadet@centralesupelec.fr
* aurelie.dehouck-neveu@edf.fr
* Web site:
* http://wdi.supelec.fr/software/RiseClipse/
*/
package fr.centralesupelec.edf.riseclipse.util;
public class RiseClipseResourceSetFactory {
public IRiseClipseResourceSet createResourceSet( boolean strictContent, IRiseClipseConsole console ) {
return new RiseClipseResourceSet( strictContent, console );
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment