You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by ki...@apache.org on 2012/10/25 01:14:57 UTC
[5/42] Refactoring the package names and removing jsql parser
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixAdmin.java b/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
new file mode 100644
index 0000000..2d6539a
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixAdmin.java
@@ -0,0 +1,387 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.helix.ConfigScope.ConfigScopeProperty;
+import org.apache.helix.model.ExternalView;
+import org.apache.helix.model.IdealState;
+import org.apache.helix.model.InstanceConfig;
+import org.apache.helix.model.StateModelDefinition;
+
+
+public interface HelixAdmin
+{
+ /**
+ * Get a list of clusters under "/"
+ *
+ * @return
+ */
+ List<String> getClusters();
+
+ /**
+ * Get a list of instances under a cluster
+ *
+ * @param clusterName
+ * @return
+ */
+ List<String> getInstancesInCluster(String clusterName);
+
+ /**
+ * Get instance configs
+ *
+ * @param clusterName
+ * @param instanceName
+ * @return
+ */
+ InstanceConfig getInstanceConfig(String clusterName, String instanceName);
+
+ /**
+ * Get a list of resources in a cluster
+ *
+ * @param clusterName
+ * @return
+ */
+ List<String> getResourcesInCluster(String clusterName);
+
+ /**
+ * Add a cluster
+ *
+ * @param clusterName
+ * @param overwritePrevRecord
+ */
+ void addCluster(String clusterName, boolean overwritePrevRecord);
+
+ /**
+ * Add a cluster and also add this cluster as a resource group in the super cluster
+ *
+ * @param clusterName
+ * @param grandCluster
+ */
+ void addClusterToGrandCluster(String clusterName, String grandCluster);
+
+ /**
+ * Add a resource to a cluster, using the default ideal state mode AUTO
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param numResources
+ * @param stateModelRef
+ */
+ void addResource(String clusterName,
+ String resourceName,
+ int numResources,
+ String stateModelRef);
+
+ /**
+ * Add a resource to a cluster
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param numResources
+ * @param stateModelRef
+ * @param idealStateMode
+ */
+ void addResource(String clusterName,
+ String resourceName,
+ int numResources,
+ String stateModelRef,
+ String idealStateMode);
+
+ /**
+ * Add a resource to a cluster, using a bucket size > 1
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param numResources
+ * @param stateModelRef
+ * @param idealStateMode
+ * @param bucketSize
+ */
+ void addResource(String clusterName,
+ String resourceName,
+ int numResources,
+ String stateModelRef,
+ String idealStateMode,
+ int bucketSize);
+
+ /**
+ * Add an instance to a cluster
+ *
+ * @param clusterName
+ * @param instanceConfig
+ */
+ void addInstance(String clusterName, InstanceConfig instanceConfig);
+
+ /**
+ * Drop an instance from a cluster
+ *
+ * @param clusterName
+ * @param instanceConfig
+ */
+ void dropInstance(String clusterName, InstanceConfig instanceConfig);
+
+ /**
+ * Get ideal state for a resource
+ *
+ * @param clusterName
+ * @param dbName
+ * @return
+ */
+ IdealState getResourceIdealState(String clusterName, String dbName);
+
+ /**
+ * Set ideal state for a resource
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param idealState
+ */
+ void setResourceIdealState(String clusterName,
+ String resourceName,
+ IdealState idealState);
+
+ /**
+ * Disable or enable an instance
+ *
+ * @param clusterName
+ * @param instanceName
+ * @param enabled
+ */
+ void enableInstance(String clusterName, String instanceName, boolean enabled);
+
+ /**
+ * Disable or enable a list of partitions on an instance
+ *
+ * @param enabled
+ * @param clusterName
+ * @param instanceName
+ * @param resourceName
+ * @param partitionNames
+ */
+ void enablePartition(boolean enabled,
+ String clusterName,
+ String instanceName,
+ String resourceName,
+ List<String> partitionNames);
+
+ /**
+ * Disable or enable a cluster
+ *
+ * @param clusterName
+ * @param enabled
+ */
+ void enableCluster(String clusterName, boolean enabled);
+
+ /**
+ * Reset a list of partitions in error state for an instance
+ *
+ * The partitions are assume to be in error state and reset will bring them from error
+ * to initial state. An error to initial state transition is required for reset.
+ *
+ * @param clusterName
+ * @param instanceName
+ * @param resourceName
+ * @param partitionNames
+ */
+ void resetPartition(String clusterName,
+ String instanceName,
+ String resourceName,
+ List<String> partitionNames);
+
+ /**
+ * Reset all the partitions in error state for a list of instances
+ *
+ * @param clusterName
+ * @param instanceNames
+ */
+ void resetInstance(String clusterName, List<String> instanceNames);
+
+ /**
+ * Reset all partitions in error state for a list of resources
+ *
+ * @param clusterName
+ * @param resourceNames
+ */
+ void resetResource(String clusterName, List<String> resourceNames);
+
+ /**
+ * Add a state model definition
+ *
+ * @param clusterName
+ * @param stateModelDef
+ * @param record
+ */
+ void addStateModelDef(String clusterName,
+ String stateModelDef,
+ StateModelDefinition record);
+
+ /**
+ * Drop a resource from a cluster
+ *
+ * @param clusterName
+ * @param resourceName
+ */
+ void dropResource(String clusterName, String resourceName);
+
+ /**
+ * Add a statistics to a cluster
+ *
+ * @param clusterName
+ * @param statName
+ */
+ void addStat(String clusterName, String statName);
+
+ /**
+ * Add an alert to a cluster
+ *
+ * @param clusterName
+ * @param alertName
+ */
+ void addAlert(String clusterName, String alertName);
+
+ /**
+ * Drop a statistics from a cluster
+ *
+ * @param clusterName
+ * @param statName
+ */
+ void dropStat(String clusterName, String statName);
+
+ /**
+ * Drop an alert from a cluster
+ *
+ * @param clusterName
+ * @param alertName
+ */
+ void dropAlert(String clusterName, String alertName);
+
+ /**
+ * Get a list of state model definitions in a cluster
+ *
+ * @param clusterName
+ * @return
+ */
+ List<String> getStateModelDefs(String clusterName);
+
+ /**
+ * Get a state model definition in a cluster
+ *
+ * @param clusterName
+ * @param stateModelName
+ * @return
+ */
+ StateModelDefinition getStateModelDef(String clusterName, String stateModelName);
+
+ /**
+ * Get external view for a resource
+ *
+ * @param clusterName
+ * @param resourceName
+ * @return
+ */
+ ExternalView getResourceExternalView(String clusterName, String resourceName);
+
+ /**
+ * Drop a cluster
+ *
+ * @param clusterName
+ */
+ void dropCluster(String clusterName);
+
+ /**
+ * Set configuration values
+ *
+ * @param scope
+ * @param properties
+ */
+ void setConfig(ConfigScope scope, Map<String, String> properties);
+
+ /**
+ * Remove configuration values
+ *
+ * @param scope
+ * @param keys
+ */
+ void removeConfig(ConfigScope scope, Set<String> keys);
+
+ /**
+ * Get configuration values
+ *
+ * @param scope
+ * @param keys
+ * @return
+ */
+ Map<String, String> getConfig(ConfigScope scope, Set<String> keys);
+
+ /**
+ * Get configuration keys
+ *
+ * @param scope
+ * @param clusterName
+ * @param keys
+ * @return
+ */
+ List<String> getConfigKeys(ConfigScopeProperty scope,
+ String clusterName,
+ String... keys);
+
+ /**
+ * Rebalance a resource in cluster
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param replica
+ * @param keyPrefix
+ */
+ void rebalance(String clusterName, String resourceName, int replica);
+
+ /**
+ * Add ideal state using a json format file
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param idealStateFile
+ * @throws IOException
+ */
+ void addIdealState(String clusterName, String resourceName, String idealStateFile) throws IOException;
+
+ /**
+ * Add state model definition using a json format file
+ *
+ * @param clusterName
+ * @param resourceName
+ * @param idealStateFile
+ * @throws IOException
+ */
+ void addStateModelDef(String clusterName,
+ String stateModelDefName,
+ String stateModelDefFile) throws IOException;
+
+ /**
+ * Add a message contraint
+ *
+ * @param constraintId
+ * @param constraints
+ */
+ void addMessageConstraint(String clusterName,
+ String constraintId,
+ Map<String, String> constraints);
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixConstants.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixConstants.java b/helix-core/src/main/java/org/apache/helix/HelixConstants.java
new file mode 100644
index 0000000..15547ff
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixConstants.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+public interface HelixConstants
+{
+ // ChangeType and PropertyType are the same; remove this
+ enum ChangeType
+ {
+ // @formatter:off
+ IDEAL_STATE,
+ CONFIG,
+ LIVE_INSTANCE,
+ CURRENT_STATE,
+ MESSAGE,
+ EXTERNAL_VIEW,
+ CONTROLLER,
+ MESSAGES_CONTROLLER,
+ HEALTH
+ // @formatter:on
+ }
+
+ enum StateModelToken
+ {
+ ANY_LIVEINSTANCE
+ }
+
+ enum ClusterConfigType
+ {
+ HELIX_DISABLE_PIPELINE_TRIGGERS
+ }
+
+ static final String DEFAULT_STATE_MODEL_FACTORY = "DEFAULT";
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixDataAccessor.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixDataAccessor.java b/helix-core/src/main/java/org/apache/helix/HelixDataAccessor.java
new file mode 100644
index 0000000..67a3ac1
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixDataAccessor.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.List;
+import java.util.Map;
+
+import org.I0Itec.zkclient.DataUpdater;
+
+/**
+ * Interface used to interact with Helix Data Types like IdealState, Config,
+ * LiveInstance, Message, ExternalView etc PropertyKey represent the HelixData
+ * type. See {@link Builder} to get more information on building a propertyKey.
+ *
+ * @author kgopalak
+ *
+ */
+public interface HelixDataAccessor
+{
+ /**
+ * Create a helix property only if it does not exist.
+ *
+ * @param key
+ * @param value
+ * @return true if creation was successful. False if already exists or if it
+ * failed to create
+ */
+
+ <T extends HelixProperty> boolean createProperty(PropertyKey key, T value);
+
+ /**
+ * Set a property, overwrite if it exists and creates if not exists. This api
+ * assumes the node exists and only tries to update it only if the call fail
+ * it will create the node. So there is a performance cost if always ends up
+ * creating the node.
+ *
+ * @param key
+ * @param value
+ * @true if the operation was successful
+ */
+ <T extends HelixProperty> boolean setProperty(PropertyKey key, T value);
+
+ /**
+ * Updates a property using newvalue.merge(oldvalue)
+ *
+ * @param key
+ * @param value
+ * @return true if the update was successful
+ */
+ <T extends HelixProperty> boolean updateProperty(PropertyKey key, T value);
+
+ /**
+ * Return the property value, it must be refer to a single Helix Property. i.e
+ * PropertyKey.isLeaf() must return true.
+ *
+ * @param key
+ * @return value, Null if absent or on error
+ */
+ <T extends HelixProperty> T getProperty(PropertyKey key);
+
+ /**
+ * Return a list of property values, each of which must be refer to a single Helix
+ * Property. Property may be bucketized.
+ *
+ * @param keys
+ * @return
+ */
+ public <T extends HelixProperty> List<T> getProperty(List<PropertyKey> keys);
+
+ /**
+ * Removes the property
+ *
+ * @param key
+ * @return true if removal was successful or node does not exist. false if the
+ * node existed and failed to remove it
+ */
+ boolean removeProperty(PropertyKey key);
+
+ /**
+ * Return the child names for a property. PropertyKey needs to refer to a
+ * collection like instances, resources. PropertyKey.isLeaf must be false
+ *
+ * @param type
+ * @return SubPropertyNames
+ */
+ List<String> getChildNames(PropertyKey key);
+
+ /**
+ * Get the child values for a property. PropertyKey needs to refer to just one
+ * level above the non leaf. PropertyKey.isCollection must be true.
+ *
+ * @param type
+ * @return subPropertyValues
+ */
+ <T extends HelixProperty> List<T> getChildValues(PropertyKey key);
+
+ /**
+ * Same as getChildValues except that it converts list into a map using the id
+ * of the HelixProperty
+ *
+ * @param key
+ * @return
+ */
+
+ <T extends HelixProperty> Map<String, T> getChildValuesMap(PropertyKey key);
+
+ /**
+ * Adds multiple children to a parent.
+ *
+ * @param key
+ * @param children
+ * @return
+ */
+ <T extends HelixProperty> boolean[] createChildren(List<PropertyKey> keys,
+ List<T> children);
+
+ /**
+ * Sets multiple children under one parent
+ *
+ * @param externalViews
+ * @param views
+ */
+ <T extends HelixProperty> boolean[] setChildren(List<PropertyKey> keys, List<T> children);
+
+ /**
+ * Updates multiple children under one parent
+ *
+ * @param externalViews
+ * @param views
+ */
+ <T extends HelixProperty> boolean[] updateChildren(List<String> paths,
+ List<DataUpdater<ZNRecord>> updaters,
+ int options);
+
+ /**
+ * Get key builder for the accessor
+ *
+ * @return
+ */
+ PropertyKey.Builder keyBuilder();
+
+ /**
+ * Get underlying base data accessor
+ *
+ * @return
+ */
+ BaseDataAccessor<ZNRecord> getBaseDataAccessor();
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixException.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixException.java b/helix-core/src/main/java/org/apache/helix/HelixException.java
new file mode 100644
index 0000000..d9d9de0
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixException.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+
+public class HelixException extends RuntimeException
+{
+
+ public HelixException(String message)
+ {
+ super(message);
+ }
+
+ public HelixException(Throwable cause)
+ {
+ super(cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/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
new file mode 100644
index 0000000..a34ab8e
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixManager.java
@@ -0,0 +1,297 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.List;
+
+import org.apache.helix.controller.GenericHelixController;
+import org.apache.helix.healthcheck.ParticipantHealthReportCollector;
+import org.apache.helix.participant.HelixStateMachineEngine;
+import org.apache.helix.participant.StateMachineEngine;
+import org.apache.helix.spectator.RoutingTableProvider;
+import org.apache.helix.store.PropertyStore;
+import org.apache.helix.store.zk.ZkHelixPropertyStore;
+
+
+/**
+ * First class Object any process will interact with<br/>
+ * General flow <blockquote>
+ *
+ * <pre>
+ * manager = HelixManagerFactory.getManagerFor<ROLE>(); ROLE can be participant, spectator or a controller<br/>
+ * manager.connect();
+ * manager.addSOMEListener();
+ * manager.start()
+ * After start is invoked the subsequent interactions will be via listener onChange callbacks
+ * There will be 3 scenarios for onChange callback, which can be determined using NotificationContext.type
+ * INIT -> will be invoked the first time the listener is added
+ * CALLBACK -> will be invoked due to datachange in the property value
+ * FINALIZE -> will be invoked when listener is removed or session expires
+ * manager.disconnect()
+ * </pre>
+ *
+ * </blockquote> Default implementations available
+ *
+ * @see HelixStateMachineEngine for participant
+ * @see RoutingTableProvider for spectator
+ * @see GenericHelixController for controller
+ * @author kgopalak
+ */
+public interface HelixManager
+{
+
+ /**
+ * Start participating in the cluster operations. All listeners will be
+ * initialized and will be notified for every cluster state change This method
+ * is not re-entrant. One cannot call this method twice.
+ *
+ * @throws Exception
+ */
+ void connect() throws Exception;
+
+ /**
+ * Check if the connection is alive, code depending on cluster manager must
+ * always do this if( manager.isConnected()){ //custom code } This will
+ * prevent client in doing anything when its disconnected from the cluster.
+ * There is no need to invoke connect again if isConnected return false.
+ *
+ * @return
+ */
+ boolean isConnected();
+
+ /**
+ * Disconnect from the cluster. All the listeners will be removed and
+ * disconnected from the server. Its important for the client to ensure that
+ * new manager instance is used when it wants to connect again.
+ */
+ void disconnect();
+
+ /**
+ * @see IdealStateChangeListener#onIdealStateChange(List, NotificationContext)
+ * @param listener
+ * @throws Exception
+ */
+ void addIdealStateChangeListener(IdealStateChangeListener listener)
+ throws Exception;
+
+ /**
+ * @see LiveInstanceChangeListener#onLiveInstanceChange(List,
+ * NotificationContext)
+ * @param listener
+ */
+ void addLiveInstanceChangeListener(LiveInstanceChangeListener listener)
+ throws Exception;
+
+ /**
+ * @see ConfigChangeListener#onConfigChange(List, NotificationContext)
+ * @param listener
+ */
+ void addConfigChangeListener(ConfigChangeListener listener) throws Exception;
+
+ /**
+ * @see MessageListener#onMessage(String, List, NotificationContext)
+ * @param listener
+ * @param instanceName
+ */
+ void addMessageListener(MessageListener listener, String instanceName)
+ throws Exception;
+
+ /**
+ * @see CurrentStateChangeListener#onStateChange(String, List,
+ * NotificationContext)
+ * @param listener
+ * @param instanceName
+ */
+
+ void addCurrentStateChangeListener(CurrentStateChangeListener listener,
+ String instanceName, String sessionId) throws Exception;
+
+ /**
+ * @see HealthStateChangeListener#onHealthChange(String, List,
+ * NotificationContext)
+ * @param listener
+ * @param instanceName
+ */
+ void addHealthStateChangeListener(HealthStateChangeListener listener,
+ String instanceName) throws Exception;
+
+ /**
+ * @see ExternalViewChangeListener#onExternalViewChange(List,
+ * NotificationContext)
+ * @param listener
+ */
+ void addExternalViewChangeListener(ExternalViewChangeListener listener)
+ throws Exception;
+
+ /**
+ * Add listener for controller change
+ *
+ * Used in distributed cluster controller
+ */
+ void addControllerListener(ControllerChangeListener listener);
+
+ /**
+ * Removes the listener. If the same listener was used for multiple changes,
+ * all change notifications will be removed.<br/>
+ * This will invoke onChange method on the listener with
+ * NotificationContext.type set to FINALIZE. Listener can clean up its state.<br/>
+ * The data provided in this callback may not be reliable.<br/>
+ * When a session expires all listeners will be removed and re-added
+ * automatically. <br/>
+ * This provides the ability for listeners to either reset their state or do
+ * any cleanup tasks.<br/>
+ *
+ * @param listener
+ * @return
+ */
+ boolean removeListener(Object listener);
+
+ /**
+ * Return the client to perform read/write operations on the cluster data
+ * store {@link getHelixDataAccessor() }
+ *
+ * @return DataAccessor
+ */
+ @Deprecated
+ DataAccessor getDataAccessor();
+
+ /**
+ * Return the client to perform read/write operations on the cluster data
+ * store
+ *
+ * @return ClusterDataAccessor
+ */
+ HelixDataAccessor getHelixDataAccessor();
+
+ /**
+ * Get config accessor
+ *
+ * @return
+ */
+ ConfigAccessor getConfigAccessor();
+
+ /**
+ * Returns the cluster name associated with this cluster manager
+ *
+ * @return
+ */
+ String getClusterName();
+
+ /**
+ * Returns the instanceName used to connect to the cluster
+ *
+ * @return
+ */
+
+ String getInstanceName();
+
+ /**
+ * Get the sessionId associated with the connection to cluster data store.
+ */
+ String getSessionId();
+
+ /**
+ * The time stamp is always updated when a notification is received. This can
+ * be used to check if there was any new notification when previous
+ * notification was being processed. This is updated based on the
+ * notifications from listeners registered.
+ */
+ long getLastNotificationTime();
+
+ /**
+ * Provides admin interface to setup and modify cluster.
+ *
+ * @return
+ */
+ HelixAdmin getClusterManagmentTool();
+
+ /**
+ * Provide get property store for a cluster
+ *
+ * @param rootNamespace
+ * @param serializer
+ * @return
+ */
+ @Deprecated
+ PropertyStore<ZNRecord> getPropertyStore();
+
+ /**
+ * Get property store
+ *
+ * @return
+ */
+ ZkHelixPropertyStore<ZNRecord> getHelixPropertyStore();
+
+ /**
+ * Messaging service which can be used to send cluster wide messages.
+ *
+ */
+ ClusterMessagingService getMessagingService();
+
+ /**
+ * Participant only component that periodically update participant health
+ * report to cluster manager server.
+ *
+ */
+ ParticipantHealthReportCollector getHealthReportCollector();
+
+ /**
+ * Get cluster manager instance type
+ *
+ * @return
+ */
+ InstanceType getInstanceType();
+
+ /**
+ * Get cluster manager version
+ *
+ * @return the cluster manager version
+ */
+ String getVersion();
+
+ /**
+ *
+ * @return the state machine engine
+ */
+ StateMachineEngine getStateMachineEngine();
+
+ /**
+ * Check if the cluster manager is the leader
+ *
+ * @return true if this is a controller and a leader of the cluster
+ */
+ boolean isLeader();
+
+ /**
+ * start timer tasks when becomes leader
+ *
+ */
+ void startTimerTasks();
+
+ /**
+ * stop timer tasks when becomes standby
+ *
+ */
+ void stopTimerTasks();
+
+ /**
+ * Add a callback that is invoked before cluster manager connects
+ *
+ * @see PreConnectCallback#onPreConnect()
+ * @param callback
+ */
+ void addPreConnectCallback(PreConnectCallback callback);
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixManagerFactory.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixManagerFactory.java b/helix-core/src/main/java/org/apache/helix/HelixManagerFactory.java
new file mode 100644
index 0000000..9f05b2d
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixManagerFactory.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+/**
+ * factory that creates cluster managers
+ *
+ * for zk-based cluster managers, the getZKXXX(..zkClient) that takes a zkClient parameter
+ * are intended for session expiry test purpose
+ */
+import org.apache.helix.manager.file.DynamicFileHelixManager;
+import org.apache.helix.manager.file.StaticFileHelixManager;
+import org.apache.helix.manager.zk.ZKHelixManager;
+import org.apache.helix.store.file.FilePropertyStore;
+import org.apache.log4j.Logger;
+
+
+public final class HelixManagerFactory
+{
+ private static final Logger logger = Logger.getLogger(HelixManagerFactory.class);
+
+ /**
+ * Construct a zk-based cluster manager enforce all types (PARTICIPANT, CONTROLLER, and
+ * SPECTATOR to have a name
+ *
+ * @param clusterName
+ * @param instanceName
+ * @param type
+ * @param zkAddr
+ * @return
+ * @throws Exception
+ */
+ public static HelixManager getZKHelixManager(String clusterName,
+ String instanceName,
+ InstanceType type,
+ String zkAddr) throws Exception
+ {
+ return new ZKHelixManager(clusterName, instanceName, type, zkAddr);
+ }
+
+ /**
+ * Construct a file-based cluster manager using a static cluster-view file the
+ * cluster-view file contains pre-computed state transition messages from initial
+ * OFFLINE states to ideal states
+ *
+ * @param clusterName
+ * @param instanceName
+ * @param type
+ * @param clusterViewFile
+ * @return
+ * @throws Exception
+ */
+ @Deprecated
+ public static HelixManager getStaticFileHelixManager(String clusterName,
+ String instanceName,
+ InstanceType type,
+ String clusterViewFile) throws Exception
+ {
+ if (type != InstanceType.PARTICIPANT)
+ {
+ throw new IllegalArgumentException("Static file-based cluster manager doesn't support type other than participant");
+ }
+ return new StaticFileHelixManager(clusterName, instanceName, type, clusterViewFile);
+ }
+
+ /**
+ * Construct a dynamic file-based cluster manager
+ *
+ * @param clusterName
+ * @param instanceName
+ * @param type
+ * @param file
+ * property store: all dynamic-file based participants/controller shall use the
+ * same file property store to avoid race condition in updating files
+ * @return
+ * @throws Exception
+ */
+ @Deprecated
+ public static HelixManager getDynamicFileHelixManager(String clusterName,
+ String instanceName,
+ InstanceType type,
+ FilePropertyStore<ZNRecord> store) throws Exception
+ {
+ if (type != InstanceType.PARTICIPANT && type != InstanceType.CONTROLLER)
+ {
+ throw new IllegalArgumentException("Dynamic file-based cluster manager doesn't support types other than participant and controller");
+ }
+
+ return new DynamicFileHelixManager(clusterName, instanceName, type, store);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixProperty.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixProperty.java b/helix-core/src/main/java/org/apache/helix/HelixProperty.java
new file mode 100644
index 0000000..01689c5
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixProperty.java
@@ -0,0 +1,224 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A wrapper class for ZNRecord. Used as a base class for IdealState, CurrentState, etc.
+ */
+public class HelixProperty
+{
+ public enum HelixPropertyAttribute
+ {
+ BUCKET_SIZE,
+ GROUP_MESSAGE_MODE
+ }
+
+ protected final ZNRecord _record;
+
+ public HelixProperty(String id)
+ {
+ _record = new ZNRecord(id);
+ }
+
+ public HelixProperty(ZNRecord record)
+ {
+ _record = new ZNRecord(record);
+ }
+
+ public final String getId()
+ {
+ return _record.getId();
+ }
+
+ public final ZNRecord getRecord()
+ {
+ return _record;
+ }
+
+ public final void setDeltaList(List<ZNRecordDelta> deltaList)
+ {
+ _record.setDeltaList(deltaList);
+ }
+
+ @Override
+ public String toString()
+ {
+ return _record.toString();
+ }
+
+ public int getBucketSize()
+ {
+ String bucketSizeStr =
+ _record.getSimpleField(HelixPropertyAttribute.BUCKET_SIZE.toString());
+ int bucketSize = 0;
+ if (bucketSizeStr != null)
+ {
+ try
+ {
+ bucketSize = Integer.parseInt(bucketSizeStr);
+ }
+ catch (NumberFormatException e)
+ {
+ // OK
+ }
+ }
+ return bucketSize;
+ }
+
+ public void setBucketSize(int bucketSize)
+ {
+ if (bucketSize <= 0)
+ bucketSize = 0;
+
+ _record.setSimpleField(HelixPropertyAttribute.BUCKET_SIZE.toString(), "" + bucketSize);
+ }
+
+ /**
+ * static method that convert ZNRecord to an instance that subclasses HelixProperty
+ *
+ * @param clazz
+ * @param record
+ * @return
+ */
+ public static <T extends HelixProperty> T convertToTypedInstance(Class<T> clazz,
+ ZNRecord record)
+ {
+ if (record == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ Constructor<T> constructor = clazz.getConstructor(new Class[] { ZNRecord.class });
+ return constructor.newInstance(record);
+ }
+ catch (Exception e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ public static <T extends HelixProperty> List<T> convertToTypedList(Class<T> clazz,
+ Collection<ZNRecord> records)
+ {
+ if (records == null)
+ {
+ return null;
+ }
+
+ List<T> decorators = new ArrayList<T>();
+ for (ZNRecord record : records)
+ {
+ T decorator = HelixProperty.convertToTypedInstance(clazz, record);
+ if (decorator != null)
+ {
+ decorators.add(decorator);
+ }
+ }
+ return decorators;
+ }
+
+ public static <T extends HelixProperty> Map<String, T> convertListToMap(List<T> records)
+ {
+ if (records == null)
+ {
+ return Collections.emptyMap();
+ }
+
+ Map<String, T> decorators = new HashMap<String, T>();
+ for (T record : records)
+ {
+ decorators.put(record.getId(), record);
+ }
+ return decorators;
+ }
+
+ public static <T extends HelixProperty> List<ZNRecord> convertToList(List<T> typedInstances)
+ {
+ if (typedInstances == null)
+ {
+ return Collections.emptyList();
+ }
+
+ List<ZNRecord> records = new ArrayList<ZNRecord>();
+ for (T typedInstance : typedInstances)
+ {
+ records.add(typedInstance.getRecord());
+ }
+
+ return records;
+ }
+
+ public void setGroupMessageMode(boolean enable)
+ {
+ _record.setSimpleField(HelixPropertyAttribute.GROUP_MESSAGE_MODE.toString(), ""
+ + enable);
+ }
+
+ public boolean getGroupMessageMode()
+ {
+ String enableStr =
+ _record.getSimpleField(HelixPropertyAttribute.GROUP_MESSAGE_MODE.toString());
+ if (enableStr == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ return Boolean.parseBoolean(enableStr.toLowerCase());
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+
+ public boolean isValid()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+ if (obj instanceof HelixProperty)
+ {
+ HelixProperty that = (HelixProperty) obj;
+ if (that.getRecord() != null)
+ {
+ return that.getRecord().equals(this.getRecord());
+ }
+ }
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/HelixTimerTask.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/HelixTimerTask.java b/helix-core/src/main/java/org/apache/helix/HelixTimerTask.java
new file mode 100644
index 0000000..8cee808
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/HelixTimerTask.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.TimerTask;
+
+public abstract class HelixTimerTask extends TimerTask
+{
+ /**
+ * Timer task starts
+ *
+ */
+ public abstract void start();
+
+ /**
+ * Timer task stops
+ *
+ */
+ public abstract void stop();
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/IdealStateChangeListener.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/IdealStateChangeListener.java b/helix-core/src/main/java/org/apache/helix/IdealStateChangeListener.java
new file mode 100644
index 0000000..d8806cc
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/IdealStateChangeListener.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.List;
+
+import org.apache.helix.model.IdealState;
+
+
+public interface IdealStateChangeListener
+{
+
+ /**
+ * Invoed when ideal state changes
+ *
+ * @param idealState
+ * @param changeContext
+ */
+ void onIdealStateChange(List<IdealState> idealState, NotificationContext changeContext);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/InstanceType.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/InstanceType.java b/helix-core/src/main/java/org/apache/helix/InstanceType.java
new file mode 100644
index 0000000..241304a
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/InstanceType.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+/**
+ * CONTROLLER: cluster managing component is a controller
+ * PARTICIPANT: participate in the cluster state changes
+ * SPECTATOR: interested in the state changes in the cluster
+ * CONTROLLER_PARTICIPANT:
+ * special participant that competes for the leader of CONTROLLER_CLUSTER
+ * used in cluster controller of distributed mode {@HelixControllerMain}
+ *
+ */
+public enum InstanceType
+{
+ CONTROLLER,
+ PARTICIPANT,
+ SPECTATOR,
+ CONTROLLER_PARTICIPANT,
+ ADMINISTRATOR
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/LiveInstanceChangeListener.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/LiveInstanceChangeListener.java b/helix-core/src/main/java/org/apache/helix/LiveInstanceChangeListener.java
new file mode 100644
index 0000000..97513a4
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/LiveInstanceChangeListener.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.List;
+
+import org.apache.helix.model.LiveInstance;
+
+
+public interface LiveInstanceChangeListener
+{
+
+ /**
+ * Invoked when live instance changes
+ *
+ * @param liveInstances
+ * @param changeContext
+ */
+ public void onLiveInstanceChange(List<LiveInstance> liveInstances,
+ NotificationContext changeContext);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/MessageListener.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/MessageListener.java b/helix-core/src/main/java/org/apache/helix/MessageListener.java
new file mode 100644
index 0000000..d8fb8c9
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/MessageListener.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.List;
+
+import org.apache.helix.model.Message;
+
+
+public interface MessageListener
+{
+
+ /**
+ * Invoked when message changes
+ *
+ * @param instanceName
+ * @param messages
+ * @param changeContext
+ */
+ public void onMessage(String instanceName, List<Message> messages,
+ NotificationContext changeContext);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/NotificationContext.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/NotificationContext.java b/helix-core/src/main/java/org/apache/helix/NotificationContext.java
new file mode 100644
index 0000000..53a3417
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/NotificationContext.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class NotificationContext
+{
+ // keys used for object map
+ public static final String TASK_EXECUTOR_KEY = "TASK_EXECUTOR";
+
+ private Map<String, Object> _map;
+
+ private HelixManager _manager;
+ private Type _type;
+ private String _pathChanged;
+ private String _eventName;
+
+ public String getEventName()
+ {
+ return _eventName;
+ }
+
+ public void setEventName(String eventName)
+ {
+ _eventName = eventName;
+ }
+
+ public NotificationContext(HelixManager manager)
+ {
+ _manager = manager;
+ _map = new HashMap<String, Object>();
+ }
+
+ public HelixManager getManager()
+ {
+ return _manager;
+ }
+
+ public Map<String, Object> getMap()
+ {
+ return _map;
+ }
+
+ public Type getType()
+ {
+ return _type;
+ }
+
+ public void setManager(HelixManager manager)
+ {
+ this._manager = manager;
+ }
+
+ public void add(String key, Object value)
+ {
+ _map.put(key, value);
+ }
+
+ public void setMap(Map<String, Object> map)
+ {
+ this._map = map;
+ }
+
+ public void setType(Type type)
+ {
+ this._type = type;
+ }
+
+ public Object get(String key)
+ {
+ return _map.get(key);
+ }
+
+ public enum Type
+ {
+ INIT, CALLBACK, FINALIZE
+ }
+
+ public String getPathChanged()
+ {
+ return _pathChanged;
+ }
+
+ public void setPathChanged(String pathChanged)
+ {
+ this._pathChanged = pathChanged;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/PreConnectCallback.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/PreConnectCallback.java b/helix-core/src/main/java/org/apache/helix/PreConnectCallback.java
new file mode 100644
index 0000000..f19a4fa
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/PreConnectCallback.java
@@ -0,0 +1,12 @@
+package org.apache.helix;
+
+public interface PreConnectCallback
+{
+ /**
+ * Callback function that is called by HelixManager before connected to zookeeper. If
+ * exception are thrown HelixManager will not connect and no live instance is created
+ *
+ * @see ZkHelixManager#handleNewSessionAsParticipant()
+ */
+ public void onPreConnect();
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/PropertyKey.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyKey.java b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
new file mode 100644
index 0000000..e1fd3db
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java
@@ -0,0 +1,553 @@
+package org.apache.helix;
+
+import static org.apache.helix.PropertyType.ALERTS;
+import static org.apache.helix.PropertyType.ALERT_HISTORY;
+import static org.apache.helix.PropertyType.ALERT_STATUS;
+import static org.apache.helix.PropertyType.CONFIGS;
+import static org.apache.helix.PropertyType.CONTROLLER;
+import static org.apache.helix.PropertyType.CURRENTSTATES;
+import static org.apache.helix.PropertyType.ERRORS;
+import static org.apache.helix.PropertyType.ERRORS_CONTROLLER;
+import static org.apache.helix.PropertyType.EXTERNALVIEW;
+import static org.apache.helix.PropertyType.HEALTHREPORT;
+import static org.apache.helix.PropertyType.HISTORY;
+import static org.apache.helix.PropertyType.IDEALSTATES;
+import static org.apache.helix.PropertyType.LEADER;
+import static org.apache.helix.PropertyType.LIVEINSTANCES;
+import static org.apache.helix.PropertyType.MESSAGES;
+import static org.apache.helix.PropertyType.MESSAGES_CONTROLLER;
+import static org.apache.helix.PropertyType.PAUSE;
+import static org.apache.helix.PropertyType.PERSISTENTSTATS;
+import static org.apache.helix.PropertyType.STATEMODELDEFS;
+import static org.apache.helix.PropertyType.STATUSUPDATES;
+import static org.apache.helix.PropertyType.STATUSUPDATES_CONTROLLER;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.helix.ConfigScope.ConfigScopeProperty;
+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.AlertHistory;
+import org.apache.helix.model.AlertStatus;
+import org.apache.helix.model.Alerts;
+import org.apache.helix.model.ClusterConstraints;
+import org.apache.helix.model.CurrentState;
+import org.apache.helix.model.Error;
+import org.apache.helix.model.ExternalView;
+import org.apache.helix.model.HealthStat;
+import org.apache.helix.model.IdealState;
+import org.apache.helix.model.InstanceConfig;
+import org.apache.helix.model.LeaderHistory;
+import org.apache.helix.model.LiveInstance;
+import org.apache.helix.model.Message;
+import org.apache.helix.model.PauseSignal;
+import org.apache.helix.model.PersistentStats;
+import org.apache.helix.model.StateModelDefinition;
+import org.apache.helix.model.StatusUpdate;
+import org.apache.log4j.Logger;
+
+
+public class PropertyKey
+{
+ private static Logger LOG = Logger.getLogger(PropertyKey.class);
+ public PropertyType _type;
+ private final String[] _params;
+ Class<? extends HelixProperty> _typeClazz;
+
+ public PropertyKey(PropertyType type,
+ Class<? extends HelixProperty> typeClazz,
+ String... params)
+ {
+ _type = type;
+ if (params == null || params.length == 0 || Arrays.asList(params).contains(null))
+ {
+ throw new IllegalArgumentException("params cannot be null");
+ }
+
+ _params = params;
+ _typeClazz = typeClazz;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return super.hashCode();
+ }
+
+ public String getPath()
+ {
+ String clusterName = _params[0];
+ String[] subKeys = Arrays.copyOfRange(_params, 1, _params.length);
+ String path = PropertyPathConfig.getPath(_type, clusterName, subKeys);
+ if (path == null)
+ {
+ LOG.error("Invalid property key with type:" + _type + "subKeys:"
+ + Arrays.toString(_params));
+ }
+ return path;
+ }
+
+ public static class Builder
+ {
+ private final String _clusterName;
+
+ public Builder(String clusterName)
+ {
+ _clusterName = clusterName;
+ }
+
+ public PropertyKey idealStates()
+ {
+ return new PropertyKey(IDEALSTATES, IdealState.class, _clusterName);
+ }
+
+ public PropertyKey idealStates(String resourceName)
+ {
+ return new PropertyKey(IDEALSTATES, IdealState.class, _clusterName, resourceName);
+ }
+
+ public PropertyKey stateModelDefs()
+ {
+ return new PropertyKey(STATEMODELDEFS, StateModelDefinition.class, _clusterName);
+ }
+
+ public PropertyKey stateModelDef(String stateModelName)
+ {
+ return new PropertyKey(STATEMODELDEFS,
+ StateModelDefinition.class,
+ _clusterName,
+ stateModelName);
+ }
+
+ public PropertyKey clusterConfig()
+ {
+ return new PropertyKey(CONFIGS,
+ null,
+ _clusterName,
+ ConfigScopeProperty.CLUSTER.toString());
+ }
+
+ public PropertyKey instanceConfigs()
+ {
+ return new PropertyKey(CONFIGS,
+ InstanceConfig.class,
+ _clusterName,
+ ConfigScopeProperty.PARTICIPANT.toString());
+ }
+
+ public PropertyKey instanceConfig(String instanceName)
+ {
+ return new PropertyKey(CONFIGS,
+ InstanceConfig.class,
+ _clusterName,
+ ConfigScopeProperty.PARTICIPANT.toString(),
+ instanceName);
+ }
+
+ public PropertyKey resourceConfig(String resourceName)
+ {
+ return new PropertyKey(CONFIGS,
+ null,
+ _clusterName,
+ ConfigScopeProperty.RESOURCE.toString(),
+ resourceName);
+ }
+
+ public PropertyKey resourceConfig(String instanceName, String resourceName)
+ {
+ return new PropertyKey(CONFIGS,
+ null,
+ _clusterName,
+ ConfigScopeProperty.RESOURCE.toString(),
+ resourceName);
+ }
+
+ public PropertyKey partitionConfig(String resourceName, String partitionName)
+ {
+ return new PropertyKey(CONFIGS,
+ null,
+ _clusterName,
+ ConfigScopeProperty.RESOURCE.toString(),
+ resourceName);
+ }
+
+ public PropertyKey partitionConfig(String instanceName,
+ String resourceName,
+ String partitionName)
+ {
+ return new PropertyKey(CONFIGS,
+ null,
+ _clusterName,
+ ConfigScopeProperty.RESOURCE.toString(),
+ resourceName);
+ }
+
+ public PropertyKey constraints()
+ {
+ return new PropertyKey(CONFIGS,
+ ClusterConstraints.class,
+ _clusterName,
+ ConfigScopeProperty.CONSTRAINT.toString());
+ }
+
+ public PropertyKey constraint(String constraintType)
+ {
+ return new PropertyKey(CONFIGS,
+ ClusterConstraints.class,
+ _clusterName,
+ ConfigScopeProperty.CONSTRAINT.toString(),
+ constraintType);
+ }
+
+ public PropertyKey liveInstances()
+ {
+ return new PropertyKey(LIVEINSTANCES, LiveInstance.class, _clusterName);
+ }
+
+ public PropertyKey liveInstance(String instanceName)
+ {
+ return new PropertyKey(LIVEINSTANCES,
+ LiveInstance.class,
+ _clusterName,
+ instanceName);
+ }
+
+ public PropertyKey instances()
+ {
+ return new PropertyKey(CONFIGS, null, _clusterName);
+ }
+
+ public PropertyKey messages(String instanceName)
+ {
+ return new PropertyKey(MESSAGES, Message.class, _clusterName, instanceName);
+ }
+
+ public PropertyKey message(String instanceName, String messageId)
+ {
+ return new PropertyKey(MESSAGES,
+ Message.class,
+ _clusterName,
+ instanceName,
+ messageId);
+ }
+
+ public PropertyKey sessions(String instanceName)
+ {
+ return new PropertyKey(CURRENTSTATES,
+ CurrentState.class,
+ _clusterName,
+ instanceName);
+ }
+
+ public PropertyKey currentStates(String instanceName, String sessionId)
+ {
+ return new PropertyKey(CURRENTSTATES,
+ CurrentState.class,
+ _clusterName,
+ instanceName,
+ sessionId);
+ }
+
+ public PropertyKey currentState(String instanceName,
+ String sessionId,
+ String resourceName)
+ {
+ return new PropertyKey(CURRENTSTATES,
+ CurrentState.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName);
+ }
+
+ public PropertyKey currentState(String instanceName,
+ String sessionId,
+ String resourceName,
+ String bucketName)
+ {
+ if (bucketName == null)
+ {
+ return new PropertyKey(CURRENTSTATES,
+ CurrentState.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName);
+
+ }
+ else
+ {
+ return new PropertyKey(CURRENTSTATES,
+ CurrentState.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName,
+ bucketName);
+ }
+ }
+
+ // addEntry(PropertyType.STATUSUPDATES, 2,
+ // "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES");
+ // addEntry(PropertyType.STATUSUPDATES, 3,
+ // "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES/{sessionId}");
+ // addEntry(PropertyType.STATUSUPDATES, 4,
+ // "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES/{sessionId}/{subPath}");
+ // addEntry(PropertyType.STATUSUPDATES, 5,
+ // "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES/{sessionId}/{subPath}/{recordName}");
+ public PropertyKey stateTransitionStatus(String instanceName,
+ String sessionId,
+ String resourceName,
+ String partitionName)
+ {
+ return new PropertyKey(STATUSUPDATES,
+ StatusUpdate.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName,
+ partitionName);
+ }
+
+ public PropertyKey stateTransitionStatus(String instanceName,
+ String sessionId,
+ String resourceName)
+ {
+ return new PropertyKey(STATUSUPDATES,
+ StatusUpdate.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName);
+ }
+
+ public PropertyKey stateTransitionStatus(String instanceName, String sessionId)
+ {
+ return new PropertyKey(STATUSUPDATES,
+ StatusUpdate.class,
+ _clusterName,
+ instanceName,
+ sessionId);
+ }
+
+ /**
+ * Used to get status update for a NON STATE TRANSITION type
+ *
+ * @param instanceName
+ * @param sessionId
+ * @param msgType
+ * @param msgId
+ * @return
+ */
+ public PropertyKey taskStatus(String instanceName,
+ String sessionId,
+ String msgType,
+ String msgId)
+ {
+ return new PropertyKey(STATUSUPDATES,
+ StatusUpdate.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ msgType,
+ msgId);
+ }
+
+ public PropertyKey stateTransitionError(String instanceName,
+ String sessionId,
+ String resourceName,
+ String partitionName)
+ {
+ return new PropertyKey(ERRORS,
+ Error.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName,
+ partitionName);
+ }
+
+ public PropertyKey stateTransitionErrors(String instanceName,
+ String sessionId,
+ String resourceName)
+ {
+ return new PropertyKey(ERRORS,
+ Error.class,
+ _clusterName,
+ instanceName,
+ sessionId,
+ resourceName);
+ }
+
+ /**
+ * Used to get status update for a NON STATE TRANSITION type
+ *
+ * @param instanceName
+ * @param sessionId
+ * @param msgType
+ * @param msgId
+ * @return
+ */
+ public PropertyKey taskError(String instanceName,
+ String sessionId,
+ String msgType,
+ String msgId)
+ {
+ return new PropertyKey(ERRORS,
+ null,
+ _clusterName,
+ instanceName,
+ sessionId,
+ msgType,
+ msgId);
+ }
+
+ public PropertyKey externalViews()
+ {
+ return new PropertyKey(EXTERNALVIEW, ExternalView.class, _clusterName);
+ }
+
+ public PropertyKey externalView(String resourceName)
+ {
+ return new PropertyKey(EXTERNALVIEW, ExternalView.class, _clusterName, resourceName);
+ }
+
+ // * addEntry(PropertyType.STATUSUPDATES_CONTROLLER, 4,
+ // *
+ // "/{clusterName}/CONTROLLER/STATUSUPDATES/{sessionId}/{subPath}/{recordName}"
+ // * ); addEntry(PropertyType.LEADER, 1,
+ // "/{clusterName}/CONTROLLER/LEADER");
+ // * addEntry(PropertyType.HISTORY, 1, "/{clusterName}/CONTROLLER/HISTORY");
+ // * addEntry(PropertyType.PAUSE, 1, "/{clusterName}/CONTROLLER/PAUSE");
+ // * addEntry(PropertyType.PERSISTENTSTATS, 1,
+ // * "/{clusterName}/CONTROLLER/PERSISTENTSTATS");
+ // addEntry(PropertyType.ALERTS,
+ // * 1, "/{clusterName}/CONTROLLER/ALERTS");
+ // addEntry(PropertyType.ALERT_STATUS,
+ // * 1, "/{clusterName}/CONTROLLER/ALERT_STATUS");
+ // * addEntry(PropertyType.ALERT_HISTORY, 1,
+ // * "/{clusterName}/CONTROLLER/ALERT_HISTORY"); // @formatter:on
+
+ public PropertyKey controller()
+ {
+ return new PropertyKey(CONTROLLER, null, _clusterName);
+ }
+
+ public PropertyKey controllerTaskErrors()
+ {
+ return new PropertyKey(ERRORS_CONTROLLER, StatusUpdate.class, _clusterName);
+ }
+
+ public PropertyKey controllerTaskError(String errorId)
+ {
+ return new PropertyKey(ERRORS_CONTROLLER, Error.class, _clusterName, errorId);
+ }
+
+ public PropertyKey controllerTaskStatuses(String subPath)
+ {
+ return new PropertyKey(STATUSUPDATES_CONTROLLER,
+ StatusUpdate.class,
+ _clusterName,
+ subPath);
+ }
+
+ public PropertyKey controllerTaskStatus(String subPath, String recordName)
+ {
+ return new PropertyKey(STATUSUPDATES_CONTROLLER,
+ StatusUpdate.class,
+ _clusterName,
+ subPath,
+ recordName);
+ }
+
+ public PropertyKey controllerMessages()
+ {
+ return new PropertyKey(MESSAGES_CONTROLLER, Message.class, _clusterName);
+ }
+
+ public PropertyKey controllerMessage(String msgId)
+ {
+ return new PropertyKey(MESSAGES_CONTROLLER, Message.class, _clusterName, msgId);
+ }
+
+ public PropertyKey controllerLeaderHistory()
+ {
+ return new PropertyKey(HISTORY, LeaderHistory.class, _clusterName);
+ }
+
+ public PropertyKey controllerLeader()
+ {
+ return new PropertyKey(LEADER, LiveInstance.class, _clusterName);
+ }
+
+ public PropertyKey pause()
+ {
+ return new PropertyKey(PAUSE, PauseSignal.class, _clusterName);
+ }
+
+ public PropertyKey persistantStat()
+ {
+ return new PropertyKey(PERSISTENTSTATS, PersistentStats.class, _clusterName);
+ }
+
+ public PropertyKey alerts()
+ {
+ return new PropertyKey(ALERTS, Alerts.class, _clusterName);
+ }
+
+ public PropertyKey alertStatus()
+ {
+ return new PropertyKey(ALERT_STATUS, AlertStatus.class, _clusterName);
+ }
+
+ public PropertyKey alertHistory()
+ {
+ return new PropertyKey(ALERT_HISTORY, AlertHistory.class, _clusterName);
+ }
+
+ public PropertyKey healthReport(String instanceName, String id)
+ {
+ return new PropertyKey(HEALTHREPORT,
+ HealthStat.class,
+ _clusterName,
+ instanceName,
+ id);
+ }
+
+ public PropertyKey healthReports(String instanceName)
+ {
+ return new PropertyKey(HEALTHREPORT, HealthStat.class, _clusterName, instanceName);
+ }
+
+ }
+
+ public PropertyType getType()
+ {
+ return _type;
+ }
+
+ public String[] getParams()
+ {
+ return _params;
+ }
+
+ public Class<? extends HelixProperty> getTypeClass()
+ {
+ return _typeClazz;
+ }
+
+ public static void main(String[] args)
+ {
+ ZkClient zkClient = new ZkClient("localhost:2181");
+ zkClient.waitUntilConnected(10, TimeUnit.SECONDS);
+ BaseDataAccessor baseDataAccessor = new ZkBaseDataAccessor(zkClient);
+ HelixDataAccessor accessor =
+ new ZKHelixDataAccessor("test-cluster", baseDataAccessor);
+ Builder builder = new PropertyKey.Builder("test-cluster");
+ HelixProperty value = new IdealState("test-resource");
+ accessor.createProperty(builder.idealStates("test-resource"), value);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/PropertyPathConfig.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyPathConfig.java b/helix-core/src/main/java/org/apache/helix/PropertyPathConfig.java
new file mode 100644
index 0000000..4cabfd1
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/PropertyPathConfig.java
@@ -0,0 +1,214 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+import static org.apache.helix.PropertyType.ALERTS;
+import static org.apache.helix.PropertyType.ALERT_STATUS;
+import static org.apache.helix.PropertyType.CONFIGS;
+import static org.apache.helix.PropertyType.CURRENTSTATES;
+import static org.apache.helix.PropertyType.EXTERNALVIEW;
+import static org.apache.helix.PropertyType.HEALTHREPORT;
+import static org.apache.helix.PropertyType.HISTORY;
+import static org.apache.helix.PropertyType.IDEALSTATES;
+import static org.apache.helix.PropertyType.LIVEINSTANCES;
+import static org.apache.helix.PropertyType.MESSAGES;
+import static org.apache.helix.PropertyType.PAUSE;
+import static org.apache.helix.PropertyType.STATEMODELDEFS;
+import static org.apache.helix.PropertyType.STATUSUPDATES;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.helix.model.AlertStatus;
+import org.apache.helix.model.Alerts;
+import org.apache.helix.model.CurrentState;
+import org.apache.helix.model.ExternalView;
+import org.apache.helix.model.HealthStat;
+import org.apache.helix.model.IdealState;
+import org.apache.helix.model.InstanceConfig;
+import org.apache.helix.model.LeaderHistory;
+import org.apache.helix.model.LiveInstance;
+import org.apache.helix.model.Message;
+import org.apache.helix.model.PauseSignal;
+import org.apache.helix.model.StateModelDefinition;
+import org.apache.helix.model.StatusUpdate;
+import org.apache.log4j.Logger;
+
+
+public class PropertyPathConfig
+{
+ private static Logger logger = Logger.getLogger(PropertyPathConfig.class);
+
+ static Map<PropertyType, Map<Integer, String>> templateMap = new HashMap<PropertyType, Map<Integer, String>>();
+ static Map<PropertyType, Class<? extends HelixProperty>> typeToClassMapping= new HashMap<PropertyType, Class<? extends HelixProperty>>();
+ static{
+ typeToClassMapping.put(LIVEINSTANCES, LiveInstance.class);
+ typeToClassMapping.put(IDEALSTATES, IdealState.class);
+ typeToClassMapping.put(CONFIGS, InstanceConfig.class);
+ typeToClassMapping.put(EXTERNALVIEW, ExternalView.class);
+ typeToClassMapping.put(STATEMODELDEFS, StateModelDefinition.class);
+ typeToClassMapping.put(MESSAGES, Message.class);
+ typeToClassMapping.put(CURRENTSTATES, CurrentState.class);
+ typeToClassMapping.put(STATUSUPDATES, StatusUpdate.class);
+ typeToClassMapping.put(HISTORY, LeaderHistory.class);
+ typeToClassMapping.put(HEALTHREPORT, HealthStat.class);
+ typeToClassMapping.put(ALERTS, Alerts.class);
+ typeToClassMapping.put(ALERT_STATUS, AlertStatus.class);
+ typeToClassMapping.put(PAUSE, PauseSignal.class);
+ }
+ static
+ {
+ // @formatter:off
+ addEntry(PropertyType.CONFIGS, 1, "/{clusterName}/CONFIGS");
+ addEntry(PropertyType.CONFIGS, 2, "/{clusterName}/CONFIGS/{scope}");
+ addEntry(PropertyType.CONFIGS, 3, "/{clusterName}/CONFIGS/{scope}/{scopeKey}");
+ // addEntry(PropertyType.CONFIGS,2,"/{clusterName}/CONFIGS/{instanceName}");
+ addEntry(PropertyType.LIVEINSTANCES, 1, "/{clusterName}/LIVEINSTANCES");
+ addEntry(PropertyType.LIVEINSTANCES, 2, "/{clusterName}/LIVEINSTANCES/{instanceName}");
+ addEntry(PropertyType.INSTANCES, 1, "/{clusterName}/INSTANCES");
+ addEntry(PropertyType.INSTANCES, 2, "/{clusterName}/INSTANCES/{instanceName}");
+ addEntry(PropertyType.IDEALSTATES, 1, "/{clusterName}/IDEALSTATES");
+ addEntry(PropertyType.IDEALSTATES, 2, "/{clusterName}/IDEALSTATES/{resourceName}");
+ addEntry(PropertyType.EXTERNALVIEW, 1, "/{clusterName}/EXTERNALVIEW");
+ addEntry(PropertyType.EXTERNALVIEW, 2, "/{clusterName}/EXTERNALVIEW/{resourceName}");
+ addEntry(PropertyType.STATEMODELDEFS, 1, "/{clusterName}/STATEMODELDEFS");
+ addEntry(PropertyType.STATEMODELDEFS, 2, "/{clusterName}/STATEMODELDEFS/{stateModelName}");
+ addEntry(PropertyType.CONTROLLER, 1, "/{clusterName}/CONTROLLER");
+ addEntry(PropertyType.PROPERTYSTORE, 1, "/{clusterName}/PROPERTYSTORE");
+ addEntry(PropertyType.HELIX_PROPERTYSTORE, 1, "/{clusterName}/HELIX_PROPERTYSTORE");
+
+ // INSTANCE
+ addEntry(PropertyType.MESSAGES, 2, "/{clusterName}/INSTANCES/{instanceName}/MESSAGES");
+ addEntry(PropertyType.MESSAGES, 3, "/{clusterName}/INSTANCES/{instanceName}/MESSAGES/{msgId}");
+ addEntry(PropertyType.CURRENTSTATES, 2, "/{clusterName}/INSTANCES/{instanceName}/CURRENTSTATES");
+ addEntry(PropertyType.CURRENTSTATES, 3,
+ "/{clusterName}/INSTANCES/{instanceName}/CURRENTSTATES/{sessionId}");
+ addEntry(PropertyType.CURRENTSTATES, 4,
+ "/{clusterName}/INSTANCES/{instanceName}/CURRENTSTATES/{sessionId}/{resourceName}");
+ addEntry(PropertyType.CURRENTSTATES, 5,
+ "/{clusterName}/INSTANCES/{instanceName}/CURRENTSTATES/{sessionId}/{resourceName}/{bucketName}");
+ addEntry(PropertyType.STATUSUPDATES, 2, "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES");
+ addEntry(PropertyType.STATUSUPDATES, 3,
+ "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES/{sessionId}");
+ addEntry(PropertyType.STATUSUPDATES, 4,
+ "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES/{sessionId}/{subPath}");
+ addEntry(PropertyType.STATUSUPDATES, 5,
+ "/{clusterName}/INSTANCES/{instanceName}/STATUSUPDATES/{sessionId}/{subPath}/{recordName}");
+ addEntry(PropertyType.ERRORS, 2, "/{clusterName}/INSTANCES/{instanceName}/ERRORS");
+ addEntry(PropertyType.ERRORS, 3, "/{clusterName}/INSTANCES/{instanceName}/ERRORS/{sessionId}");
+ addEntry(PropertyType.ERRORS, 4,
+ "/{clusterName}/INSTANCES/{instanceName}/ERRORS/{sessionId}/{subPath}");
+ addEntry(PropertyType.ERRORS, 5,
+ "/{clusterName}/INSTANCES/{instanceName}/ERRORS/{sessionId}/{subPath}/{recordName}");
+ addEntry(PropertyType.HEALTHREPORT, 2, "/{clusterName}/INSTANCES/{instanceName}/HEALTHREPORT");
+ addEntry(PropertyType.HEALTHREPORT, 3,
+ "/{clusterName}/INSTANCES/{instanceName}/HEALTHREPORT/{reportName}");
+ // CONTROLLER
+ addEntry(PropertyType.MESSAGES_CONTROLLER, 1, "/{clusterName}/CONTROLLER/MESSAGES");
+ addEntry(PropertyType.MESSAGES_CONTROLLER, 2, "/{clusterName}/CONTROLLER/MESSAGES/{msgId}");
+ addEntry(PropertyType.ERRORS_CONTROLLER, 1, "/{clusterName}/CONTROLLER/ERRORS");
+ addEntry(PropertyType.ERRORS_CONTROLLER, 2, "/{clusterName}/CONTROLLER/ERRORS/{errorId}");
+ addEntry(PropertyType.STATUSUPDATES_CONTROLLER, 1, "/{clusterName}/CONTROLLER/STATUSUPDATES");
+ addEntry(PropertyType.STATUSUPDATES_CONTROLLER, 2,
+ "/{clusterName}/CONTROLLER/STATUSUPDATES/{subPath}");
+ addEntry(PropertyType.STATUSUPDATES_CONTROLLER, 3,
+ "/{clusterName}/CONTROLLER/STATUSUPDATES/{subPath}/{recordName}");
+ addEntry(PropertyType.LEADER, 1, "/{clusterName}/CONTROLLER/LEADER");
+ addEntry(PropertyType.HISTORY, 1, "/{clusterName}/CONTROLLER/HISTORY");
+ addEntry(PropertyType.PAUSE, 1, "/{clusterName}/CONTROLLER/PAUSE");
+ addEntry(PropertyType.PERSISTENTSTATS, 1, "/{clusterName}/CONTROLLER/PERSISTENTSTATS");
+ addEntry(PropertyType.ALERTS, 1, "/{clusterName}/CONTROLLER/ALERTS");
+ addEntry(PropertyType.ALERT_STATUS, 1, "/{clusterName}/CONTROLLER/ALERT_STATUS");
+ addEntry(PropertyType.ALERT_HISTORY, 1, "/{clusterName}/CONTROLLER/ALERT_HISTORY");
+ // @formatter:on
+
+ }
+ static Pattern pattern = Pattern.compile("(\\{.+?\\})");
+
+ private static void addEntry(PropertyType type, int numKeys, String template)
+ {
+ if (!templateMap.containsKey(type))
+ {
+ templateMap.put(type, new HashMap<Integer, String>());
+ }
+ logger.trace("Adding template for type:" + type.getType() + " arguments:" + numKeys
+ + " template:" + template);
+ templateMap.get(type).put(numKeys, template);
+ }
+
+ public static String getPath(PropertyType type, String clusterName, String... keys)
+ {
+ if (clusterName == null)
+ {
+ logger.warn("ClusterName can't be null for type:" + type);
+ return null;
+ }
+ if (keys == null)
+ {
+ keys = new String[] {};
+ }
+ String template = null;
+ if (templateMap.containsKey(type))
+ {
+ // keys.length+1 since we add clusterName
+ template = templateMap.get(type).get(keys.length + 1);
+ }
+
+ String result = null;
+
+ if (template != null)
+ {
+ result = template;
+ Matcher matcher = pattern.matcher(template);
+ int count = 0;
+ while (matcher.find())
+ {
+ count = count + 1;
+ String var = matcher.group();
+ if (count == 1)
+ {
+ result = result.replace(var, clusterName);
+ } else
+ {
+ result = result.replace(var, keys[count - 2]);
+ }
+ }
+ }
+ if (result == null || result.indexOf('{') > -1 || result.indexOf('}') > -1)
+ {
+ logger.warn("Unable to instantiate template:" + template + " using clusterName:"
+ + clusterName + " and keys:" + Arrays.toString(keys));
+ }
+ return result;
+ }
+ public static String getInstanceNameFromPath(String path)
+ {
+ // path structure
+ // /<cluster_name>/instances/<instance_name>/[currentStates/messages]
+ if (path.contains("/" + PropertyType.INSTANCES + "/"))
+ {
+ String[] split = path.split("\\/");
+ if (split.length > 3)
+ {
+ return split[3];
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/437eb42e/helix-core/src/main/java/org/apache/helix/PropertyType.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/PropertyType.java b/helix-core/src/main/java/org/apache/helix/PropertyType.java
new file mode 100644
index 0000000..f709a9e
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/PropertyType.java
@@ -0,0 +1,193 @@
+/**
+ * Copyright (C) 2012 LinkedIn Inc <op...@linkedin.com>
+ *
+ * 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 org.apache.helix;
+
+
+enum Type
+{
+ CLUSTER, INSTANCE, CONTROLLER, RESOURCE;
+}
+
+public enum PropertyType
+{
+
+ // @formatter:off
+ // CLUSTER PROPERTIES
+ CONFIGS(Type.CLUSTER, true, false, false, false, true),
+ LIVEINSTANCES(Type.CLUSTER, false, false, false, true, true),
+ INSTANCES(Type.CLUSTER, true, false),
+ IDEALSTATES(Type.CLUSTER, true, false, false, false, true),
+ EXTERNALVIEW(Type.CLUSTER, true, false),
+ STATEMODELDEFS(Type.CLUSTER, true, false, false, false, true),
+ CONTROLLER(Type.CLUSTER, true, false),
+ PROPERTYSTORE(Type.CLUSTER, true, false),
+ HELIX_PROPERTYSTORE(Type.CLUSTER, true, false),
+
+ // INSTANCE PROPERTIES
+ MESSAGES(Type.INSTANCE, true, true, true),
+ CURRENTSTATES(Type.INSTANCE, true, true, false, false, true),
+ STATUSUPDATES(Type.INSTANCE, true, true, false, false, false, true),
+ ERRORS(Type.INSTANCE, true, true),
+ HEALTHREPORT(Type.INSTANCE, true, false, false, false, false, true),
+
+ // CONTROLLER PROPERTY
+ LEADER(Type.CONTROLLER, false, false, true, true),
+ HISTORY(Type.CONTROLLER, true, true, true),
+ PAUSE(Type.CONTROLLER, true, false, true),
+ MESSAGES_CONTROLLER(Type.CONTROLLER, true, false, true),
+ STATUSUPDATES_CONTROLLER(Type.CONTROLLER, true, true, true),
+ ERRORS_CONTROLLER(Type.CONTROLLER, true, true, true),
+ PERSISTENTSTATS(Type.CONTROLLER, true, false, false, false),
+ ALERTS(Type.CONTROLLER, true, false, false, false),
+ ALERT_STATUS(Type.CONTROLLER, true, false, false, false),
+ ALERT_HISTORY(Type.CONTROLLER, true, false, false, false);
+
+ // @formatter:on
+
+ Type type;
+
+ boolean isPersistent;
+
+ boolean mergeOnUpdate;
+
+ boolean updateOnlyOnExists;
+
+ boolean createOnlyIfAbsent;
+
+ /**
+ * "isCached" defines whether the property is cached in data accessor if data is cached,
+ * then read from zk can be optimized
+ */
+ boolean isCached;
+
+ boolean usePropertyTransferServer;
+
+ private PropertyType(Type type, boolean isPersistent, boolean mergeOnUpdate)
+ {
+ this(type, isPersistent, mergeOnUpdate, false);
+ }
+
+ private PropertyType(Type type,
+ boolean isPersistent,
+ boolean mergeOnUpdate,
+ boolean updateOnlyOnExists)
+ {
+ this(type, isPersistent, mergeOnUpdate, false, false);
+ }
+
+ private PropertyType(Type type,
+ boolean isPersistent,
+ boolean mergeOnUpdate,
+ boolean updateOnlyOnExists,
+ boolean createOnlyIfAbsent)
+ {
+ this(type, isPersistent, mergeOnUpdate, updateOnlyOnExists, createOnlyIfAbsent, false);
+ }
+
+ private PropertyType(Type type,
+ boolean isPersistent,
+ boolean mergeOnUpdate,
+ boolean updateOnlyOnExists,
+ boolean createOnlyIfAbsent,
+ boolean isCached)
+ {
+ this(type,
+ isPersistent,
+ mergeOnUpdate,
+ updateOnlyOnExists,
+ createOnlyIfAbsent,
+ isCached,
+ false);
+ }
+
+ private PropertyType(Type type,
+ boolean isPersistent,
+ boolean mergeOnUpdate,
+ boolean updateOnlyOnExists,
+ boolean createOnlyIfAbsent,
+ boolean isCached,
+ boolean isAsyncWrite)
+ {
+ this.type = type;
+ this.isPersistent = isPersistent;
+ this.mergeOnUpdate = mergeOnUpdate;
+ this.updateOnlyOnExists = updateOnlyOnExists;
+ this.createOnlyIfAbsent = createOnlyIfAbsent;
+ this.isCached = isCached;
+ this.usePropertyTransferServer = isAsyncWrite;
+ }
+
+ public boolean isCreateOnlyIfAbsent()
+ {
+ return createOnlyIfAbsent;
+ }
+
+ public void setCreateIfAbsent(boolean createIfAbsent)
+ {
+ this.createOnlyIfAbsent = createIfAbsent;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+
+ public void setType(Type type)
+ {
+ this.type = type;
+ }
+
+ public boolean isPersistent()
+ {
+ return isPersistent;
+ }
+
+ public void setPersistent(boolean isPersistent)
+ {
+ this.isPersistent = isPersistent;
+ }
+
+ public boolean isMergeOnUpdate()
+ {
+ return mergeOnUpdate;
+ }
+
+ public void setMergeOnUpdate(boolean mergeOnUpdate)
+ {
+ this.mergeOnUpdate = mergeOnUpdate;
+ }
+
+ public boolean isUpdateOnlyOnExists()
+ {
+ return updateOnlyOnExists;
+ }
+
+ public void setUpdateOnlyOnExists(boolean updateOnlyOnExists)
+ {
+ this.updateOnlyOnExists = updateOnlyOnExists;
+ }
+
+ public boolean isCached()
+ {
+ return isCached;
+ }
+
+ public boolean usePropertyTransferServer()
+ {
+ return usePropertyTransferServer;
+ }
+
+}