http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/FlexClientSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/FlexClientSettings.java b/common/src/main/java/flex/messaging/config/FlexClientSettings.java new file mode 100644 index 0000000..bba7e5a --- /dev/null +++ b/common/src/main/java/flex/messaging/config/FlexClientSettings.java @@ -0,0 +1,134 @@ +/* + * 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 FlexClientSettings extends PropertiesSettings +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructs a FlexClientSettings instance. + */ + public FlexClientSettings() + { + // Empty for now. + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + private long timeoutMinutes = -1; + + /** + * Returns the number of minutes before an idle FlexClient is timed out. + * + * @return The number of minutes before an idle FlexClient is timed out. + */ + public long getTimeoutMinutes() + { + return timeoutMinutes; + } + + /** + * Sets the number of minutes before an idle FlexClient is timed out. + * + * @param value The number of minutes before an idle FlexClient is timed out. + */ + public void setTimeoutMinutes(long value) + { + timeoutMinutes = value; + } + + private String flexClientOutboundQueueProcessorClassName; + + /** + * Returns the name of the default <code>FlexClientOutboundQueueProcessorClass</code>. + * + * @return The the name of the default <code>FlexClientOutboundQueueProcessorClass</code>. + */ + public String getFlexClientOutboundQueueProcessorClassName() + { + return flexClientOutboundQueueProcessorClassName; + } + + /** + * Sets the name of the default <code>FlexClientOutboundQueueProcessor</code>. + * + * @param flexClientOutboundQueueProcessorClassName The name of the default <code>FlexClientOutboundQueueProcessor</code>. + */ + public void setFlexClientOutboundQueueProcessorClassName(String flexClientOutboundQueueProcessorClassName) + { + this.flexClientOutboundQueueProcessorClassName = flexClientOutboundQueueProcessorClassName; + } + + private ConfigMap flexClientOutboundQueueProcessorProperties; + + /** + * Returns the properties for the default <code>FlexClientOutboundQueueProcessor</code>. + * + * @return The properties for the default <code>FlexClientOutboundQueueProcessor</code>. + */ + public ConfigMap getFlexClientOutboundQueueProcessorProperties() + { + return flexClientOutboundQueueProcessorProperties; + } + + /** + * Sets the properties for the default <code>FlexClientOutboundQueueProcessor</code>. + * + * @param flexClientOutboundQueueProcessorProperties properties for the default + * <code>FlexClientOutboundQueueProcessor</code> + */ + public void setFlexClientOutboundQueueProcessorProperties(ConfigMap flexClientOutboundQueueProcessorProperties) + { + this.flexClientOutboundQueueProcessorProperties = flexClientOutboundQueueProcessorProperties; + } + + private int reliableReconnectDurationMillis; + + public int getReliableReconnectDurationMillis() + { + return reliableReconnectDurationMillis; + } + + public void setReliableReconnectDurationMillis(int value) + { + reliableReconnectDurationMillis = value; + } + + private int heartbeatIntervalMillis; + + public int getHeartbeatIntervalMillis() + { + return heartbeatIntervalMillis; + } + + public void setHeartbeatIntervalMillis(int value) + { + heartbeatIntervalMillis = value; + } +}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/LocalFileResolver.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/LocalFileResolver.java b/common/src/main/java/flex/messaging/config/LocalFileResolver.java new file mode 100644 index 0000000..04b623b --- /dev/null +++ b/common/src/main/java/flex/messaging/config/LocalFileResolver.java @@ -0,0 +1,203 @@ +/* + * 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.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * + */ +public class LocalFileResolver implements ConfigurationFileResolver +{ + public static final int CLIENT = 0; + public static final int SERVER = 1; + public static final int LIVECYCLE = 2; + + private static final int ERR_MSG_INVALID_PATH_CLIENT = 11106; + private static final int ERR_MSG_INVALID_PATH_SERVER = 11108; + private static final int ERR_MSG_INVALID_PATH_LIVECYCLE = 11122; + + private Stack configurationPathStack = new Stack(); + int version = CLIENT; + + public LocalFileResolver() + { + } + + public LocalFileResolver(int version) + { + this.version = version; + } + + public void setErrorMessage(ConfigurationException e, String path) + { + if (version == LIVECYCLE) + { + // Invalid location: ''{0}''. Please specify a valid LiveCycle Data Services Configuration file via the LiveCycle Admin UI. + e.setMessage(ERR_MSG_INVALID_PATH_LIVECYCLE, new Object[] {path}); + } + else if (version == SERVER) + { + // Please specify a valid ''services.configuration.file'' in web.xml. You specified ''{0}''. This is not a valid file system path reachable via the app server and is also not a path to a resource in your J2EE application archive. + e.setMessage(ERR_MSG_INVALID_PATH_SERVER, new Object[]{path}); + } + else + { + // Please specify a valid <services/> file path in flex-config.xml. + e.setMessage(ERR_MSG_INVALID_PATH_CLIENT); + } + } + + public InputStream getConfigurationFile(String path) + { + File f = new File(path); + try + { + if (f != null && f.exists() && f.isAbsolute()) + { + FileInputStream fin = new FileInputStream(f); + pushConfigurationFile(f.getParent()); + return fin; + } + else + { + ConfigurationException e = new ConfigurationException(); + setErrorMessage(e, path); + throw e; + } + } + catch (FileNotFoundException ex) + { + ConfigurationException e = new ConfigurationException(); + setErrorMessage(e, path); + e.setRootCause(ex); + throw e; + } + catch (SecurityException se) + { + ConfigurationException e = new ConfigurationException(); + setErrorMessage(e, path); + e.setRootCause(se); + throw e; + } + } + + public InputStream getIncludedFile(String src) + { + String path = configurationPathStack.peek() + File.separator + src; + File f = new File(path); + try + { + if (f != null && f.exists() && f.isAbsolute()) + { + FileInputStream fin = new FileInputStream(f); + pushConfigurationFile(f.getParent()); + return fin; + } + else + { + // Please specify a valid include file. ''{0}'' is invalid. + ConfigurationException e = new ConfigurationException(); + e.setMessage(11107, new Object[] {path}); + throw e; + } + } + catch (FileNotFoundException ex) + { + // Please specify a valid include file. ''{0}'' is invalid. + ConfigurationException e = new ConfigurationException(); + e.setMessage(11107, new Object[] {path}); + e.setRootCause(ex); + throw e; + } + catch (SecurityException se) + { + // Please specify a valid include file. ''{0}'' is invalid. + ConfigurationException e = new ConfigurationException(); + e.setMessage(11107, new Object[] {path}); + e.setRootCause(se); + throw e; + } + } + + public void popIncludedFile() + { + configurationPathStack.pop(); + } + + /** + * Returns the list of XML files (denoted by .xml extension) in the directory + * relative to the current configuration file. + * + * @param dir a directory relative to the current configuration file + * @return a (possibly empty) list of file names + */ + public List getFiles(String dir) + { + List result = new ArrayList(); + File f = new File(configurationPathStack.peek().toString(), dir); + if (f.exists() && f.isDirectory()) + { + String[] xmlFiles = f.list(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.endsWith(".xml"); + } + }); + + // prepend the directory to each filename + for (int i = 0; i < xmlFiles.length; i++) + { + String file = xmlFiles[i]; + result.add(dir + File.separator + file); + } + return result; + } + else + { + // Please specify a valid include directory. ''{0}'' is invalid. + ConfigurationException e = new ConfigurationException(); + e.setMessage(11113, new Object[]{dir}); + throw e; + } + } + + private void pushConfigurationFile(String topLevelPath) + { + configurationPathStack.push(topLevelPath); + } + + public String getIncludedPath(String src) + { + return configurationPathStack.peek() + File.separator + src; + } + + public long getIncludedLastModified(String src) + { + String path = configurationPathStack.peek() + File.separator + src; + File f = new File(path); + return f.lastModified(); + } +} \ 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/LoggingSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/LoggingSettings.java b/common/src/main/java/flex/messaging/config/LoggingSettings.java new file mode 100644 index 0000000..5fe26e1 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/LoggingSettings.java @@ -0,0 +1,46 @@ +/* + * 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.List; +import java.util.ArrayList; + +/** + * A log maintains a series of Loggers for each logging category and + * Targets are established that listen for LogEvents on those Loggers. + * + * + */ +public class LoggingSettings extends PropertiesSettings +{ + private final List targets; + + public LoggingSettings() + { + targets = new ArrayList(); + } + + public void addTarget(TargetSettings t) + { + targets.add(t); + } + + public List getTargets() + { + return targets; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/LoginCommandSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/LoginCommandSettings.java b/common/src/main/java/flex/messaging/config/LoginCommandSettings.java new file mode 100644 index 0000000..2cc0ccd --- /dev/null +++ b/common/src/main/java/flex/messaging/config/LoginCommandSettings.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.config; + +/** + * Settings for <code>LoginCommand</code> class. + * + * + */ +public class LoginCommandSettings +{ + public static final String SERVER_MATCH_OVERRIDE = "all"; + + private String className; + private String server; + private boolean perClientAuthentication; + + /** + * Create a new <code>LoginCommandSettings</code> instance with default settings. + */ + public LoginCommandSettings() + { + perClientAuthentication = false; + } + + /** + * Returns the class name associated with the settings. + * + * @return The class name. + */ + public String getClassName() + { + return className; + } + + /** + * Sets the class name associated with the settings. + * + * @param className The class name. + */ + public void setClassName(String className) + { + this.className = className; + } + + /** + * Returns the server name associated with the settings. + * + * @return The server name. + */ + public String getServer() + { + return server; + } + + /** + * Sets the server name associated with the settings. + * + * @param server The server name. + */ + public void setServer(String server) + { + this.server = server; + } + + /** + * Returns whether per client authentication is enabled or not. + * + * @return <code>true</code> if per client authentication is enabled; + * otherwise <code>false</code>. + */ + public boolean isPerClientAuthentication() + { + return perClientAuthentication; + } + + /** + * Sets whether per client authentication is enabled or not. + * + * @param perClientAuthentication <code>true</code> if per client authentication + * is enabled; otherwise <code>false</code>. + */ + public void setPerClientAuthentication(boolean perClientAuthentication) + { + this.perClientAuthentication = perClientAuthentication; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/PropertiesSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/PropertiesSettings.java b/common/src/main/java/flex/messaging/config/PropertiesSettings.java new file mode 100644 index 0000000..4fa0a83 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/PropertiesSettings.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.config; + +import java.util.List; + +/** + * Holds any child element of the properties section of the services configuration. + * <p> + * If a property is a simple element with a text value then it is stored as a String + * using the element name as the property name. If the same element appears again then + * the element is converted to a List of values and further occurences are simply added + * to the List. + * </p> + * <p> + * If a property element has child elements the children are recursively processed + * and added as a Map. + * </p> + * + * + */ +public abstract class PropertiesSettings +{ + protected final ConfigMap properties; + + public PropertiesSettings() + { + properties = new ConfigMap(); + } + + public final void addProperties(ConfigMap p) + { + properties.addProperties(p); + } + + public ConfigMap getProperties() + { + return properties; + } + + public final String getProperty(String name) + { + return getPropertyAsString(name, null); + } + + public final void addProperty(String name, String value) + { + properties.addProperty(name, value); + } + + public final void addProperty(String name, ConfigMap value) + { + properties.addProperty(name, value); + } + + public final ConfigMap getPropertyAsMap(String name, ConfigMap defaultValue) + { + return properties.getPropertyAsMap(name, defaultValue); + } + + public final String getPropertyAsString(String name, String defaultValue) + { + return properties.getPropertyAsString(name, defaultValue); + } + + public final List getPropertyAsList(String name, List defaultValue) + { + return properties.getPropertyAsList(name, defaultValue); + } + + public final int getPropertyAsInt(String name, int defaultValue) + { + return properties.getPropertyAsInt(name, defaultValue); + } + + public final boolean getPropertyAsBoolean(String name, boolean defaultValue) + { + return properties.getPropertyAsBoolean(name, defaultValue); + } + + public final long getPropertyAsLong(String name, long defaultValue) + { + return properties.getPropertyAsLong(name, defaultValue); + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/SecurityConstraint.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/SecurityConstraint.java b/common/src/main/java/flex/messaging/config/SecurityConstraint.java new file mode 100644 index 0000000..0b7638b --- /dev/null +++ b/common/src/main/java/flex/messaging/config/SecurityConstraint.java @@ -0,0 +1,123 @@ +/* + * 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; + +/** + * Security constraints are used by the login manager to secure access to + * destinations and endpoints. + */ +public class SecurityConstraint +{ + /** + * String constant for basic authentication. + */ + public static final String BASIC_AUTH_METHOD = "Basic"; + + /** + * String constant for custom authentication. + */ + public static final String CUSTOM_AUTH_METHOD = "Custom"; + + private final String id; + private String method; + private List roles; + + /** + * Creates an anonymous <code>SecurityConstraint</code> instance. + */ + public SecurityConstraint() + { + this(null); + } + + /** + * Creates a <code>SecurityConstraint</code> instance with an id. + * + * @param id The id of the <code>SecurityConstraint</code> instance. + */ + public SecurityConstraint(String id) + { + this.id = id; + method = CUSTOM_AUTH_METHOD; + } + + /** + * Returns a list of roles of the <code>SecurityConstraint</code>. + * + * @return List of roles. + */ + public List getRoles() + { + return roles; + } + + /** + * Adds a role to the list of roles of the <code>SecurityConstraint</code>. + * + * @param role New role to add to the list of roles. + */ + public void addRole(String role) + { + if (role == null) + return; + + if (roles == null) + roles = new ArrayList(); + + roles.add(role); + } + + /** + * Returns the id of the <code>SecurityConstraint</code>. + * + * @return The id of the <code>SecurityConstraint</code>. + */ + public String getId() + { + return id; + } + + /** + * Returns the authorization method of the <code>SecurityConstraint</code>. + * + * @return Authorization method. + */ + public String getMethod() + { + return method; + } + + /** + * Sets the authorization method of the <code>SecurityConstraint</code>. + * Valid values are Basic and Custom. + * + * @param method The authentication method to set which can be custom or basic. + */ + public void setMethod(String method) + { + if (method == null) + return; + + if (CUSTOM_AUTH_METHOD.equalsIgnoreCase(method)) + this.method = CUSTOM_AUTH_METHOD; + else if (BASIC_AUTH_METHOD.equalsIgnoreCase(method)) + this.method = BASIC_AUTH_METHOD; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ServiceSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ServiceSettings.java b/common/src/main/java/flex/messaging/config/ServiceSettings.java new file mode 100644 index 0000000..44d95b5 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ServiceSettings.java @@ -0,0 +1,165 @@ +/* + * 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.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A service represents a high-level grouping of + * functionality to which the message broker can + * delegate messages. Services specify which + * message types they're interested in and use + * adapters to carry out a message's for a + * destination. + * <p> + * A service maintains a list of destinations which + * effectively represents a "whitelist" + * of actions allowed by that service. + * </p> + * + * + */ +public class ServiceSettings extends PropertiesSettings +{ + private final String id; + private String sourceFile; + private String className; + + private AdapterSettings defaultAdapterSettings; + private final Map adapterSettings; + private final List defaultChannels; + private final Map destinationSettings; + private SecurityConstraint securityConstraint; + + public ServiceSettings(String id) + { + this.id = id; + destinationSettings = new HashMap(); + adapterSettings = new HashMap(2); + defaultChannels = new ArrayList(4); + } + + public String getId() + { + return id; + } + + String getSourceFile() + { + return sourceFile; + } + + void setSourceFile(String sourceFile) + { + this.sourceFile = sourceFile; + } + + public String getClassName() + { + return className; + } + + public void setClassName(String name) + { + className = name; + } + + /* + * SERVER ADAPTERS + */ + public AdapterSettings getDefaultAdapter() + { + return defaultAdapterSettings; + } + + public AdapterSettings getAdapterSettings(String id) + { + return (AdapterSettings)adapterSettings.get(id); + } + + public Map getAllAdapterSettings() + { + return adapterSettings; + } + + public void addAdapterSettings(AdapterSettings a) + { + adapterSettings.put(a.getId(), a); + if (a.isDefault()) + { + defaultAdapterSettings = a; + } + } + + /* + * DEFAULT CHANNELS + */ + public void addDefaultChannel(ChannelSettings c) + { + defaultChannels.add(c); + } + + public List getDefaultChannels() + { + return defaultChannels; + } + + /* + * DEFAULT SECURITY + */ + + /** + * Gets the <code>SecurityConstraint</code> that will be applied to all + * destinations of the service, or <code>null</code> if no constraint has + * been registered. + * + * @return the <code>SecurityConstraint</code> for this service. + */ + public SecurityConstraint getConstraint() + { + return securityConstraint; + } + + /** + * Sets the security constraint to be applied to all destinations of the service. + * 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 + * service. + */ + public void setConstraint(SecurityConstraint sc) + { + securityConstraint = sc; + } + + /* + * DESTINATIONS + */ + public Map getDestinationSettings() + { + return destinationSettings; + } + + public void addDestinationSettings(DestinationSettings dest) + { + destinationSettings.put(dest.getId(), dest); + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ServicesConfiguration.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ServicesConfiguration.java b/common/src/main/java/flex/messaging/config/ServicesConfiguration.java new file mode 100644 index 0000000..561d75b --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ServicesConfiguration.java @@ -0,0 +1,70 @@ +/* + * 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.List; +import java.util.Map; + +/** + * Base interface for Flex Data Services configuration. + * + * Implementations may have different levels of detail + * based on how much of the configuration is supported. + * + * + */ +public interface ServicesConfiguration +{ + /* + * CHANNEL CONFIGURATION + */ + + void addChannelSettings(String id, ChannelSettings settings); + + ChannelSettings getChannelSettings(String ref); + + Map getAllChannelSettings(); + + /* + * DEFAULT CHANNELS CONFIGURATION + */ + void addDefaultChannel(String id); + + List getDefaultChannels(); + + /* + * SERVICE CONFIGURATION + */ + + void addServiceSettings(ServiceSettings settings); + + ServiceSettings getServiceSettings(String id); + + List getAllServiceSettings(); + + /* + * LOGGING CONFIGURATION + */ + void setLoggingSettings(LoggingSettings settings); + + LoggingSettings getLoggingSettings(); + + /* CLUSTER CONFIGURATION */ + ClusterSettings getClusterSettings(String clusterId); + + ClusterSettings getDefaultCluster(); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/ServicesDependencies.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/ServicesDependencies.java b/common/src/main/java/flex/messaging/config/ServicesDependencies.java new file mode 100644 index 0000000..92b7c34 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/ServicesDependencies.java @@ -0,0 +1,747 @@ +/* + * 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.File; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import flex.messaging.LocalizedException; + +/** + * Flex MXMLC compiler uses the result of the client configuration parser + * to generate mixin initialization source code to be added to the SWF by + * PreLink. It also requires a list of channel classes to be added as + * dependencies. + * + * + */ +public class ServicesDependencies +{ + private static final String ADVANCED_CHANNELSET_CLASS = "mx.messaging.AdvancedChannelSet"; + private static final String ADVANCED_MESSAGING_SUPPORT_CLASS = "flex.messaging.services.AdvancedMessagingSupport"; + private static final String REDIRECT_URL = "redirect-url"; + + private boolean containsClientLoadBalancing; + private String xmlInit = ""; + private StringBuffer imports = new StringBuffer(); + private StringBuffer references = new StringBuffer(); + private List channelClasses; + private Map configPaths; + private Map lazyAssociations; + + private static final List channel_excludes = new ArrayList(); + static + { + channel_excludes.add(REDIRECT_URL); + } + + public static final boolean traceConfig = (System.getProperty("trace.config") != null); + + public ServicesDependencies(String path, String parserClass, String contextRoot) + { + ClientConfiguration config = getClientConfiguration(path, parserClass); + + if (config != null) + { + Map importMap = new HashMap(); + lazyAssociations = new HashMap(); + configPaths = config.getConfigPaths(); + xmlInit = codegenXmlInit(config, contextRoot, importMap); + codegenServiceImportsAndReferences(importMap, imports, references); + channelClasses = listChannelClasses(config); + } + } + + public Set getLazyAssociations(String destination) + { + if (lazyAssociations == null) + { + lazyAssociations = new HashMap(); + } + + return (Set)lazyAssociations.get(destination); + } + + public void addLazyAssociation(String destination, String associationProp) + { + Set la = getLazyAssociations(destination); + if (la == null) + { + la = new HashSet(); + lazyAssociations.put(destination, la); + } + la.add(associationProp); + } + + public String getServerConfigXmlInit() + { + return xmlInit; + } + + public String getImports() + { + return imports.toString(); + } + + public String getReferences() + { + return references.toString(); + } + + public List getChannelClasses() + { + return channelClasses; + } + + public void addChannelClass(String className) + { + channelClasses.add(className); + } + + public void addConfigPath(String path, long modified) + { + configPaths.put(path, new Long(modified)); + } + + public Map getConfigPaths() + { + return configPaths; + } + + /** + * Gets ActionScript source file for a class. The class will be compiled as + * a mixin and initialize Flex at runtime. + * + * @param packageName - the package compiled into the generated source. + * @param className - the class name of the generated source. + * @return A String that represents an ActionScript Source file. + */ + public String getServicesInitSource(String packageName, String className) + { + StringBuilder sb = new StringBuilder(2048); + + sb.append("package ").append(packageName).append("\n"); + sb.append("{\n\n"); + sb.append("import mx.core.IFlexModuleFactory;\n"); + sb.append("import flash.net.registerClassAlias;\n"); + sb.append("import flash.net.getClassByAlias;\n"); + + // generated imports + sb.append(getImports()); + + sb.append("\n[Mixin]\n"); + sb.append("public class ").append(className).append("\n"); + sb.append("{\n"); + sb.append(" public function ").append(className).append("()\n"); + sb.append(" {\n"); + sb.append(" super();\n"); + sb.append(" }\n\n"); + sb.append(" public static function init(fbs:IFlexModuleFactory):void\n"); + sb.append(" {\n"); + + // code for init + sb.append(getServerConfigXmlInit()); + sb.append(" }\n\n"); + + // generated variables to create references + sb.append(getReferences()); + sb.append("}\n"); + sb.append("}\n"); + + return sb.toString(); + } + + public static ClientConfiguration getClientConfiguration(String path, String parserClass) + { + ClientConfiguration config = new ClientConfiguration(); + + ConfigurationParser parser = getConfigurationParser(parserClass); + + if (parser == null) + { + // "Unable to create a parser to load messaging configuration." + LocalizedException lme = new LocalizedException(); + lme.setMessage(10138); + throw lme; + } + + LocalFileResolver local = new LocalFileResolver(); + parser.parse(path, local, config); + + config.addConfigPath(path, new File(path).lastModified()); + + return config; + } + + static ConfigurationParser getConfigurationParser(String className) + { + ConfigurationParser parser = null; + Class parserClass = null; + + // Check for Custom Parser Specification + if (className != null) + { + try + { + parserClass = Class.forName(className); + parser = (ConfigurationParser)parserClass.newInstance(); + } + catch (Throwable t) + { + if (traceConfig) + { + System.out.println("Could not load services configuration parser as: " + className); + } + } + } + + // Try Sun JRE 1.4 / Apache Xalan Based Implementation + if (parser == null) + { + try + { + Class.forName("org.apache.xpath.CachedXPathAPI"); + className = "flex.messaging.config.ApacheXPathClientConfigurationParser"; + parserClass = Class.forName(className); + parser = (ConfigurationParser)parserClass.newInstance(); + } + catch (Throwable t) + { + if (traceConfig) + { + System.out.println("Could not load configuration parser as: " + className); + } + } + } + + // Try Sun JRE 1.5 Based Implementation + if (parser == null) + { + try + { + className = "flex.messaging.config.XPathClientConfigurationParser"; + parserClass = Class.forName(className); + // double-check, on some systems the above loads but the import classes don't + Class.forName("javax.xml.xpath.XPathExpressionException"); + + parser = (ConfigurationParser)parserClass.newInstance(); + } + catch (Throwable t) + { + if (traceConfig) + { + System.out.println("Could not load configuration parser as: " + className); + } + } + } + + if (traceConfig && parser != null) + { + System.out.println("Services Configuration Parser: " + parser.getClass().getName()); + } + + return parser; + } + + private static List listChannelClasses(ServicesConfiguration config) + { + List channelList = new ArrayList(); + Iterator it = config.getAllChannelSettings().values().iterator(); + while (it.hasNext()) + { + ChannelSettings settings = (ChannelSettings)it.next(); + if (!settings.serverOnly) + { + String clientType = settings.getClientType(); + channelList.add(clientType); + } + } + + return channelList; + } + + /** + * Emits source code declaration of public var xml:XML (unnamed package), containing ServicesConfiguration as e4x. + */ + private String codegenXmlInit(ServicesConfiguration config, String contextRoot, Map serviceImportMap) + { + StringBuffer e4x = new StringBuffer(); + String channelSetImplToImport = null; + + e4x.append("<services>\n"); + + // Add default channels of the application + if (config.getDefaultChannels().size() > 0) + { + e4x.append("\t<default-channels>\n"); + for (Iterator chanIter = config.getDefaultChannels().iterator(); chanIter.hasNext();) + { + String id = (String)chanIter.next(); + e4x.append("\t\t<channel ref=\"" + id + "\"/>\n"); + } + e4x.append("\t</default-channels>\n"); + } + + ClusterSettings defaultCluster = config.getDefaultCluster(); + // Do not add the cluster tag if the default cluster does not have + // client side load balancing. + if (defaultCluster != null && !defaultCluster.getURLLoadBalancing()) + defaultCluster = null; + + for (Iterator servIter = config.getAllServiceSettings().iterator(); servIter.hasNext();) + { + ServiceSettings entry = (ServiceSettings)servIter.next(); + + // FIXME: Need to find another way to skip BootstrapServices + // Skip services with no message types + /* + String messageTypes = entry.getMessageTypesString(); + if (messageTypes == null) + continue; + */ + + String serviceType = entry.getId(); + e4x.append("\t<service id=\""); + e4x.append(serviceType); + e4x.append("\""); + e4x.append(">\n"); + + String serviceClass = entry.getClassName(); + if (ADVANCED_MESSAGING_SUPPORT_CLASS.equals(serviceClass)) + channelSetImplToImport = ADVANCED_CHANNELSET_CLASS; + + String useTransactionsStr = entry.getProperties().getPropertyAsString("use-transactions", null); + if (useTransactionsStr != null) + { + e4x.append("\t\t<properties>\n\t\t\t<use-transactions>" + useTransactionsStr + "</use-transactions>\n"); + e4x.append("\t\t</properties>\n"); + } + + for (Iterator destIter = entry.getDestinationSettings().values().iterator(); destIter.hasNext();) + { + DestinationSettings dest = (DestinationSettings) destIter.next(); + String destination = dest.getId(); + e4x.append("\t\t<destination id=\"" + destination + "\">\n"); + + // add in the identity properties + ConfigMap metadata = dest.getProperties().getPropertyAsMap("metadata", null); + boolean closePropTag = false; + if (metadata != null) + { + e4x.append("\t\t\t<properties>\n\t\t\t\t<metadata\n"); + String extendsStr = metadata.getPropertyAsString("extends", null); + if (extendsStr != null) + { + e4x.append(" extends=\""); + e4x.append(extendsStr); + e4x.append("\""); + } + e4x.append(">"); + closePropTag = true; + List identities = metadata.getPropertyAsList("identity", null); + if (identities != null) + { + Iterator it = identities.iterator(); + while (it.hasNext()) + { + Object o = it.next(); + String identityName = null; + String undefinedValue = null; + if (o instanceof String) + { + identityName = (String) o; + } + else if (o instanceof ConfigMap) + { + identityName = ((ConfigMap) o).getPropertyAsString("property", null); + undefinedValue = ((ConfigMap) o).getPropertyAsString("undefined-value", null); + } + + if (identityName != null) + { + e4x.append("\t\t\t\t\t<identity property=\""); + e4x.append(identityName); + e4x.append("\""); + if (undefinedValue != null) + { + e4x.append(" undefined-value=\""); + e4x.append(undefinedValue); + e4x.append("\""); + } + e4x.append("/>\n"); + } + } + } + // add associations which reference other data service destinations + codegenServiceAssociations(metadata, e4x, destination, "one-to-many"); + codegenServiceAssociations(metadata, e4x, destination, "many-to-many"); + codegenServiceAssociations(metadata, e4x, destination, "one-to-one"); + codegenServiceAssociations(metadata, e4x, destination, "many-to-one"); + + e4x.append("\t\t\t\t</metadata>\n"); + } + + String itemClass = dest.getProperties().getPropertyAsString("item-class", null); + if (itemClass != null) + { + if (!closePropTag) + { + e4x.append("\t\t\t<properties>\n"); + closePropTag = true; + } + + e4x.append("\t\t\t\t<item-class>"); + e4x.append(itemClass); + e4x.append("</item-class>\n"); + } + + // add in sub-set of network-related destination properties + ConfigMap network = dest.getProperties().getPropertyAsMap("network", null); + ConfigMap clusterInfo = null; + ConfigMap pagingInfo = null; + ConfigMap reconnectInfo = null; + if (network != null || defaultCluster != null) + { + if (!closePropTag) + { + e4x.append("\t\t\t<properties>\n"); + closePropTag = true; + } + e4x.append("\t\t\t\t<network>\n"); + + if (network != null) + pagingInfo = network.getPropertyAsMap("paging", null); + if (pagingInfo != null) + { + String enabled = pagingInfo.getPropertyAsString("enabled", "false"); + e4x.append("\t\t\t\t\t<paging enabled=\""); + e4x.append(enabled); + e4x.append("\""); + // Always put page size even if it is disabled as we can + // end up using this for nested properties with lazy="true". + // supporting pageSize for backwards compatibility but config options are not camelCase in general. + String size = pagingInfo.getPropertyAsString("page-size", pagingInfo.getPropertyAsString("pageSize", null)); + if (size != null) + { + e4x.append(" page-size=\""); + e4x.append(size); + e4x.append("\""); + + // Included so that newer compilers can work with older clients + e4x.append(" pageSize=\""); + e4x.append(size); + e4x.append("\""); + } + e4x.append("/>\n"); + } + + if (network != null) + reconnectInfo = network.getPropertyAsMap("reconnect", null); + if (reconnectInfo != null) + { + String fetchOption = reconnectInfo.getPropertyAsString("fetch", "IDENTITY"); + e4x.append("\t\t\t\t\t<reconnect fetch=\""); + e4x.append(fetchOption.toUpperCase()); + e4x.append("\" />\n"); + } + + if (network != null) + { + String reliable = network.getPropertyAsString("reliable", "false"); + if (Boolean.valueOf(reliable).booleanValue()) // No need the default value for the setting. + { + e4x.append("\t\t\t\t\t<reliable>"); + e4x.append(reliable); + e4x.append("</reliable>\n"); + } + } + + if (network != null) + clusterInfo = network.getPropertyAsMap("cluster", null); + if (clusterInfo != null) + { + String clusterId = clusterInfo.getPropertyAsString("ref", null); + + ClusterSettings clusterSettings = config.getClusterSettings(clusterId); + if (clusterSettings != null && + clusterSettings.getURLLoadBalancing()) + { + e4x.append("\t\t\t\t\t<cluster ref=\""); + e4x.append(clusterId); + e4x.append("\"/>\n"); + } + } + else if (defaultCluster != null) + { + e4x.append("\t\t\t\t\t<cluster"); + if (defaultCluster.getClusterName() != null) + { + e4x.append(" ref=\""); + e4x.append(defaultCluster.getClusterName()); + e4x.append("\""); + } + e4x.append("/>\n"); + } + e4x.append("\t\t\t\t</network>\n"); + } + + String useTransactions = dest.getProperties().getPropertyAsString("use-transactions", null); + + if (useTransactions !=null) + { + if (!closePropTag) + { + e4x.append("\t\t\t<properties>\n"); + closePropTag = true; + } + e4x.append("\t\t\t\t<use-transactions>" + useTransactions + "</use-transactions>\n"); + } + + String autoSyncEnabled = dest.getProperties().getPropertyAsString("auto-sync-enabled", "true"); + + if (autoSyncEnabled.equalsIgnoreCase("false")) + { + if (!closePropTag) + { + e4x.append("\t\t\t<properties>\n"); + closePropTag = true; + } + e4x.append("\t\t\t\t<auto-sync-enabled>false</auto-sync-enabled>\n"); + } + + if (closePropTag) + { + e4x.append("\t\t\t</properties>\n"); + } + + e4x.append("\t\t\t<channels>\n"); + for (Iterator chanIter = dest.getChannelSettings().iterator(); chanIter.hasNext();) + { + e4x.append("\t\t\t\t<channel ref=\"" + ((ChannelSettings) chanIter.next()).getId() + "\"/>\n"); + } + e4x.append("\t\t\t</channels>\n"); + e4x.append("\t\t</destination>\n"); + } + e4x.append("\t</service>\n"); + } + // channels + e4x.append("\t<channels>\n"); + String channelType; + for (Iterator chanIter = config.getAllChannelSettings().values().iterator(); chanIter.hasNext();) + { + ChannelSettings chan = (ChannelSettings) chanIter.next(); + if (chan.getServerOnly()) // Skip server-only channels. + continue; + channelType = chan.getClientType(); + serviceImportMap.put(channelType, channelType); + e4x.append("\t\t<channel id=\"" + chan.getId() + "\" type=\"" + channelType + "\">\n"); + StringBuffer channelProps = new StringBuffer(); + containsClientLoadBalancing = false; + channelProperties(chan.getProperties(), channelProps, "\t\t\t\t"); + if (!containsClientLoadBalancing) // Add the uri, only when there is no client-load-balancing defined. + e4x.append("\t\t\t<endpoint uri=\"" + chan.getClientParsedUri(contextRoot) + "\"/>\n"); + containsClientLoadBalancing = false; + e4x.append("\t\t\t<properties>\n"); + e4x.append(channelProps); + e4x.append("\t\t\t</properties>\n"); + e4x.append("\t\t</channel>\n"); + } + e4x.append("\t</channels>\n"); + FlexClientSettings flexClientSettings = (config instanceof ClientConfiguration) ? ((ClientConfiguration)config).getFlexClientSettings() : null; + if (flexClientSettings != null && flexClientSettings.getHeartbeatIntervalMillis() > 0) + { + e4x.append("\t<flex-client>\n"); + e4x.append("\t\t<heartbeat-interval-millis>"); + e4x.append(flexClientSettings.getHeartbeatIntervalMillis()); + e4x.append("</heartbeat-interval-millis>"); + e4x.append("\t</flex-client>\n"); + } + e4x.append("</services>"); + + StringBuffer advancedMessagingSupport = new StringBuffer(); + if (channelSetImplToImport != null) + { + serviceImportMap.put("ChannelSetImpl", channelSetImplToImport); + + // Codegen same class alias registration as is done by flex2.tools.Prelink#codegenRemoteClassAliases(Map<String,String>). + // This codegen isn't processed by PreLink. + String alias = "flex.messaging.messages.ReliabilityMessage"; + String className = "mx.messaging.messages.ReliabilityMessage"; + advancedMessagingSupport.append(" ServerConfig.channelSetFactory = AdvancedChannelSet;\n"); + advancedMessagingSupport.append(" try {\n"); + advancedMessagingSupport.append(" if (flash.net.getClassByAlias(\"" + alias + "\") == null){\n"); + advancedMessagingSupport.append(" flash.net.registerClassAlias(\"" + alias + "\", " + className + ");}\n"); + advancedMessagingSupport.append(" } catch (e:Error) {\n"); + advancedMessagingSupport.append(" flash.net.registerClassAlias(\"" + alias + "\", " + className + "); }\n"); + if (flexClientSettings != null && flexClientSettings.getReliableReconnectDurationMillis() > 0) + { + advancedMessagingSupport.append(" AdvancedChannelSet.reliableReconnectDuration ="); + advancedMessagingSupport.append(flexClientSettings.getReliableReconnectDurationMillis()); + advancedMessagingSupport.append(";\n"); + } + } + String generatedChunk = "\n ServerConfig.xml =\n" + e4x.toString() + ";\n" + advancedMessagingSupport.toString(); + + return generatedChunk; + } + + /** + * Process channel properties recursively. + */ + private void channelProperties(ConfigMap properties, StringBuffer buf, String indent) + { + for (Iterator nameIter = properties.propertyNames().iterator(); nameIter.hasNext();) + { + String name = (String)nameIter.next(); + Object value = properties.get(name); + if (value instanceof String) + { + addStringProperty(buf, indent, name, (String)value); + } + else if (value instanceof List) + { + List children = (List)value; + for (Iterator childrenIter = children.iterator(); childrenIter.hasNext();) + addStringProperty(buf, indent, name, (String)childrenIter.next()); + } + else if (value instanceof ConfigMap) + { + ConfigMap childProperties = (ConfigMap)value; + buf.append(indent); + buf.append("<" + name + ">\n"); + if (ConfigurationConstants.CLIENT_LOAD_BALANCING_ELEMENT.equals(name)) + containsClientLoadBalancing = true; + channelProperties(childProperties, buf, indent + "\t"); + buf.append(indent); + buf.append("</" + name + ">\n"); + } + } + } + + private void addStringProperty(StringBuffer buf, String indent, String name, String value) + { + if (!channel_excludes.contains(name)) + { + buf.append(indent); + buf.append("<" + name + ">" + value + "</" + name + ">\n"); + } + } + + /** + * Analyze code gen service associations. + * @param metadata the ConfigMap object + * @param e4x the buffer object + * @param destination the current destination + * @param relation the relationship + */ + public void codegenServiceAssociations(ConfigMap metadata, StringBuffer e4x, String destination, String relation) + { + List references = metadata.getPropertyAsList(relation, null); + if (references != null) + { + Iterator it = references.iterator(); + while (it.hasNext()) + { + Object ref = it.next(); + if (ref instanceof ConfigMap) + { + ConfigMap refMap = (ConfigMap) ref; + String name = refMap.getPropertyAsString("property", null); + String associatedDestination = refMap.getPropertyAsString("destination", null); + String lazy = refMap.getPropertyAsString("lazy", null); + String loadOnDemand = refMap.getPropertyAsString("load-on-demand", null); + String hierarchicalEvents = refMap.getPropertyAsString("hierarchical-events", null); + String pageSize = refMap.getPropertyAsString("page-size", refMap.getPropertyAsString("pageSize", null)); + String pagedUpdates = refMap.getPropertyAsString("paged-updates", null); + String cascade = refMap.getPropertyAsString("cascade", null); + String ordered = refMap.getPropertyAsString("ordered", null); + e4x.append("\t\t\t\t\t<"); + e4x.append(relation); + if (lazy != null) + { + e4x.append(" lazy=\""); + e4x.append(lazy); + e4x.append("\""); + + if (Boolean.valueOf(lazy.toLowerCase().trim()).booleanValue()) + { + addLazyAssociation(destination, name); + } + } + e4x.append(" property=\""); + e4x.append(name); + e4x.append("\" destination=\""); + e4x.append(associatedDestination); + e4x.append("\""); + String readOnly = refMap.getPropertyAsString("read-only", null); + if (readOnly != null && readOnly.equalsIgnoreCase("true")) + { + e4x.append(" read-only=\"true\""); + } + if (loadOnDemand != null && loadOnDemand.equalsIgnoreCase("true")) + e4x.append(" load-on-demand=\"true\""); + if (hierarchicalEvents != null && hierarchicalEvents.equalsIgnoreCase("true")) + e4x.append(" hierarchical-events=\"true\""); + if (pagedUpdates != null) + e4x.append(" paged-updates=\"" + pagedUpdates + "\""); + if (pageSize != null) + e4x.append(" page-size=\"" + pageSize + "\""); + if (cascade != null) + e4x.append(" cascade=\"" + cascade + "\""); + if (ordered != null) + e4x.append(" ordered=\"" + ordered + "\""); + e4x.append("/>\n"); + } + } + } + } + + /** + * This method will return an import and variable reference for channels specified in the map. + * @param map HashMap containing the client side channel type to be used, typically of the form + * "mx.messaging.channels.XXXXChannel", where the key and value are equal. + * @param imports StringBuffer of the imports needed for the given channel definitions + * @param references StringBuffer of the required references so that these classes will be linked in. + */ + public static void codegenServiceImportsAndReferences(Map map, StringBuffer imports, StringBuffer references) + { + String channelSetImplType = (String)map.remove("ChannelSetImpl"); + String type; + imports.append("import mx.messaging.config.ServerConfig;\n"); + references.append(" // static references for configured channels\n"); + for (Iterator chanIter = map.values().iterator(); chanIter.hasNext();) + { + type = (String)chanIter.next(); + imports.append("import "); + imports.append(type); + imports.append(";\n"); + references.append(" private static var "); + references.append(type.replace('.', '_')); + references.append("_ref:"); + references.append(type.substring(type.lastIndexOf(".") +1) +";\n"); + } + if (channelSetImplType != null) + imports.append("import mx.messaging.AdvancedChannelSet;\nimport mx.messaging.messages.ReliabilityMessage;\n"); + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/TargetSettings.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/TargetSettings.java b/common/src/main/java/flex/messaging/config/TargetSettings.java new file mode 100644 index 0000000..3bbbf4d --- /dev/null +++ b/common/src/main/java/flex/messaging/config/TargetSettings.java @@ -0,0 +1,78 @@ +/* + * 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.List; +import java.util.ArrayList; + +import flex.messaging.log.LogCategories; + +/** + * A logging target must specify the class name + * of the implementation, the level of logging events + * it will accept, a list of filters for logging + * categories it is interested in, and a collection of + * properties required to initialize the target. + * + * + */ +public class TargetSettings extends PropertiesSettings +{ + private String className; + private String level; + private List filters; + + public TargetSettings(String className) + { + this.className = className; + } + + public String getClassName() + { + return className; + } + + public String getLevel() + { + return level; + } + + public void setLevel(String level) + { + this.level = level; + } + + public List getFilters() + { + return filters; + } + + public void addFilter(String filter) + { + if (filters == null) + filters = new ArrayList(); + + // Replace DataService with Service.Data for backwards compatibility, + // excluding DataService.coldfusion. + if (filter.startsWith("DataService") && !filter.equals("DataService.coldfusion")) + filter = filter.replaceFirst("DataService", LogCategories.SERVICE_DATA); + + filters.add(filter); + } + + +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/TokenReplacer.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/TokenReplacer.java b/common/src/main/java/flex/messaging/config/TokenReplacer.java new file mode 100644 index 0000000..90c4fd0 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/TokenReplacer.java @@ -0,0 +1,202 @@ +/* + * 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.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +import flex.messaging.log.Log; +import flex.messaging.log.LogCategories; +import flex.messaging.util.StringUtils; + +/** + * This class is used by configuration parser to replace tokens of the format + * {...} with actual values. The value can either come from a JVM property + * (eg. -Dmy.channel.id=my-amf) or from a token properties file specified via + * token.file JVM property (eg. -Dtoken.file=/usr/local/tokens.properties) where + * the token key and value are specified in the property file. + * + * If a token value is both specified as a JVM property and inside the token.file, + * JVM property takes precedence. + * + * + */ +public class TokenReplacer +{ + private static final String TOKEN_FILE = "token.file"; + private static final Pattern pattern = Pattern.compile("\\{(.*?)\\}"); + + private final Map replacedTokens; + private Properties tokenProperties; + private String tokenPropertiesFilename; + + /** + * Default constructor. + */ + public TokenReplacer() + { + replacedTokens = new LinkedHashMap(); + loadTokenProperties(); + } + + /** + * Replace any tokens in the value of the node or the text child of the node. + * + * @param node The node whose value will be searched for tokens. + * @param sourceFileName The source file where the node came from. + */ + public void replaceToken(Node node, String sourceFileName) + { + // Exit if we are attempting to replace one of the forbidden nodes - nodes + // that may have curly brackets as part of their syntax + if (ConfigurationConstants.IP_ADDRESS_PATTERN.equals(node.getNodeName())) + return; + + // ReplacementNode is either the original node if it has a value or the text + // child of the node if it does not have a value + Node replacementNode; + if (node.getNodeValue() == null) + { + if (node.getChildNodes().getLength() == 1 && node.getFirstChild() instanceof Text) + replacementNode = node.getFirstChild(); + else + return; + } + else + { + replacementNode = node; + } + + String nodeValue = replacementNode.getNodeValue(); + Matcher matcher = pattern.matcher(nodeValue); + while (matcher.find()) // Means the node value has token(s) + { + String tokenWithCurlyBraces = matcher.group(); + String tokenWithoutCurlyBraces = matcher.group(1); + String propertyValue = getPropertyValue(tokenWithoutCurlyBraces); + if (propertyValue != null) + { + nodeValue = StringUtils.substitute(nodeValue, tokenWithCurlyBraces, propertyValue); + replacedTokens.put(tokenWithCurlyBraces, propertyValue); + } + // context-path, server-name and server-port tokens can be replaced + // later, therefore, no warning is necessary if they cannot be replaced + // at this point. + else if (!ConfigurationConstants.CONTEXT_PATH_TOKEN.equals(tokenWithCurlyBraces) + && !ConfigurationConstants.CONTEXT_PATH_ALT_TOKEN.equals(tokenWithCurlyBraces) + && !ConfigurationConstants.SERVER_NAME_TOKEN.equals(tokenWithCurlyBraces) + && !ConfigurationConstants.SERVER_PORT_TOKEN.equals(tokenWithCurlyBraces)) + { + // Token ''{0}'' in ''{1}'' was not replaced. Either supply a value to this token with a JVM option, or remove it from the configuration. + ConfigurationException ex = new ConfigurationException(); + Object[] args = {tokenWithCurlyBraces, sourceFileName}; + ex.setMessage(ConfigurationConstants.IRREPLACABLE_TOKEN, args); + throw ex; + } + } + replacementNode.setNodeValue(nodeValue); + } + + /** + * See if the token have a value either provided as a JVM property or as + * part of the token property file. JVM property takes precedence on the token + * property file. + */ + private String getPropertyValue(String tokenWithoutCurlyBraces) + { + String propertyValue = System.getProperty(tokenWithoutCurlyBraces); + if (propertyValue != null) + return propertyValue; + + if (tokenProperties != null) + propertyValue = tokenProperties.getProperty(tokenWithoutCurlyBraces); + + return propertyValue; + } + + /** + * Used by the parser to report the replaced tokens once logging is setup. + */ + public void reportTokens() + { + if (Log.isWarn()) + { + if (tokenProperties != null && Log.isDebug()) + Log.getLogger(LogCategories.CONFIGURATION).debug("Token replacer is using the token file '" + tokenPropertiesFilename + "'"); + + for (Iterator iter = replacedTokens.entrySet().iterator(); iter.hasNext();) + { + Map.Entry entry = (Map.Entry)iter.next(); + String tokenWithParanthesis = (String)entry.getKey(); + String propertyValue = (String)entry.getValue(); + // Issue a special warning for context.root replacements, + if (ConfigurationConstants.CONTEXT_PATH_TOKEN.equals(tokenWithParanthesis) + || ConfigurationConstants.CONTEXT_PATH_ALT_TOKEN.equals(tokenWithParanthesis)) + { + Log.getLogger(LogCategories.CONFIGURATION).warn("Token '{0}' was replaced with '{1}'. Note that this will apply to all applications on the JVM", + new Object[]{tokenWithParanthesis, propertyValue}); + } + else if (Log.isDebug()) + { + Log.getLogger(LogCategories.CONFIGURATION).debug("Token '{0}' was replaced with '{1}'", new Object[]{tokenWithParanthesis, propertyValue}); + } + } + } + } + + /** + * Given a String, determines whether the string contains tokens. + * + * @param value The String to check. + * @return True if the String contains tokens. + */ + public static boolean containsTokens(String value) + { + return (value != null && value.length() > 0)? pattern.matcher(value).find() : false; + } + + private void loadTokenProperties() + { + tokenPropertiesFilename = System.getProperty(TOKEN_FILE); + if (tokenPropertiesFilename == null) + return; + + tokenProperties = new Properties(); + try + { + tokenProperties.load(new FileInputStream(tokenPropertiesFilename)); + } + catch (FileNotFoundException e) + { + tokenProperties = null; + } + catch (IOException e) + { + tokenProperties = null; + } + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/config/XPathClientConfigurationParser.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/config/XPathClientConfigurationParser.java b/common/src/main/java/flex/messaging/config/XPathClientConfigurationParser.java new file mode 100644 index 0000000..2495754 --- /dev/null +++ b/common/src/main/java/flex/messaging/config/XPathClientConfigurationParser.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging.config; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +/** + * Uses Sun's JDK 1.5 XPath implementation on a DOM + * representation of a messaging configuration file. + * <p> + * NOTE: Since reference ids are used between elements, certain + * sections of the document need to be parsed first. + * </p> + * + * + */ +public class XPathClientConfigurationParser extends ClientConfigurationParser +{ + private XPath xpath; + + protected void initializeExpressionQuery() + { + this.xpath = XPathFactory.newInstance().newXPath(); + } + + protected Node selectSingleNode(Node source, String expression) + { + try + { + return (Node) xpath.evaluate(expression, source, XPathConstants.NODE); + } + catch (XPathExpressionException expressionException) + { + throw wrapException(expressionException); + } + } + + protected NodeList selectNodeList(Node source, String expression) + { + try + { + return (NodeList) xpath.evaluate(expression, source, XPathConstants.NODESET); + } + catch (XPathExpressionException expressionException) + { + throw wrapException(expressionException); + } + } + + protected Object evaluateExpression(Node source, String expression) + { + try + { + return xpath.evaluate(expression, source, XPathConstants.STRING); + } + catch (XPathExpressionException expressionException) + { + throw wrapException(expressionException); + } + } + + private ConfigurationException wrapException(XPathExpressionException exception) + { + ConfigurationException result = new ConfigurationException(); + result.setDetails(PARSER_INTERNAL_ERROR); + result.setRootCause(exception); + return result; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/AbstractTarget.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/AbstractTarget.java b/common/src/main/java/flex/messaging/log/AbstractTarget.java new file mode 100644 index 0000000..25e7040 --- /dev/null +++ b/common/src/main/java/flex/messaging/log/AbstractTarget.java @@ -0,0 +1,272 @@ +/* + * 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.log; + +import flex.messaging.LocalizedException; +import flex.messaging.config.ConfigMap; +import flex.messaging.util.UUIDUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * + */ +public abstract class AbstractTarget implements Target +{ + private static final int INVALID_FILTER_CHARS = 10016; + private static final int INVALID_FILTER_STAR = 10017; + + protected final String id; + protected List filters; + protected volatile short level; + protected volatile int loggerCount; + private final Object lock = new Object(); + private boolean usingDefaultFilter = false; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Default constructor. + */ + public AbstractTarget() + { + id = UUIDUtils.createUUID(); + level = LogEvent.ERROR; + filters = new ArrayList(); + filters.add("*"); + usingDefaultFilter = true; + } + + //-------------------------------------------------------------------------- + // + // Initialize, validate, start, and stop methods. + // + //-------------------------------------------------------------------------- + + /** + * Initializes the target with id and properties. Subclasses can overwrite. + * + * @param id id for the target which is ignored. + * @param properties ConfigMap of properties for the target. + */ + public void initialize(String id, ConfigMap properties) + { + // No-op + } + + //-------------------------------------------------------------------------- + // + // Public Getters and Setters for AbstractTarget properties + // + //-------------------------------------------------------------------------- + + /** + * Return a read-only snap-shot of the current filters for this target. + * + * @return An unmodifiable list of filters. + */ + public List getFilters() + { + return Collections.unmodifiableList(new ArrayList(filters)); + } + + /** + * Adds a filter to this target. + * + * @param value Filter to be added. + */ + public void addFilter(String value) + { + if (value != null) + validateFilter(value); + else // Default to "*" + value = "*"; + + boolean filterWasAdded = false; + synchronized (lock) + { + if (!filters.contains(value)) + { + // If the default filter is being used, remove it. + if (usingDefaultFilter) + { + removeFilter("*"); + usingDefaultFilter = false; + } + filters.add(value); + filterWasAdded = true; + } + } + if (filterWasAdded) + Log.processTargetFilterAdd(this, value); + } + + /** + * Removes a filter from this target. + * + * @param value Filter to be removed. + */ + public void removeFilter(String value) + { + boolean filterWasRemoved; + synchronized (lock) + { + filterWasRemoved = filters.remove(value); + } + if (filterWasRemoved) + Log.processTargetFilterRemove(this, value); + } + + /** + * Sets the list of filters for this target. + * + * @param value List of filters. + */ + public void setFilters(List value) + { + if (value != null && value.size() > 0) + { + // a valid filter value will be fully qualified or have a wildcard + // in it. the wild card can only be located at the end of the + // expression. valid examples xx*, xx.*, * + for (int i = 0; i < value.size(); i++) + { + validateFilter((String) value.get(i)); + } + } + else + { + // if null was specified then default to all + value = new ArrayList(); + value.add("*"); + } + + Log.removeTarget(this); + synchronized (lock) + { + filters = value; + usingDefaultFilter = false; + } + Log.addTarget(this); + } + + /** + * Return the log level for this target. + * + * @return the log level set for this target. + */ + public short getLevel() + { + return level; + } + + /** + * Return the target's unique ID. + * + * @return the target's unique ID. + */ + public String getId() + { + return id; + } + + /** + * Sets the log level for this target. If not set, defaults to <code>LogEvent.ERROR</code>. + */ + public void setLevel(short value) + { + level = value; + Log.resetTargetLevel(); + } + + /** + * Sets up this target with the specified logger. + * This allows this target to receive log events from the specified logger. + * + * @param logger this target should listen to. + */ + public void addLogger(Logger logger) + { + if (logger != null) + { + synchronized (lock) + { + loggerCount++; + } + logger.addTarget(this); + } + } + + /** + * Stops this target from receiving events from the specified logger. + * + * @param logger this target should ignore. + */ + public void removeLogger(Logger logger) + { + if (logger != null) + { + synchronized (lock) + { + loggerCount--; + } + logger.removeTarget(this); + } + } + + /** + * @param filter category to check against the filters defined for this target + * @return whether filter is defined + */ + public boolean containsFilter(String filter) + { + return filters.contains(filter); + } + + //-------------------------------------------------------------------------- + // + // Protected/private methods. + // + //-------------------------------------------------------------------------- + + private void validateFilter(String value) + { + // check for invalid characters + if (Log.hasIllegalCharacters(value)) + { + //Error for filter '{filter}'. The following characters are not valid: {Log.INVALID_CHARS} + LocalizedException ex = new LocalizedException(); + ex.setMessage(INVALID_FILTER_CHARS, new Object[]{value, Log.INVALID_CHARS}); + throw ex; + } + + int index = value.indexOf('*'); + if ((index >= 0) && (index != (value.length() - 1))) + { + //Error for filter '{filter}'. '*' must be the right most character. + LocalizedException ex = new LocalizedException(); + ex.setMessage(INVALID_FILTER_STAR, new Object[]{value}); + throw ex; + } + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/8315f8fa/common/src/main/java/flex/messaging/log/ConsoleTarget.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/flex/messaging/log/ConsoleTarget.java b/common/src/main/java/flex/messaging/log/ConsoleTarget.java new file mode 100644 index 0000000..b9faf76 --- /dev/null +++ b/common/src/main/java/flex/messaging/log/ConsoleTarget.java @@ -0,0 +1,42 @@ +/* + * 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.log; + +/** + * + */ +public class ConsoleTarget extends LineFormattedTarget +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Default constructor. + */ + public ConsoleTarget() + { + super(); + } + + protected void internalLog(String message) + { + System.out.println(message); + } +}