All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pushtechnology.diffusion.examples.ClientUsingSessionLocks Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (C) 2018, 2023 DiffusionData Ltd.
 *
 * 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 com.pushtechnology.diffusion.examples;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.features.Topics;
import com.pushtechnology.diffusion.client.features.Topics.UnsubscribeReason;
import com.pushtechnology.diffusion.client.features.Topics.ValueStream;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.session.Session.SessionLock;
import com.pushtechnology.diffusion.client.session.Session.SessionLockScope;
import com.pushtechnology.diffusion.client.topics.details.TopicSpecification;
import com.pushtechnology.diffusion.client.types.PathPermission;

/**
 * An example of a client that uses session locks to coordinate actions with
 * other sessions.
 *
 * 

* In this example, a single session receives and processes updates from the * topic {@code topicA}. Each client instance running this code creates a * session and competes for the session lock {@code lockA}. The session that is * assigned the session lock will subscribe to the topic and log updates. * *

* {@link SessionLockScope#UNLOCK_ON_CONNECTION_LOSS UNLOCK_ON_CONNECTION_LOSS} * session locks are used. If the session that owns the session lock loses its * connection to the server, the server will reassign the lock to another * session. This example uses a session listener to independently detect the * connection loss, unsubscribe, unregister the stream listening for updates, * and compete for the lock again. * *

* The locking protocol has races documented under {@link SessionLock}. In the * context of this example, the consequences are: *

    *
  • There may be a transient period where two sessions are subscribed to the * topic, and both process the same update. *
  • A session acquiring a lock may miss one or more updates that were not * processed by the session that previously held the lock. *
* *

Security note

* *

* To run this example, the "client" principal must be granted * {@link PathPermission#ACQUIRE_LOCK ACQUIRE_LOCK} permission to * {@code lockA}. * * @author DiffusionData Limited * @since 6.1 */ public class ClientUsingSessionLocks { private static final Logger LOG = LoggerFactory.getLogger(ClientUsingSessionLocks.class); private static final String LOCK_NAME = "lockA"; private static final String TOPIC_PATH = "topicA"; private final Session session; private final ValueStream stream = new LogUpdates(); /** * Construct a request handling application. * * @param serverURL url of the server to connect to */ public ClientUsingSessionLocks(String serverURL) { // The "client" principal must have ACQUIRE_LOCK permission, see note in // class Javadoc. session = Diffusion.sessions().principal("client").password("password") .open(serverURL); } /** * Start competing for the lock. */ public void start() { session.addListener((s, oldState, newState) -> { if (newState.isClosed()) { onLockLost(); } }); requestLock(); } private void requestLock() { session.lock(LOCK_NAME, SessionLockScope.UNLOCK_ON_CONNECTION_LOSS) .thenAccept(lock -> onLockAcquired()); } private void onLockAcquired() { final Topics topics = session.feature(Topics.class); topics.subscribe(TOPIC_PATH); topics.addStream(TOPIC_PATH, String.class, stream); } private void onLockLost() { final Topics topics = session.feature(Topics.class); // Remove the stream from the local registry. This will prevent // processing of updates that may already be queued for this session and // will be delivered on reconnection. topics.removeStream(stream); // Unsubscribe from the topic. This will not take effect until this // session has reconnected to the server. topics.unsubscribe(TOPIC_PATH); // Compete for the lock again. This will not take effect until this // session has reconnected to the server, and will be processed after // the unsubscription. requestLock(); } /** * Close the session. If the session owned the lock, the server is free to * reassign it to another session. */ public void close() { session.close(); } /** * Log updates received for a topic. */ private static class LogUpdates extends Topics.ValueStream.Default { @Override public void onSubscription( String topicPath, TopicSpecification specification) { LOG.info("onSubscription({})", topicPath); } @Override public void onUnsubscription(String topicPath, TopicSpecification specification, UnsubscribeReason reason) { LOG.info("onUnsubscription({})", topicPath); } @Override public void onValue( String topicPath, TopicSpecification specification, String oldValue, String newValue) { LOG.info("onValue({}, {})", topicPath, newValue); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy