/**
* Copyright 2007-2008 Konrad-Zuse-Zentrum für Informationstechnik Berlin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.zib.chordsharp;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Vector;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
/**
* Provides means to realise a transaction with the chordsharp ring using Java.
*
* <p>
* It reads the connection parameters from a file called
* {@code ChordSharpConnection.properties} or uses default properties defined in
* {@link ChordSharpConnection#defaultProperties}.
* </p>
*
* <h3>Example:</h3>
* <code style="white-space:pre;">
* OtpErlangString otpKey;
* OtpErlangString otpValue;
* OtpErlangString otpResult;
*
* String key;
* String value;
* String result;
*
* Transaction transaction = new Transaction(); // {@link #Transaction()}
* transaction.start(); // {@link #start()}
*
* transaction.write(otpKey, otpValue); // {@link #write(OtpErlangString, OtpErlangObject)}
* transaction.write(key, value); // {@link #write(String, String)}
*
* otpResult = transaction.readString(otpKey); //{@link #readString(OtpErlangString)}
* result = transaction.readString(key); //{@link #readString(String)}
*
* transaction.commit(); // {@link #commit()}
* </code>
*
* <p>
* For more examples, have a look at {@link de.zib.chordsharp.examples.TransactionReadExample},
* {@link de.zib.chordsharp.examples.TransactionParallelReadsExample},
* {@link de.zib.chordsharp.examples.TransactionWriteExample} and
* {@link de.zib.chordsharp.examples.TransactionReadWriteExample}.
* </p>
*
* <h3>Attention:</h3>
* <p>
* If a read or write operation fails within a transaction all subsequent
* operations on that key will fail as well. This behaviour may particularly be
* undesirable if a read operation just checks whether a value already exists or
* not. To overcome this situation call {@link #revertLastOp()} immediately
* after the failed operation which restores the state as it was before that
* operation.<br />
* The {@link de.zib.chordsharp.examples.TransactionReadWriteExample} example shows such a use case.
* </p>
*
* @author Nico Kruber, kruber@zib.de
* @version 2.0
* @deprecated use {@link de.zib.scalaris.Transaction} instead
*/
@Deprecated
public class Transaction {
/**
* The new {@link de.zib.scalaris.Transaction} object to redirect the tasks
* to.
*/
de.zib.scalaris.Transaction transaction;
/**
* Creates the object's connection to the chordsharp node specified in the
* {@code "ChordSharpConnection.properties"} file.
*
* @throws ConnectionException
* if the connection fails
*/
public Transaction() throws ConnectionException {
try {
transaction = new de.zib.scalaris.Transaction(ChordSharpConnection
.createConnection(ChordSharpConnection.defaultProperties));
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
}
}
/**
* Starts a new transaction by generating a new transaction log.
*
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TransactionNotFinishedException
* if an old transaction is not finished (via {@link #commit()}
* or {@link #abort()}) yet
* @throws UnknownException
* if the returned value from erlang does not have the expected
* type/structure
*/
public void start() throws ConnectionException, TransactionNotFinishedException, UnknownException {
try {
transaction.start();
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
} catch (de.zib.scalaris.UnknownException e) {
throw new UnknownException(e);
} catch (de.zib.scalaris.TransactionNotFinishedException e) {
throw new TransactionNotFinishedException(e);
}
}
/**
* Commits the current transaction. The transaction's log is reset if the
* commit was successful, otherwise it still retains in the transaction
* which must be successfully committed or aborted in order to be restarted.
*
* @throws UnknownException
* If the commit fails or the returned value from erlang is of
* an unknown type/structure, this exception is thrown. Neither
* the transaction log nor the local operations buffer is
* emptied, so that the commit can be tried again.
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @see #abort()
*/
public void commit() throws UnknownException, ConnectionException {
try {
transaction.commit();
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
} catch (de.zib.scalaris.UnknownException e) {
throw new UnknownException(e);
}
}
/**
* Cancels the current transaction.
*/
public void abort() {
transaction.abort();
}
/**
* Gets the value stored under the given {@code key}.
*
* @param key
* the key to look up
* @return the value stored under the given {@code key} as a raw erlang type
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to fetch the value
* @throws NotFoundException
* if the requested key does not exist
* @throws UnknownException
* if any other error occurs
*/
public OtpErlangObject readObject(OtpErlangString key)
throws ConnectionException, TimeoutException, UnknownException,
NotFoundException {
try {
return transaction.readObject(key);
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
} catch (de.zib.scalaris.UnknownException e) {
throw new UnknownException(e);
} catch (de.zib.scalaris.TimeoutException e) {
throw new TimeoutException(e);
} catch (de.zib.scalaris.NotFoundException e) {
throw new NotFoundException(e);
}
}
/**
* Gets the value stored under the given {@code key}.
*
* @param key
* the key to look up
* @return the (string) value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to fetch the value
* @throws NotFoundException
* if the requested key does not exist
* @throws UnknownException
* if any other error occurs
*/
public OtpErlangString readString(OtpErlangString key) throws ConnectionException,
TimeoutException, UnknownException, NotFoundException {
try {
return (OtpErlangString) readObject(key);
} catch (ClassCastException e) {
// e.printStackTrace();
throw new UnknownException(e.getMessage());
}
}
/**
* Gets the value stored under the given {@code key}.
*
* @param key
* the key to look up
* @return the (string) value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to fetch the value
* @throws NotFoundException
* if the requested key does not exist
* @throws UnknownException
* if any other error occurs
*/
public String readString(String key) throws ConnectionException,
TimeoutException, UnknownException, NotFoundException {
try {
return transaction.read(key);
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
} catch (de.zib.scalaris.UnknownException e) {
throw new UnknownException(e);
} catch (de.zib.scalaris.TimeoutException e) {
throw new TimeoutException(e);
} catch (de.zib.scalaris.NotFoundException e) {
throw new NotFoundException(e);
}
}
/**
* Stores the given {@code key}/{@code value} pair.
*
* @param key
* the key to store the value for
* @param value
* the value to store
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to write the value
* @throws UnknownException
* if any other error occurs
*/
public void write(OtpErlangString key, OtpErlangObject value)
throws ConnectionException, TimeoutException, UnknownException {
try {
transaction.writeObject(key, value);
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
} catch (de.zib.scalaris.UnknownException e) {
throw new UnknownException(e);
} catch (de.zib.scalaris.TimeoutException e) {
throw new TimeoutException(e);
}
}
/**
* Stores the given {@code key}/{@code value} pair.
*
* @param key
* the key to store the value for
* @param value
* the value to store
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to write the value
* @throws UnknownException
* if any other error occurs
*/
public void write(String key, String value) throws ConnectionException,
TimeoutException, UnknownException {
try {
transaction.write(key, value);
} catch (de.zib.scalaris.ConnectionException e) {
throw new ConnectionException(e);
} catch (de.zib.scalaris.UnknownException e) {
throw new UnknownException(e);
} catch (de.zib.scalaris.TimeoutException e) {
throw new TimeoutException(e);
}
}
/**
* Reverts the last (read, parallelRead or write) operation by restoring the
* last state. If there was no operation or the last operation was already
* reverted, this method does nothing.
*
* <p>
* This method is especially useful if after an unsuccessful read a value
* with the same key should be written which is not possible if the failed
* read is still in the transaction's log.
* </p>
* <p>
* NOTE: This method works only ONCE! Subsequent calls will do nothing.
* </p>
*/
public void revertLastOp() {
transaction.revertLastOp();
}
/**
* Closes the transaction's connection to a chordsharp node.
*
* Note: Subsequent calls to the other methods will throw
* {@link ConnectionException}s!
*
* @since 2.0
*/
public void closeConnection() {
transaction.closeConnection();
}
// /////////////////////////////
// currently broken / unsupported methods
// /////////////////////////////
/**
* BROKEN: Gets the values stored under the given {@code keys}.
*
* @param keys
* the keys to look up ({@link OtpErlangString} elements in an {@link OtpErlangList})
* @return the values stored under the given {@code key} with the format [{value, Value}]
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws UnknownException
* if any other error occurs
*/
@Deprecated
private OtpErlangList parallelReads1(OtpErlangList keys)
throws ConnectionException, UnknownException {
throw new UnknownException("parallelReads is currently broken");
// if (transLog == null) {
// throw new TransactionNotStartedException("The transaction needs to be started before it is used.");
// }
// try {
// connection.sendRPC("transstore.transaction_api", "jParallel_reads",
// new OtpErlangList(new OtpErlangObject[] {keys, transLog}));
// /*
// * possible return values:
// * - {fail, NewTransLog}
// * - {[{value, Value}], NewTransLog}
// */
// OtpErlangTuple received = (OtpErlangTuple) connection.receiveRPC();
// transLog_old = transLog;
// transLog = (OtpErlangList) received.elementAt(1);
// if (received.elementAt(0).equals(new OtpErlangAtom("fail"))) {
// throw new UnknownException();
// } else {
// OtpErlangList values = (OtpErlangList) received.elementAt(0);
// return values;
// }
// } catch (OtpErlangExit e) {
// // e.printStackTrace();
// throw new ConnectionException(e.getMessage());
// } catch (OtpAuthException e) {
// // e.printStackTrace();
// throw new ConnectionException(e.getMessage());
// } catch (IOException e) {
// // e.printStackTrace();
// throw new ConnectionException(e.getMessage());
// } catch (ClassCastException e) {
// // e.printStackTrace();
// throw new UnknownException(e.getMessage());
// }
}
/**
* BROKEN: Gets the values stored under the given {@code keys}.
*
* @param keys
* the keys to look up ({@link OtpErlangString} elements in an {@link OtpErlangList})
* @return the value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws UnknownException
* if any other error occurs
*/
@Deprecated
public OtpErlangList parallelReads(OtpErlangList keys) throws ConnectionException,
UnknownException {
OtpErlangList result = parallelReads1(new OtpErlangList(keys));
// result value: [{value, Value}]
// convert result list:
OtpErlangString[] erlangValues = new OtpErlangString[result.arity()];
try {
for (int i = 0; i < result.arity(); ++i) {
OtpErlangString value = (OtpErlangString) ((OtpErlangTuple) result.elementAt(i)).elementAt(1);
erlangValues[i] = value;
}
} catch (ClassCastException e) {
// e.printStackTrace();
throw new UnknownException(e.getMessage());
}
return new OtpErlangList(erlangValues);
}
/**
* BROKEN: Gets the values stored under the given {@code keys}.
*
* @param keys
* the keys to look up
* @return the value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws UnknownException
* if any other error occurs
*/
@Deprecated
public Vector<String> parallelReads(String[] keys)
throws ConnectionException, UnknownException {
return parallelReads(new Vector<String>(Arrays.asList(keys)));
}
/**
* BROKEN: Gets the values stored under the given {@code keys}.
*
* @param keys
* the keys to look up
* @return the value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws UnknownException
* if any other error occurs
*/
@Deprecated
public Vector<String> parallelReads(Vector<String> keys) throws ConnectionException,
UnknownException {
// convert keys to an erlang list of erlang strings:
OtpErlangString[] erlangKeys = new OtpErlangString[keys.size()];
int i = 0;
for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
OtpErlangString key = new OtpErlangString(iterator.next());
erlangKeys[i++] = key;
}
OtpErlangList result = parallelReads1(new OtpErlangList(new OtpErlangList(erlangKeys)));
// result value: [{value, Value}]
// convert result list:
Vector<String> values = new Vector<String>(result.arity());
try {
for (i = 0; i < result.arity(); ++i) {
OtpErlangString value = (OtpErlangString) ((OtpErlangTuple) result
.elementAt(i)).elementAt(1);
values.add(value.stringValue());
}
} catch (ClassCastException e) {
// e.printStackTrace();
throw new UnknownException(e.getMessage());
}
return values;
}
// /////////////////////////////
// deprecated methods
// /////////////////////////////
/**
* Gets the value stored under the given {@code key}.
*
* @param key
* the key to look up
* @return the value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to fetch the value
* @throws NotFoundException
* if the requested key does not exist
* @throws UnknownException
* if any other error occurs
*/
@Deprecated
public OtpErlangString read(OtpErlangString key)
throws ConnectionException, TimeoutException, UnknownException,
NotFoundException {
return readString(key);
}
/**
* Gets the value stored under the given {@code key}.
*
* @param key
* the key to look up
* @return the value stored under the given {@code key}
* @throws ConnectionException
* if the connection is not active or a communication error
* occurs or an exit signal was received or the remote node
* sends a message containing an invalid cookie
* @throws TimeoutException
* if a timeout occurred while trying to fetch the value
* @throws NotFoundException
* if the requested key does not exist
* @throws UnknownException
* if any other error occurs
*/
@Deprecated
public String read(String key) throws ConnectionException,
TimeoutException, UnknownException, NotFoundException {
return read(new OtpErlangString(key)).stringValue();
}
}