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 "services.configuration.manager" + * 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 "services.configuration.file" + * to the MessageBrokerServlet. + * </p> + * <p> + * The ConfigurationParser implementation can also be specified in + * a servlet init-param "services.configuration.parser" 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; + } +}
