Index: fedd/fedd_create.py
===================================================================
--- fedd/fedd_create.py	(revision 987aaa19f783a2ad4457bbda88eb60f32245e021)
+++ fedd/fedd_create.py	(revision 45ebc4d93e220aff2f18e6f5e5dee6bf5fdc85db)
@@ -145,25 +145,130 @@
 		type="string", help="output certificate file")
 
+# Base class that will do a the SOAP/XMLRPC exchange for a request.
+class fedd_rpc:
+    class RPCException:
+	def __init__(self, fb):
+	    self.desc = fb.get('desc', None)
+	    self.code = fb.get('code', None)
+	    self.errstr = fb.get('errstr', None)
+
+    def __init__(self, pre): 
+	"""
+	Specialize the class for the prc method
+	"""
+	self.RequestMessage = globals()["%sRequestMessage" % pre]
+	self.ResponseMessage = globals()["%sResponseMessage" % pre]
+	self.RequestBody="%sRequestBody" % pre
+	self.ResponseBody="%sResponseBody" % pre
+	self.method = pre
+	self.RPCException = fedd_rpc.RPCException
+
+    def do_rpc(self, req_dict, url, transport, cert, trusted, tracefile=None,
+	    serialize_only=False):
+	"""
+	The work of sending and parsing the RPC as either XMLRPC or SOAP
+	"""
+
+	context = None
+	while context == None:
+	    try:
+		context = fedd_ssl_context(cert, trusted)
+	    except SSL.SSLError, e:
+		# Yes, doing this on message type is not ideal.  The string
+		# comes from OpenSSL, so check there is this stops working.
+		if str(e) == "bad decrypt": 
+		    print >>sys.stderr, "Bad Passphrase given."
+		else: raise
+
+	if transport == "soap":
+	    loc = feddServiceLocator();
+	    port = loc.getfeddPortType(url,
+		    transport=M2Crypto.httpslib.HTTPSConnection, 
+		    transdict={ 'ssl_context' : context },
+		    tracefile=tracefile)
+
+	    req = self.RequestMessage()
+
+	    set_req = getattr(req, "set_element_%s" % self.RequestBody, None)
+	    set_req(pack_soap(req, self.RequestBody, req_dict))
+
+	    if serialize_only:
+		sw = SoapWriter()
+		sw.serialize(req)
+		print str(sw)
+		sys.exit(0)
+
+	    try:
+		method_call = getattr(port, self.method, None)
+		resp = method_call(req)
+	    except ZSI.ParseException, e:
+		raise RuntimeError("Malformed response (XMLPRC?): %s" % e)
+	    except ZSI.FaultException, e:
+		resp = e.fault.detail[0]
+
+	    if resp:
+		resp_call = getattr(resp, "get_element_%s" %self.ResponseBody,
+			None)
+		if resp_call: 
+		    resp_body = resp_call()
+		    if ( resp_body != None): 
+			try:
+			    return unpack_soap(resp_body)
+			except RuntimeError, e:
+			    raise RuntimeError("Bad response. %s" % e.message)
+		elif 'get_element_FeddFaultBody' in dir(resp): 
+		    resp_body = resp.get_element_FeddFaultBody()
+		    if resp_body != None: 
+			try:
+			    fb = unpack_soap(resp_body)
+			except RuntimeError, e:
+			    raise RuntimeError("Bad response. %s" % e.message)
+			raise self.RPCException(fb)
+		else: 
+		    raise RuntimeError("No body in response!?")
+	    else: 
+		raise RuntimeError("No response?!?")
+	elif transport == "xmlrpc":
+	    if serialize_only:
+		ser = dumps((req_dict,))
+		print ser
+		sys.exit(0)
+
+	    xtransport = SSL_Transport(context)
+	    port = ServerProxy(url, transport=xtransport)
+
+	    try:
+		method_call = getattr(port, self.method, None)
+		resp = method_call(
+			encapsulate_binaries({ self.RequestBody: msg},\
+			    ('fedid',)))
+	    except Error, e:
+		resp = { 'FeddFaultBody': \
+			{ 'errstr' : e.faultCode, 'desc' : e.faultString } }
+	    if resp:
+		if resp.has_key(self.ResponseBody): 
+		    return resp[self.ResponseBody]
+		elif resp.has_key('FeddFaultBody'):
+		    raise self.RPCException(resp['FeddFaultBody'])
+		else: 
+		    raise RuntimeError("No body in response!?")
+	    else: 
+		raise RuntimeError("No response?!?")
+	else:
+	    raise RuntimeError("Unknown RPC transport: %s" % transport)
+
 # Querying experiment data follows the same control flow regardless of the
 # specific data retrieved.  This class encapsulates that control flow.
-class exp_data:
+class exp_data(fedd_rpc):
     def __init__(self, op): 
 	"""
 	Specialize the class for the type of data requested (op)
 	"""
-	if op =='vtopo':
-	    self.RequestMessage = VtopoRequestMessage;
-	    self.ResponseMessage = VtopoResponseMessage;
-	    self.RequestBody="VtopoRequestBody"
-	    self.ResponseBody="VtopoResponseBody"
-	    self.method = "Vtopo"
+
+	fedd_rpc.__init__(self, op)
+	if op =='Vtopo':
 	    self.key="vtopo"
 	    self.xml='experiment'
-	elif op == 'vis':
-	    self.RequestMessage = VisRequestMessage;
-	    self.ResponseMessage = VisResponseMessage;
-	    self.RequestBody="VisRequestBody"
-	    self.ResponseBody="VisResponseBody"
-	    self.method = "Vis"
+	elif op == 'Vis':
 	    self.key="vis"
 	    self.xml='vis'
@@ -218,98 +323,24 @@
 	    sys.exit("Experiment certfile required")
 
-	context = None
-	while context == None:
-	    try:
-		context = fedd_ssl_context(cert, opts.trusted)
-	    except SSL.SSLError, e:
-		# Yes, doing this on message type is not ideal.  The string
-		# comes from OpenSSL, so check there is this stops working.
-		if str(e) == "bad decrypt": 
-		    print >>sys.stderr, "Bad Passphrase given."
-		else: raise
-
-	msg = { 'experiment': { 'fedid': exp_fedid } }
-
-	if opts.debug > 1: print >>sys.stderr, msg
-
-	if opts.transport == "soap":
-	    loc = feddServiceLocator();
-	    port = loc.getfeddPortType(opts.url,
-		    transport=M2Crypto.httpslib.HTTPSConnection, 
-		    transdict={ 'ssl_context' : context },
+	try:
+	    resp_dict = self.do_rpc({ 'experiment': { 'fedid': exp_fedid } }, 
+		    opts.url, opts.transport, cert, opts.trusted, 
+		    serialize_only=opts.serialize_only,
 		    tracefile=opts.tracefile)
-
-	    req = self.RequestMessage()
-
-	    set_req = getattr(req, "set_element_%s" % self.RequestBody, None)
-
-	    set_req(pack_soap(req, self.RequestBody, msg))
-
-	    if opts.serialize_only:
-		sw = SoapWriter()
-		sw.serialize(req)
-		print str(sw)
-		sys.exit(0)
-
-	    try:
-		method_call = getattr(port, self.method, None)
-		resp = method_call(req)
-	    except ZSI.ParseException, e:
-		sys.exit("Malformed response (XMLPRC?): %s" % e)
-	    except ZSI.FaultException, e:
-		resp = e.fault.detail[0]
-
-	    if resp:
-		resp_call = getattr(resp, "get_element_%s" %self.ResponseBody,
-			None)
-		if resp_call: 
-		    resp_body = resp_call()
-		    if ( resp_body != None): 
-			try:
-			    resp_dict = unpack_soap(resp_body)
-			    if opts.debug > 1: print >>sys.stderr, resp_dict
-			    if resp_dict.has_key(self.key):
-				self.print_xml(resp_dict[self.key])
-			except RuntimeError, e:
-			    sys.exit("Bad response. %s" % e.message)
-		elif 'get_element_FeddFaultBody' in dir(resp): 
-		    resp_body = resp.get_element_FeddFaultBody()
-		    if resp_body != None: 
-			exit_with_fault(unpack_soap(resp_body))
-		else: sys.exit("No body in response!?")
-	    else: sys.exit("No response?!?")
-	elif opts.transport == "xmlrpc":
-	    if opts.serialize_only:
-		ser = dumps((msg,))
-		print ser
-		sys.exit(0)
-
-	    transport = SSL_Transport(context)
-	    port = ServerProxy(opts.url, transport=transport)
-
-	    try:
-		method_call = getattr(port, self.method, None)
-		resp = method_call(
-			encapsulate_binaries({ self.RequestBody: msg},\
-			    ('fedid',)))
-	    except Error, e:
-		resp = { 'FeddFaultBody': \
-			{ 'errstr' : e.faultCode, 'desc' : e.faultString } }
-	    if resp:
-		if resp.has_key(self.ResponseBody): 
-		    try:
-			resp_dict = resp[self.ResponseBody]
-			if opts.debug > 1: print >>sys.stderr, resp_dict
-			if resp_dict.has_key(self.key):
-			    self.print_xml(resp_dict[self.key])
-		    except RuntimeError, e:
-			sys.exit("Bad response. %s" % e.messgae)
-		elif resp.has_key('FeddFaultBody'):
-		    exit_with_fault(resp['FeddFaultBody'])
-		else: sys.exit("No body in response!?")
-	    else: sys.exit("No response?!?")
-
-class create:
-    def __init__(self): pass
+	except self.RPCException, e:
+	    exit_with_fault(\
+		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
+	except RuntimeError, e:
+	    sys.exit("Error processing RPC: %s" % e.message)
+
+	try:
+	    if resp_dict.has_key(self.key):
+		self.print_xml(resp_dict[self.key])
+	except RuntimeError, e:
+	    sys.exit("Bad response. %s" % e.message)
+
+class create(fedd_rpc):
+    def __init__(self): 
+	fedd_rpc.__init__(self, "Create")
 
     def add_ssh_key(self, option, opt_str, value, parser, access_keys):
@@ -398,15 +429,4 @@
 	out_certfile = opts.out_certfile
 
-	context = None
-	while context == None:
-	    try:
-		context = fedd_ssl_context(cert, opts.trusted)
-	    except SSL.SSLError, e:
-		# Yes, doing this on message type is not ideal.  The string comes
-		# from OpenSSL, so check there is this stops working.
-		if str(e) == "bad decrypt": 
-		    print >>sys.stderr, "Bad Passphrase given."
-		else: raise
-
 	msg = {
 		'experimentdescription': exp_desc,
@@ -420,88 +440,25 @@
 	if opts.debug > 1: print >>sys.stderr, msg
 
-	if opts.transport == "soap":
-	    loc = feddServiceLocator();
-	    port = loc.getfeddPortType(opts.url,
-		    transport=M2Crypto.httpslib.HTTPSConnection, 
-		    transdict={ 'ssl_context' : context },
+	try:
+	    resp_dict = self.do_rpc(msg, 
+		    opts.url, opts.transport, cert, opts.trusted, 
+		    serialize_only=opts.serialize_only,
 		    tracefile=opts.tracefile)
-
-	    req = CreateRequestMessage()
-
-	    req.set_element_CreateRequestBody(
-		    pack_soap(req, "CreateRequestBody", msg))
-
-	    if opts.serialize_only:
-		sw = SoapWriter()
-		sw.serialize(req)
-		print str(sw)
-		sys.exit(0)
-
+	except self.RPCException, e:
+	    exit_with_fault(\
+		    {'desc': e.desc, 'errstr': e.errstr, 'code': e.code})
+	except RuntimeError, e:
+	    sys.exit("Error processing RPC: %s" % e.message)
+
+	if opts.debug > 1: print >>sys.stderr, resp_dict
+
+	ea = resp_dict.get('experimentAccess', None)
+	if out_certfile and ea and ea.has_key('X509'):
 	    try:
-		resp = port.Create(req)
-	    except ZSI.ParseException, e:
-		sys.exit("Malformed response (XMLPRC?): %s" % e)
-	    except ZSI.FaultException, e:
-		resp = e.fault.detail[0]
-
-	    if resp:
-		if 'get_element_CreateResponseBody' in dir(resp): 
-		    resp_body = resp.get_element_CreateResponseBody()
-		    if ( resp_body != None): 
-			try:
-			    resp_dict = unpack_soap(resp_body)
-			    if opts.debug > 1: print >>sys.stderr, resp_dict
-			    ea = resp_dict.get('experimentAccess', None)
-			    if out_certfile and ea and ea.has_key('X509'):
-				try:
-				    f = open(out_certfile, "w")
-				    print >>f, ea['X509']
-				    f.close()
-				except IOError:
-				    sys.exit('Could not write to %s' % \
-					    out_certfile)
-			except RuntimeError, e:
-			    sys.exit("Bad response. %s" % e.message)
-		elif 'get_element_FeddFaultBody' in dir(resp): 
-		    resp_body = resp.get_element_FeddFaultBody()
-		    if resp_body != None: 
-			exit_with_fault(unpack_soap(resp_body))
-		else: sys.exit("No body in response!?")
-	    else: sys.exit("No response?!?")
-	elif opts.transport == "xmlrpc":
-	    if opts.serialize_only:
-		ser = dumps((msg,))
-		print ser
-		sys.exit(0)
-
-	    transport = SSL_Transport(context)
-	    port = ServerProxy(opts.url, transport=transport)
-
-	    try:
-		resp = port.Create({ 'CreateRequestBody': msg})
-	    except Error, e:
-		resp = { 'FeddFaultBody': \
-			{ 'errstr' : e.faultCode, 'desc' : e.faultString } }
-	    if resp:
-		if resp.has_key('CreateResponseBody'): 
-		    try:
-			resp_dict = resp['CreateResponseBody']
-			decapsulate_binaries(resp_dict, ('fedid',))
-			if opts.debug > 1: print >>sys.stderr, resp_dict
-			ea = resp_dict.get('experimentAccess', None)
-			if out_certfile and ea and ea.has_key('X509'):
-			    try:
-				f = open(out_certfile, "w")
-				print >>f, ea['X509']
-				f.close()
-			    except IOError:
-				sys.exit('Could not write to %s' % out_certfile)
-		    except RuntimeError, e:
-			sys.exit("Bad response. %s" % e.messgae)
-		elif resp.has_key('FeddFaultBody'):
-		    exit_with_fault(resp['FeddFaultBody'])
-		else: sys.exit("No body in response!?")
-
-	    else: sys.exit("No response?!?")
+		f = open(out_certfile, "w")
+		print >>f, ea['X509']
+		f.close()
+	    except IOError:
+		sys.exit('Could not write to %s' %  out_certfile)
 
 valid_cmds = ['create']
@@ -513,8 +470,8 @@
 elif sys.argv[1] == 'vtopo':
     del sys.argv[1]
-    f = exp_data('vtopo')
+    f = exp_data('Vtopo')
 elif sys.argv[1] == 'vis':
     del sys.argv[1]
-    f = exp_data('vis')
+    f = exp_data('Vis')
 else:
     sys.exit("Bad command: %s.  Valid ones are: %s" % \
