diff --git a/CHANGELOG.md b/CHANGELOG.md index d12b8723bb97977d2aefab83fbd174be51dc83bb..ef9bb15d638848138ec9b6820eabf833f9421e3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Inheritance job cannot handle inheritance from same container (!54) * Bug in the query parser (MR!56) - The parser would throw an error when the query contains a conjunction or disjunction filter with a first element which is another disjunction or conjunction and being wrapped into parenthesis. diff --git a/src/main/java/org/caosdb/server/entity/StatementStatus.java b/src/main/java/org/caosdb/server/entity/StatementStatus.java index ec6b0b8ec8cc33fc0fa2c41119e82b2b807aa89f..b3d7a613d26eba432308272b3bd932d2fdb54b26 100644 --- a/src/main/java/org/caosdb/server/entity/StatementStatus.java +++ b/src/main/java/org/caosdb/server/entity/StatementStatus.java @@ -22,12 +22,21 @@ */ package org.caosdb.server.entity; +/** + * The statement status has two purposes. + * + * <p>1. Storing the importance of an entity (any of OBLIGATORY, RECOMMENDED, SUGGESTED, or FIX). 2. + * Marking an entity as a REPLACEMENT which is needed for flat representation of deeply nested + * properties. This constant is only used for internal processes and has no meaning in the API. That + * is also the reason why this enum is not called "Importance". Apart from that, in most cases its + * meaning is identical to the importance of an entity. + * + * @author Timm Fitschen (t.fitschen@indiscale.com) + */ public enum StatementStatus { OBLIGATORY, RECOMMENDED, SUGGESTED, FIX, - SUBTYPING, - INHERITANCE, REPLACEMENT } diff --git a/src/main/java/org/caosdb/server/jobs/core/Inheritance.java b/src/main/java/org/caosdb/server/jobs/core/Inheritance.java index 3c08f9f281335c64a2af28ae131ff99d2c5ed6ca..086787e8bd4752ccf0a25f8684afa5a5c4a33c82 100644 --- a/src/main/java/org/caosdb/server/jobs/core/Inheritance.java +++ b/src/main/java/org/caosdb/server/jobs/core/Inheritance.java @@ -23,26 +23,36 @@ package org.caosdb.server.jobs.core; import java.util.ArrayList; +import java.util.List; import org.caosdb.server.database.backend.transaction.RetrieveFullEntity; import org.caosdb.server.entity.Entity; import org.caosdb.server.entity.EntityInterface; import org.caosdb.server.entity.Message; import org.caosdb.server.entity.Message.MessageType; +import org.caosdb.server.entity.StatementStatus; import org.caosdb.server.entity.wrapper.Property; import org.caosdb.server.jobs.EntityJob; import org.caosdb.server.transaction.Insert; import org.caosdb.server.transaction.Update; import org.caosdb.server.utils.EntityStatus; +/** + * Add all those properties from the parent to the child which have the same importance (or higher). + * + * @author Timm Fitschen (t.fitschen@indiscale.com) + */ public class Inheritance extends EntityJob { + /* + * Storing which properties of the properties of the parents should be inherited by the child. + */ public enum INHERITANCE_MODE { - NONE, - ALL, - OBLIGATORY, - FIX, - RECOMMENDED, - DONE + NONE, // inherit no properties from this parent + ALL, // inherit all inheritable properties, alias for suggested + OBLIGATORY, // inherit only obligatory properties + RECOMMENDED, // inherit obligatory and recommended properties + SUGGESTED, // inherit all inheritable properties, alias for all + FIX, // inherit fix properties only (deprecated) }; public static final Message ILLEGAL_INHERITANCE_MODE = @@ -66,51 +76,22 @@ public class Inheritance extends EntityJob { INHERITANCE_MODE.valueOf(parent.getFlags().get("inheritance").toUpperCase()); // mark inheritance flag as done - parent.setFlag("inheritance", "done"); - if (inheritance == INHERITANCE_MODE.NONE || inheritance == INHERITANCE_MODE.DONE) { + parent.setFlag("inheritance", null); + if (inheritance == INHERITANCE_MODE.NONE) { break parentLoop; } runJobFromSchedule(getEntity(), CheckParValid.class); - execute(new RetrieveFullEntity(parent)); - - if (parent.hasProperties()) { - // loop over all properties of the parent and - // collect - // properties to be transfered - for (final EntityInterface parProperty : parent.getProperties()) { - switch (inheritance) { - case ALL: - transfer.add(parProperty); - break; - case RECOMMENDED: - if (parProperty - .getStatementStatus() - .toString() - .equalsIgnoreCase(INHERITANCE_MODE.RECOMMENDED.toString())) { - transfer.add(parProperty); - } - case OBLIGATORY: - if (parProperty - .getStatementStatus() - .toString() - .equalsIgnoreCase(INHERITANCE_MODE.OBLIGATORY.toString())) { - transfer.add(parProperty); - } - case FIX: - if (parProperty - .getStatementStatus() - .toString() - .equalsIgnoreCase(INHERITANCE_MODE.FIX.toString())) { - transfer.add(parProperty); - } - break; - default: - break; - } - } + // try to get the parent entity from the current transaction container + EntityInterface foreign = getEntityByName(parent.getName()); + if (foreign == null) { + // was not in container -> retrieve from database. + execute(new RetrieveFullEntity(parent)); + foreign = parent; } + + collectInheritedProperties(transfer, foreign, inheritance); } catch (final IllegalArgumentException e) { parent.addWarning(ILLEGAL_INHERITANCE_MODE); break parentLoop; @@ -142,9 +123,10 @@ public class Inheritance extends EntityJob { } final INHERITANCE_MODE inheritance = INHERITANCE_MODE.valueOf(property.getFlags().get("inheritance").toUpperCase()); + // mark inheritance flag as done - property.setFlag("inheritance", "done"); - if (inheritance == INHERITANCE_MODE.NONE || inheritance == INHERITANCE_MODE.DONE) { + property.setFlag("inheritance", null); + if (inheritance == INHERITANCE_MODE.NONE) { break propertyLoop; } @@ -164,48 +146,14 @@ public class Inheritance extends EntityJob { } else { execute(new RetrieveFullEntity(validProperty)); } - - if (validProperty.getEntityStatus() == EntityStatus.VALID - && validProperty.hasProperties()) { - // loop over all properties of the property and - // collect - // properties to be transfered - for (final EntityInterface propProperty : validProperty.getProperties()) { - switch (inheritance) { - case ALL: - transfer.add(propProperty); - break; - case RECOMMENDED: - if (propProperty - .getStatementStatus() - .toString() - .equalsIgnoreCase(INHERITANCE_MODE.RECOMMENDED.toString())) { - transfer.add(propProperty); - } - case OBLIGATORY: - if (propProperty - .getStatementStatus() - .toString() - .equalsIgnoreCase(INHERITANCE_MODE.OBLIGATORY.toString())) { - transfer.add(propProperty); - } - case FIX: - if (propProperty - .getStatementStatus() - .toString() - .equalsIgnoreCase(INHERITANCE_MODE.FIX.toString())) { - transfer.add(propProperty); - } - break; - default: - break; - } - } + if (validProperty.getEntityStatus() == EntityStatus.VALID) { + collectInheritedProperties(transfer, validProperty, inheritance); } } catch (final IllegalArgumentException e) { property.addWarning(ILLEGAL_INHERITANCE_MODE); break propertyLoop; } + // transfer properties if they are not implemented yet outerLoop: for (final EntityInterface prop : transfer) { @@ -222,4 +170,52 @@ public class Inheritance extends EntityJob { } } } + + /** + * Put all those properties from the `from` entity into the `transfer` List which match the + * INHERITANCE_MODE. + * + * <p>That means: + * + * @param transfer + * @param from + * @param inheritance + */ + private void collectInheritedProperties( + List<EntityInterface> transfer, EntityInterface from, INHERITANCE_MODE inheritance) { + if (from.hasProperties()) { + for (final EntityInterface propProperty : from.getProperties()) { + switch (inheritance) { + // the following cases are ordered according to their importance level and use a + // fall-through. + case ALL: + case SUGGESTED: + if (propProperty.getStatementStatus() == StatementStatus.SUGGESTED) { + transfer.add(propProperty); + } + // fall-through! + case RECOMMENDED: + if (propProperty.getStatementStatus() == StatementStatus.RECOMMENDED) { + transfer.add(propProperty); + } + // fall-through! + case OBLIGATORY: + if (propProperty.getStatementStatus() == StatementStatus.OBLIGATORY) { + transfer.add(propProperty); + } + break; + case FIX: + if (propProperty.getStatementStatus() == StatementStatus.FIX) { + transfer.add(propProperty); + propProperty.addWarning( + new Message( + MessageType.Warning, + "DeprecationWarning: The inheritance of fix properties is deprecated and will be removed from the API in the near future. Clients have to copy fix properties by themselves, if necessary.")); + } + default: + break; + } + } + } + } }