http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/Destination.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/Destination.java b/core/src/flex/messaging/Destination.java new file mode 100644 index 0000000..312e371 --- /dev/null +++ b/core/src/flex/messaging/Destination.java @@ -0,0 +1,802 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import flex.management.ManageableComponent; +import flex.management.runtime.messaging.services.ServiceControl; +import flex.messaging.log.LogCategories; +import flex.messaging.log.Log; +import flex.messaging.services.Service; +import flex.messaging.services.ServiceAdapter; +import flex.messaging.util.ClassUtil; +import flex.messaging.cluster.ClusterManager; +import flex.messaging.config.ClusterSettings; +import flex.messaging.config.ConfigMap; +import flex.messaging.config.ConfigurationConstants; +import flex.messaging.config.ConfigurationException; +import flex.messaging.config.NetworkSettings; +import flex.messaging.config.SecurityConstraint; +/** + * The <code>Destination</code> class is a source and sink for messages sent through + * a service destination and uses an adapter to process messages. + */ +public class Destination extends ManageableComponent implements java.io.Serializable +{ + static final long serialVersionUID = -977001797620881435L; + + /** Default log category for <code>Destination</code>. */ + public static final String LOG_CATEGORY = LogCategories.SERVICE_GENERAL; + + /** Hard coded id for the push destination */ + public static final String PUSH_DESTINATION_ID = "_DS_PUSH_"; + + // Errors + private static final int NO_SERVICE = 11117; + + // Destination's properties + protected ServiceAdapter adapter; + protected List<String> channelIds; + protected NetworkSettings networkSettings; + protected SecurityConstraint securityConstraint; + protected String securityConstraintRef; + protected HashMap<String, Object> extraProperties; + protected boolean initialized; + protected boolean clustered; + protected boolean clusteredCalculated; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructs an unmanaged <code>Destination</code> instance. + */ + public Destination() + { + this(false); + } + + /** + * Constructs a <code>Destination</code> with the indicated management. + * + * @param enableManagement <code>true</code> if the <code>Destination</code> + * is manageable; otherwise <code>false</code>. + */ + public Destination(boolean enableManagement) + { + super(enableManagement); + + networkSettings = new NetworkSettings(); + } + + //-------------------------------------------------------------------------- + // + // Initialize, validate, start, and stop methods. + // + //-------------------------------------------------------------------------- + + /** + * Initializes the <code>Destination</code> with the properties. + * If subclasses override, they must call <code>super.initialize()</code>. + * + * @param id The id of the destination. + * @param properties Properties for the destination. + */ + @Override + public void initialize(String id, ConfigMap properties) + { + super.initialize(id, properties); + + if (properties == null || properties.size() == 0) + { + initialized = true; + return; + } + + ConfigMap network = properties.getPropertyAsMap(NetworkSettings.NETWORK_ELEMENT, null); + + if (network != null) + { + networkSettings.setReliable(network.getPropertyAsBoolean(NetworkSettings.RELIABLE_ELEMENT, false)); + + ConfigMap clusterInfo = network.getPropertyAsMap(ClusterSettings.CLUSTER_ELEMENT, null); + if (clusterInfo != null) + { + // Mark these as used so we do not get warnings about them. + network.allowProperty(ClusterSettings.CLUSTER_ELEMENT); + clusterInfo.allowProperty(ClusterSettings.REF_ATTR); + clusterInfo.allowProperty(ClusterSettings.SHARED_BACKEND_ATTR); + + String clusterId = clusterInfo.getPropertyAsString(ClusterSettings.REF_ATTR, null); + String coordinatorPolicy = clusterInfo.getPropertyAsString(ClusterSettings.SHARED_BACKEND_ATTR, null); + if (coordinatorPolicy != null) + networkSettings.setSharedBackend(Boolean.valueOf(coordinatorPolicy)); + + networkSettings.setClusterId(clusterId); + } + } + + initialized = true; + } + + /** + * Returns whether or not the destination has been initialized. + * + * @return True, if the destination has been initialized. + */ + public boolean isInitialized() + { + return initialized; + } + + /** + * Verifies that the <code>Destination</code> is in valid state before + * it is started. If subclasses override, they must call <code>super.validate()</code>. + */ + @Override + protected void validate() + { + if (isValid()) + return; + + super.validate(); + + if (getAdapter() == null) + { + String defaultAdapterId = getService().getDefaultAdapter(); + if (defaultAdapterId != null) + { + createAdapter(defaultAdapterId); + } + else + { + invalidate(); + // Destination '{id}' must specify at least one adapter. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(ConfigurationConstants.DEST_NEEDS_ADAPTER, new Object[]{getId()}); + throw ex; + } + } + + if (channelIds != null) + { + List<String> brokerChannelIds = getService().getMessageBroker().getChannelIds(); + for (Iterator<String> iter = channelIds.iterator(); iter.hasNext();) + { + String id = iter.next(); + if (brokerChannelIds == null || !brokerChannelIds.contains(id)) + { + iter.remove(); + if (Log.isWarn()) + { + Log.getLogger(getLogCategory()).warn("No channel with id '{0}' is known by the MessageBroker." + + " Removing the channel.", + new Object[]{id}); + } + } + } + } + + // Set the default channels if needed + if (channelIds == null) + { + List<String> defaultChannelIds = getService().getDefaultChannels(); + if (defaultChannelIds != null && defaultChannelIds.size() > 0) + { + setChannels(defaultChannelIds); + } + else + { + invalidate(); + // Destination '{id}' must specify at least one channel. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(ConfigurationConstants.DEST_NEEDS_CHANNEL, new Object[]{getId()}); + throw ex; + } + } + + MessageBroker broker = getService().getMessageBroker(); + + // Validate the security constraint + if (securityConstraint == null && securityConstraintRef != null) + { + securityConstraint = broker.getSecurityConstraint(securityConstraintRef); + // No need to throw an error as MessageBroker automatically throws + // an error if no such constraint exists + } + + ClusterManager cm = broker.getClusterManager(); + + // Set clustering if needed + if (getNetworkSettings().getClusterId() != null || cm.getDefaultClusterId() != null) + { + cm.clusterDestination(this); + } + } + + /** + * Starts the destination if its associated <code>Service</code> is started + * and if the destination is not already running. The default implementation + * of this method starts the adapter of the destination. If subclasses + * override, they must call <code>super.start()</code>. + */ + @Override + public void start() + { + if (isStarted()) + { + // Needed for adapters added after startup. + getAdapter().start(); + return; + } + + // Check if the Service is started + Service service = getService(); + if (!service.isStarted()) + { + if (Log.isWarn()) + { + Log.getLogger(getLogCategory()).warn("Destination with id '{0}' cannot be started" + + " when its Service with id '{1}' is not started.", + new Object[]{getId(), service.getId()}); + } + return; + } + + // Set up management + if (isManaged() && service.isManaged()) + { + setupDestinationControl(service); + ServiceControl controller = (ServiceControl)service.getControl(); + if (getControl() != null) + controller.addDestination(getControl().getObjectName()); + } + + super.start(); + + getAdapter().start(); + } + + /** + * The default implementation of this method stops all of the adapters + * of the destination. + * If subclasses override, they must call <code>super.stop()</code>. + * + */ + @Override + public void stop() + { + if (!isStarted()) + return; + + getAdapter().stop(); + + super.stop(); + + // Remove management + if (isManaged() && getService().isManaged()) + { + if (getControl() != null) + { + getControl().unregister(); + setControl(null); + } + setManaged(false); + } + + } + + //-------------------------------------------------------------------------- + // + // Public Getters and Setters for Destination properties + // + //-------------------------------------------------------------------------- + + /** + * Returns the <code>ServiceAdapter</code> for the <code>Destination</code>. + * + * @return The <code>ServiceAdapter</code> for the <code>Destination</code>. + */ + public ServiceAdapter getAdapter() + { + return adapter; + } + + /** + * Creates a <code>ServiceAdapter</code> instance, sets its id, sets it manageable + * if the <code>Destination</code> that created it is manageable, + * and set its <code>Destination</code> to the <code>Destination</code> that + * created it. + * + * In order to use this method, <code>Destination</code> should have an assigned + * <code>Service</code> and the id provided for the adapter should already + * be registered with the <code>Service</code>. + * + * @param id The id of the <code>ServiceAdapter</code>. + * @return The <code>ServiceAdapter</code> instanced created. + */ + public ServiceAdapter createAdapter(String id) + { + if (getService() == null) + { + // Destination cannot create adapter '{0}' without its Service set. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(NO_SERVICE, new Object[]{id}); + throw ex; + } + Map<String, String> adapterClasses = getService().getRegisteredAdapters(); + if (!adapterClasses.containsKey(id)) + { + // No adapter with id '{0}' is registered with the service '{1}'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(ConfigurationConstants.UNREGISTERED_ADAPTER, new Object[]{id, getService().getId()}); + throw ex; + } + + String adapterClassName = adapterClasses.get(id); + Class<?> adapterClass = ClassUtil.createClass(adapterClassName, + FlexContext.getMessageBroker() == null ? + null : FlexContext.getMessageBroker().getClassLoader()); + + ServiceAdapter adapter = (ServiceAdapter)ClassUtil.createDefaultInstance(adapterClass, ServiceAdapter.class); + adapter.setId(id); + adapter.setManaged(isManaged()); + adapter.setDestination(this); + + return adapter; + } + + /** + * Sets the <code>ServiceAdapter</code> of the <code>Destination</code>. + * + * <code>ServiceAdapter</code> needs to be started if the <code>Destination</code> + * is already running. + * + * @param adapter The adapter for the destination. + */ + public void setAdapter(ServiceAdapter adapter) + { + if (getAdapter() == adapter) // No need to reset the adapter. + return; + + if (adapter == null) + { + removeAdapter(); + return; + } + + addAdapter(adapter); + } + + /** + * Used by setAdapter and it removes the old adapter of the destination + * and adds the new adapter. + * + * @param adapter The adapter for the destination. + */ + private void addAdapter(ServiceAdapter adapter) + { + removeAdapter(); + + this.adapter = adapter; + + if (adapter.getDestination() == null || adapter.getDestination() != this) + adapter.setDestination(this); + } + + /** + * Used by setAdapter and addAdapter. It removes the current adapter + * of the destination + */ + private void removeAdapter() + { + ServiceAdapter adapter = getAdapter(); + if (adapter != null) + { + adapter.stop(); + } + this.adapter = null; + } + + + /** + * The destination may be not clustered at all, may be clustered for channel failover and + * destination sharing, or it may be clustered for channel failover and also have a + * common backend, such as a common database or backend clustered JMS topic. + * If the destination is clustered and has a common backend to coordinate the cluster, + * this method returns true; otherwise it return false. Note that this method returns + * <code>false</code> if the <code>Destination</code> is not runnning. + * + * @return <code>true</code> if the clustered <code>Destination</code> shares a common backend; + * otherwise <code>false</code>. + */ + public boolean isBackendShared() + { + if (!isStarted()) + return false; + + ClusterManager clm = getService().getMessageBroker().getClusterManager(); + return clm.isBackendShared(getService().getClass().getName(), getId()); + } + + /** + * Returns the list of channel ids of the <code>Destination</code>. + * + * @return The list of channel ids of the <code>Destination</code>. + */ + public List<String> getChannels() + { + return channelIds; + } + + /** + * Adds a channel to the list of channels known by the <code>Destination</code>. + * <code>MessageBroker</code> has to know the channel. Otherwise, the channel + * is not added to the list. + * + * @param id The id of the channel. + */ + public void addChannel(String id) + { + if (channelIds == null) + channelIds = new ArrayList<String>(); + else if (channelIds.contains(id)) + return; + + if (isStarted()) + { + List<String> brokerChannelIds = getService().getMessageBroker().getChannelIds(); + if (brokerChannelIds == null || !brokerChannelIds.contains(id)) + { + if (Log.isWarn()) + { + Log.getLogger(getLogCategory()).warn("No channel with id '{0}' is known by the MessageBroker." + + " Not adding the channel.", + new Object[]{id}); + } + return; + } + } + // Either message broker knows about the channel, or destination is not + // running and channel will be checked before startup during validate + channelIds.add(id); + } + + /** + * Removes the channel from the list of channels for the <code>Destination</code>. + * + * @param id The id of the channel. + * @return <code>true</code> if the list contained the channel id. + */ + public boolean removeChannel(String id) + { + return channelIds != null && channelIds.remove(id); + } + + /** + * Sets the channel list of the <code>Destination</code>. + * <code>MessageBroker</code> has to know the channels, otherwise they + * are not added to the list. + * + * @param ids List of channel ids. + */ + public void setChannels(List<String> ids) + { + if (ids != null && isStarted()) + { + List<String> brokerChannelIds = getService().getMessageBroker().getChannelIds(); + for (Iterator<String> iter = ids.iterator(); iter.hasNext();) + { + String id = iter.next(); + if (brokerChannelIds == null || !brokerChannelIds.contains(id)) + { + iter.remove(); + if (Log.isWarn()) + { + Log.getLogger(getLogCategory()).warn("No channel with id '{0}' is known by the MessageBroker." + + " Not adding the channel.", + new Object[]{id}); + } + } + } + } + // Otherwise, channels will be checked before startup during validate + channelIds = ids; + } + + /** + * The destination may be not clustered at all, may be clustered for channel failover + * only, or it may be clustered for channel failover and also have shared back ends. + * If the destination is clustered, regardless of whether or not it relies on a shared + * back end for cluster configuration, this method returns true. Note that this method + * returns <code>false</code> if the <code>Destination</code> is not runnning. + * + * @return <code>true</code> if the <code>Destination</code> is clustered; otherwise <code>false</code>. + */ + public boolean isClustered() + { + if (!isStarted()) + return false; + + if (!clusteredCalculated) + { + ClusterManager clm = getService().getMessageBroker().getClusterManager(); + clustered = clm.isDestinationClustered(getService().getClass().getName(), getId()); + clusteredCalculated = true; + } + return clustered; + } + + /** + * Sets the id of the <code>Destination</code>. If the <code>Destination</code> + * has a <code>Service</code> assigned, it also updates the id in the + * <code>Service</code>. + * + * @param id The id of the <code>Destination</code>. + */ + @Override + public void setId(String id) + { + String oldId = getId(); + + super.setId(id); + + // Update the destination id in the service and MessageBroker + Service service = getService(); + if (service != null) + { + service.removeDestination(oldId); + service.addDestination(this); + } + } + + /** + * Get the <code>NetworkSettings</code> of the <code>Destination</code>. + * + * @return The <code>NetworkSettings</code> of the <code>Destination</code>. + */ + public NetworkSettings getNetworkSettings() + { + return networkSettings; + } + + /** + * Set the <code>NetworkSettings</code> of the <code>Destination</code>. + * + * @param networkSettings The <code>NetworkSettings</code> of the <code>Destination</code>. + */ + public void setNetworkSettings(NetworkSettings networkSettings) + { + this.networkSettings = networkSettings; + } + + /** + * Returns the <code>Service</code> managing this <code>Destination</code>. + * + * @return The <code>Service</code> managing this <code>Destination</code>. + */ + public Service getService() + { + return (Service)getParent(); + } + + /** + * Sets the <code>Service</code> managing this <code>Destination</code>. + * Removes the <code>Destination</code> from the old service + * (if there was one) and adds to the list of destination in the new service. + * + * @param service The <code>Service</code> managing this <code>Destination</code>. + */ + public void setService(Service service) + { + Service oldService = getService(); + + setParent(service); + + if (oldService != null) + oldService.removeDestination(getId()); + + // Add the destination to the service if needed + if (service.getDestination(getId()) != this) + service.addDestination(this); + } + + /** + * Returns the Java class name for the <code>Service</code> managing this + * <code>Destination</code>. Returns null if there is no <code>Service</code> + * assigned to the <code>Destination</code> yet. + * + * @return The Java class name for the <code>Service</code> manageing this <code>Destination</code>. + */ + public String getServiceType() + { + Service service = getService(); + return service != null? service.getClass().getName() : null; + } + + /** + * Returns the <code>SecurityConstraint</code> of the <code>Destination</code>. + * <code>SecurityConstraint</code> is constructed as the <code>Destination</code> + * starts up. Therefore, this could return null even if the <code>SecurityConstraint</code> + * reference is set but <code>Destination</code> is not started yet. + * + * @return The <code>SecurityConstraint</code> of the <code>Destination</code>. + */ + public SecurityConstraint getSecurityConstraint() + { + return securityConstraint; + } + + /** + * Sets the <code>SecurityConstraint</code> of the <code>Destination</code>. + * + * @param securityConstraint The <code>SecurityConstraint</code> of the <code>Destination</code>. + */ + public void setSecurityConstraint(SecurityConstraint securityConstraint) + { + this.securityConstraint = securityConstraint; + } + + /** + * Sets the <code>SecurityConstraint</code> reference of the <code>Destination</code>. + * <code>MessageBroker</code> has to know the <code>SecurityConstraint</code> + * reference. Note that <code>getSecurityConstraint</code> can return null + * if the reference is set but the <code>Destination</code> is not started yet. + * + * @param ref <code>SecurityConstraint</code> reference. + */ + public void setSecurityConstraint(String ref) + { + if (isStarted()) + { + MessageBroker msgBroker = getService().getMessageBroker(); + securityConstraint = msgBroker.getSecurityConstraint(ref); + // No need to throw an error as MessageBroker automatically throws + // an error if no such constraint exists + } + securityConstraintRef = ref; + } + + //-------------------------------------------------------------------------- + // + // Other public APIs + // + //-------------------------------------------------------------------------- + + /** + * Calls {@link Destination#describeDestination(boolean)} with true boolean value. + * + * @return A <tt>ConfigMap</tt> of destination properties that the client needs. + * @see flex.messaging.Destination#describeDestination(boolean) + */ + public ConfigMap describeDestination() + { + return describeDestination(true); + } + + /** + * Returns a <tt>ConfigMap</tt> of destination properties that the client + * needs. Subclasses can add additional properties to <tt>super.describeDestination(boolean)</tt>, + * or return null if they don't want their properties to be sent to the client. + * + * @param onlyReliable Determines whether only reliable destination configuration should be returned. + * @return A <tt>ConfigMap</tt> of destination properties that the client needs. + */ + public ConfigMap describeDestination(boolean onlyReliable) + { + boolean reliable = networkSettings != null && networkSettings.isReliable(); + if (onlyReliable && !reliable) + return null; + + ConfigMap destinationConfig = new ConfigMap(); + destinationConfig.addProperty(ConfigurationConstants.ID_ATTR, getId()); + + // Include network settings if reliability for the destination is enabled. + if (reliable) + { + ConfigMap properties = new ConfigMap(); + ConfigMap network = new ConfigMap(); + + ConfigMap reliableMap = new ConfigMap(); + // Adding as a value rather than attribute to the parent + reliableMap.addProperty(ConfigurationConstants.EMPTY_STRING, Boolean.toString(networkSettings.isReliable())); + + network.addProperty(NetworkSettings.RELIABLE_ELEMENT, reliableMap); + properties.addProperty(NetworkSettings.NETWORK_ELEMENT, network); + + destinationConfig.addProperty(ConfigurationConstants.PROPERTIES_ELEMENT, properties); + } + + ConfigMap channelsConfig = new ConfigMap(); + for (String id : channelIds) + { + ConfigMap channelConfig = new ConfigMap(); + channelConfig.addProperty(ConfigurationConstants.REF_ATTR, id); + channelsConfig.addProperty(ConfigurationConstants.CHANNEL_ELEMENT, channelConfig); + } + + if (channelsConfig.size() > 0) + destinationConfig.addProperty(ConfigurationConstants.CHANNELS_ELEMENT, channelsConfig); + + return destinationConfig; + } + + /** + * Method for setting an extra property for the destination at runtime. + * + * @param name The name of the property. + * @param value The value of the property. + */ + public void addExtraProperty(String name, Object value) + { + if (extraProperties == null) + { + extraProperties = new HashMap<String, Object>(); + } + + extraProperties.put(name, value); + } + + /** + * Method for getting an extra property at runtime. + * + * @param name The name of the property. + * @return The value of the property or null if the property does not exist. + */ + public Object getExtraProperty(String name) + { + return extraProperties != null? extraProperties.get(name) : null; + } + + //-------------------------------------------------------------------------- + // + // Protected/private APIs + // + //-------------------------------------------------------------------------- + + /** + * Returns the log category of the <code>Destination</code>. Subclasses + * can override to provide a more specific log category. + * + * @return The log category. + */ + @Override + protected String getLogCategory() + { + return LOG_CATEGORY; + } + + /** + * Invoked automatically to allow the <code>Destination</code> to setup its corresponding + * MBean control. Subclasses should override to setup and register their MBean control. + * + * @param service The <code>Service</code> that manages this <code>Destination</code>. + */ + protected void setupDestinationControl(Service service) + { + // Manageable subclasses should override this template method. + setManaged(false); + } +}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/DestructibleFlexFactory.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/DestructibleFlexFactory.java b/core/src/flex/messaging/DestructibleFlexFactory.java new file mode 100644 index 0000000..d9c6a1e --- /dev/null +++ b/core/src/flex/messaging/DestructibleFlexFactory.java @@ -0,0 +1,34 @@ +/* + * 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; + +/** + * Implementors of <code>FlexFactory</code> should also implement this interface + * if their factory has custom destruction behavior. + */ +public interface DestructibleFlexFactory +{ + /** + * This method is called when a component that uses this factory is removed. + * This method gives the factory a chance to clean up resources that may have + * been allocated for the component and may now be ready for destruction. + * + * @param instanceInfo The FactoryInstance to be destroyed + * + */ + void destroyFactoryInstance(FactoryInstance instanceInfo); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FactoryDestination.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FactoryDestination.java b/core/src/flex/messaging/FactoryDestination.java new file mode 100644 index 0000000..2857e3c --- /dev/null +++ b/core/src/flex/messaging/FactoryDestination.java @@ -0,0 +1,361 @@ +/* + * 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; + +import flex.messaging.config.ConfigMap; +import flex.messaging.config.ConfigurationException; +import flex.messaging.log.Log; + +public abstract class FactoryDestination extends Destination +{ + private static final String FACTORY = "factory"; + private static final String DEFAULT_FACTORY = "java"; + + // Errors + private static int INVALID_FACTORY = 11103; + private static int FACTORY_CANNOT_BE_RETURNED = 11118; + + // FactoryDestination's properties + private FlexFactory factory; + private String source; + private String scope = FlexFactory.SCOPE_REQUEST; + + // FactoryDestination internal + private String factoryId = DEFAULT_FACTORY; + private FactoryInstance factoryInstance; + private ConfigMap factoryProperties; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructs an unmanaged <code>FactoryDestination</code> instance. + */ + public FactoryDestination() + { + this(false); + } + + /** + * Constructs a <code>FactoryDestination</code> with the indicated management. + * + * @param enableManagement <code>true</code> if the <code>FactoryDestination</code> + * is manageable; otherwise <code>false</code>. + */ + public FactoryDestination(boolean enableManagement) + { + super(enableManagement); + } + + //-------------------------------------------------------------------------- + // + // Initialize, validate, start, and stop methods. + // + //-------------------------------------------------------------------------- + + /** + * Initializes the <code>FactoryDestination</code> with the properties. + * @param id the factory id + * @param properties Properties for the <code>FactoryDestination</code>. + */ + public void initialize(String id, ConfigMap properties) + { + super.initialize(id, properties); + + if (properties == null || properties.size() == 0) + return; + + // Need to cache this for later. TODO: We shouldn't need to do this. + factoryProperties = properties; + + factoryId = properties.getPropertyAsString(FACTORY, factoryId); + scope = properties.getPropertyAsString(FlexFactory.SCOPE, scope); + source = properties.getPropertyAsString(FlexFactory.SOURCE, source); + + if (source == null) + source = getId(); + + if (factory != null) + factory.initialize(getId(), factoryProperties); + } + + /** + * Verifies that the <code>FactoryDestination</code> is in valid state before + * it is started. + */ + protected void validate() + { + if (isValid()) + return; + + super.validate(); + + if (factory == null) + { + if (factoryId == null) + { + factoryId = DEFAULT_FACTORY; + } + MessageBroker broker = getService().getMessageBroker(); + FlexFactory f = broker.getFactory(factoryId); + if (f == null) + { + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_FACTORY, new Object[] {getId(), factoryId}); + throw ex; + } + factory = f; + } + + if (scope == null) + scope = FlexFactory.SCOPE_REQUEST; + + if (source == null) + source = getId(); + } + + //-------------------------------------------------------------------------- + // + // Public Getters and Setters for Destination properties + // + //-------------------------------------------------------------------------- + + /** + * Returns the factory of the <code>FactoryDestination</code>. Before a valid + * <code>FlexFactory</code> can be returned, <code>MessageBroker</code> and + * hence <code>Service</code> of the <code>Destination</code> has to be set. + * @return FlexFactory the FlexFactory object + */ + public FlexFactory getFactory() + { + if (factory == null) + { + if (factoryId == null) + { + factoryId = DEFAULT_FACTORY; + } + if (getService() == null) + { + // Factory cannot be returned without ''{0}'' set. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(FACTORY_CANNOT_BE_RETURNED, new Object[] {"Service"}); + throw ex; + } + if (getService().getMessageBroker() == null) + { + // Factory cannot be returned without ''{0}'' set. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(FACTORY_CANNOT_BE_RETURNED, new Object[] {"MessageBroker"}); + throw ex; + } + MessageBroker broker = getService().getMessageBroker(); + FlexFactory f = broker.getFactory(factoryId); + if (f == null) + { + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_FACTORY, new Object[] {getId(), factoryId}); + throw ex; + } + factory = f; + } + return factory; + } + + /** + * Sets the factory of the <code>FactoryDestination</code>. + * <code>MessageBroker</code> has to know the factory before it can be + * assigned to the destination. + * + * @param id The id of the factory. + */ + public void setFactory(String id) + { + if (isStarted()) + { + MessageBroker broker = getService().getMessageBroker(); + FlexFactory factory = broker.getFactory(id); + if (factory == null) + { + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_FACTORY, new Object[] {getId(), factory}); + throw ex; + } + setFactory(factory); + } + factoryId = id; + } + + /** + * Sets the factory of the <code>FactoryDestination</code>. + * + * @param factory the FlexFactory object + */ + public void setFactory(FlexFactory factory) + { + this.factory = factory; + } + + /** + * Returns the <code>FactoryInstance</code>. <code>FactoryInstance</code> + * stores configuration state used for retrieving an instance from + * the factory. This needs to be called after calling <code>setSource</code> + * and <code>setScope</code> methods. + * @return FactoryInstance current FactoryInstance object + */ + public FactoryInstance getFactoryInstance() + { + // This is needed for HibernateAssembler + return getFactoryInstance(factoryProperties); + } + + /** + * Returns a <code>FactoryInstance</code> using the properties passed in. + * + * @param properties Properties to be used while creating the <code>FactoryInstance</code>. + */ + private FactoryInstance getFactoryInstance(ConfigMap properties) + { + // Automatically create a factory instance if not already set + if (factoryInstance == null) + factoryInstance = createFactoryInstance(properties); + + return factoryInstance; + } + + /** + * Creates a factory instance using the properties passed in. + * + * @param properties Properties to be used while creating the <code>FactoryInstance</code>. + */ + private FactoryInstance createFactoryInstance(ConfigMap properties) + { + if (properties == null) + properties = new ConfigMap(); + + properties.put(FlexFactory.SOURCE, source); + properties.put(FlexFactory.SCOPE, scope); + FactoryInstance factoryInstance = getFactory().createFactoryInstance(getId(), properties); + return factoryInstance; + } + + /** + * Returns the scope of the <code>FactoryDestination</code>. + * + * @return scope of the <code>FactoryDestination</code>. + */ + public String getScope() + { + return scope; + } + + /** + * Sets the scope of the <code>FactoryDestination</code> that is used + * in <code>FactoryInstance</code> creation. Scope cannot be changed to and + * from application scope once <code>FactoryInstance</code> is initialized. + * + * @param scope the scope + */ + public void setScope(String scope) + { + if (factoryInstance != null) + { + if (FlexFactory.SCOPE_APPLICATION.equals(this.scope) + && !FlexFactory.SCOPE_APPLICATION.equals(scope)) + { + if (Log.isWarn()) + Log.getLogger(getLogCategory()).warn( + "Current scope is "+FlexFactory.SCOPE_APPLICATION + +" and it cannot be changed to "+scope + +" once factory instance is initialized."); + return; + } + else if (!FlexFactory.SCOPE_APPLICATION.equals(this.scope) + && FlexFactory.SCOPE_APPLICATION.equals(scope)) + { + if (Log.isWarn()) + Log.getLogger(getLogCategory()).warn( + "Current scope is "+this.scope + +" and it cannot be changed to "+FlexFactory.SCOPE_APPLICATION + +" once factory instance is initialized."); + return; + } + factoryInstance.setScope(scope); + } + this.scope = scope; + } + + /** + * Gets the source of the <code>FactoryDestination</code>. + * + * @return the source of the <code>FactoryDestination</code>. + */ + public String getSource() + { + return source; + } + + /** + * Sets the source of the <code>FactoryDestination</code> that is used + * in <code>FactoryInstance</code> creation. Source cannot be changed once + * <code>FactoryInstance</code> is initialized and the scope is application. + * + * @param source the source string + */ + public void setSource(String source) + { + if (factoryInstance != null) + { + if (FlexFactory.SCOPE_APPLICATION.equals(scope)) + { + if (Log.isWarn()) + Log.getLogger(getLogCategory()).warn( + "Source of the destination cannot be changed once " + + "factory instance is already initialized and it has " + + FlexFactory.SCOPE_APPLICATION +" scope"); + return; + } + factoryInstance.setSource(source); + } + this.source = source; + } + + /** + * This method first calls stop on its superclass <code>Destination</code> and then + * removes any assemblers from the ServletContext or Session that are ready for removal. + * If an assembler is only used by a single destination (attribute-id==destination-id) then + * it is removed. If an assembler is shared across destinations, (attribute-id<>destination-id) + * then it is only removed if its reference count (maintained in <code>MessageBroker</code>) is + * down to zero + */ + public void stop() + { + if (isStarted()) + { + super.stop(); + // destroy factory instance to free up resources + if (factory != null && (factory instanceof DestructibleFlexFactory)) + ((DestructibleFlexFactory)factory).destroyFactoryInstance(factoryInstance); + } + else + { + super.stop(); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FactoryInstance.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FactoryInstance.java b/core/src/flex/messaging/FactoryInstance.java new file mode 100644 index 0000000..e39faed --- /dev/null +++ b/core/src/flex/messaging/FactoryInstance.java @@ -0,0 +1,181 @@ +/* + * 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; + +import flex.messaging.config.ConfigMap; +import flex.messaging.config.ConfigurationException; + +/** + * This class is used by the FlexFactory to store the configuration + * for an instance created by the factory. There is one of these for + * each destination currently since only destinations create these components. + * + * @see flex.messaging.FlexFactory + */ +public class FactoryInstance +{ + private static final int INVALID_SCOPE = 10653; + + private FlexFactory factory; + private String id; + private String scope = FlexFactory.SCOPE_REQUEST; + private String source; + private ConfigMap properties; + + /** + * Normally FactoryInstances are constructed by Data Services during startup so you + * do not need to use this method. It is typically called from the + * FlexFactory.createFactoryInstance method as Data Services is parsing + * the destination configuration information for a given destination. + * You can override this method to extract additional configuration for + * your component from the properties argument. + * + * @param factory the FlexFactory this FactoryInstance is created from + * @param id the Destination's id + * @param properties the configuration properties for this destination. + * + * @see flex.messaging.config.ConfigMap + */ + public FactoryInstance(FlexFactory factory, String id, ConfigMap properties) + { + this.factory = factory; + this.id = id; + this.properties = properties; + } + + /** + * Get the factory instance ID. + * @return The destination's id that this FactoryInstance is associated with. + */ + public String getId() + { + return id; + } + + /** + * Since many factories may provide components in different + * scopes, this is abstracted in the base factory instance class. + * @param scope the scope + */ + public void setScope(String scope) + { + this.scope = scope; + + if (!FlexFactory.SCOPE_SESSION.equals(scope) + && !FlexFactory.SCOPE_APPLICATION.equals(scope) + && !FlexFactory.SCOPE_REQUEST.equals(scope)) + { + // Invalid scope setting for RemotingService destination '{id}'. + // Valid options are 'request', 'session', or 'application'. + ConfigurationException ex = new ConfigurationException(); + ex.setMessage(INVALID_SCOPE, new Object[] {id, "\'request\', \'session\', or \'application\'"}); + throw ex; + } + + } + + /** + * Get the scope. + * @return String the scope + */ + public String getScope() + { + return scope; + } + + /** + * This is by convention the main property for the defining the + * instance we create with this factory. It may be the class name + * for the JavaFactory or the id for a factory that uses ids. + * + * @param source source + */ + public void setSource(String source) + { + this.source = source; + } + + /** + * Get the source. + * @return String the source string + */ + public String getSource() + { + return source; + } + + /** + * If possible, returns the class for the underlying configuration. + * This method can return null if the class is not known until the lookup + * method is called. The goal is so the factories which know the class + * at startup time can provide earlier error detection. If the class is not + * known, this method can return null and validation will wait until the + * first lookup call. + * + * @return the class for this configured instance or null if the class + * is not known until lookup time. + */ + public Class getInstanceClass() + { + return null; + } + + /** + * Returns the ConfigMap that this factory instance was created with. You can + * use this ConfigMap to retrieve additional properties which this factory + * instance is configured with. For example, if you are defining a remote object + * destination, your FactoryInstance can be configured with additional XML tags + * underneath the properties tag for your destination. It is important that + * if you expect additional properties that you access in the ConfigMap or call + * allowProperty on that property when the FactoryInstance is created. Otherwise, + * these properties can generate warnings about "unexpected" configuration. + * @return ConfigMap the ConfigMap that this factory was created with + * @see flex.messaging.config.ConfigMap + */ + public ConfigMap getProperties() + { + return properties; + } + + /** + * Return an instance as appropriate for this instance of the given + * factory. This just calls the lookup method on the factory that this + * instance was created on. You override this method to return the + * specific component for this destination. + * @return Object the object lookup + */ + public Object lookup() + { + return factory.lookup(this); + } + + /** + * When the caller is done with the instance, this method is called. For + * session scoped components, this gives you the opportunity to update + * any state modified in the instance in a remote persistence store. + * This method is not called when the object should be destroyed. + * To get a destroy notification, you should register for the appropriate + * events via the FlexContext. + * + * @param instance the instance returned via the lookup method for this + * destination for this operation. + */ + public void operationComplete(Object instance) + { + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexComponent.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FlexComponent.java b/core/src/flex/messaging/FlexComponent.java new file mode 100644 index 0000000..8f76444 --- /dev/null +++ b/core/src/flex/messaging/FlexComponent.java @@ -0,0 +1,48 @@ +/* + * 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; + +/** + * Defines the lifecycle interface for FlexComponents, allowing + * the server to manage the running state of server components + * through a consistent interface. + */ +public interface FlexComponent extends FlexConfigurable +{ + /** + * Invoked to start the component. + * The {@link FlexConfigurable#initialize(String, flex.messaging.config.ConfigMap)} method inherited + * from the {@link FlexConfigurable} interface must be invoked before this method is invoked. + * Once this method returns, {@link #isStarted()} must return true. + */ + void start(); + + /** + * Invoked to stop the component. + * Once this method returns, {@link #isStarted()} must return false. + */ + void stop(); + + /** + * Indicates whether the component is started and running. + * + * @return <code>true</code> if the component has started; + * otherwise <code>false</code>. + */ + boolean isStarted(); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexConfigurable.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FlexConfigurable.java b/core/src/flex/messaging/FlexConfigurable.java new file mode 100644 index 0000000..402d3c3 --- /dev/null +++ b/core/src/flex/messaging/FlexConfigurable.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package flex.messaging; + +import flex.messaging.config.ConfigMap; + +/** + * Components created in the Flex configuration environment can implement + * the FlexConfigurable interface to get access to the configuration + * properties like a regular component in the system. + */ +public interface FlexConfigurable +{ + /** + * Initializes the component with configuration information. + * + * @param id The id of the component. + * @param configMap The properties for configuring component. + */ + void initialize(String id, ConfigMap configMap); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexContext.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FlexContext.java b/core/src/flex/messaging/FlexContext.java new file mode 100644 index 0000000..79e4b96 --- /dev/null +++ b/core/src/flex/messaging/FlexContext.java @@ -0,0 +1,497 @@ +/* + * 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; + +import flex.messaging.client.FlexClient; +import flex.messaging.endpoints.Endpoint; +import flex.messaging.io.TypeMarshallingContext; +import flex.messaging.security.LoginManager; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.security.Principal; + +/** + * The <tt>FlexContext</tt> is a utility class that exposes the current execution context. + * It provides access to <tt>FlexSession</tt> and <tt>FlexClient</tt> instances associated + * with the current message being processed, as well as global context via the <tt>MessageBroker</tt>, + * <tt>ServletContext</tt> and <tt>ServletConfig</tt> for the application. + * Any, or all, of the properties exposed by this class may be <code>null</code> depending upon + * the current execution context so test for that before attempting to interact with them. + */ +public class FlexContext +{ + private static ThreadLocal<FlexClient> flexClients = new ThreadLocal<FlexClient>(); + private static ThreadLocal<FlexSession> sessions = new ThreadLocal<FlexSession>(); + private static ThreadLocal<MessageBroker> messageBrokers = new ThreadLocal<MessageBroker>(); + private static ThreadLocal<Endpoint> endpoints = new ThreadLocal<Endpoint>(); + private static ThreadLocal<HttpServletResponse> responses = new ThreadLocal<HttpServletResponse>(); + private static ThreadLocal<HttpServletRequest> requests = new ThreadLocal<HttpServletRequest>(); + private static ThreadLocal<HttpServletRequest> tunnelRequests = new ThreadLocal<HttpServletRequest>(); + private static ThreadLocal<ServletConfig> servletConfigs = new ThreadLocal<ServletConfig>(); + private static ThreadLocal<Boolean> messageFromPeer = new ThreadLocal<Boolean>(); + private static ThreadLocal<MessageRoutedNotifier> messageRoutedNotifiers = new ThreadLocal<MessageRoutedNotifier>(); + private static ServletConfig lastGoodServletConfig; + + private FlexContext() + { + } + + /** + * Users should not call this. + * + * @param flexClient the Flex client + * @param session the Flex session + * @param broker the message broker + * @param request the http servlet request + * @param response the http servlet response + * @param servletConfig the servlet config + */ + public static void setThreadLocalObjects(FlexClient flexClient, + FlexSession session, + MessageBroker broker, + HttpServletRequest request, + HttpServletResponse response, + ServletConfig servletConfig) + { + if (flexClients == null) // In case releaseThreadLocalObjects has been called. + return; + + flexClients.set(flexClient); + sessions.set(session); + messageBrokers.set(broker); + requests.set(request); + responses.set(response); + setThreadLocalServletConfig(servletConfig); + messageFromPeer.set(Boolean.FALSE); + } + + /** + * Users should not call this. + * + * @param flexClient the Flex client + * @param session the Flex session + * @param broker the message broker + */ + public static void setThreadLocalObjects(FlexClient flexClient, FlexSession session, MessageBroker broker) + { + setThreadLocalObjects(flexClient, session, broker, null, null, null); + } + + /** + * Users should not call this. + * + */ + public static void clearThreadLocalObjects() + { + if (flexClients == null) // In case releaseThreadLocalObjects has been called. + return; + + flexClients.remove(); + sessions.remove(); + messageBrokers.remove(); + endpoints.remove(); + requests.remove(); + responses.remove(); + tunnelRequests.remove(); + servletConfigs.remove(); + messageFromPeer.remove(); + messageRoutedNotifiers.remove(); + + TypeMarshallingContext.clearThreadLocalObjects(); + } + + /** + * The HttpServletResponse for the current request if the request is via HTTP. + * Returns null if the client is using a non-HTTP channel. + * Available for users. + * + * @return HttpServletRequest current HttpServletRequest object + */ + public static HttpServletRequest getHttpRequest() + { + return requests != null? requests.get() : null; + } + + /** + * Users should not call this. + * + * @param value HttpServletRequest object + */ + public static void setThreadLocalHttpRequest(HttpServletRequest value) + { + if (requests == null) + return; + + if (value == null) + requests.remove(); + else + requests.set(value); + } + + /** + * The HttpServletResponse for the current request if the request is via HTTP. + * Returns null if the using an non-HTTP channel. + * Available for users. + * + * @return HttpServletResponse current HttpServletResponse object + */ + public static HttpServletResponse getHttpResponse() + { + return responses != null? responses.get() : null; + } + + /** + * Users should not call this. + * + * @param value HttpServletResponse object + */ + public static void setThreadLocalHttpResponse(HttpServletResponse value) + { + if (responses == null) + return; + + if (value == null) + responses.remove(); + else + responses.set(value); + } + + /** + * The HttpServletRequest for the current request if it is transporting a tunneled protocol. + * Returns null if the current request protocol it not tunneled. + * Available for users. + * + * @return HttpServletRequest tunnel HttpServletRequest object + */ + public static HttpServletRequest getTunnelHttpRequest() + { + return tunnelRequests != null? tunnelRequests.get() : null; + } + + /** + * Users should not call this. + * + * @param value HttpServletRequest object + */ + public static void setThreadLocalTunnelHttpRequest(HttpServletRequest value) + { + if (tunnelRequests == null) + return; + + if (value == null) + tunnelRequests.remove(); + else + tunnelRequests.set(value); + } + + /** + * The ServletConfig for the current request, uses the last known ServletConfig + * when the request is not via HTTP. Available for users. + * + * @return ServletConfig current ServletConfig object + */ + public static ServletConfig getServletConfig() + { + if (servletConfigs != null && servletConfigs.get() != null) + { + return servletConfigs.get(); + } + return lastGoodServletConfig; + } + + /** + * Users should not call this. + * + * @param value ServletConfig object + */ + public static void setThreadLocalServletConfig(ServletConfig value) + { + if (servletConfigs == null) + return; + + if (value == null) + { + servletConfigs.remove(); + } + else + { + servletConfigs.set(value); + lastGoodServletConfig = value; + } + } + + /** + * The ServletContext for the current web application. + * + * @return ServletContext current ServletContext object + */ + public static ServletContext getServletContext() + { + return getServletConfig() != null? getServletConfig().getServletContext() : null; + } + + /** + * The FlexClient for the current request. Available for users. + * + * @return FlexClient the current FlexClient object + */ + public static FlexClient getFlexClient() + { + return flexClients != null? flexClients.get() : null; + } + + /** + * Users should not call this. + * + * @param flexClient FlexClient object + */ + public static void setThreadLocalFlexClient(FlexClient flexClient) + { + if (flexClients == null) + return; + + if (flexClient == null) + flexClients.remove(); + else + flexClients.set(flexClient); + } + + /** + * The FlexSession for the current request. Available for users. + * + * @return FlexSession the current FlexSession object + */ + public static FlexSession getFlexSession() + { + return sessions != null? sessions.get() : null; + } + + /** + * Users should not call this. + * + * @param session FlexSession object + */ + public static void setThreadLocalSession(FlexSession session) + { + if (sessions == null) + return; + + if (session == null) + sessions.remove(); + else + sessions.set(session); + } + + /** + * The MessageBroker for the current request. Not available for users. + * + * @return The MessageBroker for the current request + */ + public static MessageBroker getMessageBroker() + { + return messageBrokers != null? messageBrokers.get() : null; + } + + /** + * Users should not call this. + * + * @param value MessageBroker object + */ + public static void setThreadLocalMessageBroker(MessageBroker value) + { + // This is a special case because MessageBroker is sometimes accessed by + // services, destinations, adapters during shutdown so it needs to be set + // on the context even if a previous MessageBrokerServlet#destroy called + // releaseThreadLocalObjects. + if (messageBrokers == null) + messageBrokers = new ThreadLocal<MessageBroker>(); + + if (value == null) + messageBrokers.remove(); + else + messageBrokers.set(value); + } + + /** + * The Endpoint for the current message. Not available for users. + * + * @return The Endpoint for the current message + */ + public static Endpoint getEndpoint() + { + return endpoints != null? endpoints.get() : null; + } + + /** + * Users should not call this. + * + * @param value Endpoint object + */ + public static void setThreadLocalEndpoint(Endpoint value) + { + if (endpoints == null) + return; + + if (value == null) + endpoints.remove(); + else + endpoints.set(value); + } + + /** + * Users should not call this. + * + * @return MessageRoutedNotifier object + */ + public static MessageRoutedNotifier getMessageRoutedNotifier() + { + return messageRoutedNotifiers != null? messageRoutedNotifiers.get() : null; + } + + /** + * Users should not call this. + * + * @param value MessageRoutedNotifier object + */ + public static void setMessageRoutedNotifier(MessageRoutedNotifier value) + { + if (messageRoutedNotifiers == null) + return; + + if (value == null) + messageRoutedNotifiers.remove(); + else + messageRoutedNotifiers.set(value); + } + + /** + * Indicates whether the current message being processed came from a server peer + * in a cluster. + * + * @return true if message from a peer + */ + public static boolean isMessageFromPeer() + { + return messageFromPeer != null? messageFromPeer.get() : false; + } + + /** + * Sets a thread local indicating whether the message being processed came from + * a server peer in a cluster. + * + * @param value True if the message came from a peer; otherwise false. + */ + public static void setMessageFromPeer(boolean value) + { + if (messageFromPeer == null) + return; + + messageFromPeer.set(value); + } + + /** + * Users should not call this. + * + * @return true if per-client-authentication is turned on. + */ + public static boolean isPerClientAuthentication() + { + MessageBroker messageBroker = getMessageBroker(); + if (messageBroker == null) + return false; + + LoginManager loginManager = messageBroker.getLoginManager(); + return loginManager == null? false : loginManager.isPerClientAuthentication(); + } + + /** + * Returns the principal associated with the session or client depending on whether + * perClientauthentication is being used. If the client has not + * authenticated the principal will be null. + * + * @return The principal associated with the session. + */ + public static Principal getUserPrincipal() + { + if (isPerClientAuthentication()) + { + FlexClient client = getFlexClient(); + return client != null? client.getUserPrincipal() : null; + } + + FlexSession session = getFlexSession(); + return session != null? session.getUserPrincipal() : null; + } + + /** + * Sets the Principal on either the current FlexClient or FlexSession depending upon whether + * perClientAuthentication is in use. + * + * @param userPrincipal The principal to associate with the FlexClient or FlexSession + * depending upon whether perClientAuthentication is in use. + */ + public static void setUserPrincipal(Principal userPrincipal) + { + if (isPerClientAuthentication()) + getFlexClient().setUserPrincipal(userPrincipal); + else + getFlexSession().setUserPrincipal(userPrincipal); + } + + /** + * Create the static thread local storage. + */ + public static void createThreadLocalObjects() + { + if (flexClients == null) // Allocate if needed. + { + flexClients = new ThreadLocal<FlexClient>(); + sessions = new ThreadLocal<FlexSession>(); + messageBrokers = new ThreadLocal<MessageBroker>(); + endpoints = new ThreadLocal<Endpoint>(); + responses = new ThreadLocal<HttpServletResponse>(); + requests = new ThreadLocal<HttpServletRequest>(); + tunnelRequests = new ThreadLocal<HttpServletRequest>(); + servletConfigs = new ThreadLocal<ServletConfig>(); + messageFromPeer = new ThreadLocal<Boolean>(); + messageRoutedNotifiers = new ThreadLocal<MessageRoutedNotifier>(); + } + } + + /** + * Destroy the static thread local storage. + * Call ONLY on shutdown + */ + public static void releaseThreadLocalObjects() + { + clearThreadLocalObjects(); + + flexClients = null; + sessions = null; + messageBrokers = null; + endpoints = null; + responses = null; + requests = null; + tunnelRequests = null; + servletConfigs = null; + messageFromPeer = null; + messageRoutedNotifiers = null; + } +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexFactory.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FlexFactory.java b/core/src/flex/messaging/FlexFactory.java new file mode 100644 index 0000000..18cacf3 --- /dev/null +++ b/core/src/flex/messaging/FlexFactory.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; + +import flex.messaging.config.ConfigMap; + +/** + * The FlexFactory interface is implemented by factory components that provide + * instances to the Flex messaging framework. You can implement this interface + * if you want to tie together Flex Data Services with another system which maintains + * component instances (often called the "services layer" in a typical enterprise + * architecture). By implementing FlexFactory, you can configure a Flex + * RemoteObject destination or a Flex Data Management Services assembler which + * uses a Java object instance in your services layer rather than having Data Services + * create a new component instance. In some cases, this means you avoid writing + * glue code for each service you want to expose to flex clients. + */ +public interface FlexFactory extends FlexConfigurable +{ + /** Request scope string. */ + String SCOPE_REQUEST = "request"; + /** Session scope string. */ + String SCOPE_SESSION = "session"; + /** Application scope string .*/ + String SCOPE_APPLICATION = "application"; + /** Scope string. */ + String SCOPE = "scope"; + /** Source string. */ + String SOURCE = "source"; + + /** + * Called when the + * definition of an instance that this factory looks up is initialized. + * It should validate that + * the properties supplied are valid to define an instance + * and returns an instance of the type FactoryInstance + * that contains all configuration necessary to construct + * an instance of this object. If the instance is application + * scoped, the FactoryInstance may contain a reference to the + * instance directly. + * + * Any valid properties used for this configuration + * must be accessed to avoid warnings about unused configuration + * elements. If your factory is only used for application + * scoped components, you do not need to implement + * this method as the lookup method itself can be used + * to validate its configuration. + * + * The id property is used as a name to help you identify + * this factory instance for any errors it might generate. + * + * @param id id of the factory + * @param properties properties + * @return a new FactoryInstance instance + */ + FactoryInstance createFactoryInstance(String id, ConfigMap properties); + + /** + * This method is called by the default implementation of FactoryInstance.lookup. + * When Data Services wants an instance of a given factory destination, it calls the + * FactoryInstance.lookup to retrieve that instance. That method in turn + * calls this method by default. + * + * For simple FlexFactory implementations which do not need to + * add additional configuration properties or logic to the FactoryInstance class, + * by implementing this method you can avoid having to add an additional subclass of + * FactoryInstance for your factory. If you do extend FactoryInstance, it is + * recommended that you just override FactoryInstance.lookup and put your logic + * there to avoid the extra level of indirection. + * + * @param instanceInfo The FactoryInstance for this destination + * @return the Object instance to use for the given operation for this destination. + */ + Object lookup(FactoryInstance instanceInfo); +} http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexRemoteCredentials.java ---------------------------------------------------------------------- diff --git a/core/src/flex/messaging/FlexRemoteCredentials.java b/core/src/flex/messaging/FlexRemoteCredentials.java new file mode 100644 index 0000000..99a927b --- /dev/null +++ b/core/src/flex/messaging/FlexRemoteCredentials.java @@ -0,0 +1,93 @@ +/* + * 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; + +/** + * A wrapper object used for holding onto remote credentials. When you are using + * the proxy service, the remote credentials are used for authenticating against + * the proxy server. The remote credentials are distinct from the local credentials + * used to authenticate against the local server. You use this class along with + * the FlexSession methods getRemoteCredentials and putRemoteCredentials to associate + * the remote credentials with a specific destination. + */ +public class FlexRemoteCredentials +{ + private String service; + + private String destination; + + private String username; + + private Object credentials; + + /** + * Normally you do not have to create the FlexRemoteCredentials as they are + * created automatically when the client specifies them via the setRemoteCredentials + * method in ActionScript. You'd use this if you wanted to set your remote credentials + * on the server and not have them specified on the client. + * @param service the service id + * @param destination the destination id + * @param username the user name + * @param credentials the user credentials + */ + public FlexRemoteCredentials(String service, String destination, + String username, Object credentials) + { + super(); + this.service = service; + this.destination = destination; + this.username = username; + this.credentials = credentials; + } + + /** + * Returns the user name from the remote credentials. + * @return String the user name + */ + public String getUsername() + { + return username; + } + + /** + * Returns the credentials themselves (usually a password). + * @return Object the credentials object + */ + public Object getCredentials() + { + return credentials; + } + + /** + * Returns the id of the service these credentials are registered for. + * @return String the service id + */ + public String getService() + { + return service; + } + + /** + * Returns the destination for the service. + * @return String the destination id + */ + public String getDestination() + { + return destination; + } +}
