/*
* Copyright 2013 David Tinker
*
* 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 io.qdb.server.controller;
import io.qdb.server.model.Database;
import io.qdb.server.repo.Repository;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
@Singleton
public class DatabaseController extends CrudController {
private final Repository repo;
private final QueueController queueController;
public static class DatabaseDTO {
public String id;
public Integer version;
public String owner;
@SuppressWarnings("UnusedDeclaration")
public DatabaseDTO() { }
public DatabaseDTO(Database db) {
id = db.getId();
version = db.getVersion();
owner = db.getOwner();
}
}
private static final Pattern VALID_DATABASE_ID = Pattern.compile("[0-9a-z\\-_]+", Pattern.CASE_INSENSITIVE);
@Inject
public DatabaseController(Repository repo, JsonService jsonService, QueueController queueController) {
super(jsonService);
this.repo = repo;
this.queueController = queueController;
}
@Override
protected void list(Call call, int offset, int limit) throws IOException {
List<Database> list = repo.findDatabasesVisibleTo(call.getUser(), offset, limit);
DatabaseDTO[] ans = new DatabaseDTO[list.size()];
for (int i = 0; i < ans.length; i++) ans[i] = new DatabaseDTO(list.get(i));
call.setJson(ans);
}
@Override
protected void count(Call call) throws IOException {
call.setJson(new Count(repo.countDatabasesVisibleTo(call.getUser())));
}
@Override
protected void show(Call call, String id) throws IOException {
Database db = repo.findDatabase(id);
if (db == null) {
call.setCode(404);
} else if (db.isVisibleTo(call.getUser())) {
call.setJson(new DatabaseDTO(db));
} else {
call.setCode(403);
}
}
@Override
protected void createOrUpdate(Call call, String id) throws IOException {
if (call.getUser().isAdmin()) {
DatabaseDTO dto = getBodyObject(call, DatabaseDTO.class);
Database db;
boolean create;
synchronized (repo) {
db = repo.findDatabase(id);
if (create = db == null) {
if (call.isPut()) {
call.setCode(404);
return;
}
if (!VALID_DATABASE_ID.matcher(id).matches()) {
call.setCode(422, "Database id must contain only letters, numbers, hyphens and underscores");
return;
}
db = new Database(id);
} else {
if (dto.version != null && !dto.version.equals(db.getVersion())) {
call.setCode(409, new DatabaseDTO(db));
return;
}
db = db.deepCopy();
}
boolean changed = create;
if (dto.owner != null && !dto.owner.equals(db.getOwner())) {
if (repo.findUser(dto.owner) == null) {
call.setCode(422, "owner [" + dto.owner + "] does not exist");
return;
}
db.setOwner(dto.owner);
changed = true;
}
if (changed) repo.updateDatabase(db);
}
call.setCode(create ? 201 : 200, new DatabaseDTO(db));
} else {
call.setCode(403);
}
}
@Override
protected void delete(Call call, String id) throws IOException {
synchronized (repo) {
Database db = repo.findDatabase(id);
if (db == null) {
call.setCode(404);
return;
}
repo.deleteDatabase(id);
}
}
@Override
protected Controller getController(Call call, String id, String resource) throws IOException {
Database db = repo.findDatabase(id);
if (db != null) {
if (!db.isVisibleTo(call.getUser())) return StatusCodeController.SC_403;
call.setDatabase(db);
if ("q".equals(resource)) return queueController;
}
return StatusCodeController.SC_404;
}
}