Skip to content
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
4 changes: 2 additions & 2 deletions engine/src/main/java/com/arcadedb/GlobalConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ public Object call(final Object value) {
""),

SERVER_DEFAULT_DATABASES("arcadedb.server.defaultDatabases",
"The default databases created when the server starts. The format is '(<database-name>[(<user-name>:<user-passwd>[:<user-group>])[,]*])[{import:<URL>}][;]*'. Pay attention on using ';'"
+ " to separate databases and ',' to separate credentials. Example: 'Universe[elon:musk:admin];Amiga[Jay:Miner,Jack:Tramiel]{import:/tmp/movies.tgz}'",
"The default databases created when the server starts. The format is '(<database-name>[(<user-name>:<user-passwd>[:<user-group>])[,]*])[{import|restore:<URL>}][;]*'. Pay attention on using ';'"
+ " to separate databases and ',' to separate credentials. The supported actions are 'import' and 'restore'. Example: 'Universe[elon:musk:admin];Amiga[Jay:Miner,Jack:Tramiel]{import:/tmp/movies.tgz}'",
String.class, ""),

// SERVER HTTP
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public Restore(final String[] args) {
}

public Restore(final String file, final String databaseURL) {
settings.file = file;
settings.url = file;
settings.databaseURL = databaseURL;
}

Expand All @@ -52,7 +52,7 @@ public void restoreDatabase() {
formatImplementation.restoreDatabase();

} catch (Exception e) {
throw new RestoreException("Error during restore of database from file '" + settings.file + "'", e);
throw new RestoreException("Error during restore of database from file '" + settings.url + "'", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
public class RestoreSettings {
public String format = "full";
public String databaseURL;
public String file;
public String url;
public boolean overwriteDestination = false;
public int verboseLevel = 2;
public final Map<String, String> options = new HashMap<>();
Expand All @@ -37,25 +37,25 @@ protected void parseParameters(final String[] args) {
if (format == null)
throw new IllegalArgumentException("Missing backup format");

if (file == null)
if (url == null)
// ASSIGN DEFAULT FILENAME
switch (format) {
case "full":
file = "arcadedb-backup-%s.zip";
url = "arcadedb-backup-%s.zip";
break;
}

if (file == null) {
if (url == null) {
final DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-HHmmssSSS");
file = String.format(file, dateFormat.format(System.currentTimeMillis()));
url = String.format(url, dateFormat.format(System.currentTimeMillis()));
}
}

public int parseParameter(final String name, final String value) {
if ("format".equals(name))
format = value.toLowerCase();
else if ("f".equals(name))
file = value;
url = value;
else if ("d".equals(name))
databaseURL = value;
else if ("o".equals(name)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,29 @@
import com.arcadedb.utility.FileUtils;

import java.io.*;
import java.net.*;
import java.util.zip.*;

public class FullRestoreFormat extends AbstractRestoreFormat {
private final byte[] BUFFER = new byte[8192];

private static class RestoreInputSource {
public final InputStream inputStream;
public final long fileSize;

public RestoreInputSource(final InputStream inputStream, final long fileSize) {
this.inputStream = inputStream;
this.fileSize = fileSize;
}
}

public FullRestoreFormat(final DatabaseInternal database, final RestoreSettings settings, final ConsoleLogger logger) {
super(database, settings, logger);
}

@Override
public void restoreDatabase() throws Exception {
final File file = new File(settings.file);
if (!file.exists())
throw new RestoreException(String.format("The backup file '%s' not exist", settings.file));
final RestoreInputSource inputSource = openInputFile();

final File databaseDirectory = new File(settings.databaseURL);
if (databaseDirectory.exists()) {
Expand All @@ -49,12 +58,9 @@ public void restoreDatabase() throws Exception {
if (!databaseDirectory.mkdirs())
throw new RestoreException(String.format("Error on restoring database: the database directory '%s' cannot be created", settings.databaseURL));

logger.logLine(0, "Executing full restore of database from file '%s' to '%s'...", settings.file, settings.databaseURL);

final File backupFile = new File(settings.file);
final long databaseCompressedSize = backupFile.length();
logger.logLine(0, "Executing full restore of database from file '%s' to '%s'...", settings.url, settings.databaseURL);

try (ZipInputStream zipFile = new ZipInputStream(new FileInputStream(backupFile), DatabaseFactory.getDefaultCharset())) {
try (ZipInputStream zipFile = new ZipInputStream(inputSource.inputStream, DatabaseFactory.getDefaultCharset())) {
final long beginTime = System.currentTimeMillis();

long databaseOrigSize = 0L;
Expand All @@ -70,7 +76,7 @@ public void restoreDatabase() throws Exception {
final long elapsedInSecs = (System.currentTimeMillis() - beginTime) / 1000;

logger.logLine(0, "Full restore completed in %d seconds %s -> %s (%,d%% compression)", elapsedInSecs, FileUtils.getSizeAsString(databaseOrigSize),
FileUtils.getSizeAsString((databaseCompressedSize)), databaseOrigSize > 0 ? (databaseOrigSize - databaseCompressedSize) * 100 / databaseOrigSize : 0);
FileUtils.getSizeAsString((inputSource.fileSize)), databaseOrigSize > 0 ? (databaseOrigSize - inputSource.fileSize) * 100 / databaseOrigSize : 0);
}
}

Expand All @@ -94,4 +100,25 @@ private long uncompressFile(final ZipInputStream inputFile, ZipEntry compressedF

return origSize;
}

private RestoreInputSource openInputFile() throws IOException {
if (settings.url.startsWith("http://") || settings.url.startsWith("https://")) {
final HttpURLConnection connection = (HttpURLConnection) new URL(settings.url).openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.connect();

return new RestoreInputSource(connection.getInputStream(), 0);
}

String path = settings.url;
if (path.startsWith("file://"))
path = path.substring("file://".length());

final File file = new File(path);
if (!file.exists())
throw new RestoreException(String.format("The backup file '%s' not exist", settings.url));

return new RestoreInputSource(new FileInputStream(file), file.length());
}
}
117 changes: 68 additions & 49 deletions server/src/main/java/com/arcadedb/server/ArcadeDBServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.arcadedb.database.DatabaseInternal;
import com.arcadedb.database.EmbeddedDatabase;
import com.arcadedb.exception.ConfigurationException;
import com.arcadedb.integration.restore.Restore;
import com.arcadedb.log.LogManager;
import com.arcadedb.query.QueryEngineManager;
import com.arcadedb.server.ha.HAServer;
Expand Down Expand Up @@ -388,8 +389,9 @@ private synchronized Database getDatabase(final String databaseName, final boole
DatabaseInternal db = databases.get(databaseName);
if (db == null || !db.isOpen()) {

final DatabaseFactory factory = new DatabaseFactory(
configuration.getValueAsString(GlobalConfiguration.SERVER_DATABASE_DIRECTORY) + "/" + databaseName).setAutoTransaction(true);
final String path = configuration.getValueAsString(GlobalConfiguration.SERVER_DATABASE_DIRECTORY) + "/" + databaseName;

final DatabaseFactory factory = new DatabaseFactory(path).setAutoTransaction(true);

factory.setSecurity(getSecurity());

Expand Down Expand Up @@ -437,54 +439,9 @@ private void loadDefaultDatabases() {
final int credentialEnd = db.indexOf(']', credentialBegin);
final String credentials = db.substring(credentialBegin + 1, credentialEnd);

final String[] credentialPairs = credentials.split(",");
for (String credential : credentialPairs) {

final String[] credentialParts = credential.split(":");

if (credentialParts.length < 2) {
if (!security.existsUser(credential)) {
LogManager.instance()
.log(this, Level.WARNING, "Cannot create user '%s' to access database '%s' because the user does not exist", null, credential, dbName);
}
//FIXME: else if user exists, should we give him access to the dbName?
} else {
final String userName = credentialParts[0];
final String userPassword = credentialParts[1];
final String userRole = credentialParts.length > 2 ? credentialParts[2] : null;

if (security.existsUser(userName)) {
// EXISTING USER: CHECK CREDENTIALS
try {
final ServerSecurityUser user = security.authenticate(userName, userPassword, dbName);
if (!user.getAuthorizedDatabases().contains(dbName)) {
// UPDATE DB LIST
user.addDatabase(dbName, new String[] { userRole });
security.saveUsers();
}

} catch (ServerSecurityException e) {
LogManager.instance()
.log(this, Level.WARNING, "Cannot create database '%s' because the user '%s' already exists with a different password", null, dbName,
userName);
}
} else {
// CREATE A NEW USER
security.createUser(new JSONObject().put("name", userName)//
.put("password", security.encodePassword(userPassword))//
.put("databases", new JSONObject().put(dbName, new JSONArray())));
}
}
}
parseCredentials(dbName, credentials);

Database database;
if (existsDatabase(dbName)) {
database = getDatabase(dbName);
} else {
// CREATE THE DATABASE
LogManager.instance().log(this, Level.INFO, "Creating default database '%s'...", null, dbName);
database = createDatabase(dbName);
}
Database database = existsDatabase(dbName) ? getDatabase(dbName) : null;

if (credentialEnd < db.length() - 1 && db.charAt(credentialEnd + 1) == '{') {
// PARSE IMPORTS
Expand All @@ -501,14 +458,76 @@ private void loadDefaultDatabases() {
final String commandParams = command.substring(commandSeparator + 1);

switch (commandType) {
case "restore":
// DROP THE DATABASE BECAUSE THE RESTORE OPERATION WILL TAKE CARE OF CREATING A NEW DATABASE
if (database != null) {
database.drop();
databases.remove(dbName);
}
new Restore(commandParams, configuration.getValueAsString(GlobalConfiguration.SERVER_DATABASE_DIRECTORY) + "/" + dbName).restoreDatabase();
getDatabase(dbName);
break;

case "import":
if (database == null) {
// CREATE THE DATABASE
LogManager.instance().log(this, Level.INFO, "Creating default database '%s'...", null, dbName);
database = createDatabase(dbName);
}
database.command("sql", "import database " + commandParams);
break;

default:
LogManager.instance().log(this, Level.SEVERE, "Unsupported command %s in startup command: '%s'", null, commandType);
}
}
} else {
if (database == null) {
// CREATE THE DATABASE
LogManager.instance().log(this, Level.INFO, "Creating default database '%s'...", null, dbName);
createDatabase(dbName);
}
}
}
}
}

private void parseCredentials(final String dbName, final String credentials) {
final String[] credentialPairs = credentials.split(",");
for (String credential : credentialPairs) {

final String[] credentialParts = credential.split(":");

if (credentialParts.length < 2) {
if (!security.existsUser(credential)) {
LogManager.instance()
.log(this, Level.WARNING, "Cannot create user '%s' to access database '%s' because the user does not exist", null, credential, dbName);
}
//FIXME: else if user exists, should we give him access to the dbName?
} else {
final String userName = credentialParts[0];
final String userPassword = credentialParts[1];
final String userRole = credentialParts.length > 2 ? credentialParts[2] : null;

if (security.existsUser(userName)) {
// EXISTING USER: CHECK CREDENTIALS
try {
final ServerSecurityUser user = security.authenticate(userName, userPassword, dbName);
if (!user.getAuthorizedDatabases().contains(dbName)) {
// UPDATE DB LIST
user.addDatabase(dbName, new String[] { userRole });
security.saveUsers();
}

} catch (ServerSecurityException e) {
LogManager.instance()
.log(this, Level.WARNING, "Cannot create database '%s' because the user '%s' already exists with a different password", null, dbName, userName);
}
} else {
// CREATE A NEW USER
security.createUser(new JSONObject().put("name", userName)//
.put("password", security.encodePassword(userPassword))//
.put("databases", new JSONObject().put(dbName, new JSONArray())));
}
}
}
Expand Down