package org.neo4j.meta.model; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; /** * Represents a namespace in the meta model structure. A namespace is useful * when there would be conflicting names of properties or classes. */ public class MetaModelNamespace extends MetaModelObject { private Map<String, MetaModelClass> classCache = Collections.synchronizedMap( new HashMap<String, MetaModelClass>() ); private Map<String, MetaModelProperty> propertyCache = Collections.synchronizedMap( new HashMap<String, MetaModelProperty>() ); private Map<String, MetaModelRelationship> relationshipTypeCache = Collections.synchronizedMap( new HashMap<String, MetaModelRelationship>() ); /** * @param model the {@link MetaModel} instance. * @param node the {@link Node} to wrap. */ public MetaModelNamespace( MetaModel model, Node node ) { super( model, node ); } /** * Returns (and optionally creates) a {@link MetaModelClass} instance (with * underlying {@link Node}). * * @param name the name of the class. * @param allowCreate if {@code true} and no class by the given {@code name} * exists then it is created. * @return the {@link MetaModelClass} in this namespace with the given * {@code name}. */ public MetaModelClass getMetaClass( String name, boolean allowCreate ) throws DuplicateNameException { return ( (MetaModelImpl) model() ).findOrCreateInCollection( getMetaClasses(), name, allowCreate, MetaModelClass.class, classCache ); } /** * @return a modifiable collection of all {@link MetaModelClass} instances * for this namespace. */ public Collection<MetaModelClass> getMetaClasses() { return new ObjectCollection<MetaModelClass>( node(), MetaModelRelTypes.META_CLASS, Direction.OUTGOING, model(), MetaModelClass.class ); } /** * Returns (and optionally creates) a {@link MetaModelProperty} instance * (with underlying {@link Node}). * * @param name the name of the property. * @param allowCreate if {@code true} and no property by the given {@code * name} exists then it is created. * @return the {@link MetaModelProperty} in this namespace with the given * {@code name}. */ public MetaModelProperty getMetaProperty( String name, boolean allowCreate ) throws DuplicateNameException { return ( (MetaModelImpl) model() ).findOrCreateInCollection( getMetaProperties(), name, allowCreate, MetaModelProperty.class, propertyCache ); } /** * Returns (and optionally creates) a {@link MetaModelRelationship} instance * (with underlying {@link Node}). * * @param name the name of the property. * @param allowCreate if {@code true} and no property by the given {@code * name} exists then it is created. * @return the {@link MetaModelRelationship} in this namespace with the * given {@code name}. */ public MetaModelRelationship getMetaRelationship( String name, boolean allowCreate ) throws DuplicateNameException { return ( (MetaModelImpl) model() ).findOrCreateInCollection( getMetaRelationships(), name, allowCreate, MetaModelRelationship.class, relationshipTypeCache ); } /** * Renames an instance of a {@link MetaModelObject} * * @param oldName the current name of the meta model object. * @param newName the new name for the meta model object. */ public void rename( String oldName, String newName ) { Node metaObjectNode = indexService().getSingleNode( KEY_NAME, oldName ); if ( metaObjectNode == null ) throw new RuntimeException( "Attempt to rename non-existing meta object" ); else { if ( indexService().getSingleNode( KEY_NAME, newName ) != null ) throw new RuntimeException( "Attempt to rename meta object to an existing name" ); else { metaObjectNode.setProperty( KEY_NAME, newName ); indexService().removeIndex( metaObjectNode, KEY_NAME ); indexService().index( metaObjectNode, KEY_NAME, newName ); classCache.remove( oldName ); classCache.put( newName, new MetaModelClass( model(), metaObjectNode ) ); } } } /** * Removes a {@link MetaModelObject} * * @param name the name of the meta model object. * @param forced if {@code true} meta model object will be removed including * all its {@link Relationship}s If (@code false) an exception * will be thrown when the meta model object has * {@link Relationship}s */ public void remove( String name, Boolean forced ) { Node metaObjectNode = indexService().getSingleNode( KEY_NAME, name ); if ( forced ) { classCache.remove( name ); for ( Relationship rel : metaObjectNode.getRelationships() ) { rel.delete(); } for ( String key : metaObjectNode.getPropertyKeys() ) { metaObjectNode.removeProperty( key ); } metaObjectNode.delete(); } else { if ( metaObjectNode.hasRelationship() ) { throw new RuntimeException( "Meta object cannot be removed, it has relationships with other meta objects" ); } else { classCache.remove( name ); for ( String key : metaObjectNode.getPropertyKeys() ) { metaObjectNode.removeProperty( key ); } metaObjectNode.delete(); } } } /** * @return a modifiable collection of all {@link MetaModelProperty} * instances for this namespace. */ public Collection<MetaModelProperty> getMetaProperties() { return new ObjectCollection<MetaModelProperty>( node(), MetaModelRelTypes.META_PROPERTY, Direction.OUTGOING, model(), MetaModelProperty.class ); } /** * @return a modifiable collection of all {@link MetaModelRelationship} * instances for this namespace. */ public Collection<MetaModelRelationship> getMetaRelationships() { return new ObjectCollection<MetaModelRelationship>( node(), MetaModelRelTypes.META_RELATIONSHIP, Direction.OUTGOING, model(), MetaModelRelationship.class ); } @Override public String toString() { String name = (String) node().getProperty( KEY_NAME, "GLOBAL" ); return getClass().getSimpleName() + "[" + name + "]"; } }