/*
* Chrysalix
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
* See the AUTHORS.txt file in the distribution for a full listing of
* individual contributors.
*
* Chrysalix is free software. Unless otherwise indicated, all code in Chrysalix
* is licensed to you under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Chrysalix is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.modelspace.internal;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.Value;
import org.infinispan.commons.util.ReflectionUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.modelspace.Metamodel;
import org.modelspace.MetamodelManager;
import org.modelspace.Modelspace;
import org.modelspace.ModelspaceException;
import org.modelspace.ModelspaceI18n;
import org.modelspace.ModelspaceLexicon;
import org.modelspace.internal.task.TaskWithResult;
import org.modelspace.internal.task.WriteSystemTask;
import org.modelspace.spi.DependencyProcessor;
import org.modelspace.spi.Exporter;
import org.modelspace.spi.Importer;
import org.modeshape.common.util.CheckArg;
import org.modeshape.jcr.ExtensionLogger;
import org.modeshape.jcr.JcrLexicon;
import org.modeshape.jcr.api.JcrTools;
import org.modeshape.jcr.api.nodetype.NodeTypeManager;
import org.modeshape.jcr.api.sequencer.Sequencer;
/**
* The default implementation of a metamodel modelspace.
*/
final class MetamodelManagerImpl implements MetamodelManager {
static final String MODESHAPE_GROUP = "org/modeshape";
private static final String SEQUENCER_PREFIX = "modeshape-sequencer-";
// pass in category, version, name
private static final String SEQUENCER_PATH_PATTERN = MODESHAPE_GROUP + "/" + SEQUENCER_PREFIX + "%s/%s/%s";
// pass in category, version
private static final String SEQUENCER_ZIP_PATTERN = SEQUENCER_PREFIX + "%s-%s-module-with-dependencies.zip";
private static final String unableToFindMetamodelCategory =
"Unable to find metamodel category '%s' in registered metamodel repositories";
private static final String urlNotFound = "URL not found: %s";
private final MetamodelInstaller metamodelInstaller;
final ModelspaceImpl modelspace;
final LinkedList< URL > metamodelRepositories = new LinkedList<>();
final Set< Metamodel > metamodels = new HashSet<>();
final LibraryClassLoader libraryClassLoader = new LibraryClassLoader();
final Path library;
MetamodelManagerImpl( final ModelspaceImpl modelspace ) throws ModelspaceException {
this.modelspace = modelspace;
this.metamodelInstaller = new MetamodelInstaller();
// setup classpath area for metamodel archives
try {
library = Files.createTempDirectory( null );
} catch ( final IOException e ) {
throw new ModelspaceException( e, "Unable to create temporary folder for library" );
}
library.toFile().deleteOnExit();
// load caches from MS repository
modelspace.run( this, new WriteSystemTask() {
@Override
public void run( final Session session,
final Node systemNode ) throws Exception {
// session.getWorkspace().getObservationManager().addEventListener( new EventListener() {
//
// @Override
// public void onEvent( final EventIterator events ) {
// while ( events.hasNext() )
// // jpav: remove
// System.out.println( "event: " + events.nextEvent() );
// }
// }, Event.ALL_EVENTS, "/jcr:system", true, null, null, false );
loadMetamodelRepositories( session, systemNode );
loadCategories( session, systemNode );
}
} );
}
/**
* @param category
* the category name whose node is being requested (cannot be <code>null</code>)
* @param systemNode
* the system node (cannot be <code>null</code>)
* @param create
* <code>true</code> if the category node should be created if not found
* @return the category node or <code>null</code> if not found
* @throws Exception
* if the categories parent node is not found or if another error occurs
*/
Node categoryNode( final String category,
final Node systemNode,
final boolean create ) throws Exception {
if ( !systemNode.hasNode( ModelspaceLexicon.METAMODEL_CATEGORIES ) )
throw new ModelspaceException( "Expected categories child node of '%s' was not found", systemNode.getPath() );
final Node categoriesNode = systemNode.getNode( ModelspaceLexicon.METAMODEL_CATEGORIES );
Node categoryNode = null;
if ( !categoriesNode.hasNode( category ) ) {
if ( create ) {
categoryNode = categoriesNode.addNode( category, ModelspaceLexicon.Metamodel.Category.NODE_TYPE );
categoryNode.addNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES, ModelspaceLexicon.Metamodel.Category.ARCHIVES );
categoryNode.addNode( ModelspaceLexicon.Metamodel.Category.METAMODELS, ModelspaceLexicon.Metamodel.Category.METAMODELS );
Modelspace.LOGGER.debug( "Created category node '%s'", category );
}
} else {
categoryNode = categoriesNode.getNode( category );
Modelspace.LOGGER.debug( "Found category node '%s'", category );
}
return categoryNode;
}
/**
* @param fileNode
* the file node
* @param metamodels
* the metamodels applicable to the supplied file node
* @return the default metamodel for the supplied file node
* @throws Exception
* if any problem occurs
*/
public Metamodel defaultMetamodel( final Node fileNode,
final Metamodel[] metamodels ) throws Exception {
return metamodels.length == 0 ? null : metamodels[ 0 ];
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#defaultMetamodel(String)
*/
@Override
public Metamodel defaultMetamodel( final String filePath ) throws ModelspaceException {
CheckArg.isNotEmpty( filePath, "filePath" );
return modelspace.run( new TaskWithResult< Metamodel >() {
@Override
public Metamodel run( final Session session ) throws Exception {
final Node node = modelspace.dataNode( session, filePath );
final Metamodel metamodel = defaultMetamodel( node, metamodels( node ) );
return metamodel == null ? null : metamodel;
}
} );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#install(String)
*/
@Override
public void install( final String category ) throws ModelspaceException {
CheckArg.isNotEmpty( category, "category" );
Modelspace.LOGGER.debug( "Installing category '%s'", category );
modelspace.run( this, new WriteSystemTask() {
@Override
public void run( final Session session,
final Node systemNode ) throws Exception {
Modelspace.LOGGER.debug( "Installing importer for category '%s'", category );
installImporter( category, session, systemNode );
Modelspace.LOGGER.debug( "Installing metamodel for category '%s'", category );
installMetamodel( category, session, systemNode );
}
} );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#installableMetamodelCategories()
*/
@Override
public String[] installableMetamodelCategories() throws ModelspaceException {
final Set< String > categories = new HashSet<>();
for ( final URL repositoryUrl : metamodelRepositories ) {
try {
if ( repositoryUrl.getProtocol().startsWith( "file" ) ) {
final String path = ( repositoryUrl.getFile() + File.separatorChar + MODESHAPE_GROUP );
final File folder = new File( path );
final File[] files = folder.listFiles();
if ( files == null ) continue;
for ( final File file : files ) {
final String name = file.getName();
if ( name.contains( "sequencer-" ) )
categories.add( name.substring( name.indexOf( "sequencer-" ) + "sequencer-".length() ) );
}
} else {
final Document doc = Jsoup.connect( path( repositoryUrl.toString(), MODESHAPE_GROUP ) ).get();
final Elements elements = doc.getElementsMatchingOwnText( "sequencer-" );
for ( final Element element : elements ) {
final String href = element.attr( "href" );
categories.add( href.substring( href.indexOf( "sequencer-" ) + "sequencer-".length(),
href.lastIndexOf( '/' ) ) );
}
}
} catch ( final IOException e ) {
throw new ModelspaceException( e, "Unable to install metamodel categories for %s",
path( repositoryUrl.toString(), MODESHAPE_GROUP ) );
}
}
return categories.toArray( new String[ categories.size() ] );
}
void installImporter( final String category,
final Session session,
final Node systemNode ) throws Exception {
// don't install importer if already installed
if ( categoryNode( category, systemNode, false ) != null ) {
return;
}
final Node categoryNode = categoryNode( category, systemNode, true );
final String archiveName = String.format( SEQUENCER_ZIP_PATTERN, category, version() );
final Path archivePath = library.resolve( archiveName );
final String sequencerArchivePath = String.format( SEQUENCER_PATH_PATTERN, category, version(), archiveName );
// loop through repositories until we find the sequencer archive
for ( final URL repositoryUrl : metamodelRepositories ) {
final URL url = new URL( path( repositoryUrl.toString(), sequencerArchivePath ) );
// copy archive over to library if found at this repository
boolean archiveFound = false;
try ( InputStream urlStream = url.openStream() ) {
archiveFound = true;
Files.copy( urlStream, archivePath );
} catch ( final IOException e ) {
if ( archiveFound ) throw e;
continue;
}
try ( final ZipFile archive = new ZipFile( archivePath.toFile() ) ) {
final Collection< String > potentialSequencerClassNames = new ArrayList<>();
final Node archivesNode = categoryNode.getNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES );
for ( final Enumeration< ? extends ZipEntry > archiveIter = archive.entries(); archiveIter.hasMoreElements(); ) {
final ZipEntry archiveEntry = archiveIter.nextElement();
if ( archiveEntry.isDirectory() ) continue;
// see if archive should be ignored
String name = archiveEntry.getName().toLowerCase();
if ( !name.endsWith( ".jar" ) || name.endsWith( "-tests.jar" ) || name.endsWith( "-sources.jar" ) ) {
Modelspace.LOGGER.debug( "Ignoring Jar: %s", name );
continue;
}
// see if this jar has already been installed
final Path jarPath =
library.resolve( archiveEntry.getName().substring( archiveEntry.getName().lastIndexOf( '/' ) + 1 ) );
if ( jarPath.toFile().exists() ) {
Modelspace.LOGGER.debug( "Jar already installed: %s", jarPath );
continue;
}
// copy to library path
try ( final InputStream stream = archive.getInputStream( archiveEntry ) ) {
Files.copy( stream, jarPath );
jarPath.toFile().deleteOnExit();
}
// add to classpath
libraryClassLoader.addURL( jarPath.toUri().toURL() );
// add jar to category node in repository
try ( final InputStream stream = archive.getInputStream( archiveEntry ) ) {
new JcrTools().uploadFile( session,
archivesNode.getPath() + '/' + jarPath.getFileName().toString(),
stream );
}
// Iterate through entries looking for appropriate sequencer classes
if ( jarPath.getFileName().toString().startsWith( SEQUENCER_PREFIX ) )
try ( final ZipFile jar = new ZipFile( jarPath.toFile() ) ) {
for ( final Enumeration< ? extends ZipEntry > jarIter = jar.entries(); jarIter.hasMoreElements(); ) {
final ZipEntry jarEntry = jarIter.nextElement();
if ( jarEntry.isDirectory() ) continue;
name = jarEntry.getName();
// see if class is a possible sequencer
if ( name.endsWith( "Sequencer.class" ) ) {
potentialSequencerClassNames.add( name.replace( '/', '.' ).substring( 0, name.length() - ".class".length() ) );
Modelspace.LOGGER.debug( "Potential sequencer: %s", name );
}
}
}
}
final Node metamodelsNode = categoryNode.getNode( ModelspaceLexicon.Metamodel.Category.METAMODELS );
// try and load each potential sequencer class that was found
for ( final String sequencerClassName : potentialSequencerClassNames ) {
Class< ? > sequencerClass = null;
try {
sequencerClass = libraryClassLoader.loadClass( sequencerClassName );
if ( Sequencer.class.isAssignableFrom( sequencerClass )
&& !Modifier.isAbstract( sequencerClass.getModifiers() ) ) {
String id = Modelspace.class.getPackage().getName() + '.' + category + '.'
+ sequencerClass.getSimpleName();
id = id.endsWith( "Sequencer" ) ? id.substring( 0, id.length() - "Sequencer".length() ) : id;
// add metamodel to MS repository
final Node metamodelNode = metamodelsNode.addNode( id, ModelspaceLexicon.Metamodel.NODE_TYPE );
metamodelNode.setProperty( ModelspaceLexicon.Metamodel.IMPORTER_CLASS_NAME, sequencerClass.getName() );
// add to cache
final MetamodelImpl metamodel = new MetamodelImpl( modelspace, category, id );
metamodel.setImporter( sequencerImporter( session, sequencerClass ) );
metamodels.add( metamodel );
}
} catch ( final NoClassDefFoundError | ClassNotFoundException ignored ) {
Modelspace.LOGGER.debug( "Potential importer class '%s' cannot be loaded", sequencerClass );
}
}
}
archivePath.toFile().delete();
return;
}
throw new IllegalArgumentException( ModelspaceI18n.localize( unableToFindMetamodelCategory, category ) );
}
void installMetamodel( final String category,
final Session session,
final Node systemNode ) throws Exception {
final Node categoryNode = categoryNode( category, systemNode, false );
if ( metamodelInstaller.install( categoryNode,
libraryClassLoader,
library,
metamodelRepositories,
version(),
metamodels ) ) {
Modelspace.LOGGER.debug( "Installed extensions for category '%s'", category );
} else {
Modelspace.LOGGER.debug( "No extensions installed for category '%s'", category );
}
}
void loadCategories( final Session session,
final Node systemNode ) throws Exception {
if ( !systemNode.hasNode( ModelspaceLexicon.METAMODEL_CATEGORIES ) ) {
systemNode.addNode( ModelspaceLexicon.METAMODEL_CATEGORIES );
Modelspace.LOGGER.debug( "'%s' node created", ModelspaceLexicon.METAMODEL_CATEGORIES );
} else {
final Node categoriesNode = systemNode.getNode( ModelspaceLexicon.METAMODEL_CATEGORIES );
for ( final NodeIterator iter = categoriesNode.getNodes(); iter.hasNext(); ) {
final Node categoryNode = iter.nextNode();
loadCategoryArchives( session, categoryNode );
loadMetamodels( session, categoryNode );
}
}
}
void loadCategoryArchives( final Session session,
final Node categoryNode ) throws Exception {
if ( !categoryNode.hasNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES ) ) {
categoryNode.addNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES );
Modelspace.LOGGER.debug( "'%s' node created", ModelspaceLexicon.Metamodel.Category.ARCHIVES );
} else {
final Node archivesNode = categoryNode.getNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES );
for ( final NodeIterator iter = archivesNode.getNodes(); iter.hasNext(); ) {
final Node archiveNode = iter.nextNode();
final Path archivePath = library.resolve( archiveNode.getName() );
final Node contentNode = archiveNode.getNode( JcrLexicon.CONTENT.getString() );
try ( InputStream stream = contentNode.getProperty( JcrLexicon.DATA.getString() ).getBinary().getStream() ) {
Files.copy( stream, archivePath );
}
archivePath.toFile().deleteOnExit();
libraryClassLoader.addURL( archivePath.toUri().toURL() );
Modelspace.LOGGER.debug( "Loaded archive: %s", archivePath );
}
}
}
void loadMetamodelRepositories( final Session session,
final Node systemNode ) throws Exception {
if ( !systemNode.hasProperty( ModelspaceLexicon.METAMODEL_REPOSITORIES ) ) {
final Value[] vals = new Value[ 2 ];
vals[ 0 ] = session.getValueFactory().createValue( JBOSS_METAMODEL_REPOSITORY );
vals[ 1 ] = session.getValueFactory().createValue( MAVEN_METAMODEL_REPOSITORY );
systemNode.setProperty( ModelspaceLexicon.METAMODEL_REPOSITORIES, vals );
}
for ( final String url : JcrUtil.values( systemNode, ModelspaceLexicon.METAMODEL_REPOSITORIES ) ) {
metamodelRepositories.add( new URL( url ) );
}
}
void loadMetamodels( final Session session,
final Node categoryNode ) throws Exception {
if ( !categoryNode.hasNode( ModelspaceLexicon.Metamodel.Category.METAMODELS ) ) {
categoryNode.addNode( ModelspaceLexicon.Metamodel.Category.METAMODELS );
Modelspace.LOGGER.debug( "'%s' node created", ModelspaceLexicon.Metamodel.Category.METAMODELS );
} else {
final Node metamodelsNode = categoryNode.getNode( ModelspaceLexicon.Metamodel.Category.METAMODELS );
final String category = categoryNode.getName();
for ( final NodeIterator iter = metamodelsNode.getNodes(); iter.hasNext(); ) {
final Node metamodelNode = iter.nextNode();
final MetamodelImpl metamodel = new MetamodelImpl( modelspace, category, metamodelNode.getName() );
metamodels.add( metamodel );
if ( metamodelNode.hasProperty( ModelspaceLexicon.Metamodel.IMPORTER_CLASS_NAME ) ) {
final String className = JcrUtil.value( metamodelNode,
ModelspaceLexicon.Metamodel.IMPORTER_CLASS_NAME );
metamodel.setImporter( sequencerImporter( session, libraryClassLoader.loadClass( className ) ) );
}
if ( metamodelNode.hasProperty( ModelspaceLexicon.Metamodel.EXPORTER_CLASS_NAME ) ) {
final String className = JcrUtil.value( metamodelNode,
ModelspaceLexicon.Metamodel.EXPORTER_CLASS_NAME );
metamodel.setExporter( ( Exporter ) libraryClassLoader.loadClass( className ).newInstance() );
}
if ( metamodelNode.hasProperty( ModelspaceLexicon.Metamodel.DEPENDENCY_PROCESSOR_CLASS_NAME ) ) {
final String className = JcrUtil.value( metamodelNode,
ModelspaceLexicon.Metamodel.DEPENDENCY_PROCESSOR_CLASS_NAME );
metamodel.setDependencyProcessor( ( DependencyProcessor ) libraryClassLoader.loadClass( className ).newInstance() );
}
Modelspace.LOGGER.debug( "Loaded metamodel: %s", metamodel.id() );
}
}
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#metamodel(String)
*/
@Override
public Metamodel metamodel( final String id ) {
CheckArg.isNotEmpty( id, "id" );
for ( final Metamodel metamodel : metamodels )
if ( id.equals( metamodel.id() ) ) return metamodel;
return null;
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#metamodelCategories()
*/
@Override
public String[] metamodelCategories() {
final Set< String > categories = new HashSet<>();
for ( final Metamodel metamodel : metamodels )
categories.add( metamodel.category() );
return categories.toArray( new String[ categories.size() ] );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#metamodelRepositories()
*/
@Override
public URL[] metamodelRepositories() {
return metamodelRepositories.toArray( new URL[ metamodelRepositories.size() ] );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#metamodels()
*/
@Override
public Metamodel[] metamodels() {
return metamodels.toArray( new Metamodel[ metamodels.size() ] );
}
/**
* @param fileNode
* the file node
* @return the metamodels applicable to the supplied file node
* @throws Exception
* if any problem occurs
*/
public Metamodel[] metamodels( final Node fileNode ) throws Exception {
final Set< Metamodel > applicableMetamodels = new HashSet<>();
final String mimeType = JcrUtil.value( fileNode.getNode( JcrLexicon.CONTENT.getString() ),
JcrLexicon.MIMETYPE.getString() );
for ( final Metamodel metamodel : metamodels() ) {
if ( ( ( MetamodelImpl ) metamodel ).importer().supports( mimeType ) ) applicableMetamodels.add( metamodel );
}
return applicableMetamodels.toArray( new Metamodel[ applicableMetamodels.size() ] );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#metamodelsForArtifact(String)
*/
@Override
public Metamodel[] metamodelsForArtifact( final String filePath ) throws ModelspaceException {
CheckArg.isNotEmpty( filePath, "filePath" );
return modelspace.run( new TaskWithResult< Metamodel[] >() {
@Override
public final Metamodel[] run( final Session session ) throws Exception {
return metamodels( modelspace.dataNode( session, filePath ) );
}
} );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#metamodelsForCategory(String)
*/
@Override
public Metamodel[] metamodelsForCategory( final String category ) {
CheckArg.isNotEmpty( category, "category" );
final Set< Metamodel > metamodels = new HashSet<>();
for ( final Metamodel metamodel : metamodels )
if ( category.equals( metamodel.category() ) ) metamodels.add( metamodel );
return metamodels.toArray( new Metamodel[ metamodels.size() ] );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#moveMetamodelRepositoryDown(URL)
*/
@Override
public URL[] moveMetamodelRepositoryDown( final URL repositoryUrl ) throws ModelspaceException {
CheckArg.isNotNull( repositoryUrl, "repositoryUrl" );
final int ndx = metamodelRepositories.indexOf( repositoryUrl );
if ( ndx < 0 ) throw new IllegalArgumentException( ModelspaceI18n.localize( urlNotFound, repositoryUrl ) );
metamodelRepositories.remove( ndx );
metamodelRepositories.add( Math.min( ndx + 1, metamodelRepositories.size() ), repositoryUrl );
saveMetamodelRepositories();
return metamodelRepositories();
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#moveMetamodelRepositoryUp(URL)
*/
@Override
public URL[] moveMetamodelRepositoryUp( final URL repositoryUrl ) throws ModelspaceException {
CheckArg.isNotNull( repositoryUrl, "repositoryUrl" );
final int ndx = metamodelRepositories.indexOf( repositoryUrl );
if ( ndx < 0 ) throw new IllegalArgumentException( ModelspaceI18n.localize( urlNotFound, repositoryUrl ) );
metamodelRepositories.remove( ndx );
metamodelRepositories.add( Math.max( ndx - 1, 0 ), repositoryUrl );
saveMetamodelRepositories();
return metamodelRepositories();
}
private String path( final String prefix,
final String suffix ) {
if ( prefix.charAt( prefix.length() - 1 ) == '/' )
return suffix.charAt( 0 ) == '/' ? prefix + suffix.substring( 1 ) : prefix + suffix;
return suffix.charAt( 0 ) == '/' ? prefix + suffix : prefix + '/' + suffix;
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#registerMetamodelRepository(URL)
*/
@Override
public URL[] registerMetamodelRepository( final URL repositoryUrl ) throws ModelspaceException {
CheckArg.isNotNull( repositoryUrl, "repositoryUrl" );
if ( !metamodelRepositories.contains( repositoryUrl ) ) {
metamodelRepositories.addFirst( repositoryUrl );
saveMetamodelRepositories();
}
return metamodelRepositories();
}
private void saveMetamodelRepositories() throws ModelspaceException {
modelspace.run( this, new WriteSystemTask() {
@Override
public void run( final Session session,
final Node systemNode ) throws Exception {
final Value[] vals = new Value[ metamodelRepositories.size() ];
int ndx = 0;
for ( final URL url : metamodelRepositories )
vals[ ndx++ ] = session.getValueFactory().createValue( url.toString() );
systemNode.setProperty( ModelspaceLexicon.METAMODEL_REPOSITORIES, vals );
}
} );
}
Importer sequencerImporter( final Session session,
final Class< ? > sequencerClass ) throws Exception {
final Sequencer sequencer = ( Sequencer ) sequencerClass.newInstance();
ReflectionUtil.setValue( sequencer, "logger", ExtensionLogger.getLogger( sequencerClass ) );
ReflectionUtil.setValue( sequencer, "repositoryName",
session.getRepository().getDescriptor( org.modeshape.jcr.api.Repository.REPOSITORY_NAME ) );
ReflectionUtil.setValue( sequencer, "name", sequencerClass.getSimpleName() );
sequencer.initialize( session.getWorkspace().getNamespaceRegistry(),
( NodeTypeManager ) session.getWorkspace().getNodeTypeManager() );
return new SequencerImporter( sequencer );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#uninstall(String)
*/
@Override
public void uninstall( final String category ) throws ModelspaceException {
CheckArg.isNotEmpty( category, "category" );
// delete from cache all metamodels of that category
boolean deleted = false;
for ( final Iterator< Metamodel > iter = metamodels.iterator(); iter.hasNext(); ) {
final Metamodel metamodel = iter.next();
if ( category.equals( metamodel.category() ) ) {
deleted = true;
iter.remove();
Modelspace.LOGGER.debug( "Uninstalled metamodel '%s'", metamodel.id() );
}
}
if ( !deleted ) throw new ModelspaceException( unableToFindMetamodelCategory, category );
// delete from MS repository
modelspace.run( this, new WriteSystemTask() {
@Override
public void run( final Session session,
final Node systemNode ) throws Exception {
final Node categoryNode = categoryNode( category, systemNode, false );
if ( categoryNode == null ) throw new ModelspaceException( unableToFindMetamodelCategory, category );
// remove category archive paths from classpath
if ( categoryNode.hasNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES ) ) {
final Node archivesNode = categoryNode.getNode( ModelspaceLexicon.Metamodel.Category.ARCHIVES );
for ( final NodeIterator iter = archivesNode.getNodes(); iter.hasNext(); ) {
final Node archiveNode = iter.nextNode();
final Path archivePath = library.resolve( archiveNode.getName() );
if ( !archivePath.toFile().delete() ) Modelspace.LOGGER.debug( "Unable to delete jar: %s", archivePath );
}
}
// remove from MS repo now
categoryNode.remove();
}
} );
}
/**
* {@inheritDoc}
*
* @see MetamodelManager#unregisterMetamodelRepository(URL)
*/
@Override
public URL[] unregisterMetamodelRepository( final URL repositoryUrl ) throws ModelspaceException {
CheckArg.isNotNull( repositoryUrl, "repositoryUrl" );
if ( metamodelRepositories.remove( repositoryUrl ) ) saveMetamodelRepositories();
return metamodelRepositories();
}
private String version() throws ModelspaceException {
return modelspace.repository().getDescriptor( Repository.REP_VERSION_DESC );
}
class LibraryClassLoader extends URLClassLoader {
LibraryClassLoader() {
super( new URL[ 0 ], LibraryClassLoader.class.getClassLoader() );
}
@Override
protected void addURL( final URL url ) {
super.addURL( url );
}
}
}