diff --git a/conf/core/server.conf b/conf/core/server.conf index f831f074d1904b53b481f1ad9496c6093f7a8eed..81ae7c2c43232024549c523636cfad090996d0fd 100644 --- a/conf/core/server.conf +++ b/conf/core/server.conf @@ -145,7 +145,7 @@ MAIL_TO_FILE_HANDLER_LOC=./ # -------------------------------------------------- # Admin settings -# # -------------------------------------------------- +# -------------------------------------------------- # Name of the administrator of this instance ADMIN_NAME=CaosDB Admin # Email of the administrator of this instance @@ -183,3 +183,11 @@ CHECK_ENTITY_ACL_ROLES_MODE=MUST GLOBAL_ENTITY_PERMISSIONS_FILE=./conf/core/global_entity_permissions.xml ENTITY_VERSIONING_ENABLED=true + + +# -------------------------------------------------- +# Extension settings +# -------------------------------------------------- + +# Enabling the state machine extension +# EXT_STATE_ENTITY=ENABLE diff --git a/src/main/java/org/caosdb/server/entity/ClientMessage.java b/src/main/java/org/caosdb/server/entity/ClientMessage.java index 40a8c713deafc1cce5f8343a2fa8d15cb054ee17..f6b996770b1d1d88992a56551acc0d5aaa5db1f0 100644 --- a/src/main/java/org/caosdb/server/entity/ClientMessage.java +++ b/src/main/java/org/caosdb/server/entity/ClientMessage.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.entity; import java.util.HashMap; @@ -12,7 +35,7 @@ import org.jdom2.Element; * * <p>If no plug-in handles the client message, it is printed back to the response unaltered. * - * <p>Client message can have arbitrary key-value tuples {@link #properties}. + * <p>Client message can have arbitrary key-value (string-string typed) tuples {@link #properties}. * * @author Timm Fitschen (t.fitschen@indiscale.com) */ @@ -40,6 +63,7 @@ public class ClientMessage extends Message { parent.addContent(e); } + /** NB: This is the only place where properties are set in this class. */ public static ClientMessage fromXML(Element pe) { ClientMessage result = new ClientMessage(pe.getName(), pe.getText()); for (Attribute a : pe.getAttributes()) { diff --git a/src/main/java/org/caosdb/server/jobs/ScheduledJob.java b/src/main/java/org/caosdb/server/jobs/ScheduledJob.java index d9fa9c42a8a2e703c48d2b9a841ddfdfd0e40017..ee0c29805d7500987f5823f2c7d3eaec8f6ed50b 100644 --- a/src/main/java/org/caosdb/server/jobs/ScheduledJob.java +++ b/src/main/java/org/caosdb/server/jobs/ScheduledJob.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.jobs; /** diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java b/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java index ef3c8b270ceee19549cd2128480d2a70bfaeb31b..cd187cf17ad72c5431fcd3f2eb0b95890941faf9 100644 --- a/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java +++ b/src/main/java/org/caosdb/server/jobs/core/CheckStateTransition.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.jobs.core; import java.util.Map; @@ -14,6 +37,9 @@ import org.caosdb.server.utils.ServerMessages; /** * Check if the attempted state transition is allowed. * + * <p>This job checks if the attempted state transition is in compliance with the state model. This + * job runs during the CHECK phase and should do all necessary consistency and permission checks. + * * @author Timm Fitschen (t.fitschen@indiscale.com) */ @JobAnnotation(time = JobExecutionTime.POST_CHECK, transaction = WriteTransaction.class) @@ -47,7 +73,7 @@ public class CheckStateTransition extends EntityStateJob { checkStateTransition(oldState, newState); } else if (getEntity() instanceof DeleteEntity) { if (newState != null) checkFinalState(newState); - } else { + } else { // fresh Entity if (newState != null) checkInitialState(newState); } } catch (Message m) { @@ -61,6 +87,8 @@ public class CheckStateTransition extends EntityStateJob { /** * Check if the state belongs to the state model. * + * <p>In practical terms, throw a Message if the state is invalid. + * * @param state * @throws Message */ @@ -74,6 +102,10 @@ public class CheckStateTransition extends EntityStateJob { /** * Check if state is valid and transition is allowed. * + * <p>Especially, transitions between {@code null} states are allowed, non-trivial transitions + * from or to {@code null} must be initial or final states, respectively ({@link + * FORCE_FINAL_STATE} exception applies). + * * @param oldState * @param newState * @throws Message if not @@ -115,6 +147,8 @@ public class CheckStateTransition extends EntityStateJob { } /** + * Return the two State's common StateModel, or {@code null} if they don't have one in common. + * * @param oldState * @param newState * @return the state model which contains both of the states. diff --git a/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java b/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java index d1a2888ad2a0fd16e51febf427fe80778dc654d8..86b65fa8b8e875b700b947b8e63bf175e7a7c511 100644 --- a/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java +++ b/src/main/java/org/caosdb/server/jobs/core/EntityStateJob.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.jobs.core; import java.util.ArrayList; @@ -35,24 +58,25 @@ import org.caosdb.server.utils.EntityStatus; import org.jdom2.Element; /** - * The EntityStateJob is the abstract base class for four EntityJobs. + * The EntityStateJob is the abstract base class for four EntityJobs: * - * <p>1. The InitEntityState job reads ClientMessages or StateProperties with tag state and converts - * them into instances of State. This job runs during WriteTransactions. This job runs during the - * INIT Phase and does not perform any checks other than those necessary for the conversion. + * <p>1. The {@link InitEntityState} job reads ClientMessages or StateProperties with tag state and + * converts them into instances of State. This job runs during WriteTransactions. This job runs + * during the INIT Phase and does not perform any checks other than those necessary for the + * conversion. * - * <p>2. The CheckStateTransition job checks if the attempted state transition is in compliance with - * the state model. This job runs during the CHECK phase and should do all necessary consistency and - * permission checks. + * <p>2. The {@link CheckStateTransition} job checks if the attempted state transition is in + * compliance with the state model. This job runs during the CHECK phase and should do all necessary + * consistency and permission checks. * - * <p>3. The MakeStateProperty job constructs an ordinary Property from the State right before the - * entity is being written to the back-end and after any checks run. + * <p>3. The {@link MakeStateProperty} job constructs an ordinary Property from the State right + * before the entity is being written to the back-end and after any checks run. * - * <p>4. The MakeStateMessage job converts a state property (back) into State messages and appends - * them to the entity. + * <p>4. The {@link MakeStateMessage} job converts a state property (back) into State messages and + * appends them to the entity. * - * <p>Only the 4th job runs during Retrieve transitions. During WriteTransactions all four jobs do - * run. + * <p>Only the 4th job ({@link MakeStateMessage}) runs during Retrieve transitions. During + * WriteTransactions all four jobs do run. * * @author Timm Fitschen (t.fitschen@indiscale.com) */ @@ -110,6 +134,10 @@ public abstract class EntityStateJob extends EntityJob { private State toState; private Map<String, String> transitionProperties; + /** + * @param transition The transition Entity, from which the Transition is created. Relevant + * Properties are "to" and "from" + */ public Transition(EntityInterface transition) throws Message { this.name = transition.getName(); this.description = transition.getDescription(); @@ -230,9 +258,9 @@ public abstract class EntityStateJob extends EntityJob { } /** - * The State instance represents a single entity state. This class is used for concrete state (the - * state of a stateful entity, say a Record) and abstract states (states which belong to a - * StateModel entity). + * The State instance represents a single entity state. This class is used for concrete states + * (the state of a stateful entity, say a Record) and abstract states (states which are part of a + * {@link StateModel}). * * <p>States are identified via their name and the name of the model to which they belong. * @@ -240,8 +268,8 @@ public abstract class EntityStateJob extends EntityJob { * StateModel iff the StateModel RecordType references the State Record. Each State should only * belong to one StateModel. * - * <p>Furthermore, States are the start or end point of Transitions which belong to the same - * StateModel. Each State can be part of several transitions at the same time. + * <p>Furthermore, States are the start or end point of {@link Transition Transitions} which + * belong to the same StateModel. Each State can be part of several transitions at the same time. * * <p>Note: The purpose of this should not be confused with {@link EntityStatus} which is purely * for internal use. @@ -261,6 +289,7 @@ public abstract class EntityStateJob extends EntityJob { private Map<String, String> stateProperties; public State(String stateName, String stateModelName) throws Message { + // TODO Make constructors private or protected and outsource to caching factory methods. this.stateName = stateName; this.stateModelName = stateModelName; } @@ -326,7 +355,12 @@ public abstract class EntityStateJob extends EntityJob { return 21364234 + this.getStateName().hashCode() + this.getStateModelName().hashCode(); } - /** Serialize this State into XML. */ + /** + * Serialize this State into XML. + * + * <p>The result looks approximately like this: {@code <State name="My name" model="Model's + * name"/>} + */ @Override public void addToElement(Element ret) { Element e = new Element(STATE_XML_TAG); @@ -400,7 +434,7 @@ public abstract class EntityStateJob extends EntityJob { } /** - * Create a property which represents the current entity state of a stateful entity. + * Create a Property which represents the current entity state of a stateful entity. * * @return stateProperty * @throws Message @@ -433,7 +467,27 @@ public abstract class EntityStateJob extends EntityJob { @Override public String toString() { - return "State (name=" + getStateName() + ", model=" + getStateModelName() + ")"; + String isInitial = null; + String isFinal = null; + try { + isInitial = String.valueOf(isInitial()); + } catch (Message e) { + isInitial = "null"; + } + try { + isFinal = String.valueOf(isFinal()); + } catch (Message e) { + isFinal = "null"; + } + return "State (name=" + + getStateName() + + ", model=" + + getStateModelName() + + ", initial=" + + isInitial + + ", final=" + + isFinal + + ")"; } } @@ -468,6 +522,7 @@ public abstract class EntityStateJob extends EntityJob { } private State getInitialState(EntityInterface stateModelEntity) throws Message { + // TODO maybe check if there is more than one "initial" Property? for (Property p : stateModelEntity.getProperties()) { if (p.getName().equals(INITIAL_STATE_PROPERTY_NAME)) { return createState(p); @@ -477,6 +532,7 @@ public abstract class EntityStateJob extends EntityJob { } private State getFinalState(EntityInterface stateModelEntity) throws Message { + // TODO maybe check if there is more than one "final" Property? for (Property p : stateModelEntity.getProperties()) { if (p.getName().equals(FINAL_STATE_PROPERTY_NAME)) { return createState(p); @@ -485,6 +541,7 @@ public abstract class EntityStateJob extends EntityJob { return null; } + /** Transitions are taken from list Property with name="Transition". */ private Set<Transition> getTransitions(EntityInterface stateModelEntity) throws Message { for (Property p : stateModelEntity.getProperties()) { if (p.getName().equals(TRANSITION_RECORD_TYPE_NAME)) { @@ -505,6 +562,7 @@ public abstract class EntityStateJob extends EntityJob { Set<Transition> result = new LinkedHashSet<>(); try { if (!(p.getDatatype() instanceof AbstractCollectionDatatype)) { + // FIXME raise an exception instead? return result; } p.parseValue(); @@ -535,6 +593,7 @@ public abstract class EntityStateJob extends EntityJob { */ private Set<State> getStates(Set<Transition> transitions, StateModel stateModel) throws Message { + // TODO Move outside of this class Iterator<Transition> it = transitions.iterator(); Set<State> result = new LinkedHashSet<>(); while (it.hasNext()) { @@ -585,7 +644,9 @@ public abstract class EntityStateJob extends EntityJob { Iterator<Transition> iterator = this.transitions.iterator(); while (iterator.hasNext()) { sb.append(iterator.next().name); + sb.append(" -> "); sb.append(iterator.next().name); + sb.append(", "); } sb.append("])"); return sb.toString(); @@ -638,6 +699,7 @@ public abstract class EntityStateJob extends EntityJob { return getState(getEntity(), remove); } + /** Return (and possibly remove) the States Properties of `entity`. */ protected List<Property> getStateProperties(EntityInterface entity, boolean remove) { Iterator<Property> it = entity.getProperties().iterator(); List<Property> result = new ArrayList<>(); @@ -660,6 +722,7 @@ public abstract class EntityStateJob extends EntityJob { return getStateProperties(getEntity(), remove); } + /** Get the {@code ClientMessage}s which denote a state. */ protected List<ClientMessage> getStateClientMessages(EntityInterface entity, boolean remove) { Iterator<Message> stateMessages = entity.getMessages(STATE_XML_TAG).iterator(); List<ClientMessage> result = new ArrayList<>(); @@ -694,13 +757,15 @@ public abstract class EntityStateJob extends EntityJob { /** * Create a State instance from the value of the state property. * - * <p>This method also retrieves the state entity from the back-end. + * <p>This method also retrieves the state entity from the back-end. The StateModel is deduced + * from finding an appropriately referencing StateModel Record. * * @param p the entity's state property * @return The state of the entity * @throws Message */ protected State createState(Property p) throws Message { + // TODO this should be cached try { p.parseValue(); ReferenceValue refid = (ReferenceValue) p.getValue(); @@ -730,6 +795,7 @@ public abstract class EntityStateJob extends EntityJob { if (result != null && cached) { return result; } + // TODO This should throw a meaningful Exception if no matching StateModel can be found. TransactionContainer c = new TransactionContainer(); Query query = new Query( diff --git a/src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java b/src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java index 2afcd0eeea96636b4a1a3da499b67cdc3a5c591e..5093d86a66a9524566fecc127b18fd034f607212 100644 --- a/src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java +++ b/src/main/java/org/caosdb/server/jobs/core/InitEntityStateJobs.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.jobs.core; import java.util.ArrayList; @@ -21,8 +44,8 @@ import org.caosdb.server.utils.Observable; import org.caosdb.server.utils.Observer; /** - * Initialize the other entity jobs by converting the client message with type "State" into {@link - * State} instances. + * Initialize the other entity jobs by converting the client message with type "State" or + * StateProperties into {@link State} instances. * * <p>This job also needs to initialize the other jobs even if the current entity version does not * have a state anymore but the previous version had, because it has to be checked if the stateModel @@ -124,7 +147,8 @@ public class InitEntityStateJobs extends EntityStateJob implements Observer { } /** - * Returns a list of states as the are represented as properties or client messages in the entity. + * Return a list of states from their representations as properties or client messages in the + * entity. * * @param entity * @return list of state instances for the entity. diff --git a/src/main/java/org/caosdb/server/jobs/core/MakeStateMessage.java b/src/main/java/org/caosdb/server/jobs/core/MakeStateMessage.java index f47c1157cc529832175593bb1d56262557e88dc2..b0fc4bad949588d3a34c64f9fc1d5acf6135d0cb 100644 --- a/src/main/java/org/caosdb/server/jobs/core/MakeStateMessage.java +++ b/src/main/java/org/caosdb/server/jobs/core/MakeStateMessage.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.jobs.core; import java.util.List; diff --git a/src/main/java/org/caosdb/server/jobs/core/MakeStateProperty.java b/src/main/java/org/caosdb/server/jobs/core/MakeStateProperty.java index 0d290c0fb43d258d0f4700d60422c5a7541abf82..56682921563d77f462903567a2c128fcd5d92555 100644 --- a/src/main/java/org/caosdb/server/jobs/core/MakeStateProperty.java +++ b/src/main/java/org/caosdb/server/jobs/core/MakeStateProperty.java @@ -1,3 +1,26 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ + package org.caosdb.server.jobs.core; import org.caosdb.server.entity.Message; @@ -5,6 +28,10 @@ import org.caosdb.server.jobs.JobAnnotation; import org.caosdb.server.jobs.JobExecutionTime; import org.caosdb.server.transaction.WriteTransaction; +/** + * This job constructs an ordinary Property from the State right before the entity is being written + * to the back-end and after any checks run. + */ @JobAnnotation(transaction = WriteTransaction.class, time = JobExecutionTime.PRE_TRANSACTION) public class MakeStateProperty extends EntityStateJob { diff --git a/src/main/java/org/caosdb/server/transaction/Update.java b/src/main/java/org/caosdb/server/transaction/Update.java index 50d7f97868c2b5078292483ca6758c8be482305d..894728ccb7ed6c1e3eb72d40d6ea821e9e92ee68 100644 --- a/src/main/java/org/caosdb/server/transaction/Update.java +++ b/src/main/java/org/caosdb/server/transaction/Update.java @@ -4,6 +4,8 @@ * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> + * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as diff --git a/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java b/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java index dc93549a4e5a65d474043f109d136048c37d6146..330ce5907f601b4b4345c26b1d483029f7d049b1 100644 --- a/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/UpdateUserTransaction.java @@ -78,7 +78,7 @@ public class UpdateUserTransaction extends AccessControlTransaction { + this.user.realm + "' cannot be updated. Only the users from the realm '" + UserSources.getInternalRealm().getName() - + "' can change their passwords from withing caosdb."); + + "' can change their passwords from within caosdb."); } SecurityUtils.getSubject() diff --git a/src/main/java/org/caosdb/server/utils/AbstractObservable.java b/src/main/java/org/caosdb/server/utils/AbstractObservable.java index a19fff9d44ce7339a9cdc6712e0806ef42bdfd40..abc7f0a0ae1cdcbeff613c2778637de97a507c57 100644 --- a/src/main/java/org/caosdb/server/utils/AbstractObservable.java +++ b/src/main/java/org/caosdb/server/utils/AbstractObservable.java @@ -37,6 +37,7 @@ public abstract class AbstractObservable implements Observable { return this.observers.add(o); } + /** @param e A String denoting the notification event. */ @Override public void notifyObservers(final String e) { if (this.observers != null) { diff --git a/src/main/java/org/caosdb/server/utils/Observer.java b/src/main/java/org/caosdb/server/utils/Observer.java index be89dff4b882adf24bcfd250c3dea1387997360d..b4c8f5444b957a1d18efc7f864c67b3daff8ca33 100644 --- a/src/main/java/org/caosdb/server/utils/Observer.java +++ b/src/main/java/org/caosdb/server/utils/Observer.java @@ -25,6 +25,8 @@ package org.caosdb.server.utils; public interface Observer { /** + * Notify this observer that an event {@code e} has happened to the {@code sender}. + * * @param e * @param sender * @return true, iff the Observable has to keep it in the list of observers.