[HELIX-259] Add HelixConnection usage to the logical model example code
Project: http://git-wip-us.apache.org/repos/asf/incubator-helix/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-helix/commit/0839afa8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-helix/tree/0839afa8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-helix/diff/0839afa8 Branch: refs/heads/master Commit: 0839afa8c8e616296491031c6faeef9659e566ab Parents: 8cb38a5 Author: Kanak Biscuitwala <[email protected]> Authored: Wed Nov 6 13:09:27 2013 -0800 Committer: Kanak Biscuitwala <[email protected]> Committed: Wed Nov 6 13:17:38 2013 -0800 ---------------------------------------------------------------------- .../java/org/apache/helix/HelixManager.java | 6 +- .../helix/api/accessor/ResourceAccessor.java | 9 + helix-examples/pom.xml | 4 + .../helix/examples/LogicalModelExample.java | 298 +++++++++++++++++++ .../apache/helix/examples/NewModelExample.java | 199 ------------- 5 files changed, 316 insertions(+), 200 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/0839afa8/helix-core/src/main/java/org/apache/helix/HelixManager.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/HelixManager.java b/helix-core/src/main/java/org/apache/helix/HelixManager.java index 808705b..24f8f1e 100644 --- a/helix-core/src/main/java/org/apache/helix/HelixManager.java +++ b/helix-core/src/main/java/org/apache/helix/HelixManager.java @@ -23,6 +23,7 @@ import java.util.List; import org.apache.helix.controller.GenericHelixController; import org.apache.helix.healthcheck.ParticipantHealthReportCollector; +import org.apache.helix.manager.zk.ZKHelixManager; import org.apache.helix.model.HelixConfigScope.ConfigScopeProperty; import org.apache.helix.participant.HelixStateMachineEngine; import org.apache.helix.participant.StateMachineEngine; @@ -33,6 +34,7 @@ import org.apache.helix.store.zk.ZkHelixPropertyStore; * Class that represents the Helix Agent. * First class Object any process will interact with<br/> * General flow <blockquote> + * * <pre> * manager = HelixManagerFactory.getZKHelixManager( * clusterName, instanceName, ROLE, zkAddr); @@ -47,6 +49,7 @@ import org.apache.helix.store.zk.ZkHelixPropertyStore; * FINALIZE -> will be invoked when listener is removed or session expires * manager.disconnect() * </pre> + * * </blockquote> Default implementations available * @see HelixStateMachineEngine HelixStateMachineEngine for participant * @see RoutingTableProvider RoutingTableProvider for spectator @@ -54,7 +57,8 @@ import org.apache.helix.store.zk.ZkHelixPropertyStore; */ public interface HelixManager { - public static final String ALLOW_PARTICIPANT_AUTO_JOIN = "ALLOW_PARTICIPANT_AUTO_JOIN"; + public static final String ALLOW_PARTICIPANT_AUTO_JOIN = + ZKHelixManager.ALLOW_PARTICIPANT_AUTO_JOIN; /** * Start participating in the cluster operations. All listeners will be http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/0839afa8/helix-core/src/main/java/org/apache/helix/api/accessor/ResourceAccessor.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/api/accessor/ResourceAccessor.java b/helix-core/src/main/java/org/apache/helix/api/accessor/ResourceAccessor.java index 670d167..f24b5b1 100644 --- a/helix-core/src/main/java/org/apache/helix/api/accessor/ResourceAccessor.java +++ b/helix-core/src/main/java/org/apache/helix/api/accessor/ResourceAccessor.java @@ -270,6 +270,15 @@ public class ResourceAccessor { } /** + * get the external view of a resource + * @param resourceId the resource to look up + * @return external view or null + */ + public ExternalView readExternalView(ResourceId resourceId) { + return _accessor.getProperty(_keyBuilder.externalView(resourceId.stringify())); + } + + /** * drop external view of a resource * @param resourceId * @return true if dropped, false otherwise http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/0839afa8/helix-examples/pom.xml ---------------------------------------------------------------------- diff --git a/helix-examples/pom.xml b/helix-examples/pom.xml index 6c00af6..fca2d97 100644 --- a/helix-examples/pom.xml +++ b/helix-examples/pom.xml @@ -79,6 +79,10 @@ under the License. <mainClass>org.apache.helix.examples.Quickstart</mainClass> <name>quickstart</name> </program> + <program> + <mainClass>org.apache.helix.examples.LogicalModelExample</mainClass> + <name>run-logical-model-example</name> + </program> </programs> </configuration> </plugin> http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/0839afa8/helix-examples/src/main/java/org/apache/helix/examples/LogicalModelExample.java ---------------------------------------------------------------------- diff --git a/helix-examples/src/main/java/org/apache/helix/examples/LogicalModelExample.java b/helix-examples/src/main/java/org/apache/helix/examples/LogicalModelExample.java new file mode 100644 index 0000000..2f5a28b --- /dev/null +++ b/helix-examples/src/main/java/org/apache/helix/examples/LogicalModelExample.java @@ -0,0 +1,298 @@ +package org.apache.helix.examples; + +import java.util.List; +import java.util.Map; + +import org.apache.helix.HelixConnection; +import org.apache.helix.HelixController; +import org.apache.helix.HelixParticipant; +import org.apache.helix.NotificationContext; +import org.apache.helix.api.Partition; +import org.apache.helix.api.Scope; +import org.apache.helix.api.State; +import org.apache.helix.api.accessor.ClusterAccessor; +import org.apache.helix.api.accessor.ParticipantAccessor; +import org.apache.helix.api.accessor.ResourceAccessor; +import org.apache.helix.api.config.ClusterConfig; +import org.apache.helix.api.config.ParticipantConfig; +import org.apache.helix.api.config.ResourceConfig; +import org.apache.helix.api.config.UserConfig; +import org.apache.helix.api.id.ClusterId; +import org.apache.helix.api.id.ControllerId; +import org.apache.helix.api.id.ParticipantId; +import org.apache.helix.api.id.PartitionId; +import org.apache.helix.api.id.ResourceId; +import org.apache.helix.api.id.StateModelDefId; +import org.apache.helix.controller.rebalancer.context.FullAutoRebalancerContext; +import org.apache.helix.manager.zk.ZkHelixConnection; +import org.apache.helix.model.ExternalView; +import org.apache.helix.model.Message; +import org.apache.helix.model.StateModelDefinition; +import org.apache.helix.model.Transition; +import org.apache.helix.participant.statemachine.HelixStateModelFactory; +import org.apache.helix.participant.statemachine.StateModel; +import org.apache.helix.participant.statemachine.StateModelInfo; +import org.apache.log4j.Logger; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Example showing all major interactions with the new Helix logical model + */ +public class LogicalModelExample { + private static final Logger LOG = Logger.getLogger(LogicalModelExample.class); + + public static void main(String[] args) throws InterruptedException { + if (args.length < 1) { + LOG.error("USAGE: LogicalModelExample zkAddress"); + System.exit(1); + } + + // get a state model definition + StateModelDefinition lockUnlock = getLockUnlockModel(); + + // set up a resource with the state model definition + ResourceConfig resource = getResource(lockUnlock); + + // set up a participant + ParticipantConfig participant = getParticipant(); + + // cluster id should be unique + ClusterId clusterId = ClusterId.from("exampleCluster"); + + // a user config is an object that stores arbitrary keys and values for a scope + // in this case, the scope is the cluster with id clusterId + // this is optional + UserConfig userConfig = new UserConfig(Scope.cluster(clusterId)); + userConfig.setIntField("sampleInt", 1); + + // fully specify the cluster with a ClusterConfig + ClusterConfig.Builder clusterBuilder = + new ClusterConfig.Builder(clusterId).addResource(resource).addParticipant(participant) + .addStateModelDefinition(lockUnlock).userConfig(userConfig).autoJoin(true); + + // add a state constraint that is more restrictive than what is in the state model + clusterBuilder.addStateUpperBoundConstraint(Scope.cluster(clusterId), + lockUnlock.getStateModelDefId(), State.from("LOCKED"), 1); + + // add a transition constraint (this time with a resource scope) + clusterBuilder.addTransitionConstraint(Scope.resource(resource.getId()), + lockUnlock.getStateModelDefId(), + Transition.from(State.from("RELEASED"), State.from("LOCKED")), 1); + + ClusterConfig cluster = clusterBuilder.build(); + + // set up a connection to work with ZooKeeper-persisted data + HelixConnection connection = new ZkHelixConnection(args[0]); + connection.connect(); + + // create the cluster + createCluster(cluster, connection); + + // update the resource + updateResource(resource, clusterId, connection); + + // update the participant + updateParticipant(participant, clusterId, connection); + + // start the controller + ControllerId controllerId = ControllerId.from("exampleController"); + HelixController helixController = connection.createController(clusterId, controllerId); + helixController.startAsync(); + + // start the specified participant + HelixParticipant helixParticipant = + connection.createParticipant(clusterId, participant.getId()); + helixParticipant.getStateMachineEngine().registerStateModelFactory( + lockUnlock.getStateModelDefId(), new LockUnlockFactory()); + helixParticipant.startAsync(); + + // start another participant via auto join + HelixParticipant autoJoinParticipant = + connection.createParticipant(clusterId, ParticipantId.from("localhost_12120")); + autoJoinParticipant.getStateMachineEngine().registerStateModelFactory( + lockUnlock.getStateModelDefId(), new LockUnlockFactory()); + autoJoinParticipant.startAsync(); + + Thread.sleep(5000); + printExternalView(connection, clusterId, resource.getId()); + + // stop the participants + helixParticipant.stopAsync(); + autoJoinParticipant.stopAsync(); + + // stop the controller + helixParticipant.stopAsync(); + + // drop the cluster + Thread.sleep(5000); + dropCluster(clusterId, connection); + connection.disconnect(); + } + + private static void dropCluster(ClusterId clusterId, HelixConnection connection) { + ClusterAccessor accessor = connection.createClusterAccessor(clusterId); + accessor.dropCluster(); + } + + private static void printExternalView(HelixConnection connection, ClusterId clusterId, + ResourceId resourceId) { + ResourceAccessor accessor = connection.createResourceAccessor(clusterId); + ExternalView externalView = accessor.readExternalView(resourceId); + System.out.println("ASSIGNMENTS:"); + for (PartitionId partitionId : externalView.getPartitionIdSet()) { + System.out.println(partitionId + ": " + externalView.getStateMap(partitionId)); + } + } + + private static void updateParticipant(ParticipantConfig participant, ClusterId clusterId, + HelixConnection connection) { + // add a tag to the participant and change the hostname, then update it using a delta + ParticipantAccessor accessor = connection.createParticipantAccessor(clusterId); + ParticipantConfig.Delta delta = + new ParticipantConfig.Delta(participant.getId()).addTag("newTag").setHostName("newHost"); + accessor.updateParticipant(participant.getId(), delta); + } + + private static void updateResource(ResourceConfig resource, ClusterId clusterId, + HelixConnection connection) { + // add some fields to the resource user config, then update it using the resource config delta + ResourceAccessor accessor = connection.createResourceAccessor(clusterId); + UserConfig userConfig = resource.getUserConfig(); + Map<String, String> mapField = Maps.newHashMap(); + mapField.put("k1", "v1"); + mapField.put("k2", "v2"); + userConfig.setMapField("sampleMap", mapField); + ResourceConfig.Delta delta = + new ResourceConfig.Delta(resource.getId()).setUserConfig(userConfig); + accessor.updateResource(resource.getId(), delta); + } + + private static void createCluster(ClusterConfig cluster, HelixConnection connection) { + ClusterAccessor accessor = connection.createClusterAccessor(cluster.getId()); + accessor.createCluster(cluster); + } + + private static ParticipantConfig getParticipant() { + // identify the participant + ParticipantId participantId = ParticipantId.from("localhost_0"); + + // create (optional) participant user config properties + UserConfig userConfig = new UserConfig(Scope.participant(participantId)); + List<String> sampleList = Lists.newArrayList("elem1", "elem2"); + userConfig.setListField("sampleList", sampleList); + + // create the configuration of a new participant + ParticipantConfig.Builder participantBuilder = + new ParticipantConfig.Builder(participantId).hostName("localhost").port(0) + .userConfig(userConfig); + return participantBuilder.build(); + } + + private static ResourceConfig getResource(StateModelDefinition stateModelDef) { + // identify the resource + ResourceId resourceId = ResourceId.from("exampleResource"); + + // create a partition + Partition partition1 = new Partition(PartitionId.from(resourceId, "1")); + + // create a second partition + Partition partition2 = new Partition(PartitionId.from(resourceId, "2")); + + // specify the rebalancer configuration + // this resource will be rebalanced in FULL_AUTO mode, so use the FullAutoRebalancerContext + // builder + FullAutoRebalancerContext.Builder rebalanceContextBuilder = + new FullAutoRebalancerContext.Builder(resourceId).replicaCount(1).addPartition(partition1) + .addPartition(partition2).stateModelDefId(stateModelDef.getStateModelDefId()); + + // create (optional) user-defined configuration properties for the resource + UserConfig userConfig = new UserConfig(Scope.resource(resourceId)); + userConfig.setBooleanField("sampleBoolean", true); + + // create the configuration for a new resource + ResourceConfig.Builder resourceBuilder = + new ResourceConfig.Builder(resourceId).rebalancerContext(rebalanceContextBuilder.build()) + .userConfig(userConfig); + return resourceBuilder.build(); + } + + private static StateModelDefinition getLockUnlockModel() { + final State LOCKED = State.from("LOCKED"); + final State RELEASED = State.from("RELEASED"); + final State DROPPED = State.from("DROPPED"); + StateModelDefId stateModelId = StateModelDefId.from("LockUnlock"); + StateModelDefinition.Builder stateModelBuilder = + new StateModelDefinition.Builder(stateModelId).addState(LOCKED, 0).addState(RELEASED, 1) + .addState(DROPPED, 2).addTransition(RELEASED, LOCKED, 0) + .addTransition(LOCKED, RELEASED, 1).addTransition(RELEASED, DROPPED, 2) + .upperBound(LOCKED, 1).upperBound(RELEASED, -1).upperBound(DROPPED, -1) + .initialState(RELEASED); + return stateModelBuilder.build(); + } + + /** + * Dummy state model that just prints state transitions for the lock-unlock model + */ + @StateModelInfo(initialState = "OFFLINE", states = { + "LOCKED", "RELEASED", "DROPPED", "ERROR" + }) + public static class LockUnlockStateModel extends StateModel { + private final PartitionId _partitionId; + + /** + * Instantiate for a partition + * @param partitionId the partition for which to track state transitions + */ + public LockUnlockStateModel(PartitionId partitionId) { + _partitionId = partitionId; + } + + public void onBecomeLockedFromReleased(Message message, NotificationContext context) { + onBecomeAnyFromAny(message, context); + } + + public void onBecomeReleasedFromLocked(Message message, NotificationContext context) { + onBecomeAnyFromAny(message, context); + } + + public void onBecomeDroppedFromReleased(Message message, NotificationContext context) { + onBecomeAnyFromAny(message, context); + } + + public void onBecomeAnyFromAny(Message message, NotificationContext context) { + System.out.println("Partition " + _partitionId + " transition from " + message.getFromState() + + " to " + message.getToState()); + } + } + + /** + * State model factory for lock-unlock + */ + public static class LockUnlockFactory extends HelixStateModelFactory<LockUnlockStateModel> { + @Override + public LockUnlockStateModel createNewStateModel(PartitionId partitionId) { + return new LockUnlockStateModel(partitionId); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/0839afa8/helix-examples/src/main/java/org/apache/helix/examples/NewModelExample.java ---------------------------------------------------------------------- diff --git a/helix-examples/src/main/java/org/apache/helix/examples/NewModelExample.java b/helix-examples/src/main/java/org/apache/helix/examples/NewModelExample.java deleted file mode 100644 index 7215707..0000000 --- a/helix-examples/src/main/java/org/apache/helix/examples/NewModelExample.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.apache.helix.examples; - -import java.util.List; -import java.util.Map; - -import org.apache.helix.BaseDataAccessor; -import org.apache.helix.HelixDataAccessor; -import org.apache.helix.ZNRecord; -import org.apache.helix.api.Partition; -import org.apache.helix.api.Scope; -import org.apache.helix.api.State; -import org.apache.helix.api.accessor.ClusterAccessor; -import org.apache.helix.api.accessor.ParticipantAccessor; -import org.apache.helix.api.accessor.ResourceAccessor; -import org.apache.helix.api.config.ClusterConfig; -import org.apache.helix.api.config.ParticipantConfig; -import org.apache.helix.api.config.ResourceConfig; -import org.apache.helix.api.config.UserConfig; -import org.apache.helix.api.id.ClusterId; -import org.apache.helix.api.id.ParticipantId; -import org.apache.helix.api.id.PartitionId; -import org.apache.helix.api.id.ResourceId; -import org.apache.helix.api.id.StateModelDefId; -import org.apache.helix.controller.rebalancer.context.FullAutoRebalancerContext; -import org.apache.helix.manager.zk.ZKHelixDataAccessor; -import org.apache.helix.manager.zk.ZkBaseDataAccessor; -import org.apache.helix.manager.zk.ZkClient; -import org.apache.helix.model.StateModelDefinition; -import org.apache.helix.model.Transition; -import org.apache.helix.util.ZKClientPool; -import org.apache.log4j.Logger; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -/** - * Example showing all major interactions with the new Helix logical model - */ -public class NewModelExample { - private static final Logger LOG = Logger.getLogger(NewModelExample.class); - - public static void main(String[] args) { - if (args.length < 1) { - LOG.error("USAGE: NewModelExample zkAddress"); - System.exit(1); - } - - // get a state model definition - StateModelDefinition lockUnlock = getLockUnlockModel(); - - // set up a resource with the state model definition - ResourceConfig resource = getResource(lockUnlock); - - // set up a participant - ParticipantConfig participant = getParticipant(); - - // cluster id should be unique - ClusterId clusterId = ClusterId.from("exampleCluster"); - - // a user config is an object that stores arbitrary keys and values for a scope - // in this case, the scope is the cluster with id clusterId - // this is optional - UserConfig userConfig = new UserConfig(Scope.cluster(clusterId)); - userConfig.setIntField("sampleInt", 1); - - // fully specify the cluster with a ClusterConfig - ClusterConfig.Builder clusterBuilder = - new ClusterConfig.Builder(clusterId).addResource(resource).addParticipant(participant) - .addStateModelDefinition(lockUnlock).userConfig(userConfig); - - // add a state constraint that is more restrictive than what is in the state model - clusterBuilder.addStateUpperBoundConstraint(Scope.cluster(clusterId), - lockUnlock.getStateModelDefId(), State.from("LOCKED"), 1); - - // add a transition constraint (this time with a resource scope) - clusterBuilder.addTransitionConstraint(Scope.resource(resource.getId()), - lockUnlock.getStateModelDefId(), - Transition.from(State.from("RELEASED"), State.from("LOCKED")), 1); - - ClusterConfig cluster = clusterBuilder.build(); - - // set up accessors to work with ZooKeeper-persisted data - ZkClient zkClient = ZKClientPool.getZkClient(args[0]); - BaseDataAccessor<ZNRecord> baseDataAccessor = new ZkBaseDataAccessor<ZNRecord>(zkClient); - HelixDataAccessor accessor = new ZKHelixDataAccessor(clusterId.stringify(), baseDataAccessor); - - // create the cluster - createCluster(cluster, accessor); - - // update the resource - updateResource(resource, accessor); - - // update the participant - updateParticipant(participant, accessor); - } - - private static void updateParticipant(ParticipantConfig participant, - HelixDataAccessor helixAccessor) { - // add a tag to the participant and change the hostname, then update it using a delta - ParticipantAccessor accessor = new ParticipantAccessor(helixAccessor); - ParticipantConfig.Delta delta = - new ParticipantConfig.Delta(participant.getId()).addTag("newTag").setHostName("newHost"); - accessor.updateParticipant(participant.getId(), delta); - } - - private static void updateResource(ResourceConfig resource, HelixDataAccessor helixAccessor) { - // add some fields to the resource user config, then update it using the resource config delta - ResourceAccessor accessor = new ResourceAccessor(helixAccessor); - UserConfig userConfig = resource.getUserConfig(); - Map<String, String> mapField = Maps.newHashMap(); - mapField.put("k1", "v1"); - mapField.put("k2", "v2"); - userConfig.setMapField("sampleMap", mapField); - ResourceConfig.Delta delta = - new ResourceConfig.Delta(resource.getId()).setUserConfig(userConfig); - accessor.updateResource(resource.getId(), delta); - } - - private static void createCluster(ClusterConfig cluster, HelixDataAccessor helixAccessor) { - ClusterAccessor accessor = new ClusterAccessor(cluster.getId(), helixAccessor); - accessor.createCluster(cluster); - } - - private static ParticipantConfig getParticipant() { - // identify the participant - ParticipantId participantId = ParticipantId.from("localhost_0"); - - // create (optional) participant user config properties - UserConfig userConfig = new UserConfig(Scope.participant(participantId)); - List<String> sampleList = Lists.newArrayList("elem1", "elem2"); - userConfig.setListField("sampleList", sampleList); - - // create the configuration of a new participant - ParticipantConfig.Builder participantBuilder = - new ParticipantConfig.Builder(participantId).hostName("localhost").port(0) - .userConfig(userConfig); - return participantBuilder.build(); - } - - private static ResourceConfig getResource(StateModelDefinition stateModelDef) { - // identify the resource - ResourceId resourceId = ResourceId.from("exampleResource"); - - // create a partition - Partition partition1 = new Partition(PartitionId.from(resourceId, "1")); - - // create a second partition - Partition partition2 = new Partition(PartitionId.from(resourceId, "2")); - - // specify the rebalancer configuration - // this resource will be rebalanced in FULL_AUTO mode, so use the FullAutoRebalancerContext - // builder - FullAutoRebalancerContext.Builder rebalanceContextBuilder = - new FullAutoRebalancerContext.Builder(resourceId).replicaCount(1).addPartition(partition1) - .addPartition(partition2).stateModelDefId(stateModelDef.getStateModelDefId()); - - // create (optional) user-defined configuration properties for the resource - UserConfig userConfig = new UserConfig(Scope.resource(resourceId)); - userConfig.setBooleanField("sampleBoolean", true); - - // create the configuration for a new resource - ResourceConfig.Builder resourceBuilder = - new ResourceConfig.Builder(resourceId).rebalancerContext(rebalanceContextBuilder.build()) - .userConfig(userConfig); - return resourceBuilder.build(); - } - - private static StateModelDefinition getLockUnlockModel() { - final State LOCKED = State.from("LOCKED"); - final State RELEASED = State.from("RELEASED"); - final State DROPPED = State.from("DROPPED"); - StateModelDefId stateModelId = StateModelDefId.from("LockUnlock"); - StateModelDefinition.Builder stateModelBuilder = - new StateModelDefinition.Builder(stateModelId).addState(LOCKED, 0).addState(RELEASED, 1) - .addState(DROPPED, 2).addTransition(RELEASED, LOCKED, 0) - .addTransition(LOCKED, RELEASED, 1).upperBound(LOCKED, 2).upperBound(RELEASED, -1) - .upperBound(DROPPED, -1).initialState(RELEASED); - return stateModelBuilder.build(); - } -}
