/*
* Copyright (c) 2002-2009 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.transaction.TransactionManager;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.TransactionFailureException;
import org.neo4j.kernel.impl.nioneo.store.RelationshipTypeData;
import org.neo4j.kernel.impl.persistence.IdGenerator;
import org.neo4j.kernel.impl.persistence.PersistenceManager;
import org.neo4j.kernel.impl.util.ArrayMap;
class RelationshipTypeHolder
{
private ArrayMap<String,Integer> relTypes =
new ArrayMap<String,Integer>( 5, true, true );
private Map<Integer,String> relTranslation =
new ConcurrentHashMap<Integer,String>();
private final TransactionManager transactionManager;
private final PersistenceManager persistenceManager;
private final IdGenerator idGenerator;
RelationshipTypeHolder( TransactionManager transactionManager,
PersistenceManager persistenceManager, IdGenerator idGenerator )
{
this.transactionManager = transactionManager;
this.persistenceManager = persistenceManager;
this.idGenerator = idGenerator;
}
void addRawRelationshipTypes( RelationshipTypeData[] types )
{
for ( int i = 0; i < types.length; i++ )
{
relTypes.put( types[i].getName(), types[i].getId() );
relTranslation.put( types[i].getId(), types[i].getName() );
}
}
void addRawRelationshipType( RelationshipTypeData type )
{
relTypes.put( type.getName(), type.getId() );
relTranslation.put( type.getId(), type.getName() );
}
public RelationshipType addValidRelationshipType( String name,
boolean create )
{
if ( relTypes.get( name ) == null )
{
if ( !create )
{
return null;
}
int id = createRelationshipType( name );
relTranslation.put( id, name );
}
else
{
relTranslation.put( relTypes.get( name ), name );
}
return new RelationshipTypeImpl( name );
}
boolean isValidRelationshipType( RelationshipType type )
{
return relTypes.get( type.name() ) != null;
}
private static class RelationshipTypeImpl implements RelationshipType
{
private String name;
RelationshipTypeImpl( String name )
{
assert name != null;
this.name = name;
}
public String name()
{
return name;
}
public String toString()
{
return name;
}
public boolean equals( Object o )
{
if ( !(o instanceof RelationshipType) )
{
return false;
}
return name.equals( ((RelationshipType) o).name() );
}
public int hashCode()
{
return name.hashCode();
}
}
// TODO: this should be fixed to run in same thread
private class RelTypeCreater extends Thread
{
private boolean success = false;
private String name;
private int id = -1;
RelTypeCreater( String name )
{
super();
this.name = name;
}
synchronized boolean succeded()
{
return success;
}
synchronized int getRelTypeId()
{
return id;
}
public synchronized void run()
{
try
{
transactionManager.begin();
id = idGenerator.nextId( RelationshipType.class );
persistenceManager.createRelationshipType( id, name );
transactionManager.commit();
success = true;
}
catch ( Throwable t )
{
t.printStackTrace();
try
{
transactionManager.rollback();
}
catch ( Throwable tt )
{
tt.printStackTrace();
}
}
finally
{
this.notify();
}
}
}
private synchronized int createRelationshipType( String name )
{
Integer id = relTypes.get( name );
if ( id != null )
{
return id;
}
RelTypeCreater createrThread = new RelTypeCreater( name );
synchronized ( createrThread )
{
createrThread.start();
while ( createrThread.isAlive() )
{
try
{
createrThread.wait( 50 );
}
catch ( InterruptedException e )
{
Thread.interrupted();
}
}
}
if ( createrThread.succeded() )
{
addRelType( name, createrThread.getRelTypeId() );
return createrThread.getRelTypeId();
}
throw new TransactionFailureException(
"Unable to create relationship type " + name );
}
void addRelType( String name, Integer id )
{
relTypes.put( name, id );
}
void removeRelType( String name )
{
relTypes.remove( name );
}
void removeRelType( int id )
{
String name = relTranslation.remove( id );
if ( name != null )
{
relTypes.remove( name );
}
}
int getIdFor( RelationshipType type )
{
return relTypes.get( type.name() );
}
RelationshipType getRelationshipType( int id )
{
String name = relTranslation.get( id );
if ( name != null )
{
return new RelationshipTypeImpl( name );
}
return null;
}
public Iterable<RelationshipType> getRelationshipTypes()
{
List<RelationshipType> relTypeList = new ArrayList<RelationshipType>();
for ( String name : relTypes.keySet() )
{
relTypeList.add( new RelationshipTypeImpl( name ) );
}
return relTypeList;
}
void clear()
{
relTypes = new ArrayMap<String,Integer>();
relTranslation = new HashMap<Integer,String>();
}
}