flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cd...@apache.org
Subject [06/51] [partial] flex-blazeds git commit: Removed legacy directories and made the content of the modules directory the new root - Please use the maven build for now as the Ant build will no longer work untill it is adjusted to the new directory structur
Date Sun, 20 Dec 2015 13:13:46 GMT
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/cluster/ClusterManager.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/cluster/ClusterManager.java b/core/src/flex/messaging/cluster/ClusterManager.java
new file mode 100644
index 0000000..07ef180
--- /dev/null
+++ b/core/src/flex/messaging/cluster/ClusterManager.java
@@ -0,0 +1,673 @@
+/*
+ * 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.
+ */
+package flex.messaging.cluster;
+
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Collections;
+import java.util.TreeSet;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import flex.messaging.Destination;
+import flex.messaging.MessageBroker;
+import flex.messaging.config.ClusterSettings;
+import flex.messaging.config.ConfigMap;
+import flex.messaging.endpoints.Endpoint;
+import flex.messaging.util.ClassUtil;
+
+/**
+ *
+ * The manager of all clusters defined in services-config.xml, and the broker
+ * for the clusters created for clustered destinations.
+ */
+public class ClusterManager
+{
+    /**
+     * Supported operations.
+     */
+    public static final String OPERATION_ADD_ENDPOINT_FOR_CHANNEL = "addEndpointForChannel";
+    public static final String OPERATION_SEND_ENDPOINT_URL = "sendEndpointUrl";
+    public static final String OPERATION_RECEIVE_ENDPOINT_URL = "receiveEndpointUrl";
+
+    public static final String OPERATION_PUSH_MESSAGE_FROM_PEER = "pushMessageFromPeer";
+    public static final String OPERATION_PEER_SYNC_AND_PUSH = "peerSyncAndPush";
+    public static final String OPERATION_REQUEST_ADAPTER_STATE = "requestAdapterState";
+    public static final String OPERATION_RECEIVE_ADAPTER_STATE = "receiveAdapterState";
+    public static final String OPERATION_SEND_SUBSCRIPTIONS = "sendSubscriptions";
+    public static final String OPERATION_RECEIVE_SUBSCRIPTIONS = "receiveSubscriptions";
+    public static final String OPERATION_SUBSCRIBE_FROM_PEER = "subscribeFromPeer";
+    public static final String OPERATION_PUSH_MESSAGE_FROM_PEER_TO_PEER = "pushMessageFromPeerToPeer";
+    public static final String OPERATION_PEER_SYNC_AND_PUSH_ONE_TO_PEER = "peerSyncAndPushOneToPeer";
+
+    /**
+     * A link to the MessageBroker.
+     */
+    private MessageBroker broker;
+
+    /**
+     * A mapping between the cluster ids and the Cluster instances.
+     * name=clusterId value=clusterInstance
+     */
+    private LinkedHashMap<String,Cluster> clusters;
+
+    /**
+     * A mapping between destinations and the Cluster instances.
+     */
+    private Map<String, Cluster> clustersForDestination;
+
+    /**
+     * A mapping between cluster ids and their configuration files.
+     * name=clusterId value=propsFile
+     */
+    private Map<String, Element> clusterConfig;
+
+    /**
+     * A mapping between cluster ids and ClusterSettings instances.
+     * name=clusterId value=ClusterSettings
+     */
+    private Map<String, ClusterSettings> clusterSettings;    
+
+    /**
+     * A mapped between destinations and a boolean representing
+     * whether or not the backend for the destination is shared.
+     */
+    private Map<String, Boolean> backendSharedForDestination;
+
+    /**
+     * The default cluster when the cluster id for the destination
+     * is unspecified.
+     */
+    private Cluster defaultCluster;
+
+    /**
+     * The id of the default cluster.
+     */
+    private String defaultClusterId;
+
+    /**
+     * The manager of all clusters defined in services-config.xml, and the broker
+     * for the clusters created for clustered destinations.  This class provides
+     * an entry point and abstraction to the logical cluster implementation as
+     * well as the specific cluster implementation.
+     * @param broker the message broker which uses the cluster manager
+     */
+    public ClusterManager(MessageBroker broker)
+    {
+        this.broker = broker;
+        clusters = new LinkedHashMap<String,Cluster>();
+        clusterConfig = new HashMap<String, Element>();
+        clusterSettings = new HashMap<String, ClusterSettings>();
+        clustersForDestination = new HashMap<String,Cluster>();
+        backendSharedForDestination = new HashMap<String, Boolean>();
+    }
+
+    /**
+     * The MessageBroker for this cluster.
+     *
+     * @return The defined MessageBroker.
+     */
+    public MessageBroker getMessageBroker()
+    {
+        return broker;
+    }
+
+    /**
+     * The default cluster when the cluster id for the destination
+     * is unspecified.
+     * @return Cluster the default Cluster to use
+     */
+    public Cluster getDefaultCluster()
+    {
+        return defaultCluster;
+    }
+
+    /**
+     * The id of the default cluster.
+     * @return String the default cluster ID
+     */
+    public String getDefaultClusterId()
+    {
+        return defaultClusterId;
+    }
+
+    /**
+     * Invoke an endpoint operation across the cluster.
+     * <p>
+     * NOTE: Endpoints don't reference a specific cluster so the default cluster is used for the broadcast.
+     * If no default cluster is defined the operation is broadcast over all defined clusters.
+     * </p>
+     *
+     * @param endpointId The id of the remote endpoint across the cluster to invoke an operation on.
+     * @param operationName The name of the operation to invoke.
+     * @param params The arguments to use for operation invocation.
+     */
+    public void invokeEndpointOperation(String endpointId, String operationName, Object[] params)
+    {
+        Object[] arguments = new Object[2 + params.length];
+        arguments[0] = endpointId;
+        arguments[1] = operationName;
+        int n = params.length;
+        for (int i = 2, j = 0; j < n; ++i, ++j)
+            arguments[i] = params[j];
+
+        if (defaultCluster != null)
+        {
+            defaultCluster.broadcastServiceOperation(operationName, arguments);
+        }
+        else
+        {
+            for (Cluster cluster : clusters.values())
+                cluster.broadcastServiceOperation(operationName, arguments);
+        }
+    }
+
+    /**
+     * Invoke an endpoint operation on a specific peer within the cluster.
+     * <p>
+     * NOTE: Endpoints don't reference a specific cluster so the default cluster is used for the broadcast.
+     * If no default cluster is defined the operation is broadcast over all defined clusters.
+     * </p>
+     *
+     * @param endpointId The id of the remote endpoint across the cluster to invoke an operation on.
+     * @param operationName The name of the operation to invoke.
+     * @param params The arguments to use for operation invocation.
+     * @param targetAddress The peer node that the operation should be invoked on.
+     */
+    public void invokePeerToPeerEndpointOperation(String endpointId, String operationName, Object[] params, Object targetAddress)
+    {
+        Object[] arguments = new Object[2 + params.length];
+        arguments[0] = endpointId;
+        arguments[1] = operationName;
+        int n = params.length;
+        for (int i = 2, j = 0; j < n; ++i, ++j)
+            arguments[i] = params[j];
+
+        if (defaultCluster != null)
+        {
+            defaultCluster.sendPointToPointServiceOperation(operationName, arguments, targetAddress);
+        }
+        else
+        {
+            for (Cluster cluster : clusters.values())
+            {
+                cluster.sendPointToPointServiceOperation(operationName, arguments, targetAddress);
+            }
+        }
+    }
+
+    /**
+     * Invoke a service-related operation, which usually includes a Message as a method parameter. This method
+     * allows a local service to process a Message and then send the Message to the services on all peer nodes
+     * so that they may perform the same processing. Invoke the service operation for the cluster, identified by
+     * serviceType and destinationName.
+     *
+     * @param serviceType The name for the service for this destination.
+     * @param destinationName The name of the destination.
+     * @param operationName The name of the service operation to invoke.
+     * @param params Parameters needed for the service operation.
+     */
+    public void invokeServiceOperation(String serviceType, String destinationName,
+                                       String operationName, Object[] params)
+    {
+        Cluster c = getCluster(serviceType,destinationName);
+        ArrayList newParams = new ArrayList(Arrays.asList(params));
+        newParams.add(0, serviceType);
+        newParams.add(1, destinationName);
+        c.broadcastServiceOperation(operationName, newParams.toArray());
+    }
+
+    /**
+     * Send a service-related operation in point-to-point fashion to one and only one member of the cluster.
+     * This is similar to the invokeServiceOperation except that this invocation is sent to the node,
+     * identified by targetAddress.
+     *
+     * @param serviceType The name for the service for this destination.
+     * @param destinationName The name of the destination.
+     * @param operationName The name of the service operation to invoke.
+     * @param params Parameters needed for the service operation.
+     * @param targetAddress The node that the operation should be passed to.
+     */
+    public void invokePeerToPeerOperation(String serviceType, String destinationName,
+                                          String operationName, Object[] params, Object targetAddress)
+    {
+        Cluster c = getCluster(serviceType,destinationName);
+        ArrayList newParams = new ArrayList(Arrays.asList(params));
+        newParams.add(0, serviceType);
+        newParams.add(1, destinationName);
+        c.sendPointToPointServiceOperation(operationName, newParams.toArray(), targetAddress);
+    }
+
+    /**
+     * Determines whether the given destination is clustered.
+     *
+     * @param serviceType The name for the service for this destination.
+     * @param destinationName The name of the destination.
+     * @return Whether the destination is a clustered destination.
+     */
+    public boolean isDestinationClustered(String serviceType, String destinationName)
+    {
+        return getCluster(serviceType, destinationName) != null;
+    }
+
+    /**
+     * Checks whether the give destination is configured for a shared backend.
+     *
+     * @param serviceType The name of the service for this destination.
+     * @param destinationName The name of the destination.
+     * @return Whether the destination is configured for shared backend.
+     */
+    public boolean isBackendShared(String serviceType, String destinationName)
+    {
+        String destKey = Cluster.getClusterDestinationKey(serviceType, destinationName);
+        Boolean shared = backendSharedForDestination.get(destKey);
+        return shared != null? shared.booleanValue() : false;
+    }
+
+    /**
+     * Retrieves a list of cluster nodes for the given cluster.
+     *
+     * @param serviceType The name of the service for the clustered destination.
+     * @param destinationName The name of the destination.
+     * @return List of cluster nodes for the given cluster.
+     */
+    public List getClusterMemberAddresses(String serviceType, String destinationName)
+    {
+        Cluster c= getCluster(serviceType, destinationName);
+        return c != null? c.getMemberAddresses() :  Collections.EMPTY_LIST;
+    }
+
+    /**
+     * Used for targeted endpoint operation invocations across the cluster.
+     * If a default cluster is defined, its list of member addresses is returned.
+     * Otherwise, a de-duped list of all member addresses from all registered clusters is returned.
+     *
+     * @return The list of cluster nodes that endpoint operation invocations can be issued against.
+     */
+    public List getClusterMemberAddresses()
+    {
+        if (defaultCluster != null)
+            return defaultCluster.getMemberAddresses();
+
+        TreeSet uniqueAddresses = new TreeSet();
+        for (Cluster cluster : clusters.values())
+            uniqueAddresses.addAll(cluster.getMemberAddresses());
+
+        return new ArrayList(uniqueAddresses);
+    }
+
+    /**
+     * Find the properties file in the given cluster settings.  Read the XML based
+     * cluster configuration file and save the settings and configuration for the
+     * given cluster for retrieval later.
+     *
+     * @param settings The cluster settings for a specific cluster.
+     */
+    public void prepareCluster(ClusterSettings settings)
+    {
+        String propsFileName = settings.getPropsFileName();
+
+        checkForNullPropertiesFile(settings.getClusterName(), propsFileName);
+
+        InputStream propsFile = resolveInternalPath(propsFileName);
+
+        if( propsFile == null )
+            propsFile = resolveExternalPath(propsFileName);
+
+        if (propsFile == null)
+            throwClusterException(10208, new Object[] {propsFileName}, null);
+
+        try
+        {
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(false);
+            factory.setValidating(false);
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            Document doc = builder.parse(propsFile);
+            if (settings.isDefault())
+                defaultClusterId = settings.getClusterName();
+            clusterConfig.put(settings.getClusterName(), doc.getDocumentElement());
+            clusterSettings.put(settings.getClusterName(), settings);
+        }
+        catch (Exception ex)
+        {
+            throwClusterException(10213, new Object[] {propsFileName}, ex);
+        }
+    }
+
+    /**
+     * Retrieve the local address for the specified clustered destination.
+     *
+     * @param serviceType The service type of the clustered destination.
+     * @param destinationName The name of the clustered destination.
+     * @return The local address of the clustered destination.
+     */
+    public Object getLocalAddress(String serviceType, String destinationName)
+    {
+        Cluster c = getCluster(serviceType, destinationName);
+        return c != null? c.getLocalAddress() : null;
+    }
+
+    /**
+     * Retrieve the local address for the default cluster or if no default cluster is defined
+     * return the local address derived from the first cluster of any defined.
+     *
+     * @return The local address for this cluster node, or <code>null</code> if this node
+     *         is not a member of any cluster.
+     */
+    public Object getLocalAddress()
+    {
+        if (defaultCluster != null)
+            return defaultCluster.getLocalAddress();
+
+        // Else, use first defined cluster.
+        for (Entry<String,Cluster> entry : clusters.entrySet())
+            return entry.getValue().getLocalAddress();
+
+        return null; // No cluster defined.
+    }
+
+    /**
+     * Find the cluster for the specified cluster id.
+     *
+     * @param clusterId the cluster ID
+     * @return The cluster identified by the given id.
+     */
+    public Cluster getClusterById(String clusterId)
+    {
+        return clusters.get(clusterId);
+    }
+
+    /**
+     * Find the cluster identified by the service type and destination name.
+     *
+     * @param serviceType The service type of the clustered destination.
+     * @param destinationName The name of the clustered destination.
+     * @return The cluster identified by the serviec type and destination naem.
+     */
+    public Cluster getCluster(String serviceType, String destinationName)
+    {
+        Cluster cluster = null;
+        try
+        {
+            String destKey = Cluster.getClusterDestinationKey(serviceType, destinationName);
+
+            cluster = clustersForDestination.get(destKey);
+
+            if (cluster == null)
+                cluster = defaultCluster;
+        }
+        catch (NoClassDefFoundError nex)
+        {
+            ClusterException cx = new ClusterException();
+            cx.setMessage(10202, new Object[] { destinationName });
+            cx.setRootCause(nex);
+            throw cx;
+        }
+        return cluster;
+    }
+
+    /**
+     * Call destroy on each of the managed clusters.
+     */
+    public void destroyClusters()
+    {
+        for (Iterator<Cluster> iter=clusters.values().iterator(); iter.hasNext(); )
+        {
+            Cluster cluster = iter.next();
+            cluster.destroy();
+            iter.remove();
+        }
+    }
+
+    /**
+     * Add the specified destination to the cluster, identitied by clusterId if available.  If the cluster
+     * is not currently defined, create the cluster.  Also, setup the load balancing urls and shared
+     * backend information for this clustered destination and endpoint.
+     *
+     * @param clusterId The cluster id that this destination wants to be associated with.
+     * @param serviceType The service type for the clustered destination.
+     * @param destinationName The name of the clustered destination.
+     * @param channelId The channel id that should be added to the cluster load balancing.
+     * @param endpointUrl The endpoint url that should be added to the cluster load balancing.
+     * @param endpointPort The endpoint port that should be added to the cluster load balancing.
+     * @param sharedBackend Whether the destination has shared backend set to true or not.
+     */
+    public void clusterDestinationChannel(String clusterId, String serviceType, String destinationName,
+                                          String channelId, String endpointUrl, int endpointPort, boolean sharedBackend)
+    {
+        Cluster cluster = getClusterById(clusterId);
+        String destKey = Cluster.getClusterDestinationKey(serviceType, destinationName);
+        if (cluster == null)
+        {
+            if (!clusterConfig.containsKey(clusterId))
+            {
+                ClusterException cx = new ClusterException();
+                cx.setMessage(10207, new Object[] { destinationName, clusterId });
+                throw cx;
+            }
+            cluster = createCluster(clusterId, serviceType, destinationName);
+        }
+        else
+        {
+            clustersForDestination.put(destKey, cluster);
+        }
+        backendSharedForDestination.put(destKey, sharedBackend ? Boolean.TRUE : Boolean.FALSE);
+
+        if (cluster.getURLLoadBalancing())
+            cluster.addLocalEndpointForChannel(serviceType, destinationName,
+                                               channelId, endpointUrl, endpointPort);
+    }
+
+    /**
+     * Adds the destination to the cluster.  The settings for the clustered destination are
+     * available from the <code>Destination</code> object.
+     *
+     * @param destination The destination to be clustered.
+     */
+    public void clusterDestination(Destination destination)
+    {
+        String clusterId = destination.getNetworkSettings().getClusterId();
+        if (clusterId == null)
+            clusterId = getDefaultClusterId();
+
+        ClusterSettings cls = clusterSettings.get(clusterId);
+        if (cls == null)
+        {
+            ClusterException ce = new ClusterException();
+            ce.setMessage(10217, new Object[] {destination.getId(), clusterId});
+            throw ce;
+        }
+
+        for (String channelId : destination.getChannels())
+        {
+            Endpoint endpoint = broker.getEndpoint(channelId);
+            String endpointUrl = endpoint.getUrl();
+            int endpointPort = endpoint.getPort();
+
+            // This is only an error if we are using client side url-based load balancing.  If
+            // there is a HW load balancer, then we can assume the server.name served up by the
+            // SWF can be used to access the cluster members.  With client side load balancing,
+            // the clients need the direct URLs of all of the servers.
+            if (cls.getURLLoadBalancing())
+            {
+                // Ensure that the endpoint URI does not contain any replacement tokens.
+                int tokenStart = endpointUrl.indexOf('{');
+                if (tokenStart != -1)
+                {
+                    int tokenEnd = endpointUrl.indexOf('}', tokenStart);
+                    if (tokenEnd == -1)
+                        tokenEnd = endpointUrl.length();
+                    else
+                        tokenEnd++;
+
+                    ClusterException ce = new ClusterException();
+                    ce.setMessage(10209, new Object[] {destination.getId(), channelId, endpointUrl.substring(tokenStart, tokenEnd)});
+                    throw ce;
+                }
+            }
+
+            clusterDestinationChannel(clusterId, destination.getServiceType(), 
+                    destination.getId(), channelId, endpointUrl, endpointPort, destination.getNetworkSettings().isSharedBackend());
+      }
+    }
+
+    /**
+     * Get a list of endpoints for the destination.
+     * @param serviceType the service type
+     * @param destinationName destination name
+     * @return List the list endpoints that the destination can use
+     */
+    public List getEndpointsForDestination(String serviceType, String destinationName)
+    {
+        Cluster c = getCluster(serviceType, destinationName);
+        return c != null? c.getAllEndpoints(serviceType, destinationName) : null;
+    }
+
+
+    private void checkForNullPropertiesFile(String clusterName, String propsFileName)
+    {
+        if (propsFileName == null)
+            throwClusterException(10201, new Object[] {clusterName, propsFileName}, null);
+    }
+
+    /**
+     * Create the cluster based on the cluster settings already available. The cluster
+     * is added to the cluster managers list of clusters indexed by the cluster id.
+     * The cluster is also associated with the specified service type and destination
+     * name.  The cluster id is unique across all clusters managed by this cluster
+     * manager.  The cluster may be associated with more than one cluster destination.
+     *
+     * @param clusterId The cluster id.
+     * @param serviceType The service type of the clustered destination.
+     * @param destinationName The destination name for the clustered destination.
+     * @return The new cluster.
+     */
+    private Cluster createCluster(String clusterId, String serviceType, String destinationName)
+    {
+        String destKey = Cluster.getClusterDestinationKey(serviceType, destinationName);
+        Element propsFile = clusterConfig.get(clusterId);
+        ClusterSettings cls = clusterSettings.get(clusterId);
+        Cluster cluster = null;
+        Class clusterClass = ClassUtil.createClass(cls.getImplementationClass());
+        Constructor clusterConstructor = null;
+        try
+        {
+            clusterConstructor = clusterClass.getConstructor(ClusterManager.class);
+        }
+        catch (Exception e)
+        {
+            ClusterException cx = new ClusterException();
+            cx.setMessage(10210);
+            cx.setRootCause(e);
+            throw cx;
+        }
+        try
+        {
+            cluster = (Cluster)clusterConstructor.newInstance(this);
+            cluster.setClusterPropertiesFile(propsFile);
+            cluster.setURLLoadBalancing(cls.getURLLoadBalancing());
+            cluster.initialize(clusterId, cls.getProperties());
+        }
+        catch (Exception e)
+        {
+            ClusterException cx = new ClusterException();
+            cx.setMessage(10211);
+            cx.setRootCause(e);
+            throw cx;
+        }
+        clustersForDestination.put(destKey, cluster);
+        clusters.put(clusterId, cluster);
+
+        if (defaultClusterId != null && defaultClusterId.equals(clusterId))
+            defaultCluster = cluster;
+
+        return cluster;
+    }
+
+    private InputStream resolveExternalPath(String propsFileName)
+    {
+        try
+        {
+            return broker.resolveExternalPath(propsFileName);
+        }
+        catch (Throwable t)
+        {
+            throwClusterException(10208, new Object[] {propsFileName}, t);
+        }
+        return null;
+    }
+
+    private InputStream resolveInternalPath(String propsFileName)
+    {
+        try
+        {
+           return broker.resolveInternalPath(propsFileName);
+        }
+        catch (Throwable t)
+        {
+            throwClusterException(10208, new Object[] {propsFileName}, t);
+        }
+        return null;
+    }
+
+    private void throwClusterException(int number, Object[] args, Throwable t)
+    {
+        ClusterException cx = new ClusterException();
+        cx.setMessage(number, args);
+        if (t != null)
+            cx.setRootCause(t);
+        throw cx;
+    }
+    
+    /**
+     * Return a {@link ConfigMap} describing the clusters that have been added to the cluster manager
+     * 
+     * @return a ConfigMap of the clusters
+     */
+    public ConfigMap describeClusters()
+    {
+        ConfigMap result = new ConfigMap();
+        for (Entry<String, Cluster> entry: clusters.entrySet())
+        {
+            Cluster cluster = entry.getValue();
+            ConfigMap clusterMap = new ConfigMap();
+            clusterMap.put("id", entry.getKey());
+            ClusterSettings settings = clusterSettings.get(entry.getKey());
+            clusterMap.put("properties", settings.getPropsFileName());
+            if (settings.isDefault())
+            {
+                clusterMap.put("default", "true");
+            }
+            clusterMap.put("class", cluster.getClass().getCanonicalName());
+            
+            result.addProperty("cluster", clusterMap);
+        }
+        return result;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/cluster/ClusterMembershipListener.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/cluster/ClusterMembershipListener.java b/core/src/flex/messaging/cluster/ClusterMembershipListener.java
new file mode 100644
index 0000000..302163e
--- /dev/null
+++ b/core/src/flex/messaging/cluster/ClusterMembershipListener.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+package flex.messaging.cluster;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+
+import org.jgroups.Address;
+import org.jgroups.MembershipListener;
+import org.jgroups.View;
+
+/**
+ *
+ * Clusters employ this Listener in order to respond to nodes which
+ * join and abandon it. This class bridges the low-level protocol layer
+ * to the more abstract logical cluster.
+ */
+class ClusterMembershipListener implements MembershipListener
+{
+    /**
+     * The cluster implementation that owns this listener.
+     */
+   // TODO: The missing class JGroupsCluster seems to extend Cluster, but is missing from the repository.
+//    private JGroupsCluster cluster;
+
+    /**
+     * The list of current cluster members as we know it.
+     */
+    private List<Address> members;
+
+    /**
+     * The list of cluster members that are not currently active.
+     */
+    private List<Address> zombies;
+
+    /**
+     * Our implementation of cluster membership listener.
+     *
+     * @param cluster The logical cluster implementation.
+     */
+    public ClusterMembershipListener(Cluster cluster)
+    {
+//        this.cluster = (JGroupsCluster)cluster;
+        this.members = new ArrayList<Address>();
+        this.zombies = new ArrayList<Address>();
+    }
+
+    /**
+     * This method is invoked by the cluster infrastructure whenever
+     * a member joins or abandons the cluster group.
+     *
+     * @param membershipView Snapshot of members of the cluster.
+     */
+    public void viewAccepted(View membershipView)
+    {
+        synchronized(this)
+        {
+            Vector<Address> currentMemberList = membershipView.getMembers();
+            handleArrivingMembers(currentMemberList);
+            handleDepartedMembers(membershipView, currentMemberList);
+        }
+    }
+
+    /**
+     * This method is invoked by the cluster infrastructure whenever
+     * a member appears to have left the cluster, but before it has
+     * been removed from the active member list. The Cluster treats
+     * these addresses as zombies and will not use their channel and
+     * endpoint information.
+     *
+     * @param zombieAddress The address of the suspect node.
+     */
+    public void suspect(Address zombieAddress)
+    {
+        synchronized(this)
+        {
+            zombies.add(zombieAddress);
+        }
+    }
+
+    /**
+     * This method from the core MembershipListener is a no-op for
+     * the Flex destination Cluster.
+     */
+    public void block()
+    {
+        // No-op.
+    }
+
+    /**
+     * Allow the Cluster to determine whether a given physical address
+     * is a zombie.
+     *
+     * @param address The node to check.
+     * @return True, if the given address is a zombie.
+     */
+    public boolean isZombie(Address address)
+    {
+        return zombies.contains(address);
+    }
+
+    private void handleDepartedMembers(View membershipView, Vector<Address> currentMemberList)
+    {
+        for (Address member : members)
+        {
+            if (!membershipView.containsMember(member))
+            {
+//                cluster.removeClusterNode(member);
+                zombies.remove(member);
+            }
+        }
+        members = currentMemberList;
+    }
+
+    private void handleArrivingMembers(Vector<Address> currentMemberList)
+    {
+        for (Address member : currentMemberList) 
+        {
+/*            if (!cluster.getLocalAddress().equals(member) && !members.contains(member))
+                cluster.addClusterNode(member);*/
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/cluster/ClusterNode.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/cluster/ClusterNode.java b/core/src/flex/messaging/cluster/ClusterNode.java
new file mode 100644
index 0000000..6a0b64c
--- /dev/null
+++ b/core/src/flex/messaging/cluster/ClusterNode.java
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+package flex.messaging.cluster;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ *
+ * ClusterNode is an encapsulation for pairing a physical host and a logical
+ * software group, which is in effect a mapping between a physical address used
+ * by the cluster infrastructure and a service destination used by the message
+ * infrastructure.
+ *
+ * This class is specific to the <code>JGroupsCluster</code> implementation.
+ */
+public class ClusterNode
+{
+    /**
+     * The name of the host for this cluster node.
+     */
+    private final String host;
+
+    /**
+     * Mapping between clustered destinations and the
+     * clustered endpoint.
+     * key = destination key (String)
+     * value = Map of channel-id to endpoint-url mappings.
+     */
+    private final Map<String,Map<String,String>> destKeyToChannelMap;
+
+    /**
+     * Constructor.
+     */
+    ClusterNode(String host)
+    {
+        this.host = host;
+        destKeyToChannelMap = new HashMap<String,Map<String,String>>();
+    }
+
+    /**
+     * Returns the name of the host for this cluster node.
+     *
+     * @return The name of the host.
+     */
+    String getHost()
+    {
+        return host;
+    }
+
+    /**
+     * Returns a map of clustered destination to clustered
+     * endpoint mappings.
+     *
+     * @return Map of clustered destination to clustered
+    *  endpoint mappings.
+     */
+    Map<String,Map<String,String>> getDestKeyToChannelMap()
+    {
+        return destKeyToChannelMap;
+    }
+
+    /**
+     * Returns a map of clustered endpoints for the specified
+     * clustered destination. If there is not currently a
+     * map for the destination, an empty mapping is created
+     * and returned.
+     *
+     * The endpoint map is indexed by channel id.
+     * The endpoint map contains endpoint urls.
+     *
+     * @param serviceType The service type of the clustered destination.
+     * @param destName The destination name of the clustered destination.
+     * @return Map of clustered endpoints.
+     */
+    Map<String,String> getEndpoints(String serviceType, String destName)
+    {
+        String destKey = serviceType + ":" + destName;
+        synchronized (destKeyToChannelMap)
+        {
+            Map<String,String> channelEndpoints = destKeyToChannelMap.get(destKey);
+            if (channelEndpoints == null)
+            {
+                channelEndpoints = new HashMap<String,String>();
+                destKeyToChannelMap.put(destKey, channelEndpoints);
+            }
+            return channelEndpoints;
+        }
+    }
+
+    /**
+     * This method adds an endpoint to the list of endpoints for the clustered
+     * destination, identified by service type and destination name.
+     *
+     * @param serviceType The service type of the clustered destination.
+     * @param destName The destination name of the clustered destination.
+     * @param channelId The channel id to be added to the channel endpoint mapping.
+     * @param endpointUrl The endpoint url to be added to the endpoint url mapping.
+     */
+    void addEndpoint(String serviceType, String destName, String channelId, String endpointUrl)
+    {
+        synchronized (destKeyToChannelMap)
+        {
+            Map<String,String> channelEndpoints = getEndpoints(serviceType, destName);
+            channelEndpoints.put(channelId, endpointUrl);
+        }
+    }
+
+    /**
+     * Returns whether the endpoint, specified by channel id and endpoint url,
+     * is included in the list of endpoints in the clustered destination.
+     *
+     * @param serviceType The service type of the clustered destination.
+     * @param destName The destination name of the clustered destination.
+     * @param channelId The channel id to find in the list of endpoints.
+     * @param endpointUrl The endpoint url to find in the list of endpoints.
+     * @return Whether the endpoint is included in the list for the clustered destination.
+     */
+    boolean containsEndpoint(String serviceType, String destName, String channelId, String endpointUrl)
+    {
+        Map<String,String> channelEndpoints = getEndpoints(serviceType, destName);
+        return channelEndpoints.containsKey(channelId) && channelEndpoints.get(channelId).equals(endpointUrl);
+    }
+
+    /**
+     * Returns a description of the clustered node including details
+     * on the mapping between the clustered destinations on this node
+     * and their endpoint mappings.
+     *
+     * @return Description of the clustered node.
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer("ClusterNode[");
+        synchronized (destKeyToChannelMap)
+        {
+            for (Map.Entry<String,Map<String,String>> entry : destKeyToChannelMap.entrySet())
+            {
+                sb.append(" channels for ");
+                sb.append(entry.getKey());
+                sb.append('(');
+                for (Iterator<Map.Entry<String,String>> iter = entry.getValue().entrySet().iterator(); iter.hasNext();)
+                {
+                    Map.Entry<String,String> channelMapEntry = iter.next();
+                    sb.append(channelMapEntry.getKey());
+                    sb.append('=');
+                    sb.append(channelMapEntry.getValue());
+                    if (iter.hasNext())
+                        sb.append(", ");
+                }
+                sb.append(')');
+            }
+        }
+        sb.append(" ]");
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/cluster/RemoveNodeListener.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/cluster/RemoveNodeListener.java b/core/src/flex/messaging/cluster/RemoveNodeListener.java
new file mode 100644
index 0000000..05583c3
--- /dev/null
+++ b/core/src/flex/messaging/cluster/RemoveNodeListener.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+package flex.messaging.cluster;
+
+
+/**
+ *
+ * Called when a node leaves the cluster.  Note that for JGroups at least, this
+ * callback should not execute any "long running" operations.  This is indirectly
+ * called from the MembershipListener interface in JGroups.
+ */
+public interface RemoveNodeListener
+{
+    /**
+     * Callback that the clustering subsystem uses to notify that a
+     * node has been removed from the cluster.
+     *
+     * @address The node that was removed from the cluster.
+     */
+    void removeClusterNode(Object address);
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/cluster/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/cluster/package-info.java b/core/src/flex/messaging/cluster/package-info.java
new file mode 100644
index 0000000..0bbec3a
--- /dev/null
+++ b/core/src/flex/messaging/cluster/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+
+package flex.messaging.cluster;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/config/ApacheXPathServerConfigurationParser.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/config/ApacheXPathServerConfigurationParser.java b/core/src/flex/messaging/config/ApacheXPathServerConfigurationParser.java
new file mode 100644
index 0000000..29dd222
--- /dev/null
+++ b/core/src/flex/messaging/config/ApacheXPathServerConfigurationParser.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+package flex.messaging.config;
+
+import org.apache.xpath.CachedXPathAPI;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import javax.xml.transform.TransformerException;
+
+/**
+ * Uses Apache XPath on a DOM representation of a messaging configuration
+ * file.
+ * <p>
+ * Note: Since reference ids are used between elements, certain
+ * sections of the document need to be parsed first.
+ * </p>
+ *
+ *
+ */
+public class ApacheXPathServerConfigurationParser extends ServerConfigurationParser
+{
+    private CachedXPathAPI xpath;
+
+    protected void initializeExpressionQuery()
+    {
+        this.xpath = new CachedXPathAPI();
+    }
+
+    protected Node selectSingleNode(Node source, String expression)
+    {
+        try
+        {
+            return xpath.selectSingleNode(source, expression);
+        }
+        catch (TransformerException transformerException)
+        {
+            throw wrapException(transformerException);
+        }
+    }
+
+    protected NodeList selectNodeList(Node source, String expression)
+    {
+        try
+        {
+            return xpath.selectNodeList(source, expression);
+        }
+        catch (TransformerException transformerException)
+        {
+            throw wrapException(transformerException);
+        }
+    }
+
+    protected Object evaluateExpression(Node source, String expression)
+    {
+        try
+        {
+            return xpath.eval(source, expression);
+        }
+        catch (TransformerException transformerException)
+        {
+            throw wrapException(transformerException);
+        }
+    }
+
+    private ConfigurationException wrapException(TransformerException exception)
+    {
+       ConfigurationException result = new ConfigurationException();
+       result.setDetails(PARSER_INTERNAL_ERROR);
+       result.setRootCause(exception);
+       return result;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/config/ClasspathResourceResolver.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/config/ClasspathResourceResolver.java b/core/src/flex/messaging/config/ClasspathResourceResolver.java
new file mode 100644
index 0000000..cc4f90b
--- /dev/null
+++ b/core/src/flex/messaging/config/ClasspathResourceResolver.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+package flex.messaging.config;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Stack;
+
+public class ClasspathResourceResolver implements ConfigurationFileResolver {
+
+    private String baseConfigFileDirectory;
+
+    @Override
+    public InputStream getConfigurationFile(String path) {
+        final String cpPath = path.substring("classpath:".length());
+        baseConfigFileDirectory = cpPath.substring(0, cpPath.lastIndexOf("/"));
+        return this.getClass().getResourceAsStream(cpPath);
+    }
+
+    @Override
+    public InputStream getIncludedFile(String path) {
+        final String cpPath = baseConfigFileDirectory + "/" + path;
+        return this.getClass().getResourceAsStream(cpPath);
+    }
+
+    @Override
+    public void popIncludedFile() {
+    }
+
+    @Override
+    public List getFiles(String dir) {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/config/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/config/ConfigurationManager.java b/core/src/flex/messaging/config/ConfigurationManager.java
new file mode 100644
index 0000000..8f3f463
--- /dev/null
+++ b/core/src/flex/messaging/config/ConfigurationManager.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package flex.messaging.config;
+
+import javax.servlet.ServletConfig;
+
+import flex.messaging.log.LogCategories;
+
+/**
+ * ConfigurationManager interface
+ *
+ * The default implementation of the configuration manager is
+ * FlexConfigurationManager.  However, this value be specified in
+ * a servlet init-param &quot;services.configuration.manager&quot;
+ * to the MessageBrokerServlet.
+ *
+ *
+ */
+public interface ConfigurationManager
+{
+    String LOG_CATEGORY = LogCategories.CONFIGURATION;
+
+    MessagingConfiguration getMessagingConfiguration(ServletConfig servletConfig);
+
+    void reportTokens();
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/config/FactorySettings.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/config/FactorySettings.java b/core/src/flex/messaging/config/FactorySettings.java
new file mode 100644
index 0000000..aec365e
--- /dev/null
+++ b/core/src/flex/messaging/config/FactorySettings.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+package flex.messaging.config;
+
+import flex.messaging.FlexFactory;
+import flex.messaging.util.ClassUtil;
+
+/**
+ * The factory configuration defines a single factory in the flex
+ * configuration file.
+ *
+ *
+ */
+public class FactorySettings extends PropertiesSettings
+{
+    protected String id;
+    protected String className;
+
+    public FactorySettings(String id, String className)
+    {
+        this.id = id;
+        this.className = className;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public String getClassName()
+    {
+        return className;
+    }
+
+    public FlexFactory createFactory()
+    {
+        return createFactory(null);
+    }
+
+    public FlexFactory createFactory(ClassLoader cl)
+    {
+        try
+        {
+            Class c = ClassUtil.createClass(className, cl);
+            Object f = ClassUtil.createDefaultInstance(c, FlexFactory.class);
+            if (f instanceof FlexFactory)
+            {
+                FlexFactory ff = (FlexFactory) f;
+                ff.initialize(getId(), getProperties());
+                return ff;
+            }
+            else
+            {
+                ConfigurationException cx = new ConfigurationException();
+                cx.setMessage(11101, new Object[] { className });
+                throw cx;
+            }
+        }
+        catch (Throwable th)
+        {
+            ConfigurationException cx = new ConfigurationException();
+            cx.setMessage(11102, new Object[] { className, th.toString() });
+            cx.setRootCause(th);
+            throw cx;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/config/FlexConfigurationManager.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/config/FlexConfigurationManager.java b/core/src/flex/messaging/config/FlexConfigurationManager.java
new file mode 100644
index 0000000..313cb87
--- /dev/null
+++ b/core/src/flex/messaging/config/FlexConfigurationManager.java
@@ -0,0 +1,317 @@
+/*
+ * 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.
+ */
+package flex.messaging.config;
+
+import flex.messaging.LocalizedException;
+import flex.messaging.util.Trace;
+import flex.messaging.util.ClassUtil;
+
+import javax.servlet.ServletConfig;
+import java.io.File;
+
+/**
+ * Manages which ConfigurationParser implementation will be
+ * used to read in the services configuration file and determines
+ * where the configuration file is located.
+ * <p>
+ * The default location of the configuration file is
+ * /WEB-INF/flex/services-config.xml, however this value can
+ * be specified in a servlet init-param &quot;services.configuration.file&quot;
+ * to the MessageBrokerServlet.
+ * </p>
+ * <p>
+ * The ConfigurationParser implementation can also be specified in
+ * a servlet init-param &quot;services.configuration.parser&quot; to
+ * the MessageBrokerServlet.
+ * </p>
+ *
+ * @see ConfigurationParser
+ *
+ */
+public class FlexConfigurationManager implements ConfigurationManager
+{
+    static final String DEFAULT_CONFIG_PATH = "/WEB-INF/flex/services-config.xml";
+
+    protected String configurationPath = null;
+    protected ConfigurationFileResolver configurationResolver = null;
+    protected ConfigurationParser parser = null;
+
+    public MessagingConfiguration getMessagingConfiguration(ServletConfig servletConfig)
+    {
+        MessagingConfiguration config = new MessagingConfiguration();
+
+        if (servletConfig != null)
+        {
+            String serverInfo = servletConfig.getServletContext().getServerInfo();
+            config.getSecuritySettings().setServerInfo(serverInfo);
+        }
+
+        verifyMinimumJavaVersion();
+
+        parser = getConfigurationParser(servletConfig);
+
+        if (parser == null)
+        {
+            // "Unable to create a parser to load messaging configuration."
+            LocalizedException lme = new LocalizedException();
+            lme.setMessage(10138);
+            throw lme;
+        }
+
+        setupConfigurationPathAndResolver(servletConfig);
+        parser.parse(configurationPath, configurationResolver, config);
+
+        if (servletConfig != null)
+        {
+            config.getSystemSettings().setPaths(servletConfig.getServletContext());
+        }
+
+        return config;
+    }
+
+    public void reportTokens()
+    {
+        parser.reportTokens();
+    }
+
+    protected ConfigurationParser getConfigurationParser(ServletConfig servletConfig)
+    {
+        ConfigurationParser parser = null;
+        Class parserClass = null;
+        String className = null;
+
+        // Check for Custom Parser Specification
+        if (servletConfig != null)
+        {
+            String p = servletConfig.getInitParameter("services.configuration.parser");
+            if (p != null)
+            {
+                className = p.trim();
+                try
+                {
+                    parserClass = ClassUtil.createClass(className);
+                    parser = (ConfigurationParser)parserClass.newInstance();
+                }
+                catch (Throwable t)
+                {
+                    if (Trace.config)
+                    {
+                        Trace.trace("Could not load configuration parser as: " + className);
+                    }
+                }
+            }
+        }
+
+        // Always try Sun JRE 1.4 / Apache Xalan Based Implementation first to
+        // avoid performance problems with Sun JRE 1.5 Based Implementation
+        if (parser == null)
+        {
+            try
+            {
+                ClassUtil.createClass("org.apache.xpath.CachedXPathAPI");
+                className = "flex.messaging.config.ApacheXPathServerConfigurationParser";
+                parserClass = ClassUtil.createClass(className);
+                parser = (ConfigurationParser)parserClass.newInstance();
+            }
+            catch (Throwable t)
+            {
+                if (Trace.config)
+                {
+                    Trace.trace("Could not load configuration parser as: " + className);
+                }
+            }
+        }
+
+        // Try Sun JRE 1.5 Based Implementation
+        if (parser == null)
+        {
+            try
+            {
+                className = "flex.messaging.config.XPathServerConfigurationParser";
+                parserClass = ClassUtil.createClass(className);
+                // double-check, on some systems the above loads but the import classes don't
+                ClassUtil.createClass("javax.xml.xpath.XPathExpressionException");
+
+                parser = (ConfigurationParser)parserClass.newInstance();
+            }
+            catch (Throwable t)
+            {
+                if (Trace.config)
+                {
+                    Trace.trace("Could not load configuration parser as: " + className);
+                }
+            }
+        }
+
+        if (Trace.config && parser != null)
+        {
+            Trace.trace("Services Configuration Parser: " + parser.getClass().getName());
+        }
+
+        return parser;
+    }
+
+    /**
+     * Sets up the configuration path and resolver objects.
+     * If no entry is specified in web.xml, assumed services-config.xml in the web application.
+     * If an entry is specified for windows starting with '/', it's assumed to be in the web application.
+     * If an entry is specified for windows not starting with '\', it's assumed to be on the local file system.
+     * If an entry is specified for non-windows starting with '/', we will first look in the web application
+     *  then the the local file system.
+     *
+     * @param servletConfig configuration
+     */
+    protected void setupConfigurationPathAndResolver(ServletConfig servletConfig)
+    {
+        if (servletConfig != null)
+        {
+            String p = servletConfig.getInitParameter("services.configuration.file");
+            if ((p == null) || (p.trim().length() == 0))
+            {
+                // no entry specified in web.xml, always use default and ServletResourceResolver
+                configurationPath = DEFAULT_CONFIG_PATH;
+                configurationResolver = new ServletResourceResolver(servletConfig.getServletContext());
+            }
+            else
+            {
+                // an entry was specified in web.xml,
+                configurationPath = p.trim();
+
+                // If the uri starts with "classpath:" we need to use a different resolver.
+                if(configurationPath.startsWith("classpath:")) {
+                    configurationResolver = new ClasspathResourceResolver();
+                } else {
+                    // on windows, all paths starting with '/' should be available via the servlet resource resolver
+                    // on other systems, you're not sure so try the servlet resource loader first it but don't throw an error,
+                    //   after that try using LocalFileResolver
+                    boolean isWindows = File.separator.equals("\\");
+                    boolean isServletResource = isWindows && configurationPath.startsWith("/");
+                    if (isServletResource || !isWindows) {
+                        ServletResourceResolver resolver = new ServletResourceResolver(servletConfig.getServletContext());
+                        boolean available = resolver.isAvailable(configurationPath, isServletResource);
+                        if (available) {
+                            // it's available via the servlet resource loader
+                            configurationResolver = resolver;
+                        } else {
+                            // it wasn't available via the servlet resource loader
+                            configurationResolver = new LocalFileResolver(LocalFileResolver.SERVER);
+                        }
+                    } else {
+                        // it's windows but seems to be specified as a file
+                        configurationResolver = new LocalFileResolver(LocalFileResolver.SERVER);
+                    }
+                }
+            }
+        }
+
+        // no entry specified in web.xml
+        else
+        {
+            ConfigurationException ce =  new ConfigurationException();
+            ce.setMessage("missing ServletConfig object");
+            throw ce;
+        }
+
+
+   }
+
+    protected void verifyMinimumJavaVersion() throws ConfigurationException
+    {
+        try
+        {
+            boolean minimum = false;
+            String version = System.getProperty("java.version");
+            String vendor = System.getProperty("java.vendor");
+
+            version = version.replace('.', ':');
+            version = version.replace('_', ':');
+            String[] split = version.split(":");
+
+            int first = Integer.parseInt(split[0]);
+            if (first > 1)
+            {
+                minimum = true;
+            }
+            else if (first == 1)
+            {
+                int second = Integer.parseInt(split[1]);
+                if (second > 4)
+                {
+                    minimum = true;
+                }
+                else  if (second == 4)
+                {
+                    int third = Integer.parseInt(split[2]);
+                    if (third > 2)
+                    {
+                        minimum = true;
+                    }
+                    else if (third == 2)
+                    {
+                        if ((vendor != null) && (vendor.indexOf("Sun") != -1))
+                        {
+                            // test at least 1.4.2_06 on Sun
+                            int fourth = Integer.parseInt(split[3]);
+                            if (fourth >= 6)
+                            {
+                                minimum = true;
+                            }
+                        }
+                        else
+                        {
+                            // test at least 1.4.2 on non-Sun
+                            minimum = true;
+                        }
+                    }
+                }
+            }
+
+            if (!minimum)
+            {
+                ConfigurationException cx = new ConfigurationException();
+
+                if ((vendor != null) && (vendor.indexOf("Sun") != -1))
+                {
+                    // The minimum required Java version was not found. Please install JDK 1.4.2_06 or above. Current version is XX.
+                    cx.setMessage(10139, new Object[] { System.getProperty("java.version")});
+                }
+                else
+                {
+                    // The minimum required Java version was not found. Please install JDK 1.4.2 or above. Current version is XX.
+                    cx.setMessage(10140, new Object[] { System.getProperty("java.version")});
+                }
+
+                throw cx;
+            }
+        }
+        catch (Throwable t)
+        {
+            if (t instanceof ConfigurationException)
+            {
+                throw ((ConfigurationException)t);
+            }
+            else
+            {
+                if (Trace.config)
+                {
+                    Trace.trace("Could not verified required java version. version=" + System.getProperty("java.version"));
+                }
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/config/MessageFilterSettings.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/config/MessageFilterSettings.java b/core/src/flex/messaging/config/MessageFilterSettings.java
new file mode 100644
index 0000000..34ed523
--- /dev/null
+++ b/core/src/flex/messaging/config/MessageFilterSettings.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+package flex.messaging.config;
+
+/**
+ * Settings class for message filters.
+ * 
+ *
+ */
+public class MessageFilterSettings extends PropertiesSettings
+{
+    /**
+     * Filters belong to one of two types; those that filter messages
+     * asynchronously and those that filter messages synchronously.
+     */
+    public enum FilterType { ASYNC, SYNC }
+
+    private String id;
+
+    /**
+     * Returns the id.
+     *
+     * @return The id.
+     */
+    public String getId()
+    {
+        return id;
+    }
+
+    /**
+     * Sets the id.
+     *
+     * @param value The id.
+     */
+    public void setId(String value)
+    {
+        id = value;
+    }    
+    
+    private String className;
+
+    /**
+     * Returns the class name.
+     *
+     * @return The class name.
+     */
+    public String getClassName()
+    {
+        return className;
+    }
+
+    /**
+     * Sets the class name.
+     *
+     * @param value The class name.
+     */
+    public void setClassName(String value)
+    {
+        className = value;
+    }
+    
+    private FilterType filterType;
+    
+    /**
+     * Returns the filter type.
+     * @see FilterType
+     * 
+     * @return The filter type.
+     */
+    public FilterType getFilterType()
+    {
+        return filterType;
+    }
+    
+    /**
+     * Sets the filter type.
+     * @see FilterType
+     * 
+     * @param value The filter type.
+     */
+    public void setFilterType(FilterType value)
+    {
+        filterType = value;
+    }
+}


Mime
View raw message