package org.csc.phynixx.tutorial;
/*
* #%L
* phynixx-common
* %%
* Copyright (C) 2014 csc
* %%
* 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.
* #L%
*/
import org.csc.phynixx.common.exceptions.DelegatedRuntimeException;
import org.csc.phynixx.common.io.LogRecordReader;
import org.csc.phynixx.common.io.LogRecordWriter;
import org.csc.phynixx.connection.RequiresTransaction;
import org.csc.phynixx.loggersystem.logrecord.IDataRecord;
import org.csc.phynixx.loggersystem.logrecord.IDataRecordReplay;
import org.csc.phynixx.loggersystem.logrecord.IXADataRecorder;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
/**
* Basisklasse zur Verwaltung von Filezugriffen.
* A RandomAccessFile provides random access to the file's content.
*/
public class TAEnabledUTFWriterImpl implements TAEnabledUTFWriter {
private transient String lockToken;
/**
* Das RandomAccessFile, dass zum Schreiben u. Lesen geoeffnet wird.
*/
private UTFWriter utfWriter = null;
private IXADataRecorder xaDataRecorder;
private boolean autoCommit=false;
private transient long rollbackPosition;
private final String connectionId;
public TAEnabledUTFWriterImpl(String connectionId, UTFWriter writer) throws Exception {
this.connectionId = connectionId;
this.utfWriter= writer;
init();
}
/**
* locks the sharedFile and inits the rollback pointer
*/
private void init() throws Exception{
// try to lock the writer
this.lockToken= this.getUTFWriter().lock();
this.rollbackPosition= this.getUTFWriter().size();
}
public String getConnectionId() {
return connectionId;
}
public boolean isAutoCommit() {
return autoCommit;
}
public void setAutoCommit(boolean autoCommit) {
this.autoCommit = autoCommit;
}
/**
* Schliesst die Datei und den FileChannel
*/
public void close() {
if(lockToken!=null) {
this.getUTFWriter().unlock(this.lockToken);
this.lockToken=null;
}
}
/**
* zeigt an, ob die Instanz geschlossen ist
*
* @return true wenn die Datei geschlossen ist
*/
public boolean isClosed() {
return (this.utfWriter == null);
}
@Override
@RequiresTransaction
public void resetContent() throws IOException {
if (this.isClosed()) {
throw new IllegalStateException("Writer is closed");
}
this.getUTFWriter().resetContent();
this.rollbackPosition = 0;
if (this.getXADataRecorder() != null) {
LogRecordWriter logRecordWriter = new LogRecordWriter().writeLong(position());
this.getXADataRecorder().writeRollbackData(logRecordWriter.toByteArray());
}
}
@Override
@RequiresTransaction
public TAEnabledUTFWriter write(String value) throws IOException {
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
this.getUTFWriter().write(value);
return this;
}
@Override
public List<String> readContent() throws IOException {
return this.getUTFWriter().readContent();
}
UTFWriter getUTFWriter() {
if (this.isClosed()) {
throw new IllegalStateException("RandomAccessFile is close");
}
return utfWriter;
}
/**
* bereitet die Writer zur Wiederverwendung vor
*/
@Override
public void reset() {
try {
this.close();
this.init();
} catch (Exception e) {
throw new DelegatedRuntimeException(e);
}
}
@Override
public void commit() {
try {
LogRecordWriter logRecordWriter = new LogRecordWriter().writeLong(position());
this.getXADataRecorder().writeRollforwardData(logRecordWriter.toByteArray());
} catch (Exception e) {
throw new DelegatedRuntimeException(e);
}
}
private long position() throws IOException {
return this.utfWriter.position();
}
@Override
public void rollback() {
try {
this.getUTFWriter().restoreSize(this.rollbackPosition);
} catch (IOException e) {
throw new DelegatedRuntimeException(e);
}
}
/**
* definiert den gueltigen Zustand nach commit
*/
@Override
public void prepare() {
}
@Override
public String toString() {
return "TAEnabledUTFWriterImpl{" +
"connectionId='" + connectionId + '\'' +
'}';
}
/**
* @param xaDataRecorder
*/
@Override
public void setXADataRecorder(IXADataRecorder xaDataRecorder) {
this.xaDataRecorder = xaDataRecorder;
}
@Override
public IXADataRecorder getXADataRecorder() {
return xaDataRecorder;
}
private class DataRecordReplay implements IDataRecordReplay {
@Override
public void notifyNoMoreData() {
}
@Override
public void replayRollback(IDataRecord record) {
LogRecordReader logRecordReader = new LogRecordReader(record.getData()[0]);
try {
String fileName= logRecordReader.readUTF();
long filePosition=logRecordReader.readLong();
TAEnabledUTFWriterImpl.this.getUTFWriter().restoreSize(filePosition);
TAEnabledUTFWriterImpl.this.rollbackPosition= filePosition;
} catch (IOException e) {
throw new DelegatedRuntimeException(e);
}
}
@Override
public void replayRollforward(IDataRecord record) {
}
}
@Override
public IDataRecordReplay recoverReplayListener() {
return new DataRecordReplay();
}
}