/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube 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 <http://www.gnu.org/licenses/>. */ package org.diqube.im; import org.diqube.consensus.ConsensusMethod; import org.diqube.consensus.ConsensusStateMachine; import org.diqube.consensus.ConsensusUtil; import org.diqube.im.thrift.v1.SUser; import io.atomix.copycat.Command; import io.atomix.copycat.Query; import io.atomix.copycat.server.Commit; /** * State machine for distributing information on users/passwords/ACLs across the cluster. * * @author Bastian Gloeckle */ @ConsensusStateMachine public interface IdentityStateMachine { /** * Sets properties of a user. */ @ConsensusMethod(dataClass = SetUser.class) public void setUser(Commit<SetUser> commit); /** * Retrieves information of a specific user. * * @return Either the {@link SUser} or <code>null</code> in case user does not exist. */ @ConsensusMethod(dataClass = GetUser.class, additionalSerializationClasses = SUser.class) public SUser getUser(Commit<GetUser> commit); /** * Delete a specific user. */ @ConsensusMethod(dataClass = DeleteUser.class) public void deleteUser(Commit<DeleteUser> commit); public static class DeleteUser implements Command<Void> { private static final long serialVersionUID = 1L; private String userName; public String getUserName() { return userName; } public static Commit<DeleteUser> local(String userName) { DeleteUser res = new DeleteUser(); res.userName = userName; return ConsensusUtil.localCommit(res); } @Override public CompactionMode compaction() { return CompactionMode.SEQUENTIAL; } } public static class SetUser implements Command<Void> { private static final long serialVersionUID = 1L; private SUser user; public SUser getUser() { return user; } public static Commit<SetUser> local(SUser user) { SetUser res = new SetUser(); res.user = user; return ConsensusUtil.localCommit(res); } @Override public CompactionMode compaction() { return CompactionMode.FULL; } } public static class GetUser implements Query<SUser> { private static final long serialVersionUID = 1L; private String userName; public String getUserName() { return userName; } @Override public ConsistencyLevel consistency() { return ConsistencyLevel.BOUNDED_LINEARIZABLE; } public static Commit<GetUser> local(String userName) { GetUser res = new GetUser(); res.userName = userName; return ConsensusUtil.localCommit(res); } } /** * Listener that will be called as soon as the state machine changed a user. * * <p> * Note that this is not reliable to be called in time (i.e. all other cluster nodes can have executed the change * already, but this node has fallen behind). Therefore this is no generally-available listener, but just one that * this package can use. */ /* package */ static interface UserChangedListener { /** * User information has changed/was deleted. See {@link UserChangedListener}. */ public void userChanged(String username); } }