package server.storage;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Arrays;
import java.util.List;
import javax.swing.Timer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import rmi.NamingService;
import rmi.StorageService;
import rmi.StorageServiceImpl;
import server.Machine;
import server.Server;
import util.Variables;
import datastructure.FileUnit;
import datastructure.SynchroMeta;
public class StorageServer implements Server {
private static final Logger logger = LogManager.getLogger(StorageServer.class);
private static final String FILE_STORE_PATH = Variables.getInstance().getProperty("myRoot");// "storage";
// private static final String STORAGE_SERVER_NUMBER = "3";
private static StorageServer INSTANCE = null;
public static StorageServer getInstance() {
if ( INSTANCE == null ) INSTANCE = new StorageServer();
return INSTANCE;
}
private StorageServer() {
namingServer = new Machine("namingServer");
me = new Machine("my");
// me = new Machine("storageServer"+STORAGE_SERVER_NUMBER);
fileStoreRootDir = FILE_STORE_PATH; //+ "/" + STORAGE_SERVER_NUMBER;
File storeDir = new File(FILE_STORE_PATH);
if (!storeDir.exists()) {
storeDir.mkdir();
}
File thisServerDir = new File(fileStoreRootDir);
if (!thisServerDir.exists()) {
thisServerDir.mkdir();
}
Machine namingServer = new Machine("namingServer");
try {
namingService = (NamingService) Naming.lookup(namingServer.getAddress(NamingService.class.getName()));
} catch (Exception e) {
e.printStackTrace();
}
FileUnit localRoot = generateDirTree(thisServerDir);
List<SynchroMeta> changeMetas = null;
try {
changeMetas = namingService.informOnline(me, localRoot);
} catch (RemoteException e) {
e.printStackTrace();
}
if (changeMetas != null) {
for (SynchroMeta synchroMeta : changeMetas) {
String fullFilePath = fileStoreRootDir + synchroMeta.getPath();
if (synchroMeta.getOpType() == SynchroMeta.DELETE) {
File file = new File(fullFilePath);
if (file.isDirectory()) {
recursionDeleteDir(file);
} else {
file.delete();
}
}
if (synchroMeta.getOpType() == SynchroMeta.CONFIRM) {
connectToOtherStorageServer(synchroMeta.getTargetMachine());
logger.info("full file path: " + fullFilePath);
File file = new File(fullFilePath);
file.delete();
byte[] data = null;
try {
data = otherStorageService.getFile(synchroMeta.getPath());
} catch (RemoteException e) {
e.printStackTrace();
}
RandomAccessFile randomFile = null;
try {
randomFile = new RandomAccessFile(file, "rw");
randomFile.write(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (randomFile != null) {
try {
randomFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public final Machine namingServer;
public final Machine me;
private NamingService namingService;
private StorageService otherStorageService;
private final String fileStoreRootDir;
private boolean connectToOtherStorageServer(Machine machine) {
try {
otherStorageService = (StorageService) Naming.lookup(machine.getAddress(StorageService.class.getName()));
return true;
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
}
return false;
}
@Override
public void loadService() {
try {
final StorageService service = new StorageServiceImpl();
LocateRegistry.createRegistry(me.port);
Naming.rebind(me.getAddress(StorageService.class.getName()), service);
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
}
}
private FileUnit generateDirTree(File dir) {
FileUnit result = new FileUnit(dir.getName(), true);
File[] lowerFiles = dir.listFiles();
for (File file : lowerFiles) {
if (file.isDirectory()) {
FileUnit fileUnit = generateDirTree(file);
result.addLowerFileUnit(fileUnit);
} else {
FileUnit fileUnit = new FileUnit(file.getName(), false);
result.addLowerFileUnit(fileUnit);
}
}
return result;
}
private File locateFile(String fullFilePath) {
File file = null;
String[] path = fullFilePath.split("/");
String nowDir = new String(fileStoreRootDir);
for (int i = 0; i < path.length; i++) {
nowDir = nowDir + "/" + path[i];
file = new File(nowDir);
if (i == path.length-1) {
if (!file.exists()) {
return null;
}
} else {
if (!file.exists() || !file.isDirectory()) {
return null;
}
}
}
return file;
}
public boolean createFile(String fullFilePath, boolean isOrigin) {
File file = null;
String[] path = fullFilePath.split("/");
String nowDir = new String(fileStoreRootDir);
for (int i = 0; i < path.length; i++) {
nowDir = nowDir + "/" + path[i];
file = new File(nowDir);
if (i == path.length-1) {
if (!file.exists()) {
try {
boolean isCreateSuccess = file.createNewFile();
if (isCreateSuccess) {
List<Machine> otherMachines = namingService.notifyCreateFile(fullFilePath, isOrigin, me);
if (otherMachines != null) {
for (Machine otherMachine : otherMachines) {
if (otherMachine.equals(me)) {
continue;
}
connectToOtherStorageServer(otherMachine);
otherStorageService.createFile(fullFilePath, false);
}
}
}
return isCreateSuccess;
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
}
} else {
if (!file.exists()) {
file.mkdir();
} else if (!file.isDirectory()) {
return false;
}
}
}
return false;
}
public byte[] getFile(String fullFilePath) {
File file = locateFile(fullFilePath);
if (file == null) {
return null;
}
byte[] buffer = null;
BufferedInputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
int length = (int)file.length();
buffer = new byte[length];
inputStream.read(buffer);
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
}
}
return buffer;
}
public byte[] randomReadFile(String fullFilePath, long pos, int size) {
File file = locateFile(fullFilePath);
if (file == null) {
return null;
}
byte[] res = null;
RandomAccessFile randomFile = null;
try {
randomFile = new RandomAccessFile(file, "r");
randomFile.seek(pos);
res = new byte [size];
int count = randomFile.read(res);
if (count < 0) count = 0;
res = Arrays.copyOf(res, count);
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
} finally {
if (randomFile != null) {
try {
randomFile.close();
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
}
}
return res;
}
public boolean deleteFile(String fullFilePath, boolean isOrigin) {
File file = locateFile(fullFilePath);
if (file == null) {
return false;
}
boolean isDeleteSuccess = file.delete();
if (isDeleteSuccess) {
try {
List<Machine> otherMachines = namingService.notifyDeleteFile(fullFilePath, isOrigin, me);
if (otherMachines != null) {
for (Machine otherMachine : otherMachines) {
if (otherMachine.equals(me)) {
continue;
}
connectToOtherStorageServer(otherMachine);
otherStorageService.deleteFile(fullFilePath, false);
}
}
} catch (RemoteException e) {
logger.error(e);
e.printStackTrace();
}
}
return isDeleteSuccess;
}
public long getSizeOfFile(String fullFilePath) {
File file = locateFile(fullFilePath);
if (file == null) {
return -1;
}
return file.length();
}
public boolean appendWriteFile(String fullFilePath, byte[] data, boolean isOrigin) {
File file = locateFile(fullFilePath);
if (file == null) {
return false;
}
RandomAccessFile randomFile = null;
try {
randomFile = new RandomAccessFile(file, "rw");
long fileLength = randomFile.length();
randomFile.seek(fileLength);
randomFile.write(data);
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
} finally {
if (randomFile != null) {
try {
randomFile.close();
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
}
}
try {
List<Machine> otherMachines = namingService.notifyWriteFile(fullFilePath, isOrigin);
if (otherMachines != null) {
for (Machine otherMachine : otherMachines) {
if (otherMachine.equals(me)) {
continue;
}
connectToOtherStorageServer(otherMachine);
otherStorageService.appendWriteFile(fullFilePath, data, false);
}
}
} catch (RemoteException e) {
logger.error(e);
e.printStackTrace();
}
return true;
}
public boolean randomWriteFile(String fullFilePath, long pos, byte[] data, boolean isOrigin) {
File file = locateFile(fullFilePath);
if (file == null) {
return false;
}
RandomAccessFile randomFile = null;
try {
randomFile = new RandomAccessFile(file, "rw");
long fileLength = randomFile.length();
if (pos > fileLength) {
logger.error("Illegal: pos > fileLength");
randomFile.close();
return false;
}
randomFile.seek(pos);
randomFile.write(data);
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
} finally {
if (randomFile != null) {
try {
randomFile.close();
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
}
}
try {
List<Machine> otherMachines = namingService.notifyWriteFile(fullFilePath, isOrigin);
if (otherMachines != null) {
for (Machine otherMachine : otherMachines) {
if (otherMachine.equals(me)) {
continue;
}
connectToOtherStorageServer(otherMachine);
otherStorageService.randomWriteFile(fullFilePath, pos, data, false);
}
}
} catch (RemoteException e) {
logger.error(e);
e.printStackTrace();
}
return true;
}
public boolean createDir(String fullDirPath, boolean isOrigin) {
File file = null;
String[] path = fullDirPath.split("/");
String nowDir = new String(fileStoreRootDir);
for (int i = 0; i < path.length; i++) {
nowDir = nowDir + "/" + path[i];
file = new File(nowDir);
if (i == path.length-1) {
if (!file.exists()) {
boolean isMkdirSuccess = file.mkdir();
if (isMkdirSuccess) {
try {
List<Machine> otherMachines = namingService.notifyCreateDir(fullDirPath, isOrigin, me);
if (otherMachines != null) {
for (Machine otherMachine : otherMachines) {
if (otherMachine.equals(me)) {
continue;
}
connectToOtherStorageServer(otherMachine);
otherStorageService.createDir(fullDirPath, false);
}
}
} catch (RemoteException e) {
logger.error(e);
e.printStackTrace();
}
}
return isMkdirSuccess;
}
} else {
if (!file.exists()) {
file.mkdir();
} else if (!file.isDirectory()) {
return false;
}
}
}
return false;
}
private void recursionDeleteDir(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
recursionDeleteDir(file);
} else {
file.delete();
}
}
dir.delete();
}
public boolean deleteDir(String fullDirPath, boolean isOrigin) {
File file = null;
String[] path = fullDirPath.split("/");
String nowDir = new String(fileStoreRootDir);
for (int i = 0; i < path.length; i++) {
nowDir = nowDir + "/" + path[i];
file = new File(nowDir);
if (i == path.length-1) {
if (!file.exists() || !file.isDirectory()) {
return false;
} else {
recursionDeleteDir(file);
try {
List<Machine> otherMachines = namingService.notifyDeleteDir(fullDirPath, isOrigin, me);
if (otherMachines != null) {
for (Machine otherMachine : otherMachines) {
if (otherMachine.equals(me)) {
continue;
}
connectToOtherStorageServer(otherMachine);
otherStorageService.deleteDir(fullDirPath, false);
}
}
} catch (RemoteException e) {
logger.error(e);
e.printStackTrace();
}
return true;
}
} else {
if (!file.exists() || !file.isDirectory()) {
return false;
}
}
}
return false;
}
public static void main(String[] args) throws Exception {
StorageServer.getInstance().loadService();
final int interval = Integer.parseInt(Variables.getInstance().getProperty("contactInterval"));
final Timer timer = new Timer(interval, new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
try {
StorageServer server = StorageServer.getInstance();
NamingService loadService = (NamingService) Naming.lookup(server.namingServer.getAddress(NamingService.class.getName()));
loadService.updateMachine(server.me);
} catch (Exception e) {
logger.error(e);
e.printStackTrace();
}
}
});
timer.start();
}
}