/*
 * Delivered to the U.S. Government in Accordance with Contract FA8650-10-C-7080.
 *
 * EXPORT CONTROLLED
 * ECCN#   EAR99
 * Warning: This document contains technical data which is controlled under the
 * Bureau of Industry & Security's Export Administration Regulations and may not be
 * exported or re-exported without authorization by the Bureau of Industry & Security.
 * Diversion contrary to US law is prohibited.
 *
 * (c) 2011 United Technologies Corp.
 * Developed with the sponsorship of the Defense Advanced Research Projects Agency (DARPA).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this data,
 * including any software or models in source or binary form, as well as any drawings, 
 * specifications, and documentation (collectively "the Data"), to deal in the Data without 
 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Data, and to permit persons to whom the Data
 * is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Data.
 *
 * THE DATA IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, SPONSORS, DEVELOPERS, CONTRIBUTORS, OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE DATA OR THE
 * USE OR OTHER DEALINGS IN THE DATA.
*/

package proxy.clients;

import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;

import meta.rmi.Service;
import meta.rmi.ServiceResponse;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.output.XMLOutputter;

import proxy.ProxyElement;

import exception.ControllerException;

/**
 * A proxy that runs an SOA object
 */
public abstract class SOAProxy {
	
	public abstract Service getService() 
		throws MalformedURLException, RemoteException, NotBoundException;
	
	/**
	 * Execute an operation on a SOA object
	 * @param name        The name of the operation to perform
	 * @param attributes  Input elements for the service request
	 * @return            The response from the SOA object
	 * @throws ControllerException if any error is detected
	 */
	public ServiceResponse run(String name, List<ProxyElement> attributes)
		throws ControllerException {

		try {
			String  request          = createServiceRequest(name, attributes);
			Service service          = getService();
	  	String  xml              = service.invoke(request);
	  	ServiceResponse response = new ServiceResponse(xml);

			// Check if the service worked
			if (response.getStatus() != 0)
				throw new ControllerException(response.getStatus(),
						    		String.format("For service response \"%s\": %s", name,
						    				          response.getStatusMsg()));
	  	return response;
	  	
		} catch (MalformedURLException malex) {
			throw new ControllerException("Bad URL detected for \"%s\" command: %s",
					                           name, malex.getMessage());
			
		} catch (RemoteException remex) {
			throw new ControllerException("Error detected for \"%s\" command: %s",
          name, remex.getMessage());
			
		} catch (NotBoundException nbex) {
			throw new ControllerException("Service not bound for \"%s\" command: %s",
          name, nbex.getMessage());
			
		} catch (JDOMException jdomex) {
			throw new ControllerException("Invalid response detected for \"%s\" command: %s",
          name, jdomex.getMessage());
	
		} catch (IOException ioex) {
			throw new ControllerException("Error reading response detected for \"%s\" command: %s",
          name, ioex.getMessage());
		}
	}
	
	/**
	 * Create the service request
	 * @param name        The name of the operation to perform
	 * @param attributes  Input elements for the service request
	 * @return            The request as a string
	 * @throws ControllerException if any error is detected
	 */
	private String createServiceRequest(String name, List<ProxyElement> attributes) 
		throws ControllerException {

		Element request = new Element("service-request");
		request.setAttribute("name", name);
		
		Element args = new Element("service-arguments");
		request.addContent(args);
		
		for (ProxyElement pa : attributes) {
			args.addContent(pa.getElement());
		}
		
		Document doc = new Document();
		doc.setContent(request);
		
  	XMLOutputter xmlout = new XMLOutputter();
  	return xmlout.outputString(doc); 
	}
}
