1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.core.BasicClass;
    18  import org.as2lib.env.except.IllegalArgumentException;
    19  import org.as2lib.data.holder.Map;
    20  import org.as2lib.data.holder.map.PrimitiveTypeMap;
    21  import org.as2lib.io.conn.core.server.Server;
    22  import org.as2lib.io.conn.core.server.ServerServiceProxy;
    23  import org.as2lib.io.conn.core.server.ServerRegistry;
    24  import org.as2lib.io.conn.local.server.LocalServerServiceProxy;
    25  import org.as2lib.io.conn.local.LocalConfig;
    26  
    27  /**
    28   * {@code LocalServer} acts as a composite for many services that are all combined
    29   * in one domain.
    30   * 
    31   * <p>Example:
    32   * <code>
    33   *   var server:LocalServer = new LocalServer("local.as2lib.org");
    34   *   server.putService("myServiceOne", new MyServiceOne());
    35   *   server.putService("myServiceTwo", new MyServiceTwo());
    36   *   server.run();
    37   * </code>
    38   *
    39   * @author Simon Wacker
    40   * @author Christoph Atteneder
    41   */
    42  class org.as2lib.io.conn.local.server.LocalServer extends BasicClass implements Server {
    43  	
    44  	/** Name of this server. */
    45  	private var host:String;
    46  	
    47  	/** All services. */
    48  	private var services:Map;
    49  	
    50  	/** Server status. */
    51  	private var running:Boolean;
    52  	
    53  	/** Stores the server registry. */
    54  	private var serverRegistry:ServerRegistry;
    55  	
    56  	/**
    57  	 * Constructs a new {@code LocalServer} instance.
    58  	 *
    59  	 * @param host the name of this server
    60  	 * @throws IllegalArgumentException if the passed-in {@code host} is {@code null},
    61  	 * {@code undefined} or an empty string
    62  	 */
    63  	public function LocalServer(host:String) {
    64  		if (!host) throw new IllegalArgumentException("Argument 'host' must not be null, undefined or a blank string.", this, arguments);
    65  		this.host = host;
    66  		services = new PrimitiveTypeMap();
    67  		running = false;
    68  	}
    69  	
    70  	/**
    71  	 * Returns the currently used server registry.
    72  	 *
    73  	 * <p>This is either the server registry set via {@link #setServerRegistry} or the
    74  	 * default registry returned by the {@link LocalConfig#getServerRegistry} method.
    75  	 * 
    76  	 * @return the currently used server registry
    77  	 */
    78  	public function getServerRegistry(Void):ServerRegistry {
    79  		if (!serverRegistry) serverRegistry = LocalConfig.getServerRegistry();
    80  		return serverRegistry;
    81  	}
    82  	
    83  	/**
    84  	 * Sets a new server registry.
    85  	 *
    86  	 * <p>If {@code serverRegistry} is {@code null} or {@code undefined} the
    87  	 * {@link #getServerRegistry} method will return the default server registry.
    88  	 * 
    89  	 * @param serverRegistry the new server registry
    90  	 */
    91  	public function setServerRegistry(serverRegistry:ServerRegistry):Void {
    92  		this.serverRegistry = serverRegistry;
    93  	}
    94  	
    95  	/**
    96  	 * Runs this server.
    97  	 *
    98  	 * <p>This involves registering itself at the server registry and running all added
    99  	 * services with this host.
   100  	 * 
   101  	 * <p>If this server is already running a restart will be made. This means it will
   102  	 * be stopped and run again.
   103  	 */
   104  	public function run(Void):Void {
   105  		if (isRunning()) this.stop();
   106  		getServerRegistry().registerServer(getHost());
   107  		if (services.size() > 0) {
   108  			var serviceArray:Array = services.getValues();
   109  			for (var i:Number = 0; i < serviceArray.length; i++) {
   110  				ServerServiceProxy(serviceArray[i]).run(host);
   111  			}
   112  		}
   113  		running = true;
   114  	}
   115  	
   116  	/**
   117  	 * Stops this server.
   118  	 * 
   119  	 * <p>This involves stopping all services and removing itself from the server registry.
   120  	 */
   121  	public function stop(Void):Void {
   122  		if (services.size() > 0) {
   123  			var serviceArray:Array = services.getValues();
   124  			for (var i:Number = 0; i < serviceArray.length; i++) {
   125  				ServerServiceProxy(serviceArray[i]).stop();
   126  			}
   127  		}
   128  		if (getServerRegistry().containsServer(getHost())) {
   129  			getServerRegistry().removeServer(getHost());
   130  		}
   131  		running = false;
   132  	}
   133  	
   134  	/**
   135  	 * Puts the passed-in {@code service} to the passed-in {@code path} on this server.
   136  	 * 
   137  	 * <p>{@code service} and {@code path} are wrapped in a {@link ServerServiceProxy}
   138  	 * instance.
   139  	 *
   140  	 * @param path that path to the service on the host
   141  	 * @param service the service to make locally available
   142  	 * @return the newly created server service proxy that wraps {@code service} and 
   143  	 * {@code path}
   144  	 * @throws IllegalArgumentException if the passed-in {@code path} is {@code null}, 
   145  	 * {@code undefined} or an empty string or if the passed-in {@code service} is
   146  	 * {@code null} or {@code undefined}
   147  	 * @see #addService
   148  	 */
   149  	public function putService(path:String, service):ServerServiceProxy {
   150  		// source out instantiation
   151  		var proxy:ServerServiceProxy = new LocalServerServiceProxy(path, service);
   152  		addService(proxy);
   153  		return proxy;
   154  	}
   155  	
   156  	/**
   157  	 * Adds the passed-in {@code serviceProxy} to this service.
   158  	 *
   159  	 * <p>If this server is running, the {@code serviceProxy} will be run immediately
   160  	 * too.
   161  	 * 
   162  	 * @param serviceProxy the proxy that wraps the actual service
   163  	 * @throws IllegalArgumentException if the passed-in {@code serviceProxy} is
   164  	 * {@code null} or {@code undefined} or if the path of the passed-in {@code serviceProxy}
   165  	 * is {@code null}, {@code undefined} or an empty string or if the path of the passed-in
   166  	 * {@code serviceProxy} is already in use
   167  	 * @see #putService
   168  	 */
   169  	public function addService(serviceProxy:ServerServiceProxy):Void {
   170  		if (!serviceProxy) throw new IllegalArgumentException("Service proxy must not be null or undefined.", this, arguments);
   171  		var path:String = serviceProxy.getPath();
   172  		if (!path) throw new IllegalArgumentException("Service proxy's path must not be null, undefined or a blank string.", this, arguments);
   173  		if (services.containsKey(path)) throw new IllegalArgumentException("Service proxy with proxy path [" + path + "] is already in use.", this, arguments);
   174  		services.put(path, serviceProxy);
   175  		if (isRunning()) {
   176  			serviceProxy.run(host);
   177  		}
   178  	}
   179  	
   180  	/**
   181  	 * Removes the service registered wiht the passed-in {@code path}.
   182  	 * 
   183  	 * <p>If the service is running it will be stopped.
   184  	 *
   185  	 * <p>{@code null} will be returned if:
   186  	 * <ul>
   187  	 *   <li>The passed-in {@code path} is {@code null} or an empty string.</li>
   188  	 *   <li>There is no registered service with the passed-in {@code path}.</li>
   189  	 * </ul>
   190  	 *
   191  	 * @param path the path of the service to remove
   192  	 * @return the removed server service proxy wrapping the actual service
   193  	 */
   194  	public function removeService(path:String):ServerServiceProxy {
   195  		if (!path) return null;
   196  		var service:ServerServiceProxy = services.remove(path);
   197  		if (service.isRunning()) service.stop();
   198  		return service;
   199  	}
   200  	
   201  	/**
   202  	 * Returns the service registered with the passed-in {@code path}.
   203  	 * 
   204  	 * <p>{@code null} will be returned if:
   205  	 * <ul>
   206  	 *   <li>The passed-in {@code path} is {@code null} or an empty string.</li>
   207  	 *   <li>There is no service registered with the passed-in {@code path}.</li>
   208  	 * </ul>
   209  	 *
   210  	 * @param path the path of the service to return
   211  	 * @return the server service proxy wrapping the actual service
   212  	 */
   213  	public function getService(path:String):ServerServiceProxy {
   214  		if (!path) return null;
   215  		return services.get(path);
   216  	}
   217  	
   218  	/**
   219  	 * Returns whether this server is running.
   220  	 *
   221  	 * <p>This server is by default not running. It runs as soon as you call the
   222  	 * {@link #run} method. And stops when you call the {@ink #stop} method.
   223  	 * 
   224  	 * @return {@code true} if this server is running else {@code false}
   225  	 */
   226  	public function isRunning(Void):Boolean {
   227  		return running;
   228  	}
   229  	
   230  	/**
   231  	 * Returns the host of this server.
   232  	 *
   233  	 * @return this host of this server
   234  	 */
   235  	public function getHost(Void):String {
   236  		return host;
   237  	}
   238  	
   239  }