blob: 1272dba3f016d499a579f0f01ae42fc010174887 [file] [log] [blame]
/*
* 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>
* &lt;default-channels&gt;<br />
* ;&lt;channel ref="channel-id" /&gt;<br />
* &lt;default-channels&gt;
* </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>
* &lt;default-channels&gt;<br />
* &lt;channel ref="channel-id" /&gt;<br />
* &lt;default-channels&gt;
* </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);
}
}
}