/*
* 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.index.lucene;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import org.neo4j.kernel.impl.transaction.xaframework.LogBuffer;
import org.neo4j.kernel.impl.transaction.xaframework.XaCommand;
abstract class LuceneCommand extends XaCommand
{
private final Long nodeId;
private final String key;
private final String value;
private static final byte ADD_COMMAND = (byte) 1;
private static final byte REMOVE_COMMAND = (byte) 2;
LuceneCommand( Long nodeId, String key, String value )
{
this.nodeId = nodeId;
this.key = key;
this.value = value;
}
LuceneCommand( CommandData data )
{
this.nodeId = data.nodeId;
this.key = data.key;
this.value = data.value;
}
public Long getNodeId()
{
return nodeId;
}
public String getKey()
{
return key;
}
public String getValue()
{
return value;
}
@Override
public void execute()
{
// TODO Auto-generated method stub
}
@Override
public void writeToFile( LogBuffer buffer ) throws IOException
{
buffer.put( getCommandValue() );
buffer.putLong( getNodeId() != null ? getNodeId() : -1L );
char[] keyChars = getKey().toCharArray();
buffer.putInt( keyChars.length );
char[] valueChars = getValue() != null ?
getValue().toCharArray() : null;
buffer.putInt( valueChars != null ? valueChars.length : -1 );
buffer.put( keyChars );
if ( valueChars != null )
{
buffer.put( valueChars );
}
}
protected abstract byte getCommandValue();
static class AddCommand extends LuceneCommand
{
AddCommand( Long nodeId, String key, String value )
{
super( nodeId, key, value );
}
AddCommand( CommandData data )
{
super( data );
}
@Override
protected byte getCommandValue()
{
return ADD_COMMAND;
}
}
static class RemoveCommand extends LuceneCommand
{
RemoveCommand( Long nodeId, String key, String value )
{
super( nodeId, key, value );
}
RemoveCommand( CommandData data )
{
super( data );
}
@Override
protected byte getCommandValue()
{
return REMOVE_COMMAND;
}
}
private static class CommandData
{
private final Long nodeId;
private final String key;
private final String value;
CommandData( Long nodeId, String key, String value )
{
this.nodeId = nodeId;
this.key = key;
this.value = value;
}
}
static CommandData readCommandData( ReadableByteChannel channel,
ByteBuffer buffer ) throws IOException
{
buffer.clear(); buffer.limit( 16 );
if ( channel.read( buffer ) != buffer.limit() )
{
return null;
}
buffer.flip();
long nodeId = buffer.getLong();
int keyCharLength = buffer.getInt();
int valueCharLength = buffer.getInt();
char[] keyChars = new char[keyCharLength];
keyChars = readCharArray( channel, buffer, keyChars );
if ( keyChars == null )
{
return null;
}
String key = new String( keyChars );
String value = null;
if ( valueCharLength != -1 )
{
char[] valueChars = new char[valueCharLength];
valueChars = readCharArray( channel, buffer, valueChars );
value = new String( valueChars );
}
return new CommandData( nodeId != -1 ? nodeId : null, key, value );
}
private static char[] readCharArray( ReadableByteChannel channel,
ByteBuffer buffer, char[] charArray ) throws IOException
{
buffer.clear();
int charsLeft = charArray.length;
int maxSize = buffer.capacity() / 2;
int offset = 0; // offset in chars
while ( charsLeft > 0 )
{
if ( charsLeft > maxSize )
{
buffer.limit( maxSize * 2 );
charsLeft -= maxSize;
}
else
{
buffer.limit( charsLeft * 2 );
charsLeft = 0;
}
if ( channel.read( buffer ) != buffer.limit() )
{
return null;
}
buffer.flip();
int length = buffer.limit() / 2;
buffer.asCharBuffer().get( charArray, offset, length );
offset += length;
buffer.clear();
}
return charArray;
}
static XaCommand readCommand( ReadableByteChannel channel,
ByteBuffer buffer )
throws IOException
{
buffer.clear(); buffer.limit( 1 );
if ( channel.read( buffer ) != buffer.limit() )
{
return null;
}
buffer.flip();
byte commandType = buffer.get();
CommandData data = readCommandData( channel, buffer );
if ( data == null )
{
return null;
}
switch ( commandType )
{
case ADD_COMMAND: return new AddCommand( data );
case REMOVE_COMMAND: return new RemoveCommand( data );
default: return null;
}
}
}