http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ClientConfigurationParser.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ClientConfigurationParser.java b/common/src/main/java/flex/messaging/config/ClientConfigurationParser.java new file mode 100644 index 0000000..cff5d47 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ClientConfigurationParser.java @@ -0,0 +1,951 @@ +/* + * 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.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A special mxmlc compiler specific implentation of the configuration + * parser for JDK 1.4. Only a small subset of the configuration is + * processed to generate the information that the client needs at runtime, + * such as channel definitions and service destination properties. + * + * + */ +public abstract class ClientConfigurationParser extends AbstractConfigurationParser +{ + protected void parseTopLevelConfig(Document doc) + { + Node root = selectSingleNode(doc, "/" + SERVICES_CONFIG_ELEMENT); + + if (root != null) + { + // Validation + allowedChildElements(root, SERVICES_CONFIG_CHILDREN); + + // Channels (parse before services) + channelsSection(root); + + // Services + services(root); + + // Clustering + clusters(root); + + // FlexClient + flexClient(root); + } + } + + private void channelsSection(Node root) + { + Node channelsNode = selectSingleNode(root, CHANNELS_ELEMENT); + if (channelsNode != null) + { + // Validation + allowedAttributesOrElements(channelsNode, CHANNELS_CHILDREN); + + NodeList channels = selectNodeList(channelsNode, CHANNEL_DEFINITION_ELEMENT); + for (int i = 0; i < channels.getLength(); i++) + { + Node channel = channels.item(i); + channelDefinition(channel); + } + NodeList includes = selectNodeList(channelsNode, CHANNEL_INCLUDE_ELEMENT); + for (int i = 0; i < includes.getLength(); i++) + { + Node include = includes.item(i); + channelInclude(include); + } + } + } + + private void channelDefinition(Node channel) + { + // Validation + requiredAttributesOrElements(channel, CHANNEL_DEFINITION_REQ_CHILDREN); + allowedAttributesOrElements(channel, CHANNEL_DEFINITION_CHILDREN); + + String id = getAttributeOrChildElement(channel, ID_ATTR).trim(); + if (isValidID(id)) + { + // Don't allow multiple channels with the same id + if (config.getChannelSettings(id) != null) + { + // Cannot have multiple channels with the same id ''{0}''. + ConfigurationException e = new ConfigurationException(); + e.setMessage(DUPLICATE_CHANNEL_ERROR, new Object[]{id}); + throw e; + } + + ChannelSettings channelSettings = new ChannelSettings(id); + + // Endpoint + Node endpoint = selectSingleNode(channel, ENDPOINT_ELEMENT); + if (endpoint != null) + { + // Endpoint Validation + allowedAttributesOrElements(endpoint, ENDPOINT_CHILDREN); + + // The url attribute may also be specified by the deprecated uri attribute + String uri = getAttributeOrChildElement(endpoint, URL_ATTR); + if (uri == null || EMPTY_STRING.equals(uri)) + uri = getAttributeOrChildElement(endpoint, URI_ATTR); + channelSettings.setUri(uri); + + config.addChannelSettings(id, channelSettings); + } + + channelServerOnlyAttribute(channel, channelSettings); + + // Add the channel properties that the client needs namely polling-enabled, + // polling-interval-millis, piggybacking-enabled, login-after-disconnect, + // record-message-sizes, record-message-times, connect-timeout-seconds, + // polling-interval-seconds (deprecated), and client-load-balancing. + addProperty(channel, channelSettings, POLLING_ENABLED_ELEMENT); + addProperty(channel, channelSettings, POLLING_INTERVAL_MILLIS_ELEMENT); + addProperty(channel, channelSettings, PIGGYBACKING_ENABLED_ELEMENT); + addProperty(channel, channelSettings, LOGIN_AFTER_DISCONNECT_ELEMENT); + addProperty(channel, channelSettings, RECORD_MESSAGE_SIZES_ELEMENT); + addProperty(channel, channelSettings, RECORD_MESSAGE_TIMES_ELEMENT); + addProperty(channel, channelSettings, CONNECT_TIMEOUT_SECONDS_ELEMENT); + addProperty(channel, channelSettings, POLLING_INTERVAL_SECONDS_ELEMENT); // deprecated. + addProperty(channel, channelSettings, CLIENT_LOAD_BALANCING_ELEMENT); + addProperty(channel, channelSettings, REQUEST_TIMEOUT_SECONDS_ELEMENT); + + // enable-small-messages. + NodeList properties = selectNodeList(channel, PROPERTIES_ELEMENT + "/" + SERIALIZATION_ELEMENT); + if (properties.getLength() > 0) + { + ConfigMap map = properties(properties, getSourceFileOf(channel)); + ConfigMap serialization = map.getPropertyAsMap(SERIALIZATION_ELEMENT, null); + if (serialization != null) + { + // enable-small-messages. + String enableSmallMessages = serialization.getProperty(ENABLE_SMALL_MESSAGES_ELEMENT); + if (enableSmallMessages != null) + { + ConfigMap clientMap = new ConfigMap(); + clientMap.addProperty(ENABLE_SMALL_MESSAGES_ELEMENT, enableSmallMessages); + channelSettings.addProperty(SERIALIZATION_ELEMENT, clientMap); + } + } + } + } + else + { + // Invalid {CHANNEL_DEFINITION_ELEMENT} id '{id}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_ID, new Object[]{CHANNEL_DEFINITION_ELEMENT, id}); + String details = "An id must be non-empty and not contain any list delimiter characters, i.e. commas, semi-colons or colons."; + ex.setDetails(details); + throw ex; + } + } + + private void channelServerOnlyAttribute(Node channel, ChannelSettings channelSettings) + { + String clientType = getAttributeOrChildElement(channel, CLASS_ATTR); + clientType = clientType.length() > 0? clientType : null; + + String serverOnlyString = getAttributeOrChildElement(channel, SERVER_ONLY_ATTR); + boolean serverOnly = serverOnlyString.length() > 0 && Boolean.valueOf(serverOnlyString).booleanValue(); + + if (clientType == null && !serverOnly) // None set. + { + String url = channelSettings.getUri(); + boolean serverOnlyProtocol = (url.startsWith("samfsocket") || url.startsWith("amfsocket") || url.startsWith("ws")); + if (!serverOnlyProtocol) + { + // Endpoint ''{0}'' needs to have either class or server-only attribute defined. + ConfigurationException ce = new ConfigurationException(); + ce.setMessage(CLASS_OR_SERVER_ONLY_ERROR, new Object[]{channelSettings.getId()}); + throw ce; + } + channelSettings.setServerOnly(true); + } + else if (clientType != null && serverOnly) // Both set. + { + // Endpoint ''{0}'' cannot have both class and server-only attribute defined. + ConfigurationException ce = new ConfigurationException(); + ce.setMessage(CLASS_AND_SERVER_ONLY_ERROR, new Object[]{channelSettings.getId()}); + throw ce; + } + else // One of them set. + { + if (serverOnly) + channelSettings.setServerOnly(true); + else + channelSettings.setClientType(clientType); + } + } + + private void addProperty(Node channel, ChannelSettings channelSettings, String property) + { + NodeList properties = selectNodeList(channel, PROPERTIES_ELEMENT + "/" + property); + if (properties.getLength() > 0) + { + ConfigMap map = properties(properties, getSourceFileOf(channel)); + if (CLIENT_LOAD_BALANCING_ELEMENT.equals(property)) + { + ConfigMap clientLoadBalancingMap = map.getPropertyAsMap(CLIENT_LOAD_BALANCING_ELEMENT, null); + if (clientLoadBalancingMap == null) + { + // Invalid {0} configuration for endpoint ''{1}''; no urls defined. + ConfigurationException ce = new ConfigurationException(); + ce.setMessage(ERR_MSG_EMPTY_CLIENT_LOAD_BALANCING_ELEMENT, new Object[]{CLIENT_LOAD_BALANCING_ELEMENT, channelSettings.getId()}); + throw ce; + } + List urls = clientLoadBalancingMap.getPropertyAsList(URL_ATTR, null); + addClientLoadBalancingUrls(urls, channelSettings.getId()); + } + channelSettings.addProperties(map); + } + } + + // Add client load balancing urls after necessary validation checks. + private void addClientLoadBalancingUrls(List urls, String endpointId) + { + if (urls == null || urls.isEmpty()) + { + // Invalid {0} configuration for endpoint ''{1}''; no urls defined. + ConfigurationException ce = new ConfigurationException(); + ce.setMessage(ERR_MSG_EMPTY_CLIENT_LOAD_BALANCING_ELEMENT, new Object[]{CLIENT_LOAD_BALANCING_ELEMENT, endpointId}); + throw ce; + } + + Set clientLoadBalancingUrls = new HashSet(); + for (Iterator iterator = urls.iterator(); iterator.hasNext();) + { + String url = (String) iterator.next(); + if (url == null || url.length() == 0) + { + // Invalid {0} configuration for endpoint ''{1}''; cannot add empty url. + ConfigurationException ce = new ConfigurationException(); + ce.setMessage(ERR_MSG_EMTPY_CLIENT_LOAD_BALACNING_URL, new Object[]{CLIENT_LOAD_BALANCING_ELEMENT, endpointId}); + throw ce; + } + + if (TokenReplacer.containsTokens(url)) + { + // Invalid {0} configuration for endpoint ''{1}''; cannot add url with tokens. + ConfigurationException ce = new ConfigurationException(); + ce.setMessage(ERR_MSG_CLIENT_LOAD_BALANCING_URL_WITH_TOKEN, new Object[]{CLIENT_LOAD_BALANCING_ELEMENT, endpointId}); + throw ce; + } + + if (clientLoadBalancingUrls.contains(url)) + iterator.remove(); + else + clientLoadBalancingUrls.add(url); + } + + } + + private void channelInclude(Node channelInclude) + { + // Validation + allowedAttributesOrElements(channelInclude, CHANNEL_INCLUDE_CHILDREN); + + String src = getAttributeOrChildElement(channelInclude, SRC_ATTR); + String dir = getAttributeOrChildElement(channelInclude, DIRECTORY_ATTR); + if (src.length() > 0) + { + channelIncludeFile(src); + } + else if (dir.length() > 0) + { + channelIncludeDirectory(dir); + } + else + { + // The include element ''{0}'' must specify either the ''{1}'' or ''{2}'' attribute. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(MISSING_INCLUDE_ATTRIBUTES, new Object[]{channelInclude.getNodeName(), SRC_ATTR, DIRECTORY_ATTR}); + throw ex; + } + } + + private void channelIncludeFile(String src) + { + Document doc = loadDocument(src, fileResolver.getIncludedFile(src)); + if (fileResolver instanceof LocalFileResolver) + { + LocalFileResolver local = (LocalFileResolver)fileResolver; + ((ClientConfiguration)config).addConfigPath(local.getIncludedPath(src), local.getIncludedLastModified(src)); + } + + doc.getDocumentElement().normalize(); + + // Check for multiple channels in a single file. + Node channelsNode = selectSingleNode(doc, CHANNELS_ELEMENT); + if (channelsNode != null) + { + allowedChildElements(channelsNode, CHANNELS_CHILDREN); + NodeList channels = selectNodeList(channelsNode, CHANNEL_DEFINITION_ELEMENT); + for (int a = 0; a < channels.getLength(); a++) + { + Node service = channels.item(a); + channelDefinition(service); + } + fileResolver.popIncludedFile(); + } + else // Check for single channel in the file. + { + Node channel = selectSingleNode(doc, "/" + CHANNEL_DEFINITION_ELEMENT); + if (channel != null) + { + channelDefinition(channel); + fileResolver.popIncludedFile(); + } + else + { + // The {0} root element in file {1} must be '{CHANNELS_ELEMENT}' or '{CHANNEL_ELEMENT}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_INCLUDE_ROOT, new Object[]{CHANNEL_INCLUDE_ELEMENT, src, CHANNELS_ELEMENT, CHANNEL_DEFINITION_ELEMENT}); + throw ex; + } + } + } + + private void channelIncludeDirectory(String dir) + { + List files = fileResolver.getFiles(dir); + for (int i = 0; i < files.size(); i++) + { + String src = (String) files.get(i); + channelIncludeFile(src); + } + } + + private void services(Node root) + { + Node servicesNode = selectSingleNode(root, SERVICES_ELEMENT); + if (servicesNode != null) + { + // Validation + allowedChildElements(servicesNode, SERVICES_CHILDREN); + + // Default Channels for the application + Node defaultChannels = selectSingleNode(servicesNode, DEFAULT_CHANNELS_ELEMENT); + if (defaultChannels != null) + { + allowedChildElements(defaultChannels, DEFAULT_CHANNELS_CHILDREN); + NodeList channels = selectNodeList(defaultChannels, CHANNEL_ELEMENT); + for (int c = 0; c < channels.getLength(); c++) + { + Node chan = channels.item(c); + allowedAttributes(chan, new String[] {REF_ATTR}); + defaultChannel(chan); + } + } + + // Service Includes + NodeList services = selectNodeList(servicesNode, SERVICE_INCLUDE_ELEMENT); + for (int i = 0; i < services.getLength(); i++) + { + Node service = services.item(i); + serviceInclude(service); + } + + // Service + services = selectNodeList(servicesNode, SERVICE_ELEMENT); + for (int i = 0; i < services.getLength(); i++) + { + Node service = services.item(i); + service(service); + } + } + } + + private void clusters(Node root) + { + Node clusteringNode = selectSingleNode(root, CLUSTERS_ELEMENT); + if (clusteringNode != null) + { + allowedAttributesOrElements(clusteringNode, CLUSTERING_CHILDREN); + + NodeList clusters = selectNodeList(clusteringNode, CLUSTER_DEFINITION_ELEMENT); + for (int i = 0; i < clusters.getLength(); i++) + { + Node cluster = clusters.item(i); + requiredAttributesOrElements(cluster, CLUSTER_DEFINITION_CHILDREN); + String clusterName = getAttributeOrChildElement(cluster, ID_ATTR); + if (isValidID(clusterName)) + { + String propsFileName = getAttributeOrChildElement(cluster, CLUSTER_PROPERTIES_ATTR); + ClusterSettings clusterSettings = new ClusterSettings(); + clusterSettings.setClusterName(clusterName); + clusterSettings.setPropsFileName(propsFileName); + String defaultValue = getAttributeOrChildElement(cluster, ClusterSettings.DEFAULT_ELEMENT); + if (defaultValue != null && defaultValue.length() > 0) + { + if (defaultValue.equalsIgnoreCase("true")) + clusterSettings.setDefault(true); + else if (!defaultValue.equalsIgnoreCase("false")) + { + ConfigurationException e = new ConfigurationException(); + e.setMessage(10215, new Object[] {clusterName, defaultValue}); + throw e; + } + } + String ulb = getAttributeOrChildElement(cluster, ClusterSettings.URL_LOAD_BALANCING); + if (ulb != null && ulb.length() > 0) + { + if (ulb.equalsIgnoreCase("false")) + clusterSettings.setURLLoadBalancing(false); + else if (!ulb.equalsIgnoreCase("true")) + { + ConfigurationException e = new ConfigurationException(); + e.setMessage(10216, new Object[] {clusterName, ulb}); + throw e; + } + } + ((ClientConfiguration)config).addClusterSettings(clusterSettings); + } + } + } + } + + private void serviceInclude(Node serviceInclude) + { + // Validation + allowedAttributesOrElements(serviceInclude, SERVICE_INCLUDE_CHILDREN); + + String src = getAttributeOrChildElement(serviceInclude, SRC_ATTR); + String dir = getAttributeOrChildElement(serviceInclude, DIRECTORY_ATTR); + if (src.length() > 0) + { + serviceIncludeFile(src); + } + else if (dir.length() > 0) + { + serviceIncludeDirectory(dir); + } + else + { + // The include element ''{0}'' must specify either the ''{1}'' or ''{2}'' attribute. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(MISSING_INCLUDE_ATTRIBUTES, new Object[]{serviceInclude.getNodeName(), SRC_ATTR, DIRECTORY_ATTR}); + throw ex; + } + } + + private void serviceIncludeFile(String src) + { + Document doc = loadDocument(src, fileResolver.getIncludedFile(src)); + if (fileResolver instanceof LocalFileResolver) + { + LocalFileResolver local = (LocalFileResolver)fileResolver; + ((ClientConfiguration)config).addConfigPath(local.getIncludedPath(src), local.getIncludedLastModified(src)); + } + + doc.getDocumentElement().normalize(); + + // Check for multiple services defined in file. + Node servicesNode = selectSingleNode(doc, SERVICES_ELEMENT); + if (servicesNode != null) + { + allowedChildElements(servicesNode, SERVICES_CHILDREN); + NodeList services = selectNodeList(servicesNode, SERVICES_ELEMENT); + for (int a = 0; a < services.getLength(); a++) + { + Node service = services.item(a); + service(service); + } + fileResolver.popIncludedFile(); + } + else // Check for single service in file. + { + Node service = selectSingleNode(doc, "/" + SERVICE_ELEMENT); + if (service != null) + { + service(service); + fileResolver.popIncludedFile(); + } + else + { + // The {0} root element in file {1} must be ''{2}'' or ''{3}''. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_INCLUDE_ROOT, new Object[]{SERVICE_INCLUDE_ELEMENT, src, SERVICES_ELEMENT, SERVICE_ELEMENT}); + throw ex; + } + } + } + + private void serviceIncludeDirectory(String dir) + { + List files = fileResolver.getFiles(dir); + for (int i = 0; i < files.size(); i++) + { + String src = (String) files.get(i); + serviceIncludeFile(src); + } + } + + private void service(Node service) + { + // Validation + requiredAttributesOrElements(service, SERVICE_REQ_CHILDREN); + allowedAttributesOrElements(service, SERVICE_CHILDREN); + + String id = getAttributeOrChildElement(service, ID_ATTR); + if (isValidID(id)) + { + ServiceSettings serviceSettings = config.getServiceSettings(id); + if (serviceSettings == null) + { + serviceSettings = new ServiceSettings(id); + // Service Properties + NodeList properties = selectNodeList(service, PROPERTIES_ELEMENT + "/*"); + if (properties.getLength() > 0) + { + ConfigMap map = properties(properties, getSourceFileOf(service)); + serviceSettings.addProperties(map); + } + config.addServiceSettings(serviceSettings); + } + else + { + // Duplicate service definition '{0}'. + ConfigurationException e = new ConfigurationException(); + e.setMessage(DUPLICATE_SERVICE_ERROR, new Object[]{id}); + throw e; + } + + // Service Class Name + String className = getAttributeOrChildElement(service, CLASS_ATTR); + if (className.length() > 0) + { + serviceSettings.setClassName(className); + } + else + { + // Class not specified for {SERVICE_ELEMENT} '{id}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(CLASS_NOT_SPECIFIED, new Object[]{SERVICE_ELEMENT, id}); + throw ex; + } + + //Service Message Types - deprecated + + // Default Channels + Node defaultChannels = selectSingleNode(service, DEFAULT_CHANNELS_ELEMENT); + if (defaultChannels != null) + { + allowedChildElements(defaultChannels, DEFAULT_CHANNELS_CHILDREN); + NodeList channels = selectNodeList(defaultChannels, CHANNEL_ELEMENT); + for (int c = 0; c < channels.getLength(); c++) + { + Node chan = channels.item(c); + allowedAttributes(chan, new String[] {REF_ATTR}); + defaultChannel(chan, serviceSettings); + } + } + // Fall back on application's default channels + else if (config.getDefaultChannels().size() > 0) + { + for (Iterator iter = config.getDefaultChannels().iterator(); iter.hasNext();) + { + String channelId = (String)iter.next(); + ChannelSettings channel = config.getChannelSettings(channelId); + serviceSettings.addDefaultChannel(channel); + } + } + + // Destinations + NodeList list = selectNodeList(service, DESTINATION_ELEMENT); + for (int i = 0; i < list.getLength(); i++) + { + Node dest = list.item(i); + destination(dest, serviceSettings); + } + + // Destination Includes + list = selectNodeList(service, DESTINATION_INCLUDE_ELEMENT); + for (int i = 0; i < list.getLength(); i++) + { + Node dest = list.item(i); + destinationInclude(dest, serviceSettings); + } + } + else + { + //Invalid {SERVICE_ELEMENT} id '{id}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_ID, new Object[]{SERVICE_ELEMENT, id}); + throw ex; + } + } + + /** + * Flex application can declare default channels for its services. If a + * service specifies its own list of channels it overrides these defaults. + * <p> + * <default-channels><br /> + * ;<channel ref="channel-id" /><br /> + * <default-channels> + * </p> + * @param chan the channel node + */ + private void defaultChannel(Node chan) + { + String ref = getAttributeOrChildElement(chan, REF_ATTR); + + if (ref.length() > 0) + { + ChannelSettings channel = config.getChannelSettings(ref); + if (channel != null) + { + config.addDefaultChannel(channel.getId()); + } + else + { + // {0} not found for reference '{1}' + ConfigurationException e = new ConfigurationException(); + e.setMessage(REF_NOT_FOUND, new Object[]{CHANNEL_ELEMENT, ref}); + throw e; + } + } + else + { + //A default channel was specified without a reference for service '{0}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_DEFAULT_CHANNEL, new Object[]{"MessageBroker"}); + throw ex; + } + } + + /** + * A service can declare default channels for its destinations. If a destination + * specifies its own list of channels it overrides these defaults. + * <p> + * <default-channels><br /> + * <channel ref="channel-id" /><br /> + * <default-channels> + * </p> + * @param chan the channel node + * @param serviceSettings service settings + */ + private void defaultChannel(Node chan, ServiceSettings serviceSettings) + { + String ref = getAttributeOrChildElement(chan, REF_ATTR).trim(); + + if (ref.length() > 0) + { + ChannelSettings channel = config.getChannelSettings(ref); + if (channel != null) + { + serviceSettings.addDefaultChannel(channel); + } + else + { + // {0} not found for reference '{1}' + ConfigurationException e = new ConfigurationException(); + e.setMessage(REF_NOT_FOUND, new Object[]{CHANNEL_ELEMENT, ref}); + throw e; + } + } + else + { + //A default channel was specified without a reference for service '{0}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_DEFAULT_CHANNEL, new Object[]{serviceSettings.getId()}); + throw ex; + } + } + + private void destinationInclude(Node destInclude, ServiceSettings serviceSettings) + { + // Validation + allowedAttributesOrElements(destInclude, DESTINATION_INCLUDE_CHILDREN); + + String src = getAttributeOrChildElement(destInclude, SRC_ATTR); + String dir = getAttributeOrChildElement(destInclude, DIRECTORY_ATTR); + if (src.length() > 0) + { + destinationIncludeFile(serviceSettings, src); + } + else if (dir.length() > 0) + { + destinationIncludeDirectory(serviceSettings, dir); + } + else + { + // The include element ''{0}'' must specify either the ''{1}'' or ''{2}'' attribute. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(MISSING_INCLUDE_ATTRIBUTES, new Object[]{destInclude.getNodeName(), SRC_ATTR, DIRECTORY_ATTR}); + throw ex; + } + } + + private void destinationIncludeDirectory(ServiceSettings serviceSettings, String dir) + { + List files = fileResolver.getFiles(dir); + for (int i = 0; i < files.size(); i++) + { + String src = (String) files.get(i); + destinationIncludeFile(serviceSettings, src); + } + } + + private void destinationIncludeFile(ServiceSettings serviceSettings, String src) + { + Document doc = loadDocument(src, fileResolver.getIncludedFile(src)); + if (fileResolver instanceof LocalFileResolver) + { + LocalFileResolver local = (LocalFileResolver)fileResolver; + ((ClientConfiguration)config).addConfigPath(local.getIncludedPath(src), local.getIncludedLastModified(src)); + } + + doc.getDocumentElement().normalize(); + + // Check for multiple destination defined in file. + Node destinationsNode = selectSingleNode(doc, DESTINATIONS_ELEMENT); + if (destinationsNode != null) + { + allowedChildElements(destinationsNode, DESTINATIONS_CHILDREN); + NodeList destinations = selectNodeList(destinationsNode, DESTINATION_ELEMENT); + for (int a = 0; a < destinations.getLength(); a++) + { + Node dest = destinations.item(a); + destination(dest, serviceSettings); + } + fileResolver.popIncludedFile(); + } + else // Check for single destination definition. + { + Node dest = selectSingleNode(doc, "/" + DESTINATION_ELEMENT); + if (dest != null) + { + destination(dest, serviceSettings); + fileResolver.popIncludedFile(); + } + else + { + // The {0} root element in file {1} must be ''{2}'' or ''{3}''. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_INCLUDE_ROOT, new Object[]{DESTINATION_INCLUDE_ELEMENT, src, DESTINATIONS_ELEMENT, DESTINATION_ELEMENT}); + throw ex; + } + } + } + + private void destination(Node dest, ServiceSettings serviceSettings) + { + // Validation + requiredAttributesOrElements(dest, DESTINATION_REQ_CHILDREN); + allowedAttributes(dest, DESTINATION_ATTR); + allowedChildElements(dest, DESTINATION_CHILDREN); + + String serviceId = serviceSettings.getId(); + + DestinationSettings destinationSettings; + String id = getAttributeOrChildElement(dest, ID_ATTR); + if (isValidID(id)) + { + destinationSettings = (DestinationSettings)serviceSettings.getDestinationSettings().get(id); + if (destinationSettings != null) + { + // Duplicate destination definition '{id}' in service '{serviceId}'. + ConfigurationException e = new ConfigurationException(); + e.setMessage(DUPLICATE_DESTINATION_ERROR, new Object[]{id, serviceId}); + throw e; + } + + destinationSettings = new DestinationSettings(id); + serviceSettings.addDestinationSettings(destinationSettings); + } + else + { + //Invalid {DESTINATION_ELEMENT} id '{id}' for service '{serviceId}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_ID_IN_SERVICE, new Object[]{DESTINATION_ELEMENT, id, serviceId}); + throw ex; + } + + // Destination Properties + NodeList properties = selectNodeList(dest, PROPERTIES_ELEMENT + "/*"); + if (properties.getLength() > 0) + { + ConfigMap map = properties(properties, getSourceFileOf(dest)); + destinationSettings.addProperties(map); + } + + // Channels + destinationChannels(dest, destinationSettings, serviceSettings); + + } + + private void destinationChannels(Node dest, DestinationSettings destinationSettings, ServiceSettings serviceSettings) + { + String destId = destinationSettings.getId(); + + // Channels attribute + String channelsList = evaluateExpression(dest, "@" + CHANNELS_ATTR).toString().trim(); + if (channelsList.length() > 0) + { + StringTokenizer st = new StringTokenizer(channelsList, LIST_DELIMITERS); + while (st.hasMoreTokens()) + { + String ref = st.nextToken().trim(); + ChannelSettings channel = config.getChannelSettings(ref); + if (channel != null) + { + destinationSettings.addChannelSettings(channel); + } + else + { + // {CHANNEL_ELEMENT} not found for reference '{ref}' in destination '{destId}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(REF_NOT_FOUND_IN_DEST, new Object[]{CHANNEL_ELEMENT, ref, destId}); + throw ex; + } + } + } + else + { + // Channels element + Node channelsNode = selectSingleNode(dest, CHANNELS_ELEMENT); + if (channelsNode != null) + { + allowedChildElements + (channelsNode, DESTINATION_CHANNELS_CHILDREN); + NodeList channels = selectNodeList(channelsNode, CHANNEL_ELEMENT); + if (channels.getLength() > 0) + { + for (int c = 0; c < channels.getLength(); c++) + { + Node chan = channels.item(c); + + // Validation + requiredAttributesOrElements(chan, DESTINATION_CHANNEL_REQ_CHILDREN); + + String ref = getAttributeOrChildElement(chan, REF_ATTR).trim(); + if (ref.length() > 0) + { + ChannelSettings channel = config.getChannelSettings(ref); + if (channel != null) + { + destinationSettings.addChannelSettings(channel); + } + else + { + // {CHANNEL_ELEMENT} not found for reference '{ref}' in destination '{destId}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(REF_NOT_FOUND_IN_DEST, new Object[]{CHANNEL_ELEMENT, ref, destId}); + throw ex; + } + } + else + { + //Invalid {0} ref '{1}' in destination '{2}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_REF_IN_DEST, new Object[]{CHANNEL_ELEMENT, ref, destId}); + throw ex; + } + } + } + } + else + { + // Finally, we fall back to the service's default channels + List defaultChannels = serviceSettings.getDefaultChannels(); + Iterator it = defaultChannels.iterator(); + while (it.hasNext()) + { + ChannelSettings channel = (ChannelSettings)it.next(); + destinationSettings.addChannelSettings(channel); + } + } + } + + if (destinationSettings.getChannelSettings().size() <= 0) + { + // Destination '{id}' must specify at least one channel. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(DEST_NEEDS_CHANNEL, new Object[]{destId}); + throw ex; + } + } + + private void flexClient(Node root) + { + Node flexClient = selectSingleNode(root, FLEX_CLIENT_ELEMENT); + if (flexClient != null) + { + FlexClientSettings flexClientSettings = new FlexClientSettings(); + // Reliable reconnect duration millis + String reliableReconnectDurationMillis = getAttributeOrChildElement(flexClient, FLEX_CLIENT_RELIABLE_RECONNECT_DURATION_MILLIS); + if (reliableReconnectDurationMillis.length() > 0) + { + try + { + int millis = Integer.parseInt(reliableReconnectDurationMillis); + if (millis < 0) + { + ConfigurationException e = new ConfigurationException(); + e.setMessage(INVALID_FLEX_CLIENT_RELIABLE_RECONNECT_DURATION_MILLIS, new Object[]{reliableReconnectDurationMillis}); + throw e; + } + flexClientSettings.setReliableReconnectDurationMillis(millis); + } + catch (NumberFormatException nfe) + { + ConfigurationException e = new ConfigurationException(); + e.setMessage(INVALID_FLEX_CLIENT_RELIABLE_RECONNECT_DURATION_MILLIS, new Object[]{reliableReconnectDurationMillis}); + throw e; + } + } + else + { + flexClientSettings.setReliableReconnectDurationMillis(0); // Default is 0. + } + // heartbeat interval millis + String heartbeatIntervalMillis = getAttributeOrChildElement(flexClient, FLEX_CLIENT_HEARTBEAT_INTERVAL_MILLIS); + if (heartbeatIntervalMillis.length() > 0) + { + try + { + int millis = Integer.parseInt(heartbeatIntervalMillis); + if (millis < 0) + { + ConfigurationException e = new ConfigurationException(); + e.setMessage(INVALID_FLEX_CLIENT_HEARTBEAT_INTERVAL_MILLIS, new Object[] {heartbeatIntervalMillis}); + throw e; + } + flexClientSettings.setHeartbeatIntervalMillis(millis); + } + catch (NumberFormatException nfe) + { + ConfigurationException e = new ConfigurationException(); + e.setMessage(INVALID_FLEX_CLIENT_HEARTBEAT_INTERVAL_MILLIS, new Object[] {heartbeatIntervalMillis}); + throw e; + } + } + ((ClientConfiguration)config).setFlexClientSettings(flexClientSettings); + } + } +}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ClusterSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ClusterSettings.java b/common/src/main/java/flex/messaging/config/ClusterSettings.java new file mode 100644 index 0000000..beb64fd --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ClusterSettings.java @@ -0,0 +1,152 @@ +/* + * 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; + +/** + * + */ +public class ClusterSettings extends PropertiesSettings +{ + public static final String CLUSTER_ELEMENT = "cluster"; + public static final String REF_ATTR = "ref"; + public static final String SHARED_BACKEND_ATTR = "shared-backend"; + public static final String DEFAULT_ELEMENT = "default"; + public static final String URL_LOAD_BALANCING = "url-load-balancing"; + public static final String IMPLEMENTATION_CLASS = "class"; + + public static final String JGROUPS_CLUSTER = "flex.messaging.cluster.JGroupsCluster"; + + private String clusterName; + private String propsFileName; + private String implementationClass; + private boolean def; + private boolean urlLoadBalancing; + + /** + * Creates a new <code>ClusterSettings</code> with default settings. + */ + public ClusterSettings() + { + def = false; + urlLoadBalancing = true; + implementationClass = JGROUPS_CLUSTER; + } + + /** + * Returns the name of the cluster. + * + * @return The name of the cluster. + */ + public String getClusterName() + { + return clusterName; + } + + /** + * Sets the name of the cluster. + * + * @param clusterName The name of the cluster. + */ + public void setClusterName(String clusterName) + { + this.clusterName = clusterName; + } + + /** + * Returns whether the cluster is default or not. + * + * @return <code>true</code> is the cluster is default; otherwise <code>false</code>. + */ + public boolean isDefault() + { + return def; + } + + /** + * Sets whether the cluster is default or not. + * + * @param def <code>true</code> is the cluster is default; otherwise <code>false</code>. + */ + public void setDefault(boolean def) + { + this.def = def; + } + + /** + * Returns the properties file of the cluster. + * + * @return The properties file of the cluster. + */ + public String getPropsFileName() + { + return propsFileName; + } + + /** + * Sets the properties file of the cluster. + * + * @param propsFileName The properties file of the cluster. + */ + public void setPropsFileName(String propsFileName) + { + this.propsFileName = propsFileName; + } + + /** + * Returns whether url load balancing is enabled or not. + * + * @return <code>true</code> if the url load balancing is enabled; otherwise <code>false</code>. + */ + public boolean getURLLoadBalancing() + { + return urlLoadBalancing; + } + + /** + * Sets whether url load balancing is enabled or not. + * + * @param ulb <code>true</code> if the url load balancing is enabled; otherwise <code>false</code>. + */ + public void setURLLoadBalancing(boolean ulb) + { + urlLoadBalancing = ulb; + } + + /** + * Sets the name of the cluster implementation class. + * The default is 'flex.messaging.cluster.JGroupsCluster'. + * + * @param className name of the cluster implementation class + * + */ + public void setImplementationClass(String className) + { + this.implementationClass = className; + } + + /** + * Get the name of the cluster implementation class. + * The class must support the flex.messaging.cluster.Cluster interface. + * + * @return The implementation class name. + * + */ + public String getImplementationClass() + { + return implementationClass; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ConfigMap.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ConfigMap.java b/common/src/main/java/flex/messaging/config/ConfigMap.java new file mode 100644 index 0000000..c2bd780 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ConfigMap.java @@ -0,0 +1,469 @@ +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The ConfigMap class is a helper implementation of Map that makes it easier + * to handle properties that can appear one or more times. If a property is set + * more than once, it is converted to a List and added as another property + * rather than replacing the existing property. It also provides utility APIs + * for getting properties from the Map, cast to a certain type and allows a + * default to be specified in the event that the property is missing. + */ +public class ConfigMap extends LinkedHashMap +{ + /** + * This number was generated using the 'serialver' command line tool. + * This number should remain consistent with the version used by + * ColdFusion to communicate with the message broker over RMI. + */ + private static final long serialVersionUID = 8913604659150919550L; + + /** + * This error is thrown when a property unexpectedly contains multiple values. + */ + private static final int UNEXPECTED_MULTIPLE_VALUES = 10169; + + /** + * An *undocumented* system property can be used to revert to legacy config property handling: + * Legacy behavior - config property values were not trimmed, retaining leading/trailing whitespace which + * proved problematic for customers. + * New default behavior - config property values are trimmed. + */ + private static final String SYSPROPNAME_TRIM_CONFIG_PROPERTY_VALUES = "flex.trim-config-property-values"; + private static final boolean TRIM_CONFIG_PROPERTY_VALUES = Boolean.valueOf(System.getProperty(SYSPROPNAME_TRIM_CONFIG_PROPERTY_VALUES, "true")).booleanValue(); + + /** + * Map to keep track of accessed properties. + */ + private HashSet accessedKeys = new HashSet(); + + /** + * Constructs an empty <code>ConfigMap</code> with the default initial + * capacity of 10. + */ + public ConfigMap() + { + super(); + } + + /** + * Constructs a new <code>ConfigMap</code> with the initial + * capacity specified. + * + * @param initialCapacity the initial capacity. + */ + public ConfigMap(int initialCapacity) + { + super(initialCapacity); + } + + /** + * Constructs a new <code>ConfigMap</code> and copies the values + * from the supplied map to this map. + * + * @param m a <code>ConfigMap</code> whose properties are to be added to + * this <code>ConfigMap</code>. + */ + public ConfigMap(ConfigMap m) + { + this(); + addProperties(m); + } + + /** + * Adds all properties from a map to this map. + * + * @param p a <code>ConfigMap</code> whose properties are to be added to + * this <code>ConfigMap</code>. + */ + public void addProperties(ConfigMap p) + { + Iterator it = p.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + Object key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof ValueList) + { + addProperties(key, (ValueList) value); + } + else + { + addPropertyLogic(key, value); + } + } + } + + /** + * Helper method to add a list of values under a key. + * + * @param key The key to add the values under. + * @param values The list of values to add. + */ + private void addProperties(Object key, ValueList values) + { + ValueList list = getValueList(key); + if (list == null) + { + put(key, values.clone()); + } + else + { + list.addAll(values); + } + } + + /** + * Helper method to add a value under a key. + * + * @param key The key to add the value under. + * @param value The value to add. + */ + private void addPropertyLogic(Object key, Object value) + { + ValueList list = getValueList(key); + if (list == null) + { + put(key, value); + } + else + { + list.add(value); + } + } + + private static class ValueList extends ArrayList + { + /** + * Serial version id. + */ + static final long serialVersionUID = -5637755312744414675L; + } + + /** + * Given a key, returns a list of values associated with that key. + * + * @param key The key. + * @return A list of values associated with the key. + */ + private ValueList getValueList(Object key) + { + ValueList list; + Object old = super.get(key); + if (old instanceof ValueList) + { + list = (ValueList) old; + } + else if (old != null) + { + list = new ValueList(); + list.add(old); + put(key, list); + } + else + { + list = null; + } + return list; + } + + /** + * Adds a <code>String</code> value to this map for the given property + * name. + * + * @param name the property name + * @param value the property value + */ + public void addProperty(String name, String value) + { + addPropertyLogic(name, TRIM_CONFIG_PROPERTY_VALUES && value != null ? value.trim() : value); + } + + /** + * Adds a <code>ConfigMap</code> value to this map for the given property + * name. + * + * @param name the property name + * @param value the property value + */ + public void addProperty(String name, ConfigMap value) + { + addPropertyLogic(name, value); + } + + /** + * Gets the set of property names contained in this map. + * + * @return a <code>Set</code> of property name <code>String</code>s. + */ + public Set propertyNames() + { + return keySet(); + } + + /** + * Sets a property name as allowed without needing to access the property + * value. This marks a property as allowed for validation purposes. + * + * @param name the property name to allow + */ + public void allowProperty(String name) + { + accessedKeys.add(name); + } + + /** + * Gets the value for the given property name. Also records that this + * property was accessed. + * + * @param name the property name + * @return the value for the property, or null if property does not exist + * in this map. + */ + public Object get(Object name) + { + accessedKeys.add(name); + return super.get(name); + } + + /** + * Helper method to get the property with the specified name as a string if possible. + * + * @param name The property name. + * @return The property object. + */ + private Object getSinglePropertyOrFail(Object name) + { + Object result = get(name); + if (result instanceof ValueList) + { + ConfigurationException exception = new ConfigurationException(); + exception.setMessage + (UNEXPECTED_MULTIPLE_VALUES, new Object[] {name}); + throw exception; + } + return result; + } + + /** + * Gets the property with the specified name as a string if possible. + * + * @param name The property name. + * @return The property name. + */ + public String getProperty(String name) + { + return getPropertyAsString(name, null); + } + + /** + * Gets the property with the specified name as a ConfigMap if possible, + * or returns the default value if the property is undefined. + * + * @param name the property name + * @param defaultValue the default value + * @return ConfigMap the ConfigMap object of the property + */ + public ConfigMap getPropertyAsMap(String name, ConfigMap defaultValue) + { + Object prop = getSinglePropertyOrFail(name); + if (prop instanceof ConfigMap) + { + return (ConfigMap)prop; + } + return defaultValue; + } + + /** + * Gets the property with the specified name as a String if possible, + * or returns the default value if the property is undefined. + * + * @param name the property name + * @param defaultValue the default value + * @return String the String value of the property + */ + public String getPropertyAsString(String name, String defaultValue) + { + Object prop = getSinglePropertyOrFail(name); + if (prop instanceof String) + { + return (String)prop; + } + return defaultValue; + } + + /** + * Gets a property (or set of properties) as a List. If only one + * property exists it is added as the only entry to a new List. + * + * @param name the property name + * @param defaultValue the value to return if the property is not found + * @return the value for the property as a List if it exists in this map, + * otherwise the defaultValue is returned. + */ + public List getPropertyAsList(String name, List defaultValue) + { + Object prop = get(name); + if (prop != null) + { + if (prop instanceof List) + { + return (List) prop; + } + else + { + List list = new ArrayList(); + list.add(prop); + return list; + } + } + return defaultValue; + } + + /** + * Gets the property with the specified name as a boolean if possible, + * or returns the default value if the property is undefined. + * + * @param name the property name + * @param defaultValue the default value + * @return boolean the boolean value of the property + */ + public boolean getPropertyAsBoolean(String name, boolean defaultValue) + { + Object prop = getSinglePropertyOrFail(name); + if (prop instanceof String) + { + return Boolean.valueOf((String)prop).booleanValue(); + } + return defaultValue; + } + + /** + * Gets the property with the specified name as an int if possible, + * or returns the default value if the property is undefined. + * + * @param name the property name + * @param defaultValue the default value + * @return int the int value of the property + */ + public int getPropertyAsInt(String name, int defaultValue) + { + Object prop = getSinglePropertyOrFail(name); + if (prop instanceof String) + { + try + { + return Integer.parseInt((String)prop); + } + catch (NumberFormatException ex) + { + } + } + return defaultValue; + } + + /** + * Gets the property with the specified name as a long if possible, + * or returns the default value if the property is undefined. + * + * @param name the property name + * @param defaultValue the default value + * @return long the long value of the property + */ + public long getPropertyAsLong(String name, long defaultValue) + { + Object prop = getSinglePropertyOrFail(name); + if (prop instanceof String) + { + try + { + return Long.parseLong((String)prop); + } + catch (NumberFormatException ex) + { + } + } + return defaultValue; + } + + /** + * Returns a list of qualified property names that have not been accessed + * by one of the get*() methods. + * + * @return List a list of unused properties + */ + public List findAllUnusedProperties() + { + List result = new ArrayList(); + findUnusedProperties("", true, result); + return result; + } + + /** + * Gathers a collection of properties that exist in the map but have not + * been explicitly accessed nor marked as allowed. This list is helpful + * in validating a set of properties as one can detect those that are + * unknown or unexpected. + * + * @param parentPath Used to track the depth of property in a potential + * hierarchy of <code>ConfigMap</code>s. + * @param recurse Whether sub maps should be recursively searched. + * @param result the collection of unused properties in this map. + */ + public void findUnusedProperties + (String parentPath, boolean recurse, Collection result) + { + Iterator itr = entrySet().iterator(); + while (itr.hasNext()) + { + Map.Entry entry = (Map.Entry) itr.next(); + Object key = entry.getKey(); + String currentPath = parentPath + '/' + String.valueOf(key); + if (!accessedKeys.contains(key)) + { + result.add(currentPath); + } + else if (recurse) + { + Object value = entry.getValue(); + List values = value instanceof List ? + (List) value : Collections.singletonList(value); + for (int i = 0; i < values.size(); i++) + { + Object child = values.get(i); + if (child instanceof ConfigMap) + { + ((ConfigMap) child).findUnusedProperties + (currentPath, recurse, result); + } + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ConfigurationConstants.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ConfigurationConstants.java b/common/src/main/java/flex/messaging/config/ConfigurationConstants.java new file mode 100644 index 0000000..35fcf34 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ConfigurationConstants.java @@ -0,0 +1,467 @@ +/* + * 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; + +/** + * + */ +public interface ConfigurationConstants +{ + String CONTEXT_PATH_TOKEN = "{context.root}"; + String CONTEXT_PATH_ALT_TOKEN = "{context-root}"; + String SLASH_CONTEXT_PATH_TOKEN = "/{context.root}"; + String EMPTY_STRING = ""; + String TRUE_STRING = "true"; + String FALSE_STRING = "false"; + String SERVER_NAME_TOKEN = "{server.name}"; + String SERVER_PORT_TOKEN = "{server.port}"; + + // ELEMENTS + + // Top Level + String SERVICES_CONFIG_ELEMENT = "services-config"; + + // Services + String SERVICES_ELEMENT = "services"; + String SERVICE_ELEMENT = "service"; + String SERVICE_INCLUDE_ELEMENT = "service-include"; + + String SRC_ATTR = "file-path"; + String DIRECTORY_ATTR = "directory-path"; + String ID_ATTR = "id"; + String CLASS_ATTR = "class"; + String PER_CLIENT_AUTH="per-client-authentication"; + String MESSAGE_TYPES_ATTR = "messageTypes"; + + String PROPERTIES_ELEMENT = "properties"; + + String METADATA_ELEMENT = "metadata"; + + String ADAPTERS_ELEMENT = "adapters"; + String ADAPTER_DEFINITION_ELEMENT = "adapter-definition"; + String ADAPTER_INCLUDE_ELEMENT = "adapter-include"; + String DEFAULT_ATTR = "default"; + + String DEFAULT_CHANNELS_ELEMENT = "default-channels"; + String CHANNEL_ELEMENT = "channel"; + String REF_ATTR = "ref"; + + String DEFAULT_SECURITY_CONSTRAINT_ELEMENT = "default-security-constraint"; + + String DESTINATION_ELEMENT = "destination"; + String DESTINATIONS_ELEMENT = "destinations"; + String DESTINATION_INCLUDE_ELEMENT = "destination-include"; + String ADAPTER_ELEMENT = "adapter"; + String ADAPTER_ATTR = "adapter"; + String CHANNELS_ATTR = "channels"; + String SECURITY_CONSTRAINT_ELEMENT = "security-constraint"; + String SECURITY_CONSTRAINT_ATTR = "security-constraint"; + String SECURITY_CONSTRAINTS_ELEMENT = "security-constraints"; // for includes only + + // Security + String SECURITY_ELEMENT = "security"; + String SECURITY_CONSTRAINT_DEFINITION_ELEMENT = "security-constraint"; + String CONSTRAINT_INCLUDE_ELEMENT = "constraint-include"; + String AUTH_METHOD_ELEMENT = "auth-method"; + String ROLES_ELEMENT = "roles"; + String ROLE_ELEMENT = "role"; + String LOGIN_COMMAND_ELEMENT = "login-command"; + String SERVER_ATTR = "server"; + String RECREATE_HTTPSESSION_AFTER_LOGIN_ELEMENT = "recreate-httpsession-after-login"; + + // SocketServers + String SERVERS_ELEMENT = "servers"; + String SERVER_ELEMENT = "server"; + String IP_ADDRESS_PATTERN = "ip-address-pattern"; + + // Channels + String CHANNELS_ELEMENT = "channels"; + String CHANNEL_DEFINITION_ELEMENT = "channel-definition"; + String CHANNEL_INCLUDE_ELEMENT = "channel-include"; + String REMOTE_ATTR = "remote"; + String SERVER_ONLY_ATTR = "server-only"; + String ENDPOINT_ELEMENT = "endpoint"; + // Deprecated, use URL_ATTR instead. + String URI_ATTR = "uri"; + String URL_ATTR = "url"; + String POLLING_ENABLED_ELEMENT = "polling-enabled"; + String POLLING_INTERVAL_MILLIS_ELEMENT = "polling-interval-millis"; + String PIGGYBACKING_ENABLED_ELEMENT = "piggybacking-enabled"; + String LOGIN_AFTER_DISCONNECT_ELEMENT = "login-after-disconnect"; + String RECORD_MESSAGE_SIZES_ELEMENT = "record-message-sizes"; + String RECORD_MESSAGE_TIMES_ELEMENT = "record-message-times"; + String SERIALIZATION_ELEMENT = "serialization"; + String ENABLE_SMALL_MESSAGES_ELEMENT = "enable-small-messages"; + // Deprecated, use POLLING_INTERVAL_MILLIS_ELEMENT instead. + String POLLING_INTERVAL_SECONDS_ELEMENT = "polling-interval-seconds"; + String CONNECT_TIMEOUT_SECONDS_ELEMENT = "connect-timeout-seconds"; + String CLIENT_LOAD_BALANCING_ELEMENT = "client-load-balancing"; + String REQUEST_TIMEOUT_SECONDS_ELEMENT = "request-timeout-seconds"; + + // Clusters + String CLUSTERS_ELEMENT = "clusters"; + String CLUSTER_DEFINITION_ELEMENT = "cluster"; + String CLUSTER_PROPERTIES_ATTR = "properties"; + + // Logging + String LOGGING_ELEMENT = "logging"; + String TARGET_ELEMENT = "target"; + String FILTERS_ELEMENT = "filters"; + String PATTERN_ELEMENT = "pattern"; + String LEVEL_ATTR = "level"; + + // System + String SYSTEM_ELEMENT = "system"; + String ENFORCE_ENDOINT_VALIDATION ="enforce-endpoint-validation"; + String LOCALE_ELEMENT = "locale"; + String MANAGEABLE_ELEMENT = "manageable"; + String DEFAULT_LOCALE_ELEMENT = "default-locale"; + String REDEPLOY_ELEMENT = "redeploy"; + String ENABLED_ELEMENT = "enabled"; + String WATCH_INTERVAL_ELEMENT = "watch-interval"; + String WATCH_FILE_ELEMENT = "watch-file"; + String TOUCH_FILE_ELEMENT = "touch-file"; + String FACTORIES_ELEMENT = "factories"; + String FACTORY_ELEMENT = "factory"; + String UUID_GENERATOR_ELEMENT = "uuid-generator"; + String DOTNET_FRAMEWORK_VERSION = "dotnet-framework-version"; + + // FlexClient + String FLEX_CLIENT_ELEMENT = "flex-client"; + String FLEX_CLIENT_TIMEOUT_MINUTES_ELEMENT = "timeout-minutes"; + String FLEX_CLIENT_OUTBOUND_QUEUE_PROCESSOR_ELEMENT = "flex-client-outbound-queue-processor"; + String ADAPTIVE_FREQUENCY = "adaptive-frequency"; + String FLEX_CLIENT_RELIABLE_RECONNECT_DURATION_MILLIS = "reliable-reconnect-duration-millis"; + String FLEX_CLIENT_HEARTBEAT_INTERVAL_MILLIS = "heartbeat-interval-millis"; + + // Message filters + String ASYNC_MESSAGE_FILTERS_ELEMENT = "async-message-filters"; + String SYNC_MESSAGE_FILTERS_ELEMENT = "sync-message-filters"; + String FILTER_ELEMENT = "filter"; + + // Validators + String VALIDATORS_ELEMENT = "validators"; + String VALIDATOR_ELEMENT = "validator"; + String TYPE_ATTR = "type"; + + // CHILD ELEMENTS + + // Top Level + String[] SERVICES_CONFIG_CHILDREN = { + SERVICES_ELEMENT, SECURITY_ELEMENT, SERVERS_ELEMENT, CHANNELS_ELEMENT, LOGGING_ELEMENT, + SYSTEM_ELEMENT, CLUSTERS_ELEMENT, FACTORIES_ELEMENT, FLEX_CLIENT_ELEMENT, + ASYNC_MESSAGE_FILTERS_ELEMENT, SYNC_MESSAGE_FILTERS_ELEMENT, VALIDATORS_ELEMENT + }; + + // Services + String[] SERVICES_CHILDREN = { + SERVICE_ELEMENT, SERVICE_INCLUDE_ELEMENT, DEFAULT_CHANNELS_ELEMENT + }; + + String[] SERVICE_INCLUDE_CHILDREN = { + SRC_ATTR, DIRECTORY_ATTR + }; + + String[] SERVICE_CHILDREN = { + ID_ATTR, CLASS_ATTR, MESSAGE_TYPES_ATTR, PROPERTIES_ELEMENT, + ADAPTERS_ELEMENT, DEFAULT_CHANNELS_ELEMENT, DEFAULT_SECURITY_CONSTRAINT_ELEMENT, + DESTINATION_INCLUDE_ELEMENT, DESTINATION_ELEMENT + }; + + String[] SERVICE_REQ_CHILDREN = { + ID_ATTR, CLASS_ATTR + }; + + String[] ADAPTER_DEFINITION_CHILDREN = { + ID_ATTR, CLASS_ATTR, DEFAULT_ATTR, PROPERTIES_ELEMENT + }; + + String[] ADAPTER_DEFINITION_REQ_CHILDREN = { + ID_ATTR, CLASS_ATTR + }; + + String[] DESTINATION_INCLUDE_CHILDREN = { + SRC_ATTR, DIRECTORY_ATTR + }; + + String[] ADAPTERS_CHILDREN = { + ADAPTER_DEFINITION_ELEMENT, ADAPTER_INCLUDE_ELEMENT + }; + + String[] ADAPTER_INCLUDE_CHILDREN = { + SRC_ATTR, DIRECTORY_ATTR + }; + + String[] DEFAULT_CHANNELS_CHILDREN = { + CHANNEL_ELEMENT + }; + + String[] FLEX_CLIENT_CHILDREN = { + FLEX_CLIENT_TIMEOUT_MINUTES_ELEMENT, FLEX_CLIENT_OUTBOUND_QUEUE_PROCESSOR_ELEMENT, + ADAPTIVE_FREQUENCY, FLEX_CLIENT_RELIABLE_RECONNECT_DURATION_MILLIS, FLEX_CLIENT_HEARTBEAT_INTERVAL_MILLIS + }; + + String[] FLEX_CLIENT_OUTBOUND_QUEUE_PROCESSOR_REQ_CHILDREN = { + CLASS_ATTR + }; + + // Security + String[] SECURITY_CHILDREN = { + SECURITY_CONSTRAINT_DEFINITION_ELEMENT, LOGIN_COMMAND_ELEMENT, RECREATE_HTTPSESSION_AFTER_LOGIN_ELEMENT, + CONSTRAINT_INCLUDE_ELEMENT + }; + + String[] EMBEDDED_SECURITY_CHILDREN = { + SECURITY_CONSTRAINT_DEFINITION_ELEMENT + }; + + String[] SECURITY_CONSTRAINT_DEFINITION_CHILDREN = { + REF_ATTR, ID_ATTR, AUTH_METHOD_ELEMENT, ROLES_ELEMENT + }; + + String[] ROLES_CHILDREN = { + ROLE_ELEMENT + }; + + String[] LOGIN_COMMAND_CHILDREN = { + SERVER_ATTR, CLASS_ATTR, PER_CLIENT_AUTH + }; + + String[] LOGIN_COMMAND_REQ_CHILDREN = { + SERVER_ATTR, CLASS_ATTR + }; + + String[] SECURITY_CONSTRAINTS_CHILDREN = { + SECURITY_CONSTRAINT_ELEMENT + }; + + String[] CONSTRAINT_INCLUDE_CHILDREN = { + SRC_ATTR, DIRECTORY_ATTR + }; + + // Servers + String[] SERVERS_CHILDREN = {SERVER_ELEMENT}; + + String[] SERVER_REQ_CHILDREN = { + ID_ATTR, CLASS_ATTR + }; + + String [] SERVER_CHILDREN = { + ID_ATTR, CLASS_ATTR, PROPERTIES_ELEMENT + }; + + // Channels + String[] CHANNELS_CHILDREN = { + CHANNEL_DEFINITION_ELEMENT, CHANNEL_INCLUDE_ELEMENT + }; + + String[] CHANNEL_DEFINITION_REQ_CHILDREN = { + ENDPOINT_ELEMENT, ID_ATTR + }; + + String[] CHANNEL_DEFINITION_CHILDREN = { + ENDPOINT_ELEMENT, PROPERTIES_ELEMENT, SECURITY_ELEMENT, SERVER_ELEMENT, + SECURITY_CONSTRAINT_ATTR, CLASS_ATTR, ID_ATTR, REMOTE_ATTR, SERVER_ONLY_ATTR + }; + + String[] CHANNEL_DEFINITION_SERVER_REQ_CHILDREN = { + REF_ATTR + }; + + String[] CHANNEL_INCLUDE_CHILDREN = { + SRC_ATTR, DIRECTORY_ATTR + }; + + String[] ENDPOINT_CHILDREN = { + URI_ATTR, URL_ATTR, CLASS_ATTR + }; + + String[] DESTINATION_REQ_CHILDREN = { + ID_ATTR + }; + + String[] DESTINATION_CHILDREN = { + ID_ATTR, PROPERTIES_ELEMENT, CHANNELS_ELEMENT, SECURITY_ELEMENT, ADAPTER_ELEMENT, + CHANNELS_ATTR, ADAPTER_ATTR, SECURITY_CONSTRAINT_ATTR + }; + + String[] DESTINATIONS_CHILDREN = { + DESTINATION_ELEMENT + }; + + String[] DESTINATION_ATTR = { + ID_ATTR, PROPERTIES_ELEMENT, CHANNELS_ELEMENT, ADAPTER_ELEMENT, + CHANNELS_ATTR, ADAPTER_ATTR, SECURITY_CONSTRAINT_ATTR + }; + + String[] DESTINATION_CHANNEL_REQ_CHILDREN = { + REF_ATTR + }; + + String[] DESTINATION_CHANNELS_CHILDREN = { + CHANNEL_ELEMENT + }; + + String[] DESTINATION_ADAPTER_CHILDREN = { + REF_ATTR + }; + + // Clustering + String[] CLUSTERING_CHILDREN = { + CLUSTER_DEFINITION_ELEMENT + }; + + String[] CLUSTER_DEFINITION_CHILDREN = { + ID_ATTR, CLUSTER_PROPERTIES_ATTR + }; + + // Logging + + String[] LOGGING_CHILDREN = { + PROPERTIES_ELEMENT, LEVEL_ATTR, TARGET_ELEMENT, + }; + + String[] TARGET_CHILDREN = { + CLASS_ATTR, LEVEL_ATTR, PROPERTIES_ELEMENT, FILTERS_ELEMENT + }; + + String[] TARGET_REQ_CHILDREN = { + CLASS_ATTR + }; + + String[] FILTERS_CHILDREN = { + PATTERN_ELEMENT + }; + + // System + + String[] SYSTEM_CHILDREN = { + LOCALE_ELEMENT, ENFORCE_ENDOINT_VALIDATION, REDEPLOY_ELEMENT, MANAGEABLE_ELEMENT, UUID_GENERATOR_ELEMENT, DOTNET_FRAMEWORK_VERSION + }; + + String[] REDEPLOY_CHILDREN = { + ENABLED_ELEMENT, WATCH_INTERVAL_ELEMENT, WATCH_FILE_ELEMENT, TOUCH_FILE_ELEMENT + }; + + String[] LOCALE_CHILDREN = { + DEFAULT_LOCALE_ELEMENT + }; + + // Factories + String[] FACTORIES_CHILDREN = { + FACTORY_ELEMENT + }; + + String[] FACTORY_REQ_CHILDREN = { + ID_ATTR, CLASS_ATTR + }; + + // Message filters + String[] ASYNC_MESSAGE_FILTERS_ELEMENT_CHILDREN = { + FILTER_ELEMENT + }; + + String[] SYNC_MESSAGE_FILTERS_ELEMENT_CHILDREN = { + FILTER_ELEMENT + }; + + String[] FILTER_CHILDREN = { + ID_ATTR, CLASS_ATTR, PROPERTIES_ELEMENT + }; + + String[] FILTER_REQ_CHILDREN = { + ID_ATTR, CLASS_ATTR + }; + + // UUID Generator + String[] UUID_GENERATOR_REQ_CHILDREN = { + CLASS_ATTR + }; + + // Validators + String[] VALIDATORS_CHILDREN = { + VALIDATOR_ELEMENT + }; + + String[] VALIDATOR_CHILDREN = { + CLASS_ATTR, TYPE_ATTR, PROPERTIES_ELEMENT + }; + + String[] VALIDATOR_REQ_CHILDREN = { + CLASS_ATTR + }; + + // UTILS + String LIST_DELIMITERS = ",;:"; + + // TOKEN REPLACEMENT + String UNKNOWN_SOURCE_FILE = "uknown file"; + + + // EXCEPTION MESSAGES + + int PARSER_INIT_ERROR = 10100; + int PARSER_INTERNAL_ERROR = 10101; + int XML_PARSER_ERROR = 10102; + int INVALID_SERVICES_ROOT = 10103; + int MISSING_ELEMENT = 10104; + int MISSING_ATTRIBUTE = 10105; + int UNEXPECTED_ELEMENT = 10106; + int UNEXPECTED_ATTRIBUTE = 10107; + int TOO_MANY_OCCURRENCES = 10108; + int REF_NOT_FOUND = 10109; + int INVALID_ID = 10110; + int INVALID_ENDPOINT_PORT = 10111; + int INVALID_INCLUDE_ROOT = 10112; + int DUPLICATE_SERVICE_ERROR = 10113; + int CLASS_NOT_SPECIFIED = 10114; + int INVALID_DEFAULT_CHANNEL = 10116; + int DUPLICATE_DEFAULT_ADAPTER = 10117; + int MISSING_INCLUDE_ATTRIBUTES = 10118; + int INVALID_ID_IN_SERVICE = 10119; + int REF_NOT_FOUND_IN_DEST = 10120; + int INVALID_REF_IN_DEST = 10121; + int DUPLICATE_DESTINATION_ERROR = 10122; + int DEST_NEEDS_CHANNEL = 10123; + int DEST_NEEDS_ADAPTER = 10127; + int REF_NOT_FOUND_IN_CHANNEL = 10132; + int UNEXPECTED_TEXT = 11104; + + int NULL_COMPONENT = 11110; + int NULL_COMPONENT_ID = 11111; + int DUPLICATE_COMPONENT_ID = 11112; + int UNREGISTERED_ADAPTER = 11114; + int DUPLICATE_DEST_ID = 11119; + + int UNDEFINED_CONTEXT_ROOT = 11120; + int INVALID_FLEX_CLIENT_TIMEOUT = 11123; + int INVALID_SECURITY_CONSTRAINT_REF = 11124; + int IRREPLACABLE_TOKEN = 11125; + int INVALID_VALUE_FOR_PROPERTY_OF_COMPONENT_WITH_ID = 11126; + int DUPLICATE_CHANNEL_ERROR = 11127; + int INVALID_FLEX_CLIENT_RELIABLE_RECONNECT_DURATION_MILLIS = 11137; + int INVALID_FLEX_CLIENT_HEARTBEAT_INTERVAL_MILLIS = 11146; + + int REQUIRE_ADVANCED_MESSAGING_SUPPORT = 11129; + int CLASS_OR_SERVER_ONLY_ERROR = 11139; + int CLASS_AND_SERVER_ONLY_ERROR = 11140; + int ERR_MSG_EMPTY_CLIENT_LOAD_BALANCING_ELEMENT = 11141; + int ERR_MSG_EMTPY_CLIENT_LOAD_BALACNING_URL = 11142; + int ERR_MSG_CLIENT_LOAD_BALANCING_URL_WITH_TOKEN = 11147; + + int EXTERNAL_ENTITY_NOT_ALLOW = 11149; +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ConfigurationException.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ConfigurationException.java b/common/src/main/java/flex/messaging/config/ConfigurationException.java new file mode 100644 index 0000000..49e5285 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ConfigurationException.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** + * The server throws this exception type on encountering + * errors while parsing the configuration. Other classes + * may also throw this exception type during initialization + * in the event that the configuration settings used to + * initialize the component was invalid. + */ +public class ConfigurationException extends LocalizedException +{ + /** + * This number was generated using the 'serialver' command line tool. + * This number should remain consistent with the version used by + * ColdFusion to communicate with the message broker over RMI. + */ + private static final long serialVersionUID = -6999307106348525358L; +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ConfigurationFileResolver.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ConfigurationFileResolver.java b/common/src/main/java/flex/messaging/config/ConfigurationFileResolver.java new file mode 100644 index 0000000..8336d2b --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ConfigurationFileResolver.java @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * + */ +public interface ConfigurationFileResolver +{ + InputStream getConfigurationFile(String path); + InputStream getIncludedFile(String path); + void popIncludedFile(); + + List getFiles(String dir); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ConfigurationParser.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ConfigurationParser.java b/common/src/main/java/flex/messaging/config/ConfigurationParser.java new file mode 100644 index 0000000..ef8aaeb --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ConfigurationParser.java @@ -0,0 +1,30 @@ +/* + * 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; + +/** + * Configuration parser for Flex Data Services. The parser reads in + * a configuration file and populates a ServicesConfiguration instance. + * + * + */ +public interface ConfigurationParser +{ + void parse(String path, ConfigurationFileResolver fileResolver, ServicesConfiguration config); + + void reportTokens(); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/DestinationSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/DestinationSettings.java b/common/src/main/java/flex/messaging/config/DestinationSettings.java new file mode 100644 index 0000000..3cd0e2f --- /dev/null +++ b/common/src/main/java/flex/messaging/config/DestinationSettings.java @@ -0,0 +1,188 @@ +/* + * 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.util.ArrayList; +import java.util.List; + +/** + * Destinations are configured for a particular <code>Service</code>. A + * destination's configuration includes an <code>id</code> attribute to provide + * a public name for clients to use when sending messages. + * <p> + * The configuration also specifies which channels are valid to contact the + * destination, as well as which adapter a service must use to process + * client messages for this destination and any security constraints that need + * to be enforced. + * </p> + */ +public class DestinationSettings extends PropertiesSettings +{ + /** + * + */ + public static final String SERVER_ELEMENT = "server"; + + private final String id; + private String sourceFile; + private List channelSettings; + private AdapterSettings adapterSettings; + private SecurityConstraint constraint; + + /** + * Used to construct a new set of properties to describe a destination. + * Note that an identity is required in order for clients to refer to a + * destination. + * + * @param id A string representing the unique identity of this destination. + */ + public DestinationSettings(String id) + { + this.id = id; + channelSettings = new ArrayList(); + } + + /** + * Gets the unique identity used by clients to target a destination. + * + * @return String the destination's id. + */ + public String getId() + { + return id; + } + + /** + * Internal use only. + * + */ + String getSourceFile() + { + return sourceFile; + } + + /** + * Internal use only. + * + */ + void setSourceFile(String sourceFile) + { + this.sourceFile = sourceFile; + } + + /* + * CHANNEL SETTINGS + */ + + /** + * Adds a channel to the set of channels that should be used to contact + * this destination. The order in which channels are added is significant + * (clients use this order to locate an available channel and failover to + * the next in the list on failure). + * + * @param c the <code>ChannelSettings</code> to add to the set of + * channel definitions for this destination. + */ + public void addChannelSettings(ChannelSettings c) + { + if (c != null) + { + channelSettings.add(c); + } + } + + /** + * Overrides the set of channels that can be used to contact this + * destination. + * + * @param settings A List of <code>ChannelSettings</code>. + */ + public void setChannelSettings(List settings) + { + channelSettings = settings; + } + + /** + * Gets the set of channels that can be used to contact this destination. + * + * @return a <code>java.util.List</code> of <code>ChannelSetting</code>s + * describing the channels that can be used to contact this destination. + */ + public List getChannelSettings() + { + return channelSettings; + } + + + /* + * SECURITY + */ + + /** + * Gets the <code>SecurityConstraint</code> that will be applied to this + * destination, or <code>null</code> if no constraint has been registered. + * + * @return the <code>SecurityConstraint</code> for this destination. + */ + public SecurityConstraint getConstraint() + { + return constraint; + } + + /** + * Sets the security constraint to be applied to this destination. Security + * constraints restrict which clients can contact this destination. Use + * <code>null</code> to remove an existing constraint. + * + * @param sc the <code>SecurityConstraint</code> to apply to this + * destination. + */ + public void setConstraint(SecurityConstraint sc) + { + constraint = sc; + } + + /* + * SERVICE ADAPTER + */ + + /** + * Sets the service adapter to be used when the managing service is + * processing messages bound for this destination. + * + * @param a The <code>AdapterSettings</code> that describe the adapter + * to use for this destination. + */ + public void setAdapterSettings(AdapterSettings a) + { + adapterSettings = a; + } + + /** + * Gets the adapter to be used for this destination. + * + * @return <code>AdapterSettings</code> for this destinations adapter. + * A <code>null</code> value implies the the default service adapter should + * be used. + */ + public AdapterSettings getAdapterSettings() + { + return adapterSettings; + } + + +}
