diff --git a/caosdb-webui b/caosdb-webui index 7df3c8cdf945e5b98df8b04a084fabbdaf058946..2a6d74d7cb6bed89b2e7a0e5801ff4c040a3ebf8 160000 --- a/caosdb-webui +++ b/caosdb-webui @@ -1 +1 @@ -Subproject commit 7df3c8cdf945e5b98df8b04a084fabbdaf058946 +Subproject commit 2a6d74d7cb6bed89b2e7a0e5801ff4c040a3ebf8 diff --git a/src/main/java/caosdb/server/CaosDBServer.java b/src/main/java/caosdb/server/CaosDBServer.java index 8c67d51405f23f4f8b6f64a3c26b9413a6c5d80b..d52b6e15896ed4724b5d23af4ab1004ad994ca2d 100644 --- a/src/main/java/caosdb/server/CaosDBServer.java +++ b/src/main/java/caosdb/server/CaosDBServer.java @@ -48,6 +48,7 @@ import caosdb.server.resource.PermissionRulesResource; import caosdb.server.resource.RolesResource; import caosdb.server.resource.ScriptingResource; import caosdb.server.resource.ServerLogsResource; +import caosdb.server.resource.ServerPropertiesResource; import caosdb.server.resource.TestCaseFileSystemResource; import caosdb.server.resource.TestCaseResource; import caosdb.server.resource.ThumbnailsResource; @@ -111,10 +112,7 @@ public class CaosDBServer extends Application { private static boolean INSECURE = false; public static String getServerProperty(final String key) { - if (SERVER_PROPERTIES == null) { - SERVER_PROPERTIES = ServerProperties.initServerProperties(); - } - return SERVER_PROPERTIES.getProperty(key); + return getServerProperties().getProperty(key); } /** @@ -581,6 +579,7 @@ public class CaosDBServer extends Application { .setMatchingMode(Template.MODE_STARTS_WITH); protectedRouter.attach("/login?username={username}", AuthenticationResource.class); protectedRouter.attach("/logout", LogoutResource.class); + protectedRouter.attach("/_server_properties", ServerPropertiesResource.class); protectedRouter.attachDefault(DefaultResource.class); /* @@ -711,6 +710,13 @@ public class CaosDBServer extends Application { } SERVER_PROPERTIES.setProperty(key, value); } + + public static Properties getServerProperties() { + if (SERVER_PROPERTIES == null) { + SERVER_PROPERTIES = ServerProperties.initServerProperties(); + } + return SERVER_PROPERTIES; + } } class CaosDBComponent extends Component { diff --git a/src/main/java/caosdb/server/ServerPropertiesSerializer.java b/src/main/java/caosdb/server/ServerPropertiesSerializer.java new file mode 100644 index 0000000000000000000000000000000000000000..10189f99e2ff30a2d9306ad9dc007810607747dd --- /dev/null +++ b/src/main/java/caosdb/server/ServerPropertiesSerializer.java @@ -0,0 +1,36 @@ +package caosdb.server; + +import caosdb.server.utils.Serializer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; +import org.jdom2.Element; + +public class ServerPropertiesSerializer implements Serializer<Properties, Element> { + + private boolean sort; + + public ServerPropertiesSerializer(boolean sort) { + this.sort = sort; + } + + public ServerPropertiesSerializer() { + this(true); + } + + @Override + public Element serialize(Properties object) { + Element root = new Element("Properties"); + List<String> names = new ArrayList<>(object.stringPropertyNames()); + if (sort) { + Collections.sort(names); + } + for (String prop : names) { + Element propElem = new Element(prop); + propElem.addContent(object.getProperty(prop)); + root.addContent(propElem); + } + return root; + } +} diff --git a/src/main/java/caosdb/server/accessControl/ACMPermissions.java b/src/main/java/caosdb/server/accessControl/ACMPermissions.java index 40b063f16932c457fe176006c5b7f438a7a2252e..29988106b842fbd2b825899093e102a7448e8951 100644 --- a/src/main/java/caosdb/server/accessControl/ACMPermissions.java +++ b/src/main/java/caosdb/server/accessControl/ACMPermissions.java @@ -24,6 +24,7 @@ package caosdb.server.accessControl; public class ACMPermissions { + public static final String PERMISSION_ACCESS_SERVER_PROPERTIES = "ACCESS_SERVER_PROPERTIES"; public static final String PERMISSION_RETRIEVE_SERVERLOGS = "SERVERLOGS:RETRIEVE"; public static final String PERMISSION_RETRIEVE_USER_ROLES( diff --git a/src/main/java/caosdb/server/database/BackendTransaction.java b/src/main/java/caosdb/server/database/BackendTransaction.java index a551d5b184ef9c35045697f6f36196665cf648c0..1d5d5c2e68274e664c392a24a901aa4bcd65623b 100644 --- a/src/main/java/caosdb/server/database/BackendTransaction.java +++ b/src/main/java/caosdb/server/database/BackendTransaction.java @@ -34,6 +34,7 @@ import caosdb.server.database.backend.implementation.MySQL.MySQLGetFileRecordByP import caosdb.server.database.backend.implementation.MySQL.MySQLGetIDByName; import caosdb.server.database.backend.implementation.MySQL.MySQLGetInfo; import caosdb.server.database.backend.implementation.MySQL.MySQLGetUpdateableChecksums; +import caosdb.server.database.backend.implementation.MySQL.MySQLInsertEntityDatatype; import caosdb.server.database.backend.implementation.MySQL.MySQLInsertEntityProperties; import caosdb.server.database.backend.implementation.MySQL.MySQLInsertLinCon; import caosdb.server.database.backend.implementation.MySQL.MySQLInsertLogRecord; @@ -87,6 +88,7 @@ import caosdb.server.database.backend.interfaces.GetFileRecordByPathImpl; import caosdb.server.database.backend.interfaces.GetIDByNameImpl; import caosdb.server.database.backend.interfaces.GetInfoImpl; import caosdb.server.database.backend.interfaces.GetUpdateableChecksumsImpl; +import caosdb.server.database.backend.interfaces.InsertEntityDatatypeImpl; import caosdb.server.database.backend.interfaces.InsertEntityPropertiesImpl; import caosdb.server.database.backend.interfaces.InsertLinConImpl; import caosdb.server.database.backend.interfaces.InsertLogRecordImpl; @@ -131,13 +133,11 @@ public abstract class BackendTransaction implements Undoable { BackendTransaction parent = null; private static HashMap< Class<? extends BackendTransactionImpl>, Class<? extends BackendTransactionImpl>> - impl = - new HashMap< - Class<? extends BackendTransactionImpl>, Class<? extends BackendTransactionImpl>>(); + impl = new HashMap<>(); - protected abstract void execute() throws TransactionException; + protected abstract void execute(); - final void executeTransaction() throws TransactionException { + final void executeTransaction() { final long t1 = System.currentTimeMillis(); execute(); final long t2 = System.currentTimeMillis(); @@ -194,10 +194,11 @@ public abstract class BackendTransaction implements Undoable { setImpl(SetQueryTemplateDefinitionImpl.class, MySQLSetQueryTemplateDefinition.class); setImpl( RetrieveQueryTemplateDefinitionImpl.class, MySQLRetrieveQueryTemplateDefinition.class); + setImpl(InsertEntityDatatypeImpl.class, MySQLInsertEntityDatatype.class); } } - protected <K extends BackendTransaction> K execute(final K t) throws TransactionException { + protected <K extends BackendTransaction> K execute(final K t) { assert t != this; this.undoHandler.append(t); t.setAccess(this.access); @@ -219,8 +220,7 @@ public abstract class BackendTransaction implements Undoable { } @SuppressWarnings("unchecked") - protected <T extends BackendTransactionImpl> T getImplementation(final Class<T> clz) - throws TransactionException { + protected <T extends BackendTransactionImpl> T getImplementation(final Class<T> clz) { init(); try { final T ret = (T) impl.get(clz).getConstructor(Access.class).newInstance(this.access); diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java new file mode 100644 index 0000000000000000000000000000000000000000..a2682e80b1997b53496e3ac2f8e6147726fb77c9 --- /dev/null +++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertEntityDatatype.java @@ -0,0 +1,52 @@ +package caosdb.server.database.backend.implementation.MySQL; + +import caosdb.server.database.access.Access; +import caosdb.server.database.backend.interfaces.InsertEntityDatatypeImpl; +import caosdb.server.database.exceptions.IntegrityException; +import caosdb.server.database.exceptions.TransactionException; +import caosdb.server.database.proto.SparseEntity; +import java.sql.PreparedStatement; +import java.sql.SQLIntegrityConstraintViolationException; + +public class MySQLInsertEntityDatatype extends MySQLTransaction + implements InsertEntityDatatypeImpl { + + public MySQLInsertEntityDatatype(Access access) { + super(access); + } + + public static final String STMT_INSERT_ENTITY_DATATYPE = + "INSERT INTO data_type (domain_id, entity_id, property_id, datatype) SELECT 0, 0, ?, ( SELECT id from entities where name = ? LIMIT 1);"; + public static final String STMT_INSERT_ENTITY_COLLECTION = + "INSERT INTO collection_type (domain_id, entity_id, property_id, collection) SELECT 0, 0, ?, ?;"; + + @Override + public void execute(final SparseEntity entity) { + try { + final PreparedStatement insertEntityDatatypeStmt = + prepareStatement(STMT_INSERT_ENTITY_DATATYPE); + + insertEntityDatatypeStmt.setInt(1, entity.id); + insertEntityDatatypeStmt.setString(2, entity.datatype); + + insertEntityDatatypeStmt.execute(); + + if (entity.collection != null) { + final PreparedStatement insertEntityCollectionStmt = + prepareStatement(STMT_INSERT_ENTITY_COLLECTION); + + insertEntityCollectionStmt.setInt(1, entity.id); + insertEntityCollectionStmt.setString(2, entity.collection); + + insertEntityCollectionStmt.execute(); + } + + } catch (final SQLIntegrityConstraintViolationException exc) { + throw new IntegrityException(exc); + } catch (final TransactionException exc) { + throw exc; + } catch (final Exception exc) { + throw new TransactionException(exc); + } + } +} diff --git a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java index dbe3893945ae09cadfda0657f9d22d02bd6a9371..4ad9f5b6a3cc3e51c05bc83bbc9332807b79484d 100644 --- a/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java +++ b/src/main/java/caosdb/server/database/backend/implementation/MySQL/MySQLInsertSparseEntity.java @@ -38,12 +38,12 @@ public class MySQLInsertSparseEntity extends MySQLTransaction implements InsertS super(access); } - public static final String STMT_INSERT_SPARSE_ENTITY = "call insertEntity(?,?,?,?,?,?)"; + public static final String STMT_INSERT_SPARSE_ENTITY = "call insertEntity(?,?,?,?)"; public static final String STMT_INSERT_FILE_PROPERTIES = "INSERT INTO files (file_id, hash, size, path) VALUES (?, unhex(?), ?, ?);"; @Override - public void execute(final SparseEntity entity) throws TransactionException { + public void execute(final SparseEntity entity) { try { final PreparedStatement insertEntityStmt = prepareStatement(STMT_INSERT_SPARSE_ENTITY); final PreparedStatement insertFilePropsStmt = prepareStatement(STMT_INSERT_FILE_PROPERTIES); @@ -51,15 +51,14 @@ public class MySQLInsertSparseEntity extends MySQLTransaction implements InsertS insertEntityStmt.setString(1, entity.name); insertEntityStmt.setString(2, entity.description); insertEntityStmt.setString(3, entity.role); - insertEntityStmt.setString(4, entity.datatype); - insertEntityStmt.setString(5, entity.collection); - insertEntityStmt.setString(6, entity.acl); + insertEntityStmt.setString(4, entity.acl); - final ResultSet rs = insertEntityStmt.executeQuery(); - if (rs.next()) { - entity.id = rs.getInt("EntityID"); - } else { - throw new TransactionException("Didn't get new EntityID back."); + try (final ResultSet rs = insertEntityStmt.executeQuery()) { + if (rs.next()) { + entity.id = rs.getInt("EntityID"); + } else { + throw new TransactionException("Didn't get new EntityID back."); + } } if (entity.filePath != null) { diff --git a/src/main/java/caosdb/server/database/backend/interfaces/InsertEntityDatatypeImpl.java b/src/main/java/caosdb/server/database/backend/interfaces/InsertEntityDatatypeImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2f6f7c859281344997e1c781e9a56aafa5d03fc4 --- /dev/null +++ b/src/main/java/caosdb/server/database/backend/interfaces/InsertEntityDatatypeImpl.java @@ -0,0 +1,8 @@ +package caosdb.server.database.backend.interfaces; + +import caosdb.server.database.proto.SparseEntity; +import caosdb.server.utils.Undoable; + +public interface InsertEntityDatatypeImpl extends BackendTransactionImpl, Undoable { + public abstract void execute(SparseEntity entity); +} diff --git a/src/main/java/caosdb/server/database/backend/interfaces/InsertSparseEntityImpl.java b/src/main/java/caosdb/server/database/backend/interfaces/InsertSparseEntityImpl.java index 7ba147058b8c4675d58b66a5c11b7dd66311cabf..8ad9a9f7ac0608c4e1e51ba4783a985d0e20d985 100644 --- a/src/main/java/caosdb/server/database/backend/interfaces/InsertSparseEntityImpl.java +++ b/src/main/java/caosdb/server/database/backend/interfaces/InsertSparseEntityImpl.java @@ -22,11 +22,10 @@ */ package caosdb.server.database.backend.interfaces; -import caosdb.server.database.exceptions.TransactionException; import caosdb.server.database.proto.SparseEntity; import caosdb.server.utils.Undoable; public interface InsertSparseEntityImpl extends BackendTransactionImpl, Undoable { - public abstract void execute(SparseEntity entity) throws TransactionException; + public abstract void execute(SparseEntity entity); } diff --git a/src/main/java/caosdb/server/database/backend/transaction/InsertEntity.java b/src/main/java/caosdb/server/database/backend/transaction/InsertEntity.java index 65611a4193e8bb494666fb91c3a07a59b4aabd99..e258504908b44c8054a56315fa26e8dacae8b023 100644 --- a/src/main/java/caosdb/server/database/backend/transaction/InsertEntity.java +++ b/src/main/java/caosdb/server/database/backend/transaction/InsertEntity.java @@ -23,7 +23,6 @@ package caosdb.server.database.backend.transaction; import caosdb.server.database.BackendTransaction; -import caosdb.server.database.exceptions.TransactionException; import caosdb.server.entity.EntityInterface; import caosdb.server.entity.container.TransactionContainer; import caosdb.server.utils.EntityStatus; @@ -37,12 +36,17 @@ public class InsertEntity extends BackendTransaction { } @Override - public void execute() throws TransactionException { + public void execute() { for (final EntityInterface newEntity : this.container) { if (newEntity.getEntityStatus() == EntityStatus.QUALIFIED) { execute(new InsertSparseEntity(newEntity)); } } + for (final EntityInterface newEntity : this.container) { + if (newEntity.getEntityStatus() == EntityStatus.QUALIFIED && newEntity.hasDatatype()) { + execute(new InsertEntityDatatype(newEntity)); + } + } for (final EntityInterface newEntity : this.container) { if (newEntity.getEntityStatus() == EntityStatus.QUALIFIED) { if (newEntity.getQueryTemplateDefinition() != null) { @@ -51,7 +55,6 @@ public class InsertEntity extends BackendTransaction { if (newEntity.hasFileProperties()) { execute(new InsertFile(newEntity)); } - // execute(new InsertEntityValue(newEntity)); execute(new InsertEntityProperties(newEntity)); execute(new InsertParents(newEntity)); diff --git a/src/main/java/caosdb/server/database/backend/transaction/InsertEntityDatatype.java b/src/main/java/caosdb/server/database/backend/transaction/InsertEntityDatatype.java new file mode 100644 index 0000000000000000000000000000000000000000..39c46583cc277eb81128d9fae22d97e296d8bbc1 --- /dev/null +++ b/src/main/java/caosdb/server/database/backend/transaction/InsertEntityDatatype.java @@ -0,0 +1,36 @@ +package caosdb.server.database.backend.transaction; + +import static caosdb.server.transaction.Transaction.ERROR_INTEGRITY_VIOLATION; + +import caosdb.server.database.BackendTransaction; +import caosdb.server.database.backend.interfaces.InsertEntityDatatypeImpl; +import caosdb.server.database.exceptions.IntegrityException; +import caosdb.server.database.proto.SparseEntity; +import caosdb.server.entity.EntityInterface; +import caosdb.server.utils.EntityStatus; + +public class InsertEntityDatatype extends BackendTransaction { + + private final EntityInterface entity; + + public InsertEntityDatatype(final EntityInterface entity) { + this.entity = entity; + } + + @Override + public void execute() { + final InsertEntityDatatypeImpl t = getImplementation(InsertEntityDatatypeImpl.class); + + final SparseEntity e = this.entity.getSparseEntity(); + + try { + t.execute(e); + } catch (final IntegrityException exc) { + this.entity.addError(ERROR_INTEGRITY_VIOLATION); + this.entity.setEntityStatus(EntityStatus.CORRUPT); + throw exc; + } + + this.entity.setId(e.id); + } +} diff --git a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java index 5a32cf795b661537f3dbc07fe8717aff4d8a0242..e8bc5f4932f4c3972b6e64bd5d234e8c7898794b 100644 --- a/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java +++ b/src/main/java/caosdb/server/resource/AbstractCaosDBServerResource.java @@ -313,19 +313,29 @@ public abstract class AbstractCaosDBServerResource extends ServerResource { return new JdomRepresentation(doc, MediaType.TEXT_XML, " ", getReference(), getXSLScript()); } - protected JdomRepresentation error(final Message m, final Status status) { + protected Representation error(final Message m, final Status status) { final Document doc = new Document(); final Element root = generateRootElement(); root.addContent(m.toElement().setName("Error")); doc.setRootElement(root); + return error( + new JdomRepresentation(doc, MediaType.TEXT_XML, " ", getReference(), getXSLScript()), + status); + } + + protected Representation error(Representation entity, Status status) { getResponse().setStatus(status); - return new JdomRepresentation(doc, MediaType.TEXT_XML, " ", getReference(), getXSLScript()); + return entity; } - protected JdomRepresentation error(final Message m) { + protected Representation error(final Message m) { return error(m, Status.SERVER_ERROR_INTERNAL); } + protected Representation error(final Status status) { + return error((Representation) null, status); + } + protected JdomRepresentation warning(final Message m) { final Document doc = new Document(); final Element root = generateRootElement(); @@ -334,19 +344,19 @@ public abstract class AbstractCaosDBServerResource extends ServerResource { return new JdomRepresentation(doc, MediaType.TEXT_XML, " ", getReference(), getXSLScript()); } - protected JdomRepresentation noWellFormedNess() { + protected Representation noWellFormedNess() { return error(ServerMessages.REQUEST_BODY_NOT_WELLFORMED); } - protected JdomRepresentation emptyEntity() { + protected Representation emptyEntity() { return error(ServerMessages.REQUEST_BODY_EMPTY); } - protected JdomRepresentation connectionFailed() { + protected Representation connectionFailed() { return error(ServerMessages.CANNOT_CONNECT_TO_DATABASE); } - public JdomRepresentation handleThrowable(final Throwable t) { + public Representation handleThrowable(final Throwable t) { try { getRequest().getAttributes().put("THROWN", t); throw t; diff --git a/src/main/java/caosdb/server/resource/ServerPropertiesResource.java b/src/main/java/caosdb/server/resource/ServerPropertiesResource.java new file mode 100644 index 0000000000000000000000000000000000000000..9b878e3338a9d0b0c74704acb412ac92ceb1f0c4 --- /dev/null +++ b/src/main/java/caosdb/server/resource/ServerPropertiesResource.java @@ -0,0 +1,42 @@ +package caosdb.server.resource; + +import caosdb.server.CaosDBServer; +import caosdb.server.ServerPropertiesSerializer; +import caosdb.server.accessControl.ACMPermissions; +import org.restlet.data.Form; +import org.restlet.data.Parameter; +import org.restlet.data.Status; +import org.restlet.representation.Representation; + +public class ServerPropertiesResource extends AbstractCaosDBServerResource { + + @Override + protected void doInit() { + super.doInit(); + setXSLScript("xsl/server_properties.xsl"); + } + + @Override + protected Representation httpGetInChildClass() { + if (CaosDBServer.isDebugMode()) { + getUser().checkPermission(ACMPermissions.PERMISSION_ACCESS_SERVER_PROPERTIES); + return super.ok( + new ServerPropertiesSerializer().serialize(CaosDBServer.getServerProperties())); + } + return error(Status.CLIENT_ERROR_NOT_FOUND); + } + + @Override + protected Representation httpPostInChildClass(Representation entity) { + if (CaosDBServer.isDebugMode()) { + getUser().checkPermission(ACMPermissions.PERMISSION_ACCESS_SERVER_PROPERTIES); + Form form = new Form(entity); + for (Parameter param : form) { + CaosDBServer.setProperty(param.getName(), param.getValue()); + } + return super.ok( + new ServerPropertiesSerializer().serialize(CaosDBServer.getServerProperties())); + } + return error(Status.CLIENT_ERROR_NOT_FOUND); + } +}