Skip to content
This repository has been archived by the owner on Sep 27, 2022. It is now read-only.

07-Proxy, Федоров Андрей, 393 группа #470

Merged
merged 4 commits into from
Dec 21, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Пиши, пожалуйста, комментарии к коду в таком стиле, т.к. в таком случае можно писать ответ в том же месте.


import ru.fizteh.fivt.storage.structured.TableProvider;

interface AutoCloseableProvider extends TableProvider, AutoCloseable {
@Override
void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;

import ru.fizteh.fivt.storage.structured.Table;

interface AutoCloseableTable extends Table, AutoCloseable {
@Override
void close();
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,16 +1,74 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;

import ru.fizteh.fivt.proxy.LoggingProxyFactory;
import ru.fizteh.fivt.storage.structured.TableProviderFactory;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.DatabaseIOException;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.Log;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.LoggingProxyFactoryImpl;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.Utility;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.ValidityController;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.ValidityController.KillLock;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.ValidityController.UseLock;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.IdentityHashMap;

public class DBTableProviderFactory implements TableProviderFactory {
public final class DBTableProviderFactory implements TableProviderFactory, AutoCloseable {
private static final LoggingProxyFactory LOGGING_PROXY_FACTORY = new LoggingProxyFactoryImpl();
private static final Writer LOG_WRITER;

static {
Writer tempWriter;

try {
tempWriter = new OutputStreamWriter(new FileOutputStream("Proxy.log"));
} catch (IOException exc) {
Log.log(DBTableProviderFactory.class, exc, "Failed to create log");
tempWriter = null;
}

LOG_WRITER = tempWriter;
}

private final ValidityController validityController = new ValidityController();
private final IdentityHashMap<AutoCloseableProvider, Boolean> generatedProviders =
new IdentityHashMap<>();

static <T> T wrapImplementation(T implementation, Class<T> interfaceClass) {
if (LOG_WRITER != null) {
return (T) LOGGING_PROXY_FACTORY.wrap(LOG_WRITER, implementation, interfaceClass);
} else {
return implementation;
}
}

@Override
public synchronized void close() {
try (KillLock lock = validityController.useAndKill()) {
for (AutoCloseableProvider provider : generatedProviders.keySet()) {
provider.close();
}
generatedProviders.clear();
}
}

/**
* Unregisters the given provider.
* @param provider
* Pure (not proxied) link to the closed provider.
*/
synchronized void onProviderClosed(AutoCloseableProvider provider) {
try (UseLock useLock = validityController.use()) {
generatedProviders.remove(provider);
}
}

private void checkDatabaseDirectory(final Path databaseRoot) throws DatabaseIOException {
if (!Files.isDirectory(databaseRoot)) {
Expand All @@ -31,25 +89,37 @@ private void checkDatabaseDirectory(final Path databaseRoot) throws DatabaseIOEx
}

@Override
public DBTableProvider create(String dir) throws IllegalArgumentException, DatabaseIOException {
Utility.checkNotNull(dir, "Directory");

Path databaseRoot = Paths.get(dir).normalize();
if (!Files.exists(databaseRoot)) {
if (databaseRoot.getParent() == null || !Files.isDirectory(databaseRoot.getParent())) {
throw new DatabaseIOException(
"Database directory parent path does not exist or is not a directory");
}
protected void finalize() throws Throwable {
super.finalize();
close();
}

@Override
public synchronized AutoCloseableProvider create(String dir)
throws IllegalArgumentException, DatabaseIOException {
try (UseLock useLock = validityController.use()) {
Utility.checkNotNull(dir, "Directory");

try {
Files.createDirectory(databaseRoot);
} catch (IOException exc) {
throw new DatabaseIOException("Failed to establish database on path " + dir, exc);
Path databaseRoot = Paths.get(dir).normalize();
if (!Files.exists(databaseRoot)) {
if (databaseRoot.getParent() == null || !Files.isDirectory(databaseRoot.getParent())) {
throw new DatabaseIOException(
"Database directory parent path does not exist or is not a directory");
}

try {
Files.createDirectory(databaseRoot);
} catch (IOException exc) {
throw new DatabaseIOException("Failed to establish database on path " + dir, exc);
}
} else {
checkDatabaseDirectory(databaseRoot);
}
} else {
checkDatabaseDirectory(databaseRoot);
}

return new DBTableProvider(databaseRoot);
AutoCloseableProvider provider = new DBTableProvider(databaseRoot, this);
AutoCloseableProvider wrappedProvider = wrapImplementation(provider, AutoCloseableProvider.class);
generatedProviders.put(provider, Boolean.TRUE);
return wrappedProvider;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
* Database class responsible for a set of tables assigned to it.
* @author phoenix
*/
public class Database {
protected final TableProvider provider;
public class Database implements AutoCloseable {
private final TableProvider provider;
/**
* Root directory of all database files
*/
Expand Down Expand Up @@ -69,6 +69,13 @@ public void dropTable(String tableName) throws IllegalArgumentException, IOExcep
}
}

@Override
public void close() throws Exception {
if (provider instanceof AutoCloseable) {
((AutoCloseable) provider).close();
}
}

public Table getActiveTable() throws NoActiveTableException {
checkCurrentTableIsOpen();
return activeTable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,53 @@
import ru.fizteh.fivt.storage.structured.ColumnFormatException;
import ru.fizteh.fivt.storage.structured.Storeable;
import ru.fizteh.fivt.storage.structured.Table;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.json.JSONComplexObject;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.json.JSONField;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class StoreableImpl implements Storeable {
/**
* Implementation of Storeable that can be put to the table it is assigned to as a value.<br/>
* Not thread-safe.<br/>
* Not bound to any table.
*/
@JSONComplexObject(wrapper = true)
public final class StoreableImpl implements Storeable {
@JSONField
private final Object[] values;

private Table host;
private final List<Class<?>> types;

/**
* Creates a new instance of Storeable with null values as default.
* @param host
* Host table.
*/
StoreableImpl(Table host) {
this.host = host;
if (host instanceof StoreableTableImpl) {
// Memory optimization.
types = ((StoreableTableImpl) host).getColumnTypes();
} else {
types = new ArrayList<>(host.getColumnsCount());
for (int i = 0; i < host.getColumnsCount(); i++) {
types.add(host.getColumnType(i));
}
}
this.values = new Object[host.getColumnsCount()];
}

Table getHost() {
return host;
List<Class<?>> getTypes() {
return types;
}

private void ensureMatchColumnType(int columnIndex, Class<?> clazz) throws ColumnFormatException {
Class<?> columnType = host.getColumnType(columnIndex);
Class<?> columnType = types.get(columnIndex);
if (!columnType.equals(clazz)) {
throw new ColumnFormatException(
String.format(
"wrong type (Table '%s', col %d: Expected instance of %s, but got %s)",
host.getName(),
"wrong type (col %d: Expected instance of %s, but got %s)",
columnIndex,
columnType.getSimpleName(),
clazz.getSimpleName()));
Expand Down Expand Up @@ -106,7 +124,7 @@ private <T> T getTypedValue(int columnIndex, Class<T> clazz)

@Override
public int hashCode() {
return host.hashCode();
return values.length;
}

@Override
Expand All @@ -116,21 +134,11 @@ public boolean equals(Object obj) {
}
StoreableImpl storeable = (StoreableImpl) obj;

if (host != storeable.host) {
return false;
}

if (host.getColumnsCount() != storeable.host.getColumnsCount()) {
if (values.length != storeable.values.length) {
return false;
}

for (int col = 0; col < host.getColumnsCount(); col++) {
if (!host.getColumnType(col).equals(storeable.host.getColumnType(col))) {
return false;
}
}

for (int col = 0; col < host.getColumnsCount(); col++) {
for (int col = 0; col < storeable.values.length; col++) {
if (!Objects.equals(values[col], storeable.values[col])) {
return false;
}
Expand All @@ -141,9 +149,20 @@ public boolean equals(Object obj) {

@Override
public String toString() {
if (host instanceof StoreableTableImpl) {
return ((StoreableTableImpl) host).getProvider().serialize(host, this);
StringBuilder sb = new StringBuilder(StoreableImpl.class.getSimpleName()).append('[');

boolean comma = false;
for (Object obj : values) {
if (comma) {
sb.append(',');
}
comma = true;
if (obj != null) {
sb.append(obj.toString());
}
}
return super.toString();

sb.append(']');
return sb.toString();
}
}
Loading